blitting with bitblt, again

snarfblam

Mega-Ultra Chicken
Joined
Jun 10, 2003
Messages
1,832
Location
USA
User Rank
*Expert*
I am making a user control in vb.net. I am trying to use GDI, however, to handle the blitting, since GDI is faster.

I am using the hdcs that i retreive from graphics objects to pass to bitblt, and bitblt return values indicate a successful blit. But after I release the hdcs and try to display the bitmap on the screen, i get nothing but blackness.

It works, however with GDI+ functions.

Here is the GDI+ Version

Code:
    Dim Source As New Bitmap("D:\Visual studio projects\console\LEDWindows.bmp")
    Dim GSource As Graphics = Graphics.FromImage(Source)
    Dim hDCSource As IntPtr

    Dim Persist As Bitmap
    Dim GPersist As Graphics
    Dim hDCPersist As IntPtr 

    Private Sub NewSize()
        Dim i, j As Integer
        Persist = New Bitmap(m_ConsoleSize.Width * 12, m_ConsoleSize.Height * 20)
        GPersist = Graphics.FromImage(Persist)

        For i = 0 To m_ConsoleSize.Width - 1
            For j = 0 To m_ConsoleSize.Height - 1
                GPersist.DrawImage(Source, i * CharWidth, j * CharHeight, New Rectangle(0, 40, 12, 20), GraphicsUnit.Pixel)
            Next
        Next

        Me.BackgroundImage = Persist
        Me.Refresh()
    End Sub

Here is the GDI Version
Code:
    Dim Source As New Bitmap("D:\Visual studio projects\console\LEDWindows.bmp")
    Dim GSource As Graphics = Graphics.FromImage(Source)
    Dim hDCSource As IntPtr

    Dim Persist As Bitmap
    Dim GPersist As Graphics
    Dim hDCPersist As IntPtr 

    Private Sub NewSize()
        Dim i, j As Integer
        Persist = New Bitmap(m_ConsoleSize.Width * 12, m_ConsoleSize.Height * 20, Imaging.PixelFormat.Format24bppRgb)
        GPersist = Graphics.FromImage(Persist)
        hDCPersist = GPersist.GetHdc
        hDCSource = GSource.GetHdc

        For i = 0 To m_ConsoleSize.Width - 1
            For j = 0 To m_ConsoleSize.Height - 1
                BitBlt(hDCPersist, i * CharWidth, j * CharHeight, 12, 20, hDCSource, 0, 40, vbSrcCopy)
            Next
        Next

        GPersist.ReleaseHdc(hDCPersist)
        GSource.ReleaseHdc(hDCSource)
        Me.BackgroundImage = Persist
        Me.Refresh()
    End Sub

Note that the only difference is that the GDI+ version uses drawimage() and the GDI version grabs the hdcs, uses bitblt(), then releases the hdcs, which would be the GDI equivalent, so I cant figure out why this wont work.
 
If you are making a control, just stick with GDI+. GDI32 is faster, but you wont notice it in a control like this (you would only notice it in a graphic intensive application, like a game, and its possible that in the case of many many calls to the GDI32, GDI+ would end up being faster).

Recently there has been a lot of discussion about "Oh, GDI32 is faster than GDI+", but that doesnt mean you should use GDI32 instead of GDI+; GDI+ is a managed part of the .NET Framework that .NET natively supports, while GDI32 requires calls to GDI32.DLL.

When I tested it, the speed ratio was about 5:1 - it took about 500ms to draw 2000 images with DrawImage, and about 100ms to draw 2000 images with BitBlt. In that case, it would probably take around 0.25ms to draw with DrawImage and 0.05ms to draw with BitBlt. Not a big deal at all.
 
Ok, dont start this.

I am making up to, depending on the size of the control, up to 3200 calls to the blitting function (generally more like 480). Thats graphic intensive. There is a noticable lag when the control is initially drawn, or when the size is changed. I dont want that, and I am NOT using GDI+.

In the case of many, many calls to GDI+ vs GDI, GDI wins. No question about it. Ive made many applications like this in vb6 with no visible lag, and a few in .net with GDI+, ALWAYS with visible lag.

And why would i mind calling GDI32.dll? And what is wrong with calling unmanaged code that is not part of .net?

To me it is a big deal, i want my programs to run smoothly.

Please, no one tell me not to use GDI. I want to use GDI. When GDI+ is appropriate, as in drawing only a few images, or performing skewing and stretching effects, etc., i will GLADLY use GDI+. But I want to use GDI, it does exactly what I want it to with no unwanted side effects. So PLEASE dont tell me to use GDI+ or DirectX. Pretty please?
 
Heh, OK, I didnt realize you were the one that wed already had this discussion with. From your code, it didnt look like it was being called that many times.

Have you declared vbSrcCopy as anything? If Option Explicit is not on, then that will evaluate to 0. vbSrcCopy is not a constant in .NET.
 
Yeah, thats me.

Anyways, I always use option explicit, and all my constants are declared. I got the value of vbSrcCopy from vb6.

Also, Im an idiot. I copied the bitblt declaration for vb6 and didnt change the parameters from longs to integers. I fixed it though, and it is still behaving the same.
 
Oops. I know why this doesnt work.

HDCs aquired from graphics objects backed by bitmaps (like my bitmap named Source) are meant to be write only. You cant copy graphics from them, or you will turn up with blackness.

So I need to create a GDI compatible source DC.
 
In future, can all GDI questions be posted in the Interop forum, thanks.
 
Polymorpher said:
could you please tell me the value of vbSrcCopy? I have been looking everywhere.
Google Search: The first link has the answer. vbSourceCopy is the same as the Windows API SRCCOPY constant.

In the future, new questions should generally go in new threads.
 
I know this is an old thread, but I found this use of bitblt in C# on the web a while ago if its of any help.

C#:
public static void DrawBitBlt(Graphics g, Bitmap bmp, ref Rectangle destRec)
{
	IntPtr hDC = g.GetHdc();
	IntPtr hBmp = bmp.GetHbitmap();

	IntPtr ImageDC= a.Api.CreateCompatibleDC(hDC);
	IntPtr offscreenDC= a.Api.CreateCompatibleDC(hDC);

	IntPtr drawBmp= a.Api.CreateCompatibleBitmap(hDC, destRec.Size.Width, destRec.Size.Height);

	IntPtr oldBmp= a.Api.SelectObject(ImageDC, hBmp);
	IntPtr oldDrawBmp= a.Api.SelectObject(offscreenDC, drawBmp);

	if(bmp.Size.Equals(destRec.Size))
	{
		a.Api.BitBlt(offscreenDC, 0, 0, destRec.Width, destRec.Height, ImageDC, 0, 0, SrcCopy);
	}
	else
		a.Api.StretchBlt(offscreenDC, 0, 0, destRec.Width, destRec.Height, ImageDC, 0, 0, bmp.Width, bmp.Height, SrcCopy);

	a.Api.BitBlt(hDC, destRec.X, destRec.Y, destRec.Width, destRec.Height, offscreenDC, 0, 0, SrcCopy);

	a.Api.SelectObject(ImageDC, oldBmp);
	a.Api.DeleteObject(hBmp);

	a.Api.SelectObject(offscreenDC, oldDrawBmp);
	a.Api.DeleteObject(drawBmp);

	a.Api.DeleteDC(ImageDC);
	a.Api.DeleteDC(offscreenDC);

	g.ReleaseHdc(hDC);
}
 
Back
Top