如何从 MFC 应用程序中调用 .NET 框架求答案
1个回答
展开全部
有一个框架类叫 SendKeys,其静态函数 Send 使得发送击键易如反掌。你甚至可以用花哨的语法发送专用键。例如用“{F1}{BACKSPACE}A”来发送 F1,Backspace,A。为此我还写了.NET 版本的 Typematic,起名为:Typematic.NET,它使用 SendKeys。这样 SendString 函数变成这样:#pragma managed void SendString(LPCTSTR str) { SendKeys::SendWait(str); } 还有什么比这更容易呢?当我刚开始做的时候,我很自然地用 SendKeys::Send 尝试,而不是 SendWait。为什么我要等待应用程序吃完这些键呢?唉,我尝试的时候 Typematic 惨烈地崩溃了,在 Windows.Forms.dll 的某个地方发生 System.InvalidOperationException 异常。当我启动公共语言运行时(CLR)调试器察看缘由时,Output 窗口显示出下列信息:“附加信息:由于该应用程序不处理 Windows 消息,SendKeys 无法在该应用程序中运行。要么让该应用程序处理消息,要么使用 SendKeys.SendWait 方法。” 这就是我所称得友好的出错信息!就让它成为所有人的一个例子吧。但在使用 SendKeys 之前,要提醒你的一件事情是:它不像 SendInput 那样稳定。通过针对不同的应用如:IE、Notepad、MFC 窗体视图或其它熟悉的应用,对 Typematic 和 Typematic.NET 进行测试,你自己就能发现这个结果。处于某些原因,SendKeys 工作并不总是正常。我猜测它是焦点或定时问题——这些键被发送后马上就消失了,因为你认为具有焦点的窗口实际上没有焦点。所以虽然 SendKeys 很容易使用,同时也比 SendInput 更强大,但它在使用过程中的表现不佳,很可惜!也许微软的老大们在下一个版本中能摆平这个问题。 一个最后的警告:发送击键是一种名声狼藉的控制其它应用程序的古怪方法。你必须完全正确地获得所有键,一旦上下文或用户界面稍有改变,便可能导致问题。如果你想要控制其它应用程序,可以看看脚本系统、编程接口或宏语言。 我读了一些关于禁用系统键序列的文章,如:Ctrl+Alt+Del,包括你在 2002 年 MSDN 杂志九月刊上的专栏文章。但是我如何通过编程来发送 Ctrl+Alt+Del 呢? William Burns 本文的第一个问题回答了如何发送击键到任何应用程序,但是你无法用 SendInput 发送 Ctrl+Alt+Del,因为这个键序列是在操作系统底层处理的。不管怎样,用合成击键的方法来“发送”Ctrl+Alt+Del 是不合适的。那用什么方法呢?如果你想启动任务管理器,用“taskmgr.exe”作为参数调用 ShellExecute。如果你想重启机器,可以用 EWX_REBOOT 标志调用 ExitWindowsEx。ExitWindowsEx 具备所有以不同方式关闭或重启机器的标志(参见 Figure 4)。此外,你的应用程序必须具备 SE_SHUTDOWN_NAME 特权才能重启机器。 有人知道 Ctrl+Alt+Del 的由来吗?如果你认为你知道,给我发个 e-mail 过来。我会在以后的专栏里公布答案? 我能从 MFC 应用程序中调用 .NET 框架吗?我想从我的非托管 MFC 代码中调用托管类,并且我想通过 #using <mscorlib.dll> 来做,但我总遇到“/RTC1 incompatible with /clr”。那么我如何才能从 MFC 应用程序中调用 .NET? Julian Kinsey 你当然可以从你的 MFC 程序中调用 .NET!就像 Windows 中的其它机制一样,一旦你知道了正确的方法,它是很容易的。当你着手创建 MFC 程序时,应用程序向导(App Wizard)为你设置所有的编译选项。其中之一是项目配置属性中“C/C++|代码生成”项下的“基本运行时检查”。在创建 MFC 程序时,应用程序向导在调试版本中选择“两者/RTC1,等同于/RTCsu)”以实现运行时检查,如检查堆栈帧、未初始化变量或缓冲溢出及内存不足。这些检查与 /clr 不兼容,因为托管代码完全不同(它是 Microsoft 的中间语言,非本机语言),但是当你添加 /clr ,那么 IDE 不会自动移除 /REC1。所以你必须用手动方式来做。 对于项目中的每一个 .cpp 文件,“基本运行时检查”设置为“默认”。这样做十分不幸,因为对于本地/非托管函数来说,这项检查是很好的事情。它有助于你在交付前发现程序的Bug。但对于要调用.NET类库的程序来说,这样做就不是一件好事。那么我们该怎么办呢? 问题是使用托管扩展调用 .NET 框架,你必须将“使用托管扩展”设置为“是”,它将打开/clr开关,进行这个设置的唯一地方是在项目属性页中,它是全局有效的。“使用托管扩展”为项目中所有模块打开/clr 开关。在缺省情况下,所有函数都是托管的了。如果你想默认使用本地模式,可以在 stdafx.h 文件的末尾添加一行:#pragma unmanaged 因为每个模块都要包含 stdafx.h 文件,所以所有模块都是以本地模式进行编译的。当要调用 .NET 框架时,你可以像这样跳到托管模式:#pragma managed void DoSomethingWithDotNET(...) { // call framework classes here // safe from managed functions } 直到现在,我都是用这个技巧(将 #pragma unmanaged 放在 stdafx.h 末尾)。但它解决不了运行时检查问题,因为 /clr 仍然与 /RTC 不兼容,即便你的大多数函数是本地的。在混合模式的应用程序中,编译器不会让你在本地函数中进行运行时检查的。 Figure 5 项目设置 你真正想做的是只用 /clr 编译调用 .NET 框架的模块。但如何做呢?当在项目范围内使用“使用托管扩展”时,这一点很容易做到:在模块生成属性的“命令行”项下添加专门的开关即可。Figure 5 和 Figure 6 显示了设置方法。在全局项目设置中,将“使用托管扩展”设置为“否”,然后针对每个调用 .NET 框架的模块添加 /clr。此时其它模块仍然使用 /RTC1 并执行运行时检查。当然,你必须将<mscorlib.dll>以及所有来自 stdafx.h 的框架文件移到托管模块中。如果你愿意,可以将所有标准的 .NET 包含在一个 UsesDotNet.h 文件中,就像下面这样:#using <mscorlib.dll> #using <System.dll> #include <vcclr.h> using namespace System; Figure 6 模块设置 然后在每个调用 .NET 框架的模块中包含 #include "UsesDotNet.h" 即可。你仍然可以在某个模块中用 #pragma managed/unmanaged 来混合托管和本地代码。 还有一个设置要做,那就是当你添加 /clr 到一个模块文件时,除了关闭运行时检查外,你同时还必须选择“不使用与编译头”。与编译头信息仅在所有模块具有相同的编译选项时才起作用;如果一个模块有 /clr 选项,那么它不能使用与其它没有 /clr 选项的模块相同的预编译头。嘿,当今计算机是如此之快,谁还需要预编译头?如果你确实想与众不同,那么就用单独的头文件如 UsesDotNet.h 来编译你的托管模块吧。 在实际应用中,如果你使用我这里所描述的方法,请参考本文附带的例子代码:Typematic.NET,其中所有模块都是以常规的本地方式编译的,通过 stdafx.h 使用预编译头,并且不使用“托管扩展”选项。唯一调用 .NET 框架的函数位于一个单独的模勘疚氖纠牖蛩夭南略
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询