2012-01-03 10 views
3

実際に他の人に隠されているウィンドウ上の特定のピクセルを読み取ろうとしています。私はGDIライブラリからGetPixel関数を使用したいが、グローバルデバイスコンテキストでしか動作しないようだ。私は特定のウィンドウからピクセルを読み取ることができません。理由はわかりません。 this article PrintWindow関数を使用して、特定のウィンドウコンテンツを読み取り可能な一時的なデバイスコンテキストにコピーします。しかし私はそれを再現することはできません。ウィンドウのピクセルをzオーダーに関係なくキャプチャする

EDITは、すべて私の問題が解決されるありがとう:)
このスクリプトあなたに選びだしウィンドウ上のポインタのRGBの色を与え、ウィンドウが隠されているにもかかわらず。管理者権限で起動したプロセスのピクセルを取得するには、このプログラムを管理者権限で起動する必要があることに注意してください。

#define STRICT 
#define WINVER 0x0501 
#define _WIN32_WINNT 0x0501 
// 0x0501 for PrintWindow function 
// You must be at least running Windows XP 
// See http://msdn.microsoft.com/en-us/library/6sehtctf.aspx 

#include <stdio.h> 
#include <string.h> 
#include <windows.h> 

#define WINDOW_LIST_LIMIT 32 
#define WINDOW_NAME_LIMIT 1024 

void FatalError(char* error) 
{ 
    printf("%s", error); 
    exit(-1); 
} 

HWND window_list[WINDOW_LIST_LIMIT]; 
unsigned int window_list_index = 0; 

BOOL EnumWindowsProc(HWND window_handle, LPARAM param) 
{ 
    char window_title[WINDOW_NAME_LIMIT]; 

    if(!IsWindowVisible(window_handle)) return TRUE; 

    RECT rectangle = {0}; 
    GetWindowRect(window_handle, &rectangle); 
    if (IsRectEmpty(&rectangle)) return TRUE; 

    GetWindowText(window_handle, window_title, sizeof(window_title)); 
    if(strlen(window_title) == 0) return TRUE; 
    if(!strcmp(window_title, "Program Manager")) return TRUE; 

    window_list[window_list_index] = window_handle; 
    window_list_index++; 

    printf("%u - %s\n", window_list_index, window_title); 

    if(window_list_index == WINDOW_LIST_LIMIT) return FALSE; 
    return TRUE; 
} 

int main(int argc, char** argv) 
{ 
    unsigned int i, input; 

    EnumWindows((WNDENUMPROC) EnumWindowsProc, (LPARAM) NULL); 

    printf("\nChoose a window: "); 
    scanf("%u", &input); 
    printf("\n"); 
    if(input > window_list_index) FatalError("Bad choice..\n"); 

    HDC window_dc = GetWindowDC(window_list[input - 1]), global_dc = GetDC(0), temp_dc; 
    if(!window_dc && !global_dc) FatalError("Fatal Error - Cannot get device context.\n"); 

    POINT cursor, previous_cursor; 

    while(1) 
    { 
     temp_dc = CreateCompatibleDC(window_dc); 
     if(!temp_dc) FatalError("Fatal Error - Cannot create compatible device context.\n"); 

     RECT window_rectangle; 
     GetWindowRect(window_list[input - 1], &window_rectangle); 

     HBITMAP bitmap = CreateCompatibleBitmap(window_dc, 
      window_rectangle.right - window_rectangle.left, 
      window_rectangle.bottom - window_rectangle.top); 

     if (bitmap) 
     { 
      SelectObject(temp_dc, bitmap); 
      PrintWindow(window_list[input - 1], temp_dc, 0); 
      DeleteObject(bitmap); 
     } 

     GetCursorPos(&cursor); 
     if(cursor.x != previous_cursor.x && cursor.y != previous_cursor.y) 
     { 
      COLORREF color = GetPixel(temp_dc, cursor.x - window_rectangle.left, cursor.y - window_rectangle.top); 
      int red = GetRValue(color); 
      int green = GetGValue(color); 
      int blue = GetBValue(color); 

      printf("\rRGB %02X%02X%02X", red, green, blue); 

      cursor = previous_cursor; 
     } 

     DeleteDC(temp_dc); 
     Sleep(50); // for lags 
    } 

    ReleaseDC(window_list[input - 1], window_dc); 
    return 0; 
} 

私はいくつかのことを変更しましたが、User32は動的に読み込まれません。それは

gcc main.c -o main.exe -lGid32 -lUser32 

でコンパイル
は素晴らしい一日を!

+1

あなたはプロセス間でPrintWindow()仕事をすることはできません。 –

+1

@Hansあなたは本当ですか? ['PrintWindow'](http://msdn.microsoft.com/en-us/library/windows/desktop/dd162869.aspx)ドキュメントには、別途記載されています。 –

+0

はい。ペイントコードは他のプロセスにも存在します。 HDCは、プロセスの親和性を有する:[?XPで隠したりクリッピング窓からコンテンツをコピー]のhttp://stackoverflow.com/questions/2499487/sharing-hdc-between-different-processes –

答えて

4

GetDCにプロセスハンドルを渡しています。それは正しくありません。プロセスにはデバイスコンテキストがありません。プロセスは多くのウィンドウを持つことができます。

問題のウィンドウのウィンドウハンドル、HWNDを保持し、それをGetDCに渡す必要があります。私はFindWindowまたはEnumWindowsを使用して、ターゲットトップレベルウィンドウを探します。

もちろん、あなたのコードには他の問題があるかもしれませんが、それは私に飛び乗るものです。間違ったのすべての種類です

+0

ありがとうございました。私はコードに変更を加えました:) – Muja

