Версия 6.0 общих элементов управления (comctl32.dll) реализует новый подход для элементов управления подклассами, который недоступен в старых версиях Windows. Каков наилучший способ реализации подкласса, чтобы он работал на системах, поддерживающих любую версию библиотеки общих элементов управления?Как подклассифицировать элемент управления win32 и поддерживать совместимость с более старыми версиями comctl32.dll?
ответ
Во-первых, существует article on MSDN, в котором обсуждаются изменения, которые произошли в элементах управления подклассами между версией 6.0 и ранее, с которыми вы должны быть знакомы.
Лучший способ поддерживать обратную совместимость - создавать функции-обертки для элементов управления подклассами. Это потребует динамической загрузки функций, необходимых для элементов управления подклассами в версии 6 comctl32.dll. Вот пример того, как это можно сделать.
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);
}
Только один пример можно найти в OpenJDK. Единственным недостатком является то, что он использует WindowProc как идентификатор подкласса, который сбой, если вы подклассифицируете более одного элемента управления в диалоговом окне с той же функцией WindowProc. В приведенном выше примере мы выделяем новую структуру памяти под названием SubclassStruct и передаем ее адрес в качестве идентификатора подкласса, который гарантирует, что каждый экземпляр элемента управления, который вы используете для подкласса, будет иметь уникальный идентификатор подкласса.
Если вы используете функции подкласса в нескольких приложениях, некоторые из которых используют comctl32.dll < 6, а некоторые, которые используют comctl32.dll> = 6, вы можете определить, какая версия общей библиотеки управления была загружена, получив comctl32. Информация о версии файла dll. Это можно сделать с помощью GetModuleFileName
и GetFileVersionInfo
.
Кроме того, если вы используете SetWindowWord/GetWindowWord в подклассе обратных вызовов с comctl32.dll 6.0, например, в следующей статье доктор Доббс на Writing Windows Custom Controls, то вам нужно будет использовать эти блоки кода условно, когда comctl32.dll < 6, потому что они не будут работать с версией 6 или выше и вызовет сбой приложения.
- 1. Совместимость со старыми версиями Android
- 2. Обеспечить обратную совместимость с более старыми версиями ECore
- 3. Призма 6 совместимость со старыми версиями
- 4. Совместимость заголовков HTTP2 с более старыми браузерами
- 5. Элементы управления ActiveX со старыми версиями Delphi
- 6. Тестирование с более старыми версиями .Net
- 7. Совместимость C++ с более старыми библиотеками
- 8. Любые альтернативы Clirr (двоичная и исходная совместимость со старыми версиями)?
- 9. андроид - как найти несовместимые интерфейсы с более старыми версиями
- 10. Ссылка на библиотеки DLL, построенные со старыми .Net-версиями
- 11. Ссылка на GCC Win32 API с ComCtl32
- 12. Поддерживает ли более поздние версии BJam обратную совместимость со старыми версиями Boost?
- 13. Схема управления версиями
- 14. Продукты WSO2 и совместимость с углеродными версиями
- 15. Тест со старыми версиями Firefox
- 16. Совместимость с различными версиями PDF
- 17. Как поддерживать совместимость браузера
- 18. Должны ли хранилища управления версиями поддерживать поиск?
- 19. Чрезмерное использование памяти comctl32.dll, когда элемент управления флажка видимый становится истинным
- 20. ComCtl32.dll Версия 6 с Qt
- 21. Совместимость с VB6 dll?
- 22. Совместимость OpenSocial Win32
- 23. Совместимость Cacerts с версиями java
- 24. Как поддерживать несколько компьютеров, несколько пользователей для управления версиями git
- 25. Android: Как поддерживать обратную совместимость?
- 26. Как проверить, совместим ли шаблон с более старыми версиями Firefox, Chrome и Opera
- 27. Обратная совместимость с версиями C# Reflection и NUnit
- 28. Использование `@ unittest.skipIf` со старыми версиями Python
- 29. Совместимость приложений между версиями
- 30. Wordpress скачать плагин со старыми версиями файлов
0,15% компьютеров Windows требуют кода, подобного этому. Их владельцы не покупают программное обеспечение. –
В соответствии с [документацией для 'SetWindowSubclass'] (http://msdn.microsoft.com/en-us/library/windows/desktop/bb762102.aspx) эта функция доступна для Comctl32.dll версии 5.8 или новее , Это неправильно, или это на самом деле не требует от вас выбора в v6? (Я не могу вспомнить, что далеко назад.) –
Если вы ориентируетесь на Windows 95-2000, эта функция не будет доступна. –