Vista Task Dialog

Share your advanced PureBasic knowledge/code with the community.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Vista Task Dialog

Post by SFSxOI »

Code updated For 5.20+

There are two versions of the new Vista TaskDialog functions, a more simple TaskDialog function (like in this post) and a more robust version with a lot more flexability (like text boxs and stuff...) called TaskDialogIndirect. Discovering these begins with accessing the correct version of COMCTL32.dll.

There are two versions of COMCTL32.dll on Windows Vista systems, one (version 5) which is a “legacy” control DLL, and one (version 6) which contains all of the new controls for Windows Vista, the legacy control version is the one installed by default and used mostly, the new version 6 is called by Vista apps. Your application needs to “opt in” to version 6, and to do so you will need to specify a manifest file. So to use the new Vista TaskDialog function you do something like this:

First the code:

Code: Select all

;Windows Vista TaskDialog for PureBasic
;by SFSxOI 27 Jan 2008
;version 1.0

;variables
	nHWND.l
	hInstance.l 
	cTitle.s
	cDescription.s
	cContent.s
	pnButton.l
	nIcon.l
	nResult.l

; CASE test values for button clicks
#IDOK = 1
#IDCANCEL = 2
#IDABORT = 3
#IDRETRY = 4
#IDIGNORE = 5
#IDYES = 6
#IDNO = 7
#IDCLOSE = 8

Enumeration ;_TASKDIALOG_COMMON_BUTTON_FLAGS
#TDCBF_OK_BUTTON            = 1 ;selected control Return value IDOK
#TDCBF_YES_BUTTON           = 2 ;selected control Return value IDYES
#TDCBF_NO_BUTTON            = 4 ;selected control Return value IDNO
#TDCBF_CANCEL_BUTTON        = 8 ;selected control Return value IDCANCEL
#TDCBF_RETRY_BUTTON         = 16 ;selected control Return value IDRETRY
#TDCBF_CLOSE_BUTTON         = 32 ;selected control Return value IDCLOSE
EndEnumeration

;Icons
#TD_ICON_BLANK = 100
#TD_ICON_WARNING = 101
#TD_ICON_QUESTION = 102
#TD_ICON_ERROR = 103
#TD_ICON_INFORMATION = 104
#TD_ICON_BLANK_AGAIN = 105
#TD_ICON_SHIELD = 106

Procedure.l x_Ansi2Uni(string.s)
  *out = AllocateMemory(Len(string)*2 * 2) 
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string))  
  ProcedureReturn *out  
EndProcedure

Procedure Task_Dialog(nHWND, hInstance, cTitle_x, cDescription_x, cContent_x, dwCommonButtons.l, nIcon_x)

Libef = LoadLibrary_("comctl32.dll")

pnButton.l
  If Libef
    *Task_Dialog_Func = GetProcAddress_(Libef, "TaskDialog")
    If *Task_Dialog_Func
    CallFunctionFast(*Task_Dialog_Func, nHWND, hInstance, cTitle_x, cDescription_x, cContent_x, dwCommonButtons.l, nIcon_x, @pnButton.l)
    EndIf
  EndIf
  FreeLibrary_(Libef)
       
ProcedureReturn pnButton
EndProcedure
 
cTitlex = x_Ansi2Uni("Task Dialog")
cDescriptionx = x_Ansi2Uni("This is a Task Dialog")
cContentx = x_Ansi2Uni("This is some content to see and something else to add in the Task Dialog to explain something or maybe give some directions and stuff.")

;TaskDialog function takes Unicode
pnButton = Task_Dialog(0, #Null, cTitlex, cDescriptionx, cContentx, #TDCBF_OK_BUTTON | #TDCBF_YES_BUTTON | #TDCBF_CANCEL_BUTTON | #TDCBF_CLOSE_BUTTON, #TD_ICON_INFORMATION)

	Select pnButton
    Case #IDOK
			Debug "You clicked the OK button"
    Case #IDYES
	    Debug "you clicked the Yes button"
    Case #IDCANCEL
			Debug "You clicked the Cancel button"
    Case #IDCLOSE
			Debug "You clicked the Close button"
  EndSelect 

next you need a resource file. Here is the resouce file - copy and paste the below into a text file saved in your application directory (folder) as TaskDialog.rc and put it in the compiler options resources:

Code: Select all

1 24 "H:\purebasic 4.10\Vista interfaces functions\TaskDialog.manifest"
Replace my path in the TaskDialog.rc file above with your own path to your manifest file (see next block below for the manifest code), you have to have the full path, anyone know of a work around for that so i can just do "TaskDialog.manifest" instead of the full path as shown above? .

And then you need the manifest file. This is the code for the manifest file. Copy and paste the below into a text file and save it in your application directory as TaskDialog.manifest

Code: Select all

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <assemblyIdentity 
        version="1.0.0.0" 
        processorArchitecture="X86" 
        name="Microsoft.TestApps.TaskDialog" 
        type="win32" 
    /> 
    <description>TaskDialog Test Application</description> 
    <dependency> 
        <dependentAssembly> 
            <assemblyIdentity 
                type="win32" 
                name="Microsoft.Windows.Common-Controls" 
                version="6.0.0.0" 
                processorArchitecture="X86" 
                publicKeyToken="6595b64144ccf1df" 
                language="*" 
        /> 
        </dependentAssembly> 
    </dependency> 
</assembly> 
and here is what the above produces, the most basic Task Dialog box for Vista:

http://i268.photobucket.com/albums/jj24 ... dialog.png
Last edited by SFSxOI on Tue Jan 29, 2008 11:51 pm, edited 3 times in total.
User avatar
Rook Zimbabwe
Addict
Addict
Posts: 4326
Joined: Tue Jan 02, 2007 8:16 pm
Location: Cypress TX
Contact:

Post by Rook Zimbabwe »

This is very cool!!! Good job!!! 8)
Binarily speaking... it takes 10 to Tango!!!

Image
http://www.bluemesapc.com/
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

Updated the code in the first post, the Ansi2Uni wasn't working correctly, replaced it, now no more problems with the text showing properly and no more of the text overlap problems. sorry bout that...

For the examples in this post use the same manifest and rc file and setup that you used in the first post in this thread.

Here is another example using the other Task Dialog function, TaskDialogIndirect and showing the use of custom button lables.

Code: Select all

Enumeration ;_TASKDIALOG_COMMON_BUTTON_FLAGS
#TDCBF_OK_BUTTON            = 1 ;selected control Return value IDOK
#TDCBF_YES_BUTTON           = 2 ;selected control Return value IDYES
#TDCBF_NO_BUTTON            = 4 ;selected control Return value IDNO
#TDCBF_CANCEL_BUTTON        = 8 ;selected control Return value IDCANCEL
#TDCBF_RETRY_BUTTON         = 16 ;selected control Return value IDRETRY
#TDCBF_CLOSE_BUTTON         = 32 ;selected control Return value IDCLOSE
EndEnumeration

Enumeration ;_TASKDIALOG_FLAGS
#TDF_ENABLE_HYPERLINKS               = 1
#TDF_USE_HICON_MAIN                  = 2
#TDF_USE_HICON_FOOTER                = 4
#TDF_ALLOW_DIALOG_CANCELLATION       = 8
#TDF_USE_COMMAND_LINKS               = 16
#TDF_USE_COMMAND_LINKS_NO_ICON       = 32
#TDF_EXPAND_FOOTER_AREA              = 64
#TDF_EXPANDED_BY_DEFAULT             = 128
#TDF_VERIFICATION_FLAG_CHECKED       = 256
#TDF_SHOW_PROGRESS_BAR               = 512
#TDF_SHOW_MARQUEE_PROGRESS_BAR       = 1024
#TDF_CALLBACK_TIMER                  = 2048
#TDF_POSITION_RELATIVE_TO_WINDOW     = 4096
#TDF_RTL_LAYOUT                      = 8192
#TDF_NO_DEFAULT_RADIO_BUTTON         = 16384
#TDF_CAN_BE_MINIMIZED                = 32768
EndEnumeration

#TD_ICON_BLANK = 100
#TD_ICON_WARNING = 101
#TD_ICON_QUESTION = 102
#TD_ICON_ERROR = 103
#TD_ICON_INFORMATION = 104
#TD_ICON_BLANK_AGAIN = 105
#TD_ICON_SHIELD = 106

Structure TASKDIALOG_BUTTON
nButtonID.l
pszButtonText.l
EndStructure

