如何从MFC应用程序中调用.NET框架

如何从MFC应用程序中调用.NET框架,第1张

如何发送击键到其它应用程序关于如何通过编程来发送 Ctrl+Alt+Del 击键?如何从 MFC 应用程序中调用 NET 框架?我想编写一个应用程序,它能通过击键将信息写到另外一个应用程序的窗体中。我是不是应该发送 WM_KEYDOWN 和 WM_KEYUP 消息?有没有更好的办法?发送WM_KEYDOWN 和 WM_KEYUP 消息也许能行得通,但 SendInput 是专门被设计用于此目的的 API 函数。它通过 INPUT 结构数组参数来合成包括击键和鼠标事件在内的输入,每个 INPUT 结构数组元素对应一个输入事件——击键或鼠标动作。INPUT 结构含有一个联合类型,其成员为 MOUSEINPUT,KEYBDINPUT (或 HARDWAREINPUT,仿真面包烤箱)。对于击键来说其 KEYBDINPUT 结构如下:struct KEYBDINPUT {WORD wVk; // virt key codeWORD wScan; // hw scan codeDWORD dwFlags; // flags—see docDWORD time; // time stamp, 0 = dfltULONG_PTR dwExtraInfo; // app-defined};所以向另外一个应用程序发送击键其实就是建立一个 INPUT 数组,每一个数组元素对应一次击键(d起和按下),然后调用 SendInput 函数。为了示范其实际使用方法,我编写了一个叫 Typematic 的小程序,你只要按下一个热键,便可以快速将姓名、地址、电话号码或其它信息敲入窗体中。这对于网上购物者们来说是件很理想的事情。当你第一次运行 Typematic 时,显示的对话框如 Figure 1 所示:Figure 1 Typematic 的初始对话框按“OK”按钮后进入隐藏状态。其后你可以按 +T 来重新激活 Typematic,显示如 Figure 2 所示的对话框:Figure 2 重新被激活得 Typematic此时可以看到对话框里显示出了一列缩写信息。敲入“n”代表姓名,“a”代表地址,Typematic 发送相应的字符串到当前窗体或应用程序。这些缩写信息定义在一个静态表中,你可以将它们改为自己的信息:struct ABBREV {TCHAR key;LPCTSTR text;} MYABBREVS[] = {{ _T(''n''),_T("Elmer Fudd") },{ _T(''a''),_T("1 Bunny Way") },{ 0,NULL}};当然,在实际开发过程中,你不必硬编码这些信息,你可以提供一个用户界面来定制它,并将其保存在用户配置文件中,以便这一台机器的每一个用户都有不同的设置。Typematic 示范了一些其它的技巧:如何注册热键来激活你的应用程序(参见 2000 第十二期的专栏)以及如何让静态文本控件接受键盘输入(你必须处理 WM_GETDLGCODE 并返回DLGC_WANTCHARS )。Typematic 定义了一个专门的静态文本控件 CStaticAbbrev,它既可以显示缩写信息也可以读取加速键。代码如 Figure 3 所示。当用户按下热键。 Typematic 便被唤醒并将焦点定位到该 CStaticAbbrev 控件,等待字符输入。当 CStaticAbbrev::OnChar 获得一个与表中缩写之一匹配的键时,它便隐藏对话框,然后调用辅助函数 SendString 发送文本:// in CStaticAbbrev::OnCharif (/ find char in ABBREV table /) {GetParent()->ShowWindow(SW_HIDE); // hide dialogSendString(abbrevtext); // send text}当Typematic 将自己隐藏后,Windows 自动将焦点恢复到之前拥有焦点的窗口,这样输入便定下向到用户按热键之前焦点所在的窗口。非常聪明,不是吗?如果你需要将输入定向到一个特定的应用程序或窗口,调用 SendInput 之前一定要确保它是活动的,为此可以调用 SetForegroundWindow 函数。所有发送击键的工作都在 SendString 中进行,它建立 INPUT 数组并调用 SendInput (参见 Figure 3)。SendString 发送一系列 KEYDOWN/KEYUP 的 INPUT 结构对,字符串中的每一个字符对应一双这样的结构表示按下/d起。它用 KEYEVENTF_UNICODE 标志将串作为 Unicode 字符发送。Unicode 比较容易处理,因为你不必用 Shift 键合成大写字符。如果不借助 KEYEVENTF_UNICODE 的话,你必须将大写的 E 发送成 后跟e,每个字符都有一次按下/d起(down/up)事件, 共有四次击键。感谢微软的人添加了 KEYEVENTF_UNICODE。如果你用托管 C++ 或 Microsoft NET 中其它的语言编程,发送击键更容易。有一个框架类叫 SendKeys,其静态函数 Send 使得发送击键易如反掌。你甚至可以用花哨的语法发送专用键。例如用“{F1}{BACKSPACE}A”来发送 F1,Backspace,A。为此我还写了NET 版本的 Typematic,起名为:TypematicNET,它使用 SendKeys。这样 SendString 函数变成这样:#pragma managedvoid SendString(LPCTSTR str) {SendKeys::SendWait(str);}还有什么比这更容易呢?当我刚开始做的时候,我很自然地用 SendKeys::Send 尝试,而不是 SendWait。为什么我要等待应用程序吃完这些键呢?唉,我尝试的时候 Typematic 惨烈地崩溃了,在 WindowsFormsdll 的某个地方发生 SystemInvalidOperationException 异常。当我启动公共语言运行时(CLR)调试器察看缘由时,Output 窗口显示出下列信息:“附加信息:由于该应用程序不处理 Windows 消息,SendKeys 无法在该应用程序中运行。要么让该应用程序处理消息,要么使用 SendKeysSendWait 方法。”这就是我所称得友好的出错信息!就让它成为所有人的一个例子吧。但在使用 SendKeys 之前,要提醒你的一件事情是:它不像 SendInput 那样稳定。通过针对不同的应用如:IE、Notepad、MFC 窗体视图或其它熟悉的应用,对 Typematic 和 TypematicNET 进行测试,你自己就能发现这个结果。处于某些原因,SendKeys 工作并不总是正常。我猜测它是焦点或定时问题——这些键被发送后马上就消失了,因为你认为具有焦点的窗口实际上没有焦点。所以虽然 SendKeys 很容易使用,同时也比 SendInput 更强大,但它在使用过程中的表现不佳,很可惜!也许微软的老大们在下一个版本中能摆平这个问题。一个最后的警告:发送击键是一种名声狼藉的控制其它应用程序的古怪方法。你必须完全正确地获得所有键,一旦上下文或用户界面稍有改变,便可能导致问题。如果你想要控制其它应用程序,可以看看脚本系统、编程接口或宏语言。我读了一些关于禁用系统键序列的文章,如:Ctrl+Alt+Del,包括你在 2002 年 MSDN 杂志九月刊上的专栏文章。但是我如何通过编程来发送 Ctrl+Alt+Del 呢?William Burns本文的第一个问题回答了如何发送击键到任何应用程序,但是你无法用 SendInput 发送 Ctrl+Alt+Del,因为这个键序列是在 *** 作系统底层处理的。不管怎样,用合成击键的方法来“发送”Ctrl+Alt+Del 是不合适的。那用什么方法呢?如果你想启动任务管理器,用“taskmgrexe”作为参数调用 ShellExecute。如果你想重启机器,可以用 EWX_REBOOT 标志调用 ExitWindowsEx。ExitWindowsEx 具备所有以不同方式关闭或重启机器的标志(参见 Figure 4)。此外,你的应用程序必须具备 SE_SHUTDOWN_NAME 特权才能重启机器。有人知道 Ctrl+Alt+Del 的由来吗?如果你认为你知道,给我发个 e-mail 过来。我会在以后的专栏里公布答案?我能从 MFC 应用程序中调用 NET 框架吗?我想从我的非托管 MFC 代码中调用托管类,并且我想通过 #using 来做,但我总遇到“/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 开关。在缺省情况下,所有函数都是托管的了。如果你想默认使用本地模式,可以在 stdafxh 文件的末尾添加一行:#pragma unmanaged因为每个模块都要包含 stdafxh 文件,所以所有模块都是以本地模式进行编译的。当要调用 NET 框架时,你可以像这样跳到托管模式:#pragma managedvoid DoSomethingWithDotNET() {// call framework classes here}直到现在,我都是用这个技巧(将 #pragma unmanaged 放在 stdafxh 末尾)。但它解决不了运行时检查问题,因为 /clr 仍然与 /RTC 不兼容,即便你的大多数函数是本地的。在混合模式的应用程序中,编译器不会让你在本地函数中进行运行时检查的。Figure 5 项目设置你真正想做的是只用 /clr 编译调用 NET 框架的模块。但如何做呢?当在项目范围内使用“使用托管扩展”时,这一点很容易做到:在模块生成属性的“命令行”项下添加专门的开关即可。Figure 5 和 Figure 6 显示了设置方法。在全局项目设置中,将“使用托管扩展”设置为“否”,然后针对每个调用 NET 框架的模块添加 /clr。此时其它模块仍然使用 /RTC1 并执行运行时检查。当然,你必须将以及所有来自 stdafxh 的框架文件移到托管模块中。如果你愿意,可以将所有标准的 NET 包含在一个 UsesDotNeth 文件中,就像下面这样:#using #using #include using namespace System;Figure 6 模块设置然后在每个调用 NET 框架的模块中包含 #include "UsesDotNeth" 即可。你仍然可以在某个模块中用 #pragma managed/unmanaged 来混合托管和本地代码。还有一个设置要做,那就是当你添加 /clr 到一个模块文件时,除了关闭运行时检查外,你同时还必须选择“不使用与编译头”。与编译头信息仅在所有模块具有相同的编译选项时才起作用;如果一个模块有 /clr 选项,那么它不能使用与其它没有 /clr 选项的模块相同的预编译头。嘿,当今计算机是如此之快,谁还需要预编译头?如果你确实想与众不同,那么就用单独的头文件如 UsesDotNeth 来编译你的托管模块吧。

CWnd::OnKeyDown

afx_msg

void

OnKeyDown(

UINT

nChar,

UINT

nRepCnt,

UINT

nFlags

);

参数:

nChar

指定了给定键的虚拟键码。

nRepCnt

重复计数(用户按住键引起的重复击键数目)。

nFlags

指定了扫描码、暂态键码、原来的键状态和上下文代码,如下面的列表所示:

描述

0-7

扫描码(依赖于OEM的值)

8

扩展键,比如功能键或数字键盘上的键(如果它是扩展键,则为1)

9-10

未使用

11-12

Windows内部使用

13

上下文代码(如果按下键时ALT键时被按下的,则为1;否则为0)

14

原来的键状态(如果在调用之前键时按下的,则为1;如果键是d起的,则为0)

15

暂态(如果键正在被释放,则为1;如果键正被按下,则为0)

对于WM_KEYDOWN消息,键暂态位(15位)为0,并且上下文代码位(13位)为0。

说明:

当用户按下了一个非系统键时,框架调用这个成员函数。非系统键是指当ALT键为被按下时按下的键盘键或者当CWnd拥有输入焦点时按下的键盘键。

由于自动重复,在调用OnKeyUp成员函数之前可能会产生多个OnKeyDown调用。指明原来的键状态的位可以被用来确定OnKeyDown调用时是第一次被按下还是重复的按下状态。

对于IBM增强101和102键键盘,增强键包括键盘主体部分的右ALT键和右CTRL键;数字键盘左侧的INS,DEL,HOME,END,PAGE

UP,PAGE

DOWN和箭头键;以及数字键盘上的斜杠(/)和ENTER键。一些其它的键盘可能支持nFlags中的扩展键位。

注意

框架调用这个成员函数以允许你的应用程序处理一个Windows消息。传递给你的成员函数的参数反映了接收到消息时框架接收到的参数。如果你调用了这个函数的基类实现,则该实现将使用最初传递给消息的参数(而不是你提供给这个函数的参数)。

当键盘有按键被按下的时候,OnKeyDown函数会被调用。

函数原型:

afx_msg void OnKeyDown(

UINT nChar,

UINT nRepCnt,

UINT nFlags

);

参数一:UINT nChar 虚拟键盘码

参数二:UINT nRepCnt, nRepCnt参数保存了键被重击的次数。

参数三:UINT nFlags,值是一个16位的UINT型各位代表的意义如下:

第0-7位:扫描码

第8位:扩展键,比如说功能键(F1-12),或者数字区的键

第9-10位:没有使用

第11-12位:供Windows内部使用

第13位:状态描述码(如果键按下时ATL键也是按下的,那么值为1,否则为0)

第14位:前一个键的状态(如果是按下的,值为1,否则为0)

第15位:变换状态(如果键是正在被按下,值为1,如果是正在放开,值为0)

对话框是不会响应OnChar和OnKeyDown消息的,会被 其它控件拦截

试时发现不会进入这两个函数,必须重定义PreTranslateMessage()虚函数才能正确地进入这两个消息函数,具体实现如下:

BOOL CTestDlg::PreTranslateMessage(MSG pMsg)

{

SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam);

return 0;

//return CDialog::PreTranslateMessage(pMsg);

}

