LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

GetDC and BitBlt in Labview C DLL

Hello everyone,
 
This is a pretty tricky question for C/Labview people.  I am trying to BitBlt to an OpenLabview window, and to do this I need to grab the Device Context of the window front panel that I would like to write to.  The BitBlt is succesful, but after several thousand updates (5000 - 10000) Labview crashes.  I have traced it down to the GetDC command.  If this command is executed, Labview will crash 100% of the time.  If the command is removed, Labview will not crash (but doesn't work because BitBlt doesn't know which window to write to).  Does anyone know what is causing this?  C code is as follows:
 

__declspec

(dllexport) float WriteToFrontPanel(unsigned int *ptrRGB)

{

HWND Labview;

BITMAPV4HEADER bih;

ZeroMemory(&bih,

sizeof(BITMAPV4HEADER));

bih.bV4Size =

sizeof(BITMAPV4HEADER);

bih.bV4Width = 1000;

bih.bV4Height = -1000;

bih.bV4Planes = 1;

bih.bV4BitCount = 32;

bih.bV4V4Compression = BI_RGB;

int temp = 0;

Labview = FindWindow(NULL,

"Window.vi");

HDC bit_dc = CreateCompatibleDC(NULL);

HBITMAP hBit = CreateDIBitmap(GetDC(Labview), (LPBITMAPINFOHEADER)&bih, CBM_INIT, ptrRGB, (LPBITMAPINFO)&bih, DIB_RGB_COLORS);

SelectObject(bit_dc, hBit);

BitBlt(GetDC(Labview), 0, 0, 1000, 1000, bit_dc, 0, 0, SRCCOPY);

temp = ReleaseDC(Labview, GetDC(Labview));

DeleteDC(bit_dc);

DeleteObject(hBit);

return temp;

}

The function commands and descriptions are at www.msdn.com if anyone is interested in following the discussion.

Thanks for your time,

Austin



Message Edited by AustinMcElroy on 02-28-2008 02:24 PM
0 Kudos
Message 1 of 35
(8,096 Views)
Ok, problem solved.  I can post the solution if anyone cares, it is basically an overhead free way to display ARGB data, i.e. no intensity plots or picture windows to deal with.  Windows only, sorry Linux guys 😕
0 Kudos
Message 2 of 35
(8,065 Views)
Hi,

You have this solved, but I'll comment on it anyway...

Seems to me you open three DC's with GetDC. Once in CreateDIBitmap, once in
BitBlt, once in ReleaseDC. You close the reference once in ReleaseDC. I'm
not a C expert, but I think all three of the GetDC return a differente
reference!

Could you comment on your solution (I'm not going to use it anytime soon,
but other reader might)?

Btw. If I recall correctly, the GetDC is very slow. You could try to buffer
it, and only use GetDC when the old one causes an error when used.

Regards,

Wiebe.


0 Kudos
Message 3 of 35
(8,052 Views)
Well, the solution to the problem matches up pretty much with what you are saying.  At the very begining, create a temporary DC, hTempDC, that is equal to GetDC(Labview) and call that instead of the GetDC(Labview) each time.  At the end, destroy the hTempDC and that is that: a non-CPU intensive ARGB plot straight into Labview!  Each GetDC was using a little bit of memory but never being destroyed, thus causing an overflow somwhere, most likely the video card since the system memory was not filling up. 

Thanks,
Austin


Message Edited by AustinMcElroy on 02-29-2008 08:49 AM

Message Edited by AustinMcElroy on 02-29-2008 08:50 AM
0 Kudos
Message 4 of 35
(8,045 Views)
Austin (or Weibe),
 
I think I'm having a similar problem, but I do not follow your solution since I'm not familiar with C.  Could you attach a VI that illustrates how you create hTempDC that is equal to GetDC (LabVIEW)?  How do you know if the temporary DC expires (or does it not expire in your application)?  How do you destroy the DC when you are finished (that is, if Weibe is correct and ReleaseDC creates another DC... Am I missing something?)?
 
Thanks!
Jason

Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
0 Kudos
Message 5 of 35
(7,934 Views)

"LabBEAN" <x@no.email> wrote in message
news:1207226412787-682832@exchange.ni.com...
> Austin (or Weibe),
> &nbsp;
> I think I'm&nbsp;having a similar problem, but I do not follow your
solution since I'm not familiar with C.&nbsp; Could you attach a VI that
illustrates how you create hTempDC that is equal to GetDC (LabVIEW)?&nbsp;
How do you know if the temporary DC expires (or does it not expire in your
application)?&nbsp; How do you destroy the DC when you are finished (that
is, if Weibe is correct and ReleaseDC creates another DC... Am I missing
something?)?
> &nbsp;
> Thanks!Jason

You might be missing something... ReleaseDC doesn't create a DC, and GetDC
will return a new DC each time it is called. A DC is a pointer to a copy of
data related to a window. So if you call GetDC 100 times, you have 100
copies of the data, and 100 different Dc values, while you only need one.

Perhaps you better explain what you are trying to do, but I'll give some
comment anyway.

