Windows API is stupid!

For everything that's not in any way related to PureBasic. General chat etc...
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Small update:

- Fixed an issue where clicking a lot on the window near the end could have caused an IMA

- Added single-instance enforcement

- Source is released

You'll need the sounds and pictures: https://lloydsplace.com/winapistupid.zip

I got the builder sprites free from here: http://reinerstileset.4players.de/

The program could be made smaller by using gdiplus to tilt the window and using small sprites to update only the dented part of the window, but these are more work and I'm too lazy...

Code: Select all

;========================================================================
; Program:          Resize Window Improvement                           
; Author:           Lloyd Gallant (netmaestro)                                     
; Date:             June 21, 2008                                       
; Target OS:        Windows 2000/XP and later                           
; Target Compiler:  PureBasic 4.0 and later                             
; License:          Free, unrestricted, no warranty                     
; Why:              I just haven't written anything silly in a while    
;========================================================================    

Import "gdiplus.lib"
  GdipCreateBitmapFromStream(*stream, *image) 
  GdipGetImageWidth(*image, *Width) 
  GdipGetImageHeight(*image, *Height) 
  GdipCreateFromHDC( hdc.i, *gfx) 
  GdipDrawImageRectI(*gfx, *image, a.i, b.i, Width.i, Height.i) 
  GdipDeleteGraphics(*gfx)  
  GdipDisposeImage(*image) 
  GdiplusStartup(*token, *input, a.i)
  GdiplusShutdown(*token) 
EndImport

Declare CatchPNG(ImageNumber, Address, Length) 
Declare MainThread(void)
Declare WalkingW(void)
Declare WalkingE(void)
Declare WalkingNE(void)
Declare WalkingSE(void)
Declare HammeringE(void)
Declare HammeringW(effect)
Declare UpdateWindow(window,img)
Declare Instance_Running(LockStr$)

DataSection
  sheet:  
  IncludeBinary "builder2.png" 
  endsheet:
  win1:   
  IncludeBinary "win1.png"     
  endwin1:
  tilt1:  
  IncludeBinary "win2.png"     
  endtilt1:
  tilt2:  
  IncludeBinary "win3.png"     
  endtilt2:
  bent1:  
  IncludeBinary "win4.png"     
  endbent1:
  bent2:  
  IncludeBinary "win5.png"    
  endbent2:
  swear:  
  IncludeBinary "swear.png"    
  endswear:
  giveup: 
  IncludeBinary "giveup.png"   
  endgiveup:
  walk:   
  IncludeBinary "walk.wav"
  hammer: 
  IncludeBinary "hammer.wav"
EndDataSection

If Instance_Running("netmaestro's Resize Window Improvement")
  End
EndIf

Global soundon = InitSound()
If soundon
  CatchSound(0, ?hammer)
  CatchSound(1, ?walk)
EndIf