这样,程序就能正确地调用onKeyDown和onChar这两个函数了,且onKeyDown()在onCchar()之前处理的。

这样就能在对话框中响应WM_CHAR、WM_KEYDOWM消息了,注意在发送WM_CHAR时,实际发送了三个消息

即 WM_CHAR

WM_KEYDOWM

WM_KEYUP

所以,如果你有如下代码:

void CMy1Dlg::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

// TODO: Add your message handler code here and/or call default

if(nChar=='a')

MessageBox("a");

CDialog::OnChar(nChar, nRepCnt, nFlags);

}

会d出两个消息对话框 ,所以最好单独在WM_KEYDOWM或WM_KEYUP处理事件。

SendKeysSend(KeysEnterToString());//模拟按下回车键

SendKeysSend("{BackSpace}");// 模拟按下退格键

以下是 SendKeys 的一些特殊键代码表。

键 代码

BACKSPACE {BACKSPACE}、{BS} 或 {BKSP}

BREAK {BREAK}

CAPS LOCK {CAPSLOCK}

DEL 或 DELETE {DELETE} 或 {DEL}

DOWN ARROW(下箭头键) {DOWN}

END {END}

ENTER {ENTER} 或 ~

ESC {ESC}

HELP {HELP}

HOME {HOME}

INS 或 INSERT {INSERT} 或 {INS}

