ATTENTION ALL FANS!!! THIS BLOG HAS MOVED!!!
go to: http://www.taotekaching.com

Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Wednesday, March 25, 2009

A Stupid Anonymous Thread Trick, and Me…

Ok, the storyline:  A web site creates a temporary file to work with, then is supposed to delete it, because maybe space is low on the drive or whatever.  There are times where the file will still be locked from our work when we try to delete it.  Perhaps we did something like:

File.WriteAllBytes("newFile", File.ReadAllBytes("oldFile"));

And it hasn’t released the lock on “oldFile” when we get to the next statement.  Oh man, that’s a problem.  A BIG problem.  A HUGE problem.

Not anymore!  Introducing a stupid anonymous thread method pause trick we can do:

bool deleted = false;

int tries = 3;

while ((!deleted) && (tries > 0))

{

    try

    {

        File.Delete("theFile");

        deleted = true;

    }

    catch

    {

        Thread pauser = new Thread(

            new ParameterizedThreadStart(

                delegate(object o)

                {

                    System.Threading.Thread.Sleep(500);

                }));

        pauser.Start();

        while (pauser.IsAlive) ;

        tries--;

    }

}

Oh god yeah…

Ok, a quick run-through.  We try to delete our file.  An exception is caught, so to allow the current thread to finish any IO operations, we create a temporary thread (pauser), which we wait for to finish.  Once it’s done, we try again until either we succeed or just give up.

My sandbox for playing around with this idea is here.  I have a question, though, that needs answering desperately:

              Is this useful anywhere?

If so, please provide an example of where this would be great to use.  I just need to know I didn’t fully waste my time.

~ZagNut

Submit this story to DotNetKicks

Saturday, March 07, 2009

Duplicate Files, Hash Codes, SQLite, and Me…

My wife’s been getting on my case about having a gazillion different hard drives with everything and our mothers on them all around the house.  I mean, come on everybody, she just wants her pictures in one @%$!# spot!  She also “misused” Picasa, and now has a bunch of duplicates on her laptop (she doesn’t read my blog, so I ain’t worried she’ll read that).

So, out shopping for Little Liam last weekend, and we decide to pop into Circuit City’s closing-its-doors blowout sale.  I grabbed her a 500 GB Western Digital external drive and, when we got home, proceeded immediately on a simple solution to shut her pie hole.

The result: MyPicturesConsolidator!  It is a WYSIWYG image grabber, duplicate detector, and file-copier-consolidator all in one, gorgeous package!

Ok, this program is NOT a work of art, but may contain some good stuff you can use, and it works pretty solidly, so…

mpc

How it works:

First, you select where you want any pictures it finds to get copied to:

mpc_dest

Second, select the logical drive you want to scan for pictures.  I included a Refresh Drive List button for changing between USB drives:

mpc_src

Third, click Find My Pictures!  And you’re good!

Behind the scenes:

I wanted a “list” to be maintained that kept track of files we’ve gone through.  I decided to use a SQLite database that would hold MD5 and SHA1 hashes of the pictures.  A good side effect of this is, just take it with the exe and SQLite dll to another computer along with your destination drive (or network share path, etc.), and the duplicates list maintained in the SQLite db should work golden for you.

MD5 and SHA1 generation is, for lack of a better phrase, retardedly easy via .NET.  An MD5 hash of a file, for instance, can be had in one line of code:

byte[] md5Hash = new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.IO.File.ReadAllBytes(filename));

The code is here.  Go ahead and take a look.  There’s some dumb things I’m doing in there that deal with my wife’s needs (i.e. Picasa uses file creation dates, ergo I try to find the earliest for her when I can, etc.).

~ZagNut

Submit this story to DotNetKicks

Tuesday, February 24, 2009

Binary Data Transforms, Hex Editing, Design Patterns, and Me…

Lately for work I have been responsible for developing a .NET layer to read from and write to an existing application's binary data files.  The task has proven tedious, but not necessarily boring, as I've discovered some invaluable tools and development principles from this.

First off, the HxD hex editor, and, more importantly, comparison tool is simply perfect for the job.

hxd

Many minute differences in my binary output were discovered with this tool.  By using the comparison feature:

hxd-compare

I could determine the first instance of a difference in output and, if unexpected, use the location from HxD to quickly narrow down the area of code responsible.

