Die Community zu .NET und Classic VB.
Menü

VB 5/6-Tipp 0470: Form-Regions anhand einer Bitmap erstellen

 von 

Beschreibung 

Unter Windows 2000/XP geht dies mit der API SetLayeredWindowAttributes. Mit Hilfe dieses Moduls können sie dies auch unter älteren Windows Versionen machen! Und das sehr schnell, durch die Benutzung von DIBs(Device Independend Bitmaps). Die Routine erkennt, ob das Betriebssystem die API SetLayeredWindowAttributes unterstützt, und wenn nicht, macht es die Form manuell transparent. Das einzige, was Sie nur tun müssen, ist eine Farbe anzugeben, welche die Form transparent macht. Was noch beachtet werden sollte ist, dass beim Zielobjekt AutoRedraw aktiviert ist.

Schwierigkeitsgrad:

Schwierigkeitsgrad 2

Verwendete API-Aufrufe:

BitBlt, CombineRgn, CreateCompatibleDC, CreateDIBSection, CreateRectRgn, DeleteDC, DeleteObject, FreeLibrary, GetDIBits, GetModuleHandleA (GetModuleHandle), GetPixel, GetProcAddress, GetWindowLongA (GetWindowLong), LoadLibraryA (LoadLibrary), OleTranslateColor, ReleaseCapture, SelectObject, SendMessageA (SendMessage), SetLayeredWindowAttributes, SetWindowLongA (SetWindowLong), SetWindowRgn

Download:

Download des Beispielprojektes [41,38 KB]

'Dieser Quellcode stammt von http://www.activevb.de
'und kann frei verwendet werden. Für eventuelle Schäden
'wird nicht gehaftet.

'Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
'Ansonsten viel Spaß und Erfolg mit diesem Source!

'------------- Anfang Projektdatei Projekt1.vbp -------------
'--------- Anfang Formular "Form1" alias Form1.frm  ---------
' Steuerelement: Schaltfläche "Command1"
Option Explicit

Private Const WM_NCLBUTTONDOWN As Long = &HA1&
Private Const HTCAPTION As Long = 2&

Private Declare Function SendMessage Lib "user32" _
                         Alias "SendMessageA" ( _
                         ByVal hWnd As Long, _
                         ByVal wMsg As Long, _
                         ByVal wParam As Long, _
                         lParam As Any) As Long
                         
Private Declare Function ReleaseCapture Lib "user32" () As Long

Private Sub Command1_Click()
    Unload Me
End Sub

Private Sub Form_Load()
    Me.Picture = LoadPicture(App.Path & "\Back.gif")
    Me.Width = Me.ScaleX(Me.Picture.Width, vbHimetric, vbTwips)
    Me.Height = Me.ScaleY(Me.Picture.Height, vbHimetric, vbTwips)
    MakeFormTransparent Me, vbMagenta
End Sub

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
    ReleaseCapture
    SendMessage Me.hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0&
End Sub

'---------- Ende Formular "Form1" alias Form1.frm  ----------
'--- Anfang Modul "RegionFromBitmap" alias RegionFromBitmap.bas ---
' Code von Benjamin Wilger
' Benjamin@ActiveVB.de
' Copyright (C) 2001
Option Explicit

Private Declare Function CreateRectRgn Lib "gdi32" ( _
                         ByVal X1 As Long, _
                         ByVal Y1 As Long, _
                         ByVal X2 As Long, _
                         ByVal Y2 As Long) As Long
                         
Private Declare Function GetPixel Lib "gdi32" ( _
                         ByVal hDC As Long, _
                         ByVal x As Long, _
                         ByVal y As Long) As Long
                         
Private Declare Function CombineRgn Lib "gdi32" ( _
                         ByVal hDestRgn As Long, _
                         ByVal hSrcRgn1 As Long, _
                         ByVal hSrcRgn2 As Long, _
                         ByVal nCombineMode As Long) As Long
                         
Private Declare Function DeleteObject Lib "gdi32" ( _
                         ByVal hObject As Long) As Long
                         
Private Declare Function SetWindowRgn Lib "user32" ( _
                         ByVal hWnd As Long, _
                         ByVal hRgn As Long, _
                         ByVal bRedraw As Boolean) As Long
                         
Private Const RGN_OR As Long = 2&

Private Declare Sub OleTranslateColor Lib "oleaut32.dll" ( _
                    ByVal clr As Long, _
                    ByVal hpal As Long, _
                    ByRef lpcolorref As Long)
                    
