出现的错误是这个:检测到 PInvoke 堆栈不平衡。
您所看到的只是一点背景,Ria 的回答将解决您的问题。这实际上不是错误,它是 MDA 产生的警告。托管调试助手,它是添加到 CLR、框架和调试器的额外代码,用于密切关注意外的运行时问题,并在使用调试器运行时激活。您可以查看可用的 MDA,使用 Debug + Exceptions 并展开“Managed Debugging Assistants”节点来查看它们。默认情况下,它们中的很多都被禁用,因为它们往往很吵,或者往往会产生错误的警告,或者以后已经产生了异常。请注意,pInvokeStackImbalance MDA 实际上并未在此处列出,它很特别,因为它无法关闭。
完整的 MDA 列表记录在 here。 pInvokeStackImbalance 的描述包含对它检测到的问题原因的体面描述:
平台调用调用的托管签名可能与被调用方法的非托管签名不匹配。这种不匹配可能是由于托管签名没有声明正确数量的参数或没有为参数指定适当的大小。 MDA 也可以激活,因为调用约定(可能由 DllImportAttribute 属性指定)与非托管调用约定不匹配。
我在您的案例中强调了真正的原因,您的 lParam 参数类型错误。 wParam 类型也是错误的,但碰巧有正确的大小。当您的代码在 64 位操作系统上运行时,这些事故往往会发生。
虽然这只是一个警告,并且当您忽略它并继续运行时,您的代码似乎运行良好,但堆栈不平衡是一种非常严重的运行时问题。故障模式是不可预测的,它可能在 Debug 版本中运行得很好,但在 Release 版本中会用一个难以理解的异常来轰炸你的程序。这里的具体问题是,当您调用该方法时,您在堆栈上推送了太多数据,而 Windows 没有从堆栈中弹出足够多的数据。当你经常调用它时,它会用这个站点的名称来轰炸你的程序。这个问题往往被隐藏起来,因为从 C# 方法返回会重新平衡堆栈。在发布模式下,抖动优化器内联该方法时,所有赌注都关闭。只有当您没有附加调试器时它才会这样做,这是尝试诊断的最糟糕的错误。
找到正确的 pinvoke 声明并不是特别容易。声明它们的方法不止一种,您经常会发现关于声明的故意“谎言”,以使函数更容易被调用。 pinvoke.net 网站是一个相当不错的来源,尽管它倾向于过度指定声明。就像在 Ria 的示例中一样,[return:] 属性是不必要的,因为这已经是 bool 的默认编组。当您不拥有窗口句柄时,HandleRef 没有多大意义。但它会工作得很好。另一个相当不错的来源是 Pinvoke Interop Assistant,这是一个您可以find here 的工具。它会生成自动生成的声明,它们并不漂亮。
最后但同样重要的是,您不能使用 PostMessage 可靠地将击键插入另一个进程的窗口。当您需要进程的键盘状态准确时,您会遇到麻烦,尤其是 Shift、Alt 和 Ctrl 键。像 Alt+Gr 这样的死键出现在具有不同布局的键盘上,特别是对于有很多变音符号或大字母表的语言。要戳打字键,您应该改用 WM_CHAR。