hxd-compare2

In my code, a Stream is passed to a method that will populate a struct representing the file.  This Stream is put into a BinaryReader for sequential type-based reading of the file.   By simply adding conditional breakpoints at various places in the code, locating the problem was easy.  The condition of the breakpoint would be something like:

myBinReader.BaseStream.Position > 10000

where 10000 would be just below the difference location given by HxD.

hxd-compare3

So this greatly, greatly, very much helped speed up the process of making sure I was reading and writing the native binary file format out correctly.  Next, I was to transform some of this data to XML for use by another application.  I already had the struct of native data, and wanted to make the transformation to and from XML as stupidly simple as possible.  To do this, I threw down a bunch of different classes, each representing the XML element I was to turn out, and had the elements inherit a base interface with a ToXML() contract method.  Some of the “element” classes contained List<>s of the other “element” classes, so when churning out the XML, it was as simple as doing a foreach and callling ToXML() from each of those to produce my child nodes correctly.

I very much realize this solution is neither new nor ingenious.  I am using it, in fact, as a tangent off into a discussion on this patterns-war stemming from the Spolsky comment on the SOLID method.  Quite frankly, I’m not sure what pattern or patterns I implemented above.  The Proxy or Facade?  I would like to know, as I’ve used this technique of a sort of “translation class” a bazillion times, except my bosses really don’t provide me much time to learn about it, much less, say, spend time with my family (I know you gobblers are reading this).  However, I have an opinion on this patterns-war that I would love some feedback on.  It centers around hiring:  if your team is hiring a new developer / engineer, and you or your team are big into design patterns, don't make knowledge of design patterns a requisite for hiring.

I have been programming most of my life, but only somewhat recently have been able to make it my career.  Already I've met a good range of coders: the hardcore enthusiast, the day-job-only coder, the serious professional.  They seem to come in all types, but all have the same common denominator:  they enjoy writing code.  Some more than others, but ultimately, there is a certain gene-pool that simply enjoys writing code.  It actually has little to do with being a computer enthusiast.  A good majority of systems administrators I've worked with or under don't like programming, period.  But there are those of us who are addicted to "realizing" our thoughts right there on the screen.

Until maybe two or three years ago, I knew little to nothing about design patterns.  As I became familiar with and researched them, I've discovered that I've been using many of them for a long, long time.  And that's exactly what they are:  patterns that have been "recognized" in the programming trade.  As such, they are most valuable as a means of communicating an approach to a task or problem at hand.  They are not, however, a requirement to attack a programming task, nor are they any indication of the competency of the prospective engineer / developer.

If your programming shop or R&D department or whatever group you work in is a pattern-heavy group, then make the applicant aware of this, but don't dismiss them if they simply don't know design patterns.  Most likely the applicant would be more than eager to learn them, and will discover they’ve already used many of them anyways.  Ergo, it's a subset of a lexicon we, as coders, may or may not need to know, depending only on how to be most efficient in our team.

I've noticed that a majority of the programmers I've worked with thus far who are heavy into patterns arrogantly criticize and judge their colleagues when they find out they don't know what a singleton is or the proxy pattern or whatever.  So far, from what I've seen, neither camp has shown to be better programmers than the other.  The real thing that quickly separates an experienced programmer from a truly great programmer, though, is ego.  I personally love everything from learning new tricks and techniques from my colleagues to having them point out where I was really dumb in my code.  It only makes me ultimately a better programmer (hopefully).  What I don’t want to do, and I think this is a pretty unanimous feeling, is converse with an asshole.

When you really think about it, the literal sense of “conversing with an asshole” is identical to it’s figurative sense: an asshole really never listens, and only barks out useless foulness you’ll want to stay away from.  Plus, your friends, family, and colleagues all may very well think less of you if they see you regularly conversing with assholes, even if it’s the same asshole.

So really, whether you’re big into design patterns or not, don’t be an asshole, because it just means you don’t listen and no one wants to be near you anyways.  And if you’re hiring, replace “do they know what a flyweight pattern is?” with “are they an asshole?” on your checklist.  You’ll always build a better team that way.

~zagnut

Submit this story to DotNetKicks

Tuesday, February 10, 2009

Baby Toys, Potty Words, SQL, and Me...

