目的是用掃描槍掃描條碼之後,根據掃描的內容,修改輸出到目前正在關注的輸入欄位
以下是我嘗試的程式碼
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
請問有辦法做到在任何地方輸入嗎?
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
上面提供的方式,的確可以在記事本上面輸入訊息,但是沒辦法持續輸入跟換行,會被取代掉。
[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++,請問有辦法解決嗎?