4
HDC process_dc = GetDC(process_handle) 

まあ。 GetDCは、プロセスハンドルではなくウィンドウハンドルを受け入れます。このようなエラーを見つけるために

は、

あなたが含まれて前に置か
#define STRICT 

で再コンパイルします。

+0

'#define STRICT'はどのように機能しますか?それは私にとって初めてのことです。 –

+1

@DavidHeffernan:それは 'HANDLE'、' HDC'を、作る '' 'void *型のための代わりにエイリアスのHWND'すべての異なるタイプ。 http://msdn.microsoft.com/en-us/library/aa383731.aspx –

+0

を参照してください。CまたはC++でWin32をコード化しないと言うことができます。定義がこのようにラウンドすることは驚くばかりです。 'STRICT'はデフォルトでなければなりません。そのような犯罪を取り除くには、' #define LAX'を書かなければなりません!ありがとう。 +1 –

2

これはちょっと混乱する話題なので、私はいくつかを明確にすることができるかどうかを見てみましょう。

最初にまず:DavidとBenの両方がすでに答えているので、あなたはプロセスハンドルをGetDC関数に渡していますが間違っています。 GetDCは、ウィンドウHWNDタイプ)へのハンドルを受け入れ、そのウィンドウに対応するデバイスコンテキスト(DC、HDCタイプ)を返します。他のものが動く前に、それを修正する必要があります。今

、あなたが読んだ記事は(彼らが正しくプログラムされてきたと仮定して)ウィンドウが指定されたデバイスコンテキスト(HDC)に自分自身の画像をレンダリングすることによりWM_PRINTまたはWM_PRINTCLIENTメッセージに応答、を示しているよう。これは、ウィンドウの「イメージ」をキャプチャする簡単で効果的な方法です。オーバーラップするウィンドウでも、個々のコントロールのウィンドウでも構いません。

デバイスコンテキストへハンドルがHDCあなたは自分自身をレンダリングすることになっているその中に別のプロセス、ウィンドウに渡すことを意味し、プロセスの親和性を、持っているので、ハンスは、コメントで述べたようにRUBは、入ってきますその他のプロセスからは有効ではありません。デバイスコンテキストへのハンドルは、プロセス境界を越えて渡すことはできません。それがコードが失敗する主な理由です(またはハンドルタイプの問題を修正すると失敗する)。 MSDN entry on GDI Objectsは、これを明示的にクリアします。

GDIオブジェクトへのハンドルは、プロセスにとってプライベートです。つまり、GDIオブジェクトを作成したプロセスだけがオブジェクトハンドルを使用できます。

これを固定したり回避したりするのは、ややこしい戦いです。私は第1のメモリ内のDCを作成し、他のアプリケーションのプロセスにコードを注入することである知っている唯一の解決法は、そのメモリ内のデバイスコンテキストに描画するために、そのプロセスが所有するウィンドウにWM_PRINT又はWM_PRINTCLIENTメッセージを送信し、そして得られたビットマップを自分のアプリケーションに転送します。これは、いくつかのタイプのプロセス間通信メカニズムを実装する必要があります。

私は、WM_PRINTWM_PRINTCLIENTというメッセージを使ってプロセス間でデバイスコンテキストのハンドルを処理するという逸話的な証拠を見たことがありますが、現在の実装のアーティファクトであるかどうかは不明ですこれは、Windowsが実際にプロセス間のマーシャリングを処理しているためです。私はどちらかの方法でドキュメントを見たことがありません。これが楽しいものや限定された使い方のためにやっているワンオフプロジェクトの場合は、試してみるといいかもしれません。他の目的のためには、実際にこれを正しい方法で実行するためにIPCを使用して調べることをお勧めします。 DCはPrintWindowに渡すため

+0

これは人格的な使い方のためのものなので、PrintWindowを使うのが好きです。:)すべてのこれらの説明をありがとう – Muja

+0

WindowsはすべてのOS定義メッセージのマーシャリングを処理します。コントロール固有、WM_USER、およびWM_APPの範囲のメッセージはありません(すべてのアプリケーションにとって意味のある単一のマーシャル実装はありません)。 –

1

はGetDCを使用しないでください。互換性のあるDCを作成する必要があります(ただし、NULLを渡して一般的な画面DCにすることはできますが)。キャプチャしようとしているウィンドウのサイズと互換性のあるビットマップを作成し、DCに選択します。そのDCハンドルをPrintWindowに渡します。

WindowsはWM_PRINTまたはWM_PRINTCLIENTに適切に応答する必要はありませんので、あなたはこの作業を取得する際にも、いくつかの不具合があるかもしれません。

関連する問題