Private Type BITMAPINFOHEADER
    biSize As Long
    biWidth As Long
    biHeight As Long
    biPlanes As Integer
    biBitCount As Integer
    biCompression As Long
    biSizeImage As Long
    biXPelsPerMeter As Long
    biYPelsPerMeter As Long
    biClrUsed As Long
    biClrImportant As Long
End Type

Private Type RGBQUAD
    rgbBlue As Byte
    rgbGreen As Byte
    rgbRed As Byte
    rgbReserved As Byte
End Type

Private Type BITMAPINFO
    bmiHeader As BITMAPINFOHEADER
    bmiColors As RGBQUAD
End Type

Private Declare Function CreateCompatibleDC Lib "gdi32" ( _
                         ByVal hDC As Long) As Long
                         
Private Declare Function CreateDIBSection Lib "gdi32" ( _
                         ByVal hDC As Long, _
                         pBitmapInfo As BITMAPINFO, _
                         ByVal un As Long, _
                         ByVal lplpVoid As Long, _
                         ByVal handle As Long, _
                         ByVal dw As Long) As Long
                         
Private Declare Function SelectObject Lib "gdi32" ( _
                         ByVal hDC As Long, _
                         ByVal hObject As Long) As Long
                         
Private Declare Function BitBlt Lib "gdi32" ( _
                         ByVal hDestDC As Long, _
                         ByVal x As Long, _
                         ByVal y As Long, _
                         ByVal nWidth As Long, _
                         ByVal nHeight As Long, _
                         ByVal hSrcDC As Long, _
                         ByVal xSrc As Long, _
                         ByVal ySrc As Long, _
                         ByVal dwRop As Long) As Long
                         
Private Declare Function GetDIBits Lib "gdi32" ( _
                         ByVal aHDC As Long, _
                         ByVal hBitmap As Long, _
                         ByVal nStartScan As Long, _
                         ByVal nNumScans As Long, _
                         lpBits As Any, _
                         lpBI As BITMAPINFO, _
                         ByVal wUsage As Long) As Long
                         
Private Declare Function DeleteDC Lib "gdi32" ( _
                         ByVal hDC As Long) As Long
                         
Private Const BI_RGB As Long = 0&
Private Const DIB_RGB_COLORS As Long = 0&

Private Declare Function GetModuleHandle Lib "kernel32" _
                         Alias "GetModuleHandleA" ( _
                         ByVal lpModuleName As String) As Long
                         
Private Declare Function LoadLibrary Lib "kernel32" _
                         Alias "LoadLibraryA" ( _
                         ByVal lpLibFileName As String) As Long
                         
Private Declare Function GetProcAddress Lib "kernel32" ( _
                         ByVal hModule As Long, _
                         ByVal lpProcName As String) As Long
                         
Private Declare Function FreeLibrary Lib "kernel32" ( _
                         ByVal hLibModule As Long) As Long
                         
Private Const LWA_COLORKEY As Long = &H1&
Private Const GWL_EXSTYLE As Long = (-20&)
Private Const WS_EX_LAYERED As Long = &H80000

Private Declare Function GetWindowLong Lib "user32" _
                         Alias "GetWindowLongA" ( _
                         ByVal hWnd As Long, _
                         ByVal nIndex As Long) As Long
                         
Private Declare Function SetWindowLong Lib "user32" _
                         Alias "SetWindowLongA" ( _
                         ByVal hWnd As Long, _
                         ByVal nIndex As Long, _
                         ByVal dwNewLong As Long) As Long
                         
Private Declare Function SetLayeredWindowAttributes Lib "user32" ( _
                         ByVal hWnd As Long, _
                         ByVal crKey As Long, _
                         ByVal bAlpha As Byte, _
                         ByVal dwFlags As Long) As Long
                         
Public Function MakeFormTransparent(frm As Form, ByVal lngTransColor As Long)

    Dim hRegion As Long
    Dim WinStyle As Long
    
    ' Systemfarben ggf. in RGB-Werte übersetzen
    If lngTransColor < 0 Then OleTranslateColor lngTransColor, 0&, lngTransColor
    
    ' Ab Windows 2000/98 geht das relativ einfach per API
    ' Mit IsFunctionExported wird geprüft, ob die Funktion
    ' SetLayeredWindowAttributes unter diesem Betriebsystem unterstützt wird.
    If IsFunctionExported("SetLayeredWindowAttributes", "user32") Then
    
        ' Den Fenster-Stil auf "Layered" setzen
        WinStyle = GetWindowLong(frm.hWnd, GWL_EXSTYLE)
        WinStyle = WinStyle Or WS_EX_LAYERED
        SetWindowLong frm.hWnd, GWL_EXSTYLE, WinStyle
        SetLayeredWindowAttributes frm.hWnd, lngTransColor, 0&, LWA_COLORKEY
        
    Else ' Manuell die Region erstellen und übernehmen
    
        hRegion = RegionFromBitmap(frm, lngTransColor)
        SetWindowRgn frm.hWnd, hRegion, True
        DeleteObject hRegion
        
    End If
    