CatchPNG(0, ?sheet,?endsheet-?sheet)
Global win1    = CatchPNG(#PB_Any, ?win1, ?endwin1-?win1)
Global tilt1   = CatchPNG(#PB_Any, ?tilt1, ?endtilt1-?tilt1)
Global tilt2   = CatchPNG(#PB_Any, ?tilt2, ?endtilt2-?tilt2)
Global bent1   = CatchPNG(#PB_Any, ?bent1, ?endbent1-?bent1)
Global bent2   = CatchPNG(#PB_Any, ?bent2, ?endbent2-?bent2)
Global swear   = CatchPNG(#PB_Any, ?swear, ?endswear-?swear)
Global giveup  = CatchPNG(#PB_Any, ?giveup, ?endgiveup-?giveup)
Global wait    = GrabImage(0,#PB_Any, 16*96,192,96,96)
Global threadfinished=0


Global NewList walke()
For i=0 To 7
  AddElement(walke())
  walke()=GrabImage(0,#PB_Any, 96*i,0,96,96)
Next
FirstElement(walke())

Global NewList walkw()
For i=0 To 7
  AddElement(walkw())
  walkw()=GrabImage(0, #PB_Any, i*96,96,96,96)
Next
FirstElement(walkw())

Global NewList walkne()
For i=0 To 7
  AddElement(walkne())
  walkne()=GrabImage(0,#PB_Any, i*96,192,96,96)
Next
FirstElement(walkne())

Global NewList hammere()
For i=0 To 10
  AddElement(hammere())
  hammere()=GrabImage(0, #PB_Any, (96*8)+i*96,0,96,96)
Next
FirstElement(hammere())

Global NewList hammerw()
For i=0 To 10
  AddElement(hammerw())
  hammerw()=GrabImage(0, #PB_Any, (96*8)+i*96,96,96,96)
Next
FirstElement(hammerw())

Global NewList walkse()
For i=0 To 7
  AddElement(walkse())
  walkse()=GrabImage(0,#PB_Any, (96*8)+i*96,192,96,96)
Next
FirstElement(walkse())

win=OpenWindow(0,0,0,320,290,"ResizeWindow Improvement",#PB_Window_BorderLess|#PB_Window_Invisible|#PB_Window_ScreenCentered)
SetWindowLong_(win,#GWL_EXSTYLE, GetWindowLong_(win,#GWL_EXSTYLE)|#WS_EX_LAYERED|#WS_EX_TOOLWINDOW)
UpdateWindow(0, win1)
StickyWindow(0,1)

win2=OpenWindow(1,0,0,320,290,"",#PB_Window_BorderLess|#PB_Window_Invisible, WindowID(0))
SetWindowLong_(win2,#GWL_EXSTYLE, GetWindowLong_(win2,#GWL_EXSTYLE)|#WS_EX_LAYERED|#WS_EX_TOOLWINDOW)
UpdateWindow(1, swear)
StickyWindow(1,1)

HideWindow(0,0)

man = OpenWindow(9,0,0,96,96,"",#PB_Window_BorderLess|#PB_Window_Invisible|#PB_Window_ScreenCentered, WindowID(0))
SetWindowLong_(man,#GWL_EXSTYLE, GetWindowLong_(man,#GWL_EXSTYLE)|#WS_EX_LAYERED|#WS_EX_TOOLWINDOW)
StickyWindow(9,1)
UpdateWindow(9,wait)

main_tid = CreateThread(@MainThread(),0)

Repeat
  WaitWindowEvent(10)
Until GetAsyncKeyState_(#VK_ESCAPE) & 32768 
End

Procedure MainThread(void)
  Protected tid
  
  ; Opening view
  Delay(1000)
  HideWindow(9,0)
  Delay(1000)
  
  ; Walk to top right corner
  tid=CreateThread(@WalkingNE(),0)
  Repeat
    Delay(1)
  Until WindowX(9)>=WindowX(0)+WindowWidth(0)-20
  threadfinished = #True:WaitThread(tid)
  
  ; Hammer on right corner 
  tid=CreateThread(@HammeringW(),0)
  WaitThread(tid)
  Delay(500)
  ResizeWindow(1, WindowX(9)+10,WindowY(9)-80,#PB_Ignore,#PB_Ignore)
  HideWindow(1,0):Delay(2000):HideWindow(1,1)
  
  ; Walk to top left corner
  tid=CreateThread(@WalkingW(),0)
  Repeat
    Delay(1)
  Until WindowX(9)<=WindowX(0)-110
  threadfinished = #True:WaitThread(tid)
  tid=CreateThread(@WalkingSE(),0)
  Repeat
    Delay(1)
  Until WindowX(9)>=WindowX(0)-80
  threadfinished = #True:WaitThread(tid)  
  
  ; Hammer on left corner
  tid=CreateThread(@HammeringE(),0)
  WaitThread(tid)
  
  ; Walk to right of mid-window
  tid=CreateThread(@WalkingSE(),0)
  Repeat
    Delay(1)
  Until WindowX(9)>=WindowX(0)+20
  threadfinished = #True:WaitThread(tid)  
  tid=CreateThread(@WalkingE(),0)
  Repeat
    Delay(1)
  Until WindowX(9)>=WindowX(0)+WindowWidth(0)-20
  threadfinished = #True:WaitThread(tid)  
  
  ; Hammer on mid-window
  tid=CreateThread(@HammeringW(),1) ; parameter specifies effect of hammering: 0=tilt,1=dent
  WaitThread(tid)
  Delay(500)
  ResizeWindow(1, WindowX(9)+10,WindowY(9)-80,#PB_Ignore,#PB_Ignore)
  HideWindow(1,0):Delay(2000):HideWindow(1,1)   
  
  ; Walk back to mid window and give up
  tid=CreateThread(@WalkingW(),0)
  Repeat
    Delay(1)
  Until WindowX(9)<=WindowX(0)+110
  threadfinished = #True:WaitThread(tid)
  UpdateWindow(9, wait)
  Delay(1000)
  UpdateWindow(1, giveup)
  ResizeWindow(1, WindowX(9),WindowY(9)-110,#PB_Ignore,#PB_Ignore)
  HideWindow(1,0):Delay(3000):HideWindow(1,1)   
  
  ; End the program
  PostMessage_(WindowID(0), #WM_SYSCOMMAND, #SC_CLOSE,0) 
  
EndProcedure

Procedure HammeringW(effect)
  Protected hits = 0 ; Counts the hits
  Protected cc   = 0 ; Counts the sprite frames, record a hit on 7th frame
  
  Repeat
    UpdateWindow(9, hammerw())
    If cc=7 
      If soundon
        PlaySound(0)
      EndIf
      hits+1
    EndIf
    Delay(100)
    If Not NextElement(hammerw())
      FirstElement(hammerw())
      cc=0
    Else
      cc+1  
    EndIf
    Select effect
      Case 0
        If hits = 2 
          UpdateWindow(0, tilt1)
        EndIf
        If hits = 4 
          UpdateWindow(0,tilt2)
        EndIf
      Case 1
        If hits = 2 
          UpdateWindow(0,bent1)
          ResizeWindow(9,WindowX(9)-1,#PB_Ignore,#PB_Ignore,#PB_Ignore)
        EndIf
        If hits = 4 
          UpdateWindow(0,bent2)
        EndIf
    EndSelect      
  Until hits = 4 And cc=0
EndProcedure

Procedure HammeringE(void)
  Protected hits = 0 ; Counts the hits
  Protected cc   = 0 ; Counts the sprite frames, record a hit on 7th frame
  
  Repeat
    UpdateWindow(9, hammere())
    If cc=7 
      If soundon
        PlaySound(0)
      EndIf
      hits+1
    EndIf
    Delay(100)
    If Not NextElement(hammere())
      FirstElement(hammere())
      cc=0
    Else
      cc+1  
    EndIf
    If hits = 2 
      UpdateWindow(0,tilt1)
    EndIf
    If hits = 4 
      UpdateWindow(0,win1)
    EndIf
    
  Until hits = 4 And cc=0
EndProcedure

Procedure WalkingW(void)
  threadfinished=0
  Repeat
    UpdateWindow(9,walkw())
    If (cc=1 Or cc=5) And soundon
      PlaySound(1)
    EndIf
    ResizeWindow(9, WindowX(9)-5,#PB_Ignore,#PB_Ignore,#PB_Ignore)
    Delay(100)
    If Not NextElement(walkw())
      FirstElement(walkw())
      cc=0
    Else
      cc+1  
    EndIf
  Until threadfinished
EndProcedure

Procedure WalkingE(void)
  threadfinished=0
  Repeat
    UpdateWindow(9,walke())
    If (cc=1 Or cc=5) And soundon
      PlaySound(1)
    EndIf
    ResizeWindow(9, WindowX(9)+5,#PB_Ignore,#PB_Ignore,#PB_Ignore)
    Delay(100)
    If Not NextElement(walke())
      FirstElement(walke())
      cc=0
    Else
      cc+1  
    EndIf
  Until threadfinished
EndProcedure

Procedure WalkingNE(void)
  threadfinished=0
  Repeat
    UpdateWindow(9,walkne())
    If (cc=1 Or cc=5) And soundon
      PlaySound(1)
    EndIf
    ResizeWindow(9, WindowX(9)+5,WindowY(9)-3,#PB_Ignore,#PB_Ignore)
    Delay(100)
    If Not NextElement(walkne())
      FirstElement(walkne())
      cc=0
    Else
      cc+1  
    EndIf
  Until threadfinished
EndProcedure

Procedure WalkingSE(void)
  threadfinished=0
  Repeat
    UpdateWindow(9,walkse())
    If (cc=1 Or cc=5) And soundon
      PlaySound(1)
    EndIf
    ResizeWindow(9, WindowX(9)+5,WindowY(9)+5,#PB_Ignore,#PB_Ignore)
    Delay(100)
    If Not NextElement(walkse())
      cc=0
      FirstElement(walkse())
    Else
      cc+1
    EndIf
  Until threadfinished
EndProcedure

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

Procedure 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 
  
  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 
      GdiplusShutdown(*token) 
      ProcedureReturn 0 
    EndIf 
    
    If *image 
      GdipGetImageWidth(*image, @Width.l) 
      GdipGetImageHeight(*image, @Height.l) 
      If imagenumber = #PB_Any 
        return_imagenumber = CreateImage(#PB_Any, Width, Height, 32, #PB_Image_Transparent) 
      Else 
        CreateImage(return_imagenumber, Width, Height, 32, #PB_Image_Transparent) 
      EndIf 
      hDC = StartDrawing(ImageOutput(return_imagenumber)) 
        GdipCreateFromHDC(hdc, @*gfx) 
        GdipDrawImageRectI(*gfx, *image, 0, 0, Width, Height) 
      StopDrawing()  
      GdipDeleteGraphics(*gfx)  
      GdipDisposeImage(*image) 
      GdiplusShutdown(*token) 
      
      ProcedureReturn return_imagenumber 
    Else 
      ProcedureReturn -1 
    EndIf 
  Else 
    ProcedureReturn -1 
  EndIf 
EndProcedure 

Procedure Instance_Running(LockStr$)
  *MyMutex = CreateMutex_(#Null, 1, LockStr$)
  If *MyMutex <> 0 And GetLastError_() = #ERROR_ALREADY_EXISTS
    CloseHandle_(*MyMutex)
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure
Last edited by netmaestro on Mon Nov 14, 2022 5:04 am, edited 2 times in total.
BERESHEIT
byo
Enthusiast
Enthusiast
Posts: 635
Joined: Mon Apr 02, 2007 1:43 am
Location: Brazil

Post by byo »

Wow, well done. :lol:
Proud registered Purebasic user.
Because programming should be fun.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Post by Kwai chang caine »

I don't know if it's the fault of the PC of my job, but i have tried to run your code and your exe on it and i have some problem :cry:

This macine works on W2000 SP4, is it normal ???
ImageThe happiness is a road...
Not a destination
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

The code uses gdiplus to load the png images, and I believe gdiplus doesn't ship with w2000. But gdiplus.dll is a free download from Microsoft, so you could DL it and put it in \system32 and see if it works now.
BERESHEIT
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Post by Kwai chang caine »

Thanks a lot, NETMAESTRO
I go to do all that you said to me 8)

I wish you a good day :D
ImageThe happiness is a road...
Not a destination
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Post by Kwai chang caine »

Yes, you are always right :D

I put the gdiplus.dll in the same directory of the application, and your splendid code works fine now

Thanks again 8)
ImageThe happiness is a road...
Not a destination
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

Very good but it should go in \windows\system32 so other applications that might use it can find it too.
BERESHEIT
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Post by Kwai chang caine »

Yes especially the DLL is big 1.6 Mo.
It's more better to put it in system32 for not instal in every application :wink:

I love your little worker :D

I search all a day somes picture with green background or other, but it's very difficult to find :?
I find with the "pre-keyed" word in google or "greenscreen" but they are not full of result.

A society sell severals animation and movie, but it's very expensive :?
http://www.timelinegfx.com/freegreenscreen.html

A solution, ask to my wife, to dance in front of a green cloth :lol:

I continue my search.....
ImageThe happiness is a road...
Not a destination
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4322
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post by Rook Zimbabwe »

Well... stupid is a mean word! I mean it just does what it is told to do!!! If it is told stupid, then it does stupid! (Look at all my programs for an example of someone telling the computer stupid! ) :wink:
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

@netmaestro, nice one! 8)
Thanks for the source.

I have been near to complain because reading the title "Resize Window Improvement", i have been trying to manually resize the window and it didn't work! :lol:
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Ollivier
Enthusiast
Enthusiast
Posts: 281
Joined: Mon Jul 23, 2007 8:30 pm
Location: FR

Post by Ollivier »

Threads managing is perfect (XP . 1GHz . 1GB)
Graphism is good too.

API is less stupid with men like you.

Thank you
User avatar
idle
Always Here
Always Here
Posts: 5915
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Post by idle »

that made my day!

:D
npath
User
User
Posts: 74
Joined: Tue Feb 15, 2005 5:15 pm

Post by npath »

Hilarious... I really enjoyed your new implementation of resizing windows.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Windows API is stupid!

Post by netmaestro »

I really enjoyed this one and I was disappointed when I lost the files for it last year. But I did post the code and so now that I have some spare time I've created new graphics and sounds for it and it's back up and running again, all links working.
BERESHEIT
Post Reply