Firstly, there is an article on MSDN that discusses the changes that have occurred in the elements of the subclass between version 6.0 and earlier that you should be familiar with.
The best way to maintain backward compatibility is to create wrapper functions for subclass controls. This will require the dynamic loading of the functions required for subclass controls in version 6 of comctl32.dll. Here is a rough example of how this can be done.
typedef BOOL (WINAPI *LPFN_SETWINDOWSUBCLASS)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); typedef LRESULT (WINAPI *LPFN_DEFSUBCLASSPROC)(HWND, UINT, WPARAM, LPARAM); typedef BOOL (WINAPI *LPFN_REMOVEWINDOWSUBCLASS)(HWND, SUBCLASSPROC, UINT_PTR); typedef BOOL (WINAPI *LPFN_INITCOMMONCONTROLSEX)(LPINITCOMMONCONTROLSEX); typedef struct SubclassStruct { WNDPROC Proc; } SubclassStruct; LPFN_SETWINDOWSUBCLASS SetWindowSubclassPtr = NULL; LPFN_REMOVEWINDOWSUBCLASS RemoveWindowSubclassPtr = NULL; LPFN_DEFSUBCLASSPROC DefSubclassProcPtr = NULL; LPFN_INITCOMMONCONTROLSEX InitCommonControlsExPtr = NULL; HMODULE ComCtlModule = NULL; int Subclasser_Init(void) { INITCOMMONCONTROLSEX CommonCtrlEx = {0}; ComCtlModule = LoadLibrary("comctl32.dll"); if (ComCtlModule == NULL) return FALSE; SetWindowSubclassPtr = (LPFN_SETWINDOWSUBCLASS)GetProcAddress(ComCtlModule, "SetWindowSubclass"); RemoveWindowSubclassPtr = (LPFN_REMOVEWINDOWSUBCLASS)GetProcAddress(ComCtlModule, "RemoveWindowSubclass"); DefSubclassProcPtr = (LPFN_DEFSUBCLASSPROC)GetProcAddress(ComCtlModule, "DefSubclassProc"); InitCommonControlsExPtr = (LPFN_INITCOMMONCONTROLSEX)GetProcAddress(ComCtlModule, "InitCommonControlsEx"); if (InitCommonControlsExPtr != NULL) { CommonCtrlEx.dwSize = sizeof(CommonCtrlEx); InitCommonControlsExPtr(&CommonCtrlEx); } return TRUE; } int Subclasser_Uninit(void) { if (ComCtlModule != NULL) FreeLibrary(ComCtlModule); return TRUE; } LRESULT CALLBACK Subclasser_SharedSubclassProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam, UINT_PTR SubclassId, DWORD_PTR RefData) { SubclassStruct *Subclass = (SubclassStruct *)SubclassId; return CallWindowProc(Subclass->Proc, hWnd, Message, wParam, lParam); } int Subclasser_SetProc(HWND hWnd, WNDPROC Proc, WNDPROC *OriginalProc, void *Param) { SubclassStruct *Subclass = NULL; int Result = TRUE; SetLastError(0); if (SetWindowLongPtr(hWnd, GWLP_USERDATA, (__int3264)(UINT_PTR)Param) == 0) { if (GetLastError() > 0) return FALSE; } if (SetWindowSubclassPtr!= NULL) { Subclass = (SubclassStruct*)malloc(sizeof(SubclassStruct)); Subclass->Proc = Proc; *OriginalProc = (WNDPROC)Subclass; Result = SetWindowSubclassPtr(hWnd, Subclasser_SharedSubclassProc, (UINT_PTR)Subclass, NULL); } else { *OriginalProc = (WNDPROC)(void *)GetWindowLongPtr(hWnd, GWLP_WNDPROC); SetLastError(0); if (SetWindowLongPtr(hWnd, GWLP_WNDPROC, (__int3264)(intptr)Proc) == 0) { if (GetLastError() > 0) Result = FALSE; } } if (Result == FALSE) return FALSE; return TRUE; } int Subclasser_UnsetProc(HWND hWnd, WNDPROC Proc, WNDPROC *OriginalProc) { SubclassStruct *Subclass = NULL; int Result = TRUE; if (RemoveWindowSubclassPtr != NULL) { if (*OriginalProc != NULL) { Subclass = (SubclassStruct *)*OriginalProc; Proc = Subclass->Proc; } Result = RemoveWindowSubclassPtr(hWnd, Subclasser_SharedSubclassProc, (UINT_PTR)Subclass); free(Subclass); } else { SetLastError(0); if (SetWindowLongPtr(hWnd, GWLP_WNDPROC, (__int3264)(UINT_PTR)*OriginalProc) == 0) { if (GetLastError() > 0) Result = FALSE; } } SetLastError(0); if (SetWindowLongPtr(hWnd, GWLP_USERDATA, 0) == 0) { if (GetLastError() > 0) Result = FALSE; } *OriginalProc = NULL; if (Result == FALSE) return FALSE; return TRUE; } LRESULT Subclasser_DefProc(WNDPROC OriginalProc, HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) { if (OriginalProc == NULL) return DefWindowProc(hWnd, Message, wParam, lParam); if (DefSubclassProcPtr != NULL) return DefSubclassProcPtr(hWnd, Message, wParam, lParam); return CallWindowProc(OriginalProc, hWnd, Message, wParam, lParam); }
The only other example can be found in OpenJDK . The only drawback is that it uses WindowProc as the identifier of the subclass, which fails if you subclass more than one control in a dialog box with the same WindowProc function. In the above example, we allocate a new memory structure called SubclassStruct and pass it as the identifier of the subclass, which ensures that each instance of the control that you use for the subclass has a unique identifier for the subclass.
If you use the subclass functions in several applications, some that use comctl32.dll <6 and some that use comctl32.dll> = 6, you can determine which version of the shared management library was loaded by retrieving the version information of the comctl32.dll file . This can be done using GetModuleFileName and GetFileVersionInfo .
Also, if you use SetWindowWord / GetWindowWord in subclass callbacks with comctl32.dll 6.0, for example, in Dr. Dobs' next article on Writing Custom Windows Controls , then you will need to use these code blocks conditionally when comctl32.dll <6. because they will not work with version 6 or higher and will cause the application to crash.