簡體   English   中英

在c#中將鍵擊發送到應用程序(sendkeys,postmessage,sendmessage都不起作用)

[英]Send keystroke to application in c# (sendkeys, postmessage, sendmessage all not working)

我正在嘗試執行以下操作之一1.打開所需程序並以編程方式按鍵2​​.找到程序打開窗口並以編程方式按鍵(或者很好)

我嘗試了很多SendKeys.SendWait(),PostMessage()和SendMessage()的實現失敗。 以下是我的代碼片段

    //included all these for attempts 
    [DllImport("User32.dll")] 
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);  

    [DllImport("User32.dll")] 
    static extern int SetForegroundWindow(IntPtr hWnd);

    [DllImport("User32.Dll", EntryPoint = "PostMessageA")]
    static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

    [DllImport("user32.dll")]
    static extern byte VkKeyScan(char ch);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

獲取sendmessage / postmessage / sendkeys使用的窗口,變量的句柄

IntPtr ptrOBS = proc.Handle;//this works properly, proc is instantiated properly
//IntPtr ptrOBS = FindWindow(null, "Open Broadcaster Software v0.472b");
SetForegroundWindow(ptrOBS);
const UInt32 WM_CHAR = 0x0102;
const uint WM_KEYDOWN = 0x100;
const int VK_R = 0x52; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx
const int VK_S = 0x53;

SendMessage嘗試:

SendMessage(ptrOBS, WM_KEYDOWN, (IntPtr)VK_R, (IntPtr)1);//tried both WM_CHAR and WM_KEYDOWN

PostMessage嘗試:

string message = "rs";
bool sent = PostMessage(ptrOBS, WM_KEYDOWN, VkKeyScan(message[0]), 0);

SendKeys嘗試:

SendKeys.SendWait("{r}");

在父窗口(應用程序)和子窗口上嘗試SetFocus(由按鍵觸發的按鈕即可嘗試發送):

static void SetFocus(IntPtr hwndTarget, string childClassName)
    {
        // hwndTarget is the other app's main window 
        // ...
        IntPtr targetThreadID = GetWindowThreadProcessId(hwndTarget, IntPtr.Zero); //target thread id
        IntPtr myThreadID = GetCurrentThread(); // calling thread id, our thread id
        try
        {
            bool lRet = AttachThreadInput(myThreadID, targetThreadID, -1); // attach current thread id to target window

            // if it's not already in the foreground...
            lRet = BringWindowToTop(hwndTarget);
            SetForegroundWindow(hwndTarget);

            // if you know the child win class name do something like this (enumerate windows using Win API again)...
            IntPtr hwndChild = (IntPtr)1183492;//(IntPtr)EnumAllWindows(hwndTarget, childClassName).FirstOrDefault();

            if (hwndChild == IntPtr.Zero)
            {
                // or use keyboard etc. to focus, i.e. send keys/input...
                // SendInput (...);
                return;
            }

            // you can use also the edit control's hwnd or some child window (of target) here
            SetFocus(hwndChild); // hwndTarget);
            SendKeys.SendWait("{r}");
        }
        finally
        {
            SendKeys.SendWait("{r}");
            bool lRet = AttachThreadInput(myThreadID, targetThreadID, 0); //detach from foreground window
            SendKeys.SendWait("{r}");
        }
    }

對於NSGaga:

    string windowName = "Open Broadcaster Software v0.472b";
IntPtr outerPtr = FindWindow(null, windowName);
IntPtr ptrOBS = (IntPtr)527814;//button that im trying to trigger keypress on
SetForegroundWindow(outerPtr);
SetForegroundWindow(ptrOBS);
SetFocus(outerPtr, "OBSWindowClass");//SetFocus(ptrOBS, "Button");
const UInt32 WM_CHAR = 0x0102;
const int VK_R = 0x52; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx
const int VK_S = 0x53;

//SetForegroundWindow(ptrOBS);
System.Threading.Thread.Sleep(3000);
SendKeys.SendWait("{r}");
SendMessage(outerPtr, WM_KEYDOWN, (IntPtr)VK_R, (IntPtr)1);
PostMessage(outerPtr, WM_KEYDOWN, VkKeyScan('r'), 0);

您無法可靠地使用SendMessagePostMessage來合成鍵盤輸入 它們不是為此而設計的。 這些消息( WM_CHARWM_KEYDOWN等)是在接收,處理並轉發到適當的收件人的鍵盤輸入時由較低級子系統引發的通知 自己發送或發布這些消息就像惡作劇一樣。

SendKeys (與所有其他輸入合成器方法一樣,包括明確設計用於合成鍵盤輸入的SendInput函數,至少在某些實現中是SendKeys實際使用的內容)僅當您希望接收鍵盤輸入的窗口具有焦點。 在Windows中,只有聚焦(活動)窗口接收輸入事件。

所以SendKeys可能是你要去的工作方式(無論是P / Invoking SendInput及其所有相關結構),但你需要尊重收件人窗口必須具有的警告。焦點。 否則,它不會得到任何東西。

從您的示例代碼看,您嘗試使用SetForegroundWindow函數來滿足此前提條件。 不幸的是,你傳遞的是一個無效的值,並沒有做任何可能提醒你注意這個錯誤的錯誤檢查。 具體來說,這段代碼是錯誤的:

IntPtr ptrOBS = proc.Handle;//this works properly, proc is instantiated properly
SetForegroundWindow(ptrOBS); // WRONG, ptrOBS is not a window handle

即使我信任你正確初始化ptrOBS ,這也使它成為進程的有效句柄,這與窗口的有效句柄完全不同。 除了明顯的名義差異外,進程可以有多個窗口,只有一個窗口可以有焦點(即“在前台”)。

在調用SetForegroundWindow之前,您需要獲取特定窗口的句柄,並且假設我們知道一個進程可以有多個窗口,這可能很棘手。 您需要一些可靠的方法來確定您想要的窗口。 很多人通過將窗口的名稱硬編碼為字符串來實現這一目標,這種方法很有效,直到目標應用程序被重新編譯並且此實現細節發生變化。 我能想到的唯一防彈方法是讓用戶單擊目標窗口和代碼來檢索當前位於鼠標指針下的窗口的句柄。

當然,所有這些都假定您已經觀察到使用SetForegroundWindow的限制,這些限制在鏈接的SDK文檔的“備注”部分中列舉。

為了讓它發揮作用,有很多試驗和錯誤
這里是我之前發布的一些代碼,你可能想嘗試一下(並附上一些更多的信息)......

Pinvoke SetFocus到特定的控件

首先嘗試設置焦點(使用提到的機制) - 然后使用SendKeysSendInput

這是SendInput一些詳細代碼......

如何將字符串發送到其他應用程序,包括Microsoft Word

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM