Page 1 of 1

Posted: Mon Dec 03, 2007 6:11 pm
by netmaestro
I still can't get your PNG so I'll whip one up and show you where you're at with this:

To do the demo you need this: http://www.lloydsplace.com/BG.png

You have two main issues that must be overcome:

Firstly, the PNG image decoder that ships with PureBasic is currently incompatible with the UpdateLayeredWindow API. So you must decode the image using another tool. I've supplied you with an arrow from my quiver, so that's out of the way.

Secondly, sad to report, Microsoft has made windows using the UpdateLayeredWindow API unable to host child windows. This is due to the fact that it uses a different, per-pixel update routine to draw the window and it doesn't process #WM_PAINT messages like a normal window does. So, while the child controls exist, they are never drawn.

The UpdateLayeredWindow approach has one major advantage over other forms of skinning or achieving transparency in that you can create dropshadows for the window edges and they will render correctly. In fact, it's the only technology on Windows I know of that will achieve this. So, we must find a way to make it work.

Here we go, this is our plan:

Make a Layered window with dropshadowed edges for use as a window border only.

Make another toplevel window to host the gadgets and keep it centered on the first window at all times.

As hackitistically perverted as this idea is, it actually is one of the options suggested by Microsoft engineers as a solution to this known limitation.

On to the hack!

Code: Select all

;========================================= 
; Danger, netmaestro software ahead 
;========================================= 

ProcedureDLL CatchPNG(ImageNumber, Address, Length) 

  CompilerIf Defined(GdiplusStartupInput, #PB_Structure) = 0 
    Structure GdiplusStartupInput 
      GdiPlusVersion.l 
      *DebugEventCallback.Debug_Event 
      SuppressBackgroundThread.l 
      SuppressExternalCodecs.l 
    EndStructure 
  CompilerEndIf  
  
  Structure StreamObject 
    block.l 
    *bits 
    stream.ISTREAM 
  EndStructure 

  Protected lib 
  lib = OpenLibrary(#PB_Any, "gdiplus.dll") 
  If Not lib 
    ProcedureReturn -1 
  EndIf 
  
  input.GdiplusStartupInput 
  input\GdiPlusVersion = 1 
  
  CallFunction(lib, "GdiplusStartup", @*token, @input, #Null) 
  If *token 
    stream.streamobject 
    Stream\block = GlobalAlloc_(#GHND, Length) 
    Stream\bits = GlobalLock_(Stream\block) 
    CopyMemory(address, stream\bits, Length) 
    If CreateStreamOnHGlobal_(stream\bits, 0, @Stream\stream) = #S_OK 
      CallFunction(lib, "GdipCreateBitmapFromStream", Stream\stream , @*image) 
      Stream\stream\Release() 
      GlobalUnlock_(Stream\bits) 
      GlobalFree_(Stream\block) 
    Else 
      CallFunction(lib, "GdiplusShutdown", *token) 
      ProcedureReturn 0 
    EndIf 
    
    If *image 
      CallFunction(lib, "GdipGetImageWidth", *image, @Width.l) 
      CallFunction(lib, "GdipGetImageHeight", *image, @Height.l) 
      If imagenumber = #PB_Any
        return_imagenumber = CreateImage(#PB_Any, Width, Height, 32)
      Else
        CreateImage(return_imagenumber, Width, Height, 32, #PB_Image_Transparent)
      EndIf
      hDC = StartDrawing(ImageOutput(return_imagenumber)) 
        CallFunction(lib, "GdipCreateFromHDC", hdc, @*gfx) 
        CallFunction(lib, "GdipDrawImageRectI", *gfx, *image, 0, 0, Width, Height) 
      StopDrawing()  
      CallFunction(lib, "GdipDeleteGraphics", *gfx)  
      CallFunction(lib, "GdipDisposeImage", *image) 
      CallFunction(lib, "GdiplusShutdown", *token) 
      CloseLibrary(0) 
      
      ProcedureReturn return_imagenumber 
    Else 
      ProcedureReturn -1
    EndIf 
  Else 
    ProcedureReturn -1
  EndIf 
EndProcedure 

Procedure WinProc(hwnd, msg, wparam, lparam) 
  result = #PB_ProcessPureBasicEvents 
  Select msg 
    Case #WM_MOVE, #WM_ACTIVATE, #WM_ACTIVATEAPP, #WM_GETICON 
      ResizeWindow(0,WindowX(1)+96, WindowY(1)+30, #PB_Ignore, #PB_Ignore) 
    Case #WM_LBUTTONDOWN 
      If EventlParam()>>16<21
        SendMessage_(hwnd, #WM_NCLBUTTONDOWN, #HTCAPTION, 0) 
      EndIf
  EndSelect 
  ProcedureReturn result 
EndProcedure 

CatchPNG(0, ?bkimg, ?endbk-?bkimg) 

OpenWindow(1, 0, 0, 512, 384, "", #PB_Window_ScreenCentered | #PB_Window_BorderLess) 
OpenWindow(0, 0, 0, 300, 200, "", #PB_Window_BorderLess, WindowID(1) ) 

SetWindowLong_(WindowID(1), #GWL_EXSTYLE, GetWindowLong_(WindowID(1), #GWL_EXSTYLE) | #WS_EX_LAYERED) 
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, GetWindowLong_(WindowID(0), #GWL_EXSTYLE) | #WS_EX_LAYERED) 

SetLayeredWindowAttributes_(WindowID(0), 0, 255, #LWA_ALPHA) ; Not necessary but just to show it's ok to do it 
SetWindowColor(0, RGB(131,193,178)) ; Same color as PNG 

hdc = StartDrawing(ImageOutput(0)) 
  sz.SIZE 
  sz\cx = ImageWidth(0) 
  sz\cy = ImageHeight(0) 
  ContextOffset.POINT 
  BlendMode.BLENDFUNCTION 
  BlendMode\SourceConstantAlpha = 255 
  BlendMode\AlphaFormat = 1 
  UpdateLayeredWindow_(WindowID(1), 0, 0, @sz, hDC, @ContextOffset, 0, @BlendMode, 2) 
StopDrawing() 

SetWindowCallback(@WinProc(),1) 

ButtonGadget(1,20,20,100,30,"Press to exit...") 
  
Repeat 
  Select WaitWindowEvent() 
    Case #PB_Event_Gadget 
      Break 
    Case #PB_Event_CloseWindow 
      Break 
  EndSelect 
ForEver 

DataSection 
  bkimg:
  IncludeBinary "BG.png" 
  endbk: 
EndDataSection

Posted: Tue Dec 04, 2007 7:57 am
by ankachen
Wow! Your solution was terrific!! Thank you for helping.
I was clarified on this issue.

Thanks again!!

Posted: Fri Dec 07, 2007 10:41 pm
by Rook Zimbabwe
That is Hacktastic!!!! 8) Netmaestro Rulez!!!!

I am seriously impressed.

Posted: Sat Dec 08, 2007 1:10 am
by Dare
netmaestro wrote:

Code: Select all

;========================================= 
; Danger, netmaestro software ahead 
;========================================= 
:lol: