ホーム | プログラミングTClock |


2003/12/01記。

サブクラス化の競合対策

TClock Light(031201以降)では、ほかのTClock型のソフトウェア(タスクバーの各パーツをサブクラス化するソフトウェア)との競合を防ぐため、「すでにサブクラス化されているウィンドウはサブクラス化しない」という対策を取っています。

サブクラス化のチェック

指定されたウィンドウがすでにサブクラス化されているかどうかを調べるために、関数IsSubclassedを用意しました(dll/dllutil.c)。API GetClassLongでウィンドウクラスに設定されたウィンドウプロシージャのアドレスを取り出し、API GetWindowLongで現在のウィンドウプロシージャのアドレスを取り出して、比較します。

NT系(NT4/2000/XP)の場合はユニコード版のAPI 何々W を使い、そうでなければAPI 何々A を使います。

BOOL IsSubclassed(HWND hwnd)
{
    LONG wndproc1, wndproc2;
    
    if(g_winver&WINNT)
    {
        wndproc1 = GetClassLongW(hwnd, GCL_WNDPROC);
        wndproc2 = GetWindowLongW(hwnd, GWL_WNDPROC);
    }
    else
    {
        wndproc1 = GetClassLongA(hwnd, GCL_WNDPROC);
        wndproc2 = GetWindowLongA(hwnd, GWL_WNDPROC);
    }
    
    if(wndproc1 != wndproc2) return TRUE;
    return FALSE;
}

時計の改造を始める前には、時計ウィンドウがサブクラス化されているかどうかを調べ、サブクラス化されていれば、改造を失敗させます(dll/main2.c)。

void InitClock(HWND hwnd)
{
    if(g_bInitClock) return;
    g_bInitClock = TRUE;
    
    g_hInst = GetModuleHandle(DLLFILENAME);
    
    g_winver = CheckWinVersion();       // common/util.c
    g_bIE4 = IsIE4();                   // common/util.c
    g_bVisualStyle = IsXPVisualStyle(); // common/util.c
    
    // check subclassification
    if(IsSubclassed(hwnd))
    {
        SendMessage(g_hwndTClockMain, TCM_CLOCKERROR, 0, 6);
        return;
    }
    (後略)

チェックしないウィンドウ

スタートボタンは、すでにタスクバーのプログラムによってサブクラス化されています。サブクラス化のチェックを行うと改造できなくなるので、スタートボタンの場合はチェックなしで改造しています(dll/startbtn.c)。

Windows XPの場合、タスクスイッチの子ウィンドウであるツールバーも、すでにサブクラス化されているので、チェックは行いません。タスクスイッチの子ウィンドウのツールバーは、「平らなタスクスイッチ」か「タスクスイッチにアイコンのみ表示」のときにサブクラス化されます(dll/taskswitch.c)。

TClockのあとに他のソフトが割り込んだ場合

サブクラス化のチェックは、TClock Lightがサブクラス化を始める前に、すでに他のソフトウェアによってサブクラス化が行われている場合のチェックです。TClock Lightがサブクラス化を行ったあとで、他のソフトウェアがサブクラス化を行う場合は、何も対策は取りません。そうした場合の処理の責任は、そのソフトウェアにある、ということで。