Warum fehlschlägt die TVM_GetItem -Nachricht auf COMCTL32.OCX oder mSCOMCTL.OCX -Baumansichten?

StackOverflow https://stackoverflow.com/questions/2244037

Frage

Ich habe eine Funktion geschrieben, die den Text eines Baumansichtselements ergeben kann, auch wenn sich die Baumansicht in einem Remote -Prozess befindet. Die Funktion zuordnet im Remote -Prozess zwei Speicherbrocken zu, füllt eine TVITEM -Struktur (die in den Remote -Prozess kopiert wird), sendet eine TVM_GetItem -Nachricht und liest schließlich den Inhalt des zweiten Remote -Speichers in einen lokalen Puffer zurück. Dies ist der Code:

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;
}

Dieser Code funktioniert sehr gut mit den einfachen Baumansichten, die Sie beim Übergeben des Verabschiedes erhalten WC_TREEVIEW Klassenname zu CreateWindow. Ich bemerkte jedoch, dass es nicht mit den neueren Bäumen funktioniert, die von MS Common Controls V5 (COMCTL32.OCX) oder MS Common Controls V6 (mSComctl.ocx) bereitgestellt wurden. In diesen Fällen ist der zurückgegebene Text immer leer (der Puffer ist alle Nullen). Mir ist auch aufgefallen, dass der SendMessage -Anruf Null zurückgibt (daher der von der bezeichnete Fehlerhandhabung // handle error Kommentare oben treten ein). Es ist mir unklar, ob dies wirklich einen Fehler anzeigt, auf jeden Fall ist der Puffer mit allen Nullen gefüllt.

Alle anderen Baumansichtsnachrichten (wie TVM_GetItemrect) scheinen perfekt zu funktionieren.

Weiß jemand, warum das so ist? Ich habe versucht, mit der Unicode -Flagge herumzuspielen (ich habe das bemerkt TVM_GETITEM ist entweder definiert zu TVM_GETITEMA oder TVM_GETITEMW) Aber das schien nicht zu helfen.

War es hilfreich?

Lösung

OK, lass uns einen weiteren Schuss geben.

Neuere Treeviews erwarten TVITEMEX Anstatt von TVITEM, und da es kein gewöhnliches gibt cbSize Feld, die Steuerung kann nicht sagen, welche Version es empfängt und annimmt TVITEMEX. Vielleicht gibt es ein Problem mit dem Treeview, der nicht in der Lage ist, zu den letzten Mitgliedern von zugreifen zu können TVITEMEX Weil kein Gedächtnis zugewiesen wird. Versuchen Sie es zu verwenden TVITEMEX oder ein bisschen mehr Speicher für TVITEM als tatsächlich erforderlich.

Betrachten Sie das auch

Der zurückgegebene Text wird nicht unbedingt im ursprünglichen Puffer gespeichert, der von der Anwendung übergeben wird. Es ist möglich, dass PSZText auf Text in einem neuen Puffer hinweist, anstatt ihn in den alten Puffer zu legen.

Möglicherweise müssen Sie daher aus einem anderen Prozess des Prozessspeichers lesen.

Und der Puffer ist Null, weil virtualallocex den Speicher zurücksetzt.

Und als letzter und wahrscheinlich nutzloses Resort, versuchen Sie es zu verwenden MEM_RESERVE|MEM_COMMIT statt gerecht MEM_COMMIT.

Andere Tipps

Der Code funktioniert nicht wie erwartet, wenn er mit definierter Unicode kompiliert wird, der Remote -Prozess ist jedoch nicht (oder umgekehrt). Sie sollten anrufen IsWindowunicode zuerst auf der treeView Handle, um zu prüfen, ob die Remote -Seite Unicode -Nachrichten erwartet.

Dies ist erforderlich, da das Standard-Zwei-Wege-Marsching, das SendMessage tut, in diesem Fall nicht ausreicht: Sie müssen zwei völlig unterschiedliche Fenstermeldungen senden, je nachdem, ob die Remote-Seite ein Unicode-Fenster ist oder nicht. Wenn es sich um Unicode handelt, verwenden Sie SendMessagew mit TVM_GetItemw. Wenn es sich um ANSI handelt, verwenden Sie SendMessagea mit TVM_Getitema.

Dies gilt für alle gängigen Steuerelemente, jedoch nicht für die grundlegenden Steuerelemente (die Fenstermeldungen <1024 verwendet).

Ich glaube auch, dass der Code brechen wird, wenn er in eine 64 -Bit -Binärdatei zusammengestellt wird, der Remote -Prozess jedoch 32 -Bit (oder umgekehrt umgekehrt). Dies liegt daran, dass der Code kopiert, dass es sich um lokale (z. B.: 64 -Bit -TVItem) in den Remoteprozess handelt und dann erwartet, dass der Remote -Prozess Toread wie erwartet im Umgang mit der TVM_GetItem (A | W) -Meldung ist. Die Größe der Struktur kann jedoch unterschiedlich sein (aufgrund unterschiedlicher Zeigergrößen).

Verwenden Sie SPY ++, um festzustellen, ob das TreeView mit wm_notify -Nachrichten mit dem NM_Customdraw -Benachrichtigungs -Flag behandelt wird. Wenn ja, dann Pech. Die tatsächlichen Daten werden irgendwie intern gespeichert und Sie haben wenig Chance, sie herauszuziehen.

Dies gilt gleichermaßen für frühere Versionen von Windows übrigens.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top