I am trying to take the CXTipListBox
from the classes here:
https://www.codeproject.com/Articles/4438/XTipComboBox-Display-tooltips-for-combobox
To use it for a CListBox
control on a dialog.
It compiles and runs fine in MFC Win32 32 bit.
But 64 bit will not compile and says:
7>XTipListBox.cpp
7>D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\XTipListBox.cpp(38,2): error C2440: 'static_cast': cannot convert from 'void (__cdecl CXTipListBox::* )(UINT)' to 'void (__cdecl CWnd::* )(UINT_PTR)'
7>D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\XTipListBox.cpp(38,2): message : Cast from base to derived requires dynamic_cast or static_cast
I am stumped.
Microsoft started shipping 64-bit versions of Windows XP for mainstream CPU architectures in 2005. The library in question (XTipComboBox) was published in 2003, understandably, without 64-bit support. The compiler error is a testament to that:
cannot convert from 'void (CXTipListBox::* )(UINT)' to 'void (CWnd::* )(UINT_PTR)'
This starts in the ON_WM_TIMER
macro. Like all message map entry macros, it requires a particular signature for the callback (and, in this case, also a fixed name, OnTimer
). The mismatch between the class types in the member function pointer types is allowed; it's the argument's type causing the build to fail.
UINT
is a type alias for unsigned int
(a 32-bit unsigned integer) for all architectures. The UINT_PTR
type introduced in the migration to 64-bit Windows is still a type alias for unsigned int
for 32-bit builds but aliases unsigned __int64
for 64-bit architectures. This is why a 32-bit build succeeds while a 64-bit build fails.
To resolve this issue, the library code needs to be updated by changing the OnTimer
class member's parameter list from taking a UINT
to accepting a UINT_PTR
instead1. It may be required to update the implementation correspondingly to account for the potentially wider type. The Programming Guide for 64-bit Windows is a valuable resource to find further information on this.
Timer IDs (and IDs in general) are frequently the source of confusion. The requirement for an ID to be unique rarely raises an eyebrow. Things turn fuzzy from here unless you follow up with two more questions:
A timer ID needs to be unique for the lifetime of a thread and can take on the value of any address. The latter is often overlooked as an opportunity. A window can't have two timers with the same ID, so how do I assign an ID that nobody else is using? takes a comprehensive look at this property and offers actionable insights.
1 This has no adverse effect for 32-bit builds. UINT
and UINT_PTR
alias the same type for 32-bit architectures, so this change is inconsequential.