So little Liam just had his first birthday last Thursday.  Among the plethora of toys dumped on him is an incredibly annoying, er, wonderful alphabet speaking caterpillar:

My fat son!

There’s a small yellow bow switch just below the head with three settings, plus off (dear God): letter pronouncing, alternate letter pronouncing, and color word.  These obviously coincide with the feet, so if you press the A foot, the caterpillar will speak “A” on the letter pronunciation, “ah” on the alternate pronunciation, and “red” on the color one.

caterpillar

I had the setting on alternate pronunciation, and was lying back letting Liam play and climb on me.  While smashing the caterpillar, he hit a bunch of keys, seemingly at once.  The F key said “fuh” first, then the caterpillar giggled and said “that tickles!”, and then “kh” for the K key.

This immediately caught my attention, and I had to make the evil caterpillar curse violently so mom would toss it in the closet.  With Liam’s full attention, I hit the F, then K keys.  Again, “he he he, that tickles!” between the two keys.  I took the caterpillar from Liam.  This was now science!  I tried K, O, “he he he, that tickles!”, K.  FASCINATING!  They built in anti-potty-wording!  It blocked T-I-“he he he, that tickles!”-T, F then C, K-O-“he he he, that tickles!”-C, C-O-“he he he, that tickles!”-C, C-U-“he he he, that tickles!”-M, and P-I-S (latin for to pee).  J-I-Z worked, as well as B-U-T.  The word for buttocks or donkey (A-“he he he, that tickles!”-S) did not.

This makes me wonder about other alphabet toys and whether they were as thoroughly scrutinized or not.  Needless to say, I had been working on some SQL for work and decided to see how well it tells the SOUNDEX difference between various spellings of rather naughty words using DIFFERENCE.  Using SQL 2005, the results were startlingly poor.  In a few instances, SQL was smart in its comparisons, however in many cases a comparison between, say, a naughty reference to a woman’s genitals and a man’s returns a DIFFERENCE value of 3.  For those who don’t know, the value returned ranges from 0 to 4, 0 being completely dissimilar to 4 being extremely similar if not identical.  The values in the above case should have been a 0.  The SQL and source for the simple tests are here.  Basically, I’d at least look at additional resources for filtering potty language from user input.

I guess really the only useful thing that came out of this arguably utterly useless exercise is some quick C# I threw together to de-Cartesian-ize my SQL result set:

using System;

using System.Collections.Generic;

using System.Text;

 

using System.IO;

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            List<string> csv = new List<string>(File.ReadAllLines("potty.csv"));

            List<string> csvmod = new List<string>();

            csv.FindAll(delegate(string s)

            {

                string[] l = s.Split(new char[] { ',' });

                if (csvmod.FindIndex(delegate(string s2)

                {

                    return (s2.Contains(l[0] + ",") && s2.Contains(l[1] + ",") && (s2.IndexOf(l[0] + ",") != s2.IndexOf(l[1] + ",")));

                }) < 0)

                    csvmod.Add(s);

                return false;

            });

            File.WriteAllLines("potty-less.csv", csvmod.ToArray());

        }

    }

}

Just an example of hot anonymous delegate action for ya.

Tasty…

~zagnut

Submit this story to DotNetKicks

Tuesday, February 03, 2009

Visual Studio Extensions, C++ Debugging, and Me…

So, I am lazy, as I believe most programmers are.  I follow Bill Cosby’s sage advice to work hard to keep from working.

At work I’d “inherited” a code-complete medium-sized application in C++ that requires somewhat extensive feature enhancements / changes (due to the customer, of course).

I’ve been noticing that it seems much easier to write very foreign looking code in C / C++ than it is in C#, and although this application was obviously brilliantly coded, it is quite foreign indeed, seeming to be more of a C+ application than full-on C or C++.

Nevertheless, I have my work cut out for me, and it needs to be done FAST.  I need to make changes and see what breaks, then fix it, and so on.  The problem was, no debugging code was written into the application at all.  What was I to do?  I could spend a good 2 to 3 weeks adding debug output to all the functions, but I don’t have 2 to 3 weeks.  WHAT DO I DO?

Introducing AutoDebugIndexer!  It’s a simple Visual Studio Extension in C# that tried to add an OutputDebugStringA to the beginning of every function it finds.  What’s great is it seems to work!

