#### Archived

This topic is now archived and is closed to further replies.

# Memory DC's

This topic is 6046 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi: I''m writing a game in Visual Basic. VB isn''t very good with graphics, so everyone bypasses the VB graphics and uses the GDI. For some reason, though, no-one makes their own device contexts. Everyone uses invisible PictureBox controls (a simple VB control that displays pictures) because they have a DC property. For example, if someone wanted to blit a transparent picture on to the window, they would have three PictureBox controls, let''s say Pic1, Pic2, and Pic3. They would load the picture they want to blit onto in Pic1, the picture they want to blit in Pic2, and a mask in Pic3. They would import the GDI BitBlt function and use the following VB code: BitBlt Pic1.hDC, 0, 0, 100, 100, Pic3.hDC, 0, 0, SRCAND BitBlt Pic1.hDC, 0, 0, 100, 100, Pic2.hDC, 0, 0, SRCPAINT BitBlt Me.hDC, 0, 0, 100, 100, Pic1.hDC, 0, 0, SRCCOPY. This is all fine if your doing a little animation or something, but if I want to make a full game, perhaps using independant classes that may not have access to windows and their PictureBoxes, how do I use the GDI to make memory DC''s? I can''t find it anywhere. How do C programmers, who don''t have access to PictureBox controls, make memory DCs that can be used to temporarily Blt on to and off again? Thanx in advance, Shalom

##### Share on other sites
You''ll have much better luck with this post in the general programming forum, so I''am moving it.

##### Share on other sites
Windows apps have one or more windows. For any windows you can gets its DC by calling GetDC(hwnd) where hwnd is the handle of the window. This is usually done in response to a paint message (WM_PAINT) but can be done any time. This is what I do...

void Paint (HWND hwnd)
{
HDC dc = GetDC(hwnd);
int savedc = SaveDC(dc);

// there are many DC related draw functions:
// SelectObject(), MoveTo(), LineTo(), SetPixel(),
// BitBlt(), TextOut(), Rectangle(), Ellipse(),
// SetTextColor(), SetTextAlign(), on and on

RestoreDC(dc, savedc);
ReleaseDC(hwnd, dc);
}

DC''s have a ton of state information that you have to make sure is restored before you release them, or you get GDI leaks, so I always save/restore the whole thing.

##### Share on other sites
Hi, I can access the window''s DC, but how do I make a temporary DC? For example, let''s take a simple case - double buffering. How would I make a little animation in an imaginary DC and then BitBlt from that imaginary DC to the window''s DC? How do I make a sort of "buffer" DC?

Thanks,
Shalom

##### Share on other sites
hi shalom,

Device Contexts are just some sort of a "reference" to the device and they don''t anything on their own (they don''t hold the picture, they just point to the device that displays it...), and for that reason the term "temporary dc" doesn''t really mean anything cause it''s just a refernce to the device and you have to handle some sort of buffer yourself(by maybe having something hidden you draw into and then copying for the hidden object to the display object).

this is just a thought, havn''t been using VB for grahpics or the such

##### Share on other sites
Isn''t there a way of making a device in memory, without having a physical object?

##### Share on other sites
In other words, how do I make a buffer that I can point a device context to, with out having access to a window with my invisible objects and whatever?

##### Share on other sites
I''m just writing this off the top of my head and its been a while since I''ve used DCs, but I think this will work:

  HDC buffer;HDC window;HBITMAP temp;window = GetDC( window_hWnd );buffer = CreateCompatibleDC( window );temp = CreateCompatibleBitmap( buffer, width_of_image, height_of_image );SelectObject( buffer, temp );DeleteObject( temp );ReleaseDC( window_hWnd, window );

That will create an offscreen DC you can use to draw to. You must create a bitmap object and select it into the DC or you won''t be able to use the DC. I''m sure that I messed up some of the parameters (I don''t remember them all), but you should be able to look up the API functions and see what the parameters should be.

I don''t really remember VB that well, but I''d guess that the VB code would be something like:

  DIM buffer as LongDIM window as LongDIM temp as LongSet window = GetDC( Form1.hWnd )Set buffer = CreateCompatibleDC( window );Set temp = CreateCompatibleBitmap( buffer, width, height )Call SelectObject( buffer, temp )Call DeleteObject( temp );Call ReleaseDC( Form1.hWnd, window );

Im assuming that since you use BitBlt you know how to declare APIs for use in VB.

If you want direct access to the bits being displayed, I recomend that you create the bitmap object that you are going to select into the buffer DC with CreateDIBSection. That way you will have a pointer to the actual bits which will allow you to do things like alpha blending (I realize that alpha blending can be done with GetPixel/SetPixel, but that is to slow).

Feel free to email me any questions you might have
Mike010@netZero.net

##### Share on other sites
Thank you so much, Mike. It seems silly to get stuck on such a simple point. I have my entire game planned out and most of it programmed, and I don''t know how to use the GDI! Well, I''ll try it out.

##### Share on other sites
Oh no! I used the following code exactly, and it makes a square the right size in the top left corner of the window, but its all black! What did I do wrong?
  Option ExplicitPrivate Sub Form_Load()Dim buffer As LongDim window As LongDim temp As Longwindow = GetDC(Form1.hwnd)buffer = CreateCompatibleDC(window)temp = CreateCompatibleBitmap(buffer, Picture1.ScaleWidth, Picture1.ScaleHeight)SelectObject buffer, tempDeleteObject tempReleaseDC Form1.hwnd, windowBitBlt buffer, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, Picture1.hdc, 0, 0, SRCCOPYBitBlt Me.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, buffer, 0, 0, SRCCOPYForm1.RefreshDeleteDC bufferEnd Sub

