Как получить текст элемента дерева другого приложения
От: DmitryChernov  
Дата: 16.07.04 10:00
Оценка:
Приветствую.

Пытаюсь получить текст элемента дерева другого приложения (например, из "Windows Explorer") пишу вот так:
#include <atlbase.h>
#include <atlapp.h>
#include <atlctrls.h>
#include <iostream>

int main()
{
    CTreeViewCtrlEx tvc;

    tvc = (HWND)0x000806D8; //Значение получено при помощи Spy++

    CTreeItem tiCur = tvc.GetSelectedItem(); //Значение получаю, т.е. тут не NULL
    WCHAR szBuf[1024] = { 0 };
    if (!tiCur.GetText(szBuf, sizeof(szBuf) / sizeof(WCHAR)))
//    if (!tiCur.SortChildren(TRUE))
        std::wcout << L"Error" << std::endl;
    else
        std::wcout << szBuf << std::endl;

    return 0;
}

Так вот всегда вываливается на ошибку и буфер не заполняет. С начало закралась мысль, что сообщения пришедшие из другого приложения не попадают к окну (понимаю, что мысль шальная, но черт его знает), заменил строку получения текста на сортировку. В результате все сработало и дочерние элементы отсортировались, это доказывает, что сообщения к окну приходят (хотя может быть ни все, но все же ходят). Может кто объяснит, что я не так делаю?
Re: Как получить текст элемента дерева другого приложения
От: Patalog Россия  
Дата: 16.07.04 10:44
Оценка:
Здравствуйте, DmitryChernov, Вы писали:

[]

См. в сторону ReadProcessMemory.
Кстати, у Рихтера есть схожий пример.
Почетный кавалер ордена Совка.
Re: Как получить текст элемента дерева другого приложения
От: algol Россия about:blank
Дата: 16.07.04 11:34
Оценка:
Здравствуйте, DmitryChernov, Вы писали:

DC>Пытаюсь получить текст элемента дерева другого приложения (например, из "Windows Explorer") пишу вот так:

DC>Так вот всегда вываливается на ошибку и буфер не заполняет. С начало закралась мысль, что сообщения пришедшие из другого приложения не попадают к окну (понимаю, что мысль шальная, но черт его знает), заменил строку получения текста на сортировку. В результате все сработало и дочерние элементы отсортировались, это доказывает, что сообщения к окну приходят (хотя может быть ни все, но все же ходят). Может кто объяснит, что я не так делаю?

Есть вот такой код для копирования дерева из другого процесса. Требует доработки напильником в MemAllocate/MemRelease (см. закомментированную строку), но в принципе работает:
// TreeViewFPDE.h: interface for the CTreeViewFPDE class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_TREEVIEWFPDE_H__9A632F5A_BA1D_4597_AFED_774A7EE00EC8__INCLUDED_)
#define AFX_TREEVIEWFPDE_H__9A632F5A_BA1D_4597_AFED_774A7EE00EC8__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

// information about target ListView
struct dmTreeView
{
    HWND hWnd;
    CString Class;
    long ItemCount;
    RECT rect;
};

class CTreeViewFPDE  
{
public:
    CTreeViewFPDE();
    virtual ~CTreeViewFPDE();

    BOOL GetTreeviewInfo(dmTreeView& tvInfo);
    CString WindowClass(HWND hWindow);
    void TreeViewScan(dmTreeView& tvInfo, CTreeViewCtrl& tree);

protected:
    LPVOID MemAllocate(DWORD nBytes, DWORD fpID);
    BOOL MemRelease(LPVOID mPointer);
    void SubTreeScan(DWORD hItem, HTREEITEM hTreeItem, CTreeViewCtrl& tree);
    CString TreeviewItem(DWORD hItem);
    BOOL TreeviewItemExpanded(DWORD hItem);
    void ReadProcessData(LPVOID pBuffer, LPVOID pData, DWORD nBytes);
    void WriteProcessData(LPVOID pBuffer, LPVOID pData, DWORD nBytes);

    BOOL m_bWindowsNT;
    HWND tvWindow;
    HANDLE fpHandle;
    TVITEM TVitem;
    LPVOID tvItemPointer, tvDataPointer;
};

#endif // !defined(AFX_TREEVIEWFPDE_H__9A632F5A_BA1D_4597_AFED_774A7EE00EC8__INCLUDED_)


// TreeViewFPDE.cpp: implementation of the CTreeViewFPDE class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TreeViewFPDE.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTreeViewFPDE::CTreeViewFPDE()
{
    OSVERSIONINFO verinfo;
    verinfo.dwOSVersionInfoSize = sizeof(verinfo);
    if (GetVersionEx(&verinfo))
    {
        m_bWindowsNT = (verinfo.dwPlatformId == 2);
    }
    tvWindow = NULL;
}

CTreeViewFPDE::~CTreeViewFPDE()
{

}

CString CTreeViewFPDE::WindowClass(HWND hWindow)
{
    long cLen;
    char className[64] = {0};
    cLen = GetClassName(hWindow, className, 63);
    if (cLen)
        className[cLen] = 0;
    return className;
}

// Fills in info about target window (passed via tvInfo.hWnd)
// Returns TRUE if hWindow is a handle to a TreeView control
BOOL CTreeViewFPDE::GetTreeviewInfo(dmTreeView& tvInfo)
{
    tvWindow = tvInfo.hWnd;
    if (IsWindow(tvWindow) == 0)
    {
        tvWindow = NULL;
        return FALSE;
    }

    tvInfo.Class = WindowClass(tvWindow);

    if (tvInfo.Class.CompareNoCase("SysTreeView32"))
    {
        tvWindow = NULL;
        tvInfo.ItemCount = 0;
        return FALSE;
    }

    tvInfo.ItemCount = SendMessage(tvWindow, TVM_GETCOUNT, NULL, NULL);
    GetWindowRect(tvWindow, &tvInfo.rect);
    return TRUE;
}

