ページ 1 / 1
他プロセスのウィンドウの表示内容を取得したい
Posted: 2011年2月07日(月) 00:30
by Cir
いつもお世話になっております。
早速質問なのですが、件名のとおり、他プロセスのウィンドウの表示内容(クライアント領域、非クライアント領域の両方)を一定間隔(500msくらい)で取得し、自ウィンドウのクライアント領域に描画したいのです。
図で表すと

- fig1.JPG (54.17 KiB) 閲覧数: 8603 回
このような感じです(AAA.exeのウィンドウにマインスイーパのウィンドウが描画されている)。
はじめは
コード:
HDC hdc_Target;
HWND hTargetWnd;
hdc_Target = GetWindowDC(hTargetWnd);
/*
BitBlt使ったりして自ウィンドウに他プロセスのウィンドウを描画
*/
ReleaseDC(hTargetWnd, hdc_Target);
対象のウィンドウ全体のデバイスコンテキストを取得し、BitBltを使用して自ウィンドウに描画していたのですが、この方法だと他のウィンドウが対象のウィンドウに覆いかぶさってしまうと、

- fig2.JPG (52.2 KiB) 閲覧数: 8603 回
のように、覆いかぶさったウィンドウごと取得してしまうのです。また対象ウィンドウが最小化されていたり、画面外にはみ出していたりすると、その部分が黒くなっています。
PrintWindow関数を使ってもみたのですが、長時間にわたって連続で呼び出していると対象のウィンドウの表示内容が崩れしまい、この方法は使えませんでした。
何か良い方法などありますでしょうか?(説明べたで申し訳ありません…)
--------開発環境--------
・WindowsXP SP3
・VC++2008
・Win32APIを使用
Re: 他プロセスのウィンドウの表示内容を取得したい
Posted: 2011年2月07日(月) 00:47
by Ciel
画面全体のデバイスコンテキストを取得していませんか?
対象のウィンドウのデバイスコンテキストを取得して描画したら、
ウィンドウが重なっていても、問題なく描画できましたよ。
下のコードは対象の座標部分(0,0)のウィンドウハンドルを取得して、
描画するものですけど、これでウィンドウが重なってもいけました。
コード:
static HDC hdc,targethdc;
PAINTSTRUCT ps;
POINT point={0,0};
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
targethdc=GetWindowDC(WindowFromPoint(point));
BitBlt(hdc,0,0,WIDTH,HEIGHT,targethdc,0,0,SRCCOPY);
EndPaint(hwnd,&ps);
return 0;
Re: 他プロセスのウィンドウの表示内容を取得したい
Posted: 2011年2月07日(月) 00:55
by Ciel
画像はこれ。
ウィンドウを3重に重ねてもいけました。
Re: 他プロセスのウィンドウの表示内容を取得したい
Posted: 2011年2月07日(月) 17:28
by Cir
早速のご回答ありがとうございます!
せっかくコードを提示していただいたのですが、私の環境ではウィンドウが覆いかぶさった状態のものが表示されてしまいました…。
このような感じです。

- fig2_1.JPG (23.47 KiB) 閲覧数: 8552 回
スクリーン座標(0, 0)にあるVisual C++のデバイスコンテキストを500ms間隔で取得し、AAA.exe(自プロセス)のクライアントエリアに描画しているのですが、やはり覆いかぶさったウィンドウ(この画像の場合ではAAA.exeのウィンドウ)ごと表示されてしまいます。
コードは次のようにしました。
コード:
#define TIMER_ID (100)
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
static HDC hdc, hdc_target;
PAINTSTRUCT ps;
POINT point = {0, 0};
static int width, height;
switch(msg)
{
//ウィンドウが作られた
case WM_CREATE:
//500ms毎にデバイスコンテキストを取得するためにタイマーを設定しておく
SetTimer(hWnd, TIMER_ID, 500, NULL);
break;
//指定時間になった
case WM_TIMER:
InvalidateRect(hWnd, NULL, TRUE);
break;
//ウィンドウが壊される
case WM_DESTROY:
PostQuitMessage(0);
break;
//ウィンドウの大きさが変更された
case WM_SIZE:
//ウィンドウの大きさを取得しておく
width = LOWORD(lp);
height = HIWORD(lp);
break;
//描画
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
hdc_target = GetWindowDC(WindowFromPoint(point));
BitBlt(hdc, 0, 0, width, height, hdc_target, 0, 0, SRCCOPY);
//********(2011/2/7/18:00編集)ReleaseDCを忘れていたので追加*************************
ReleaseDC(WindowFromPoint(point), hdc_target);
//********編集ここまで**************************************************************************
EndPaint(hWnd, &ps);
break;
//そのほか
default:
return DefWindowProc(hWnd, msg, wp, lp);
}
return 0;
}
これは、環境によって得られる結果が異なるのでしょうか?
Re: 他プロセスのウィンドウの表示内容を取得したい
Posted: 2011年2月07日(月) 17:49
by ISLe
Cir さんが書きました:これは、環境によって得られる結果が異なるのでしょうか?
Windows Vista以降はメインウインドウごとに描画バッファを持つようになったことが関係してるのではないでしょうか。
(追記)
Windows Vista以降はウインドウの見えない部分も描画されて保持されています。
XP以前はウインドウの見えないところは本当に描かれていない(上書きされて失われている)ので対象のアプリに再描画してもらう以外に取得する方法はありません。
Re: 他プロセスのウィンドウの表示内容を取得したい
Posted: 2011年2月07日(月) 18:19
by Cir
ISLe さんが書きました:
(追記)
Windows Vista以降はウインドウの見えない部分も描画されて保持されています。
XP以前はウインドウの見えないところは本当に描かれていない(上書きされて失われている)ので対象のアプリに再描画してもらう以外に取得する方法はありません。
なるほど、そのような事情があったのですか…。
となると、ウィンドウの描画内容を取得するのは難しそうですね。
Re: 他プロセスのウィンドウの表示内容を取得したい
Posted: 2011年2月07日(月) 19:40
by Cir
解決方法が見つかりました!
対象のウィンドウをレイヤード ウィンドウにすることによって、たとえ他のウィンドウが覆いかぶさっていても問題なくウィンドウの表示内容を取得、描画することが出来ました!
ご回答してくださった皆様、本当にありがとうございました!
Re: 他プロセスのウィンドウの表示内容を取得したい
Posted: 2011年2月07日(月) 19:43
by Ciel
それは知らなかった・・・。
難しそうですね。
アクティブにして取るとかしかなさそうですね。
追記:
そんな方法があったのか。参考になりました。。
Re: 他プロセスのウィンドウの表示内容を取得したい
Posted: 2011年2月07日(月) 21:29
by ISLe
レイヤードウインドウにするとブレンド処理用にバッファが用意されるのですね。
そんな副作用があったとは。
良いことを知りました。