aewarnick Posted June 25, 2003 Posted June 25, 2003 public static void DrawBitBlt(Graphics g, Bitmap bmp, ref Rectangle destRec) { IntPtr hDC= g.GetHdc(); IntPtr offscreenDC= a.Api.CreateCompatibleDC(hDC); a.Api.SelectObject(offscreenDC, bmp.GetHbitmap()); if(bmp.Width==destRec.Width && bmp.Height==destRec.Height) a.Api.BitBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, SrcCopy); else a.Api.StretchBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, bmp.Width, bmp.Height, SrcCopy); a.Api.DeleteDC(offscreenDC); g.ReleaseHdc(hDC); } I am hoping someone here can pinpoint where it is. Quote C#
*Experts* Volte Posted June 25, 2003 *Experts* Posted June 25, 2003 Try replacing this like:a.Api.SelectObject(offscreenDC, bmp.GetHbitmap());with this:a.Api.DeleteObject(a.Api.SelectObject(offscreenDC, bmp.GetHbitmap()));Define DeleteObject if it's not already part of your API class. :) Also, you can use if (bmp.Size.Equals(destRect.Size)) {I believe, for your size check. Quote
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 That did the trick. Thanks VF! I have one more question to ask about BitBlt. I'll post a new thread right now. I couldn't find anything on the net about it. Quote C#
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 This doesn't make sense! Why is the IntPtr returned here: IntPtr objectPtr= a.Api.SelectObject(offscreenDC, bmp.GetHbitmap()); different from the one returned below? Quote C#
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 public static void DrawBitBlt(Graphics g, Bitmap bmp, ref Rectangle destRec) { IntPtr hDC= g.GetHdc(); IntPtr offscreenDC= a.Api.CreateCompatibleDC(hDC); IntPtr objectPtr= a.Api.SelectObject(offscreenDC, bmp.GetHbitmap()); if(bmp.Width==destRec.Width && bmp.Height==destRec.Height) a.Api.BitBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, SrcCopy); else a.Api.StretchBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, bmp.Width, bmp.Height, SrcCopy); a.Api.DeleteObject(objectPtr); a.MB.ShowDialog(objectPtr+" "+a.Api.SelectObject(offscreenDC, bmp.GetHbitmap())); a.Api.DeleteDC(offscreenDC); g.ReleaseHdc(hDC); } My custom messageBox (MB) shows the results. Quote C#
*Experts* Volte Posted June 25, 2003 *Experts* Posted June 25, 2003 Because you've already selected the new object into it. At first, you are returning the handle to the bitmap stored in the DC into a variable. Then you are replacing the handle in the DC with a new bitmap's handle. So it's like this: Before objectPtr is nothing Handle in offscreenDC = xxxxxx Handle of bmp = yyyyyy Your 'objectPtr = ' statement here After objectPtr = xxxxx Handle in offscreenDC = yyyyyy Handle of bmp = yyyyyy So naturally, when you retrieve the handle in offscreenDC it will be different than it initially was. The second time around it returns the handle of bmp, instead of the handle of the placeholder in offscreenDC. Quote
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 I guess I'll have to read up on how SelectObject works. Quote C#
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 THE LEAK IS BACK! I don't know how or why. public static void DrawBitBlt(Graphics g, Bitmap bmp, ref Rectangle destRec) { IntPtr hDC= g.GetHdc(); IntPtr offscreenDC= a.Api.CreateCompatibleDC(hDC); a.Api.SelectObject(offscreenDC, bmp.GetHbitmap()); if(bmp.Size.Equals(destRec.Size)) a.Api.BitBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, SrcCopy); else a.Api.StretchBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, bmp.Width, bmp.Height, SrcCopy); a.Api.DeleteObject(a.Api.SelectObject(offscreenDC, bmp.GetHbitmap())); a.Api.DeleteDC(offscreenDC); g.ReleaseHdc(hDC); } Quote C#
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 THE LEAK IS BACK! I don't know how or why. public static void DrawBitBlt(Graphics g, Bitmap bmp, ref Rectangle destRec) { IntPtr hDC= g.GetHdc(); IntPtr offscreenDC= a.Api.CreateCompatibleDC(hDC); a.Api.SelectObject(offscreenDC, bmp.GetHbitmap()); if(bmp.Size.Equals(destRec.Size)) a.Api.BitBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, SrcCopy); else a.Api.StretchBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, bmp.Width, bmp.Height, SrcCopy); a.Api.DeleteObject(a.Api.SelectObject(offscreenDC, bmp.GetHbitmap())); a.Api.DeleteDC(offscreenDC); g.ReleaseHdc(hDC); } The return value of DeleteObject is 1 meaning success. Quote C#
*Experts* Volte Posted June 25, 2003 *Experts* Posted June 25, 2003 Replace the first SelectObject line with the second one, and then remove the second one from the bottom; once you use SelectObject, the handle in the DC changes, so SelectObject() will not return the same thing it did last time you used it. It basically sticks what you tell it to into the DC and returns what used to be there. If you don't do anything with it, you can't get it back later, because the new object is now in the DC, so SelectObject will return that. Quote
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 It's done and it works but it takes a while for the dumped memory to show up in the task manager. Let me see if I understand this correctly. When I call SelectObject, deleting it in the same statement it only deletes an extra object I don't need and the other it placed into the back buffer DC. Correct? Quote C#
*Experts* Volte Posted June 25, 2003 *Experts* Posted June 25, 2003 Yes, that's correct. And also, don't worry about the memory taking awhile to show up; memory allocated within a .NET app probably won't be really free until the Garbage Collector frees it up. Quote
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 That creates a major problem. When I use DrawImageUnscaled my ram stays at around 12000kb but using BitBlt it jacks up to over 40k before it is removed! Making the animation very choppy. How can I prevent this? Quote C#
*Experts* Volte Posted June 25, 2003 *Experts* Posted June 25, 2003 That doesn't seem right... paste your code again, let me make sure there are no leaks. Quote
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 public static void DrawBitBlt(Graphics g, Bitmap bmp, ref Rectangle destRec) { IntPtr hDC= g.GetHdc(); IntPtr offscreenDC= a.Api.CreateCompatibleDC(hDC); a.Api.DeleteObject(a.Api.SelectObject(offscreenDC, bmp.GetHbitmap())); if(bmp.Size.Equals(destRec.Size)) a.Api.BitBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, SrcCopy); else a.Api.StretchBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, bmp.Width, bmp.Height, SrcCopy); a.Api.DeleteDC(offscreenDC); g.ReleaseHdc(hDC); GC.Collect(); //a desparate attempt, that failed. } Quote C#
*Experts* Volte Posted June 25, 2003 *Experts* Posted June 25, 2003 Well, it seems like it should be alright... perhaps using the API so much (I assume you are using it in some sort of loop, meaning calling it very often) it taking its toll on .NET... it is unmanaged afterall. divil would know better than I on this one, I think. Quote
aewarnick Posted June 25, 2003 Author Posted June 25, 2003 (edited) Here is the whole project. Maybe you will get different results. It is very simple. Not much code in the main form. At the bottom of Form1 (the main form) you will see this: //a.Api.DrawBitBlt(e.Graphics, B, ref this.posRec); e.Graphics.DrawImageUnscaled(B, this.posRec); Just alternate them to test. You will notice also, that the form closes 50 times faster when the api is not used.game.zip Edited June 25, 2003 by aewarnick Quote C#
*Gurus* divil Posted June 26, 2003 *Gurus* Posted June 26, 2003 Here's the correct way of doing it, making sure everything used is cleaned up properly. public static void DrawBitBlt(Graphics g, Bitmap bmp, ref Rectangle destRec) { // Get DC handle and create a compatible one IntPtr hDC= g.GetHdc(); IntPtr offscreenDC= a.Api.CreateCompatibleDC(hDC); // Select our bitmap in to DC, recording what was there before IntPtr hBitmap = bmp.GetHbitmap(); IntPtr oldObject = a.Api.SelectObject(offscreenDC, hBitmap); // Perform blt if(bmp.Size.Equals(destRec.Size)) a.Api.BitBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, SrcCopy); else a.Api.StretchBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, bmp.Width, bmp.Height, SrcCopy); // Select our bitmap object back out of the DC a.Api.SelectObject(offscreenDC, oldObject); // Delete our bitmap a.Api.DeleteObject(hBitmap); // Delete memory DC and release our DC handle a.Api.DeleteDC(offscreenDC); g.ReleaseHdc(hDC); } Quote MVP, Visual Developer - .NET Now you see why evil will always triumph - because good is dumb. My free .NET Windows Forms Controls and Articles
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.