iT邦幫忙

0

C# winform,取得當前關注的輸入欄位的Handle

  • 分享至 

  • xImage

目的是用掃描槍掃描條碼之後,根據掃描的內容,修改輸出到目前正在關注的輸入欄位
以下是我嘗試的程式碼

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static ASUSBarcodeChange.BardcodeHook;

namespace ASUSBarcodeChange
{
    public class BardcodeHook
    {
        public delegate void BardcodeDeleteGate(BarCodes barCode);
        public event BardcodeDeleteGate BarCodeEvent;

        private static HookProc hookproc;

        public struct BarCodes
        {
            public int VirtKey;
            public int ScanCode;
            public string KeyName;
            public uint Ascll;
            public char Chr;
            public string BarCode;//條碼資訊
            public bool IsValid;//條碼是否有效
            public DateTime Time;//掃描時間
        }

        private struct EventMsg
        {
            public int message;
            public int paramL;
            public int paramH;
            public int Time;
            public int hwnd;
        }



        delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
        BarCodes barCode = new BarCodes();
        int hKeyboardHook = 0;
        string strBarCode = "";

        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            if (nCode == 0)
            {
                EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));
                if (wParam == 0x100)//WM_KEYDOWN=0x100
                {
                    barCode.VirtKey = msg.message & 0xff;//虛擬嗎
                    barCode.ScanCode = msg.paramL & 0xff;//掃描碼
                    StringBuilder strKeyName = new StringBuilder(225);
                    if (GetKeyNameText(barCode.ScanCode * 65536, strKeyName, 255) > 0)
                    {
                        barCode.KeyName = strKeyName.ToString().Trim(new char[] { ' ', '\0' });
                    }
                    else
                    {
                        barCode.KeyName = "";
                    }
                    byte[] kbArray = new byte[256];
                    uint uKey = 0;
                    GetKeyboardState(kbArray);


                    if (ToAscii(barCode.VirtKey, barCode.ScanCode, kbArray, ref uKey, 0))
                    {
                        barCode.Ascll = uKey;
                        barCode.Chr = Convert.ToChar(uKey);
                    }

                    TimeSpan ts = DateTime.Now.Subtract(barCode.Time);

                    if (ts.TotalMilliseconds > 50)
                    {
                        strBarCode = barCode.Chr.ToString();
                    }
                    else
                    {
                        if ((msg.message & 0xff) == 13 && strBarCode.Length > 3)
                        {

                            barCode.BarCode = strBarCode;
                            barCode.IsValid = true;
                            //IntPtr focuswindow = FindWindow("notepad",null);
                            //Process processes = Process.GetProcessesByName("notepad").FirstOrDefault();
                            //IntPtr focuswindow = GetForegroundWindow();
                            //IntPtr focuswindow = FindWindowEx(processes.MainWindowHandle, IntPtr.Zero, "edit", null);


                            IntPtr foregroundWindow = GetForegroundWindow();
                            int foregroundWindowProcessId;
                            GetWindowThreadProcessId(foregroundWindow, out foregroundWindowProcessId);
                            Process foregroundProcess = Process.GetProcessById(foregroundWindowProcessId);
                            //記事本用
                            IntPtr focuswindow = FindWindowEx(foregroundProcess.MainWindowHandle, IntPtr.Zero, "edit", null);
                            //Notepad++用
                            //IntPtr focuswindow = FindWindowEx(foregroundProcess.MainWindowHandle, IntPtr.Zero, "Scintilla", null);

                            //SetForegroundWindow(foregroundWindow);
                            //IntPtr focuswindow = GetFocus();
                            

                            if (focuswindow == IntPtr.Zero)
                            {
                                MessageBox.Show("Failed to retrieve program process correctly, please try again.");
                                return 1;
                            }
                            else
                            {
                                //SendMessage(focuswindow, 0x0102, 'A', 0);

                                Clipboard.SetText(barCode.BarCode + "\r");
                                SendMessageW(focuswindow, 0x0302, 0, 0);
                                //PostMessage(new HandleRef(processes, focuswindow), 0x0302, IntPtr.Zero, IntPtr.Zero);
                                
                                //SendKeys.SendWait(new string(new char[] { 'A', (char)Keys.Enter }));
                            }
                            //return 1;
                        }
                        strBarCode += barCode.Chr.ToString();
                    }
                    barCode.Time = DateTime.Now;
                    if (BarCodeEvent != null) BarCodeEvent(barCode);//觸發事件
                    barCode.IsValid = false;
                }
            }
            //return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
            return 1;
        }

        //安裝鉤子
        public bool Start()
        {
            if (hKeyboardHook == 0)
            {
                hookproc = new HookProc(KeyboardHookProc);

                IntPtr moduleptr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);

                hKeyboardHook = SetWindowsHookEx(13, hookproc, moduleptr, 0);


                //WH_KEYBOARD_LL=13
                //hKeyboardHook = SetWindowsHookEx(13, new HookProc(KeyboardHookProc), Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
            }
            return (hKeyboardHook != 0);
        }

        //卸載鉤子
        public bool Stop()
        {
            if (hKeyboardHook != 0)
            {
                return UnhookWindowsHookEx(hKeyboardHook);
            }
            return true;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern bool UnhookWindowsHookEx(int idHook);

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

        [DllImport("user32", EntryPoint = "GetKeyNameText")]
        private static extern int GetKeyNameText(int IParam, StringBuilder lpBuffer, int nSize);

        [DllImport("user32", EntryPoint = "GetKeyboardState")]
        private static extern int GetKeyboardState(byte[] pbKeyState);

        [DllImport("user32", EntryPoint = "ToAscii")]
        private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeySate, ref uint lpChar, int uFlags);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetModuleHandle(string name);

        // Get a handle to an application window.
        [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        // Activate an application window.
        [DllImport("USER32.DLL")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

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

        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        private const int WM_SETTEXT = 0x0102;

        [DllImport("User32.dll")]
        public static extern int SendMessageW(IntPtr hWnd, int uMsg, int wParam, int lParam);

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

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

        [DllImport("user32.dll")]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
        private static extern IntPtr GetFocus();

        [DllImport("user32.dll")]
        private static extern IntPtr GetAncestor(IntPtr hWnd, uint flags);

        private const uint GA_ROOT = 2;
    }
}