End Function

Private Function RegionFromBitmap(picSource As Object, _
    ByVal lngTransColor As Long) As Long
    
    Dim lngRetr As Long, lngHeight As Long, lngWidth As Long
    Dim lngRgnFinal As Long, lngRgnTmp As Long
    Dim lngStart As Long
    Dim x As Long, y As Long
    Dim hDC As Long
    Dim bi24BitInfo As BITMAPINFO
    Dim iBitmap As Long
    Dim BWidth As Long
    Dim BHeight As Long
    Dim iDC As Long
    Dim PicBits() As Byte
    Dim Col As Long
    Dim OldScaleMode As ScaleModeConstants
    
    OldScaleMode = picSource.ScaleMode
    picSource.ScaleMode = vbPixels
    hDC = picSource.hDC
    lngWidth = picSource.ScaleWidth ' - 1
    lngHeight = picSource.ScaleHeight - 1
    BWidth = (picSource.ScaleWidth \ 4) * 4 + 4
    BHeight = picSource.ScaleHeight
    
    ' Bitmap-Header
    With bi24BitInfo.bmiHeader
    
        .biBitCount = 24
        .biCompression = BI_RGB
        .biPlanes = 1
        .biSize = Len(bi24BitInfo.bmiHeader)
        .biWidth = BWidth
        .biHeight = BHeight + 1
        
    End With
    
    ' ByteArrays in der erforderlichen Größe anlegen
    ReDim PicBits(0 To bi24BitInfo.bmiHeader.biWidth * 3 - 1, 0 To _
        bi24BitInfo.bmiHeader.biHeight - 1)
        
    iDC = CreateCompatibleDC(hDC)
    
    ' Gerätekontextunabhängige Bitmap (DIB) erzeugen
    iBitmap = CreateDIBSection(iDC, bi24BitInfo, DIB_RGB_COLORS, ByVal 0&, ByVal 0&, _
        ByVal 0&)
        
    ' iBitmap in den neuen DIB-DC wählen
    Call SelectObject(iDC, iBitmap)
    
    ' hDC des Quell-Fensters in den hDC der DIB kopieren
    Call BitBlt(iDC, 0, 0, bi24BitInfo.bmiHeader.biWidth, _
        bi24BitInfo.bmiHeader.biHeight, hDC, 0, 0, vbSrcCopy)
        
    ' Gerätekontextunabhängige Bitmap in ByteArrays kopieren
    Call GetDIBits(hDC, iBitmap, 0, bi24BitInfo.bmiHeader.biHeight, PicBits(0, 0), _
        bi24BitInfo, DIB_RGB_COLORS)
        
    ' Wir brauchen nur den Array, also können wir die Bitmap direkt wieder löschen.
    ' DIB-DC
    Call DeleteDC(iDC)
    
    ' Bitmap
    Call DeleteObject(iBitmap)
    
    lngRgnFinal = CreateRectRgn(0, 0, 0, 0)
    
    For y = 0 To lngHeight
    
        x = 0
        
        Do While x < lngWidth
        
            Do While x < lngWidth And RGB(PicBits(x * 3 + 2, lngHeight - y + 1), _
                PicBits(x * 3 + 1, lngHeight - y + 1), PicBits(x * 3, lngHeight - y + 1) _
                ) = lngTransColor
                
                x = x + 1
                
            Loop
            
            If x <= lngWidth Then
            
                lngStart = x
                
                Do While x < lngWidth And RGB(PicBits(x * 3 + 2, lngHeight - y + 1), _
                    PicBits(x * 3 + 1, lngHeight - y + 1), PicBits(x * 3, lngHeight - y _
                    + 1)) <> lngTransColor
                    
                    x = x + 1
                    
                Loop
                
                If x + 1 > lngWidth Then x = lngWidth
                
                lngRgnTmp = CreateRectRgn(lngStart, y, x, y + 1)
                lngRetr = CombineRgn(lngRgnFinal, lngRgnFinal, lngRgnTmp, RGN_OR)
                DeleteObject lngRgnTmp
                
            End If
            
        Loop
        
    Next
    
    picSource.ScaleMode = OldScaleMode
    RegionFromBitmap = lngRgnFinal
    
