ページ 11

WinAPIでデスクトップのイベントを拾う方法

Posted: 2017年5月05日(金) 10:34
by Miti
初めて質問させていただきます。現在WinAPIとC/C++を使ってSAO Utilsのようなランチャーを作成しようと思っています。具体的には、デスクトップ上でマウスを左クリックしながら下にドラッグするとメニューが出てきて、メニューから任意のアプリケーションに飛ぶというようなものを考えています。

そこで質問なのですが、デスクトップ上でのイベントハンドルを取得するにはどうすればいいのでしょうか。GetDesktopWindow()を使ってデスクトップのウィンドウハンドルを取得することは出来、デスクトップのウィンドウハンドルを親ウィンドウにして子ウィンドウを(ボタン等)作成することは出来ましたが、イベントハンドルを拾うことが出来ません。マウスのイベントを拾うにはどうしたらいいのか、また可能なのか、どなたかご教授頂けないでしょうか。

Re: WinAPIでデスクトップのイベントを拾う方法

Posted: 2017年5月06日(土) 22:13
by Math
>そこで質問なのですが、デスクトップ上でのイベントハンドルを取得するにはどうすればいいのでしょうか。
>GetDesktopWindow()を使ってデスクトップのウィンドウハンドルを取得することは出来、デスクトップのウィンドウハンドルを
>親ウィンドウにして子ウィンドウを(ボタン等)作成することは出来ましたが、イベントハンドルを拾うことが出来ません。
>マウスのイベントを拾うにはどうしたらいいのか、また可能なのか、どなたかご教授頂けないでしょうか。
イベントハンドルといういいかたはないとおもいますが?

具体的なコードを提示していただくと明確になるのですが私がVS2017でテストしたコードです。
マウス・イベントハンドラー:(マウス・イベント処理)[Windows10,VS2017Community]

コード:

// Windows ヘッダー ファイル:
#include <windows.h>
// C ランタイム ヘッダー ファイル
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#define MAX_STRING 100

// グローバル変数:
HINSTANCE hInst;                                // 現在のインターフェイス
TCHAR szTitle[MAX_STRING]="Form1";             // タイトル バーのテキスト
TCHAR szWindowClass[MAX_STRING]="FormClass";  // メイン ウィンドウ クラス名
int Top = 20;
int Left = 10;
int Width = 300;
int Height = 200;

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM             MyRegisterClass(HINSTANCE hInstance);
BOOL             InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

//
//  関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:  メイン ウィンドウのメッセージを処理します。
//
//  WM_COMMAND  - アプリケーション メニューの処理
//  WM_PAINT    - メイン ウィンドウの描画
//  WM_DESTROY  - 中止メッセージを表示して戻る
//
// [ ここに イベント処理 プログラム を書く ]
COLORREF color;    //テキストの色
int x, y;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	HDC hdc; 
    PAINTSTRUCT ps;
	    
    switch(msg){
    case WM_CREATE:
        color = RGB( 0, 0, 0 );            //最初は黒色
        x = 50;
        y = 50;
        break;
    case WM_LBUTTONDOWN:
        color = RGB( 0, 0, 255 );        //左クリックされたら青色に
        x = LOWORD(lParam);
        y = HIWORD(lParam);
        InvalidateRect(hWnd, NULL, TRUE);  //領域無効化
        UpdateWindow(hWnd);                //再描画命令
        break;
    case WM_RBUTTONDOWN:
        color = RGB( 255, 0, 0 );        //右クリックされたら赤色に
        x = LOWORD(lParam);
        y = HIWORD(lParam);
        InvalidateRect(hWnd, NULL, TRUE);  //領域無効化
        UpdateWindow(hWnd);                //再描画命令
        break;
    //ペイント
    case WM_PAINT:
        hdc= BeginPaint (hWnd, &ps);
        SetTextColor(hdc, color);
        TextOut( hdc, x, y, "Mouse sample", 12 );
        EndPaint(hWnd, &ps);
        break;
    //終了処理
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0L;
    }
    //デフォルトの処理
    return  DefWindowProc(hWnd,msg,wParam,lParam);
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,      // コマンドラインから受け取る文字列
                     int       nCmdShow)       // ウィンドウの状態:最大化、最小化、通常
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: ここにコードを挿入してください。
	MSG msg;

	MyRegisterClass(hInstance);

	// アプリケーションの初期化を実行します:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	while (GetMessage(&msg, NULL, 0, 0))
	{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
	}

	return (int) msg.wParam;
}
//
//  関数: MyRegisterClass()
//
//  目的: ウィンドウ クラスを登録します。
//
//  コメント:
//
//    この関数および使い方は、'RegisterClassEx' 関数が追加された
//    Windows 95 より前の Win32 システムと互換させる場合にのみ必要です。
//    アプリケーションが、関連付けられた
//    正しい形式の小さいアイコンを取得できるようにするには、
//    この関数を呼び出してください。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= NULL;
	wcex.hCursor		= NULL;
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= NULL;

	return RegisterClassEx(&wcex);
}
//
//   関数: InitInstance(HINSTANCE, int)
//
//   目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します。
//
//   コメント:
//
//        この関数で、グローバル変数でインスタンス ハンドルを保存し、
//        メイン プログラム ウィンドウを作成および表示します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // グローバル変数にインスタンス処理を格納します。

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      Left, Top, Width, Height, NULL, NULL, hInstance, NULL);  

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}
[/size]
画像

