What parameters does PB use internally to create windows?

Just starting out? Need help? Post your questions and find answers here.
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

@Netmaestro: Thank you...You ain't too bad yourself my friend. :)

@AND51: You can pick and choose which MessageRequesters to hook. You just call the SetWindowsHookEx() as needed prior to using MessageRequester().

I'll clean this up and make it more user friendly later this weekend. ;)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
AND51
Addict
Addict
Posts: 1040
Joined: Sun Oct 15, 2006 8:56 pm
Location: Germany
Contact:

Post by AND51 »

Although I don't want to get everything served, but I would appreciate it, if you can made one or two procedures out of this code.

I would like to have a procedure that replaces my MessageRequester(). Furthemore, I think, you cannot overcome the Hook-callback, so therefor you need an additional procedure.

If you want I can try it on my own. I have some experience with API; however, there are many new API-commands and I must look up each of them which makes me processing the code more slowly.

All in all, I thank you a lot! THANK YOU! I also post this code and a lin to this thread to the german forum: [http://www.purebasic.fr/german/viewtopic.php?t=10825]
PB 4.30

Code: Select all

onErrorGoto(?Fred)
AND51
Addict
Addict
Posts: 1040
Joined: Sun Oct 15, 2006 8:56 pm
Location: Germany
Contact:

Post by AND51 »

I've got a furhter question: Can you auto-locate the checkbox? The checkbox overlaps the text and/or the buttons, if you have multi-line text!

I try to figure it out, but I'm too tired... :?
PB 4.30

Code: Select all

onErrorGoto(?Fred)
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

Another Sparkie masterpiece.

Well done and thanks for sharing with us.

It's going in my toolbox :)

cheers
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

That is great Sparks. :)

Where the hell d'ya pull #WH_CBT from?

I've seen it in passing, but never thought anything of it! It really seems quite powerful though - as demonstrated by your code! I don't think the docs do this one justice.

Nice one.

:)
I may look like a mule, but I'm not a complete ass.
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Thank you all, and you're all welcome :)

@srod: I first used WH_CALLWNDPROC but then I remembered using WH_CBT in one of my previous projects after reading somewhere (Google) that the WH_CBT uses less overhead since it reports back on fewer messages. The only messages we really need are the creation (HCBT_CREATEWND) and activation (HCBT_ACTIVATE) of our MessageRequester.
AND51 wrote:The checkbox overlaps the text and/or the buttons, if you have multi-line text!
I can't reproduce this. See if the new code works any better for you. :)

Use AskAgainRequester() in place of the native PB MessageRequester(). It takes the exact same parameters.

Code: Select all

; ***************************************************** 
; Code    : MessageRequester with "Don't ask me again" 
; Author  : Sparkie 
; Date    : November 18, 2006 
; OS      : Windows only 
; License : It's all yours to use as you so desire 
;           (props/credit would be nice) 
; ***************************************************** 

Global hHook.l = 0, oldProc.l = 0, askagain.l = 0 

;...These are missing in PB def 
#BS_TEXT = 0 
#IDABORT = 3
#IDTRYAGAIN = 10
#IDCONTINUE = 11

;...Make sure Checkbox ID <> any of the other MessageRequester buttons 
#CheckBoxID = 12 