void CTreeViewFPDE::TreeViewScan(dmTreeView& tvInfo, CTreeViewCtrl& tree)
{
    DWORD tvProcessId;
    GetWindowThreadProcessId(tvWindow, &tvProcessId);

    tvItemPointer = MemAllocate(sizeof(TVitem), tvProcessId);
    tvDataPointer = MemAllocate(255, tvProcessId);

    tvInfo.ItemCount = SendMessage(tvWindow, TVM_GETCOUNT, 0, 0);
    long tvCount = tvInfo.ItemCount;
    if (tvCount == 0) return;
    long tvIndex = 1;

    long hItem = SendMessage(tvWindow, TVM_GETNEXTITEM, TVGN_ROOT, 0);
    while (hItem)
    {
        HTREEITEM hRootItem = tree.InsertItem(TreeviewItem(hItem), TVI_ROOT, TVI_LAST);
        if (TreeviewItemExpanded(hItem))
            tree.SetItemState(hRootItem, TVIS_EXPANDED, TVIS_EXPANDED);

        SubTreeScan(hItem, hRootItem, tree);
        hItem = SendMessage(tvWindow, TVM_GETNEXTITEM, TVGN_NEXT, hItem);
    }

    MemRelease(tvItemPointer);
    MemRelease(tvDataPointer);
}

void CTreeViewFPDE::SubTreeScan(DWORD hItem, HTREEITEM hParentItem, CTreeViewCtrl& tree)
{
    if (tvWindow == NULL)
        return;

    hItem = SendMessage(tvWindow, TVM_GETNEXTITEM, TVGN_CHILD, hItem);
    if (hItem == 0)
        return;

    while (hItem)
    {
        HTREEITEM hTreeItem = tree.InsertItem(TreeviewItem(hItem), hParentItem, TVI_LAST);
        if (TreeviewItemExpanded(hItem))
            tree.SetItemState(hTreeItem, TVIS_EXPANDED, TVIS_EXPANDED);

        SubTreeScan(hItem, hTreeItem, tree);
        hItem = SendMessage(tvWindow, TVM_GETNEXTITEM, TVGN_NEXT, hItem);
    }
}

CString CTreeViewFPDE::TreeviewItem(DWORD hItem)
{
    if (tvWindow == NULL)
        return "";

    // 1. Fill in TVITEM in the normal fashion, with just one difference
    TVitem.mask = TVIF_TEXT;
    TVitem.hItem = (HTREEITEM)hItem;
    TVitem.pszText = (char*)tvDataPointer;        // ItemData address is our shared buffer!
    TVitem.cchTextMax = 255;

    // 2. Copy the TVITEM to the shared buffer, and send the GETITEM request
    WriteProcessData(tvItemPointer, &TVitem, sizeof(TVitem));
    LRESULT apiResult = SendMessage(tvWindow, TVM_GETITEMA, 0, (LPARAM)tvItemPointer);

    // 3. Get the return data from the shared buffer (and convert to VB string)
    //    TVM_GETITEM doesn't return the item's text length
    if (apiResult)
    {
        char myBuffer[256];
        ReadProcessData(tvDataPointer, myBuffer, 255);
        return myBuffer;
    }
    return "";
}

BOOL CTreeViewFPDE::TreeviewItemExpanded(DWORD hItem)
{
    if (tvWindow == NULL)
        return NULL;
   
    // 1. Fill in TVITEM in the normal fashion, with just one difference
    TVitem.mask = TVIF_STATE;
    TVitem.hItem = (HTREEITEM)hItem;
    TVitem.stateMask = TVIS_EXPANDED;

    // 2. Copy the TVITEM to the shared buffer, and send the GETITEM request
    WriteProcessData(tvItemPointer, &TVitem, sizeof(TVitem));
    LRESULT apiResult = SendMessage(tvWindow, TVM_GETITEMA, 0, (LPARAM)tvItemPointer);
    ReadProcessData(tvItemPointer, &TVitem, sizeof(TVitem));

    // 3. Check my mask state bit
    return (TVitem.state & TVIS_EXPANDED);
}

LPVOID CTreeViewFPDE::MemAllocate(DWORD nBytes, DWORD fpID)
{
    // Returns pointer to a share-able buffer (size nBytes) in target process
    // fpID is the foreign process id - we only need it on NT platforms, actually
    if (m_bWindowsNT)
    {
        fpHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, fpID);
        return VirtualAllocEx(fpHandle, 0, nBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    }
    else
    {
        fpHandle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, nBytes, NULL);
        return MapViewOfFile(fpHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    }
}

BOOL CTreeViewFPDE::MemRelease(LPVOID mPointer)
{
    if (m_bWindowsNT)
    {
        VirtualFreeEx(fpHandle, mPointer, 0, MEM_RELEASE);
    }
    else
    {
        UnmapViewOfFile(mPointer);
    }
//    return CloseHandle(fpHandle);
    return TRUE;
}

void CTreeViewFPDE::ReadProcessData(LPVOID pBuffer, LPVOID pData, DWORD nBytes)
{
    if (m_bWindowsNT)
        ReadProcessMemory(fpHandle, pBuffer, pData, nBytes, 0);
    else
        CopyMemory(pData, pBuffer, nBytes);
}

void CTreeViewFPDE::WriteProcessData(LPVOID pBuffer, LPVOID pData, DWORD nBytes)
{
    if (m_bWindowsNT)
        WriteProcessMemory(fpHandle, pBuffer, pData, nBytes, 0);
    else
        CopyMemory(pBuffer, pData, nBytes);
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.