Author Topic: GDI+ Works on %WS_Ex_Layered Window?  (Read 10068 times)

0 Members and 1 Guest are viewing this topic.

Offline Gary Beene

  • Jr. Member
  • **
  • Posts: 96
  • User-Rate: +3/-0
GDI+ Works on %WS_Ex_Layered Window?
« on: March 15, 2011, 03:35:20 PM »
In the code below, I display a rotated image (ruler) with a blue background. The dialog is given the %WS_Ex_Layered style so that the blue background will be transparent color:
Code: [Select]
Dialog New Pixels, 0, "Ruler",300,300,400,50, %WS_Popup, %WS_Ex_Layered To hDlgand then ...
Code: [Select]
SetLayeredWindowAttributes(hDlg, %Blue, 255, %LWA_ALPHA Or %LWA_ColorKey)
When I use PlgBlt to rotate the image, transparency works fine.  But when I rotate the image with GDI+, the transparency effect is lost - the blue background is visible, rather than being transparent.

Is there an interaction between GDI+ and WS_Ex_Layered windows that would explain this?

Here's the compilable code (uses Jose's includes  :D).  Use the mouse wheel to rotate the image, right mouse click to close the app.

Code: [Select]
#Compile Exe
#Dim All
#Debug Error On
#Debug Display On
#Include "gdiplus.inc"

Global hDlg, hDC As Dword, rulerH, rulerW, rotateW, rotateH As Long, theta As Single

Function PBMain() As Long
   Local StartupInput As GdiplusStartupInput, token As Dword
   StartupInput.GdiplusVersion = 1     ' Initialize GDI+
   GdiplusStartup(token, StartupInput, ByVal %NULL)
   Dialog New Pixels, 0, "Ruler",300,300,400,50, %WS_Popup, %WS_Ex_Layered To hDlg
   Dialog Show Modal hDlg Call DlgProc
   GDIPlusShutDown token
End Function

CallBack Function DlgProc() As Long
   Local PS As PaintStruct
   Select Case Cb.Msg
      Case %WM_InitDialog
         rulerW = 222 : rulerH = 48             'for this example, ruler is fixed at 222x48 pixels
         Dialog Set Color hDlg, %Black, %Blue
         Dialog Set Size hDlg, rulerW, rulerH
         SetLayeredWindowAttributes(hDlg, %Blue, 255, %LWA_ALPHA Or %LWA_ColorKey)
      Case %WM_MouseWheel
         Select Case Hi(Integer,Cb.WParam)    'note the use of Integer
           Case > 0 : theta = theta + 0.05 : RotateRuler
           Case < 0 : theta = theta - 0.05 : RotateRuler
         End Select
      Case %WM_ContextMenu
         Dialog End hDlg        'right mouse click to end app
      Case %WM_LButtonDown
         If Cb.WParam = %MK_LBUTTON Then SendMessage hDlg, %WM_NCLButtonDown, %HTCaption, ByVal %Null  ' force drag
      Case %WM_Paint
         hDC = BeginPaint(hDlg, PS)
         RotateRuler
         EndPaint hDlg, PS
   End Select
End Function

Sub RotateRuler
   Local iMax,tempx,tempy,w,h,XCenter,YCenter,dx,dy As Long, hTemp, hTempDC, pGraphics, pImage, hBitmap As Dword

       'resize dialog to enclose ruler after rotation
       rotateW = RulerW*Abs(Cos(theta)) + RulerH*Abs(Sin(theta))               'bounding W once ruler is rotated
       rotateH = RulerH*Abs(Cos(theta)) + RulerW*Abs(Sin(theta))               'bounding H once ruler is rotated
       Dialog Get Loc hDlg To tempx, tempy  :  Dialog Get Size hDlg To w,h     'get current dialog size
       Dialog Set Size hDlg, RotateW, RotateH                                  'set dialog size to bounding dimensions
       Dialog Set Loc hDlg, tempx - (RotateW-w)/2, tempy -(RotateH-h)/2        'relocate so rotation is about center of dialog

       If 1 Then                      'GDI+ version of rotation
           'load ruler image, which is in larger-than-needed image, surrounded by transparency color)
           iMax = 300                                             'image containg ruler just happens to be 300x300
           Graphic Bitmap Load "ruler1.bmp", iMax, iMax To hTemp   'centered ruler + blue surrounding
           Graphic Attach hTemp, 0
           Graphic Get DC To hTempDC

           'create GDI+ object
           GdipCreateFromHDC(hTempDC, pGraphics)                      'get pGraphics
           hBitmap = GetCurrentObject(hTempDC, %OBJ_Bitmap)           'get hBitmap
           GDIpCreateBitmapFromHBITMAP(hBitmap, ByVal %Null, pImage)  'get pImage

           'rotate the image
           GdipTranslateWorldTransform(pGraphics, iMax/2, iMax/2, %MatrixOrderPrepend)       ' Move to center
           GdipRotateWorldTransform(pGraphics, theta * 57.3, %MatrixOrderPrepend)                  ' Rotate
           GdipTranslateWorldTransform(pGraphics, -iMax/2, -iMax/2, %MatrixOrderPrepend) ' Return
           GdipDrawImage(pGraphics, pImage, 0, 0)

           Dialog ReDraw hdlg      'clear previous image
           BitBlt hDC, 0,0,rotateW,rotateH, hTempDC, iMax/2-rotateW/2,iMax/2-rotateH/2 , %SRCCopy   'copy ruler image to dialog surface

           If pImage Then GdipDisposeImage(pImage)        'cleanup
           If pGraphics Then GdipDeleteGraphics(pGraphics)'cleanup

      Else                            'PlgBlt version of rotation
           'create memory BMP containing just the ruler (222x48)
           Graphic Bitmap Load "ruler2.bmp", rulerW, rulerH To hTemp     'just the ruler, no surrounding blue color
           Graphic Attach hTemp, 0
           Graphic Get DC To hTempDC

          'get the 3 corners of the rotated image (point are located on hDlg)
           dx = (rotateW - rulerW)/2  : dy = (rotateH - rulerH)/2
           XCenter = rulerW/2         : YCenter = rulerH/2
           Dim PlgPts(2) As PointAPI
           PlgPts(0).X = XCenter + (0        - XCenter) * Cos(theta) - (0        - YCenter) * Sin(theta) + dx 'upper-left in target
           PlgPts(0).Y = YCenter + (0        - XCenter) * Sin(theta) + (0        - YCenter) * Cos(theta) + dy
           PlgPts(1).X = XCenter + (RulerW   - XCenter) * Cos(theta) - (0        - YCenter) * Sin(theta) + dx 'upper-right in target
           PlgPts(1).Y = YCenter + (RulerW   - XCenter) * Sin(theta) + (0        - YCenter) * Cos(theta) + dy
           PlgPts(2).X = XCenter + (0        - XCenter) * Cos(theta) - (RulerH   - YCenter) * Sin(theta) + dx 'lower left in target
           PlgPts(2).Y = YCenter + (0        - XCenter) * Sin(theta) + (RulerH   - YCenter) * Cos(theta) + dy
           Dialog ReDraw hdlg      'clear image, display blue background color
           PlgBlt hDC, PlgPts(0),hTempDC, 0,0,RulerW,RulerH,0&,0,0  'copy ruler image to dialog surface
   End If
End Sub




Offline Gary Beene

  • Jr. Member
  • **
  • Posts: 96
  • User-Rate: +3/-0
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #1 on: March 15, 2011, 04:16:55 PM »

Offline Gary Beene

  • Jr. Member
  • **
  • Posts: 96
  • User-Rate: +3/-0
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #2 on: March 15, 2011, 04:19:38 PM »
More information ... conflicting results.

I'm running on Win7. 

When I run under an Aero theme, the transparency works.

But when I run under a basic theme (Windows Classic), the transparency does not work.


Offline Gary Beene

  • Jr. Member
  • **
  • Posts: 96
  • User-Rate: +3/-0
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #3 on: March 15, 2011, 04:39:54 PM »
More data ... transparency doesn't work on my wife's XP machine either.

In looking around the web, I'm seeing a number of posts who's title suggests a similar problem.  But I haven't yet found a clear explanation of why, of how to resolve the problem.