Sigh... I''m causing so much trouble with such a simple problem. Oh well.

##### Share on other sites
I think that the problem is that the first BitBlt call is not working because I just read that in WinNT (I have 2000), all the pixels are initialized to black, while in Windows 9x/ME they are not initialized. Does anyone see why this call might not go through?

##### Share on other sites
I don''t have access to VB here at work. I''ll test it when I get home; in the mean time, here are some things to check:

1) what are your scale units? are you certain that they are pixels?
2) do you have an image loaded into the picture box? i''m guessing you do.
3) are you sure you can Blt to the form itself? I remember always using a picture box as my final destination (I don''t remember why though).

My best guess...

I''m wondering, does the Load function get called before your image is loaded into the picture box? try adding a button to your form that you can click on so that you are certain that the image has been loaded into the picture box.

If your form has an .hDC property, then you do not need to call GetDC. You can just use From1.hDC (or Me.hDC).

Also, why load an image into a picture box, then copy it to a buffer? Are you just doing this for testing purposes?

##### Share on other sites
quote:
Original post by Mike
1) what are your scale units? are you certain that they are pixels?
2) do you have an image loaded into the picture box? i''m guessing you do.
3) are you sure you can Blt to the form itself? I remember always using a picture box as my final destination (I don''t remember why though).

My best guess...

I''m wondering, does the Load function get called before your image is loaded into the picture box? try adding a button to your form that you can click on so that you are certain that the image has been loaded into the picture box.

If your form has an .hDC property, then you do not need to call GetDC. You can just use From1.hDC (or Me.hDC).

Also, why load an image into a picture box, then copy it to a buffer? Are you just doing this for testing purposes?

I have updated the code to this and it still comes up with the same black box:
  Option ExplicitPrivate Sub Command1_Click()Dim buffer As LongDim temp As Longbuffer = CreateCompatibleDC(hdc)temp = CreateCompatibleBitmap(buffer, Picture1.ScaleWidth, Picture1.ScaleHeight)SelectObject buffer, tempDeleteObject tempBitBlt buffer, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, Picture1.hdc, 0, 0, SRCCOPYBitBlt Me.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, buffer, 0, 0, SRCCOPYForm1.RefreshDeleteDC bufferEnd Sub

I''m certain everythings in pixels. I have a loaded image and I just tried it with a PictureBox and it came up with the same thing.
BTW - Thanx for all your help.

##### Share on other sites
Well... I''m not sure what the problem is. My only remaining recomendations are to change the HDC you use in the call to CreateCompatibleBitmap to the HDC of the form instead of the buffer, and try hard coding in the numbers.

When I get home from work I''ll try it out and see what I can come up with.

##### Share on other sites
I figured it out!
I was fiddling around with the code and trying anything. The first argument of CreateCompatibleBitmap should NOT be the buffer dc created by CreateCompatibleDC, it should be the form''s DC.
Thanks for all your help, Mike, now I can get on with the more interesting parts of my game. It''s amazing how sometimes games get stuck over little things.

Shalom

##### Share on other sites
WARNING! You rlast posted code LEAKS the bitmap. You cannot call DeleteObject() on an object selected into a DC. You must first either seelct the original bitmap back into the DC (return value of SelectObject) or SaveDC/RestoreDC like I showed you in my code. It may be minor in a simple app, but if you paint hundreds of times, your display/system will start to get wierd because of the GDI handles being eaten up.

##### Share on other sites
Thanks for that information, Mr Ekted. That''s actually quite important because I''m writing an isometric engine which involves hundreds of tiles. Though it''s incovenient because it means I''ll have to keep track of all the hold stuff that was selected out of the DC, but I suppose that only means a few more lines of code.

##### Share on other sites
I don''t want any memory leaks or extra private class variables, so please tell me if this hypothetical class is correct:

  class MakeDC{ private: HDC DC; Whatever buffer; //In VB the variable types are all Whatever oldContents; //long anyways, I don''t need a //real format MakeDC(); ~MakeDC(); //I don''t remember the C++ syntax for destructors};MakeDC::MakeDC(){ DC=CreateCompatibleDC(MyWindowDC); buffer=CreateCompatibleDC(MyWindowDC, MyWidth, MyHeight); oldContents=SelectObject(DC,buffer);}MakeDC::~MakeDC() { SelectObject(DC,oldContents); DeleteObject(buffer); DeleteDC(DC);}

So, am I correct in saying that that covers all memory leaks?
Thanks, everyone, for their help.

##### Share on other sites
you class seems to be correct (except you for you typo in the second line of the constructor... it should be createcompatiblebitmap).

Good call on the mistake in my code; i knew i was forgetting something.

##### Share on other sites
You don''t need to specify an existing DC to CreateCompatibleDC. Passing 0 to it is easy and valid.

##### Share on other sites
Saving and restoring the BITMAP alone is not sufficient in all cases. You need to restore PEN, BRUSH, PALETTE, FONT, and REGION. If you know you are only calling SelectObject() on the BITMAP, then what you have is fine. However, I really recommend making your class use "int SaveDC(HDC)" and "BOOL RestoreDC(HDC, int)" to make it generic.