The MASM Forum

Miscellaneous => Miscellaneous Projects => Topic started by: avcaballero on April 28, 2013, 09:31:50 PM

Title: My Windows Graphics Tutorial
Post by: avcaballero on April 28, 2013, 09:31:50 PM
Well Gunther, what stress, guy ;). I've finally released my tutorial on Windows graphics (http://abreojosensamblador.net/Productos/AOWG/). It
is not finished at all, but... well, here it is... I hope you all like it. I keep on working on it... I did it in a hurry so, maybe it may has anything wrong (broken links, etc) ... Only in Spanish for now, sorry, only a bit translated to English...

Regards
Title: Re: My Windos Graphics Tutorial
Post by: Gunther on April 28, 2013, 09:40:37 PM
Hi Alfonso,

looks nice and interesting. Thank you.  :t We need to torment the translation program. But never mind.

Gunther
Title: Re: My Windos Graphics Tutorial
Post by: dedndave on April 28, 2013, 10:32:13 PM
great, Alfonso - i'll have a look   :t
Title: Re: My Windos Graphics Tutorial
Post by: Vortex on April 29, 2013, 04:48:13 AM
Hi Alfonso,

Thanks for your contribution.
Title: Re: My Windos Graphics Tutorial
Post by: Siekmanski on April 29, 2013, 04:26:05 PM
Hi Alfonso,

COOL  8)
Title: Re: My Windos Graphics Tutorial
Post by: avcaballero on July 02, 2013, 04:34:39 PM
Hello, I have updated my graphics tuto with the latest demos. Of course, not finished, many things to do yet. Only in Spanish, English version is for the previous one, so deprecated for the moment, till I have time to translate it.

Regards
Title: Re: My Windos Graphics Tutorial
Post by: Gunther on July 02, 2013, 09:53:26 PM
Thank you Alfonso. Great work.  :t

Gunther
Title: Re: My Windos Graphics Tutorial
Post by: avcaballero on August 19, 2013, 04:38:40 AM
Hello there, if anyone interested I've just uploaded my updated tuto on GDI Win graphics.

There are here many new stuff from the last one though many to do yet, including translating

it to English, but I'm getting more lazy to work on it, though surely I will keep on making

things for it. In the other hand, there're many things that I've removed from the downloable

version, that may be not in the interest of anybody.

Now you can download the entire tuto from here (http://www.abreojosensamblador.net/Productos/AOWG/html/Pags/Descargar.html).

Also you can download the libs from here (http://www.abreojosensamblador.net/Foro.php?nivel=1&padre=5&accion=0), but you need login first in my forum. The

registering is 100% free, but you have to provide a valid email to complete it. I did it

just for have an idea of how many times it was downloaded (at least one time for my checking

;) ) and by who... I know, I know, you are rather shy and can't do it. Never mind, many

codes really don't need libs...

Besides, there're many new things from last one.

Oops, I must say that the libs have failed while downloading, I will check it as soon as I

can :)

