Results 1 to 35 of 35

Thread: UpdateLayeredWindow and elliptic region (Jagged edges)

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    UpdateLayeredWindow and elliptic region (Jagged edges)

    Hi,

    I have a form and I want to make the form look circular .

    1- I use CreateEllipticRgn to create the circular region.
    2- I use CreateCompatibleBitmap (Also tried CreateDIBSection) and CreateCompatibleDC to create a memory DC.
    3- I use FillRect to draw some brush color (ex: RED) onto the memry DC.
    4- I use SelectClipRgn to select the above circular region onto the memory DC.
    5- I use UpdateLayeredWindow (ULW_COLORKEY) - This takes away the memory DC black background.

    This works and displays the form as a RED circular shape BUT the circle outline looks with jagged edges.

    Does the UpdateLayeredWindow API along with ULW_ALPHA requires the bitmap to have an Alpha channel in order to draw smooth borders ?

    Any thoughts ? Thank you.

  2. #2
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Shot in the dark here but it sounds like you need some form of anti-aliasing to smooth out the jagged edges. You should probably look into that. My GDI is a bit rusty so I can't recall if there are options for anti-aliasing.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  3. #3
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,207

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by AngelV View Post
    Does the UpdateLayeredWindow API along with ULW_ALPHA requires the bitmap to have an Alpha channel in order to draw smooth borders ?
    Yes.

    Olaf

  4. #4
    Hyperactive Member
    Join Date
    Dec 2008
    Location
    Argentina
    Posts
    439

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by AngelV View Post
    Hi,

    Does the UpdateLayeredWindow API along with ULW_ALPHA requires the bitmap to have an Alpha channel in order to draw smooth borders ?
    .
    yes and you would have to use "GDI+" since it allows SmoothingModeAntiAlias

    anyway i want to share this, but it's only for windows 10, and you can also get the gdi+ routine

    add this code to a form with BorderStyle = 0

    Code:
    Option Explicit
    Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
    Private Declare Function ReleaseCapture Lib "user32.dll" () As Long
    Private Declare Function SetWindowCompositionAttribute Lib "user32.dll" (ByVal hWnd As Long, ByRef Data As WindowsCompostionAttributeData) As Long
    Private Declare Function GdipCreateFromHDC Lib "gdiplus" (ByVal hdc As Long, ByRef graphics As Long) As Long
    Private Declare Function GdipDeleteGraphics Lib "gdiplus" (ByVal graphics As Long) As Long
    Private Declare Function GdiplusStartup Lib "gdiplus" (ByRef token As Long, ByRef lpInput As GDIPlusStartupInput, Optional ByRef lpOutput As Any) As Long
    Private Declare Function GdiplusShutdown Lib "gdiplus" (ByVal token As Long) As Long
    Private Declare Function GdipSetSmoothingMode Lib "GdiPlus.dll" (ByVal mGraphics As Long, ByVal mSmoothingMode As Long) As Long
    Private Declare Function GdipDeleteBrush Lib "GdiPlus.dll" (ByVal mBrush As Long) As Long
    Private Declare Function GdipFillEllipseI Lib "GdiPlus.dll" (ByVal mGraphics As Long, ByVal mBrush As Long, ByVal mX As Long, ByVal mY As Long, ByVal mWidth As Long, ByVal mHeight As Long) As Long
    Private Declare Function GdipCreateSolidFill Lib "GdiPlus.dll" (ByVal mColor As Long, ByRef mBrush As Long) As Long
    Private Declare Function CreateEllipticRgn Lib "gdi32.dll" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
    Private Declare Function SetWindowRgn Lib "user32.dll" (ByVal hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long
    
    Private Type GDIPlusStartupInput
        GdiPlusVersion                      As Long
        DebugEventCallback                  As Long
        SuppressBackgroundThread            As Long
        SuppressExternalCodecs              As Long
    End Type
      
    Private Const SmoothingModeAntiAlias    As Long = &H4
    
    
    Private Const WM_SYSCOMMAND As Long = &H112&
    Private Const MOUSE_MOVE As Long = &HF012&
    
    Private Type WindowsCompostionAttributeData
        Attribute As Long
        Data As Long
        SizeOfData As Long
    End Type
    
    Private Enum AccentState
        ACCENT_DISABLED = 0
        ACCENT_ENABLE_GRADIENT = 1
        ACCENT_ENABLE_TRANSPARENTGRADIENT = 2
        ACCENT_ENABLE_BLURBEHIND = 3
        ACCENT_INVALID_STATE = 4
    End Enum
    
    Const WCA_ACCENT_POLICY = 19
    
    Private Type AccentPolicy
        AccentState As AccentState
        AccentFlags As Long
        GradientColor As Long
        AnimationId As Long
    End Type
    
    Private Sub Form_Load()
        Dim Data As WindowsCompostionAttributeData
        Dim accent As AccentPolicy
        
        Me.ScaleMode = vbPixels
        Me.AutoRedraw = True
        Me.BackColor = vbBlack
        Me.Width = 5000
        Me.Height = 5000
        
        accent.AccentState = 6
        accent.AnimationId = 5
        
        Data.Attribute = WCA_ACCENT_POLICY
        Data.SizeOfData = Len(accent)
        Data.Data = VarPtr(accent)
        
      
        Call SetWindowCompositionAttribute(hWnd, Data)
        
        Dim hRgn As Long
        hRgn = CreateEllipticRgn(-5, -5, Me.ScaleWidth + 5, Me.ScaleHeight + 5)
        SetWindowRgn hWnd, hRgn, True
        
        Dim GdipToken As Long
        Dim GdipStartupInput As GDIPlusStartupInput
        Dim hGraphics As Long, hBrush As Long
        
        GdipStartupInput.GdiPlusVersion = 1&
        Call GdiplusStartup(GdipToken, GdipStartupInput, ByVal 0)
        If GdipCreateFromHDC(hdc, hGraphics) = 0 Then
            Call GdipSetSmoothingMode(hGraphics, SmoothingModeAntiAlias)
            GdipCreateSolidFill &HFFFF0000, hBrush
            GdipFillEllipseI hGraphics, hBrush, 0, 0, Me.ScaleWidth - 1, Me.ScaleHeight - 1
            GdipDeleteBrush hBrush
            GdipDeleteGraphics hGraphics
        End If
        Call GdiplusShutdown(GdipToken)
    End Sub
    
    
    Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
        ReleaseCapture
        SendMessage hWnd, WM_SYSCOMMAND, MOUSE_MOVE, 0
    End Sub
    
    Private Sub Form_DblClick()
        Unload Me
    End Sub
    leandroascierto.com Visual Basic 6 projects

  5. #5
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,720

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    another alternative is to create the circular picture in paintshop. save it as .png
    and have it load during startup.

  6. #6

  7. #7

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Thanks everyone.

    I like LeandroA's workaround. It makes coding this a lot easier. However, it won't work prior to Win10 so I can't use it in my project.

    baka suggested the use of a png image. I had already thought about that.

    I am thinking If I use a png file representing a solid colored circle image with transparent background I could then use UpdateLayeredWindow along with ULW_ALPHA to reshape the form as the circle image hence producing a round form with smooth edges. I can subsequently still draw whatever I want onto the form's DC.

    I am not sure if this is the way to go.

  8. #8

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    I have just implemented UpdateLayeredWindow on the form based on a PNG file (PNG with transparent background).

    The form was reshaped successfully as the PNG image BUT the form edges still look jagged !!

    I thought that UpdateLayeredWindow was supposed to produce smoother images\edges than SetLayeredWindowAttributes... Is that true ? It doesn't seem to be the case though.

    BTW, I have tried both: ULW_ALPHA and ULW_COLORKEY when calling UpdateLayeredWindow just in case but no difference.

    This is how the reshaped form looks based on the PNG image and using the UpdateLayeredWindow api function. I see no edges smoothness.

    Name:  xxxxxxxxxx.png
Views: 488
Size:  4.1 KB

    I see no difference in quality over using SetWindowRgn

    Am I missing something ? Any ideas ?

    EDIT:
    Also, I am using GdipSetSmoothingMode(hGraphics, SmoothingModeAntiAlias) on the memory dc but makes no difference.
    Last edited by AngelV; Jan 30th, 2023 at 03:07 AM.

  9. #9
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,720

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    the PNG image itself need to have smooth edges. its a 32bit PNG picture where u can see the edges of the circle with different opacity levels (so it kind of fade away) that will create the effect of smoothness since opacity will let the background show depending on the opacity level.

  10. #10

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by baka View Post
    the PNG image itself need to have smooth edges. its a 32bit PNG picture where u can see the edges of the circle with different opacity levels (so it kind of fade away) that will create the effect of smoothness since opacity will let the background show depending on the opacity level.
    Thanks baka.

    I just double checked the png image file (along with two other png images) and it is a 32bit PNG


    Name:  bpp.png
Views: 400
Size:  18.0 KB

  11. #11
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,720

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    the circle should be like this
    https://i.stack.imgur.com/poE8A.png
    but with transparent background.
    Im not home so I cant create one. should be easy with any paint tool.

  12. #12

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by baka View Post
    the circle should be like this
    https://i.stack.imgur.com/poE8A.png
    but with transparent background.
    Im not home so I cant create one. should be easy with any paint tool.
    Thanks baka.

    Finally, I seem to have managed to make a decent transparent round PNG image online (https://kleki.com/) for testing and just as you suggested, it worked ! The edges of the resulting re-shaped form are now very smooth.

    Question: Do you think I could achieve the same result with other image formats other than PNG so long as they have an alpha channel ?

  13. #13
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by AngelV View Post
    Question: Do you think I could achieve the same result with other image formats other than PNG so long as they have an alpha channel ?
    Yes. In Windows all image formats are eventually converted to an hBitmap.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  14. #14
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    You can even draw/generate the circle/ellipse in memory so no need to ship a separate PNG file for this reason only.

    If your transparency needs are more complex than a basic shape then a special purpose PNG might be justified shipping.

    cheers,
    </wqw>

  15. #15

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by wqweto View Post
    You can even draw/generate the circle/ellipse in memory so no need to ship a separate PNG file for this reason only.

    If your transparency needs are more complex than a basic shape then a special purpose PNG might be justified shipping.

    cheers,
    </wqw>
    Hi wqweto.

    Yes. Creating the circle in memory is what I had in mind and is what I was thinking to do next. This would give me much more control over the size, color etc of the image PLUS t will serve my project portability w\o the need to ship a separate image file.

    And since it is always going to be a basic circle with a transparent background (only difference will be in the circle size), it will be ideal to create the image in memory.

    I know how to create a 32bpp bitmap in memory but I am not sure how I would go about the transparency layer (alpha channel). I have never done this before.

    Would it be easier to create the 32bpp transparent memory bitmap with legacy GDI, GDIPlus or WIA ?

  16. #16
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,720

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    if u want to be able to change color, maybe inverted circle.
    so the center is transparent.
    and if u want to be able to resize, maybe the inverted circle as big possible
    and resize using interpolation bilinear/bicubic.
    or if u want to use GDI32, u can use halftone (SetStretchBltMode) should be good enough for this purpose.

    the png can be stored as resource. so no need to have it as an external picture u load.
    also, who cares 2022 about a .exe that is 1MB in size?

  17. #17
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by AngelV View Post
    Would it be easier to create the 32bpp transparent memory bitmap with legacy GDI, GDIPlus or WIA ?
    Easiest is using GDI+ the way LeandroA used Call GdipSetSmoothingMode(hGraphics, SmoothingModeAntiAlias)

    It's possible with only GDI too but first post your non-working GDI code which produces jagged results (preferrably a single Form1 with nothing extra) to illustrate the issue and let someone fix it for you.

    Working with existing code is so much simpler for us and so much better to figure out the root issue. That's why programming forums are very convenient for getting help back on your specific *code*.

    cheers,
    </wqw>

  18. #18
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,207

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by wqweto View Post
    Easiest is using GDI+ ...
    Nahh, to be fair here, easiest is to use the Cairo-Wrapper and the Alpha-capable RC6-FormEngine:
    (code below only needs a *.bas-Module in a Project which starts from Sub Main and has an RC6-reference)
    Code:
    Option Explicit
    
    Sub Main()
      Const W = 640, H = 480
      Dim CC As cCairoContext
      Set CC = Cairo.CreateSurface(W, H).CreateContext
          CC.SetLineWidth 6
          CC.Ellipse W / 2, H / 2, W - 1, H - 1, True
          CC.Stroke , Cairo.CreateSolidPatternLng(vbRed)
      
      Cairo.ImageList.AddSurface "BG", CC.Surface
      
      Const AlphaWithTaskbarEntry = 6, AlphaNoTaskbarEntry = 7
      Dim fMain As cWidgetForm
      Set fMain = Cairo.WidgetForms.Create(AlphaWithTaskbarEntry, "MyCaption", , W, H)
          fMain.WidgetRoot.ImageKey = "BG"
          fMain.Show vbModal
    End Sub
    HTH

    Olaf
    Last edited by Schmidt; Jan 31st, 2023 at 04:03 AM.

  19. #19
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Place this into a standard module:

    Code:
    '--- Module1.bas
    Option Explicit
    DefObj A-Z
    
    Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleW" (ByVal lpModuleName As Long) As Long
    Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long
    Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
    Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) As Long
    Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
    Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongW" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
    Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongW" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
    Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
    Private Declare Function GetWindowRect Lib "user32" (ByVal hWnd As Long, lpRect As Any) As Long
    Private Declare Function UpdateLayeredWindow Lib "user32" (ByVal hWnd As Long, ByVal hdcDest As Long, ptDst As Any, pSize As Any, ByVal hdcSrc As Long, ptSrc As Any, ByVal crKey As Long, pBlend As Any, ByVal dwFlags As Long) As Long
    '--- GDI+
    Private Declare Function GdiplusStartup Lib "gdiplus" (hToken As Long, pInputBuf As Any, Optional ByVal pOutputBuf As Long = 0) As Long
    Private Declare Function GdipCreateBitmapFromScan0 Lib "gdiplus" (ByVal lWidth As Long, ByVal lHeight As Long, ByVal lStride As Long, ByVal lPixelFormat As Long, ByVal Scan0 As Long, hBitmap As Long) As Long
    Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal hImage As Long) As Long
    Private Declare Function GdipGetImageGraphicsContext Lib "gdiplus" (ByVal hImage As Long, hGraphics As Long) As Long
    Private Declare Function GdipDeleteGraphics Lib "gdiplus" (ByVal hGraphics As Long) As Long
    Private Declare Function GdipSetSmoothingMode Lib "gdiplus" (ByVal hGraphics As Long, ByVal lSmoothingMd As Long) As Long
    Private Declare Function GdipCreateSolidFill Lib "gdiplus" (ByVal argb As Long, hBrush As Long) As Long
    Private Declare Function GdipDeleteBrush Lib "gdiplus" (ByVal hBrush As Long) As Long
    Private Declare Function GdipFillEllipseI Lib "gdiplus" (ByVal hGraphics As Long, ByVal hBrush As Long, ByVal lX As Long, ByVal lY As Long, ByVal lWidth As Long, ByVal lHeight As Long) As Long
    Private Declare Function GdipCreateHBITMAPFromBitmap Lib "gdiplus" (ByVal hBitmap As Long, hbmReturn As Long, ByVal clrBackground As Long) As Long
    
    Private Type POINTAPI
        X                   As Long
        Y                   As Long
    End Type
    
    Public Function GdipCreateEllipseBitmap(ByVal lWidth As Long, ByVal lHeight As Long, ByVal lColor As Long, Optional ByVal SmoothingMode As Long) As Long
        Const PixelFormat32bppPARGB As Long = &HE200B
        Dim aInput(0 To 3)  As Long
        Dim hBitmap         As Long
        Dim hGraphics       As Long
        Dim hBrush          As Long
        
        If GetModuleHandle(StrPtr("gdiplus")) = 0 Then
            aInput(0) = 1
            Call GdiplusStartup(0, aInput(0))
        End If
        If GdipCreateBitmapFromScan0(lWidth, lHeight, 4 * lWidth, PixelFormat32bppPARGB, 0, hBitmap) <> 0 Then
            GoTo QH
        End If
        If GdipGetImageGraphicsContext(hBitmap, hGraphics) <> 0 Then
            GoTo QH
        End If
        If SmoothingMode <> 0 Then
            If GdipSetSmoothingMode(hGraphics, SmoothingMode) <> 0 Then
                GoTo QH
            End If
        End If
        If GdipCreateSolidFill(lColor, hBrush) <> 0 Then
            GoTo QH
        End If
        If GdipFillEllipseI(hGraphics, hBrush, 0, 0, lWidth - 1, lHeight - 1) <> 0 Then
            GoTo QH
        End If
        '--- success
        GdipCreateEllipseBitmap = hBitmap
        hBitmap = 0
    QH:
        If hBrush <> 0 Then
            Call GdipDeleteBrush(hBrush)
        End If
        If hGraphics <> 0 Then
            Call GdipDeleteGraphics(hGraphics)
        End If
        If hBitmap <> 0 Then
            Call GdipDisposeImage(hBitmap)
        End If
    End Function
    
    Public Function GdipUpdateLayeredWindow(ByVal hWnd As Long, ByVal hBitmap As Long, Optional ByVal Opacity As Single = 1) As Boolean
        Const GWL_EXSTYLE   As Long = -20
        Const WS_EX_LAYERED As Long = &H80000
        Const ULW_ALPHA     As Long = 2
        Const AC_SRC_ALPHA  As Long = &H1000000
        Dim lStyle          As Long
        Dim hScreenDC       As Long
        Dim hMemDC          As Long
        Dim hBmp            As Long
        Dim hPrevBmp        As Long
        Dim uRect(0 To 1)   As POINTAPI
        Dim uPtSrc          As POINTAPI
        
        lStyle = GetWindowLong(hWnd, GWL_EXSTYLE)
        If (lStyle And WS_EX_LAYERED) = 0 Then
            Call SetWindowLong(hWnd, GWL_EXSTYLE, lStyle Or WS_EX_LAYERED)
        End If
        hScreenDC = GetDC(0)
        If hScreenDC = 0 Then
            GoTo QH
        End If
        hMemDC = CreateCompatibleDC(hScreenDC)
        If hMemDC = 0 Then
            GoTo QH
        End If
        If GdipCreateHBITMAPFromBitmap(hBitmap, hBmp, 0) <> 0 Then
            GoTo QH
        End If
        hPrevBmp = SelectObject(hMemDC, hBmp)
        If hPrevBmp = 0 Then
            GoTo QH
        End If
        Call GetWindowRect(hWnd, uRect(0))
        With uRect(1)
            .X = .X - uRect(0).X
            .Y = .Y - uRect(0).Y
        End With
        Call UpdateLayeredWindow(hWnd, hScreenDC, uRect(0), uRect(1), hMemDC, uPtSrc, 0, _
            AC_SRC_ALPHA Or CByte(255 * Opacity) * &H10000, ULW_ALPHA)
        '--- success
        GdipUpdateLayeredWindow = True
    QH:
        If hBmp <> 0 Then
            If hPrevBmp <> 0 Then
                Call SelectObject(hMemDC, hPrevBmp)
            End If
            Call DeleteObject(hBmp)
        End If
        If hMemDC <> 0 Then
            Call DeleteDC(hMemDC)
        End If
        If hScreenDC <> 0 Then
            Call ReleaseDC(0, hScreenDC)
        End If
    End Function
    You can use GdipCreateEllipseBitmap and GdipUpdateLayeredWindow from a form like this

    Code:
    '--- Form1.frm
    Option Explicit
    DefObj A-Z
    
    Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal hImage As Long) As Long
    Private Declare Function ReleaseCapture Lib "user32" () As Long
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageW" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
    
    Private Sub Form_Load()
        Const SmoothingModeAntiAlias As Long = 4
        Dim bInIde          As Boolean: Debug.Assert pvSetTrue(bInIde)
        Dim hBitmap         As Long
        
        If bInIde Then
            Visible = True
        End If
        hBitmap = GdipCreateEllipseBitmap(Width / Screen.TwipsPerPixelX, Height / Screen.TwipsPerPixelY, &HFFFF0000, SmoothingModeAntiAlias)
        If hBitmap = 0 Then
            MsgBox "Cannot create elliptical bitmap", vbExclamation
            GoTo QH
        End If
        If Not GdipUpdateLayeredWindow(hWnd, hBitmap, 0.5) Then
            MsgBox "Layered window failed", vbExclamation
            GoTo QH
        End If
    QH:
        If hBitmap <> 0 Then
            Call GdipDisposeImage(hBitmap)
        End If
    End Sub
    
    Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
        Const WM_SYSCOMMAND                 As Long = &H112
        Const SC_MOVE                       As Long = &HF010&
        
        Call ReleaseCapture
        Call SendMessage(hWnd, WM_SYSCOMMAND, SC_MOVE, 0)
    End Sub
    
    Private Function pvSetTrue(bValue As Boolean) As Boolean
        bValue = True
        pvSetTrue = True
    End Function
    This is not a quick hack (has proper error handling) but the code is made with reusability in mind (not brevity).

    There is an optional SmoothingMode parameter of GdipCreateEllipseBitmap where you can try different modes of anti-aliasing the ellipse.

    There is an optional Opacity parameter of GdipUpdateLayeredWindow.

    The final form is in the shape of a red ellipse *and* is 50% transparent because it's easy w/ the API call.

    cheers,
    </wqw>

  20. #20

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Thanks wqweto,

    I have adapted your code to x64bit vba and worked beautifully!

    I was already half way into making it work but was stuck when trying to resize the image to fit the exact size of the form.

    I am still studying the code so that I better uderstand it.

    BTW, reading the MS documentation on the blend argument of the UpdateLayeredWindow api, it says that the pblend is a pointer to the BLENDFUNCTION structure. Therefore, I initially proceeded like this :

    Code:
        Const AC_SRC_OVER = &H0
        Dim tBF As BLENDFUNCTION, pBF As Long
        
        With tBF
            .BlendOp = AC_SRC_OVER
            .BlendFlags = 0
            .SourceConstantAlpha = 255
            .AlphaFormat = 0
        End With
        
        Call CopyMemory(pBF, tBF, 4)
    
        Call UpdateLayeredWindow(hwnd, hScreenDC, uRect(0), uRect(1), hMemDC, uPtSrc, 0, pBF, ULW_ALPHA)
    I was expecting the above to work but it didn't.

    Whereas if I pass the following, in the pblend argument :
    AC_SRC_ALPHA Or CByte(255 * Opacity) * &H10000
    It works. Just like you have done in your code.

    I would be grateful if you could explain this bit ?

    Thanks

  21. #21
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by AngelV View Post
    I would be grateful if you could explain this bit ?
    It should work both ways, I've seen the UDT being passed both ByVal and ByRef.

    BLENDFUNCTION is a 4-byte UDT and in AlphaBlend API it's passed ByVal (this is possible for UDTs less than 8 bytes long).

    Current SDK definition of UpdateLayeredWindow uses a pointer to BLENDFUNCTION i.e. the UDT should be passed ByRef but for some reason it works even if the UDT is passed ByVal like in AlphaBlend case.

    No idea why this is possible, probably too many people erred or some prior version (XP?) of the SDK had this parameter declared ByVal.

    I'm not sure this is such a good idea on x64 though where pointers are larger than the small 4 byte UDT, so keep passing the parameter ByRef to be in sync with the latest SDK.

    cheers,
    </wqw>

  22. #22

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by wqweto View Post
    It should work both ways, I've seen the UDT being passed both ByVal and ByRef.

    BLENDFUNCTION is a 4-byte UDT and in AlphaBlend API it's passed ByVal (this is possible for UDTs less than 8 bytes long).

    Current SDK definition of UpdateLayeredWindow uses a pointer to BLENDFUNCTION i.e. the UDT should be passed ByRef but for some reason it works even if the UDT is passed ByVal like in AlphaBlend case.

    No idea why this is possible, probably too many people erred or some prior version (XP?) of the SDK had this parameter declared ByVal.

    I'm not sure this is such a good idea on x64 though where pointers are larger than the small 4 byte UDT, so keep passing the parameter ByRef to be in sync with the latest SDK.

    cheers,
    </wqw>
    Thanks.

    I will take another look at that.

    I am still not clear as to how the following actually works : (The OR and * Opeartors as well as the &H10000 confuse me) :

    AC_SRC_ALPHA Or CByte(255 * Opacity) * &H10000

    Trying to visualise the above bitwise.

    Thanks

  23. #23
    Frenzied Member VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    1,294

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by AngelV View Post
    The OR and * Opeartors as well as the &H10000 confuse me) :

    AC_SRC_ALPHA Or CByte(255 * Opacity) * &H10000
    Multiplication (*) takes precedence over bitwise "Or" so first you calculate the multiplications which just seem to set some bits. &H10000 is decimal 65536 which is 2^16 so an integer with the 17th bit set to 1 and the rest to 0. I don't know the value of "Opacity" but if it's "1" for example then multiplication result would be "1111 1111 0000 0000 0000 0000" in binary. If you need to "visualize" the bits then you could use the Windows Calculator in "programmer mode" since it shows you the same value in Hex, Decimal and Binary for easy comparisons

  24. #24
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by wqweto View Post
    It should work both ways, I've seen the UDT being passed both ByVal and ByRef...
    Quote Originally Posted by wqweto View Post
    No idea why this is possible, probably too many people erred or some prior version (XP?) of the SDK had this parameter declared ByVal.
    I'm skeptical that it does work both ways. Besides, I've never seen a Win32 API function that expects a structure to be passed by value. Even if they do exist, these would be exceptions. The rule with Win32 functions seems to be to pass pointers when passing structures.

    I'd wager that these code that passes them by value either don't actually work or if they do, it's only a fluke.

    The only other possibility I can think of is that the function can detect an invalid pointer and when it does, it treats the pointer as the value itself. It's certainly possible but I can't imagine what the point of writing an interface like that would be.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  25. #25
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by Niya View Post
    I'm skeptical that it does work both ways. Besides, I've never seen a Win32 API function that expects a structure to be passed by value. Even if they do exist, these would be exceptions. The rule with Win32 functions seems to be to pass pointers when passing structures.
    POINT, LARGE_INTEGER structures are often passed by value. BTW the last example i encountered yesterday:
    https://learn.microsoft.com/en-us/wi...calingcallback
    Code:
    Private Function MagCallback( _
                     ByVal hWnd As OLE_HANDLE, ByVal pSrc As PTR, _
                     ByVal lSrcHdr_Width As Long, ByVal lSrcHdr_Height As Long, _
                     ByVal lSrcHdr_cFormat1 As Currency, ByVal lSrcHdr_cFormat2 As Currency, _
                     ByVal lSrcHdr_lStride As Long, ByVal lSrcHdr_lOffset As Long, _
                     ByVal lSrcHdr_cbSize As Long, ByVal pDst As PTR, _
                     ByVal lDsrHdr_Width As Long, ByVal lDsrHdr_Height As Long, _
                     ByVal lDsrHdr_cFormat1 As Currency, ByVal lDsrHdr_cFormat2 As Currency, _
                     ByVal lDsrHdr_lStride As Long, ByVal lDsrHdr_lOffset As Long, _
                     ByVal lDsrHdr_cbSize As Long, ByVal lUnclippedLeft As Long, _
                     ByVal lUnclippedTop As Long, ByVal lUnclippedRight As Long, _
                     ByVal lUnclippedBottom As Long, ByVal lClippedLeft As Long, _
                     ByVal lClippedTop As Long, ByVal lClippedRight As Long, _
                     ByVal lClippedBottom As Long, ByVal hDirty As OLE_HANDLE) As Long

  26. #26
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by The trick View Post
    POINT, LARGE_INTEGER structures are often passed by value. BTW the last example i encountered yesterday:
    Yea, POINT and RECT structures do sometimes tend to get passed by value. Another example is WindowFromPoint. Interestingly though, people often just pass the members as individual parameters.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  27. #27
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Yes, you can split an UDT of two Longs and pass both members separately due to matching stack layout but this hack fails fast under x64 because the calling convention there uses registers for the first several parameters and you have to revert back to “packing” your 8 byte ByVal UDT into a ByVal Currency parameter to work both x86 and x64.

  28. #28

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by VanGoghGaming View Post
    Multiplication (*) takes precedence over bitwise "Or" so first you calculate the multiplications which just seem to set some bits. &H10000 is decimal 65536 which is 2^16 so an integer with the 17th bit set to 1 and the rest to 0. I don't know the value of "Opacity" but if it's "1" for example then multiplication result would be "1111 1111 0000 0000 0000 0000" in binary. If you need to "visualize" the bits then you could use the Windows Calculator in "programmer mode" since it shows you the same value in Hex, Decimal and Binary for easy comparisons
    Thanks VanGoghGaming

    I understand that. What I don't understand is how AC_SRC_ALPHA Or CByte(255 * Opacity) * &H10000 evaluates to the memory address of the BLENDFUNCTION UDT !!

  29. #29

    Thread Starter
    Addicted Member
    Join Date
    Jun 2022
    Posts
    234

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    @wqweto

    Couple of observations on your working code:

    * I noticed that you filled only the first member (GdiplusVersion) of the GdiplusStartupInput UDT and never obtained a token. Also you didn't call GdiplusShutdown when done.
    Any particular reason ? and is it safe not to call GdiplusShutdown in the end ?
    Code:
    aInput(0) = 1
    Call GdiplusStartup(0, aInput(0))

    * You used WM_SYSCOMMAND and SC_MOVE . This keeps the mouse jumping to the top when moving the image. Is there a reason for doing this ?

    Code:
    Private Sub UserForm_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal Y As Single)
        Const WM_SYSCOMMAND = &H112
        Const SC_MOVE = &HF010&
    
        Call ReleaseCapture
        Call SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE, 0)
    End Sub
    Shouldn't it be like this :
    Code:
    Private Sub UserForm_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal Y As Single)
     
    Const WM_NCLBUTTONDOWN As Long = &HA1
    Const HTCAPTION As Long = 2&
    
    Call ReleaseCapture
    SendMessage hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0
    
    End Sub

    * The Scan0 argument in the GdipCreateBitmapFromScan0 api expects a pointer to an array of bytes that contains the pixel data. Here, we passed a null pointer (0).

    Would it then be fair to say that if we were to pass a pointer to a byte array filled with pixel data in the Scan0 arg, it would load the image (based on the pixel data) and hence it would then be similar to using the GdipLoadImageFromStream GDIPlus function ? I can't seem to find much info\examples on GDIPlus.

    Also, would I be correct to say that when we pass a null pointer in the Scan0 argument (just like you did in your code), we are essentially just creating a *blank* GDI+ bitmap object (like a blank canvas) on which we can then draw whatever we want?

    Regards.


    Late edit:
    In the GdipUpdateLayeredWindow routine, you declared Const AC_SRC_ALPHA As Long = &H1000000 but I already had AC_SRC_ALPHA =1 declared elswhere in my code (I had already looked up the value of the AC_SRC_ALPHA constant on the web)... I had to change it when testing out\filling the BLENDFUNCTION UDT.
    Last edited by AngelV; Jan 31st, 2023 at 11:53 PM.

  30. #30
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by AngelV View Post
    * I noticed that you filled only the first member (GdiplusVersion) of the GdiplusStartupInput UDT and never obtained a token. Also you didn't call GdiplusShutdown when done.
    Any particular reason ? and is it safe not to call GdiplusShutdown in the end ?
    You don't shutdown original GDI, do you? Anyone seen trying to unload base DLLs like gdi32.dll or crypt32.dll?

    Other languages have GDI+ loaded by the runtime (i.e. before hitting Sub Main) so you never have to worry when to start/shut it down

    I was begging LaVolpe and everyone else here to stop shutting GDI+ at all and stop fiddling with any of its startup tokens.

    No one else in this world besides VB6 devs try to unload gdiplus.dll.

    Quote Originally Posted by AngelV View Post
    * You used WM_SYSCOMMAND and SC_MOVE . This keeps the mouse jumping to the top when moving the image. Is there a reason for doing this ?
    I copied this from Leandro's snippet here and never gave it a thought. Saw the jumping but deemed it a minor nuisance.

    You are not planning on using exactly this hack in production, do you? Please, don't!

    Quote Originally Posted by AngelV View Post
    * The Scan0 argument in the GdipCreateBitmapFromScan0 api expects a pointer to an array of bytes that contains the pixel data. Here, we passed a null pointer (0).

    Would it then be fair to say that if we were to pass a pointer to a byte array filled with pixel data in the Scan0 arg, it would load the image (based on the pixel data) and hence it would then be similar to using the GdipLoadImageFromStream GDIPlus function ? I can't seem to find much info\examples on GDIPlus.

    Also, would I be correct to say that when we pass a null pointer in the Scan0 argument (just like you did in your code), we are essentially just creating a *blank* GDI+ bitmap object (like a blank canvas) on which we can then draw whatever we want?
    Right! Yes, it's a hack. This creates an empty bitmap (all pixels = 0) with desired format, it's RGB w/ precomputed alpha to be compatible w/ GDI and particularly w/ UpdateLayeredWindow API call. The format of the GDI+ bitmap is the most important parameter here.

    Didn't want to risk it creating halo effect w/ non-precomputed (straight) alpha here although GdipCreateHBITMAPFromBitmap call would probably fix such format mismatch between GDI+ bitmap format and GDI's only supported pre-computed alpha.

    Quote Originally Posted by AngelV View Post
    Late edit:
    In the GdipUpdateLayeredWindow routine, you declared Const AC_SRC_ALPHA As Long = &H1000000 but I already had AC_SRC_ALPHA =1 declared elswhere in my code (I had already looked up the value of the AC_SRC_ALPHA constant on the web)... I had to change it when testing out\filling the BLENDFUNCTION UDT.
    Yes, now you know why declaring consts local to a procedure and local to a module is very handy -- one can change their values! :-))

    Here I just precomputed the offset for 3-rd byte (&H1000000) into the value (&H1) and got &H1000000 for AC_SRC_ALPHA which is exactly what I needed the source code to convey here -- to deliver the intent which comes with the name of the constant. Otherwise I would have simply slapped &H1000000 as an anonymous literal and everyone reading this would wonder what's going on here.

    cheers,
    </wqw>

  31. #31

  32. #32
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,092

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by The trick View Post
    When you specify Scan0 parameter it uses your array as pixels data abd you can change it at any time. When you specify null GDI+ allocates and manages this data.
    Well, I wasn't sure of this but if true this would be very cool.

    First I started by creating a DIB and passing its lpBits returned to GdipCreateBitmapFromScan0 so that I can use GDI+ to draw anti-aliased ellipse right inside the DIB but I wasn't sure if GDI+ is making a copy of the bits and operate on this copy for speed and didn't have time to investigate.

    This would be a very cool trick to mingle GDI and GDI+ with simple DIBs if it's working.

    cheers,
    </wqw>

  33. #33
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    373

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    For reference only.

    Like I always said, I don't use PictureBox to store the file image, because (1) the image may be 32-BPP with alpha values in the 4th bytes and (2) if I use DIB instead, the image can thus be saved back to file as 32 BPP, subsequent to an edit if any. I invariably use DIBs only (may be of 32, 24, 8 &/or 1 BPP ones).

    When I want to draw an Oval, an unfilled or filled one, I use the code below.

    Remarks: (A) As said, I store the image in DIB only, hence when I call GdipCreateBitmapFromScan0() I just pass the DIB's bytes pointer "BitsPtr"; and (B) After calling OvalGDIplus(), DIB may be "rendered" (or "BitBlt/StretchBlt" if without alpha) to whatever the display medium. AlphaBlend is dispensed with (see "Edited" below) **.

    Code:
    Public Sub OvalGDIplus(inDIB As clsDIB, ByVal inX1 As Long, ByVal inY1 As Long, ByVal inX2 As Long, _
          ByVal inY2 As Long, ByVal inBrushSize As Long, ByVal inColor As Long, _
          Optional ByVal inAlpha As Integer = 255, Optional inFilled As Boolean = False, _
          Optional inPremultiplied As Boolean = False)
          
        Dim hBitmap As Long
        Dim hImg As Long
        Dim hPath As Long
        Dim hPen As Long
        Dim w As Long, h As Long
        Dim WW As Long, HH As Long
        Dim mPenSize As Single
        Dim hBrush As Long
        Dim tmpX As Long, tmpY As Long
    
        If inBrushSize < 1 Then inBrushSize = 1
    
        mPenSize = CSng(inBrushSize)
       
        If inX1 > inX2 Then
            tmpX = inX2
            inX2 = inX1
            inX1 = tmpX
        End If
        If inY1 > inY2 Then
            tmpY = inY2
            inY2 = inY1
            inY1 = tmpY
        End If
       
        w = inX2 - inX1 + 1
        h = inY2 - inY1 + 1
    
        WW = inDIB.Width
        HH = inDIB.Height
        
        If inPremultiplied = False Then
             inDIB.RotateDIB inDIB, 1                  'Adjust our bottom up DIB
             GdipCreateBitmapFromScan0 WW, HH, WW * 4, PixelFormat32bppARGB, ByVal inDIB.BitsPtr, hImg
             If hImg = 0& Then
                  inDIB.RotateDIB inDIB, 1      'Restore
                  Exit Sub
             End If
             Call GdipGetImageGraphicsContext(hImg, hBitmap)
               'Remember to call "nDIB.RotateDIB inDIB, 1" to restore DIB orientation before Exit Sub
        Else
             If GdipCreateFromHDC(inDIB.hDC, hBitmap) <> [ok] Then
                  Exit Sub
             End If
        End If
          
        Call GdipSetSmoothingMode(hBitmap, SmoothingModeAntiAlias)
        Call GdipSetInterpolationMode(hBitmap, [InterpolationModeHighQualityBicubic])
    
        If inFilled = False Then
             Call GdipCreatePen1(ColorValue(inColor, inAlpha), mPenSize, UnitPixel, hPen)
             Call GdipDrawEllipseI(hBitmap, hPen, inX1, inY1, w, h)
        Else
             Call GdipCreateSolidFill(ColorValue(inColor, inAlpha), hBrush)
             Call GdipFillEllipseI(hBitmap, hBrush, inX1, inY1, (inX2 - inX1), (inY2 - inY1))
        End If
    
         If inFilled = False Then
             Call GdipDeletePen(hPen)
        Else
             If hPen <> 0 Then
                  Call GdipDeletePen(hPen)
             End If
             If hPath <> 0 Then
                  Call GdipDeletePath(hPath)
             End If
             Call GdipDeleteBrush(hBrush)
        End If
        
        Call GdipDeleteGraphics(hBitmap)
        If hImg <> 0 Then
             Call GdipDisposeImage(hImg)
        End If
    
        If inPremultiplied = False Then
             inDIB.RotateDIB inDIB, 1           'Restore
        End If
    End Sub
    
    
    Private Function ColorValue(inColor As Long, inA As Integer) As Long
        Dim arrByte(0 To 3) As Byte
        Dim mColor As Long
        If inA < 5 Then inA = 5
        If inA > 255 Then inA = 255
        arrByte(0) = (inColor \ &H10000) And &HFF
        arrByte(1) = (inColor \ &H100) And &HFF
        arrByte(2) = inColor And &HFF
        arrByte(3) = CByte(inA)
        CopyMemory mColor, arrByte(0), 4&
        ColorValue = mColor
    End Function


    ** Edited: Regarding earlier said "AlphaBlend is dispensed with"

    -- Here we are to draw (an oval) only.
    -- When AlphaBlend is deployed, per MS rules R,G & B bytes must be premultiplied first, both destination and source DIBs.
    Last edited by Brenker; Feb 1st, 2023 at 09:07 PM.

  34. #34
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by wqweto View Post
    Well, I wasn't sure of this but if true this would be very cool.

    First I started by creating a DIB and passing its lpBits returned to GdipCreateBitmapFromScan0 so that I can use GDI+ to draw anti-aliased ellipse right inside the DIB but I wasn't sure if GDI+ is making a copy of the bits and operate on this copy for speed and didn't have time to investigate.

    This would be a very cool trick to mingle GDI and GDI+ with simple DIBs if it's working.

    cheers,
    </wqw>
    Yes, GDI+ doesn't make a copy you could use an array or a DIB as well for pixel data. Long ago when I started to study GDI+ i was very surprised why garbage appears on my bitmaps and the program crashes sometimes (it was becasue i used local arrays for pixel initialization because i thought GDI+ makes copy too like GDI )

  35. #35
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: UpdateLayeredWindow and elliptic region (Jagged edges)

    Quote Originally Posted by The trick View Post
    Yes, GDI+ doesn't make a copy you could use an array or a DIB as well for pixel data. Long ago when I started to study GDI+ i was very surprised why garbage appears on my bitmaps and the program crashes sometimes (it was becasue i used local arrays for pixel initialization because i thought GDI+ makes copy too like GDI )
    We have similar problems in .Net with GDI+. For example:-
    Code:
    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            'Open a JPG file using a FileStream
            Dim s As FileStream = File.Open("d:\a.jpg", FileMode.Open)
    
            'Create a GDI+ Bitmap from the FileStream.
            Dim b As New Bitmap(s)
    
            'Close the FileStream
            s.Close()
    
            'This throws an error because GDI+ doesn't actually make a copy of the image
            'from the Filestream. It needs the FileStream to remain open and valid
            Me.BackgroundImage = b
    
        End Sub
    End Class
    Fortunately for us the Bitmap class has a constructor that takes another instance of a Bitmap which it copies. To fix the above we just need to change this:-
    Code:
    Dim b As New Bitmap(s)
    To this:-
    Code:
    Dim b As New Bitmap(New Bitmap(s))
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width