End Function

' Code von vbVision:
' Diese Funktion überprüft, ob die angegebene Function von einer DLL exportiert wird.
Private Function IsFunctionExported(ByVal sFunction As String, ByVal sModule As String) _
    As Boolean
    
    Dim hMod As Long, lpFunc As Long, bLibLoaded As Boolean
    
    ' Handle der DLL erhalten
    hMod = GetModuleHandle(sModule)
    
    If hMod = 0 Then ' Falls DLL nicht registriert ...
    
        hMod = LoadLibrary(sModule) ' DLL in den Speicher laden.
        
        If hMod Then bLibLoaded = True
        
    End If
    
    If hMod Then
        If GetProcAddress(hMod, sFunction) Then IsFunctionExported = True
        
    End If
    
    If bLibLoaded Then Call FreeLibrary(hMod)
    
End Function


'--- Ende Modul "RegionFromBitmap" alias RegionFromBitmap.bas ---
'-------------- Ende Projektdatei Projekt1.vbp --------------

Tipp-Kompatibilität:

Windows/VB-VersionWin32sWin95Win98WinMEWinNT4Win2000WinXP
VB4
VB5
VB6

Hat dieser Tipp auf Ihrem Betriebsystem und mit Ihrer VB-Version funktioniert?

Ja, funktioniert!

Nein, funktioniert nicht bei mir!

VB-Version:

Windows-Version:

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 9 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von TiKu am 09.02.2010 um 10:23

Der Code hat ein GDI-Handle-Leak, also ein Speicherleck. Die Bitmap iBitmap wird in einen DC selektiert, vor dem Löschen aber nicht wieder herausselektiert. Dadurch schlägt das Löschen fehl.

Kommentar von P. Soell am 08.02.2006 um 11:08

Wie kann der Code auch für MDI-Formulare verwendet werden? Sobald MDIChild auf True gesetzt wird, wird das Fenster nicht mehr durchsichtig angezeigt.

Kommentar von Reichenbach am 14.08.2005 um 19:43

Ich möchte die Form noch wahlweise in zwei Arten modifizieren:
(1) Die Form soll Eingaben (z.B. Mausclicks) auch in den transparenten Bereichen entgegennehmen.

bzw.

(2) Die Form soll die Eingaben an die darunterliegende Applikation weiterreichen, selbst aber im Vordergrund (passiv) sichtbar bleiben.

Vielen Dank für einen evtl. Tipp!!

Kommentar von Benjamin Wilger am 16.06.2005 um 09:31

Lieber Coolzero,

das Modul hat den Vorteil, dass je nachdem welches Betriebssystem verwendet wird, jeweils die beste Variante genutzt wird.
Die einfachste mir bekannte Variante ist die mit den SetLayeredWindowAttributes. Jedoch funktioniert die nur ab Win2K.

Gruß,
Benjamin

Kommentar von Coolzero am 18.02.2005 um 11:46

Also mal ehrlich,
findet Ihr nicht das das ein wenig zu aufwändig ist nur um das aussehen der Form zu ändern ???

Ich kann mich daran erinnern das es da ne einfachere Methode gibt aber weis sie eben nicht mehr.

MFG
Coolzero

Kommentar von ... am 28.07.2003 um 21:53

Die Methode ohne SetLayeredWindowAttributes hat den Vorteil, daß sie auch mit Bildboxen und wahrscheinlich allen anderen Steuerelementen funktioniert, die einen hWnd haben.

Kommentar von Frager am 20.10.2002 um 20:42

kann man das auch so verändern das das bild was als hintergrund genommen wird mit in die exe-datei eingebunden ist und nicht mehr einzeln dazu gegeben werden muß?

Kommentar von Benjamin Wilger am 19.07.2002 um 18:39

Hallo Peter,
ich habe das trotzdem aus dem Upload entfernt, weil es eben redundant ist.
Du kannst im Forum direkt auf einen Tipp verweisen, indem Du !tipXXXX schreibst. Das XXXX steht für die Tippnummer.
Beste Grüße,
Benjamin Wilger

Kommentar von Peter am 23.06.2002 um 10:49

Ähm, Sorry dass ich das ganze noch mal in den Download gestellt habe, aber im Forum hat einer danach gefragt, und ich hab dann gesucht wo das hier steht, habs aber nicht gefunden. Darum steht's halt nochmal im Download (aber nur das Modul)
Ich hoffe das macht nix!
Peter