Structure TASKDIALOGCONFIG
  cbSize.l
  hwndParent.l
  hInstance.l
  dwFlags.l 
  dwCommonButtons.l
  pszWindowTitle.l 
    StructureUnion
    hMainIcon.l
    pszMainIcon.l
    EndStructureUnion
  pszMainInstruction.l
  pszContent.l
  cButtons.l
  pButtons.l
  nDefaultButton.l 
  cRadioButtons.l
  pRadioButtons.l
  nDefaultRadioButton.l
  pszVerificationText.l
  pszExpandedInformation.l
  pszExpandedControlText.l
  pszCollapsedControlText.l
    StructureUnion
    hFooterIcon.l
    pszFooterIcon.l
    EndStructureUnion
  pszFooter.l
  pfCallback.l
  lpCallbackData.l
  cxWidth.l ;width of the Task Dialog's client area in DLU's. If 0, Task Dialog will calculate the ideal width.
EndStructure

Macro MAKEINTRESOURCE(I) 
  (I) 
EndMacro

Procedure.l x_Ansi2Uni(string.s)
  *out = AllocateMemory(Len(string)*2 * 2) 
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string))  
  ProcedureReturn *out  
EndProcedure

stTaskConfig.TASKDIALOGCONFIG
ZeroMemory_(@stTaskConfig,SizeOf(TASKDIALOGCONFIG))
stTaskConfig\cbSize = SizeOf(TASKDIALOGCONFIG)
stTaskConfig\hwndParent = #Null
stTaskConfig\hInstance = #Null

stTaskConfig\dwFlags = #TDF_ALLOW_DIALOG_CANCELLATION
stTaskConfig\pszMainIcon = #TD_ICON_SHIELD

stTaskConfig\pszWindowTitle = x_Ansi2Uni("Our Application")
stTaskConfig\pszMainInstruction = x_Ansi2Uni("Do you want to install this application?");messenger client?")
stTaskConfig\pszContent = x_Ansi2Uni("This client is needed to communicate with third party applications. (This doesn't really install anything, its just an example application.)")

#ID_BUTTON_INSTALL = 1000
#ID_BUTTON_DO_NOT_INSTALL = 1001

stTaskConfig\cButtons = 2

Dim buttons.TASKDIALOG_BUTTON(1) ; an array of custom buttons
buttons(0)\nButtonID = #ID_BUTTON_INSTALL
buttons(0)\pszButtonText = x_Ansi2Uni("Install")
buttons(1)\nButtonID = #ID_BUTTON_DO_NOT_INSTALL
buttons(1)\pszButtonText = x_Ansi2Uni("Do Not install")

stTaskConfig\pButtons = @buttons(0)\nButtonID
stTaskConfig\nDefaultButton = #ID_BUTTON_INSTALL

stTaskConfig\pszExpandedInformation  = x_Ansi2Uni("An example by SFSxOI for the PureBasic Tips And Tricks Forum")
stTaskConfig\pszExpandedControlText  = x_Ansi2Uni("Show concise")
stTaskConfig\pszCollapsedControlText = x_Ansi2Uni("More information")
stTaskConfig\pszVerificationText = x_Ansi2Uni("Do not prompt me again")
stTaskConfig\dwFlags = #TDF_EXPAND_FOOTER_AREA

Procedure Task_DialogIndirect(stTaskConfig)
Global fVerifyx.l, SelRadiox.l
Libef = LoadLibrary_("comctl32.dll")

nResultx.l
  If Libef
    *Task_Dialog_Func = GetProcAddress_(Libef, "TaskDialogIndirect")
    If *Task_Dialog_Func
    CallFunctionFast(*Task_Dialog_Func, stTaskConfig, @nResultx, @SelRadio, @fVerifyx)
    EndIf
  EndIf
  FreeLibrary_(Libef)
  ProcedureReturn  nResultx      
EndProcedure

ResultN = Task_DialogIndirect(@stTaskConfig)

If fVerifyx = #True
  Debug "You checked the 'Do not prompt me again' box"
   ;set some registry To indicate so, so Next time the prompt is Not shown
Else
  ;clear the registry, so Next time the prompt is shown
EndIf 

  
  Select ResultN
    Case #ID_BUTTON_INSTALL
			Debug "You clicked the Install button" +Str(fVerifyx)
    Case #ID_BUTTON_DO_NOT_INSTALL
			Debug "You clicked the Do Not Install button"+Str(fVerifyx)
  EndSelect
and yet another version here showing more of how the Task Dialog can be a lot more flexable then the message box type of feedback to the user, and more selection with the radio buttons. This example also shows how to define custom radio buttons along with an expandable footer with information and custom button lables, along with how to use the checkbox.

Code: Select all

#IDOK = 1
#IDCANCEL = 2
#IDABORT = 3
#IDRETRY = 4
#IDIGNORE = 5
#IDYES = 6
#IDNO = 7
#IDCLOSE = 8

#TD_WARNING_ICON = -1
#TD_ERROR_ICON = -2
#TD_INFORMATION_ICON = -3
#TD_SHIELD_ICON = -4

#TD_ICON_BLANK = 100
#TD_ICON_WARNING = 101
#TD_ICON_QUESTION = 102
#TD_ICON_ERROR = 103
#TD_ICON_INFORMATION = 104
#TD_ICON_BLANK_AGAIN = 105
#TD_ICON_SHIELD = 106

Structure TASKDIALOG_BUTTON
  nButtonID.l
  pszButtonText.l
EndStructure

Structure TASKDIALOGCONFIG
  cbSize.l
  hwndParent.l
  hInstance.l
  dwFlags.l
  dwCommonButtons.l
  pszWindowTitle.l
    StructureUnion
    hMainIcon.l
    pszMainIcon.l
    EndStructureUnion
  pszMainInstruction.l
  pszContent.l
  cButtons.l
  pButtons.l
  nDefaultButton.l 
  cRadioButtons.l
  pRadioButtons.l
  nDefaultRadioButton.l
  pszVerificationText.l
  pszExpandedInformation.l
  pszExpandedControlText.l
  pszCollapsedControlText.l
    StructureUnion
    hFooterIcon.l
    pszFooterIcon.l
    EndStructureUnion
  pszFooter.l
  pfCallback.l
  lpCallbackData.l
  cxWidth.l
EndStructure

Macro MAKEINTRESOURCE(I) 
  (I) 
EndMacro

Procedure.l x_Ansi2Uni(string.s)
  *out = AllocateMemory(Len(string)*2 * 2) 
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string))  
  ProcedureReturn *out  
EndProcedure  

Dim tbButtons.TASKDIALOG_BUTTON(2)
sBtn1 = x_Ansi2Uni("Heck Yeah!")
sBtn2 = x_Ansi2Uni("Nope!")
sBtn3 = x_Ansi2Uni("Repeat The Question?")
tbButtons(0)\nButtonID = #IDYES
tbButtons(0)\pszButtonText = sBtn1
tbButtons(1)\nButtonID = #IDNO
tbButtons(1)\pszButtonText = sBtn2
tbButtons(2)\nButtonID = #IDCANCEL
tbButtons(2)\pszButtonText = sBtn3

#ID_RADIO_BUTTON_PURE = 1002
#ID_RADIO_BUTTON_BASIC = 1003
#ID_RADIO_BUTTON_IS_NEAT = 1004

Dim ID_RADIOButtons.TASKDIALOG_BUTTON(2)
IDsBtn1 = x_Ansi2Uni("Pure")
IDsBtn2 = x_Ansi2Uni("Basic")
IDsBtn3 = x_Ansi2Uni("Is Neat!?")
ID_RADIOButtons(0)\nButtonID = #ID_RADIO_BUTTON_PURE
ID_RADIOButtons(0)\pszButtonText = IDsBtn1
ID_RADIOButtons(1)\nButtonID = #ID_RADIO_BUTTON_BASIC
ID_RADIOButtons(1)\pszButtonText = IDsBtn2
ID_RADIOButtons(2)\nButtonID = #ID_RADIO_BUTTON_IS_NEAT
ID_RADIOButtons(2)\pszButtonText = IDsBtn3


sWindowTitle = x_Ansi2Uni("A Larger Task Dialog")
sMainInstruction = x_Ansi2Uni("Do you want to view the larger TaskDialog?")
sContent = x_Ansi2Uni("Here it is now with custom buttons.")
sVerify = x_Ansi2Uni("Don't show this message again")
sExpanded = x_Ansi2Uni("An example provided by SFSxOI for PureBasic Tips and Tricks.")
sCollapsedControlText = x_Ansi2Uni("Where the heck did this come from?")
sExpandedControlText = x_Ansi2Uni("Ah, got it!")

