[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.dotnet.framework.interop

Specific Problem calling VC8 dll from c# .NET

Jon E

9/18/2007 8:16:00 AM

Having spent years using Visual C++, I'm a relevent newbie to .NET./ I'm
fairly comfortable with teh new programming environment, but the one area
that I constantly struggle with is calling legacy VC DLL's (straight Dll's,
not extension Dlls). Using www.PInvoke.net I usually find an equivalent
example and learn from that, but one specific item has defeated me.

In the legacy DLL I have a function :-

BOOL GetLatestImage( BITMAPINFO *pInfo, BYTE *pPixelBuffer ) ;

It returns the format of the image in pInfo and copies raw pixel data in
pPixelBuffer. (pPixelBuffer can be NULL if all's you want is pInfo).

So, how do I call this function from .NET so that I can get the image into
an 'Image' or 'Bitmap' class ?

As the function call may be used frequently (lets say 100 times per second
for the sake of argument) I'm also looking for efficiency if possible.

Thanks in advance.

TTFN,
Jon

3 Answers

Doug Semler

9/18/2007 6:10:00 PM

0

On Sep 18, 4:16 am, Jon E <J...@discussions.microsoft.com> wrote:
> Having spent years using Visual C++, I'm a relevent newbie to .NET./ I'm
> fairly comfortable with teh new programming environment, but the one area
> that I constantly struggle with is calling legacy VC DLL's (straight Dll's,
> not extension Dlls). Usingwww.PInvoke.netI usually find an equivalent
> example and learn from that, but one specific item has defeated me.
>
> In the legacy DLL I have a function :-
>
> BOOL GetLatestImage( BITMAPINFO *pInfo, BYTE *pPixelBuffer ) ;
>
> It returns the format of the image in pInfo and copies raw pixel data in
> pPixelBuffer. (pPixelBuffer can be NULL if all's you want is pInfo).
>
> So, how do I call this function from .NET so that I can get the image into
> an 'Image' or 'Bitmap' class ?
>
> As the function call may be used frequently (lets say 100 times per second
> for the sake of argument) I'm also looking for efficiency if possible.
>
> Thanks in advance.
>
> TTFN,
> Jon

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?

Anyway, as long as you know how much to allocate, you can do something
like:

namespace whatever
{
[StructLayout(LayoutKind.Sequential)]
class BitmapInfoHeader
{
public uint biSize =
(uint)Marshal.SizeOf(typeof(BitmapInfoHeader));
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;
}

[StructLayout(LayoutKind.Sequential)]
struct RGBQUAD
{
public byte rgbBlue;
public byte rgbGreen;
public byte rgbRed;
public byte rgbReserved;
}

[StructLayout(LayoutKind.Sequential)]
class BitmapInfo
{
public BitmapInfoHeader Header = new BitmapInfoHeader();
// use SizeConst if you know the size before hand and you can
put the new here.
[MarshalAs(UnmanagedType.ByValArray)]
public RGBQUAD[] rgbInfo; // = new RGBQUAD[mySizeConst];
}

class UnsafeNativeMethods
{
// use correct calling convention
[DllImport("dllname", CallingConvention =
CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
// [In, Out] required for the data to be copied from callee to
caller.
public static extern bool GetLatestImage([In, Out]BitmapInfo
pInfo, [In, Out]byte[] pPixelBuffer);
}

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
}
}
}

Jon E

9/19/2007 7:58:00 AM

0



"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.

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).

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.

Once again, thanks for your help.

TTFN,
Jon

Doug Semler

9/19/2007 1:13:00 PM

0

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...