Я не могу понять, как использовать вызовы SendMessage или PostMessage - PullRequest
7 голосов
/ 30 апреля 2009

Мне нужно смоделировать нажатие клавиш в стороннем приложении. Допустим, у меня есть приложение на C #, которое должно отправить «8» в приложение калькулятора. Я не могу использовать SendKeys из .Net или keybd_event из win32 api, потому что им обоим нужно, чтобы окно было верхним активным, что не так в моей ситуации.

Так что это оставляет меня с вызовами sendMessage и postMessage. Последние три часа я пытался добиться каких-то результатов, но сейчас я совершенно безнадежен.

У меня есть следующее:

        [DllImport("user32.dll")]
    public static extern int FindWindow(string lpClassName,string lpWindowName);
    [DllImport("user32.dll")]
    public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);

    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("user32.dll", SetLastError = true)]
    public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);

    private void button1_Click(object sender, EventArgs e)
    {
        const int WM_KEYDOWN = 0x100;
        const int WM_SYSCOMMAND = 0x018;
        const int SC_CLOSE = 0x053;

        int WindowToFind = FindWindow(null,"Calculator");

        int result = SendMessage(WindowToFind, WM_SYSCOMMAND, SC_CLOSE, 0);
        Boolean result2 = PostMessage(WindowToFind, WM_SYSCOMMAND, SC_CLOSE, 0);

        int result3 = SendMessage(WindowToFind, WM_KEYDOWN,((int)Keys.NumPad7), 0);
        Boolean result4 = PostMessage(WindowToFind, WM_KEYDOWN, ((int)Keys.NumPad7), 0);
    }

Как видите, я делаю четыре попытки связаться с Калькулятором. Использование sendMessage и PostMessage для закрытия окна, а также для отправки ключа 7. Ничего не работает. Метод FindWindow работает, потому что я получаю обработчик приложения (я даже пытался запустить процесс сам и получить к нему доступ с помощью process.MainWindowHandler, но не повезло). Там нет ошибок или исключений, но это просто ничего не делает в калькуляторе.

Я тоже пробовал делать то же самое с помощью блокнота, но ничего не изменилось.

Ответы [ 5 ]

12 голосов
/ 30 апреля 2009

Есть ли шанс, что вы используете это на 64-битной машине? Если так, то я считаю, что все эти значения типа int, которые на самом деле являются hWnds (первый аргумент для Send / Post, возвращаемое значение из FindWindow) должны быть IntPtr.


После более тщательной проверки, похоже, что для SendMessage и PostMessage 1-й, 3-й и 4-й параметры должны быть IntPtr вместо int (а также возвращаемые значения для всех них)

Итак, правильные подписи будут:

[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
3 голосов
/ 30 апреля 2009

На CodeProject есть хорошая статья об этом: http://www.codeproject.com/KB/cs/SendKeys.aspx

SendKeys на самом деле правильная идея, но вам нужно получить HWND (дескриптор окна) целевого окна. В этом примере MSDN показано, как эффективно использовать SendKeys, а не как обнаружить HWND чего-либо, кроме самого верхнего окна.

Объедините два метода, используя пример CodeProject, чтобы найти HWND приложения, которое вы хотите настроить, а затем используйте статью MSDN, чтобы с помощью SendKeys отправлять нажатия клавиш (или события мыши) целевому приложению.

2 голосов
/ 30 апреля 2009

Не ваш вопрос, но разница между SendMessage и PostMessage заключается в том, что Send является блокирующим вызовом, Post немедленно возвращается (до того, как получающее приложение обработало его).

MSDN объясняет разницу: http://msdn.microsoft.com/en-us/library/ms644950(VS.85).aspx

Также, если вы используете Vista, но не используете .NET 3.0, это также может быть проблемой:

Класс SendKeys был обновлен для .NET Framework 3.0, чтобы обеспечить его использование в приложениях, работающих в Windows Vista. Повышенная безопасность Windows Vista (известная как контроль учетных записей или UAC) не позволяет предыдущей реализации работать должным образом.

1 голос
/ 14 июня 2018

Мне помогло решение , но Мне пришлось его отредактировать, и теперь оно короче:

Также здесь полезный список кодов виртуальных ключей

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll")]
        static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);

        private void button1_Click(object sender, EventArgs e)
        {
            const int WM_SYSKEYDOWN = 0x0104;

            IntPtr WindowToFind = FindWindow(null, "Calculator");

            PostMessage(WindowToFind, WM_SYSKEYDOWN, ((int)Keys.NumPad7), 0);
        }
1 голос
/ 04 октября 2010

Потому что это окно редактирования дочернего элемента внутри окна блокнота. Вы должны отправлять сообщения в правильное дочернее окно. Это рабочий пример в C:

#include <windows.h>
#include <stdio.h>

void main(void) {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    HWND mainwnd,editwnd;
    char c;
    si.cb=sizeof(si);
    si.lpReserved=NULL;
    si.lpDesktop=NULL;
    si.lpTitle=NULL;
    si.dwFlags=0;
    si.cbReserved2=0;
    si.lpReserved2=NULL;
    if(!CreateProcess("c:\\windows\\notepad.exe",NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) {
        printf("Failed to run app");
        return;
    }
    WaitForInputIdle(pi.hProcess,INFINITE);
    mainwnd=FindWindow(NULL,"Untitled - Notepad");
    if(!mainwnd) {
        printf("Main window not found");
        return;
    }
    editwnd=FindWindowEx(mainwnd,NULL,"Edit","");
    if(!editwnd) {
        printf("Edit window not found");
        return;
    }
    for(c='1';c<='9';c++) {
        PostMessage(editwnd,WM_CHAR,c,1);
        Sleep(100);
    }
}
...