This is a version of my cTaskDialog 1.2R2 project that uses conditional compilation to support both VB6/VBA6 and twinBASIC/VBA7 in either x86 or x64. See that page for complete project description and numerous more pictures and examples.
Notably, people have had difficulty calling this API in VBA7 64bit, because it expects a structure without packing that on 32bit, doesn't happen, but does on 64bit. In twinBASIC, there's the PackingAlignment attribute. For VBA7x64, this project implements a workaround that copies the packed structure (since the attribute is conditionally only applied in tB) into a structure consisting of just the 160 raw bytes the API expects. It does this by copying each individual member to the correct offset, which is done for the button arrays too with the pointer for those set to the workaround ones.
Since people have asked about using this in VBA, it goes back to the earlier method of using a module to help with subclassing, as the self-subclass code in the last VB6 version only works in VB6, and while twinBASIC supports AddressOf on class members, VBA7 does not. Note that there's a bug in the self-sub version that changes the way multiple pages are handled, sending all events through the first page class. So if you use multiple paged Task Dialogs, you'll now need to relocate events for the other pages to their own event Subs (the Demo does this with it's multi-page Demos).
LongPtr in VB6/VBA?
You'll need to add LongPtr support to use this codebase in VB6/VBA6. This thread provides two methods: via a typelib with an alias, or via an enum. For simplicity this project currently uses the Enum method (defined in modHelper.bas).
In the ZIP
The zip contains the .twinproj for twinBASIC, and an export directory with the project sources. You don't need the images in other projects, but you might need the manifest. The images in the root folder are just for the demo too.
IMPORTANT: For full compatibility with all platforms, the class relies on external module to help with subclassing, so you must additionally add mTDHelper.bas to any project you add cTaskDialog.cls to (you do not need mTDSample for other projects, it's just for the Demo app).
For twinBASIC, this projects requires Beta 108 or newer, although the latest Beta 154 is recommended to avoid an issue with an erroneous error saying GetSystemImageList is ambiguous (if you do wish to use an earlier version, restarting the compiler will get rid of that).
Note for users of the previous VB6 version
For multi-page Task Dialogs, it was actually a bug that all pages had their events raised in the first page's class. This version doesn't have the bug, and events will fire in the actual class of each page. So if you use multi-page dialogs, keep that in mind when switching to this version.
UPDATED: Version 1.2.4 fixes improper VarPtr calls in the VBA7x64 routines in ShowDialog and NavigatePage.
Version 1.2.3 fixes a repositioning issue on system with certain visual effects disabled. When min/max animation was disabled, the main window was resized immediately, so when it checked for a difference from the old value, there was none.
Version 1.2.2 fixes the font scaling issues on some systems, the logo position/transparency issue, an issue with the dialog resizing too small after unexpanding an expando, the Long instead of LongPtr in one unused Sub, and a bug with different behavior in a page of a multi-page task dialog if you navigate back to it after loading another. Also adds a default date/time (Now) for disabled check datetimes, and the twinBASIC Logo Demo shows querying the class for current DPI to load a larger image if needed.
This project can be downloaded from it's repository on GitHub, if you want to use that to report bugs or make feature requests (you can still do it here too). I'm no longer maintaining two separate points of download, gotta be honest they'll just get out of sync.
Last edited by fafalone; May 2nd, 2023 at 01:40 PM.
Re: [twinBASIC/VBA7/VB6] TaskDialogIndirect: cTaskDialog universal implementation x86
As a comparison, here's an x86-only twinBASIC version that's just a direct import of the VB6 project with the subclassing/callback method changed to use tB's AddressOf on class members instead of the incompatible ASM thunks in the VB6 version. Other than that it works with no changes.
Any recent version should be fine... looking back, I'd say Beta 108 is probably when support starts, because it uses the PackingAlignment attribute. If you have 153 or earlier you might get an erroneous 'GetSystemImageList is ambiguous' error that goes away if you restart the compiler.
(Which btw, I forgot about, I've temporarily removed the download while I fix it)
Last edited by fafalone; Oct 21st, 2022 at 08:30 PM.
Re: [twinBASIC/VB6/VBA7] TaskDialogIndirect: cTaskDialog universal implementation x86
Ok, project updated. The PackingAlignment attribute is inside a conditional compilation argument only for twinBASIC. In VB6 and 32bit VBA, it doesn't matter. For 64bit VBA7, I've implemented imo a rather clever workaround...
Code:
#If VBA7 Then
#If (Win64 <> 0) And (TWINBASIC = 0) Then
'VBA7 does not support the packing alignment attribute that makes calling this easy in twinBASIC; x64 inserts padding this particular API doesn't expect.
Private Type TASKDIALOG_BUTTON_VBA7
data(11) As byte
End Type
Private m_uButtons_VBA7() As TASKDIALOG_BUTTON_VBA7
Private m_uRadioButtons_VBA7() As TASKDIALOG_BUTTON_VBA7
Private Type TASKDIALOGCONFIG_VBA7
data(159) As Byte
End Type
Private uTDC_VBA7 As TASKDIALOGCONFIG_VBA7
Private Declare PtrSafe Function TaskDialogIndirect_VBA7 Lib "comctl32.dll" Alias "TaskDialogIndirect" (pTaskConfig As TASKDIALOGCONFIG_VBA7, _
pnButton As Long, _
pnRadioButton As Long, _
pfVerificationFlagChecked As Long) As Long
#End If
The correct structure size is 160 bytes; declaring it like that avoids the insertion of alignment bytes, which will cause the API to fail because VBA7 doesn't support manually aligned structures if the members are separate.
But the main structure is used everywhere, it must be a mess, right? Nope... the only place the alternate is used is right where the API is called, so only in the ShowDialog and Navigate procedures... there, I copy each individual member from the (in VBA7x64) incorrectly aligned structure to the correct offset in the byte field of the alternate:
Code:
#If (VBA7 <> 0) And (TWINBASIC = 0) And (Win64 <> 0) Then
'Special handling for 64bit VBA7, which doesn't support our manually aligned structure.
ReDim m_uButtons_VBA7(uTDC.cButtons)
Dim i As Long
If uTDC.cButtons Then
For i = 0 to uTDC.cButtons - 1
CopyMemory m_uButtons_VBA7(i).data(0), m_uButtons(i).nButtonID, 4
CopyMemory m_uButtons_VBA7(i).data(4), m_uButtons(i).pszButtonText, 8
next i
End If
ReDim m_uRadioButtons_VBA7(uTDC.cRadioButtons)
If uTDC.cRadioButtons Then
For i = 0 To uTDC.cRadioButtons - 1
CopyMemory m_uRadioButtons_VBA7(i).data(0), m_uRadioButtons(i).nButtonID, 4
CopyMemory m_uRadioButtons_VBA7(i).data(4), m_uRadioButtons(i).pszButtonText, 8
next i
End If
Dim ptrBtn As LongPtr, ptrRbn As LongPtr
ptrBtn = VarPtr(m_uButtons_VBA7(0)): ptrRbn = VarPtr(m_uRadioButtons_VBA7(0))
CopyMemory uTDC_VBA7.data(0), uTDC.cbSize, 4: CopyMemory uTDC_VBA7.data(4), uTDC.hWndParent, 8: CopyMemory uTDC_VBA7.data(12), uTDC.hInstance, 8
CopyMemory uTDC_VBA7.data(16), uTDC.dwFlags, 4: CopyMemory uTDC_VBA7.data(20), uTDC.dwCommonButtons, 4: CopyMemory uTDC_VBA7.data(24), uTDC.pszWindowTitle, 8
CopyMemory uTDC_VBA7.data(32), uTDC.pszMainIcon, 8: CopyMemory uTDC_VBA7.data(40), uTDC.pszMainInstruction, 8: CopyMemory uTDC_VBA7.data(48), uTDC.pszContent, 8
CopyMemory uTDC_VBA7.data(56), uTDC.cButtons, 4: CopyMemory uTDC_VBA7.data(60), ptrBtn, 8: CopyMemory uTDC_VBA7.data(68), uTDC.nDefaultButton, 4
CopyMemory uTDC_VBA7.data(72), uTDC.cRadioButtons, 4: CopyMemory uTDC_VBA7.data(76), ptrRbn, 8: CopyMemory uTDC_VBA7.data(84), uTDC.nDefaultRadioButton, 4
CopyMemory uTDC_VBA7.data(88), uTDC.pszVerificationText, 8: CopyMemory uTDC_VBA7.data(96), uTDC.pszExpandedInformation, 8: CopyMemory uTDC_VBA7.data(104), uTDC.pszExpandedControlText, 8
CopyMemory uTDC_VBA7.data(112), uTDC.pszCollapsedControlText, 8: CopyMemory uTDC_VBA7.data(120), uTDC.pszFooterIcon, 8: CopyMemory uTDC_VBA7.data(128), uTDC.pszFooter, 8
CopyMemory uTDC_VBA7.data(136), uTDC.pfCallback, 8: CopyMemory uTDC_VBA7.data(144), uTDC.lpCallbackData, 8: CopyMemory uTDC_VBA7.data(156), uTDC.CXWidth, 4
hr = TaskDialogIndirect_VBA7(uTDC_VBA7, pnButton, pnRadButton, pfVerify)
#Else
hr = TaskDialogIndirect(uTDC, pnButton, pnRadButton, pfVerify)
#End If
Then something similar in Navigate.
Let me know if there's any issues with this.
Note: I originally uploaded the wrong version which has a simple typo in the VBA7 loop, missing = 0. I fixed it after 10 minutes but a couple people already grabbed it, if that's you, sorry
Last edited by fafalone; Nov 23rd, 2022 at 03:12 PM.
Re: [twinBASIC/VB6/VBA7] TaskDialogIndirect: cTaskDialog universal implementation x86
UPDATED: Version 1.2.2 fixes the font scaling issues on some systems, the logo position/transparency issue, an issue with the dialog resizing too small after unexpanding an expando, the Long instead of LongPtr in one unused Sub, and a bug with different behavior in a page of a multi-page task dialog if you navigate back to it after loading another. Also adds a default date/time (Now) for disabled check datetimes, and the twinBASIC Logo Demo shows querying the class for current DPI to load a larger image if needed.
Re: [twinBASIC/VB6/VBA7] TaskDialogIndirect: cTaskDialog universal implementation x86
UPDATED: Version 1.2.3 fixes a repositioning issue on system with certain visual effects disabled. When min/max animation was disabled, the main window was resized immediately, so when it checked for a difference from the old value, there was none.
Special thanks to Wayne Phillips for figuring this out!
Re: [twinBASIC/VB6/VBA7] TaskDialogIndirect: cTaskDialog universal implementation x86
Originally Posted by fafalone
cTaskDialog64 v1.2.3
This is a version of my cTaskDialog 1.2R2 project that uses conditional compilation to support both VB6/VBA6 and twinBASIC/VBA7 in either x86 or x64. See that page for complete project description and numerous more pictures and examples.
Notably, people have had difficulty calling this API in VBA7 64bit, because it expects a structure without packing that on 32bit, doesn't happen, but does on 64bit. In twinBASIC, there's the PackingAlignment attribute. For VBA7x64, this project implements a workaround that copies the packed structure (since the attribute is conditionally only applied in tB) into a structure consisting of just the 160 raw bytes the API expects. It does this by copying each individual member to the correct offset, which is done for the button arrays too with the pointer for those set to the workaround ones.
Since people have asked about using this in VBA, it goes back to the earlier method of using a module to help with subclassing, as the self-subclass code in the last VB6 version only works in VB6, and while twinBASIC supports AddressOf on class members, VBA7 does not. Note that there's a bug in the self-sub version that changes the way multiple pages are handled, sending all events through the first page class. So if you use multiple paged Task Dialogs, you'll now need to relocate events for the other pages to their own event Subs (the Demo does this with it's multi-page Demos).
LongPtr in VB6/VBA?
You'll need to add LongPtr support to use this codebase in VB6/VBA6. This thread provides two methods: via a typelib with an alias, or via an enum. For simplicity this project currently uses the Enum method (defined in modHelper.bas).
In the ZIP
The zip contains the .twinproj for twinBASIC, and an export directory with the project sources. You don't need the images in other projects, but you might need the manifest. The images in the root folder are just for the demo too.
IMPORTANT: For full compatibility with all platforms, the class relies on external module to help with subclassing, so you must additionally add mTDHelper.bas to any project you add cTaskDialog.cls to (you do not need mTDSample for other projects, it's just for the Demo app).
For twinBASIC, this projects requires Beta 108 or newer, although the latest Beta 154 is recommended to avoid an issue with an erroneous error saying GetSystemImageList is ambiguous (if you do wish to use an earlier version, restarting the compiler will get rid of that).
Note for users of the previous VB6 version
For multi-page Task Dialogs, it was actually a bug that all pages had their events raised in the first page's class. This version doesn't have the bug, and events will fire in the actual class of each page. So if you use multi-page dialogs, keep that in mind when switching to this version.
UPDATED: Version 1.2.3 fixes a repositioning issue on system with certain visual effects disabled. When min/max animation was disabled, the main window was resized immediately, so when it checked for a difference from the old value, there was none.
Version 1.2.2 fixes the font scaling issues on some systems, the logo position/transparency issue, an issue with the dialog resizing too small after unexpanding an expando, the Long instead of LongPtr in one unused Sub, and a bug with different behavior in a page of a multi-page task dialog if you navigate back to it after loading another. Also adds a default date/time (Now) for disabled check datetimes, and the twinBASIC Logo Demo shows querying the class for current DPI to load a larger image if needed.
Known Issues
-Custom control repositioning after expansion is incorrect on some systems. This is related to DPI scaling, but as I'm on a 150% scale myself and it doesn't happen on my system, it's proving difficult to isolate and fix the cause of this without breaking positioning on my system and/or 100% scale.
This project is also on GitHub, if you want to use that to report bugs or make feature requests (you can still do it here too).
Good day to you Mr. fafalone,
I love the work with the task dialog. The folks I work for recently switched to Office 64 bit and I have been using your Task Dialog for their MS Access application. When the switch was made, I grabbed your 64 bit version. When the Showdialog is run the software gets hung up on Line 2485 "ptrBtn = VarPtr(m_uButtons_VBA7): ptrRbn = VarPtr(m_uRadioButtons_VBA7)" with the compile error Type mismatch, In the immediate window I get "DebugAppend Event Line 1527:[2022-11-18 08:44:41] TaskDialogIndirect ret=0x80070057:". The folks I am working with are USCG. Would you be able to assist me in finding a way to get this to work? If so, what would you need from me?
I've updated the project in the first post and on GitHub.
(Have been having trouble getting 64bit Office up and running, so haven't been able to thoroughly test... the error, 0x80070057, is 'Invalid parameter' and likely caused by having a null pointer for the buttons if you skipped over those lines when they errored; so fixing the above should fix that as well)
Edit: There does seem to be a deeper issue preventing it from working; I managed to get Office installed on a VM and I fixed some other bugs and am trying to resolve it soon. Update: I'm honestly at loss right now; the VBA code to call it by byte array works perfectly under twinBASIC x64 now, but VBA just keeps crashing. I've traced it to the callback method... if I disable the callback, it works... but that also eliminates numerous basic features.
Last edited by fafalone; Nov 27th, 2022 at 09:23 PM.