It simply recurses through all the CodeElements of each Project’s CodeModel, checks to see if each (as a C++ CodeElement) is a vsCMElementFunction, and if so, tries to slap an OutputDebugStringA containing the function’s FullName at the beginning of that function’s BodyTextDownload the source and see for yourself.  Really you only need to look at AutoDebug.cs, everything else is pretty much Extensibility Wizard code.

On a side note, this is an extremely simple solution here.  I did not try at all to make this pretty, nor make it work beyond C++.  The latter is easy, however.  You’d just test for the code type, at the very least at the project level, and if it is say C#, insert a System.Diagnostics.Debug.WriteLine(“blah”); instead of the OutputDebugStringA.

Hope this is as valuable to you as it certainly will be for me!

~ZagNut

Submit this story to DotNetKicks

Wednesday, January 21, 2009

In the name of Science, and Me…

All programmers, at one point or another, have dreamt of this:

3M TA3

Of course, you know what this is, right? It’s a file. Duh, you say? No, you don’t understand. Each pixel represents 4 bytes of a file. I used the first two pixels to “store” the number of bytes of the actual file, then the rest up to that white line at the end, is the file.

Brilliant? Yes, yes I know. I have not been able to purge my mind of this ridiculously stupid project / experiment for years. Every now and then, it’s very “what if” resurfaces like a slightly annoyed blackhead. It needed popping…

Needless to say, it is not very good for compressing. Zipping the image actually increases it’s size slightly. I was skeptical of this, though (this is SCIENCE), so I decided to try it on a PCLinuxOS Mini-Me 2008 ISO image I had laying around on my desktop, which is around 296MB. The bmp generated is quite large – 8821 x 8821. The compression results:

  • PCLOS ISO: 311,207,936 bytes
  • PCLOS ISO bitmapped: 309,407,681 bytes
  • PCLOS ISO zipped: 307,880,700 bytes
  • PCLOS ISO bitmapped & zipped: 309,407,811 bytes

There. Finally. Purged from my mind…but…

WHAT IF I GENERATED A SERIES OF 50 x 50 BITMAPS OF THE ISO AND STRUNG THEM INTO AN AVI?

Not going there. If you do, please dear God and baby Jesus let me know how it goes. Here’s my dumb code if it’ll help, or get it from here:

file

But that’s not all I did in the name of science tonight! I went out to have a cigarette (in our 15 degree weather) in celebration of lobotomizing the bitmap wart from my mind to discover this:

lite-off

In the name of science, I had to know what it would look like lit up. I knew the dangers. I knew I might, potentially, kill the power to our house, destroy my beloved TV, and black out the neighborhood.

lite-on

Eh, boring. Thought all the ice would light up or something…

~zagnut

Submit this story to DotNetKicks

Thursday, January 08, 2009

Device Independent Bitmaps, C#, and Me…REDUX!


Well, after using the previously posted code in some projects at work, some limitations arose quickly. The two biggest were support for 8-bit bitmaps, and support for both 5-5-5 and 5-6-5 16-bit bitmaps.

The new code looks like the following:

using System;

using System.Collections.Generic;

using System.Drawing;

using System.Drawing.Imaging;

using System.Runtime.InteropServices;

using System.IO;

namespace DIBitmaps