Re: MathWinAPIでデスクトップのイベントを拾う方法

Posted: 2017年5月06日(土) 22:26
by Math

http://www.kumei.ne.jp/c_lang/sdk/sdk_35.htm
を参考に
メッセージ・クラッカーを使って すっきりさせることができますね。

Re: WinAPIでデスクトップのイベントを拾う方法

Posted: 2017年5月07日(日) 01:05
by Miti
質問の意図がうまく伝わってなかったようで申し訳ないです。
自作のウィンドウでのイベントハンドルの取得ではなく、デスクトップ画面のイベントハンドルの取得がしたいのです。GetDesktopWindow()関数でデスクトップ画面のウィンドウハンドルの取得はでき、GetDesktopWindow()で取得したウィンドウハンドルを親にしてボタン等の子ウィンドウを作成することはできるのですがデスクトップ画面上でのイベントハンドルが取得できず困っている次第です。どうすれば可能になるのでしょうか?

Re: WinAPIでデスクトップのイベントを拾う方法

Posted: 2017年5月07日(日) 05:44
by durandal
横から失礼します。
マウスのイベントを拾うにはどうしたらいいのか、また可能なのか、どなたかご教授頂けないでしょうか。
WindowsAPIのSetWindowLongPtr関数でハンドルを用いて、対象のウィンドウプロシージャをマウスイベントなどを設定した別のプロシージャに変更することができますが、この方法が通用するのは自プロセスに対してのみで、他のプロセスへの変更はできません。
なので回答としては、(私の知っている限りでは)不可能です。

他の方法だと、やったことがないので断定できませんが、WindowsAPIのSetWindowsHookEx関数などのフックで実現できるかもしれません。
ただ、フックはキーロガーなどのマルウェアにも用いられる手法なので、ウイルス対策ソフトなどに怒られるかもしれないです。(SAO Utilsはどういう原理なんだろう。。。)


スマートな回答ではないかもしれませんが、少しでもお力になれたらと思います

Re: WinAPIでデスクトップのイベントを拾う方法

Posted: 2017年5月07日(日) 09:04
by みけCAT
イベントではなく、マウスの入力をポーリングして「左クリックしながら下にドラッグ」したかを判定する、というのはどうでしょうか?

Re: WinAPIでデスクトップのイベントを拾う方法

Posted: 2017年5月07日(日) 23:15
by Miti
フックは最終手段として頭に入れておきます。ありがとうございます。
マウスの入力をポーリングするにはどうしたらいいのでしょうか。