2

ツリー ビューがリモート プロセスにある場合でも、ツリー ビュー アイテムのテキストを生成できる関数を作成しました。この関数は、リモート プロセスに 2 つのメモリ チャンクを割り当て、TVITEM 構造体 (リモート プロセスにコピーされたもの) を設定し、TVM_GETITEM メッセージを送信し、最後に 2 番目のリモート メモリ チャンクの内容をローカル バッファに読み込みます。これはコードです:

std::string getTreeViewItemText( HWND treeView, HTREEITEM item )
{
    DWORD pid;
    ::GetWindowThreadProcessId( treeView, &pid );

    HANDLE proc = ::OpenProcess( PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pid );
    if ( !proc )
        // handle error

    TVITEM tvi;
    ZeroMemory( &tvi, sizeof(tvi) );

    LPVOID tvi_ = ::VirtualAllocEx( proc, NULL, sizeof(tvi), MEM_COMMIT, PAGE_READWRITE);
    if ( !tvi_ )
        // handle error

    TCHAR buffer[100] = { 'X' };

    LPVOID txt_ = ::VirtualAllocEx( proc, NULL, sizeof(buffer), MEM_COMMIT, PAGE_READWRITE );
    if ( !txt_ )
        // handle error

    tvi.mask = TVIF_TEXT | TVIF_HANDLE;
    tvi.pszText =  (LPTSTR)txt_;
    tvi.cchTextMax = sizeof(buffer) / sizeof(buffer[0] );
    tvi.hItem = item;

    if ( !::WriteProcessMemory( proc, tvi_, &tvi, sizeof(tvi), NULL ) )
        // handle error

    if ( !::SendMessage( treeView, TVM_GETITEM, 0, (LPARAM)tvi_ ) )
        // handle error

    if ( !::ReadProcessMemory( proc, (LPCVOID)txt_, buffer, sizeof( buffer ), NULL ) )
        // handle error

    ::VirtualFreeEx( proc, tvi_, 0, MEM_RELEASE );

    ::VirtualFreeEx( proc, txt_, 0, MEM_RELEASE );

    ::CloseHandle( proc );

    return buffer;
}

WC_TREEVIEWこのコードは、クラス名をに渡すときに得られる単純なツリー ビューと非常にうまく連携しますCreateWindow。ただし、MS Common Controls v5 (comctl32.ocx) または MS Common Controls v6 (mscomctl.ocx) によって提供される新しいツリーでは機能しないことに気付きました。そのような場合、返されるテキストは常に空です (バッファはすべてゼロです)。また、SendMessage 呼び出しがゼロを返すことにも気付きました (したがって、// handle error上記のコメントで示されているエラー処理が開始されます)。これが本当にエラーを示しているかどうかは不明です。いずれにせよ、バッファはすべてゼロで埋められています。

他のすべてのツリー ビュー メッセージ (TVM_GETITEMRECT など) は完全に機能しているようです。

それがなぜなのか誰か知っていますか?UNICODE フラグをいじってみました (またはTVM_GETITEMに定義されていることに気付きました) が、それは役に立たなかったようです。TVM_GETITEMATVM_GETITEMW

4

3 に答える 3

5

UNICODE を定義してコンパイルした場合、コードは期待どおりに動作しませんが、リモート プロセスはそうではありません (またはその逆)。リモート側が Unicode メッセージを予期しているかどうかを確認するには、まずハンドルでIsWindowUnicodeを呼び出す必要があります。treeView

この場合、SendMessage が行う標準の双方向マーシャリングでは不十分なため、これが必要です。リモート側が Unicode ウィンドウであるかどうかに応じて、2 つのまったく異なるウィンドウ メッセージを送信する必要があります。Unicode の場合は、TVM_GETITEMW で SendMessageW を使用します。ANSI の場合は、TVM_GETITEMA で SendMessageA を使用します。

これはすべての一般的なコントロールに適用されますが、コントロールの基本セット (1024 未満のウィンドウ メッセージを使用する) には適用されません。

また、コードが 64 ビット バイナリにコンパイルされた場合、コードが壊れると思いますが、リモート プロセスは 32 ビット (またはその逆) です。これは、コードがローカル (たとえば 64 ビット) の TVITEM をリモート プロセスにコピーし、リモート プロセスが TVM_GETITEM(A|W) メッセージの処理中に期待どおりに読み取ることを期待しているためです。ただし、構造体のサイズは異なる場合があります (ポインターのサイズが異なるため)。

于 2010-02-18T09:37:12.713 に答える
3

よし、もう一度やってみよう。

新しい TreeViews はTVITEMEX代わりに期待しTVITEM、通常のcbSizeフィールドがないため、コントロールはどのバージョンを受け取って想定するかを判断できませんTVITEMEXTVITEMEXメモリが割り当てられていないため、ツリービューが最後のメンバーにアクセスできないという問題がある可能性があります。実際に必要なよりもTVITEMEX少し多くのメモリを使用または割り当ててみてください。TVITEM

また、それを考慮してください

返されたテキストは、アプリケーションによって渡された元のバッファーに格納されるとは限りません。pszText は、テキストを古いバッファーに配置するのではなく、新しいバッファー内のテキストを指す可能性があります。

したがって、別のプロセス メモリから読み取る必要がある場合があります。

また、VirtualAllocEx がメモリをリセットするため、バッファはゼロになります。

そして、おそらく役に立たない最後の手段として、 のMEM_RESERVE|MEM_COMMIT代わりに を使用してみてくださいMEM_COMMIT

于 2010-02-18T01:09:37.067 に答える
1

Spy++ を使用して、ツリービューが NM_CUSTOMDRAW 通知フラグを持つ WM_NOTIFY メッセージを処理するかどうかを確認します。もしそうなら、運が悪い。実際のデータは何らかの形で内部に保存されており、それを引き出す機会はほとんどありません。

これは、以前のバージョンの Windows BTW にも同様に当てはまります。

于 2010-02-11T11:46:48.537 に答える