;...Subclassed MessageRequester Procedure() 
Procedure MsgBoxProc(hwnd.l, msg.l, wParam.l, lParam.l) 
  result.l = CallWindowProc_(oldProc, hwnd, msg, wParam, lParam) 
  Select msg 
    Case #WM_DESTROY 
      ;...Get handle to our checkbox 
      hCheckBox.l = GetDlgItem_(hwnd, #CheckBoxID) 
      ;...Get the checkbox state. <0 = not checked> <1 = checked> 
      ;...For this test I'll set a Global var to = CheckBox state 
      ;...In a real app you could set the value in a config/ini file 
      ;...or maybe a use a Registry setting 
      askagain = SendMessage_(hCheckBox, #BM_GETCHECK, 0, 0) 
  EndSelect 
  ProcedureReturn result 
EndProcedure 

;...Our hook Procedure() 
Procedure CBTProc(nCode.l, wParam.l, lParam.l) 
  result.l = CallNextHookEx_(hHook, nCode,wParam,lParam) 
  ;...Creation of MessageRequester is here 
  If nCode = #HCBT_CREATEWND 
    *cbt_cw.CBT_CREATEWND = lParam 
    *lpcs.CREATESTRUCT = *cbt_cw\lpcs 
    ;...Take action only if this is our MessageRequester 
    If *lpcs\hWndParent = WindowID(0) And *lpcs\lpszClass = 32770 
      ;...Resize the MessageRequester to make room for our CheckBoxGadget 
      *lpcs\cy + 25 
    EndIf
    result = 0 
  EndIf 
  
  ;...MessageRequester is about to become active 
  ;...Here we will add our "Don't ask me this again" checkbox 
  If nCode = #HCBT_ACTIVATE 
    hMsgBox.l = wParam 
    ;...Subclass the MessageRequester 
    oldProc = SetWindowLong_(hMsgBox, #GWL_WNDPROC, @MsgBoxProc()) 
    hFont.l = GetStockObject_(#DEFAULT_GUI_FONT) 
    StartDrawing(WindowOutput(0))
    DrawingFont(hFont)
    cbWidth = TextWidth("Don't ask me this again.") + 22 ; add room for checkbox
    cbHeight = TextHeight("Don't ask me this again.")
    StopDrawing()
    ;...Determine Checkbox placement
    GetWindowRect_(hMsgBox, @winRC.RECT)
    pt.POINT\x = winRC\left
    pt.POINT\y = winRC\bottom
    ScreenToClient_(hMsgBox, pt)
    cbX = 10
    cbY = (pt\y - cbHeight) - 10
    hCheckBox.l = CreateWindowEx_(0, "Button", "Don't ask me this again.", #BS_AUTOCHECKBOX | #BS_TEXT | #WS_GROUP | #WS_TABSTOP | #WS_CHILD | #WS_VISIBLE, cbX, cbY, cbWidth, cbHeight, hMsgBox, #CheckBoxID, GetModuleHandle_(0), 0) 
    SendMessage_(hCheckBox, #WM_SETFONT, hFont, 0) 
    ;...Release the hook 
    UnhookWindowsHookEx_(hHook) 
    hHook = 0 
    result = 0 
  EndIf 
  ProcedureReturn result 
EndProcedure 

;...Procedure for custom MessageRequester with "Don't ask again" CheckBox
Procedure AskAgainRequester(caption$, message$, buttons_icon)
  hHook = SetWindowsHookEx_(#WH_CBT, @CBTProc(), 0, GetCurrentThreadId_()) 
  If hHook
    result = MessageRequester(caption$, message$, buttons_icon)
  EndIf
  ProcedureReturn result
EndProcedure

;Procedure to diplay the result from MessageRequester
Procedure.s DisplayAnswer(ans.l)
  Select ans
    Case #IDABORT
      ans$ = "Abort"
    Case #IDCANCEL
      ans$ = "Cancel"
    Case #IDCONTINUE
      ans$ = "Continue"
    Case #IDIGNORE
      ans$ = "Ignore"
    Case #IDNO
      ans$ = "No"
    Case #IDOK
      ans$ = "Ok"
    Case #IDRETRY
      ans$ = "Retry"
    Case #IDTRYAGAIN
      ans$ = "Try Again"
    Case #IDYES
      ans$ = "Yes"
  EndSelect
  ProcedureReturn ans$
EndProcedure
      
If OpenWindow(0, 100, 100, 300, 200, "Don't ask me again", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) 
  ButtonGadget(1, 10, 40, 280, 25, "Display Custom MessageRequester")
  ButtonGadget(2, 10, 80, 280, 25, "Display Normal MessageRequester")
  TextGadget(3, 10, 120, 280, 50, "")
  Repeat 
    Event.l = WaitWindowEvent() 
    If Event = #PB_Event_Gadget
      Select EventGadget()
        Case 1
          SetGadgetText(3, "")
          ans$ = ""
          answer.l = AskAgainRequester("Welcome", "Do you want to continue?", #MB_YESNOCANCEL | #MB_ICONQUESTION) 
          If askagain
            ans$ + #CRLF$ + "Don't ask me again was checked"
          Else
            ans$ + #CRLF$ + "Don't ask me again was not checked"
          EndIf
          SetGadgetText(3, "The answer was "  + DisplayAnswer(answer) + #CRLF$ + ans$)
        Case 2
          SetGadgetText(3, "")
          answer.l = MessageRequester("Hello", "No hook is being used right now.", #MB_OK | #MB_ICONINFORMATION) 
          SetGadgetText(3, "The answer was "  + DisplayAnswer(answer))
      EndSelect
    EndIf 
  Until Event = #PB_Event_CloseWindow 
EndIf 
;...Just in case it's still there
If hHook 
  UnhookWindowsHookEx_(hHook) 
  hHook = 0 
EndIf
End
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Doffs hat. Nice.
Dare2 cut down to size
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Thanks Dare :)

Here is another MessaageBox with a checkbox option. It's only for Win2K and up, and IMHO, it's not as useful as the previous example, but here it is just the same.

http://msdn.microsoft.com/library/defau ... xcheck.asp

Running this code will create a new Registry entry at HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain. The Name will be SparkieSaysDeleteMe. Use the App Button or go into RegEdit and delete it by hand if so desired. As always, anytime you deal with the Registry...backup...backup...backup. ;)

Code: Select all

; ******************************************************************************* 
; Code    : MessageRequester with "In the future, do not show me this dialog box" 
; Author  : Sparkie 
; Date    : November 18, 2006 
; OS      : Windows only 
; Notes   : Use at your own risk as this reads/writes in the Registry
; License : It's all yours to use as you so desire 
;           (props/credit would be nice) 
; ******************************************************************************* 

If OSVersion() > #PB_OS_Windows_ME
  If OpenWindow(0, 100, 100, 300, 200, "Don't ask me again", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) 
    ButtonGadget(1, 10, 40, 280, 25, "Display Custom MessageRequester") 
    ButtonGadget(2, 10, 70, 280, 25, "Delete Registry Entry to enable MessageRequester") 
    DisableGadget(2, 1)
    Repeat 
      Event.l = WaitWindowEvent() 
      If Event = #PB_Event_Gadget 
        Select EventGadget() 
          Case 1 
            hdll = OpenLibrary(0, "shlwapi.dll")
            If hdll
              ;...SHMessageBoxCheck() can only be called by it's ordinal
              *shmbc = GetFunctionEntry(0, 185)
              If *shmbc
                ;...6th parameter is value to return if this MessageRequester has been turned off
                ;...7th parameter is unique Registry identifier
                result = CallFunctionFast(*shmbc, WindowID(0), @"This is a test of the SHMessageBoxCheck() Function", @"Welcome", #MB_YESNO, -1, @"SparkieSaysDeleteMe")
                Select result
                  Case -1
                    ;...MessageRequester has been disabled
                    ;...Allow removal of Registry entry to re-enable Messagerequester
                    DisableGadget(2, 0)
                  Default
                    ;...MessageRequester is still enabled
                    ;...No need to delete Registry entry
                    DisableGadget(2, 1)
                EndSelect
              EndIf
              CloseLibrary(0)
            EndIf
          Case 2
            ;...Delete Registry entry
            hKey = 0
            RegOpenKeyEx_(#HKEY_CURRENT_USER, @"Software\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain", 0, #KEY_ALL_ACCESS, @hKey)
            If hKey <> 0 And result = -1
              RegDeleteValue_(hKey, @"SparkieSaysDeleteMe")
              RegCloseKey_(hKey)
              hKey = 0
              DisableGadget(2, 1)
            EndIf
        EndSelect 
      EndIf 
    Until Event = #PB_Event_CloseWindow 
  EndIf 
Else
  MessageRequester("Sorry", "This requires a minimum of Win2K", #MB_OK | #MB_ICONEXCLAMATION)
EndIf
End
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
AND51
Addict
Addict
Posts: 1040
Joined: Sun Oct 15, 2006 8:56 pm
Location: Germany
Contact:

Post by AND51 »

Great Sparkie wrote:
AND51 wrote:The checkbox overlaps the text and/or the buttons, if you have multi-line text!
I can't reproduce this. See if the new code works any better for you. :)
Hi! I tried this message-text with your old code and th checkbox overlapped the text and the buttons.
Well, with your new code (not the 2k+ one) it works well! THANK YOU AGAIN!

Code: Select all

AskAgainRequester("Welcome", "Do you want to continue?"+#CRLF$+#CRLF$+#CRLF$+#CRLF$+#CRLF$+#CRLF$+#CRLF$+#CRLF$+"There are many line-breaks... =(", #MB_YESNOCANCEL | #MB_ICONQUESTION) 
  • I tried this message-text. Old code: overlap; new code: OK!
PB 4.30

Code: Select all

onErrorGoto(?Fred)
AND51
Addict
Addict
Posts: 1040
Joined: Sun Oct 15, 2006 8:56 pm
Location: Germany
Contact:

Post by AND51 »

Sparkie wrote:Here is another MessaageBox with a checkbox option. It's only for Win2K and up, and IMHO, it's not as useful as the previous example, but here it is just the same.

http://msdn.microsoft.com/library/defau ... xcheck.asp
I'm not sure, but can't you import functions since PB 4.00 with Import and/or Prototype?

I'm just guessing right now, because I have never worked with these commands. My idea is: If you import the functions into your final EXE, you can use the API command also on Win 9x/ME etc.
PB 4.30

Code: Select all

onErrorGoto(?Fred)
BarryG
Addict
Addict
Posts: 4225
Joined: Thu Apr 18, 2019 8:17 am

Re: What parameters does PB use internally to create windows?

Post by BarryG »

Sparkie's code here doesn't work anymore (illegal memory access) -> viewtopic.php?p=171031#p171031

Anyone know how to fix it? Thanks.
Comfort
User
User
Posts: 32
Joined: Thu Jul 05, 2018 11:52 pm

Re: What parameters does PB use internally to create windows?

Post by Comfort »

BarryG wrote: Sun Apr 16, 2023 1:38 am Sparkie's code here doesn't work anymore (illegal memory access) -> viewtopic.php?p=171031#p171031

Anyone know how to fix it? Thanks.
A couple of variables need to be integers for it to work with C backend compiler... there could be more.

Line 10 :

Code: Select all

Global hHook.i = 0, oldProc.i = 0, askagain.l = 0 
Fred
Administrator
Administrator
Posts: 18352
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: What parameters does PB use internally to create windows?

Post by Fred »

I just updated the code for PB6+
Post Reply