目前有成功做到的是可以抓到記事本、notepad++的輸入欄位,且修改字串後輸入,但是不知道該怎樣取得任意輸入欄位的Handle,去做訊息的輸出

感謝各位協助幫忙,如果還有缺什麼資料需要提供的,麻煩說一下,謝謝

--2023/03/10,更新

IntPtr foregroundWindow = GetForegroundWindow();
int foregroundWindowProcessId;
GetWindowThreadProcessId(foregroundWindow, out foregroundWindowProcessId);
Process foregroundProcess = Process.GetProcessById(foregroundWindowProcessId);
List<IntPtr> result = new List<IntPtr>();
int ct = 0;
IntPtr prevChild = IntPtr.Zero;
IntPtr currChild = IntPtr.Zero;

while (true && ct < 100)
{
	currChild = FindWindowEx(foregroundProcess.MainWindowHandle, prevChild, null, null);
	if (currChild == IntPtr.Zero) break;
	result.Add(currChild);
	prevChild = currChild;
	++ct;
}

Point caretPos = Cursor.Position;
IntPtr target = IntPtr.Zero;
target = WindowFromPoint(caretPos);
foreach (IntPtr hWnd in result)
{
	if (hWnd == target)
	{
		Clipboard.SetText(BarcodeSplit(strBarCode) + "\r");
		SendMessage(hWnd, WM_PASTE, 0, "");
	}
}

目前已經達到可以根據滑鼠的位置,去找到輸入欄位,並且輸入修改後的字串
但是沒辦法輸入在任何地方,如:網頁、word、powerpoint...等
作業系統是WIN10

請問有辦法做到在任何地方輸入嗎?

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

不明
【**此則訊息已被站方移除**】
1
japhenchen
iT邦超人 1 級 ‧ 2023-03-09 07:53:16
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsAPIExample
{
    public partial class Form1 : Form
    {
        // 定義Windows API函數
        [DllImport("user32.dll")]
        static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);

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

        // 定義WM_SETTEXT訊息常數
        const int WM_SETTEXT = 0x000C;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // 取得目標程式的視窗控制代碼(handle)
            IntPtr targetWindow = Process.GetProcessesByName("notepad")[0].MainWindowHandle;

            // 取得目標程式的textbox輸入框的控制代碼(handle)
            IntPtr targetTextBox = GetDlgItem(targetWindow, 15);

            // 傳送WM_SETTEXT訊息和文字到textbox輸入框
            SendMessage(targetTextBox, WM_SETTEXT, 0, "abcdefg");
        }
    }
}

用SPY++工具來幫你找到TEXTBOX輸入項所示意的HANDLE
C:\Program Files (x86)\Microsoft Visual Studio x.y\Common7\Tools\spyxx.exe

jack8900 iT邦新手 2 級 ‧ 2023-03-09 08:52:53 檢舉

上面提供的方式,的確可以在記事本上面輸入訊息,但是沒辦法持續輸入跟換行,會被取代掉。

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
[DllImport("User32.dll")]
public static extern int SendMessageW(IntPtr hWnd, int uMsg, int wParam, int lParam);

//取得目前關注視窗
IntPtr foregroundWindow = GetForegroundWindow();
//取得目標程式的textbox輸入框的控制代碼(handle)
IntPtr focuswindow = GetDlgItem(foregroundWindow, 15);
//覆蓋剪貼簿資料
Clipboard.SetText(barCode.BarCode + "\r");
//執行貼上
SendMessageW(focuswindow, 0x0302, 0, 0);

上面修改後的方法確定可以用,但是只能在記事本上面輸入,沒辦法在其他程式使用,例:notepad++,請問有辦法解決嗎?

我要發表回答

立即登入回答