LEFT ARROW(左箭头键) {LEFT}

NUM LOCK {NUMLOCK}

PAGE DOWN {PGDN}

PAGE UP {PGUP}

PRINT SCREEN {PRTSC}(保留,以备将来使用)

RIGHT ARROW(右箭头键) {RIGHT}

SCROLL LOCK {SCROLLLOCK}

TAB {TAB}

UP ARROW(上箭头键) {UP}

F1 {F1}

F2 {F2}

F3 {F3}

F4 {F4}

F5 {F5}

F6 {F6}

F7 {F7}

F8 {F8}

F9 {F9}

F10 {F10}

F11 {F11}

F12 {F12}

F13 {F13}

F14 {F14}

F15 {F15}

F16 {F16}

数字键盘加号 {ADD}

数字键盘减号 {SUBTRACT}

数字键盘乘号 {MULTIPLY}

数字键盘除号 {DIVIDE}

若要指定与 SHIFT、CTRL 和 ALT 键的任意组合一起使用的键,请在这些键代码之前加上以下一个或多个代码:

键 代码

SHIFT +

CTRL ^

ALT %

keydown

当你按下键盘中的键后启动,并且把你按的以ASCII的方式存在keycode变量中

keypress

地位仅次于keydown的事件,如果本身有keydown事件的话此事件很可能没有反应(这个需要按着才能触发事件)

(keyup是释放任一键吧囧)

这个程序的意思很大一部分和ascii表有关

=====================

题目很简单:你可以查表之后发现e的ascii表上代表101,101-4=97,也就是a(小写),一次类推,r是114,114-4=110,查表后发现答案是n

仔细看看下面的表吧~哇户

以上就是关于如何从MFC应用程序中调用.NET框架全部的内容,包括:如何从MFC应用程序中调用.NET框架、谁能讲一下C++中的函数“OnKeyDown”、VC/MFC什么时候调用OnKeyDown函数等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zz/9797167.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-02
下一篇 2023-05-02

发表评论

登录后才能评论

评论列表(0条)

保存