To draw in a window (any window, not just a LabVIEW window), you need a DC.
You get the DC through the window handler. If you want to draw a lot, you do
this once, and use the obtained DC over and over again. The DC will not
expire as long as the window is destroyed, or until you release the DC
yourself. Typically, you release the DC yourself when you are completelly
done drawing, so your application will look like:

get the DC
while (not done)
{draw to the DC}
release the DC

This looks a lot simpler, but in C it is actually easier to program like
this:

while (not done)
{
get the DC
draw to the DC
release the DC
}

Don't use this method. It is very slow...

Also, each DC you open, should be closed. If you don't do that, you'll get
leaks, and eventually a crash.

As a last note, I'd advice agains drawing in a LabVIEW window like this if
there is any way to prevent it. It is very difficult to make perfect. One
reason for this is you don't have acces to the repainting messages that are
send to LabVIEW windows.

Regards,

Wiebe.






0 Kudos
Message 6 of 35
(7,898 Views)
Wiebe,
 
Thank you for your input.  I understand now that the provided example (above) was unnecessarily calling GetDC (rather than the ReleaseDC function itself somehow generating an additional DC).  In my application, I've used hWnd = 0 with GetDC and ReleaseDC.  Everything seems to be working.  This sequence only happens when the user places their finger on the fingerprint reader (and I subsequently update the LabVIEW picture control), so I hope its okay to just use hWnd = 0 since this is what the SDK provider's example does.
 
Regards,
Jason

Certified LabVIEW Architect
TestScript: Free Python/LabVIEW Connector

One global to rule them all,
One double-click to find them,
One interface to bring them all
and in the panel bind them.
0 Kudos
Message 7 of 35
(7,872 Views)
Sorry everyone, out of town for buisness for a few days.

LabBean, let me update my example with the solution to the overflow problem I was having:

__declspec(dllexport) float WriteToFrontPanel(unsigned int *ptrRGB)

{
HWND Labview;

BITMAPV4HEADER bih;

ZeroMemory(&bih, sizeof(BITMAPV4HEADER));

bih.bV4Size = sizeof(BITMAPV4HEADER);

bih.bV4Width = 1000;

bih.bV4Height = -1000;

bih.bV4Planes = 1;

bih.bV4BitCount = 32;

bih.bV4V4Compression = BI_RGB;

int temp = 0;

Labview = FindWindow(NULL, "Window.vi");  //change this to the name of the window you want to draw to

HDC bit_dc = CreateCompatibleDC(NULL);

HDC hTempDC = GetDC(Labview);

HBITMAP hBit = CreateDIBitmap(hTempDC, (LPBITMAPINFOHEADER)&bih, CBM_INIT, ptrRGB, (LPBITMAPINFO)&bih, DIB_RGB_COLORS);

SelectObject(bit_dc, hBit);

BitBlt(hTempDC, 0, 0, 1000, 1000, bit_dc, 0, 0, SRCCOPY);

temp = ReleaseDC(Labview, hTempDC);

DeleteDC(bit_dc);

DeleteDC(hTempDC);

DeleteObject(hBit);

return temp;

}


Before, everywhere there was a hTempDC I was creating unneeded ones that weren't being closed, which caused my overflow problem.  By created a DC and equating it to the one I need, I can simply destroy the created one in the end and not have to worry about overflowing.  And yes, I am drawing to a Labview window, and yes I don't have control over the windows re-paint commands.  I just have to be creative to creative when using this BitBlt method to find ways around the repainting calls.  Even with this hassle, I feel the BitBlt method in a Labview window is orders of magnitude better than those cursed intensity graphs that sink a  VI's performance and hog CPU time.


Austin



0 Kudos
Message 8 of 35
(7,863 Views)
>>Even with this hassle, I feel the BitBlt method in a Labview window is
orders of magnitude better than those cursed intensity graphs that sink
a&nbsp; VI's performance and hog CPU time.Austin

Compairing intensity graphs with a BitBlt is a bit unfair. Have you tried
to:

Allocate a 2d array (once).
Fill this array the same way you fill the Blt'ed bitmap.
Draw this 2d array in a picture control.

I've done entire 2d arcade games in this manner (galaxy/space invaders, and
started boulder dash). Depending on the array size, it's pretty fast. I've
done this in LV 5, 6 and 7, in 8 the performance will probably be even
better.

It still won't be as fast as the BitBlt, but the performance shouldn't be
far off. If you need it to be really fast, you can remove a lot of garbage
from the draw unflattend pixmap vi, to get it even faster.

You can even use a graph's front picture to draw in, so you get the scales
from the graph, and the speed of the BitBlt.

Regards,

Wiebe.


0 Kudos
Message 9 of 35
(7,835 Views)
GetDC(NULL) or GetDC(0) will get the DC of the "the entire screen". If you
want to draw in a particular window, that is not the way to do it. But if it
works for you and it's in the manual it should be fine.

There might be problems with multiple monitors though, since each screen has
it's own DC... GetDC(0) will probably return the default monitor's DC, but
if you need to draw on the other display, you'll have top use
EnumDisplayMonitors and CreateDC. EnumDisplayMonitors is difficult, because
it uses a callback function.

Regards,

Wiebe.


0 Kudos
Message 10 of 35
(7,835 Views)