In the end... Good fun
Title: Re: My Windows Graphics Tutorial
Post by: avcaballero on September 05, 2013, 09:45:43 PM
Updated with a new chapter (http://www.abreojosensamblador.net/Productos/AOWG/html/Pags_en/Chap06.html) about optimizations. Only in TinyC and no exe, just c files uploaded. Any suggestion?

Regards
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on September 05, 2013, 10:07:30 PM
one of the things that i found was to do your drawing on a DIB section with a controlled bit-depth
some programmers like to use a 32-bit DIB section to draw on - because addressing is simple
if you use CreateCompatibleBitmap, the bitmap bit-depth is dependant on the user display settings
on my machine, i have my display setttings set to 32-bit, so it creates a 32-bit bitmap
while addressing pixels might be simpler in a 32-bit bitmap, it can be slow as hell - lol

in this particular app, i am using FloodFillEx for part of the image
and, 256 colors is plenty
when i changed from CreateCompatibleBitmap to CreateDIBSection, using a 24-bit DIB,
the flood fill was 6 times faster
and, faster still using a 256-color DIB

i am talking about the back-buffer/memory DC that you draw on before you blit to the display DC

of course, you have probably covered this in another section.....
but, i want to mention returning the DC to original state before deleting it

some functions return the original value/state when called
functions like SetBkMode, etc
but, the documentation does not say it should be restored
i think it is a good idea to do so, however

one way to restore a DC is to use SaveDC/RestoreDC
these functions will save DC states in a stack-like manner (LIFO)
simpler and probably a little faster than calling several SelectObject's   :P
Title: Re: My Windows Graphics Tutorial
Post by: avcaballero on September 05, 2013, 10:25:10 PM
Thank you Dave, I'll have a look :t
Title: Re: My Windows Graphics Tutorial
Post by: avcaballero on September 09, 2013, 05:39:59 PM
Hello, Dave. Thanks a lot. When I started this project I tried to do the same, dumping the DIB buffer directly to the main window device context, but after several tries I decided that I did not able to do it, thus from there it is that I first dump dib to bmp and then bmp to hdc |o| and go on to work... Good, now it works, just one step for dumping dib to hdc !!  What the hell did I before for it didn't work...? Hmmm, never mind, it works... lightning fast ;)

I owe you a beer!  :biggrin:  :t


By the way, does any one know if these examples works in Win mobiles phones? or tablets, etc... Mine is Android... Thank you.
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on September 09, 2013, 10:31:22 PM
you probably got better at writing GDI code while writing the tutorial   :t

i have had similar experiences...
like, if you try to create the back-buffer DC as compatible to something other than the device DC   :P

INVOKE  BeginPaint,hWnd,addr ps
INVOKE  CreateCompatibleDC,eax
mov     hdcMem,eax
INVOKE  CreateDIBSection,ps.hdc,....
INVOKE  SelectObject,hdcMem,eax

seems to work nicely
although, i like to store hdcMem in ESI or EDI if i am going to do a lot of different things with it

many GDI functions, like SetPixel, LineTo, PolyLine, PolyBezier, etc, create a DIB section to do the work
if it's already a DIB section, it seems to save a step
Title: CreateDIBSection
Post by: jj2007 on November 24, 2013, 10:32:45 AM
I have a weird problem with CreateDIBSection:

.data
bmih   BITMAPINFOHEADER <BITMAPINFOHEADER, 400, 300, 1, 32, BI_RGB, 0, 0, 0, 0, 0>
bmiColors   RGBQUAD <0, 0, 0, 0>
bmi   BITMAPINFO <<bmih>, bmiColors>   ; OK for ML 6.15 but not for JWasm
...
.code
...
case WM_CREATE:
   invoke SetLastError, 0
   mov hDC, rv(GetDC, hWnd)      ; use handle to main window
   mov hDib, rv(CreateDIBSection, eax, addr bmi, DIB_RGB_COLORS, addr ppvBits, 0, 0)
   deb 4, "CDS", hDib, ppvBits, hDC, hWnd, $Err$()


hDC is a valid handle, but CreateDIBSection returns zero, with hDib=0, ppvBits=0, GetLastError = zero... ::)
MDSN (http://msdn.microsoft.com/en-us/library/aa926298.aspx):
QuoteReturn Value

A handle to the newly created device-independent bitmap indicates success, and *ppvBits points to the bitmap's bit values.

NULL indicates failure, and *ppvBits is NULL.

To get extended error information, call GetLastError.

Which logically excludes the case that both CreateDIBSection and GetLastError return zero :eusa_boohoo:

In addition, ML and JWasm behave contradictory:

bmih   BITMAPINFOHEADER <BITMAPINFOHEADER, 400, 300, 1, 32, BI_RGB, 0, 0, 0, 0, 0>
bmiColors   RGBQUAD <0, 0, 0, 0>      ; OK for ML and JWasm

; OK for ML 6.15 but JWasm says Structure improperly initialized: RGBQUAD
bmi   BITMAPINFO <<bmih>, bmiColors>

; OK for JWasm but ML says invalid data initializer
bmi   BITMAPINFO <<bmih>, <0, 0, 0, 0>>


Any ideas? Anybody use CreateDIBSection successfully?
Title: Re: CreateDIBSection
Post by: qWord on November 24, 2013, 11:24:29 AM
Quote from: jj2007 on November 24, 2013, 10:32:45 AMbmi   BITMAPINFO <<bmih>, bmiColors>   ; OK for ML 6.15 but not for JWasm
I've doubts that you get what you did expect.
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 24, 2013, 11:27:07 AM
i've used it a lot - though, not much for 32-bit DIB's
For 16-bpp or 32-bpp non-palletized images, the color table must be three entries long;
the entries must specify the values of the red, green, and blue bitmasks.
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 24, 2013, 11:29:07 AM
as for the RGBQUAD structure, see how Andreas defines the structure in wininc
i think Hutch has it as byte, byte, byte, byte
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 24, 2013, 11:33:34 AM
i use it mostly for 256-color and 24-bit DIB's
you have to understand that, in C, structure definition works a little differently
what i do for a 256-color structure is create a special definition
BITMAPINFO256   STRUCT
  bmiHeader       BITMAPINFOHEADER <>
;   biSize          dd ?               ;BITMAPINFOHEADER structure size
;   biWidth         dd ?               ;image width in pixels
;   biHeight        dd ?               ;signed image height in pixels
;   biPlanes        dw ?               ;= 1
;   biBitCount      dw ?               ;= 8
;   biCompression   dd ?               ;= BI_RGB
;   biSizeImage     dd ?               ;image data bytes
;   biXPelsPerMeter dd ?               ;= 0
;   biYPelsPerMeter dd ?               ;= 0
;   biClrUsed       dd ?               ;= 0
;   biClrImportant  dd ?               ;= 0
  bmiColors       RGBQUAD 256 dup(<>)
BITMAPINFO256   ENDS


that simplifies the "translation" between C and ASM
maybe you can do something similar for 32-bit, with 3 RGBQUAD's
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 24, 2013, 11:35:59 AM
also, you have to initialize biSizeImage with (400x300x4) = 480000
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 24, 2013, 11:52:20 AM
Quoteif (nCompression == BI_BITFIELDS)
                nColors = 3; // 16 or 32 bpp have 3 colors(masks) in the color table if bitfield compression
            else
                nColors = 0; // 16 or 32 bpp have no color table if no bitfield compression

https://bitbucket.org/afriza/wince-screencapture/src/c208b8fa263e/DIBSectionLite.cpp?at=tip (https://bitbucket.org/afriza/wince-screencapture/src/c208b8fa263e/DIBSectionLite.cpp?at=tip)
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 24, 2013, 12:05:58 PM
console mode
;###############################################################################################

        .XCREF
        .NoList
        INCLUDE    \Masm32\Include\Masm32rt.inc
        .List

;###############################################################################################

BITMAPINFO32    STRUCT
  bmiHeader       BITMAPINFOHEADER <>
;   biSize          dd ?               ;BITMAPINFOHEADER structure size
;   biWidth         dd ?               ;image width in pixels
;   biHeight        dd ?               ;signed image height in pixels
;   biPlanes        dw ?               ;= 1
;   biBitCount      dw ?               ;= 32
;   biCompression   dd ?               ;= BI_RGB
;   biSizeImage     dd ?               ;image data bytes
;   biXPelsPerMeter dd ?               ;= 0
;   biYPelsPerMeter dd ?               ;= 0
;   biClrUsed       dd ?               ;= 0
;   biClrImportant  dd ?               ;= 0
BITMAPINFO32    ENDS

;###############################################################################################

        .DATA

pvBits  LPVOID ?

bmi BITMAPINFO32 <<BITMAPINFOHEADER,400,300,1,32,BI_RGB,480000,0,0,0,0>>

;***********************************************************************************************

        .DATA?

;###############################################################################################

        .CODE

;***********************************************************************************************

_main   PROC

    INVOKE  GetDC,HWND_DESKTOP
    xchg    eax,ebx
    INVOKE  CreateDIBSection,ebx,offset bmi,DIB_RGB_COLORS,offset pvBits,NULL,NULL
    xchg    eax,esi
    print   uhex$(pvBits),13,10
    .if esi
        INVOKE  DeleteObject,esi
    .endif
    INVOKE  ReleaseDC,HWND_DESKTOP,ebx
    print   chr$(13,10)
    inkey
    INVOKE  ExitProcess,0

_main   ENDP

;###############################################################################################

        END     _main
Title: Re: My Windows Graphics Tutorial
Post by: jj2007 on November 24, 2013, 06:13:39 PM
Thanxalot, Dave, it works (and even without setting biSizeImage) :t

So effectively, you are only passing a header struct with no RGBQUAD, right? This works exactly as your version:
bmi BITMAPINFOHEADER <BITMAPINFOHEADER,400,300,1,32,BI_RGB,0,0,0,0,0>
::)
Title: Re: My Windows Graphics Tutorial
Post by: TWell on November 24, 2013, 08:03:37 PM
After succesfull call to CreateDIBSection(), call GetDIBits() 0 in lpvBits to get biSizeImage
or use GetObject() with DIBSECTION.
Example in C:#define WIN32_LEAN_AND_MEAN
#include <windows.h>