{

static public class DIB

{

// our BITMAPINFOHEADER struct, as per gdi

// use LayoutKind to make sure data is marshalled as we've laid it out

[StructLayout(LayoutKind.Sequential)]

public struct BITMAPINFOHEADER

{

public uint biSize;

public int biWidth;

public int biHeight;

public ushort biPlanes;

public ushort biBitCount;

public uint biCompression;

public uint biSizeImage;

public int biXPelsPerMeter;

public int biYPelsPerMeter;

public uint biClrUsed;

public uint biClrImportant;

//public void Init()

//{

// biSize = (uint)Marshal.SizeOf(this);

//}

}

public static Bitmap BitmapFromDIB(MemoryStream dib)

{

// get byte array of device independent bitmap

byte[] dibBytes = dib.ToArray();

// get the handle for the byte array and "pin" that memory (i.e. prevent

// garbage collector from gobbling it up right away)...

GCHandle hdl = GCHandle.Alloc(dibBytes, GCHandleType.Pinned);

// marshal our data into a BITMAPINFOHEADER struct per Win32

// definition of BITMAPINFOHEADER

BITMAPINFOHEADER dibHdr = (BITMAPINFOHEADER)Marshal.PtrToStructure

(hdl.AddrOfPinnedObject(), typeof(BITMAPINFOHEADER));

bool is555 = true;

Bitmap bmp = null;

if (dibHdr.biBitCount == 8)

{

// set our pointer to end of BITMAPINFOHEADER

Int64 jumpTo = hdl.AddrOfPinnedObject().ToInt64() + dibHdr.biSize;

bmp = new Bitmap(dibHdr.biWidth, dibHdr.biHeight, PixelFormat.Format8bppIndexed);

bmp.SetResolution((100f * (float)dibHdr.biXPelsPerMeter) / 2.54f,

(100f * (float)dibHdr.biYPelsPerMeter) / 2.54f);

// set the colors in our palette

ColorPalette palette = bmp.Palette;

IntPtr ptr = IntPtr.Zero;

int colors = (int)(dibBytes.Length - (bmp.Width * bmp.Height) - dibHdr.biSize);

for (int i = 0; i < 256; i++)

{

ptr = new IntPtr(jumpTo);

uint bmiColor = (uint)Marshal.ReadInt32(ptr);

int r = (int)((bmiColor & 0xFF0000) >> 16),

g = (int)((bmiColor & 0xFF00) >> 8),

b = (int)((bmiColor & 0xFF));

palette.Entries[i] = Color.FromArgb(r, g, b);

jumpTo += 4;

}

bmp.Palette = palette;

// now write the remaining bmp data to our bitmap

BitmapData _8bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),

ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

jumpTo -= hdl.AddrOfPinnedObject().ToInt64();

Marshal.Copy(dibBytes, (int)jumpTo, _8bd.Scan0, _8bd.Stride * _8bd.Height);

bmp.UnlockBits(_8bd);

}

else if ((dibHdr.biBitCount == 16) && (dibHdr.biCompression == 3))

{

Int64 jumpTo = (Int64)(dibHdr.biClrUsed * (uint)4 + dibHdr.biSize);

IntPtr ptr = new IntPtr(hdl.AddrOfPinnedObject().ToInt64() + jumpTo);

ushort redMask = (ushort)Marshal.ReadInt16(ptr);

ptr = new IntPtr(ptr.ToInt64() + (2 * Marshal.SizeOf(typeof(UInt16))));

ushort greenMask = (ushort)Marshal.ReadInt16(ptr);

ptr = new IntPtr(ptr.ToInt64() + (2 * Marshal.SizeOf(typeof(UInt16))));

ushort blueMask = (ushort)Marshal.ReadInt16(ptr);

is555 = ((redMask == 0x7C00) && (greenMask == 0x03E0) && (blueMask == 0x001F));

}

// go ahead and release the "pin" from our handle on that memory

hdl.Free();

// If the target device does not have one plane, or we're working with a bitmap other

// than a non-compressed (BI_RGB) bitmap, we're not gonna work woith it

if (dibHdr.biPlanes != 1 || (dibHdr.biCompression != 0 && dibHdr.biCompression != 3))

return null;

if (bmp == null)

{

// we need to know beforehand the pixel-depth of our bitmap

PixelFormat fmt = PixelFormat.Format24bppRgb;

switch (dibHdr.biBitCount)

{

case 32:

fmt = PixelFormat.Format32bppRgb;

break;

case 24:

fmt = PixelFormat.Format24bppRgb;

break;

case 16:

fmt = (is555) ? PixelFormat.Format16bppRgb555 :

PixelFormat.Format16bppRgb565;

break;

default:

return null;

}

// prepare for our output bitmap

bmp = new Bitmap(dibHdr.biWidth, dibHdr.biHeight, fmt);

// load our "empty" bitmap into memory and lock it for

// writing in the format we specified

BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),

ImageLockMode.WriteOnly, fmt);

// marshal our device independent bitmap data over to our output bitmap

Marshal.Copy(dibBytes, Marshal.SizeOf(dibHdr), bd.Scan0, bd.Stride * bd.Height);

// we're done marshalling, so release our bitmapdata lock

bmp.UnlockBits(bd);

}

if (dibHdr.biHeight > 0)

{

// DIB data is upside-down for some reason, so flip it

bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);

}

// return our bitmap

