Как изменить значение элемента управления из другой программы (процесса) - PullRequest
0 голосов
/ 14 февраля 2012

Я хотел бы написать программу, которая позволяет мне изменять значения в текстовом поле другой программы или автоматически копировать значения из одной программы в другую.

Я нашел способ получить hWnd для большинства(не знаю, все ли они) элементов управления в программе targer, и указывать их курсором мыши.Я сделал для этого простую структуру, и ее массив

struct hWndpointer
   {
   HWND hWnd;
   AnsiString text;
   };

hWndpointer tbl[250];

EnumWindowProc и EnumChildWindowProc загружает дескрипторы и текст окна в массив и в элемент управления списком в моей программе, поэтому я могу нажатьэлемент в списке (или выберите его с помощью клавиатуры), и курсор указывает элемент управления (например, кнопку или текстовое поле), как ожидалось ... К сожалению, есть некоторые элементы управления без текста (или, скорее, GetWindowText не возвращает текста), поэтому нет никакого способадля идентификации элемента управления.

Вопрос заключается в следующем: есть ли способ получить / прочитать ИМЯ элемента управления?Есть ли какой-нибудь способ получить / прочитать и установить конкретное значение, такое как 'enabled' или 'text' или 'value'?

Заранее спасибо

PS: Извините за мой английский;)

Ответы [ 2 ]

0 голосов
/ 17 февраля 2012

С точки зрения Win32 API, элементы управления пользовательского интерфейса не имеют имен, поэтому вы не можете попросить API вернуть Name элемента управления пользовательского интерфейса в другом процессе, поскольку такого значения не существует. Имена - это особенность структуры пользовательского интерфейса, используемой приложением (VCL в случае C ++ Builder), и вы не можете напрямую обращаться к платформам через границы процессов. Вам потребуется сотрудничество с приложением-владельцем элемента управления.

Например, одним из способов было бы заставить оба приложения вызывать RegisterWindowMessage(), чтобы зарегистрировать пользовательское оконное сообщение, а затем ваше приложение может опубликовать это сообщение в другом приложении, указав желаемый элемент управления HWND и свой собственный HWND как параметры. Затем другое приложение может SendMessage() Name элемента управления вернуться к HWND вашего приложения, используя сообщение WM_COPYDATA, которое вы можете использовать для соответствующего обновления своего списка.

В платформе VCL вы можете преобразовать HWND в TWinControl* указатель, используя функцию FindControl(). Он вернет NULL, если HWND не принадлежит вызывающему процессу, в противном случае вы можете скопировать значение из его свойства Name. Например:

const UINT WM_GETCONTROLNAME = RegisterWindowMessage("WM_GetControlName");
const UINT WM_GETCONTROLNAME_RESULT = RegisterWindowMessage("WM_GetControlName_Result");

#include <pshpack1.h>
struct sControlName
{
    HWND hWnd;
    int Length;
    char Value[1];
};
#include <poppack.h>

void __fastcall TMyForm::WndProc(TMessage &Message)
{
    if ((Message.Msg == WM_COPYDATA) && (WM_GETCONTROLNAME_RESULT != 0))
    {
        LPCOPYDATASTRUCT cds = (LPCOPYDATASTRUCT) Message.LParam;
        if (cds->dwData == WM_GETCONTROLNAME_RESULT)
        {
            sControlName *pName = (sControlName*) cds->lpData;
            AnsiString sName(pName->Value, pName->Length);

            // locate pName->hWnd in your list and assign sName to it as needed...

            return;
        }
    }

    TForm::WndProc(Message);
}

void ___fastcall TMyForm::FillList()
{
    ...
    if (WM_GETCONTROLNAME != 0)
    {
        HWND TheControlHWND = ...;
        HWND OtherAppHWND = ...;
        PostMessage(OtherAppHWND, WM_GETCONTROLNAME, (WPARAM)TheControlHWND, (LPARAM)this->Handle);
    }
    ...
}

.

const UINT WM_GETCONTROLNAME = RegisterWindowMessage("WM_GetControlName");
const UINT WM_GETCONTROLNAME_RESULT = RegisterWindowMessage("WM_GetControlName_Result");

#include <pshpack1.h>
struct sControlName
{
    HWND hWnd;
    int Length;
    char Value[1];
};
#include <poppack.h>

void __fastcall TMyForm::WndProc(TMessage &Message)
{
    if ((Message.Msg == WM_GETCONTROLNAME) && (WM_GETCONTROLNAME != 0) && (WM_GETCONTROLNAME_RESULT != 0))
    {
        HWND hWnd = (HWND) Message.WParam;

        TWinControl *Ctrl = FindControl(hWnd);
        if (Ctrl)
        {
            AnsiString sName = Ctrl->Name;

            std::vector<unsigned char> buffer((sizeof(sControlName) - 1) + sName.Length());
            sControlName *pName = (sControlName*) &buffer[0];

            pName->hWnd = hWnd;
            pName->Length = sName.Length();
            strncpy(pName->Value, sName.c_str(), pName->Length);

            COPYDATASTRUCT cds = {0};
            cds.dwData = WM_GETCONTROLNAME_RESULT;
            cds.cdData = buffer.size();
            cds.lpData = pName;

            SendMessage((HWND)Message.LParam, WM_COPYDATA, (WPARAM)this->Handle, (LPARAM)&cds);
        }

        return;
    }

    TForm::WndProc(Message);
}
0 голосов
/ 14 февраля 2012

Вы можете использовать SendMessage и PostMessage для отправки WM_GETTEXT, WM_SETTEXT, WM_ENABLE в окна, принадлежащие другим процессам. (SendMessage для запросов, PostMessage для действий только для записи)

Часто дочерний идентификатор будет использоваться для идентификации подокон (особенно в диалоге), но для программы также возможно полагаться исключительно на динамические значения HWND, и в этом случае вам придется вернуться к окну позиции для дифференциации.

...