tdlg.TASKDIALOGCONFIG
tdlg\cbSize = SizeOf(tdlg)
tdlg\hwndParent = #Null
tdlg\hInstance = #Null
tdlg\dwFlags = #Null
tdlg\dwCommonButtons = #Null
tdlg\pszWindowTitle = sWindowTitle
tdlg\hMainIcon = #TD_ICON_SHIELD
tdlg\pszMainInstruction = sMainInstruction
tdlg\pszContent = sContent
tdlg\cButtons = 3
tdlg\pButtons = @tbButtons(0)\nButtonID
tdlg\cRadioButtons = 3
tdlg\pRadioButtons = @ID_RADIOButtons(0)\nButtonID
tdlg\nDefaultButton = #IDNO
tdlg\pszVerificationText = sVerify
tdlg\pszExpandedInformation = sExpanded
tdlg\pszExpandedControlText = sExpandedControlText
tdlg\pszCollapsedControlText = sCollapsedControlText
tdlg\hFooterIcon = #Null
tdlg\pszFooter = #Null
tdlg\pfCallback = #Null

Procedure Task_DialogIndirect(tdlgx)
Global fVerifyx.l, SelRadiox.l

Libef = LoadLibrary_("comctl32.dll")
  If Libef
    *Task_Dialog_Func = GetProcAddress_(Libef, "TaskDialogIndirect")
    If *Task_Dialog_Func
    CallFunctionFast(*Task_Dialog_Func, tdlgx, @ClickedButtonx, @SelRadiox, @fVerifyx)
    EndIf
  EndIf
  FreeLibrary_(Libef)
  ProcedureReturn  ClickedButtonx      
EndProcedure

ClickedButton = Task_DialogIndirect(tdlg)

If fVerifyx = #True
  Debug "You checked the 'Do not prompt me again' box"
   ;set some registry To indicate so, so Next time the prompt is Not shown
Else
  ;clear the registry, so Next time the prompt is shown
EndIf

If SelRadiox = #ID_RADIO_BUTTON_PURE
			SelRadio$ = "PURE radio button"
  Else
    If SelRadiox = #ID_RADIO_BUTTON_BASIC
    			SelRadio$ = "BASIC radio button"
    Else
      If SelRadiox = #ID_RADIO_BUTTON_IS_NEAT
      			SelRadio$ = "IS NEAT! radio button"
      EndIf
  EndIf
EndIf

Select ClickedButton

    Case #IDOK
			Debug "You clicked the OK button"
			Debug "and you also clicked the " +SelRadio$
    Case #IDCANCEL
			Debug "You clicked the Repeat Question? button"
			Debug "and you also clicked the " +SelRadio$
    Case #IDABORT
			Debug "You clicked the Abort button"
			Debug "and you also clicked the " +SelRadio$
		Case #IDRETRY
			Debug "You clicked the Retry button" +Str(ClickedButton)
			Debug "and you also clicked the " +SelRadio$
		Case #IDIGNORE
			Debug "You clicked the Ignore button" +Str(ClickedButton)
			Debug "and you also clicked the " +SelRadio$
		Case #IDYES
			Debug "You clicked the Heck Yeah! button" +Str(ClickedButton)
			Debug "and you also clicked the " +SelRadio$
		Case #IDNO
			Debug "You clicked the Nope! button" +Str(ClickedButton)
			Debug "and you also clicked the " +SelRadio$
  
  EndSelect
Last edited by SFSxOI on Sat Feb 02, 2008 6:46 pm, edited 1 time in total.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

And....from the above code samples, here are some pics of what you get:

Image

Image

Image



Don't forget that you need the manifest file and the .rc file from the first post in this thread before the above code will work.

I think these are much better looking and more useful then the old message box.
Last edited by SFSxOI on Wed Jan 30, 2008 2:49 am, edited 2 times in total.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

In this example we use the Task Dialog to demonstrate a very basic way to let the TaskDialog do some work. In this example, which is actually a modified version of an example above, we add a radio button that will, after its checked and the 'Heck Yeah!' button is clicked, open Internet Explorer and browse to the Tips and Tricks forum, more specificially to this thread :)

Don't forget to create the .rc and .manifest file's from the first post in the thread.

Heres the code:

Code: Select all

#IDOK = 1
#IDCANCEL = 2
#IDABORT = 3
#IDRETRY = 4
#IDIGNORE = 5
#IDYES = 6
#IDNO = 7
#IDCLOSE = 8

#TD_WARNING_ICON = -1
#TD_ERROR_ICON = -2
#TD_INFORMATION_ICON = -3
#TD_SHIELD_ICON = -4

#TD_ICON_BLANK = 100
#TD_ICON_WARNING = 101
#TD_ICON_QUESTION = 102
#TD_ICON_ERROR = 103
#TD_ICON_INFORMATION = 104
#TD_ICON_BLANK_AGAIN = 105
#TD_ICON_SHIELD = 106

Structure TASKDIALOG_BUTTON
  nButtonID.l
  pszButtonText.l
EndStructure

Structure TASKDIALOGCONFIG
  cbSize.l
  hwndParent.l
  hInstance.l
  dwFlags.l
  dwCommonButtons.l
  pszWindowTitle.l
    StructureUnion
    hMainIcon.l
    pszMainIcon.l
    EndStructureUnion
  pszMainInstruction.l
  pszContent.l
  cButtons.l
  pButtons.l
  nDefaultButton.l 
  cRadioButtons.l
  pRadioButtons.l
  nDefaultRadioButton.l
  pszVerificationText.l
  pszExpandedInformation.l
  pszExpandedControlText.l
  pszCollapsedControlText.l
    StructureUnion
    hFooterIcon.l
    pszFooterIcon.l
    EndStructureUnion
  pszFooter.l
  pfCallback.l
  lpCallbackData.l
  cxWidth.l
EndStructure

Macro MAKEINTRESOURCE(I) 
  (I) 
EndMacro

Procedure.l x_Ansi2Uni(string.s)
  *out = AllocateMemory(Len(string)*2 * 2) 
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string))  
  ProcedureReturn *out  
EndProcedure  

Dim tbButtons.TASKDIALOG_BUTTON(2)
sBtn1 = x_Ansi2Uni("Heck Yeah!")
sBtn2 = x_Ansi2Uni("Nope!")
sBtn3 = x_Ansi2Uni("Repeat The Question?")
tbButtons(0)\nButtonID = #IDYES
tbButtons(0)\pszButtonText = sBtn1
tbButtons(1)\nButtonID = #IDNO
tbButtons(1)\pszButtonText = sBtn2
tbButtons(2)\nButtonID = #IDCANCEL
tbButtons(2)\pszButtonText = sBtn3

#ID_RADIO_BUTTON_PURE = 1002
#ID_RADIO_BUTTON_BASIC = 1003
#ID_RADIO_BUTTON_IS_NEAT = 1004
#ID_RADIO_BUTTON_FORUM = 1005

Dim ID_RADIOButtons.TASKDIALOG_BUTTON(3)
IDsBtn1 = x_Ansi2Uni("Pure")
IDsBtn2 = x_Ansi2Uni("Basic")
IDsBtn3 = x_Ansi2Uni("Is Neat!")
IDsBtn4 = x_Ansi2Uni("Go to the Purebasic Tips and Tricks Forum - select here and click the 'Heck Yeah!' button ")
ID_RADIOButtons(0)\nButtonID = #ID_RADIO_BUTTON_PURE
ID_RADIOButtons(0)\pszButtonText = IDsBtn1
ID_RADIOButtons(1)\nButtonID = #ID_RADIO_BUTTON_BASIC
ID_RADIOButtons(1)\pszButtonText = IDsBtn2
ID_RADIOButtons(2)\nButtonID = #ID_RADIO_BUTTON_IS_NEAT
ID_RADIOButtons(2)\pszButtonText = IDsBtn3
ID_RADIOButtons(3)\nButtonID = #ID_RADIO_BUTTON_FORUM
ID_RADIOButtons(3)\pszButtonText = IDsBtn4


sWindowTitle = x_Ansi2Uni("A Larger Task Dialog")
sMainInstruction = x_Ansi2Uni("Do you want to view the larger TaskDialog?")
sContent = x_Ansi2Uni("Here it is now with custom buttons.")
sVerify = x_Ansi2Uni("Don't show this message again")
sExpanded = x_Ansi2Uni("An example provided by SFSxOI for PureBasic Tips and Tricks.")
sCollapsedControlText = x_Ansi2Uni("Where the heck did this come from?")
sExpandedControlText = x_Ansi2Uni("Ah, got it!")

