FindWindowEx из user32.dll возвращает дескриптор нуля и код ошибки 127, используя dllimport - PullRequest
10 голосов
/ 09 марта 2011

Мне нужно обработать другое приложение Windows программно, выполнив поиск в Google. Я нашел образец, который обрабатывает калькулятор Windows с помощью атрибута DLLImport и импортировал функции user32.dll в управляемые функции в C #.

Приложение запущено, я получаю дескриптор главного окна, т. Е. Самого калькулятора, но последующий код не работает. Метод FindWindowEx не возвращает дескрипторы дочерних элементов Калькулятора, такие как кнопки и текстовое поле.

Я попытался использовать SetLastError = True для DLLImport и обнаружил, что получаю код ошибки 127, который называется «Процедура не найдена».

Это ссылка, откуда я взял пример приложения:

http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=14519&av=34503

Пожалуйста, помогите, если кто-нибудь знает, как решить.

ОБНОВЛЕНИЕ: DLLImport:

[DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className,  string  windowTitle);

Код, который не работает:

hwnd=FindWindow(null,"Calculator"); // This is working, I am getting handle of Calculator

// The following is not working, I am getting hwndChild=0 and err = 127
hwndChild = FindWindowEx((IntPtr)hwnd,IntPtr.Zero,"Button","1");

                Int32 err = Marshal.GetLastWin32Error();

Ответы [ 3 ]

12 голосов
/ 09 марта 2011

Код, который вы пытаетесь использовать, использует заголовки отдельных кнопок для их идентификации.Например, он использует следующий код для получения дескриптора кнопки «1»:

hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "Button", "1");

, который указывает «Button» для имени класса окна и «1» для имениокно (в случае кнопки, это то же самое, что текст заголовка, отображаемый на самой кнопке).

Этот код прекрасно работал в Windows XP (и предыдущих версиях), где кнопки калькулятора были идентифицированы кактекстовые подписи.Кнопка «1» имела название окна «1», и, таким образом, «1» отображалось как заголовок кнопки.

Однако, похоже, что все изменилось под Windows 7 (возможно, под Vista,хотя я не могу проверить это, потому что у меня нет доступа к такой системе).Использование Spy ++ для исследования окна калькулятора подтверждает, что кнопка «1» больше не имеет названия окна «1».На самом деле, у него вообще нет названия окна;заголовок NULL.Предположительно, новый причудливый вид калькулятора требовал, чтобы кнопки были нарисованы на заказ, поэтому подписи больше не нужны, чтобы указать, какая кнопка соответствует какой функции.Пользовательские процедуры рисования позаботятся о том, чтобы нарисовать необходимые заголовки.

Поскольку ни одна кнопка не может быть найдена с указанным вами текстом окна, для дескриптора окна возвращается значение 0 (NULL).

Документация для функции FindWindowEx указывает, что вы можете указать NULL для параметра lpszWindow, но это, конечно, будет соответствовать всем окнамуказанный класс.Вероятно, не то, что вы хотите в этом случае, так как приложение калькулятора имеет кучу кнопок.

Я не знаю хорошего обходного пути.Калькулятор не был разработан, чтобы быть «автоматизированным» таким образом, и Microsoft никогда не гарантировала, что они не изменят его внутреннюю работу.Это риск, которым вы рискуете, используя этот подход, чтобы связываться с окнами других приложений.


РЕДАКТИРОВАТЬ: Код, на который вы ссылаетесь, также неверен в другом довольно серьезном смыследаже на более ранних версиях Windows.Он объявляет переменную hwnd как тип int, а не как тип IntPtr.Поскольку дескриптор окна - это указатель , вы всегда должны хранить его как тип IntPtr.Это также исправляет уродливое приведение при вызове функции FindWindowEx, которое должно было отправлять красные флаги.

Вам также необходимо исправить объявление SendMessage, чтобы его первый параметр имел тип IntPtr.

Код должен быть написан так:

IntPtr hwnd = IntPtr.Zero;
IntPtr hwndChild = IntPtr.Zero;

//Get a handle for the Calculator Application main window
hwnd = FindWindow(null, "Calculator");
if(hwnd == IntPtr.Zero)
{
    if(MessageBox.Show("Couldn't find the calculator" + 
                       " application. Do you want to start it?", 
                       "TestWinAPI", 
                       MessageBoxButtons.YesNo) == DialogResult.Yes)
    {
        System.Diagnostics.Process.Start("Calc");
    }
}
else
{
    //Get a handle for the "1" button
    hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "1");

    //send BN_CLICKED message
    SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);

    //Get a handle for the "+" button
    hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "+");

    //send BN_CLICKED message
    SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);

    //Get a handle for the "2" button
    hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "2");

    //send BN_CLICKED message
    SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);

    //Get a handle for the "=" button
    hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "=");

    //send BN_CLICKED message
    SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);
}
2 голосов
/ 16 апреля 2012

Следующий код отлично работает в Caculator из Windows 7 в классической теме (не работает в основной или в Aero теме):

=============================================== ===

IntPtr hwndFrame = FindWindowEx(hwnd, IntPtr.Zero, "CalcFrame", null); 
IntPtr hwndDialog = FindWindowEx(hwndFrame, IntPtr.Zero, "#32770", null); 
IntPtr hwndDialog2 = FindWindowEx(hwndFrame, (IntPtr)hwndDialog, "#32770", null);


IntPtr hwndThree = FindWindowEx(hwndDialog2, IntPtr.Zero, "Button", "3"); 
SendMessage((int)hwndThree, BN_CLICKED, 0, IntPtr.Zero);

IntPtr hwndPlus = FindWindowEx(hwndDialog2, IntPtr.Zero, "Button", "+");
SendMessage((int)hwndPlus, BN_CLICKED, 0, IntPtr.Zero);

IntPtr hwndOne = FindWindowEx((IntPtr)hwndDialog2, IntPtr.Zero, "Button", "1");
SendMessage((int)hwndOne, BN_CLICKED, 0, IntPtr.Zero);

IntPtr hwndEqual = FindWindowEx(hwndDialog2, IntPtr.Zero, "Button", "=");
SendMessage((int)hwndEqual, BN_CLICKED, 0, IntPtr.Zero);
2 голосов
/ 09 марта 2011

Мне удалось воспроизвести это на Win7 Pro. Ваша проблема, скорее всего, в том, что ярлыки на кнопках нарисованы через тему калькулятора, а не как подпись. Когда служба «Темы» работает, запуск калькулятора приведет к тому, что на ней будут кнопки без заголовка.

Чтобы получить правильные заголовки кнопок, необходимо:

  1. Остановите службу Themes (запустите net stop themes из командной строки с повышенными привилегиями или используйте инструмент администрирования служб).
  2. Запустить калькулятор.

Если у вас запущен калькулятор при остановке службы Themes, вы заметите, что все его кнопки стали пустыми.

...