Doug Semler
9/19/2007 1:13:00 PM
On Sep 19, 3:58 am, Jon E <J...@discussions.microsoft.com> wrote:
> "Doug Semler" wrote:
> > [Part of useful code section snipped]
>
> > static class code
> > {
> > public static void foo()
> > {
> > BitmapInfo info = new BitmapInfo();
> > byte[] array = new byte[100]; // allocate corect size
> > info.rgbInfo = new RGBQUAD[256]; // allocate correct size
> > UnsafeNativeMethods.GetLatestImage(info, array);
> > // note on return info.rgbInfo will have size of 1
> > element. Can't help that with no sizeConst
> > }
> > }
> > }
>
> Thanks for that !
>
> > OK. Before this question can be answered, you need to answer the
> >following:
> > Do you have to allocate the color table array at the end of
> > BITMAPINFO before you can make this call? In addition, how do you
> > know the size you need to allocate for pixelBuffer? how do you know
> > the size of the color table array to allocate?
>
> Yes, the caller is expected to calc the buffer size from the bitmapinfo -
> not very OOP I grant you, but that's legacy stuff for you :-(
>
> I do however have the luxury of knowing the image will be either 24 or 32
> bit, so no colour table to worry about.
OK. Based on that information, you can SizeConst the RGBQUAD array to
1 (and initialize it on the constructor). As long as you are going to
be SURE that the callee is not going to try to copy things into that
buffer...or if you want to be "safe" you could allocate a long buffer,
say 256 RGBQUADS. that way the marshal will always send a structure
that is a K too big)).
So basically have to make two calls. The first is to the function
with a null as the byte[] array, so that you can get the size, then
the second is with the allocated array. OK.
>
> The last missing link for me is how to get the byte array into the Bitmap ?
> The intention would be to create the Bitmap and Byte[] objects the first time
> they are needed, and only destroy them and build new ones if the image size
> changes (which will be a rare occurence).
Instead of declaring the function with a byte[] array and doing it
that way, you can declare the function as an IntPtr (remove the [In,
Out]. Use Marshal.AllocHGlobal() with the correct size. You can then
use this pointer in the appropriate Bitmap constructor (width, height,
stride, pixel format, intptr). You are responsible for keeping the
pointer around until you are done with the bitmap (in other words, you
cannot free the hglobal until you have Dispose()d the Bitmap object.
In addition, I believe the bitmap expects the byte array to be aligned
and formatted as in a DIB (each scan aligned on a 4 byte boundary).
The other thing is I believe that the constructor expects the bitmap
to be top down. I also think that once the bitmap object controls the
pointer, you can't change the info in it without calling LockBits.
Or, you could just create your own bitmap in memory with a
BITMAPFILEHEADER, BITMAPINFO, and the Bytearary, and use that in the
bitmap constructor if you want to do it that way, but that requires
some copying....
>
> Finally, to me, the operations are a bit "black box". What is happening
> under the hood ? For example, worst case would be having already copied image
> into byte array, the "managing" process did a copy and then there was another
> copy to get it into the bitmap object.
>
That's what happens when you have a managed-unmanaged transition.
Whenever I have complicated stuff like this I tend to use C++/CLI so I
don't have to worry (too much) about the transition layer...