tdlg.TASKDIALOGCONFIG
tdlg\cbSize = SizeOf(tdlg)
tdlg\hwndParent = #Null
tdlg\hInstance = #Null
tdlg\dwFlags = #Null
tdlg\dwCommonButtons = #Null
tdlg\pszWindowTitle = sWindowTitle
tdlg\hMainIcon = #TD_ICON_SHIELD
tdlg\pszMainInstruction = sMainInstruction
tdlg\pszContent = sContent
tdlg\cButtons = 3
tdlg\pButtons = @tbButtons(0)\nButtonID
tdlg\cRadioButtons = 4
tdlg\pRadioButtons = @ID_RADIOButtons(0)\nButtonID
tdlg\nDefaultButton = #IDNO
tdlg\pszVerificationText = sVerify
tdlg\pszExpandedInformation = sExpanded
tdlg\pszExpandedControlText = sExpandedControlText
tdlg\pszCollapsedControlText = sCollapsedControlText
tdlg\hFooterIcon = #Null
tdlg\pszFooter = #Null
tdlg\pfCallback = #Null

Procedure Task_DialogIndirect(tdlgx)
Global fVerifyx.l, SelRadiox.l

Libef = LoadLibrary_("comctl32.dll")
  If Libef
    *Task_Dialog_Func = GetProcAddress_(Libef, "TaskDialogIndirect")
    If *Task_Dialog_Func
    CallFunctionFast(*Task_Dialog_Func, tdlgx, @ClickedButtonx, @SelRadiox, @fVerifyx)
    EndIf
  EndIf
  FreeLibrary_(Libef)
  ProcedureReturn  ClickedButtonx      
EndProcedure

ClickedButton = Task_DialogIndirect(tdlg)

If fVerifyx = #True
  Debug "You checked the 'Do not prompt me again' box"
   ;set some registry To indicate so, so Next time the prompt is Not shown
Else
  ;clear the registry, so Next time the prompt is shown
EndIf

If SelRadiox = #ID_RADIO_BUTTON_PURE
SelRadio$ = "PURE radio button"
  Else
  If SelRadiox = #ID_RADIO_BUTTON_BASIC
  SelRadio$ = "BASIC radio button"
    Else
    If SelRadiox = #ID_RADIO_BUTTON_IS_NEAT
    SelRadio$ = "IS NEAT! radio button"
      Else
      If SelRadiox = #ID_RADIO_BUTTON_FORUM And ClickedButton = #IDYES
      SelRadio$ = "Go to the Purebasic Tips and Tricks Forum"
      ShellExecute_(#Null,"open","http://www.purebasic.fr/english/viewtopic.php?t=30801",#NULL$,#NULL$,#SW_SHOWMAXIMIZED)
      EndIf 
    EndIf
  EndIf
EndIf

Select ClickedButton

    Case #IDOK
			Debug "You clicked the OK button"
			Debug "and you also clicked the " +SelRadio$
    Case #IDCANCEL
			Debug "You clicked the Repeat Question? button"
			Debug "and you also clicked the " +SelRadio$
    Case #IDABORT
			Debug "You clicked the Abort button"
			Debug "and you also clicked the " +SelRadio$
		Case #IDRETRY
			Debug "You clicked the Retry button"
			Debug "and you also clicked the " +SelRadio$
		Case #IDIGNORE
			Debug "You clicked the Ignore button"
			Debug "and you also clicked the " +SelRadio$
		Case #IDNO
			Debug "You clicked the Nope button"
			Debug "and you also clicked the " +SelRadio$
		Case #IDYES
			Debug "You clicked the Heck Yeah! button"
			Debug "and you also clicked the " +SelRadio$
  
  EndSelect
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

Here is an example using the callback features, hyperlinks (in the expanded section at the bottom), Command Links buttons with icons, and setting a default button.

Don't forget to create and use the manifest and the .rc file fom the first post.

I've also included an include file below also.

first the include "TaskDialog_include.pbi"

Code: Select all

; Vista TaskDialog for PureBasic
; by SFSxOI, Feb 2 2008
; TaskDialog_include.pbi


#IDOK     = 1
#IDCANCEL = 2
#IDABORT  = 3
#IDRETRY  = 4
#IDIGNORE = 5
#IDYES    = 6
#IDNO     = 7
#IDCLOSE  = 8

#TD_WARNING_ICON      = 65535 ;MAKEINTRESOURCEW(-1)
#TD_ERROR_ICON        = 65534 ;MAKEINTRESOURCEW(-2)
#TD_INFORMATION_ICON  = 65533 ;MAKEINTRESOURCEW(-3)
#TD_SHIELD_ICON       = 65532 ;MAKEINTRESOURCEW(-4) 

#TD_ICON_BLANK        = 100
#TD_ICON_WARNING      = 101
#TD_ICON_QUESTION     = 102
#TD_ICON_ERROR        = 103
#TD_ICON_INFORMATION  = 104
#TD_ICON_BLANK_AGAIN  = 105
#TD_ICON_SHIELD       = 106

Enumeration ;_TASKDIALOG_FLAGS
  #TDF_ENABLE_HYPERLINKS               = 1
  #TDF_USE_HICON_MAIN                  = 2
  #TDF_USE_HICON_FOOTER                = 4
  #TDF_ALLOW_DIALOG_CANCELLATION       = 8
  #TDF_USE_COMMAND_LINKS               = 16
  #TDF_USE_COMMAND_LINKS_NO_ICON       = 32
  #TDF_EXPAND_FOOTER_AREA              = 64
  #TDF_EXPANDED_BY_DEFAULT             = 128
  #TDF_VERIFICATION_FLAG_CHECKED       = 256
  #TDF_SHOW_PROGRESS_BAR               = 512
  #TDF_SHOW_MARQUEE_PROGRESS_BAR       = 1024
  #TDF_CALLBACK_TIMER                  = 2048
  #TDF_POSITION_RELATIVE_TO_WINDOW     = 4096
  #TDF_RTL_LAYOUT                      = 8192
  #TDF_NO_DEFAULT_RADIO_BUTTON         = 16384
  #TDF_CAN_BE_MINIMIZED                = 32768
EndEnumeration

Enumeration ; _TASKDIALOG_NOTIFICATIONS
  #TDN_CREATED                         = 0
  #TDN_NAVIGATED                       = 1
  #TDN_BUTTON_CLICKED                  = 2  ; wParam = Button ID
  #TDN_HYPERLINK_CLICKED               = 3  ; lParam = (LPCWSTR)pszHREF
  #TDN_TIMER                           = 4  ; wParam = Milliseconds since dialog created Or timer reset
  #TDN_DESTROYED                       = 5
  #TDN_RADIO_BUTTON_CLICKED            = 6  ; wParam = Radio Button ID
  #TDN_DIALOG_CONSTRUCTED              = 7
  #TDN_VERIFICATION_CLICKED            = 8  ; wParam = 1 If checkbox checked 0 If Not lParam is unused And always 0
  #TDN_HELP                            = 9
  #TDN_EXPANDO_BUTTON_CLICKED          = 10 ; wParam = 0 (dialog is now collapsed) wParam != 0 (dialog is now expanded)
EndEnumeration

Enumeration ; _TASKDIALOG_ELEMENTS
  #TDE_CONTENT
  #TDE_EXPANDED_INFORMATION
  #TDE_FOOTER
  #TDE_MAIN_INSTRUCTION
EndEnumeration 

Enumeration ; _TASKDIALOG_ICON_ELEMENTS
  #TDIE_ICON_MAIN
  #TDIE_ICON_FOOTER
EndEnumeration

Enumeration ;_TASKDIALOG_COMMON_BUTTON_FLAGS
  #TDCBF_OK_BUTTON            = 1   ;selected control Return value IDOK
  #TDCBF_YES_BUTTON           = 2   ;selected control Return value IDYES
  #TDCBF_NO_BUTTON            = 4   ;selected control Return value IDNO
  #TDCBF_CANCEL_BUTTON        = 8   ;selected control Return value IDCANCEL
  #TDCBF_RETRY_BUTTON         = 16  ;selected control Return value IDRETRY
  #TDCBF_CLOSE_BUTTON         = 32  ;selected control Return value IDCLOSE
EndEnumeration

Enumeration ; _TASKDIALOG_MESSAGES
  #TDM_NAVIGATE_PAGE                        = #WM_USER+101
  #TDM_CLICK_BUTTON                         = #WM_USER+102 ; wParam = Button ID
  #TDM_SET_MARQUEE_PROGRESS_BAR             = #WM_USER+103 ; wParam = 0 (nonMarque) wParam != 0 (Marquee)
  #TDM_SET_PROGRESS_BAR_STATE               = #WM_USER+104 ; wParam = new progress state
  #TDM_SET_PROGRESS_BAR_RANGE               = #WM_USER+105 ; lParam = MAKELPARAM(nMinRange nMaxRange)
  #TDM_SET_PROGRESS_BAR_POS                 = #WM_USER+106 ; wParam = new position
  #TDM_SET_PROGRESS_BAR_MARQUEE             = #WM_USER+107 ; wParam = 0 (stop marquee) wParam != 0 (start marquee) lparam = speed (milliseconds between repaints)
  #TDM_SET_ELEMENT_TEXT                     = #WM_USER+108 ; wParam = element (TASKDIALOG_ELEMENTS) lParam = new element text (LPCWSTR)
  #TDM_CLICK_RADIO_BUTTON                   = #WM_USER+110 ; wParam = Radio Button ID
  #TDM_ENABLE_BUTTON                        = #WM_USER+111 ; lParam = 0 (disable) lParam != 0 (enable) wParam = Button ID
  #TDM_ENABLE_RADIO_BUTTON                  = #WM_USER+112 ; lParam = 0 (disable) lParam != 0 (enable) wParam = Radio Button ID
  #TDM_CLICK_VERIFICATION                   = #WM_USER+113 ; wParam = 0 (unchecked) 1 (checked) lParam = 1 (set key focus)
  #TDM_UPDATE_ELEMENT_TEXT                  = #WM_USER+114 ; wParam = element (TASKDIALOG_ELEMENTS) lParam = new element text (LPCWSTR)
  #TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE  = #WM_USER+115 ; wParam = Button ID lParam = 0 (elevation Not required) lParam != 0 (elevation required)
  #TDM_UPDATE_ICON                          = #WM_USER+116 ; wParam = icon element (TASKDIALOG_ICON_ELEMENTS) lParam = new icon (hIcon If TDF_USE_HICON_* was set PCWSTR otherwise)
EndEnumeration

Structure TASKDIALOG_BUTTON
  nButtonID.l
  pszButtonText.l
EndStructure

Structure TASKDIALOGCONFIG
  cbSize.l
  hwndParent.l
  hInstance.l
  dwFlags.l
  dwCommonButtons.l
  pszWindowTitle.l
    StructureUnion
      hMainIcon.l
      pszMainIcon.l
    EndStructureUnion
  pszMainInstruction.l
  pszContent.l
  cButtons.l
  pButtons.l
  nDefaultButton.l 
  cRadioButtons.l
  pRadioButtons.l
  nDefaultRadioButton.l
  pszVerificationText.l
  pszExpandedInformation.l
  pszExpandedControlText.l
  pszCollapsedControlText.l
    StructureUnion
      hFooterIcon.l
      pszFooterIcon.l
    EndStructureUnion
  pszFooter.l
  pfCallback.l
  lpCallbackData.l
  cxWidth.l
EndStructure

Macro MAKEINTRESOURCE(I) ; forum code
  (I)
EndMacro

Macro MakeLong(loWord, hiWord) ; forum code - Flype
  ( hiWord << 16 | loWord ) 
EndMacro
 
Macro MAKEWPARAM(loWord, hiWord) ; forum code - Flype
  MakeLong(loWord, hiWord) 
EndMacro
 
Macro MAKELPARAM(loWord, hiWord) ; forum code - Flype
  MakeLong(loWord, hiWord) 
EndMacro
 
Macro MAKELRESULT(loWord, hiWord) ; forum code - Flype
  MakeLong(loWord, hiWord) 
EndMacro 

Procedure.l x_Ansi2Uni(string.s) ; forum code - Droopy I think
  *out = AllocateMemory(Len(string)*2 * 2) 
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string))  
  ProcedureReturn *out  
