49022


■概要  
ポップアップ系のダイアログの背景を透明化し、  
特定の文字列だけをデバイスコンテキストを使用して描画させています。  
これを実現するためにSetLayeredWindowAttributes()を使用しています。  
しかし、調べたところによると上記APIを使用した場合、非力なマシンだと処理が  
重くなる可能性があるとの情報があったので、より軽量で速度の早い方法が無いかを探しています。

■質問内容  
SetLayeredWindowAttributes()を使用した背景色の透過処理以外で  
より軽量になる方法は無いでしょうか？  
※DirectXを使ったやり方の方が軽くなるなど、全く別のアプローチ掲示でも何でも構いません。

■制約や補足  
Win32のDLLモジュールを作成し、そのDLLロードしたアプリケーション上で  
ダイアログ用のスレッドを生成し、そのスレッド上でダイアログプロシージャを  
動作させています。（そのため、直接アプリケーション側のウィンドウプロシージャを使用できないので直接描画ができません）  
ダイアログ側は属性として「Layred（WS_EX_LAYERED）」を設定しています。

■現状のソースコード

[code]

    DllMain(HINSTANCE hInstDLL, ...)
    {
        .
        .
        .
        case DLL_PROCESS_ATTACH:
            CreateThread(..., DlgThreadProc, hInstDLL, ...);
        .
        .
        .
    }
    
    DWORD WINAPI DlgThreadProc( LPVOID lpParameter )
    {
        HWND    hOwner;
        HWND    hDlg;
        MSG     tagMsg;
        DWORD   dwExitCode;
        BOOL    bRinf;
    
        while (1)
        {
            // ロード対象のプロセスIDからウィンドウハンドル取得（内容は割愛）
            hOwner = GetWindowHandle(GetCurrentProcessId());
            if (hOwner != NULL)
            {
                break;
            }
    
            // タイムスライス譲渡
            Sleep(0);
        }
    
        hDlg = CreateDialogParam( (HINSTANCE)lpParameter, MAKEINTRESOURCEA(IDD_DIALOGBAR), hOwner, (DLGPROC)DlgProc, 0L );
        if ( hDlg == NULL )
        {
            dwExitCode = GetLastError();
            goto ERROR_END;
        }
    
        ShowWindow( hDlg, SW_SHOWNORMAL );
    
        while ( 1 )
        {
            bRinf = GetMessage( &tagMsg, NULL, 0, 0 );
            switch ( bRinf )
            {
            case 0:                         // プログラム終了
    
                dwExitCode = ERROR_SUCCESS;
                break;
    
            case -1:                        // イベントメッセージ取得エラー
    
                dwExitCode = GetLastError();
                break;
    
            default:
    
                if ( IsDialogMessage( hDlg, &tagMsg ) == FALSE )
                {
                    TranslateMessage( &tagMsg );
                    DispatchMessage( &tagMsg );
                }
    
                break;
            }
    
            if ( bRinf == 0 || bRinf == -1 ) break;
        }
    
    ERROR_END:
        ExitThread( dwExitCode );
    }
    
    INT_PTR CALLBACK DlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
    {
        INT iRet;
    
        iRet = 0;
    
        switch (uMsg)
        {
        case WM_INITDIALOG:
    
            // カラーキー設定にて描画内容を排他
            SetLayeredWindowAttributes(hwndDlg, GetSysColor(COLOR_BTNFACE), 0, LWA_COLORKEY);
    
            iRet = 1;
    
            break;
    
        case WM_PAINT:
            hdc = BeginPaint(hwndDlg, &ps);
    
            SetBkMode(hdc, TRANSPARENT);
            SetTextColor(hdc, RGB(196, 163, 191));
    
            // 透明化されたダイアログに文字列描画
            TextOut(hdc, 20, 0, "テスト描画", sizeof("テスト描画"));
    
            EndPaint(hwndDlg, &ps);
            break;
    
        case WM_CLOSE:
            EndDialog( hwndDlg, 0 );
            break;
    
        default:;
        }
    
        return iRet;
    }
    
[/code]


CC BY-SA 4.0
2018-09-29T17:25:15.990
48834
2018-10-06T13:48:16.770
20931
question
c winapi
Win32のダイアログプロシージャによるダイアログ画面の透明化処理の軽量化方法


先日、頂いたアドバイスを元に試してみたところうまくいきました。  
下記に試した擬似コードを掲載します。

[code]

    static WNDPROC g_DefWndProc;
    
    INT_PTR CALLBACK HookWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        HDC                 hdc;
        PAINTSTRUCT         ps;
    
        switch (uMsg)
        {
        case WM_PAINT:
        {
            hdc = BeginPaint(hWnd, &ps);
            ・
            ・
            ・
            EndPaint(hWnd, &ps);
    
            break;
        }
        case WM_REQ_INIT:
        {
            // 初期化（WM_REQ_INIT = WM_USER + n）
    
            return 0;
        }
    
        case WM_CLOSE:
        {
            ・
            ・
            ・
            break;
        }
        default:;
        }
    
        // 本来のウィンドウプロシージャに譲渡
        return CallWindowProc(g_DefWndProc, hWnd, uMsg, wParam, lParam);
    }
    
    void SetHookWndProc(...)
    {
        // GetWindowHandleの処理内容は割愛
        // ※対象アプリのメインウィンドウハンドルを取得できればOK
        HWND hOwner = GetWindowHandle(GetCurrentProcessId());
    
        // サブクラス化
        g_DefWndProc = (WNDPROC)GetWindowLongPtr(hOwner, GWLP_WNDPROC);
        SetWindowLongPtr(hOwner, GWLP_WNDPROC, (LONG_PTR)HookWndProc);
    
        return;
    }
    
[/code]


CC BY-SA 4.0
2018-10-06T13:48:16.770
49022
2018-10-06T13:48:16.770
20931
48834
answer