int __cdecl WinMainCRTStartup(void)
{
BITMAPINFO bmi = {{sizeof(BITMAPINFOHEADER),200,200,1,32},};
RGBQUAD *prgbBits;
HDC hdcWin = GetDC(0);
HBITMAP hbm = CreateDIBSection(hdcWin, (BITMAPINFO *)&bmi,
DIB_RGB_COLORS, (void *)(&prgbBits), NULL, 0);
if (hbm) {
BITMAPFILEHEADER bfh = {0x4D42};
DIBSECTION ds;
GetObject(hbm, sizeof(DIBSECTION), &ds);
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bfh.bfSize = bfh.bfOffBits + ds.dsBmih.biSizeImage;
HANDLE hFile = CreateFile("TestDIB3.bmp", GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwWritten = 0;
WriteFile( hFile, &bfh, sizeof(bfh), &dwWritten , NULL );
WriteFile( hFile, &ds.dsBmih, sizeof(BITMAPINFOHEADER), &dwWritten, NULL );
WriteFile( hFile, ds.dsBm.bmBits, ds.dsBmih.biSizeImage, &dwWritten, NULL );
CloseHandle( hFile );
DeleteObject(hbm);
}
ReleaseDC(0, hdcWin);
ExitProcess(0);
}
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 24, 2013, 08:14:11 PM
ok - i have always pre-calculated biSizeImage
and - i may continue to do so, because that's how it's documented - lol
still interesting to note - maybe we can test that on various OS versions with different DIB bit-depths

but, that's how msdn documentation is
they're the ones that told us we need 3 RGBQUAD's when we don't

what's a little unfortunate with the CreateDIBSection function is that
we don't pass a total structure size - that would tell us for sure if we needed the bitmasks
i do know that, for 256-color images, the 4th byte of all RGBQUAD's must be 0 or the call will fail
just now, i tried the code above with 4 0FFFFFFFFh dword's following the structure
it created the DIB section, so we may be in good shape

i guess the one i haven't tried is 16 bpp
maybe playing with that one will give us some insight   :P
Title: Re: My Windows Graphics Tutorial
Post by: jj2007 on November 24, 2013, 08:49:52 PM
Now I found a solution that looks correct, and works with both ML and JWasm:

bmi   BITMAPINFO <{BITMAPINFOHEADER, bWidth, bHeight, 1, 32, BI_RGB, bWidth*bHeight, 0, 0, 0, 0}, {}>
...
   mov hDC, rv(GetDC, hWnd)      ; use handle to main window
   mov hDib, rv(CreateDIBSection, eax, addr bmi, DIB_RGB_COLORS, addr ppvBits, 0, 0)


The good news is it returns a hDib.
The bad news is that GetLastError returns ERROR_NOT_ENOUGH_MEMORY.

But, following strictly the MSDN logic, this is not an error. It's just the crappy behaviour of a WinAPI that encounters an internal insignificant error but decides not to reset the error state in order to scare away the hobby coder :eusa_boohoo:
Title: Re: My Windows Graphics Tutorial
Post by: TWell on November 24, 2013, 09:05:48 PM
size is bWidth*bHeight*4 ?
Title: Re: My Windows Graphics Tutorial
Post by: jj2007 on November 24, 2013, 09:20:50 PM
Quote from: TWell on November 24, 2013, 09:05:48 PM
size is bWidth*bHeight*4 ?

Right :t
But it doesn't change the behaviour: non-zero hDib but complaints in GetLastError.
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 24, 2013, 10:05:21 PM
if EAX is non-zero, then GetLastError returns undefined
(i.e., GetLastError is only meaningful if EAX tells you to look at it)
and - if you want to calc the size, don't forget that DIB lines are always multiples of 4 bytes
Title: Re: My Windows Graphics Tutorial
Post by: Gunther on November 24, 2013, 10:10:09 PM
Quote from: dedndave on November 24, 2013, 10:05:21 PM
if you want to calc the size, don't forget that DIB lines are always multiples of 4 bytes

I think that has to do with the BMP image format, hasn't it?

Gunther
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 24, 2013, 10:16:41 PM
the BMP image format includes (contains) a DIB
and - as far as i know, all uncompressed DIB lines are always multiples of 4 bytes
no matter what the bit-depth or image width are
Title: Re: My Windows Graphics Tutorial
Post by: Gunther on November 24, 2013, 10:39:25 PM
Dave,

Quote from: dedndave on November 24, 2013, 10:16:41 PM
the BMP image format includes (contains) a DIB
and - as far as i know, all uncompressed DIB lines are always multiples of 4 bytes
no matter what the bit-depth or image width are

yes. In a certain way, this is a waste of memory space.

Gunther
Title: Re: My Windows Graphics Tutorial
Post by: jj2007 on November 24, 2013, 11:11:53 PM
Quote from: dedndave on November 24, 2013, 10:05:21 PM
if EAX is non-zero, then GetLastError returns undefined
(i.e., GetLastError is only meaningful if EAX tells you to look at it)
I know, but it's still very irritating to see that particular "not enough memory" error in this context. Plain stupid, dear friends in Richmond :eusa_naughty:

Quoteand - if you want to calc the size, don't forget that DIB lines are always multiples of 4 bytes
as TWell rightly mentioned, see above; however, it works fine without the size.

Working example (plain Masm32) attached. Something's wrong with RGB - it turns out as BGR...
Title: Re: My Windows Graphics Tutorial
Post by: TWell on November 24, 2013, 11:43:48 PM
Quote from: Gunther on November 24, 2013, 10:39:25 PM
yes. In a certain way, this is a waste of memory space.

Gunther
Performance/aligning reasons.
Quote from: dedndave on November 24, 2013, 10:16:41 PM
the BMP image format includes (contains) a DIB
and - as far as i know, all uncompressed DIB lines are always multiples of 4 bytes
no matter what the bit-depth or image width are
24-bit DIB biSizeImage ?    // Calculate the image size in bytes
    bmpInfoHeader.biSizeImage = lWidth * lHeight * (wBitsPerPixel/8);
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 25, 2013, 03:05:17 AM
the bytes in a DIB data area, as well as in a palette, are ordered B,G,R,(A)

also, if the biHeight member is positive, the top line of the image is at the higher address
if you assign it as a negative number, the bitmap is "right-side-up"
supposedly, you cannot compress a "right-side-up" image (don't ask me why - lol)

i have been meaning to make some measurements to see if blitting a "right-side-up" image is faster
probably no difference

anyways - all of this was inherited from win1 days (or earlier)
some microsoft guy had his upside-down hat on, that day
Title: Re: My Windows Graphics Tutorial
Post by: avcaballero on November 25, 2013, 07:21:53 PM
Hello, I've missed this debate, ... not much time lately... If what you want is an example of mandelbrot in win32 asm, you can get this one (http://forum.nasm.us/index.php?topic=1635.msg6945#msg6945) that I developped in nasmx

Don't know if you want to do your work by yourself, but why don't use my examples as a starting point ?... Get the code, modify it on your needs, maybe the better way ?...

Regards

PS. If you want, I can look for it and upload it here
Title: Re: My Windows Graphics Tutorial
Post by: Gunther on November 26, 2013, 05:17:25 AM
Hi Alfonso,

Quote from: avcaballero on November 25, 2013, 07:21:53 PM
Hello, I've missed this debate, ... not much time lately... If what you want is an example of mandelbrot in win32 asm, you can get this one (http://forum.nasm.us/index.php?topic=1635.msg6945#msg6945) that I developped in nasmx

good idea, but the provided link hides your attachment. What about posting it here again?

Gunther
Title: Re: My Windows Graphics Tutorial
Post by: avcaballero on November 26, 2013, 07:20:49 PM
Here it goes, Gunther :icon_cool:

By the way, it is no need to create a bmp buffer, you just need a dib section (this source is dated before the dedndave's tip (thank you dave) ;) :

Quote
     case WM_PAINT :
          {
              hdc = BeginPaint(hWnd, &ps);
              //PintaObjeto ();
              bResult = BitBlt(hdc, 0, 0, cdXSize, cdYSize, bufDIBDC, 0, 0, SRCCOPY);
              EndPaint(hWnd, &ps);
              return 0 ;
          }
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 26, 2013, 08:38:49 PM
works under XP SP3, Alfonso   :t

too bad it's Nasm, though - lol
Title: Re: My Windows Graphics Tutorial
Post by: avcaballero on November 26, 2013, 09:39:22 PM
Thank you Dave, my idea was to do all the tuto in masm, nasm, fasm and tinyc, but time is short...
Title: Re: My Windows Graphics Tutorial
Post by: dedndave on November 26, 2013, 09:42:22 PM
looking at the Nasm code - not too hard to understand   :P
Title: Re: My Windows Graphics Tutorial
Post by: FORTRANS on November 27, 2013, 12:37:39 AM
Hi,

   Runs on Windows 2000.  The code looks reasonable.  The decent
amount of comments does help.

Cheers,

Steve N.
Title: Re: My Windows Graphics Tutorial
Post by: Gunther on November 27, 2013, 04:30:26 AM
Thank you Alfonso. Works fine under Windows 7.

Quote from: dedndave on November 26, 2013, 08:38:49 PM
too bad it's Nasm, though - lol

It's not to hard to translate it into MASM syntax.

Gunther
Title: SetDIBitsToDevice slower than BitBlt
Post by: jj2007 on November 27, 2013, 07:15:22 PM
Some bits for the graphics tutorial: I've done some testing with the Mandelbrot code (http://masm32.com/board/index.php?topic=2598.msg27977#msg27977). Inter alia, it turns out that BitBlt is about 5% faster than SetDIBitsToDevice:

  CASE WM_PAINT
   invoke BeginPaint, hWnd, addr ps
     NanoTimer() ; MasmBasic macro - any other timer will be fine, too
     if 1      ; 1987 microseconds
      invoke SetDIBitsToDevice, hDC, 0, 0, rc.right, rc.bottom, 0, 0, 0, rc.bottom, ppvBits, offset bmi, DIB_RGB_COLORS
     else      ; 1880 us
      invoke BitBlt, hDC, 0, 0, rc.right, rc.bottom, hDC, 0, 0, SRCCOPY
   endif
   add ntSum, NanoTimer(us)  ; calculate the average
   inc ntCt
   push ntSum
   fild stack
   fidiv ntCt
   deb 4, "Paint", ST(0)  ; show average in microseconds
   fstp st
   invoke EndPaint, hWnd, addr ps


Another observation is that you don't really need a compatible memory DC when working with a DIB:

  CASE WM_SIZE   ; adjust painting rectangle (on resizing problems)
   mov edi, offset rc.right
   movzx eax, word ptr lParam   ; width of client area
   stosd
   push eax
   movzx eax, word ptr lParam+2   ; height
   stosd
   mov edi, offset bmi.bmiHeader.biHeight
   neg eax
   stosd
   pop [edi-8]   ; .biWidth
   mov ecx, oldDib
   jecxz @F
   invoke SelectObject, hDC, ecx   ; de-select,
   ; invoke DeleteDC, hMemDC   ; delete DC,
   invoke DeleteObject, hDib   ; delete old DIB
@@:   ; after a window size change, setup a new bitmap:
   ; mov hMemDC, rv(CreateCompatibleDC, hDC)
   mov hDib, rv(CreateDIBSection, hDC, addr bmi, DIB_RGB_COLORS, addr ppvBits, 0, 0)
   mov oldDib, rv(SelectObject, hDC, eax)


Works fine, but not with BitBlt, only with SetDIBitsToDevice. And it is 5-10% slower than the version with a compatible DC.