EndProcedure

Procedure.s x_Uni2Ansi(Pointer) ; forum code - Droopy I think
  Buffer.s=Space(512)
  WideCharToMultiByte_(#CP_ACP,0,Pointer,-1,@Buffer,512,0,0)
  ProcedureReturn Buffer
EndProcedure

Procedure Task_DialogIndirect(m_config)
Global m_selectedButtonId.l, m_selectedRadioButtonId.l, m_verificationChecked.l

Libef = LoadLibrary_("comctl32.dll")
  If Libef
    *Task_Dialog_Func = GetProcAddress_(Libef, "TaskDialogIndirect")
    If *Task_Dialog_Func
    CallFunctionFast(*Task_Dialog_Func, m_config, @m_selectedButtonId, @m_selectedRadioButtonId, @m_verificationChecked)
    EndIf
  EndIf
  FreeLibrary_(Libef)
  ProcedureReturn    
EndProcedure
now the example:

Code: Select all

; Vista TaskDialog for PureBasic
; by SFSxOI, Jan 31 2008
; Thanks to hallodri for the hyperlink code in *ExpandedInformation
; Thanks to freak for getting me straight on the callback

XIncludeFile "TaskDialog_include.pbi"

#ID_BUTTON_INSTALL_SINGLE_USER = 1000
#ID_BUTTON_INSTALL_MULTI_USER = 1001
#ID_BUTTON_DO_NOT_INSTALL = 1002

Procedure TDCallback(handle, notification, wParam, lParam, userdata)
; just did lParam = userdata for example
; the URL is really passed in lParam
; but I wanted to also use the lpCallbackData in the 
; TASKDIALOGCONFIG structure for example purposes.
; notice something here also, the URL is really a ANSII string but
; lpCallbackData takes a pointer and the callback gets whats in
; lpCallbackData but lParam and userdata are used here as long.
 
lParam = userdata

Select notification

  Case #TDN_HYPERLINK_CLICKED
  ShellExecute_(#Null,"open",lParam,#NULL$,#NULL$,#SW_SHOWMAXIMIZED)
  no_closeDialog = #True 
  
  Case #TDN_BUTTON_CLICKED
  ; got a button click now filter for which button
      If wParam = #ID_BUTTON_INSTALL_SINGLE_USER
      no_closeDialog = #True
      ; do something here like call another pocedure after we filter the buttons
      ; like MyDoSomethingProc(button#, <param..,.param>, no_closeDialog)
      ; no_closeDialog = #True - if the callback returns false the dialog closes
      ; this is not the exact setup, its for example purposes
      Debug "Sorry, You can only install this client on a Tuesdays."
      EndIf
      
      If wParam = #ID_BUTTON_INSTALL_MULTI_USER
      ; do something here like call another pocedure after we filter the buttons
      Debug "You may only install the client multi-user version if your name is Bud!"
      no_closeDialog = #True
      EndIf
      
      If wParam = #ID_BUTTON_DO_NOT_INSTALL
      Debug"OK, fine...be that way then, see if I care :)"
      no_closeDialog = #False
      EndIf   
  
  Case #TDN_RADIO_BUTTON_CLICKED
  Debug "#TDN_RADIO_BUTTON_CLICKED"
  no_closeDialog = #True
  
  Case #TDN_VERIFICATION_CLICKED
  Debug "#TDN_VERIFICATION_CLICKED"
  no_closeDialog = #True
  
  Case #TDN_EXPANDO_BUTTON_CLICKED
  Debug "Now, just why do you want to peek in here..hmmmm?"
  no_closeDialog = #True

EndSelect
; this is not the exact setup, its for example purposes
; normally this procedure returns #S_OK for the entire pocedure
; but since we ae not using a real window here and this
; is only an example we just return no_closeDialog
; in our example where a #False or #S_OK will close the dialog.
; In an actual application, to prevent the Task Dialog from
; closing the application must return #True
ProcedureReturn no_closeDialog 

EndProcedure

Procedure Install_Stuff_Example()

stTaskConfig.TASKDIALOGCONFIG
ZeroMemory_(@stTaskConfig,SizeOf(TASKDIALOGCONFIG))
stTaskConfig\cbSize = SizeOf(TASKDIALOGCONFIG)
stTaskConfig\hwndParent = #Null
stTaskConfig\hInstance = #Null
stTaskConfig\pszMainIcon = #TD_ICON_SHIELD
stTaskConfig\dwFlags = #TDF_ALLOW_DIALOG_CANCELLATION | #TDF_USE_COMMAND_LINKS | #TDF_EXPAND_FOOTER_AREA | #TDF_ENABLE_HYPERLINKS

WindowTitle = x_Ansi2Uni("Vista TaskDialog Example for PureBasic")
MainInstruction = x_Ansi2Uni("Do you want to install messenger client?")
Content = x_Ansi2Uni("This client is needed to communicate with third party applications.")
ExpandedInformation  = x_Ansi2Uni("Task Dialog By SFSxOI for PureBasic, <a href=" + Chr(34) + "http://www.purebasic.fr/english/viewtopic.php?t=30801/\" + Chr(34) + ">PureBasic Web Site</a>")
http$ = "http://www.purebasic.fr/english/viewtopic.php?t=30801"
ExpandedControlText  = x_Ansi2Uni("Show concise")
CollapsedControlText = x_Ansi2Uni("More information")
VerificationText     = x_Ansi2Uni("Do not prompt me again")

stTaskConfig\pszWindowTitle = WindowTitle
stTaskConfig\pszMainInstruction = MainInstruction
stTaskConfig\pszContent = Content
stTaskConfig\pszExpandedInformation  = ExpandedInformation
stTaskConfig\pszExpandedControlText  = ExpandedControlText
stTaskConfig\pszCollapsedControlText = CollapsedControlText
stTaskConfig\pszVerificationText     = VerificationText

stTaskConfig\cButtons = 3

Dim buttons.TASKDIALOG_BUTTON(2)
buttons(0)\nButtonID = #ID_BUTTON_INSTALL_SINGLE_USER
buttons(0)\pszButtonText = x_Ansi2Uni("Install single user client software.")
buttons(1)\nButtonID = #ID_BUTTON_INSTALL_MULTI_USER
buttons(1)\pszButtonText = x_Ansi2Uni("Install network client software.")
buttons(2)\nButtonID = #ID_BUTTON_DO_NOT_INSTALL
buttons(2)\pszButtonText = x_Ansi2Uni("Do not install.")
stTaskConfig\pButtons = @buttons(0)\nButtonID
stTaskConfig\nDefaultButton = #ID_BUTTON_INSTALL_SINGLE_USER
stTaskConfig\pfCallback = @TDCallback() ; register the callback
stTaskConfig\lpCallbackData = @http$ ; our web link to pass to the callback

Task_DialogIndirect(@stTaskConfig)

EndProcedure

Install_Stuff_Example()
and....here is what the above code will produce, notice the hyperlink to PureBasic in the expanded section at the bottom of the task dialog. If you click on it your browser will start up and you will be taken to this thread.

Image
Last edited by SFSxOI on Tue Feb 05, 2008 3:08 am, edited 9 times in total.
Denis
Enthusiast
Enthusiast
Posts: 704
Joined: Fri Apr 25, 2003 5:10 pm
Location: Doubs - France

Post by Denis »

Nice pieces of code, i will certainly use some of them.

Tkx SFSxOI :D
A+
Denis
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

Glad you guys like it.

Updated the include file a few posts above to add a few macros which will be needed at one point or another especially when dealing with some sort of timer or pogress bar.

Also by request, quick short procedure calls examples alluded to in the code above in the callback where I said "do something here like call another procedure ...."

Code: Select all

Procedure GetSelectedButtonId()
ProcedureReturn m_selectedButtonId.l
EndProcedure

Procedure GetSelectedRadioButtonId()
ProcedureReturn m_selectedRadioButtonId.l
EndProcedure

Procedure VerificiationChecked(m_verificationChecked.b)
ProcedureReturn m_verificationChecked
EndProcedure

Procedure ClickButton(buttonId.l)

; example : detect a button click and sendmessage to a window(hwnd) to do something 
; filter for the particular button clicked based on the button ID
; Select buttonId
; 
;   Case Button1
;   do something
;   SendMessage_(hwnd, #TDM_CLICK_BUTTON, buttonId, lParam)
; sendmessage says: "Hey MyWindow(hwnd), a button was clicked(#TDM_CLICK_BUTTON), it was button# which is a 'DoSomething' button (buttonId), now do this (lParam) 
;   Case Button2
;   do something
;   SendMessage_(hwnd, #TDM_CLICK_BUTTON, buttonId, lParam)
;   Case etc.......
; 
; EndSelect

SendMessage_(hwnd, #TDM_CLICK_BUTTON, buttonId, lParam)
EndProcedure

Procedure ClickRadioButton(buttonId.l)
; see ClickButton for example
SendMessage_(hwnd, #TDM_CLICK_RADIO_BUTTON, buttonId, lParam)
EndProcedure

Procedure ClickVerification(bool_checked.b, bool_setKeyFocus.b)
; see ClickButton for example
SendMessage_(hwnd, #TDM_CLICK_VERIFICATION, bool_checked, bool_setKeyFocus)
EndProcedure

Procedure EnableButton(buttonId.l, bool_enable.b)
; see ClickButton for example
SendMessage_(hwnd, #TDM_ENABLE_BUTTON, buttonId, bool_enable)
EndProcedure

Procedure EnableRadioButton(buttonId.l, bool_enable.b)
; see ClickButton for example
SendMessage_(hwnd, #TDM_ENABLE_RADIO_BUTTON, buttonId, bool_enable)
EndProcedure

Procedure SetMarqueeProgressBar(bool_marquee.b)
; see ClickButton for example
SendMessage_(hwnd, #TDM_SET_MARQUEE_PROGRESS_BAR, marquee, lParam)
EndProcedure

Procedure SetProgressBarMarquee(bool_marquee.b, DWORD_milliseconds.l)
; see ClickButton for example
SendMessage_(hwnd, #TDM_SET_PROGRESS_BAR_MARQUEE, marquee, DWORD_milliseconds);
EndProcedure

Procedure SetProgressBarState(state.l)
; see ClickButton for example
SendMessage_(hwnd, #TDM_SET_PROGRESS_BAR_STATE, state, lParam)
EndProcedure

Procedure SetProgressBarPosition(position.l)
; see ClickButton for example
SendMessage_(hwnd, #TDM_SET_PROGRESS_BAR_POS, position, lParam)
EndProcedure

Procedure SetProgressBarRange(minRange.w, maxRange.w)
; see ClickButton for example
SendMessage_(hwnd, #TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(minRange, maxRange))
EndProcedure

Procedure SetButtonElevationRequired(buttonId.l, bool_required.b)
; see ClickButton for example
SendMessage_(hwnd, #TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, buttonId, bool_required)
EndProcedure

Procedure OnHyperlinkClicked(hwnd, url.s)
ShellExecute_(#Null,"open",url,#NULL$,#NULL$,#SW_SHOWMAXIMIZED)
EndProcedure
Last edited by SFSxOI on Sun Feb 03, 2008 2:44 pm, edited 1 time in total.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

Someone asked me about this so I thought i'd mention it. Additional Information for Task Dialogs for Vista in PureBasic:

Look at the 'stTaskConfig\lpCallbackData = @http$' part of the code, i'm feeding it a pointer to an ansii string, its strange that it works. "So, whats so strange about that?" you might ask. Well, even though the lpCallbackData of the TASKDIALOGCONFIG is not well documented, its supposed to take a pointer to a UNICODE string and not a pointer to a ansii string, thats the strange part. lpCallbackData and the rest of the TaskDialog API are supposed to operate with unicode strings only, no ansii at all, you can notice the many ansii to unicode conversions in the code.

Even though i've not seen it mentioned anywhere, it seems that lpCallbackData will take a pointer to an ansii string after all. Which solves a problem for us because using embedded hyperlinks in TaskDialog with PureBasic are done as shown in the code above, and the href (the url) is supposed to be passed in the lParam without the need for lpCallbackData, in fact lpCallbackData from what i can tell is almost never used for anything at all and certainly not for hyperlinks. Its supposed to be; an embedded url is clicked on and the url is passed in the lParam in the callback, works fine in C++ but doesn't work that way in PureBasic.

Not sure why, if its the way the ansii to unicode conversion is done or the way the url needs to be formatted in the ExpandedInformation component...don't know. But...since lpCallbackData will take a pointer to an ansii string also and just not a pointer to a unicode string only, our problem is solved even though it means we need to have an extra variable (http$ = "http://www.purebasic.fr/english/viewtopic.php?t=30801" in the code above which is at stTaskConfig\lpCallbackData = @http$)

Anyway, lpCallbackData isn't documented very well at all, and i think aside from a brief mention in the MSDN, its not documented at all. No one mentions it or uses it from what i'v seen, in fact sometimes you will see it but its always set to #Null. I don't know if i discovered something by accident or not, or if its just the way i'm using the code.

You can pass any ansii string thru lpCallbackData as long as its a pointer to an ansii string from what I can tell so far. If you wanted to attempt to use the unicode you would need to call the library for Shell32.dll and use ShellExecuteW (not the ShellExecute being used above). Even if you did do it the standard API way that the C++ guys are doing, in PureBasic your going to find that the clicked url is indeed passed thru the lParam but its not correct and extra characters are added causing the browsing effort to fail, works OK in C++ though. But...since you can pass an ansii string thru lpCallbackData just make lParam = lpCallbackData like i did above and the url works correctly. You can also pass the link to files in your string and get it to open files... just do this:

Code: Select all

Myfile$ = "C:\myfile.txt" (or how about "C:\my_help_file.chm")

and then in lpCallbackData you would do this:

stTaskConfig\lpCallbackData = @Myfile$ ; pointer to the ansii string
then when a hyperlink to a help file or some other file on the computer is clicked on (you can redefine the hyperlink to do this in the code above), your file is opened. You could even define a url to an update for your program this way like:

Code: Select all

MyUpdatefile$ = "http://www.mysite.com/updates/my_program_update.exe"

and then in lpCallbackData you would do this:

stTaskConfig\lpCallbackData = @MyUpdatefile$ ; pointer to the ansii string
Or you could simply redefine stTaskConfig\lpCallbackData to point to anything at all as long as its 'executable' in some way and a pointer to an ansii string, it doesn't need to be a url, just move the ShellExecute to a button in the callback. You can redifine the ansii pointer fed to lpCallbackData any time you need to.

A little utility is lost in a way with having to define our url twice, but some is gained, so it balances out somewhat. Of course I could have completly screwed it up too :)

To get an idea of what i'm talking about, do this:

Code: Select all

At the top of the example a few posts above, add this:

Procedure Shell_ExecuteW(url)

open = x_Ansi2Uni("open")

Libsef = LoadLibrary_("Shell32.dll")
  If Libsef
    *Shell_ExecuteW_Func = GetProcAddress_(Libsef, "ShellExecuteW")
    If *Shell_ExecuteW_Func
    CallFunctionFast(*Shell_ExecuteW_Func, #Null, open, url, #Null, #Null, #SW_SHOWMAXIMIZED)
    EndIf
  EndIf
  FreeLibrary_(Libsef)
  ProcedureReturn    
EndProcedure

then in the Procedure:

TDCallback(hwnd, notification, wParam, lParam, userdata)

comment out the ShellExecute line thats already there and add the Shell_ExecuteW(lParam) line below it:

Case #TDN_HYPERLINK_CLICKED
 ;ShellExecute_(#Null,"open",lParam,#NULL$,#NULL$,#SW_SHOWMAXIMIZED)
  Shell_ExecuteW(lParam)

Then in the TDCallback comment out the lParam = userdata line.

Further down in the code comment out the line: stTaskConfig\lpCallbackData = @http$

Now run the example and click on the hyperlink. The browser will start and attempt to browse to this thread but will fail, if you look at the url then you will see it looks like this:

http://%22http//www.purebasic.fr/english/viewtopic.php?t=30801/",,-1,0,,,,

well, of course the attempt to browse to the page will fail.
 
I'm thinking that it gets mangled in the lParam by the way the url is repesented in the ExpandedInformation line. So, if anyone can come up with a better way to represent the url please let me know.
cas
Enthusiast
Enthusiast
Posts: 597
Joined: Mon Nov 03, 2008 9:56 pm

Re: Vista Task Dialog

Post by cas »

Hi, thanks for this code.

I have one question: i see that you are allocating some memory in x_Ansi2Uni() procedure, but where are you freeing it?
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Vista Task Dialog

Post by SFSxOI »

The memory is freed automatically when the procedure ends. But you could change it to this:

Code: Select all

Procedure.l x_Ansi2Uni(string.s)
  *out = AllocateMemory(Len(string)*2 * 2) 
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string))  
  ProcedureReturn *out
  FreeMemory(*out)  
EndProcedure
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
cas
Enthusiast
Enthusiast
Posts: 597
Joined: Mon Nov 03, 2008 9:56 pm

Re: Vista Task Dialog

Post by cas »

SFSxOI wrote:The memory is freed automatically when the procedure ends. But you could change it to this:

Code: Select all

Procedure.l x_Ansi2Uni(string.s)
  *out = AllocateMemory(Len(string)*2 * 2) 
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string))  
  ProcedureReturn *out
  FreeMemory(*out)  
EndProcedure
Is this a joke? :)
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Vista Task Dialog

Post by SFSxOI »

well, yes :)
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: Vista Task Dialog

Post by Rescator »

With PureBasic 4.40 at least, the v6 manifest is included luckily.
I created a MessageRequesterPlus) based on your code SFSxOI.
It's somewhat simplified, with a fallback (and a very "dirty" fallback) and some flashy icon selections.

Simply explained it's MessageRequester() but with Vista/Win7 flashyness and optional timeout with a progress bar.
And this is unicode only as I consider anything older than Windows 5.0 (2000) to be dead, sorry Win9x fans. ;P

Code: Select all

;Roger Hågensen 2010
;Public Domain.

;Make sure to compile with with unicode.
;since this is intended for Windows 6.x (Vista and Windows 7),
;and considering the fact that Windows 5.x (2000, XP, 2003, etc) are also unicode
;it makes sense to use unicode as it's less overhead, ansi/ascii is only needed on Win9x.

EnableExplicit

#TD_WARNING_ICON         =$FFFF
#TD_ERROR_ICON           =$FFFF-1
#TD_INFORMATION_ICON     =$FFFF-2
#TD_SHIELD_ICON          =$FFFF-3
#TD_SHIELD_GRADIENT_ICON =$FFFF-4
#TD_SHIELD_WARNING_ICON  =$FFFF-5
#TD_SHIELD_ERROR_ICON    =$FFFF-6
#TD_SHIELD_OK_ICON       =$FFFF-7
#TD_SHIELD_GRAY_ICON     =$FFFF-8

#TDF_ENABLE_HYPERLINKS           = 1
#TDF_USE_HICON_MAIN              = 2
#TDF_USE_HICON_FOOTER            = 4
#TDF_ALLOW_DIALOG_CANCELLATION   = 8
#TDF_USE_COMMAND_LINKS           = 16
#TDF_USE_COMMAND_LINKS_NO_ICON   = 32
#TDF_EXPAND_FOOTER_AREA          = 64
#TDF_EXPANDED_BY_DEFAULT         = 128
#TDF_VERIFICATION_FLAG_CHECKED   = 256
#TDF_SHOW_PROGRESS_BAR           = 512
#TDF_SHOW_MARQUEE_PROGRESS_BAR   = 1024
#TDF_CALLBACK_TIMER              = 2048
#TDF_POSITION_RELATIVE_TO_WINDOW = 4096
#TDF_RTL_LAYOUT                  = 8192
#TDF_NO_DEFAULT_RADIO_BUTTON     = 16384
#TDF_CAN_BE_MINIMIZED            = 32768

#TDN_CREATED                = 0
#TDN_NAVIGATED              = 1
#TDN_BUTTON_CLICKED         = 2
#TDN_HYPERLINK_CLICKED      = 3
#TDN_TIMER                  = 4
#TDN_DESTROYED              = 5
#TDN_RADIO_BUTTON_CLICKED   = 6
#TDN_DIALOG_CONSTRUCTED     = 7
#TDN_VERIFICATION_CLICKED   = 8
#TDN_HELP                   = 9
#TDN_EXPANDO_BUTTON_CLICKED = 10

#TDCBF_OK_BUTTON            = 1
#TDCBF_YES_BUTTON           = 2
#TDCBF_NO_BUTTON            = 4
#TDCBF_CANCEL_BUTTON        = 8
#TDCBF_RETRY_BUTTON         = 16
#TDCBF_CLOSE_BUTTON         = 32

#TDM_NAVIGATE_PAGE                        = #WM_USER+101
#TDM_CLICK_BUTTON                         = #WM_USER+102
#TDM_SET_MARQUEE_PROGRESS_BAR             = #WM_USER+103
#TDM_SET_PROGRESS_BAR_STATE               = #WM_USER+104
#TDM_SET_PROGRESS_BAR_RANGE               = #WM_USER+105
#TDM_SET_PROGRESS_BAR_POS                 = #WM_USER+106
#TDM_SET_PROGRESS_BAR_MARQUEE             = #WM_USER+107
#TDM_SET_ELEMENT_TEXT                     = #WM_USER+108
#TDM_CLICK_RADIO_BUTTON                   = #WM_USER+110
#TDM_ENABLE_BUTTON                        = #WM_USER+111
#TDM_ENABLE_RADIO_BUTTON                  = #WM_USER+112
#TDM_CLICK_VERIFICATION                   = #WM_USER+113
#TDM_UPDATE_ELEMENT_TEXT                  = #WM_USER+114
#TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE  = #WM_USER+115
#TDM_UPDATE_ICON                          = #WM_USER+116

Structure TASKDIALOGCONFIG
 cbSize.l
 hwndParent.l
 hInstance.l
 dwFlags.l
 dwCommonButtons.l
 pszWindowTitle.l
 StructureUnion
  hMainIcon.l
  pszMainIcon.l
 EndStructureUnion
 pszMainInstruction.l
 pszContent.l
 cButtons.l
 pButtons.l
 nDefaultButton.l
 cRadioButtons.l
 pRadioButtons.l
 nDefaultRadioButton.l
 pszVerificationText.l
 pszExpandedInformation.l
 pszExpandedControlText.l
 pszCollapsedControlText.l
 StructureUnion
  hFooterIcon.l
  pszFooterIcon.l
 EndStructureUnion
 pszFooter.l
 pfCallback.l
 lpCallbackData.l
 cxWidth.l
EndStructure

Structure __TD_Callback_struct__
 ms.l
 timeout.l
 timeouttriggered.l
EndStructure

#PBST_NORMAL=$0001
#PBST_ERROR=$0002
#PBST_PAUSED=$0003

Procedure.i __TD_Callback__(hwnd.i,uNotification.l,wParam.i,lParam.i,*tdcu.__TD_Callback_struct__)
 Protected result=#S_OK,ms.l,timeout.l,progress.f
 Select uNotification
  Case #TDN_DIALOG_CONSTRUCTED
   If *tdcu
	   If *tdcu\timeout>0
     SendMessage_(hwnd,#TDM_SET_PROGRESS_BAR_STATE,#PBST_NORMAL,#Null)
	   EndIf
	  EndIf
  Case #TDN_CREATED
   If *tdcu
	   If *tdcu\timeout>0
     *tdcu\ms=ElapsedMilliseconds()
	   EndIf
	  EndIf
  Case #TDN_TIMER
   If *tdcu
    If *tdcu\timeout>0
     ms=ElapsedMilliseconds()
     timeout=ms-*tdcu\ms
     progress=timeout/*tdcu\timeout
     If progress>1.0
      progress=1.0
     EndIf
     SendMessage_(hwnd,#TDM_SET_PROGRESS_BAR_POS,Int(Round(progress*100.0,#PB_Round_Nearest)),#Null)
     If timeout>=*tdcu\timeout
      result=-1
      *tdcu\timeouttriggered=#True
     EndIf
    EndIf
   EndIf
  Case #TDN_HYPERLINK_CLICKED
   If lParam
    RunProgram(PeekS(lParam))
    Debug PeekS(lParam)
   EndIf
 EndSelect
 ProcedureReturn result
EndProcedure

;Behaves the same as MessageRequester() but uses Vista and Windows 7 features.
;The extra optional timeout specified in seconds will show a progress bar,
;when it reaches zero a timeout is triggered and MessageRequesterPlus() returns #Null,
;in the case of an error it will return #PB_MessageRequester_Cancel to be on the safe side.
;If unable to use/load the Vista+ dialog then the native PureBasic requester is used as fallback.
Procedure.i MessageRequesterPlus(Title$,Text$,Flags=#Null,Timeout=0)
 Protected result=#Null,tdc.TASKDIALOGCONFIG,Text1$,Text2$,Text3$,Icon,dwFlags,tdcu.__TD_Callback_struct__,mbp.MSGBOXPARAMS,window
 Protected dll,*TaskDialogIndirect,nButtonPressed.l,*MessageBoxTimeout
	window=GetActiveWindow()
	If IsWindow(window)
	 window=WindowID(window)
	Else
	 window=#Null
	EndIf
 dll=OpenLibrary(#PB_Any,"comctl32.dll")
 If dll
  *TaskDialogIndirect=GetFunction(dll,"TaskDialogIndirect")
  If *TaskDialogIndirect
		 Select Flags&#MB_ICONMASK
		  Case #MB_ICONERROR
		   Icon=#TD_SHIELD_ERROR_ICON
		  Case #MB_ICONWARNING
		   Icon=#TD_SHIELD_WARNING_ICON
		  Case #MB_ICONINFORMATION
		   Icon=#TD_SHIELD_OK_ICON
		  Default ;#MB_ICONQUESTION
		   Icon=#TD_SHIELD_GRADIENT_ICON
		 EndSelect
		 Select Flags&$0F
		  Case #PB_MessageRequester_YesNo
		   Flags=#TDCBF_YES_BUTTON|#TDCBF_NO_BUTTON
		  Case #PB_MessageRequester_YesNoCancel
		   Flags=#TDCBF_YES_BUTTON|#TDCBF_NO_BUTTON|#TDCBF_CANCEL_BUTTON
		  Default ;#PB_MessageRequester_Ok
		   Flags=#TDCBF_OK_BUTTON
		 EndSelect
		 Text1$=StringField(Text$,1,#LF$)
		 Text2$=StringField(Text$,2,#LF$)
		 Text3$=StringField(Text$,3,#LF$)
 	 tdc\cbSize=SizeOf(TASKDIALOGCONFIG)
		 tdc\hwndParent=window
		 tdc\pszMainIcon=Icon
		 If timeout
		  tdcu\ms=ElapsedMilliseconds()
		  tdcu\timeout=Timeout*1000
		  tdc\lpCallbackData=tdcu
		  dwFlags|#TDF_SHOW_PROGRESS_BAR|#TDF_CALLBACK_TIMER
		 EndIf
		 tdc\pszWindowTitle=@Title$
		 tdc\pszMainInstruction=@Text1$
		 tdc\pszContent=@Text2$
		 tdc\pszExpandedInformation=@Text3$
		 tdc\dwCommonButtons=Flags
		 tdc\dwFlags=dwFlags|#TDF_EXPAND_FOOTER_AREA|#TDF_ENABLE_HYPERLINKS|#TDF_POSITION_RELATIVE_TO_WINDOW
		 tdc\pfCallback=@__TD_Callback__()
   result=CallFunctionFast(*TaskDialogIndirect,tdc,@nButtonPressed,#Null,#Null)
		 If result=#Null
		  Select nButtonPressed
		   Case #IDOK
		    result=#PB_MessageRequester_Ok
		   Case #IDYES
		    result=#PB_MessageRequester_Yes
		   Case #IDNO
		    result=#PB_MessageRequester_No
		   Case #IDCANCEL
		    result=#PB_MessageRequester_Cancel
		   Default ;unsupported button etc, treat it as if a timeout happened.
		    result=#Null
		  EndSelect
		 Else
		  result=#Null
		 EndIf
  EndIf
  CloseLibrary(dll)
 EndIf
 If Not *TaskDialogIndirect ;Windows 5.x (2000, XP, 2003 etc.) fallback
	 dll=OpenLibrary(#PB_Any,"user32.dll")
	 If dll
	  *MessageBoxTimeout=GetFunction(dll,"MessageBoxTimeoutW") ;pretend you never saw this,
	  If *MessageBoxTimeout ;this does not exist
    result=CallFunctionFast(*MessageBoxTimeout,window,@Text$,@Title$,Flags,#Null,Timeout*1000) ;I'm not kidding,
    If result=32000 ;these are not the droids you are looking for, I mean MessageBox, erm....
     result=#Null ;you may be on your way, move along, move along.
    EndIf
   Else
    result=MessageRequester(Title$,Text$,Flags) ;If all else fail, do it the PureBasic way!
	  EndIf
	 EndIf
 EndIf
 ProcedureReturn result
EndProcedure

OpenWindow(1,0,0,400,200,"Test",#PB_Window_ScreenCentered)

Debug MessageRequester("Do you think this is cool?","Maybe not!"+#LF$+"It's just the old messagerequester?"+#LF$+"Wouldn't it be cool to be Vista/Win7 flashy?",#PB_MessageRequester_Ok)
Debug MessageRequesterPlus("Do you think this is cool?","Isn't this cool?"+#LF$+"Hell yeah!",#PB_MessageRequester_Ok|#MB_ICONERROR,5)
Debug MessageRequesterPlus("Do you think this is cool?","This is so cool!"+#LF$+"This rocks!",#PB_MessageRequester_YesNo|#MB_ICONWARNING,5)
Debug MessageRequesterPlus("Do you think this is cool?","This is getting kinda silly, it's not THAT awsome!"+#LF$+"but it is kinda cool anyway, right?",#PB_MessageRequester_YesNoCancel|#MB_ICONINFORMATION,5)
Debug MessageRequesterPlus("Do you think this is cool?","So yeah, it's kinda cool!"+#LF$+"Just make sure to use it appropriately!"+#LF$+"This is pretty cool too: <a href="+#DQUOTE$+"http://purebasic.com/"+#DQUOTE$+">PureBasic</a>",#PB_MessageRequester_YesNoCancel)

;How should you treat a timeout? My advise is to simply treat it as if the user had Canceled whatever caused the message requester to appear in the first place.
;"Are you sure you wish to quit the program?" If a timeout then treat it as a cancel (in this case same as No as well)
;"Do you wish to save the document?" if a timeout then treat it as a yes.
;A cancel is usually a "oops I pressed the wrong button" situation or a "not now, ask me later" scenario.
;While a timeout means the user is not there, so as a program/programmer you need to decide if you should cancel, ask again later,
;or go ahead but making sure that whatever action is taken is a positive one for the user.
;After all it's better that the user must clean up a extraneus backup file, than loosing their last 2 hours of work because no backup was made.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Vista Task Dialog

Post by SFSxOI »

Thats nice Rescator. Thank You very much. I like the timeout idea. :)

This doesn't seem to be working though:

Code: Select all

<a href="+#DQUOTE$+"http://purebasic.com/"+#DQUOTE$+">PureBasic</a>"
Were you trying to put a clickable link there?
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
Post Reply