return bmp;

}

}

}

The adjusted code can be downloaded here.

If you find any other issues, please let me know and I’ll get it updated ASAP.

~ZagNUT

Submit this story to DotNetKicks

Thursday, December 04, 2008

Native MDI Containers, Managed Child Forms, and Me...

So, at work we have this (ugly) native C++ MFC application that the Powers-That-Be insist needs a complex web-services riddled interface to our social-networking-meets-file-sharing new website.  Initially, said interface was to be in MFC native code action.  I said, "sheeeeeeeeeiiiiiiiiiiiiiiiittt".  But then the light came: why not do the interface in a .NET form and pass the form handle somehow to the native application to pull it into its window as a child window.  Any interaction between the two can be handled easily through messaging calls.  I immediately began to Google on it.  I found nothing that directly addressed this problem.  I concluded it was one of two things: either it was so easy, no one bothered documenting it, or so rarely done, no one bothered documenting it.  Either way, no one bothered documenting it...UNTIL NOW!!!

Basically my solution was to grab the parent window's class using a call to GetClassName, then send this as a command line parameter to the .NET exe via a ShellExecute call.  Once in the .NET client, I use two DllImport-ed calls: FindWindow and SetParent -- FindWindow to get the window handle from the class name I passed in as a parameter, and SetParent to, well, set the parent of my form.

The sample code is here.  Note, you'll need to change the hardcoded path in the NativeMaster C++ solution to the output of the ManagedChild project.  Hope it's helpful...

~ZagNut

Submit this story to DotNetKicks

Monday, November 24, 2008

DIB, C#, and Me...

Ok, after pulling out my hair trying to generate thumbnails from device-independent bitmaps stored by a CArchive in an "old" MFC program, I finally got help here at the workplace on this.

I must say I could not find this easily with much Googling, ergo I'm gonna post this up here with comments for anyone else out there looking for the same thing.

Please suggest any updations to comments and / or code, if you see the need...

NOTE: This code has been updated. Look here for it.

// our BITMAPINFOHEADER struct, as per gdi
// use LayoutKind to make sure data is marshalled as we've laid it out
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFOHEADER
{
public uint biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public uint biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
public void Init()
{
biSize = (uint)Marshal.SizeOf(this);
}
}

public static Bitmap BitmapFromDIB(MemoryStream dib)
{
// get byte array of device independent bitmap
byte[] dibBytes = dib.ToArray();

// get the handle for the byte array and "pin" that memory (i.e. prevent garbage collector from
// gobbling it up right away)...
GCHandle hdl = GCHandle.Alloc(dibBytes, GCHandleType.Pinned);

// marshal our data into a BITMAPINFOHEADER struct per Win32 definition of BITMAPINFOHEADER
BITMAPINFOHEADER dibHdr = (BITMAPINFOHEADER)Marshal.PtrToStructure(hdl.AddrOfPinnedObject(), typeof(BITMAPINFOHEADER));

// go ahead and release the "pin" from our handle on that memory
hdl.Free();

// If the target device does not have one plane, or we're working with a bitmap other than a
// non-compressed (BI_RGB) bitmap, we're not gonna work woith it
if (dibHdr.biPlanes != 1 || dibHdr.biCompression != 0)
return null;

// we need to know beforehand the pixel-depth of our bitmap
PixelFormat fmt = PixelFormat.Format24bppRgb;
switch (dibHdr.biBitCount)
{
case 32:
fmt = PixelFormat.Format32bppRgb;
break;
case 24:
fmt = PixelFormat.Format24bppRgb;
break;
case 16:
fmt = PixelFormat.Format16bppRgb555;
break;
default:
return null;
}

// prepare for our output bitmap
Bitmap bmp = new Bitmap(dibHdr.biWidth, dibHdr.biHeight, fmt);

// load our "empty" bitmap into memory and lock it for writing in the format we specified
BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, fmt);

// marshal our device independent bitmap data over to our output bitmap
Marshal.Copy(dibBytes, Marshal.SizeOf(dibHdr), bd.Scan0, bd.Stride * bd.Height);

// we're done marshalling, so release our bitmapdata lock
bmp.UnlockBits(bd);

// DIB data is upside-down for some reason, so flip it
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);

// return our bitmap
return bmp;
}


~simon

Submit this story to DotNetKicks