2012-03-17 13 views
4

共通コントロール(comctl32.dll)のバージョン6.0では、古いバージョンのWindowsでは使用できないコントロールをサブクラス化するための新しいアプローチが実装されています。どちらのバージョンの共通コントロールライブラリをサポートするシステムでも動作するように、サブクラス化を実装する最善の方法は何ですか?win32コントロールをサブクラス化し、古いバージョンのcomctl32.dllとの互換性を維持するにはどうすればよいですか?

+3

Windowsマシンの0.15%にはこのようなコードが必要です。その所有者はソフトウェアを購入していない。 –

+0

[SetWindowSubclass'のドキュメント(http://msdn.microsoft.com/en-us/library/windows/desktop/bb762102.aspx)によれば、その関数はComctl32.dll、バージョン5.8以降で使用できます。それは間違っていますか?これは実際にv6にオプトインする必要はありませんか? (私は遠くまで覚えていません) –

+0

Windows 95-2000をターゲットにしている場合、その機能は利用できなくなります。 –

答えて

4

最初に、バージョン6.0とそれ以前のバージョンの間のコントロールのサブクラス化で発生した変更について説明しているarticle on MSDNがあります。

下位互換性を維持する最も良い方法は、コントロールをサブクラス化するためのラッパー関数を作成することです。これには、comctl32.dllのバージョン6のコントロールをサブクラス化するために必要な関数を動的にロードする必要があります。これはどのように行うことができるかの大まかな例です。

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です。その欠点の1つは、同じWindowProc関数を持つダイアログ上に複数のコントロールをサブクラス化する場合にクラッシュするサブクラスIDとしてWindowProcを使用することです。上記の例では、SubclassStructという新しいメモリ構造体を割り当て、そのアドレスをサブクラスIDとして渡して、サブクラス化するコントロールの各インスタンスに一意のサブクラスIDを持たせるようにしています。

複数のアプリケーションでサブクラス関数を使用している場合、comctl32.dll <を使用するものと、comctl32.dll> = 6を使用するものがあります。comctl32を取得することによって読み込まれた共通コントロールライブラリのバージョンを検出できます。 DLLのファイルバージョン情報。これは、GetModuleFileNameGetFileVersionInfoを使用して行うことができます。また

、あなたが Writing Windows Custom Controlsに、次の博士ドブスの記事のように、comctl32.dllが6.0とサブクラスのコールバックにSetWindowWord/GetWindowWordを使用した場合、その後、あなたはときのcomctl32.dll条件付きで、それらのコードブロックを使用する必要があります< 6、バージョン6以上では動作しないため、アプリケーションがクラッシュする可能性があるためです。

関連する問題