c# - 方法.Invoke(o, null); 只能从主体调用一次,而不能从键盘处理程序中调用
问题描述
我正在尝试创建一个低级键盘处理程序,以在检测到特定键盘组合时使用反射启动外部应用程序。
我可以直接启动应用程序一次而没有错误,但是从按键处理程序内部,应用程序在正确显示MessageBox
对话框后崩溃。
我正在将外部 dll 读入一个字节数组,对于这个测试,您可以使用任何 .Net 应用程序,一个简单的 Hello World win 表单应用程序就可以工作。
string filePath = @".\x.exe";
FileStream fs = new FileStream(filePath, FileMode.Open);
BinaryReader br = new BinaryReader(fs);
byte[] bin = br.ReadBytes(Convert.ToInt32(fs.Length));
fs.Close();
br.Close();
然后加载外部Assembly
并通过反射执行它:
public Assembly a;
public MethodInfo method;
public object o;
a = Assembly.Load(bin);
method = a.EntryPoint;
o = a.CreateInstance(method.Name);
method.Invoke(o, null);
这工作一次,但如果我重复上面的代码再次执行它会失败。
下面的代码演示了第二次调用的失败,如果你注释掉你可以看到键盘检测的失败Left++DownA
即使您在程序根目录中注释掉这两个调用,应用程序在第一次检测到键时也会意外关闭。
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.Windows.Input;
public class Program
{
public static bool lctrlKeyPressed;
public static bool f1KeyPressed;
public static bool AKeyPressed;
public static bool LeftKeyPressed;
public static bool DownKeyPressed;
public static Assembly a;
// search for the Entry Point
public static MethodInfo method;
// create an istance of the Startup form Main method
public static object o;
[STAThread]
public static void Main()
{
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
string filePath = @".\x.exe";
FileStream fs = new FileStream(filePath, FileMode.Open);
BinaryReader br = new BinaryReader(fs);
byte[] bin = br.ReadBytes(Convert.ToInt32(fs.Length));
fs.Close();
br.Close();
//public Assembly a;
//public MethodInfo method;
//public object o;
a = Assembly.Load(bin);
method = a.EntryPoint;
o = a.CreateInstance(method.Name);
method.Invoke(o, null);
a = Assembly.Load(bin);
method = a.EntryPoint;
o = a.CreateInstance(method.Name);
method.Invoke(o, null);
LowLevelKeyboardHook kbh = new LowLevelKeyboardHook();
kbh.OnKeyPressed += kbh_OnKeyPressed;
kbh.OnKeyUnpressed += kbh_OnKeyUnPressed;
kbh.HookKeyboard();
Application.Run();
kbh.UnHookKeyboard();
}
public static void kbh_OnKeyPressed(object sender, Keys e)
{
if (e == Keys.A)
{
AKeyPressed = true;
}
else if (e == Keys.Left)
{
LeftKeyPressed = true;
}
else if (e == Keys.Down)
{
DownKeyPressed = true;
}
CheckKeyCombo();
}
public static void kbh_OnKeyUnPressed(object sender, Keys e)
{
if (e == Keys.A)
{
AKeyPressed = false;
}
else if (e == Keys.Left)
{
LeftKeyPressed = false;
}
else if (e == Keys.Down)
{
DownKeyPressed = false;
}
}
public static void CheckKeyCombo()
{
if (AKeyPressed && LeftKeyPressed && DownKeyPressed)
{
MessageBox.Show("Left Key + Down Key + A Key + Pressed");
//a = Assembly.Load(bin);
method = a.EntryPoint;
o = a.CreateInstance(method.Name);
method.Invoke(o, null);
}
}
}
public class LowLevelKeyboardHook
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_SYSKEYDOWN = 0x0104;
private const int WM_KEYUP = 0x101;
private const int WM_SYSKEYUP = 0x105;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public event EventHandler<Keys> OnKeyPressed;
public event EventHandler<Keys> OnKeyUnpressed;
private LowLevelKeyboardProc _proc;
private IntPtr _hookID = IntPtr.Zero;
public LowLevelKeyboardHook()
{
_proc = HookCallback;
}
public void HookKeyboard()
{
_hookID = SetHook(_proc);
}
public void UnHookKeyboard()
{
UnhookWindowsHookEx(_hookID);
}
private IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
OnKeyPressed.Invoke(this, ((Keys)vkCode));
}
else if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP)
{
int vkCode = Marshal.ReadInt32(lParam);
OnKeyUnpressed.Invoke(this, ((Keys)vkCode));
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
解决方案
非常感谢大家的参与
基本上我打算让 C# 代码做的是这个
- X.exe 是由 JitBit Macro Recorder 创建的宏
- C# 读取键盘按钮按下
- 当按下一系列键盘按钮时,它会运行 X.exe 宏
这是一种可怕的做事方式
但这是我现在要做的最好的事情
因此,在 C# 代码中,我需要能够尽快运行 X.exe
这就是为什么我将它加载到内存中
X.exe应该也可以被调用很多很多次
这是我正在玩的游戏
我玩游戏时 C# 程序在后台运行
如果我按下某个键盘按钮序列,C# 将运行 X.exe
这本质上只是 JitBit Macro Recorder 的一个宏
为什么我使用 Jitbit 宏录制器?
因为它是一个速度极快的宏引擎,而且效果很好
以我刚才所说的
非常感谢对 C# 程序的任何进一步贡献
真心感谢大家!!!
推荐阅读
- bash - 使用 SED 在文件中由变量指定的行插入一行
- django - 如何从 html 生成 DOC 和 PDF在 Django
- xml - 从 XML 生成带有注释和文档的 XSD
- python - Python Networkx 权重标签定位
- amazon-web-services - 已删除联合登录用户创建的 AWS 资源
- html - 如何在 printThis 插件中使用背景颜色?
- python - 使用 pandas 在 SQL Server 中插入数据
- gremlin - 给定gremlin中的引用数组,如何获取最相似顶点的列表
- java - 如何修复已弃用的 .getDate()
- android - 使用 java.net.Uri 从 onActivityResult 创建新文件时出现“找不到文件”