Offline Gary Beene

  • Jr. Member
  • **
  • Posts: 96
  • User-Rate: +3/-0
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #4 on: March 16, 2011, 02:29:06 AM »
Over in the PowerBASIC forums, Donald gave me some code that will work. But he took a slightly different route so I still don't know why the code I posted fails. 

http://www.powerbasic.com/support/pbforums/showthread.php?p=371051#post371051

Different Question:
In these forums, how do I hide the URL above, and use it to make a highlighted link?



Offline José Roca

  • Administrator
  • Hero Member
  • *****
  • Posts: 2481
  • User-Rate: +204/-0
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #5 on: March 16, 2011, 07:08:03 AM »
Quote
In these forums, how do I hide the URL above, and use it to make a highlighted link?

WS_Ex_Layered + GDI+ Problems?

[_url=http://www.powerbasic.com/support/pbforums/showthread.php?p=371051#post371051]WS_Ex_Layered + GDI+ Problems?[_/url]

Without the underscores before url and /url.

Offline Patrice Terrier

  • ROMs
  • Hero Member
  • *****
  • Posts: 936
  • User-Rate: +62/-1
    • www.zapsolution.com
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #6 on: March 16, 2011, 08:51:06 AM »
Layered windows aren't handled the same on XP and VISTA/SEVEN.
Also in order to work correctly the graphic card must be not too old and running in 32-bit mode.

Did you try the "Boing" demo on your wife's PC,
or the "AeroGL" that is a unique combination of different graphic technologies:
OpenGL + GDI32 + GDIPLUS + composited layered window.
But i can't force you to studdy my SDK code, if you don't want to ;)

Also as a last resort, you can always use a region built on the fly and that will work fine with W2K/XP/VISTA/SEVEN, but the borders of the ruler will look jagged.
« Last Edit: March 16, 2011, 11:19:15 AM by Patrice Terrier »
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Patrice Terrier

  • ROMs
  • Hero Member
  • *****
  • Posts: 936
  • User-Rate: +62/-1
    • www.zapsolution.com
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #7 on: March 16, 2011, 11:56:08 AM »
Gary,

I am writing a SDK AeroRuler example for you.  8)

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Patrice Terrier

  • ROMs
  • Hero Member
  • *****
  • Posts: 936
  • User-Rate: +62/-1
    • www.zapsolution.com
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #8 on: March 16, 2011, 02:33:14 PM »
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Gary Beene

  • Jr. Member
  • **
  • Posts: 96
  • User-Rate: +3/-0
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #9 on: March 16, 2011, 02:35:47 PM »
Hi Patrice!

Quote
But i can't force you to study my SDK code, if you don't want to

Yes, that is true.  If I wasn't feeling the pressure to work on a couple of other projects I've already started, I'd love to spend the time to catch up on several programming areas which I've neglected, SDK being one of them.  

But you know of course, that even when I will be working on SDK, that I'll be trying to do the same thing in DDT so I can understand what works in one vs the other - and how they play together.  I plan to be multi-lingual forever!  I want to be proficient in SDK, but don't see any reason to neglect DDT solutions as well.

I will say that because I like to post code that is as generally useful as possible, and because (as Jose has pointed out) the PowerBASIC forums are not so SDK intensive as they once were, I do resist moving over to SDK as my mainline programming theme.  My upcoming update of my online PowerBASIC tutorials, to incorporate SDK coding, should at least show recognition of the importance of the coding approach, and a commitment to help newbies appreciate/understand their options.

Even this current problem you've been helping me with, GDI+ rotation of the ruler image, doesn't tell me not to use DDT.  It only tells me that you SDK folks have already solved the problem.  I don't yet know enough to say that there's not an equally straight-forward DDT solution.   Years from now, when there are aging PowerBASIC programmers with DDT experience to match your own SDK experience, who knows what the coding landscape will look like!

As always, thank you for your comments, code, and patience!



Offline Patrice Terrier

  • ROMs
  • Hero Member
  • *****
  • Posts: 936
  • User-Rate: +62/-1
    • www.zapsolution.com
Re: GDI+ Works on %WS_Ex_Layered Window?
« Reply #10 on: March 16, 2011, 02:45:53 PM »
Gary,

DDT is based on the CreateDialog API, that is itself a limited subset of the CreateWindowEx API.

You won't be able to do what i show you in AeroRuler with DDT, never.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com