因測試一個程序,該程序的安卓端執行掃描條碼二維碼操作,然后服務器端需要在PC當前處於激活狀態的窗體的當前光標處顯示安卓程序掃描到的條形碼。這是博主“小李飛菜刀”的掃描寶服務程序。場景就是苦於手邊沒有掃描槍,又想測試條碼掃描。“小李飛菜刀”同學使用的是 "SendKeys"的“Send”方法。這是同一應用才能有效的辦法。如果需要在其他應用的光標處輸入字符,就只有使用"SendMessage"的windows api了。經過一番搜索,抄到段代碼,測試了一下沒有效果,TNND。請圍觀:
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui);
[StructLayout(LayoutKind.Sequential)]
public struct GUITHREADINFO
{
public int cbSize;
public int flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public RECT rectCaret;
}
public static GUITHREADINFO? GetGuiThreadInfo(IntPtr hwnd)
{
if (hwnd != IntPtr.Zero)
{
//Mbox.Info(GetTitle(hwnd), "O");
uint threadId = GetWindowThreadProcessId(hwnd, IntPtr.Zero);
GUITHREADINFO guiThreadInfo = new GUITHREADINFO();
guiThreadInfo.cbSize = Marshal.SizeOf(guiThreadInfo);
if (GetGUIThreadInfo(threadId, ref guiThreadInfo) == false)
return null;
return guiThreadInfo;
}
return null;
}
public static void SendText(string text)
{
IntPtr hwnd = GetForegroundWindow();
if (String.IsNullOrEmpty(text))
return;
Hwindow.GUITHREADINFO? guiInfo = Hwindow.GetGuiThreadInfo(hwnd);
if (guiInfo != null)
{
IntPtr ptr = (IntPtr)guiInfo.Value.hwndCaret;
if (ptr != IntPtr.Zero)
{
for (int i = 0; i < text.Length; i++)
{
SendMessage(ptr, Message.WM_CHAR, (IntPtr)(int)text[i], IntPtr.Zero);
}
}
}
}
這是csdn抄的,原文:C#怎么獲得當前屏幕光標的位置,然后在光標的位置上輸入想輸入數據。
發現RECT沒辦法被感知,又一番搜索發現是個結構體:
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
int left;
int top;
int right;
int bottom;
}
加上之后可以編譯成功。但是沒效果,仔細調試下來對方法“SendText”進行了修改。代碼的主要思路:用GetForegroundWindow找到焦點窗體,
然后GetWindowThreadProcessId和GetGUIThreadInfo找到含有光標的控件句柄,即GUITHREADINFO中的hwndCaret,然后用該句柄發送消息。
下面貼上修改后有效果的代碼:
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui);
[StructLayout(LayoutKind.Sequential)]
public struct GUITHREADINFO
{
public int cbSize;
public int flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public RECT rectCaret;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
int left;
int top;
int right;
int bottom;
}
public GUITHREADINFO? GetGuiThreadInfo(IntPtr hwnd)
{
if (hwnd != IntPtr.Zero)
{
uint threadId = GetWindowThreadProcessId(hwnd, IntPtr.Zero);
GUITHREADINFO guiThreadInfo = new GUITHREADINFO();
guiThreadInfo.cbSize = Marshal.SizeOf(guiThreadInfo);
if (GetGUIThreadInfo(threadId, ref guiThreadInfo) == false)
return null;
return guiThreadInfo;
}
return null;
}
protected void SendText(string text)
{
IntPtr hwnd = GetForegroundWindow();
if (String.IsNullOrEmpty(text))
return;
GUITHREADINFO? guiInfo = GetGuiThreadInfo(hwnd);
if (guiInfo != null)
{
for (int i = 0; i < text.Length; i++)
{
SendMessage(guiInfo.Value.hwndFocus, 0x0102, (IntPtr)(int)text[i], IntPtr.Zero);
}
}
}
主要發現 “IntPtr ptr = (IntPtr)guiInfo.Value.hwndCaret;”,這里始終是0.改成: SendMessage(guiInfo.Value.hwndFocus, 0x0102, (IntPtr)(int)text[i], IntPtr.Zero);
hwndFocus字面意思就是當前光標處的句柄。搞定,收工!
