Where do you want to go next?here's for you :)about homeopathyassorted rantsVB and subclassingVB, screensavers and security concernsLet the Skriptkiddiots play...VB and pointersVB and the Windows shellVB and multitaskingVisual Basiclibrariessnakeoil and blatant liesZoneAlarmeSafefirewall basicsabout harmful codeIn Commerce' Service - sniffersabout spywarecookie jarabout PGPabout privacymain page

Irregular windows


Have you ever wondered, how those windows are done, that are not rectangular? Without cheating. No use of *.gif on ActiveDesktop, that is.


It's quite simple, once you've got the hang of it. I found the first steps into this in "Hardcore Visual Basic". The author is Bruce McKinney and you'll find the book in the MSDN.


Sidenote of April 2000: This is no longer the case. It found it in the MSDN of October 1999 for the last time.


There's two functions to get the job done: the BitBlt (pron.: bitblit) and the PaintPicture. The first is API, the second VB, but you can use either. I talk of BitBlt here, since I'm most familar with it, but the things said apply to both.


*grin* Ah, you got me there. You could also use PutPixel...


First make a dump of the desktop window. That's the one with hwnd = 0 :) Take it as it is and store the contents, any storage with a hwnd will do. You'll have to update this storage whenever the look of the window changes. New windows are opened, others moved... Just make sure you notice it. I prefer taking an educated guess every 10 seconds or so, that won't hamper the processes too much, but your variable will be quite up to date.

I found it easiest to store the pictures I want to use in an imagelist, but... Oh well, a resource-file or putting them plainly out does the job as well.


Take a window without borders or titlebar, just the naked thing. We'll paint on the raw form now... Call BitBlt and pass the hwnd of your storage, the top and left of your window on the desktop (that takes a POINT, it's in the API-viewer), the hwnd of your window and the point of your window where you want the painting to start. Paint away and you won't see your window any longer. Uh, it's still there, but it's camouflaged now :)


Which reminds me: for debugging purposes leave the titlebar on ;)

I had another method here before, but it seems it wasn't too clear.


I always use at least two picture-boxes, one for the original picture, the other for the mask. On the form you can have every picture, just SRC_COPY it.


Okay, here's how to create the mask (remember to declare the proper API-functions):

Public Sub MakeMask()
Dim hdcMono As Long
Dim hbmpMono As Long
Dim hbmpOld As Long
Dim dxBlt As Long
Dim dyBlt As Long

    dxBlt = Scr.PBox.Width
    dyBlt = Scr.PBox.Height
   
    Scr.PBoxMask.Width = dxBlt
    Scr.PBoxMask.Height = dyBlt

    hdcMono = CreateCompatibleDC(0)
    hbmpMono = CreateCompatibleBitmap(hdcMono, dxBlt, dyBlt)
    hbmpOld = SelectObject(hdcMono, hbmpMono)
    BitBlt hdcMono, 0, 0, dxBlt, dyBlt, Scr.PBox.hdc, 0, _

0, &HCC0020

    BitBlt Scr.PBoxMask.hdc, 0, 0, dxBlt, dyBlt, hdcMono, _

0, 0, &HCC0020


    Scr.PBoxMask.Refresh


    'don't forget to clean up
    Call SelectObject(hdcMono, hbmpOld)
    Call DeleteDC(hdcMono)
    Call DeleteObject(hbmpMono)
End Sub


BitBlt the picture on the form using SRC_INVERT, bitblt over this the mask with SRC_AND and again bitblt over it the picture with SRC_INVERT.


Well, that's all of it ;) Easy and pretty, hm? Have a look at Pingu! in the downloads-section if you want to see what I did to find out how this worked.