﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-c++初学者-随笔分类-VC++</title><link>http://www.cppblog.com/tgh621/category/8150.html</link><description>专注技术开发</description><language>zh-cn</language><lastBuildDate>Wed, 11 Feb 2009 17:37:41 GMT</lastBuildDate><pubDate>Wed, 11 Feb 2009 17:37:41 GMT</pubDate><ttl>60</ttl><item><title>MFC窗口的清除过程[转]</title><link>http://www.cppblog.com/tgh621/archive/2009/02/11/73433.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Wed, 11 Feb 2009 02:50:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2009/02/11/73433.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/73433.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2009/02/11/73433.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/73433.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/73433.html</trackback:ping><description><![CDATA[<p>对于vc++初学者来说,总觉得窗口对象的清除过程有些莫名其妙.在程序中看不到对delete的显式调用,这似乎违反了c++中有关初始化和清除的规则.那么,程序是怎样取消一个窗口对象?</p>
<p>要消除窗口对象,必须清楚窗口对象的构成.在一个通常的程序中，先创建c++窗口对象,然后由Windows创建实际的窗口结构,并返回句柄与c++对象连接.也就是说,窗口对象包含c++窗口对象和Windows窗口对象,两者通过句柄HWND联系.</p>
<p>现在,让我们看看"正规"的窗口对象清除流程.所谓对象的清除是指释放对象所占的资源,窗口对象中Windows窗口对象占有的是系统资源,c++对象占有的是内存资源.释放系统资源相对要简单一些:调用虚函数DestroyWindow删除Windows窗口对象.如果DestroyWindow删除的是父窗口,Windows会自动为子窗口调用DestroyWindow.一般来说,程序不必调用DestroyWindow.因为当用户关闭窗口时,Windows便发送WM_CLOSE消息,WM_CLOSE的缺省消息处理函数CWnd::OnClose调用DestroyWindow.</p>
<p>到这时,清除工作已经完成了一半,屏幕上的窗口已经不见了!但是别忘了,在内存中还有一个c++窗口对象.让我们再看看c++对象清除的过程:当窗口被取消时,窗口最后发送的一个消息是WM_NCDESTROY.它缺省的消息处理函数CWnd::OnNcDestroy把c++窗口对象与句柄HWND分离,并调用一个很重要的虚函数PostNcDestroy.这个函数是搞清窗口对象清除的关键.Cwnd中的PostNcDestroy什么都不做.有些MFC窗口类会重载它,并加入delete this代码删除c++对象.这些窗口类常常是以new操作符建立在堆中的.由于重载了PostNcDestroy,使窗口有自动清除功能.因此,我们不用关心清除问题了.另外的一些MFC窗口类一般是以变量形式创建的,MFC没有为也没必要为它们重载PostNcDestroy函数.</p>
<p>不具备自动清除功能的窗口类,一般在堆栈中创建或嵌入于其它c++对象中:</p>
<p>所有标准的Windows控件类(如CStatic, CEdit, CListBox等等)</p>
<p>由CWnd类直接派生出来的子窗口对象(如用户定制的控件)</p>
<p>拆分窗口类(CSplitterWnd)</p>
<p>缺省的控制条类(CControlBar的派生类)</p>
<p>对话框类(CDialog)在堆栈上创建的模态对话框类</p>
<p>所有的Windows通用对话框(除CFindReplaceDialog)</p>
<p>由ClassWizard创建的对话框</p>
<p>具有自动清除功能的窗口类,一般在堆中创建:</p>
<p>主框架窗口类(直接或间接从CFrameWnd类派生)</p>
<p>视图类(直接或间接从CView类派生)</p>
<p>从某种程度上来说,MFC的"服务到家"使初学者有些找不着北.不过,不得不承认:MFC干的很漂亮!</p>
<p>谈到这里,我们应该明白c++里一条重要的准则:用DestroyWindow清除窗口对象,不要用"delete".</p>
<p>对于不具备自动清除功能的窗口类使用"delete"时,"delete"先调用析构函数里的DestroyWindow,由于在析构函数中,虚机制不起作用,这里只能调用本地版本(Cwnd类)DestroyWindow函数,显然这不是我们想要的.对于有自动清除功能的窗口类,好象问题更严重一点,前面提到了重载的PostNcDestroy已经含有了"delete this",这样c++对象就被释放了两次.</p>
<p>很多人认为,vc++同vb一样,是一个完全可视化的产品,不用在看c++的书了.通过上面对窗口对象的清除的介绍,可以发现,Windows程序是与Windows紧密结合的,而且牵涉到很多c++的知识(如虚函数、析构函数、new操作符等).要对vc++有进一步理解,必须理解Windows机制,深入学习c++.</p>
<img src ="http://www.cppblog.com/tgh621/aggbug/73433.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2009-02-11 10:50 <a href="http://www.cppblog.com/tgh621/archive/2009/02/11/73433.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]可在运行时编辑的加速键表</title><link>http://www.cppblog.com/tgh621/archive/2009/01/12/71821.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Mon, 12 Jan 2009 09:22:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2009/01/12/71821.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/71821.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2009/01/12/71821.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/71821.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/71821.html</trackback:ping><description><![CDATA[＊＊＊简　介＊＊＊
<p>　　本文首先简要介绍了一下<a href="http://dev.21tx.com/os/windows/" target=_blank><u><font color=#0000ff>Windows</font></u></a>中的几个与<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表有关的API函数及结构。然后对在WIN32位程序中实现<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行了探讨，分别就API下的程序设计及MFC下的程序设计进行了叙述。<br>　　对于运行时可编辑的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表仅在MFC下进行了详细描述。包括其实现原理，并引导大家建立了一个用于编辑<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的对话框，含详细的代码。关于在API下实现运行时的可编辑<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表不再叙述，可参考MFC下的代码。<br>　　我们通常希望将编辑过的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存起来，以便下次运行程序时保持我们编辑后的风格。在本文的最后，介绍了如何将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存至文件中，并从文件中读取我们保存的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。你若是有意将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存至<a href="http://school.21tx.com/os/regtable/" target=_blank><u><font color=#0000ff>注册表</font></u></a>或其它什么地方，可参考其它的有关资料。本人建议保存至文件比较恰当。<br>　　本文介绍的所有方法及代码都是在 Windows98SE + Microsoft Visual <a href="http://dev.21tx.com/language/c/" target=_blank><u><font color=#0000ff>C++</font></u></a> 6.0 中进行编制和调试的。　</p>
<p><br>　　一、与<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表有关的几个API函数和结构。</p>
<p>　　操作<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表使用的几个API函数（关于这几个函数的详细说明请参考有关书籍）：<br>　　HACCEL LoadAccelerators(HINSTANCE hInstance, LPCTSTR lpTableNAme);<br>　　LoadAccelerators函数从程序的资源中加载一个<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表，加载成功后返回一个加速健表的句柄。其中：<br>　　hInstance　　应用程序的实例句柄。<br>　　lpTableName　指向<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表名称字符串的指针。</p>
<p>　　HACCEL CreateAcceleratorTable(LPACCEL lpaccl, int cEntries);<br>　　CreateAcceleratorTable函数根据一个ACCEL结构数组创建一个<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。该函数与LoadAccelerators不同的是：LoadAccelerators函数加载的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表在程序结束后系统会自动将该<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表从内存中清除，但CreateAcceleratorTable函数创建的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表需要使用函数DestoryAceleratorTable函数进行清除。<br>　　lpaccl　　　一个指向ACCEL结构数组的指针。<br>　　cEntries　　数组中元素的个数。</p>
<p>　　BOOL　DestoryAcceleratorTable(HACCEL hAccel);<br>　　DestoryAcceleratorTable函数清除由CreateAcceleratorTable函数创建的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表，成功则返回TRUE。其中：<br>　　hAccel　　　需要清除的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表句柄。</p>
<p>　　int TranslateAccelerator(HWND hWd, HACCEL hAccTable, LPMSG lpMsg);<br>　　TranslateAccelerator函数负责翻译<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>。其中：<br>　　hWnd　　　　 窗口句柄，翻译后的消息将被发往该窗口<br>　　hAccTable　　<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表句柄。<br>　　lpMsg　　　　指向MSG结构的指针。</p>
<p>　　ACCEL结构的定义：<br>typedef struct tagACCEL{<br>&nbsp;&nbsp;&nbsp; BYTE&nbsp;&nbsp;&nbsp; fVirt;<br>&nbsp;&nbsp;&nbsp; WORD&nbsp;&nbsp;&nbsp; key;<br>&nbsp;&nbsp;&nbsp; WORD&nbsp;&nbsp;&nbsp; cmd;<br>}ACCEL,*LPACCEL;</p>
<p>其中：<br>　　fVirt　　　<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的标记。<br>　　key　　　　键的代码。如fVirt成员包含FVIRTKEY标志，则key指一个虚键码，否则是一个ASCII码。<br>　　cmd　　　　命令ID号，该参数将被放入WM＿COMMAND或WM＿SYSCOMMAND消息的wParam参数的低位字发至窗口。</p>
<p><br>　　二、在windows下如何使用<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。</p>
<p>　　在window下使用<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表一般有两种方法：1，创建一个<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>资源，在程序中使用API函数LoadAccelerators来将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表加载入内存。并在消息循环中使用API函数TranslateAccelerator来翻译该<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。2、在程序中填充一个ACCEL数组。然后调用API函数CreateAcceleratorTable来创建加速表，翻译<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>同上，但不要忘记在退出程序前使用API函数DestoryAcceleratorTable来清除它。下面分别给出一个例子：</p>
<p>/*例1:使用LoadAccelerators。<br>　假设你已经建立了一个<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>资源，ID为IDR＿ACCEL。<br>　假设你已经定义了初始化函数InitApplication(HINSTANCE hInstance,int nCmdShow),<br>　该函数执行注册窗口类和创建窗口操作。<br>*/<br>#include &lt;windows.h&gt;<br>#include "rc/resource.h"<br>BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);</p>
<p>int APIENTRY WinMain(HINSTANCE hInstance,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HINSTANCE hPrevInstance,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPSTR&nbsp;&nbsp;&nbsp;&nbsp; lpCmdLine,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nCmdShow) <br>{<br>&nbsp;&nbsp;&nbsp;&nbsp; MSG msg;<br>&nbsp;&nbsp;&nbsp;&nbsp; HANDLE hAccelTable;<br>&nbsp;&nbsp;&nbsp;&nbsp; // 初始化应用程序，并生成主窗口.<br>&nbsp;&nbsp;&nbsp;&nbsp; if (!InitApplication(hInstance, nCmdShow))<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 初始化失败<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //使用函数LoadAccelerators从程序资源中加载<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 取得并分发消息直到接收到 WM_QUIT 消息.<br>&nbsp;&nbsp;&nbsp;&nbsp; while (GetMessage(&amp;msg, NULL, 0, 0))<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //在分发消息前首先试着用<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行翻译，如果是一个<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>则由<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //TranslateAccelerator函数进行翻译，不再继续处理该消息。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!TranslateAccelerator(msg.hwnd, hAccelTable, &amp;msg))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TranslateMessage(&amp;msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DispatchMessage(&amp;msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; return msg.wParam;&nbsp; // Returns the value from PostQuitMessage <br>} <br>&nbsp;</p>
<p><br>/*例2:使用CreateAcceleratorTable。<br>　假设你已经定义了初始化函数InitApplication(HINSTANCE hInstance,int nCmdShow),<br>　该函数执行注册窗口类和创建窗口操作。<br>*/</p>
<p>#include &lt;windows.h&gt;<br>#include "rc/resource.h"</p>
<p>＃define ID_CMD_A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00000230<br>＃define ID_CMD_B&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00000231<br>＃define ID_CMD_C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00000232<br>＃define ID_CMD_D&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00000233<br>＃define ID_CMD_E&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00000234<br>＃define ID_CMD_F&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00000235<br>＃define ID_CMD_G&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x00000236</p>
<p>//定义了七个<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>,请在消息回调函数中处理这七个命令ID。<br>static ACCEL accel[]={<br>&nbsp;&nbsp;&nbsp; {FVIRTKEY|FCONTROL,VK_F5,ID_CMD_A},<br>&nbsp;&nbsp;&nbsp; {FVIRTKEY|FCONTROL,VK_F6,ID_CMD_B},<br>&nbsp;&nbsp;&nbsp; {FVIRTKEY|FCONTROL,VK_HOME,ID_CMD_C},<br>&nbsp;&nbsp;&nbsp; {FVIRTKEY|FCONTROL,VK_END,ID_CMD_D},<br>&nbsp;&nbsp;&nbsp; {FVIRTKEY|FCONTROL,"G",ID_CMD_E},<br>&nbsp;&nbsp;&nbsp; {FVIRTKEY|FCONTROL,VK_SPACE,ID_CMD_F},<br>&nbsp;&nbsp;&nbsp; {FVIRTKEY|FCONTROL,"K",ID_CMD_G},<br>};&nbsp;&nbsp;&nbsp; </p>
<p>BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);</p>
<p>int APIENTRY WinMain(HINSTANCE hInstance,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HINSTANCE hPrevInstance,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LPSTR&nbsp;&nbsp;&nbsp;&nbsp; lpCmdLine,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nCmdShow) <br>{<br>&nbsp;&nbsp;&nbsp;&nbsp; MSG msg;<br>&nbsp;&nbsp;&nbsp;&nbsp; HANDLE hAccelTable;<br>&nbsp;&nbsp;&nbsp;&nbsp; // 初始化应用程序，并生成主窗口.<br>&nbsp;&nbsp;&nbsp;&nbsp; if (!InitApplication(hInstance, nCmdShow))<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 初始化失败<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //使用函数CreateAcceleratorTable从数组accel中加载<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hAccelTable = CreateAcceleratorTable(accel, sizeof(accel)/sizeof(ACCEL));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 取得并分发消息直到接收到 WM_QUIT 消息.<br>&nbsp;&nbsp;&nbsp;&nbsp; while (GetMessage(&amp;msg, NULL, 0, 0))<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //在分发消息前首先试着用<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行翻译，如果是一个<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>则由<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //TranslateAccelerator函数进行翻译，不再继续处理该消息。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!TranslateAccelerator(msg.hwnd, hAccelTable, &amp;msg))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TranslateMessage(&amp;msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DispatchMessage(&amp;msg);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; //删除<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表<br>&nbsp;&nbsp;&nbsp;&nbsp; DestoryAcceleratorTable(hAccelTable);<br>&nbsp;&nbsp;&nbsp;&nbsp; return msg.wParam;&nbsp; // Returns the value from PostQuitMessage <br>} <br>&nbsp;</p>
<p><br>　　在MFC程序设计中，有关于<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的操作已经被CFrameWnd类进行了封装。通常，我们的程序的主框架类CMainFrame从CFrameWnd类派生（SDI界面程序），或者从CMDIFrameWnd类派生（MDI界面程序），而CMDIFrameWnd类也是从CFrameWnd类派生的。所以，我们并不用去关心那个资源号为IDR_MAINFRAME的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表是如何加载的，如果你只是需要一个这样的静态的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的话。<br>　　那么我们能不能使用自己的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表呢？答案是：可以的。<br>　　创建<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的方法同前。由于在MFC中，WinMain函数被隐藏，我们不能直接修改WinMain函数，所以，<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的创建将在CMainFrame的OnCreate函数中创建。<br>　　1、在CMainFrame类中添加一个HACCEL类型保护成员变量：m_hMyAccel。在构造函数中初始化为NULL。<br>　　2、在CMainFrame::OnCreate函数的 &#8220;return 0;&#8221;句前增加创建<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的代码。返回的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表句柄保存在m_hMyAccel中：</p>
<p>　　　方法1：(IDR＿MYACCEL为你定义的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表资源号)<br>　　　m_hMyAccel=LoadAccelerators(AfxGetApp()-&gt;m_hInstance,MAKEINTRESOURCE(IDR_MYACCEL));</p>
<p>　　　方法2：(accel同前面的例子一样在本文件的开头部分进行定义)<br>　　　m_hMyAccel=CreateAcceleratorTable(accel,sizeof(accel)/sizeof(ACCEL));</p>
<p>　　3、如果是使用CreateAccelTable函数创建的，则重载虚拟函数DestoryWindow()。在该函数的&#8220;return CMDIFrameWnd::DestroyWindow();&#8221;前增加如下代码:</p>
<p>&nbsp;&nbsp;&nbsp; if(m_hMyAccel!=NULL){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DestroyAcceleratorTable(m_hMyAccel);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_hMyAccel=NULL;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>　　通过前面的三步，<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表已经能正确地被创建和删除了，但是它还没有工作。下面就是要让我们刚才所创建的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表工作起来。<br>　　在API程序设计中大家已经知道了<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>是如何工作的。也就是在消息还没有分发出去之前先检查是不是一个<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>。我们通过API函数TranslateAccelerator来实现。在MFC中，消息机制已经被封装了，我们不能去修改消息循环。但是，框架在分发消息前会调用虚拟函数PerTranslateMessage，并且如果该函数返回TRUE，则不再处理该消息。这正是我们所需要的。<br>　　让我们再回到CMainFrame类，生成PerTranslateMessage函数的覆盖版本。修改函数体如下：</p>
<p>BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) <br>{<br>&nbsp;&nbsp;&nbsp; // TODO: Add your specialized code here and/or call the base class<br>&nbsp;&nbsp;&nbsp; if(m_hMyAccel&amp;&amp;TranslateAccelerator(m_hWnd, m_hMyAccel, pMsg))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;<br>&nbsp;&nbsp;&nbsp; return CMDIFrameWnd::PreTranslateMessage(pMsg);<br>}</p>
<p>　　好了，现在我们的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>已经能正常地工作了。以上方法用在其它窗口同样有效（如对话框中，你不妨在对话框中试试）。</p>
<p><br>　　三、可在运行时编辑的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。</p>
<p>　　通过上面的叙述，你可能已经对可编辑的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表有了一定的轮廓。其实其实现思想很简单：只要对一个ACCEL数组进行修改，然后重新生成<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表就行了。<br>　　为了区分命令，我们为每个命令取一个名字。在CMainFrame类定义的前面加上下面的一个结构定义：</p>
<p>typedef struct{<br>&nbsp;&nbsp;&nbsp; char cCmd[32];<br>&nbsp;&nbsp;&nbsp; ACCEL accel;<br>}ACCELITEM,*LPACCELITEM;</p>
<p>　　我们将使用该结构来保存<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的数据。在CMainFrame类中添加两个保护成员变量：</p>
<p>&nbsp;&nbsp;&nbsp; LPACCELITEM m_lpAccel;<br>&nbsp;&nbsp;&nbsp; DWORD m_dwAccelCount;</p>
<p>　　在构造函数中将m_lpAccel初始化为NULL，m_dwAccelCount初始化为0。在数组accel的定义下面增加一个字符串数组的静态变量的定义（用来指定命令的名称,请仿照下面自己定义，个数多少不限，字符串长度不要超过31个字符）：</p>
<p>static char strCmd[][32]={<br>&nbsp;&nbsp;&nbsp; "Command One",<br>&nbsp;&nbsp;&nbsp; "Command Two",<br>&nbsp;&nbsp;&nbsp; "Command Three",<br>&nbsp;&nbsp;&nbsp; "Command Four",<br>&nbsp;&nbsp;&nbsp; "Command Five"<br>};</p>
<p><br>　　在CMainFrame类中添加一个保护成员函数LoadAccel(),该函数用来将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表装入，定义如下：</p>
<p>BOOL CMainFrame::LoadAccel()<br>{<br>&nbsp;&nbsp;&nbsp; ASSERT(m_hActAccel==NULL);<br>&nbsp;&nbsp;&nbsp; ASSERT(m_lpAccel==NULL);<br>&nbsp;&nbsp;&nbsp; m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);<br>&nbsp;&nbsp;&nbsp; m_lpAccel=new ACCELITEM[m_dwAccelCount];<br>&nbsp;&nbsp;&nbsp; memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);<br>&nbsp;&nbsp;&nbsp; DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[32]);<br>&nbsp;&nbsp;&nbsp; for(DWORD dw=0;dw&lt;m_dwAccelCount;dw++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_lpAccel[dw].accel=accel[dw];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(m_lpAccel[dw].cCmd,dw&lt;dwCmdStr?strCmd[dw]:"Command Unknow");<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);<br>&nbsp;&nbsp;&nbsp; return TRUE;</p>
<p>}</p>
<p>　　删除OnCreate函数中原来创建<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的代码，改成对LoadAccel()的调用：</p>
<p>&nbsp;&nbsp;&nbsp; LoadAccel();</p>
<p>　　在CMainFrame的析构函数中增加以下内容：</p>
<p>&nbsp;&nbsp;&nbsp; if(m_lpAccel)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete[] m_lpAccel;</p>
<p>　　为了能够对<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>数据进行编辑，我们在工程中添加一个对话框资源，ID为&#8220;IDD_ACCELEDIT&#8221;，在对话框上放置三个成组框（Group Box），左边一个标题为&#8220;命令&#8221;；中间一个标题为&#8220;组合键&#8221;；右边一个标题为&#8220;虚键值&#8221;。在左边成组框中放置一个列表框（List Box），ID为&#8220;IDC_LST_CMD&#8221;。在中间成组框中放置三个核选框（Check Box），上下排列。上面的核选框的ID为&#8220;IDC_CHK_ALT&#8221;，标题为&#8220;Alt&#8221;，并勾选&#8220;Group&#8221;属性；中间的核选框的ID为&#8220;IDC_CHK_SHIFT&#8221;，标题为&#8220;Shift&#8221;，取消&#8220;Group&#8221;属性；下面的核选框的ID为&#8220;IDC_CHK_CTRL&#8221;，标题为&#8220;Ctrl&#8221;，取消&#8220;Group&#8221;属性。在右边的成组框中放置一个列表框，ID为&#8220;IDC_LST_KEY&#8221;。调整各个控件的尺寸及位置至合适。设置控件的TAB跳转顺序，从左至右、从上到下。依次为：左成组框、IDC_LST_CMD列表框、中成组框、IDC_CHK_ALT核选框、IDC_CHK_SHIFT核选框、IDC_CHK_CTRL核选框、右成组框、IDC_LST_KEY列表框、OK按钮、CANCEL按钮。<br>　　打开类向导，为对话框新建一个类，类名为&#8220;CDlgEditAccel&#8221;。为两个列表框和三个核选框映射变量，如下：<br>　　控件ID:ID_LST_CMD；类型:Control/CListBox；名称:m_LstCmd；<br>　　控件ID:ID_LST_KEY；类型:Control/CListBox；名称:m_LstKey；<br>　　控件ID:ID_CHK_ALT；类型:Control/CButton；名称:m_ChkAlt；<br>　　控件ID:ID_CHK_SHIFT；类型:Control/CButton；名称:m_ChkShift；<br>　　控件ID:ID_CHK_CTRL；类型:Control/CButton；名称:m_ChkCtrl；</p>
<p>　　在类CDlgEditAccel的定义前加入下面的定义：<br>typedef struct tag_KeyName{<br>&nbsp;&nbsp;&nbsp; CString m_strName;<br>&nbsp;&nbsp;&nbsp; WORD m_wID;<br>&nbsp;&nbsp;&nbsp; tag_KeyName(CString str,WORD id){m_strName=str,m_wID=id;}<br>}KEYNAME,*LPKEYNAME;</p>
<p>typedef struct tag_ActAccel{<br>&nbsp;&nbsp;&nbsp; CString m_strCmd;<br>&nbsp;&nbsp;&nbsp; ACCEL m_Accel;<br>}ACTACCEL,*LPACTACCEL;</p>
<p>class CActAccelList<br>{<br>public:<br>&nbsp;&nbsp;&nbsp; CActAccelList();<br>&nbsp;&nbsp;&nbsp; ~CActAccelList();</p>
<p>protected:<br>&nbsp;&nbsp;&nbsp; LPACTACCEL m_lpActAccel;<br>&nbsp;&nbsp;&nbsp; int m_iCount;</p>
<p>public:<br>&nbsp;&nbsp;&nbsp; ACTACCEL&amp; operator[](int index);<br>&nbsp;&nbsp;&nbsp; BOOL SetSize(int iSize);<br>&nbsp;&nbsp;&nbsp; int GetSize();<br>};</p>
<p><br>　　在文件DlgEditAccel.cpp文件中定义类CActAccelList的成员函数，代码如下：<br>CActAccelList::CActAccelList()<br>{<br>&nbsp;&nbsp;&nbsp; m_lpActAccel=NULL;<br>&nbsp;&nbsp; m_iCount=0;<br>}</p>
<p>CActAccelList::~CActAccelList()<br>{<br>&nbsp;&nbsp;&nbsp; if(m_iCount&gt;0&amp;&amp;m_lpActAccel)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete[] m_lpActAccel;<br>}</p>
<p>int CActAccelList::GetSize()<br>{<br>&nbsp;&nbsp;&nbsp; return m_iCount;<br>}</p>
<p>ACTACCEL&amp; CActAccelList::operator []( int index)<br>{<br>&nbsp;&nbsp;&nbsp; if(!(index&gt;=0&amp;&amp;index&lt;m_iCount))<br>&nbsp;&nbsp;&nbsp; AfxThrowMemoryException();<br>&nbsp;&nbsp;&nbsp; return m_lpActAccel[index];<br>}</p>
<p>BOOL CActAccelList::SetSize(int iSize)<br>{<br>&nbsp;&nbsp;&nbsp; if(iSize&lt;0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; if(m_iCount&gt;0&amp;&amp;m_lpActAccel)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete[] m_lpActAccel;<br>&nbsp;&nbsp;&nbsp; m_iCount=0;<br>&nbsp;&nbsp;&nbsp; m_lpActAccel=new ACTACCEL[iSize];<br>&nbsp;&nbsp;&nbsp; if(m_lpActAccel==NULL)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; m_iCount=iSize;<br>&nbsp;&nbsp;&nbsp; return TRUE;<br>}</p>
<p><br>　　在DlgAccelEdit.cpp文件头部定义全局变量－－数组key：<br>static KEYNAME key[]={<br>&nbsp;&nbsp;&nbsp; KEYNAME("Left mouse button",VK_LBUTTON),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Right mouse button",VK_RBUTTON),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Control-break processing",VK_CANCEL),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Middle mouse button",VK_MBUTTON),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Back Space",VK_BACK),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Tab",VK_TAB),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Clear",VK_CLEAR),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Enter",VK_RETURN),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Shift",VK_SHIFT),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Ctrl",VK_CONTROL),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Alt",VK_MENU),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Pause",VK_PAUSE),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Caps Lock",VK_CAPITAL),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Esc",VK_ESCAPE),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Space",VK_SPACE),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Page Up",VK_PRIOR),&nbsp; <br>&nbsp;&nbsp;&nbsp; KEYNAME("Page Down",VK_NEXT),<br>&nbsp;&nbsp;&nbsp; KEYNAME("End",VK_END),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Home",VK_HOME),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Left",VK_LEFT),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Up",VK_UP),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Right",VK_RIGHT),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Down",VK_DOWN),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Select",VK_SELECT),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Excute",VK_EXECUTE),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Print Screen",VK_SNAPSHOT),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Insert",VK_INSERT),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Delete",VK_DELETE),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Help",VK_HELP),<br>&nbsp;&nbsp;&nbsp; KEYNAME("0",'0'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("1",'1'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("2",'2'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("3",'3'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("4",'4'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("5",'5'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("6",'6'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("7",'7'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("8",'8'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("9",'9'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("A",'A'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("B",'B'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("C",'C'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("D",'D'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("E",'E'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F",'F'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("G",'G'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("H",'H'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("I",'I'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("J",'J'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("K",'K'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("L",'L'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("M",'M'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("N",'N'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("O",'O'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("P",'P'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Q",'Q'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("R",'R'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("S",'S'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("T",'T'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("U",'U'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("V",'V'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("W",'W'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("X",'X'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Y",'Y'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Z",'Z'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Left windows",VK_LWIN),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Right windows",VK_RWIN),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Applications",VK_APPS),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 0",&nbsp;VK_NUMPAD0),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 1",&nbsp;VK_NUMPAD1),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 2",&nbsp;VK_NUMPAD2),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 3",&nbsp;VK_NUMPAD3),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 4",&nbsp;VK_NUMPAD4),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 5",&nbsp;VK_NUMPAD5),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 6",&nbsp;VK_NUMPAD6),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 7",&nbsp;VK_NUMPAD7),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 8",&nbsp;VK_NUMPAD8),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Numeric keypad 9",&nbsp;VK_NUMPAD9), <br>&nbsp;&nbsp;&nbsp; KEYNAME("Multiply",VK_MULTIPLY),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Add",VK_ADD),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Separator",VK_SEPARATOR),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Subtract",VK_SUBTRACT),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Decimal Point",VK_DECIMAL),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Divide",VK_DIVIDE),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F1",VK_F1),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F2",VK_F2),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F3",VK_F3),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F4",VK_F4),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F5",VK_F5),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F6",VK_F6),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F7",VK_F7),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F8",VK_F8),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F9",VK_F9),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F10",VK_F10),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F11",VK_F11),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F12",VK_F12),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F13",VK_F13),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F14",VK_F14),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F15",VK_F15),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F16",VK_F16),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F17",VK_F17),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F18",VK_F18),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F19",VK_F19),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F20",VK_F20),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F21",VK_F21),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F22",VK_F22),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F23",VK_F23),<br>&nbsp;&nbsp;&nbsp; KEYNAME("F24",VK_F24),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Attn",VK_ATTN),<br>&nbsp;&nbsp;&nbsp; KEYNAME("CrSel",VK_CRSEL),<br>&nbsp;&nbsp;&nbsp; KEYNAME("ExSel",VK_EXSEL),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Erase",VK_EREOF),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Play",VK_PLAY),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Zoom",VK_ZOOM),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Reserved for future use",VK_NONAME ),<br>&nbsp;&nbsp;&nbsp; KEYNAME("PA1",VK_PA1),<br>&nbsp;&nbsp;&nbsp; KEYNAME("Clear(OEM)",VK_OEM_CLEAR ),</p>
<p>&nbsp;&nbsp;&nbsp; KEYNAME("<a href="file://%22,'//'"><u><font color=#0000ff>file://",'//'</font></u></a>),<br>&nbsp;&nbsp;&nbsp; KEYNAME("-",'-'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("=",'='),<br>&nbsp;&nbsp;&nbsp; KEYNAME("[",'['),<br>&nbsp;&nbsp;&nbsp; KEYNAME("]",']'),<br>&nbsp;&nbsp;&nbsp; KEYNAME(";",';'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("\'",'\''),<br>&nbsp;&nbsp;&nbsp; KEYNAME(",",','),<br>&nbsp;&nbsp;&nbsp; KEYNAME(".",'.'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("/",'/'),<br>&nbsp;&nbsp;&nbsp; KEYNAME("`",'`')<br>};</p>
<p><br>　　在类CDlgAccelEdit中响应Windows消息：WM_INITDIALOD，代码如下：<br>BOOL CDlgEditAccel::OnInitDialog() <br>{<br>&nbsp;&nbsp;&nbsp; CDialog::OnInitDialog();</p>
<p>&nbsp;&nbsp;&nbsp; // TODO: Add extra initialization here<br>&nbsp;&nbsp;&nbsp; SetWindowText("Edit Accelerator Table");</p>
<p>&nbsp;&nbsp;&nbsp; int iCount=m_AccelList.GetSize();<br>&nbsp;&nbsp;&nbsp; int i;<br>&nbsp;&nbsp;&nbsp; for(i=0;i&lt;iCount;i++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_LstCmd.AddString(m_AccelList[i].m_strCmd);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; for(i=0;i&lt;sizeof(key)/sizeof(KEYNAME);i++)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_LstKey.AddString(key[i].m_strName);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; m_LstCmd.SetCurSel(0);<br>&nbsp;&nbsp;&nbsp; OnSelchangeLstCmd();<br>&nbsp;&nbsp;&nbsp; return TRUE;&nbsp; // return TRUE unless you set the focus to a control<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // EXCEPTION: OCX Property Pages should return FALSE<br>}</p>
<p><br>　　为类CDglAccelEdit增加一个保护成员函数：<br>&nbsp;&nbsp;&nbsp; void SaveChange(int index=-1);</p>
<p>　　在文件DlgAccelEdit中定义该函数，代码如下：</p>
<p>void CDlgEditAccel::SaveChange(int index)<br>{<br>&nbsp;&nbsp;&nbsp; if(index&gt;=0||(index=m_LstCmd.GetCurSel())&gt;=0)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(m_LstKey.GetCurSel()&lt;0){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox("你必需选择一个键码!");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BYTE btCmp=((m_ChkAlt.GetCheck()==1)?FALT:NULL)|<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((m_ChkCtrl.GetCheck()==1)?FCONTROL:NULL)|<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((m_ChkShift.GetCheck()==1)?FSHIFT:NULL)|FVIRTKEY;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WORD wKey=key[m_LstKey.GetCurSel()].m_wID;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_AccelList[index].m_Accel.fVirt=btCmp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_AccelList[index].m_Accel.key=wKey;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>　　响应列表框ID_LST_CMD的通知消息&#8220;LBN_SELCHANGE&#8221;，函数代码如下：<br>void CDlgEditAccel::OnSelchangeLstCmd() <br>{<br>&nbsp;&nbsp;&nbsp; // TODO: Add your control notification handler code here<br>&nbsp;&nbsp;&nbsp; int iCmd=m_LstCmd.GetCurSel();<br>&nbsp;&nbsp;&nbsp; WORD wKey=m_AccelList[iCmd].m_Accel.key;<br>&nbsp;&nbsp;&nbsp; BYTE btCmp=m_AccelList[iCmd].m_Accel.fVirt;<br>&nbsp;&nbsp;&nbsp; m_ChkAlt.SetCheck(btCmp&amp;FALT);<br>&nbsp;&nbsp;&nbsp; m_ChkCtrl.SetCheck(btCmp&amp;FCONTROL);<br>&nbsp;&nbsp;&nbsp; m_ChkShift.SetCheck(btCmp&amp;FSHIFT);<br>&nbsp;&nbsp;&nbsp; int iCount=sizeof(key)/sizeof(KEYNAME);<br>&nbsp;&nbsp;&nbsp; int id=-1;<br>&nbsp;&nbsp;&nbsp; for(int i=0;i&lt;iCount;i++)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(key[i].m_wID==wKey){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id=i;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; m_LstKey.SetCurSel(id);</p>
<p>}</p>
<p>　　响应列表框ID_LST_KEY的通知消息&#8220;LBN_SELCHANGE&#8221;，函数代码如下：<br>void CDlgEditAccel::OnSelchangeLstKey() <br>{<br>&nbsp;&nbsp;&nbsp; SaveChange();&nbsp;<br>}</p>
<p>　　响应核选框ID_CHK_ALT的通知消息&#8220;BN_CLICKED&#8221;，函数代码如下：<br>void CDlgEditAccel::OnChkAlt() <br>{<br>&nbsp;&nbsp;&nbsp; SaveChange();<br>}</p>
<p>　　响应核选框ID_CHK_SHIFT的通知消息&#8220;BN_CLICKED&#8221;，函数代码如下：<br>void CDlgEditAccel::OnChkShift() <br>{<br>&nbsp;&nbsp;&nbsp; SaveChange();<br>}</p>
<p>　　响应核选框ID_CHK_CTRL的通知消息&#8220;BN_CLICKED&#8221;，函数代码如下：<br>void CDlgEditAccel::OnChkCtrl() <br>{<br>&nbsp;&nbsp;&nbsp; SaveChange();<br>}</p>
<p>　　至此，用于编辑<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的对话框已经完成。我们现在要做的就是在程序中打开对话框来编辑了。让我们回到CMainFrame类中。我们将在该类中响应一个命令来打开编辑对话框，对<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行编辑。完成后点按OK回到主程序中，然后更新<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。这样后，我们刚刚编辑好的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表就开始起作用了。<br>　　首先，打开菜单。在&#8220;查看&#8221;项后增加一个&#8220;工具(&amp;T)&#8221;下拉菜单，在下拉菜单中增加一个了菜单：&#8220;编辑<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表(&amp;A)...&#8221;，ID为&#8220;ID_TOOL_ACCELEDIT&#8221;。打开类向导，选择CMainFrame类，响应&#8220;ID_TOOL_ACCELEDIT&#8221;命令。编辑响应函数如下：</p>
<p>void CMainFrame::OnToolAcceledit() <br>{<br>&nbsp;&nbsp;&nbsp; // TODO: Add your command handler code here<br>&nbsp;&nbsp;&nbsp; CDlgEditAccel dlg;</p>
<p>&nbsp;&nbsp;&nbsp; DWORD i;<br>&nbsp;&nbsp;&nbsp; dlg.m_AccelList.SetSize(m_dwAccelCount);<br>&nbsp;&nbsp;&nbsp; for(i=0;i&lt;m_dwAccelCount;i++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dlg.m_AccelList[i].m_strCmd=m_lpAccel[i].cCmd;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dlg.m_AccelList[i].m_Accel=m_lpAccel[i].accel;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; if(IDOK==dlg.DoModal()){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACCEL* pAccel=new ACCEL[m_dwAccelCount];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(DWORD dw=0;dw&lt;m_dwAccelCount;dw++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_lpAccel[dw].accel=pAccel[dw]=dlg.m_AccelList[dw].m_Accel;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(m_hActAccel!=NULL)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DestroyAcceleratorTable(m_hActAccel);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_hActAccel=CreateAcceleratorTable(pAccel,m_dwAccelCount);<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>　　在该文件的头部包含类CDlgEditAccel的头文件：</p>
<p>#include "DlgEditAccel.h"</p>
<p>　　至此，可编辑的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表已经完成了。不妨试试看。</p>
<p>　　三、将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存至文件，并在程序运行时自动从文件中加载。</p>
<p>　　上面我们实现了可编辑的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。但是，当程序退出后，我们编辑过的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>数据就消失了，下次运行程序时还是和以前一样了。将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存起来以备下次使用，这是我们所希望的。下面讨论的方法是使用文件来保存我们的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。<br>　　首先，在MainFrm.cpp文件的头部定义一个全局字符串，也就是用于保存<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的文件名：</p>
<p>static char strAccelFileName[]="Accel.cus";</p>
<p>　　定义一个DWORD值作为文件头，我们通过该DWORD值来判断是否是一个有效格式的文件：</p>
<p>#define ACCEL_FILE_HEAD&nbsp;0x00434341</p>
<p><br>　　其次，为CMainFrame类添加一个保护的成员函数：&#8220;BOOL SaveAccel()&#8221;，编辑其代码如下：<br>BOOL CMainFrame::SaveAccel()<br>{<br>&nbsp;&nbsp;&nbsp; char lpAppName[256];<br>&nbsp;&nbsp;&nbsp; char lpAppPath[256];<br>&nbsp;&nbsp;&nbsp; char* lpFilePart=NULL;<br>&nbsp;&nbsp;&nbsp; GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);<br>&nbsp;&nbsp;&nbsp; GetFullPathName(lpAppName,255,lpAppPath,&amp;lpFilePart);<br>&nbsp;&nbsp;&nbsp; TRACE1("Application File Name:%s.\n",lpAppName);<br>&nbsp;&nbsp;&nbsp; strcpy(lpFilePart,strAccelFileName);<br>&nbsp;&nbsp;&nbsp; TRACE1("Accelerator File Name:%s.\n",lpAppPath);<br>&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwHead=ACCEL_FILE_HEAD;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwCount=m_dwAccelCount;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CFile fAccel(lpAppPath,CFile::modeCreate|CFile::modeWrite);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fAccel.SeekToBegin();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fAccel.Write(&amp;dwHead,sizeof(DWORD));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fAccel.Write(&amp;dwCount,sizeof(DWORD));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(DWORD dw=0;dw&lt;dwCount;dw++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fAccel.Write(m_lpAccel+dw,sizeof(ACCELITEM));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; catch(CFileException* e)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char buf[256];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char buf2[512];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int iError;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iError=e-&gt;m_cause;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e-&gt;GetErrorMessage(buf,256);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf2,"将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存到文件 \"%s\" 中时发生错误!\n"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "错 误 号:%d\n"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "错误描述:%s\n"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "\0",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strAccelFileName,iError,buf);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox(buf2,MB_OK|MB_ICONSTOP|MB_DEFBUTTON1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>　　再次，修改LoadAccel()函数如下：</p>
<p>BOOL CMainFrame::LoadAccel()<br>{<br>&nbsp;&nbsp;&nbsp; char lpAppName[256];<br>&nbsp;&nbsp;&nbsp; char lpAppPath[256];<br>&nbsp;&nbsp;&nbsp; char* lpFilePart=NULL;<br>&nbsp;&nbsp;&nbsp; GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);<br>&nbsp;&nbsp;&nbsp; GetFullPathName(lpAppName,255,lpAppPath,&amp;lpFilePart);<br>&nbsp;&nbsp;&nbsp; TRACE1("Application File Name:%s.\n",lpAppName);<br>&nbsp;&nbsp;&nbsp; strcpy(lpFilePart,strAccelFileName);<br>&nbsp;&nbsp;&nbsp; TRACE1("Accelerator File Name:%s.\n",lpAppPath);<br>&nbsp;&nbsp;&nbsp; try<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwHead;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwCount;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CFile fAccel(lpAppPath,CFile::modeRead);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fAccel.SeekToBegin();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(fAccel.Read(&amp;dwHead,sizeof(DWORD))!=sizeof(DWORD))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(dwHead!=ACCEL_FILE_HEAD)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxThrowFileException(CFileException::invalidFile,13,lpAppPath);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(fAccel.Read(&amp;dwCount,sizeof(DWORD))!=sizeof(DWORD))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ASSERT(m_lpAccel==NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_lpAccel=new ACCELITEM[dwCount];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(m_lpAccel,0,sizeof(ACCELITEM)*dwCount);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_dwAccelCount=dwCount;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(DWORD dw=0;dw&lt;dwCount;dw++)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(fAccel.Read(m_lpAccel+dw,sizeof(ACCELITEM))!=sizeof(ACCELITEM))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACCEL* pAccel=new ACCEL[dwCount];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(dw=0;dw&lt;dwCount;dw++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pAccel[dw]=m_lpAccel[dw].accel;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_hActAccel=CreateAcceleratorTable(pAccel,dwCount);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;</p>
<p>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; catch(CFileException* e)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char buf[256];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char buf2[512];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int iError;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iError=e-&gt;m_cause;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e-&gt;GetErrorMessage(buf,256);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf2,"从文件 \"%s\" 中加载<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表时发生错误!\n"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "错 误 号:%d\n"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "错误描述:%s\n"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "是否生成默认的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表?\n\0",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strAccelFileName,iError,buf);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(IDYES==AfxMessageBox(buf2,MB_YESNO|MB_SYSTEMMODAL|MB_ICONSTOP|MB_DEFBUTTON1))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ASSERT(m_hActAccel==NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ASSERT(m_lpAccel==NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_lpAccel=new ACCELITEM[m_dwAccelCount];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[30]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(DWORD dw=0;dw&lt;m_dwAccelCount;dw++){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_lpAccel[dw].accel=accel[dw];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(m_lpAccel[dw].cCmd,dw&lt;dwCmdStr?strCmd[dw]:"Command Unknow");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SaveAccel();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>　　最后，在DestroyWindow()函数头部增加对SaveAccel()函数的调用：</p>
<p>&nbsp;&nbsp;&nbsp; SaveAccel();<br>&nbsp;&nbsp;&nbsp; ...</p>
<p>　　好了，你自己的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>数据已经能保存在文件中了，并能从中正确加载。如果文件不存在或程序读取时发现错误则提醒你是否建立缺省的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表，如你确认的话则生成缺省的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表并立刻保存至文件中。<br>　　由于水平有限，其中难免有误，欢迎批评指正、发表你的意见。本人不胜感激。<br></p>
<img src ="http://www.cppblog.com/tgh621/aggbug/71821.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2009-01-12 17:22 <a href="http://www.cppblog.com/tgh621/archive/2009/01/12/71821.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为什么 char** 不能自动转化为 const char** (转) </title><link>http://www.cppblog.com/tgh621/archive/2008/11/11/66588.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Tue, 11 Nov 2008 03:23:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/11/11/66588.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/66588.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/11/11/66588.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/66588.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/66588.html</trackback:ping><description><![CDATA[<div class=postText>
<p>一次偶然的情况下我发现以下代码竟然无法被编译通过（如果你的编译器，比如VC6或VC2003，允许它编译通过，我想你首先应该换个编译器，比如GCC或VC2005）：<br><font color=#0000ff>void foo( <strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* [] ) { }<br>int main( void )<br>{<br>&nbsp;&nbsp;&nbsp; <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* s[2];<br>&nbsp;&nbsp;&nbsp; foo( s );<br>}</font><br>简化成更一般的形式是：<br><font color=#0000ff><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** p1 = 0;<br><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** p2 = p1;</font><br>错误是：<font color=#a52a2a>invalid conversion from `<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>**' to `<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>**'</font>.</p>
<p><a href="http://blog.vckbase.com/lostpencil" target=_blank><u><font color=#0066cc>lostpencil</font></u></a>更加仔细，使用C编译器给出的是一个警告：<br><font color=#a52a2a>initialization from incompatible pointer type</font>.</p>
<p>随后<a href="http://www.vckbase.com/bbs/userinfo.asp?id=hpho" target=_blank><u><font color=#0066cc>hpho</font></u></a>给出了合理的解释，同时<a href="http://groups.google.com/group/comp.lang.c++.moderated" target=_blank><u><font color=#0066cc>comp.lang.c++.moderated</font></u></a>上的<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#101;&#99;&#107;&#104;&#97;&#114;&#100;&#116;&#64;&#115;&#97;&#116;&#111;&#114;&#108;&#97;&#115;&#101;&#114;&#46;&#99;&#111;&#109;"><u><font color=#0066cc>Ulrich Eckhardt</font></u></a>也用代码进行了说明。</p>
<p>用代码来说明最直观了：<br><font color=#0000ff><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* s = "abc";<br>int main( void )<br>{<br>&nbsp;&nbsp;&nbsp; <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* p0 = 0;<br>&nbsp;&nbsp;&nbsp; <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** p1 = &amp;p0;<br>&nbsp;&nbsp;&nbsp; <strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** p2 = p1;</font> // 先假设这一句是合法的 ( 测试时，可以先强制类型<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">转</strong>化一下 )<br><font color=#0000ff>&nbsp;&nbsp;&nbsp; *p2 = s;<br>&nbsp;&nbsp;&nbsp; *p0 = 'A';</font> // 通过p0在修改不应该被修改的s，这显然和<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong>相违背，其运行结果不可知。<br><font color=#0000ff>}<br><br><br><br><br></font></p>
</div>
<p><font color=#0000ff>看了 **的 想到的<br>tekyDec 29, 2005 -&nbsp; Show original item </font></p>
<p><font color=#0000ff>看完后.明白**讲的为什么<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>** 不能自动<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">转</strong>化为 <strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>**,(原文)但对我影响最深的是下面的话:</font></p>
<p><font color=#0000ff>==================================================================<br><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p="abc" 能不能编译通过要看你使用的编译器。鉴于大量遗留代码的存在，大部分编译器允许其通过，或者给个警告。当然，程序员自己必须保证绝不去修改其值。 </font></p>
<p><font color=#0000ff>程序员不应该在代码中出现*p='A'这样的语句。这是当初约定好了的：编译器允许<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p="abc"通过，而程序员保证不去修改它。 <br>b. *p='A'编译时应该允许通过，因为单就这条语句而言，它完全合法。 <br>c. 运行时*p='A'能不能通过要看实际的运行环境，包括你使用的操作系统、编译器、编译器选项 等等，一句话，其运行结果由不得你，且不应该由你去关心，因为这种行为本身已经违反约定了。 <br>==================================================================</font></p>
<p><font color=#0000ff>工作关系吧,用CString 和string用的太多了,很少这样定义字符串 <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p=&#8220;abcde&#8220;了<br>匝一看,还不适应,:(,渐渐的回想才想起一些来(哎,还是太生疏,赶快写下来,以后别忘了)</font></p>
<p><font color=#0000ff>这样定义的字符串<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p=&#8220;abcde&#8220; ; <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p1=&#8220;123445667&#8220;;</font></p>
<p><font color=#0000ff>正如上面提到的是不能再 *p='A',运行的时候会出错,同样,strcpy(p,p1)也会出错哟,</font></p>
<p><font color=#0000ff>"abcde"字符串可以看做是个常量字符串了,是不能被修改的,</font></p>
<p><font color=#0000ff>但如果 <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> p[]=&#8220;abcde&#8220; 这样定义,就没有问题,你可以修改*p='A',只要不越界就ok.</font></p>
<p><font color=#0000ff>并且发现这样两种定义<br><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p=&#8220;abcde&#8220;</font></p>
<p><font color=#0000ff><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> p[]=&#8220;abcde&#8220; </font></p>
<p><font color=#0000ff>在运行的时候,p指向的地址也不是一样的,可见<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p=&#8220;abcde&#8220;还是有特殊的处理 :),具体怎么处理就不知道了,高手请指教:)</font></p>
<font color=#0000ff></font>
<p><font color=#0000ff><br>随着测试,又发现个问题,可能是个老问题了吧:</font></p>
<p><font color=#0000ff><br>int main(int argc, <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong>* argv[])<br>{ <br>&nbsp;int t[10];<br>&nbsp;<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> p1[7]="123456";<br>&nbsp;<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const</strong> <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char</strong> *p2="1234567890123213123";<br>&nbsp;<br>&nbsp;int len(0);<br>&nbsp;<br>&nbsp; //*p1='C';&nbsp; err</font></p>
<p><font color=#0000ff>&nbsp;len=strlen(p1);<br>&nbsp;printf("%d\n",len);<br>&nbsp;<br>&nbsp;strcpy(p1,p2);&nbsp;&nbsp; ///??????????<br>&nbsp;<br>&nbsp;printf("%s\n",p1);<br>&nbsp;<br>&nbsp;len=strlen(p1);<br>&nbsp;<br>&nbsp;printf("%d\n",len);<br>&nbsp;return 0;<br>}</font></p>
<p><font color=#0000ff>我定义的是7个字符数组, 但用strcpy把p2拷到p1中,p1是放不下的,但程序却正常执行,warning ,err都没有,运行也正常?</font></p>
<p><font color=#0000ff><br>输出 </font></p>
<p><font color=#0000ff>6<br>1234567890123213123<br>19</font></p>
<p><font color=#0000ff>应该是使用内存越界了阿??怎么会正常运行呢?</font></p>
<p><font color=#0000ff>难道对于内存越界的使用,运气好才崩溃表现出来,运气不好就正常运行??</font></p>
<p class=postfoot>posted on 2006-02-22 13:04 <a href="http://www.blogjava.net/Vencent/"><u><font color=#0066cc>Vincent.Chen</font></u></a> 阅读(232) <a href="http://cache.baidu.com/c?m=9d78d513d9921cf319ab837e7c478d35594380122ba1d5020ca7870fd33a541b0120a1ac26510d199680397001d81902b7a56e21735037b7ec94df0cc0ffc5747edf7b726d4fc607498247f88a5b24c22b965dfeaf6ebdfcaf6c&amp;p=90769a4086cc41ae1fb2c528510c&amp;user=b#Post"><u><font color=#0066cc>评论(0)</font></u></a> &nbsp;<a href="http://www.blogjava.net/Vencent/admin/EditArticles.aspx?postid=31945"><u><font color=#0066cc>编辑</font></u></a> &nbsp;<a href="http://www.blogjava.net/Vencent/AddToFavorite.aspx?id=31945"><u><font color=#0066cc>收藏</font></u></a> 所属分类: <a href="http://www.blogjava.net/Vencent/category/5790.html"><u><font color=#0066cc>杂</font></u></a></p>
<img src ="http://www.cppblog.com/tgh621/aggbug/66588.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-11-11 11:23 <a href="http://www.cppblog.com/tgh621/archive/2008/11/11/66588.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】向任意进程注入DLL</title><link>http://www.cppblog.com/tgh621/archive/2008/09/28/62974.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Sun, 28 Sep 2008 04:24:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/09/28/62974.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/62974.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/09/28/62974.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/62974.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/62974.html</trackback:ping><description><![CDATA[<p>可能这对高手来说已经是老掉牙的东西了,</p>
<p>还是来说说原理把(本人也是菜鸟啊)!<br>远程注入就是在目标进程中用VirtualAllocEx申请一段内存,<br>然后用WriteProcessMemory函数将自己dll的完整路径复制到远程进程中,<br>然后在Kernel32中计算LoadLibraryA的地址,再调用LoadLibraryA函数加载远程dll,<br>并在CreateRemoteThread创建远程进程! <br>Code Language : C<br>#include \"stdafx.h\"<br>#include \"windows.h\"<br>#include \"tlhelp32.h\"<br>#include \"stdio.h\"<br>#pragma comment(lib,\"ws2_32\")<br>&nbsp;<br>int EnableDebugPriv(const char * name)//提提权函数<br>{<br>&nbsp; HANDLE hToken;<br>&nbsp; TOKEN_PRIVILEGES tp;<br>&nbsp; LUID luid;<br>&nbsp; //打开进程令牌环<br>&nbsp; if(!OpenProcessToken(GetCurrentProcess(),<br>&nbsp; TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,<br>&nbsp;&nbsp;&nbsp; &amp;hToken))<br>&nbsp; {<br>&nbsp;&nbsp;&nbsp; MessageBox(NULL,\"OpenProcessToken Error!\",\"Error!\",MB_OK);<br>&nbsp;&nbsp;&nbsp;&nbsp; return 1;<br>&nbsp;}<br>&nbsp;//获得进程本地唯一ID<br>&nbsp;if(!LookupPrivilegeValue(NULL,name,&amp;luid))<br>&nbsp;{<br>&nbsp;&nbsp; MessageBox(NULL,\"LookupPrivivlegeValue Error!\",\"Error\",MB_OK);<br>&nbsp;}<br>&nbsp;tp.PrivilegeCount=1;<br>&nbsp;tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;<br>&nbsp;tp.Privileges[0].Luid=luid;<br>&nbsp;//调整权限<br>&nbsp;if(!AdjustTokenPrivileges(hToken,0,&amp;tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))<br>&nbsp;{<br>&nbsp;&nbsp; MessageBox(NULL,\"AdjustTokenPrivileges Error!\",\"Error\",MB_OK);<br>&nbsp;&nbsp; return 1;<br>&nbsp;}<br>&nbsp;return 0;<br>}<br>BOOL injectit(const char *DllPath,const DWORD dwRemoteProcessld)//注入主函数<br>{<br>&nbsp;HANDLE hrp;<br>&nbsp;if(EnableDebugPriv(SE_DEBUG_NAME))<br>&nbsp;{<br>&nbsp;&nbsp; MessageBox(NULL,\"Add Privilege Error!\",\"Error\",MB_OK);<br>&nbsp;&nbsp; return FALSE;<br>&nbsp;}<br>&nbsp;if((hrp=OpenProcess(PROCESS_CREATE_THREAD|//允许远程创建线程<br>&nbsp;&nbsp; PROCESS_VM_OPERATION|//允许远程VM操作<br>&nbsp;&nbsp; PROCESS_VM_WRITE,//允许远程VM写<br>&nbsp;&nbsp; FALSE,dwRemoteProcessld))==NULL)<br>&nbsp;{<br>&nbsp;&nbsp; MessageBox(NULL,\"OpenProcess Error!\",\"Error\",MB_OK);<br>&nbsp;&nbsp; return FALSE;<br>&nbsp;}<br>&nbsp;char *psLibFileRemote;<br>&nbsp;//使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲<br>&nbsp;psLibFileRemote=(char *)VirtualAllocEx(hrp,NULL,lstrlen(DllPath)+1,<br>&nbsp;&nbsp; MEM_COMMIT,PAGE_READWRITE);<br>&nbsp;if(psLibFileRemote==NULL)<br>&nbsp;{<br>&nbsp;&nbsp; MessageBox(NULL,\"VirtualAllocEx Error!\",\"Error\",MB_OK);<br>&nbsp;&nbsp; return FALSE;<br>&nbsp;}<br>&nbsp;//使用WriteProcessMemory函数将DLL的路径名复制到远程的内存空间<br>&nbsp;if(WriteProcessMemory(hrp,psLibFileRemote,(void *)DllPath,lstrlen(DllPath)+1,NULL)==0)<br>&nbsp;{<br>&nbsp;&nbsp; MessageBox(NULL,\"WriteProcessMemory Error!\",\"Error\",MB_OK);<br>&nbsp;&nbsp; return FALSE;<br>&nbsp;}<br>&nbsp;//计算LoadLibraryA的入口地址<br>&nbsp;PTHREAD_START_ROUTINE pfnStartAddr=(PTHREAD_START_ROUTINE)<br>&nbsp;&nbsp; GetProcAddress(GetModuleHandle(TEXT(\"Kernel32\")),\"LoadLibraryA\");<br>&nbsp;if(pfnStartAddr==NULL)<br>&nbsp;{<br>&nbsp;&nbsp; MessageBox(NULL,\"GetProcAddress Error!\",\"Error\",MB_OK);<br>&nbsp;&nbsp; return FALSE;<br>&nbsp;}<br>&nbsp;//pfnStartAddr地址就是LoadLibraryA的入口地址<br>&nbsp;<br>&nbsp;<br>&nbsp;HANDLE hrt;<br>&nbsp;if((hrt=CreateRemoteThread(hrp,<br>&nbsp;&nbsp; NULL,<br>&nbsp;&nbsp; 0,<br>&nbsp;&nbsp; pfnStartAddr,<br>&nbsp;&nbsp; psLibFileRemote,<br>&nbsp;&nbsp; 0,<br>&nbsp;&nbsp; NULL))==NULL)<br>&nbsp;{<br>&nbsp;&nbsp; MessageBox(NULL,\"CreateRemote Error!\",\"Error\",MB_OK);<br>&nbsp;&nbsp; return FALSE;<br>&nbsp;}<br>&nbsp;return TRUE;<br>}<br>unsigned long getpid(char *pn)//得到进程pid<br>{<br>&nbsp;BOOL b;<br>&nbsp;HANDLE hnd;<br>&nbsp;PROCESSENTRY32 pe;<br>&nbsp;//得到进程快照<br>&nbsp;hnd=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);<br>&nbsp;pe.dwSize=sizeof(pe);<br>&nbsp;b=Process32First(hnd,&amp;pe);<br>&nbsp;while(b)<br>&nbsp;{<br>&nbsp;&nbsp; if(strcmp(pn,pe.szExeFile)==0)<br>&nbsp;&nbsp;&nbsp;&nbsp; return pe.th32ProcessID;<br>&nbsp;&nbsp; b=Process32Next(hnd,&amp;pe);<br>&nbsp;}<br>}<br>&nbsp;<br>int main(int argc, char* argv[])<br>{<br>&nbsp;if(argc&lt;2)<br>&nbsp;{<br>&nbsp;&nbsp; printf(\"++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\");<br>&nbsp;&nbsp; printf(\"injectpro V1.0!\nAuthor:text QQ:52674548\nusage:\n injectpro.exe targetprocess youdll\n\");<br>&nbsp;&nbsp; printf(\" eg:injectpro.exe iexplorer.exe c:\\youdll.dll\n\");<br>&nbsp;&nbsp; printf(\"++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\");<br>&nbsp;&nbsp; return 0;<br>&nbsp;}<br>&nbsp;EnableDebugPriv(SE_DEBUG_NAME);//自身提权<br>&nbsp;DWORD pid=getpid(argv[1]);<br>&nbsp;//printf(\"%d\",pid);<br>&nbsp;if(pid==0)<br>&nbsp;&nbsp; return 1;<br>&nbsp;&nbsp; if(injectit(argv[2],pid))<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp; printf(\"inject success!\");<br>&nbsp;&nbsp; }<br>&nbsp;&nbsp; else<br>&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp; printf(\"inject error!\");<br>&nbsp;&nbsp; }<br>&nbsp;return 0;<br>}</p>
<p>本篇文章来源于 黑反在线-信息安全第一站 原文链接：<a href="http://www.hf110.com/hack/hackprg/200809/203556.html">http://www.hf110.com/hack/hackprg/200809/203556.html</a></p>
<img src ="http://www.cppblog.com/tgh621/aggbug/62974.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-09-28 12:24 <a href="http://www.cppblog.com/tgh621/archive/2008/09/28/62974.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]怎样将自己的DLL加载到Explorer.exe</title><link>http://www.cppblog.com/tgh621/archive/2008/09/28/62966.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Sun, 28 Sep 2008 03:34:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/09/28/62966.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/62966.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/09/28/62966.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/62966.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/62966.html</trackback:ping><description><![CDATA[我们知道将动态连接库注入到其他进程中有很多种方法。最常见的方法是使用钩子函数(Hook)，但是这种方法主要有两个缺点：第一如果某个进程没有加载User32.dll，那么Hook DLL将永远也不会被加载。第二Hook DLL加载的时机问题，只有在进程发出User32调用的时候, Hook DLL才有可能被加载。也就是说假设进程正在进行复杂的数值计算而没有时间进行消息调用的时候，Hook DLL是不会被加载。理论上我们没有精确的办法来确定我们的Hook DLL是否已经注入到我们想要的进程中。另外一种最常见的方法是使用函数CreateRemoteThread,在其他进程中开启一个线程来装载DLL。应该说这是一种比较完美的解决放案，这种方法避免了上述使用钩子函数的所有缺点，但是遗憾的是这个函数只能使用在WinNT/2000下。<br><br><br><br><br><br>&nbsp;&nbsp;本文将讨论一种将动态连接库注入到其他进程中的一种新方法。它的思路与使用函数CreateRemoteThread的方法相类似，只不过可以使用在Win9x,Win2k,WinXP等操作系统下。在这里我们将向读者演示我们是如何将DLL(InjectDll.dll)注入到Explorer.exe进程中！<br><br><br><br><br><br>程序的思路如下<br><br>1：得到Explorer.exe进程中任意一个线程的ID.<br><br>2：根据这个线程的ID，得到这个线程的句柄Handle<br><br>3：挂起这个线程，并保存线程当前的&#8220;上下文&#8221;<br><br>4：改变这个线程的EIP指针，使它指向我们装载DLL的函数（InjectCodeFun），然后恢复这个线程。<br><br>5：我们的装载DLL的函数运行完成后，再次挂起这个线程，使用我们以前保存的&#8220;上下文&#8221;，恢复这个线程到它被改变前的状态，并继续运行。<br><br>经过上述几个步骤，Explorer.exe进程中就会替我们装载我们的DLL(InjectDll.dll)了，有趣的是Explorer.exe对此丝毫没有察觉任何异常 ！<br><br><br><br><br><br>下面我们将详细解释一下如何编程实现上述过程。<br><br>步骤1的实现是很容易的，我们只需要调用ToolHelp的函数就可以得到我们所要得，这里我们就不详细说明了，请参考源代码中GetProcessID, GetThreadID 两个函数。<br><br><br><br>步骤2就比较麻烦了，在Win9x中没有提供一个函数可以由Thread ID得到Thread Handle（幸运的是Win2K提供这种功能）。好在我们在国外一些BBS上可以找到这个函数，它使用了一些未公开的结构，本文的目的不是讨论这个问题，读者如果有兴趣的话，可以参考我们的源代码OpenThread2函数。这个函数的作用就是传入一个Thread ID参数返回相应的 Thread Handle。<br><br><br><br>步骤3 的实现也是很容易和规范的，我们可以用SuspendThread，GetThreadContext等SDK函数轻松完成。<br><br><br><br>步骤4 这个步骤是最重要的步骤了。为了说明方便，我们将引用我们源代码中的语句，请读者参考源代码中InjectCodeIntoThread 函数。<br><br>首先改变线程的EIP指针，我们可以用下列代码完成<br><br>ThreadContext.Eip = (DWORD)m_lpCodeBase;<br><br>SetThreadContext(m_hInjectThread,&amp;ThreadContext)；<br><br>变量m_lpCodeBase指向我们的装载DLL的函数（InjectCodeFun）的首地址。<br><br>这里最关键的部分是我们如何产生我们的装载DLL的函数（InjectCodeFun）。注意我们不能简单地在我们的程序里写一个函数，然后将它的首地址赋值给EIP。这是因为装载DLL的函数是要运行在Explorer.exe地址空间中的，如果我们使用自己地址空间中的函数的话，那么必然会导致系统崩溃。解决的办法是将我们写的装载DLL函数（InjectCodeFun）放在所有程序共享的地址空间中去，在Win9x中0x80000000 ~ 0xFFFFFFFF这段地址就是我们想要的共享地址空间，那么如何将我们写的装载DLL函数放在这段地址空间呢 ？方法有很多，我们使用一种规范的方法&#8220;内存映像文件&#8221;来解决这个问题。我们通过函数CreateFileMapping来分配一段共享地址空间，然后将我们写的装载DLL函数拷贝到这段地址空间中去。具体代码请参源代码中InitInject函数。<br><br>在我们写的装载DLL函数（InjectCodeFun）中还有两个问题我们需要解释一下，第一 在这个函数中我们不能使用任何我们自己程序中定义的变量，道理跟上面讲的一样，因为地址空间不同。还有我们不能直接调用函数，例如在InjectCodeFun中直接使用LoadLibray。这是因为如果直接使用LoadLibray那么就需要经过程序的Import表，跳转一下才能到达真正的Windows的LoadLibray函数。但是不同的进程有不同的Import，所以我们不能直接调用函数。我们可以使用一种叫做&#8220;动态构造函数&#8221;的技术来创建我们的函数。首先用GetProcAddress得到函数LoadLibray的直接地址，然后在调用LoadLibray的地方，使用一个特殊的数字来代替它如 0x11111111，最后在将我们的函数拷贝到共享地址空间之后，搜索共享内存找到这个特殊数字，用我们先前得到的正确地址替换它既可。第二个有趣的现象是我们所写的装载DLL函数（InjectCodeFun）是不应该返回的。这是因为这个函数是在Explorer的线程中运行的，我们不知道堆栈的正确内容，不知道ESP所指向的地址是什么，如果函数返回的话，我们将失去对程序的控制。我们的办法是，当调用完LoadLibray之后，向我们的主程序发送一个自定义消息，通告我们的程序已经完成装载任务，然后让线程进入死循环状态。<br><br><br><br>步骤5当我们的程序接受到了自定义消息后，就会再次挂起这个线程，把我们以前保存的线程的&#8220;上下文&#8221;用函数SetThreadContext恢复，然后恢复运行这个线程。结果是Explorer.exe丝毫没有感觉到自己被中断过。<br><br><br><br><br><br>以上就是我们所介绍的方法，读者可以参考我们的源代码来具体了解上述方法。源代码的功能是将我们的DLL(InjectDll.dll)注入到Explorer.exe 中，在InjectDll.dll中我们创建了一个新的线程，然后在屏幕的左上角显示当前的时间。源代码分为Win9x版本和Win2k版本，这两个版本的主要差别是分配共享内存的方法不同而已。源代码已经在PWn98,PwinMe,Win2k,WinXP等操作系统下，使用VC6编译通过。
<img src ="http://www.cppblog.com/tgh621/aggbug/62966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-09-28 11:34 <a href="http://www.cppblog.com/tgh621/archive/2008/09/28/62966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UNICODE串转换成char类型串的四种方法[转]</title><link>http://www.cppblog.com/tgh621/archive/2008/09/27/62924.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Sat, 27 Sep 2008 10:11:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/09/27/62924.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/62924.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/09/27/62924.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/62924.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/62924.html</trackback:ping><description><![CDATA[<p>1. 调用 WideCharToMultiByte() API</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;WideCharToMultiByte&nbsp;(<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;UINT&nbsp;&nbsp;&nbsp;&nbsp;CodePage,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">1&nbsp;Unicode编码的字符页，Unicode编码有字符页的概念，比如gb2312/936，big5/950等</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp;&nbsp;dwFlags,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">2&nbsp;如何处理复合unicode字符，详细查google</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;LPCWSTR&nbsp;lpWideCharStr,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">3&nbsp;待转换的unicode串</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cchWideChar,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">4&nbsp;表示参数3的长度&nbsp;&nbsp;传递-1表示以0x00结尾</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;LPSTR&nbsp;&nbsp;&nbsp;lpMultiByteStr,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">5&nbsp;接受转换后的串的字符缓冲</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cbMultiByte,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">6&nbsp;表示参数5lpMutiByteStr的字节大小&nbsp;通常sizeof一下</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;LPCSTR&nbsp;&nbsp;lpDefaultChar,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">7&nbsp;NULL&nbsp;具体google</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;LPBOOL&nbsp;&nbsp;lpUsedDefaultChar</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">8&nbsp;NULL&nbsp;具体google</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">);<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>2. 调用CRT函数wcstombs()</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">size_t&nbsp;wcstombs&nbsp;(<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mbstr,<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;wchar_t</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;wcstr,<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;size_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count&nbsp;);<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>3. 使用CString构造器或赋值操作</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;假设有一个Unicode串wszSomeString<img alt="" src="http://www.cnblogs.com/Images/dot.gif"></span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>CString&nbsp;str1&nbsp;(&nbsp;wszSomeString&nbsp;);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;用构造器转换</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">CString&nbsp;str2;<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>str2&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;wszSomeString;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;用赋值操作转换</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>4. 使用ATL串转换宏</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">atlconv.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;还是假设有一个Unicode串wszSomeString<img alt="" src="http://www.cnblogs.com/Images/dot.gif"></span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_58_177_Open_Image onclick="this.style.display='none'; document.getElementById('Codehighlighter1_58_177_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_58_177_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_58_177_Closed_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_58_177_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_58_177_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_58_177_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_58_177_Open_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_58_177_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img alt="" src="http://www.cnblogs.com/Images/dot.gif"></span><span id=Codehighlighter1_58_177_Open_Text><span style="COLOR: #000000">{<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;szANSIString&nbsp;[MAX_PATH];<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;USES_CONVERSION;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;声明这个宏要使用的局部变量</span><span style="COLOR: #008000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000"><br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;lstrcpy&nbsp;(&nbsp;szANSIString,&nbsp;OLE2A(wszSomeString)&nbsp;);<br><img alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br></span></div>
<img src ="http://www.cppblog.com/tgh621/aggbug/62924.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-09-27 18:11 <a href="http://www.cppblog.com/tgh621/archive/2008/09/27/62924.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>自绘按钮补遗【转】</title><link>http://www.cppblog.com/tgh621/archive/2008/09/25/62779.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Thu, 25 Sep 2008 12:19:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/09/25/62779.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/62779.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/09/25/62779.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/62779.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/62779.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/tgh621/archive/2008/09/25/62779.html'>阅读全文</a><img src ="http://www.cppblog.com/tgh621/aggbug/62779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-09-25 20:19 <a href="http://www.cppblog.com/tgh621/archive/2008/09/25/62779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决Visual C++ 编译器中混合 .c 文件时收到 C1853 预编译头错误的方法（转）</title><link>http://www.cppblog.com/tgh621/archive/2008/09/25/62764.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Thu, 25 Sep 2008 08:02:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/09/25/62764.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/62764.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/09/25/62764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/62764.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/62764.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/tgh621/archive/2008/09/25/62764.html'>阅读全文</a><img src ="http://www.cppblog.com/tgh621/aggbug/62764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-09-25 16:02 <a href="http://www.cppblog.com/tgh621/archive/2008/09/25/62764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>字符串转换_BSTR/LPSTR/LPWSTR/Char </title><link>http://www.cppblog.com/tgh621/archive/2008/09/02/60729.html</link><dc:creator>大海</dc:creator><author>大海</author><pubDate>Tue, 02 Sep 2008 10:20:00 GMT</pubDate><guid>http://www.cppblog.com/tgh621/archive/2008/09/02/60729.html</guid><wfw:comment>http://www.cppblog.com/tgh621/comments/60729.html</wfw:comment><comments>http://www.cppblog.com/tgh621/archive/2008/09/02/60729.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tgh621/comments/commentRss/60729.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tgh621/services/trackbacks/60729.html</trackback:ping><description><![CDATA[<p>一、BSTR、LPSTR和LPWSTR<br>在Visual C++.NET的所有编程方式中，我们常常要用到这样的一些基本字符串类型，如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型，是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。</p>
<p>　　那么什么是BSTR、LPSTR以及LPWSTR呢？</p>
<p>　　BSTR(Basic STRing，Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的API函数(如SysAllocString)来管理它以及一些默认的调度代码，因此BSTR实际上就是一个COM字符串，但它却在自动化技术以外的多种场合下得到广泛使用。图1描述了BSTR的结构，其中DWORD值是字符串中实际所占用的字节数，且它的值是字符串中Unicode字符的两倍。</p>
<p>　　LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(&#8216;\0&#8217;)结尾的8位ANSI字符数组指针，而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中，还有类似的字符串类型，如LPTSTR、LPCTSTR等，它们的含义如图2所示。</p>
<p>　　例如，LPCTSTR是指&#8220;long pointer to a constant generic string&#8221;，表示&#8220;一个指向一般字符串常量的长指针类型&#8221;，与C/C++的const char*相映射，而LPTSTR映射为 char*。</p>
<p>　　一般地，还有下列类型定义：</p>
<p>#ifdef UNICODE<br>typedef LPWSTR LPTSTR;<br>typedef LPCWSTR LPCTSTR;<br>#else<br>typedef LPSTR LPTSTR;<br>typedef LPCSTR LPCTSTR;<br>#endif</p>
<p>二、CString、CStringA 和 CStringW</p>
<p>　　Visual C++.NET中将CStringT作为ATL和MFC的共享的&#8220;一般&#8221;字符串类，它有CString、CStringA和CStringW三种形式，分别操作不同字符类型的字符串。这些字符类型是TCHAR、char和wchar_t。TCHAR在Unicode平台中等同于WCHAR(16位Unicode字符)，在ANSI中等价于char。wchar_t通常定义为unsigned short。由于CString在MFC应用程序中经常用到，这里不再重复。</p>
<p>三、VARIANT、COleVariant 和_variant_t</p>
<p>　　在OLE、ActiveX和COM中，VARIANT数据类型提供了一种非常有效的机制，由于它既包含了数据本身，也包含了数据的类型，因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版：</p>
<p>struct tagVARIANT {<br>VARTYPE vt;<br>union {<br>short iVal; // VT_I2.<br>long lVal; // VT_I4.<br>float fltVal; // VT_R4.<br>double dblVal; // VT_R8.<br>DATE date; // VT_DATE.<br>BSTR bstrVal; // VT_BSTR.<br>&#8230;<br>short * piVal; // VT_BYREF|VT_I2.<br>long * plVal; // VT_BYREF|VT_I4.<br>float * pfltVal; // VT_BYREF|VT_R4.<br>double * pdblVal; // VT_BYREF|VT_R8.<br>DATE * pdate; // VT_BYREF|VT_DATE.<br>BSTR * pbstrVal; // VT_BYREF|VT_BSTR.<br>};<br>};</p>
<p>　　显然，VARIANT类型是一个C结构，它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如，如果vt为VT_I2，那么我们可以从iVal中读出VARIANT的值。同样，当给一个VARIANT变量赋值时，也要先指明其类型。例如：</p>
<p>VARIANT va;<br>:: VariantInit(&amp;va); // 初始化<br>int a = 2002;<br>va.vt = VT_I4; // 指明long数据类型<br>va.lVal = a; // 赋值</p>
<p>　　为了方便处理VARIANT类型的变量，Windows还提供了这样一些非常有用的函数：</p>
<p>　　VariantInit —— 将变量初始化为VT_EMPTY；</p>
<p>　　VariantClear —— 消除并初始化VARIANT；</p>
<p>　　VariantChangeType —— 改变VARIANT的类型；</p>
<p>　　VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIANT。</p>
<p>　　COleVariant类是对VARIANT结构的封装。它的构造函数具有极为强大大的功能，当对象构造时首先调用VariantInit进行初始化，然后根据参数中的标准类型调用相应的构造函数，并使用VariantCopy进行转换赋值操作，当VARIANT对象不在有效范围时，它的析构函数就会被自动调用，由于析构函数调用了VariantClear，因而相应的内存就会被自动清除。除此之外，COleVariant的赋值操作符在与VARIANT类型转换中为我们提供极大的方便。例如下面的代码：</p>
<p>COleVariant v1("This is a test"); // 直接构造<br>COleVariant v2 = "This is a test";<br>// 结果是VT_BSTR类型，值为"This is a test"<br>COleVariant v3((long)2002);<br>COleVariant v4 = (long)2002;<br>// 结果是VT_I4类型，值为2002</p>
<p>　　_variant_t是一个用于COM的VARIANT类，它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句：</p>
<p>　　#include "comutil.h"</p>
<p>　　#pragma comment( lib, "comsupp.lib" )</p>
<p>四、CComBSTR和_bstr_t</p>
<p>　　CComBSTR是对BSTR数据类型封装的一个ATL类，它的操作比较方便。例如：</p>
<p>CComBSTR bstr1;<br>bstr1 = "Bye"; // 直接赋值<br>OLECHAR* str = OLESTR("ta ta"); // 长度为5的宽字符<br>CComBSTR bstr2(wcslen(str)); // 定义长度为5<br>wcscpy(bstr2.m_str, str); // 将宽字符串复制到BSTR中<br>CComBSTR bstr3(5, OLESTR("Hello World"));<br>CComBSTR bstr4(5, "Hello World");<br>CComBSTR bstr5(OLESTR("Hey there"));<br>CComBSTR bstr6("Hey there");<br>CComBSTR bstr7(bstr6);<br>// 构造时复制，内容为"Hey there"</p>
<p>　　_bstr_t是是C++对BSTR的封装，它的构造和析构函数分别调用SysAllocString和SysFreeString函数，其他操作是借用BSTR API函数。与_variant_t相似，使用时也要添加comutil.h和comsupp.lib。</p>
<p>五、BSTR、char*和CString转换</p>
<p>　　(1) char*转换成CString</p>
<p>　　若将char*转换成CString，除了直接赋值外，还可使用CString::Format进行。例如：</p>
<p>char chArray[] = "This is a test";<br>char * p = "This is a test";</p>
<p>　　或</p>
<p>LPSTR p = "This is a test";</p>
<p>　　或在已定义Unicode应的用程序中</p>
<p>TCHAR * p = _T("This is a test");</p>
<p>　　或</p>
<p>LPTSTR p = _T("This is a test");<br>CString theString = chArray;<br>theString.Format(_T("%s"), chArray);<br>theString = p;</p>
<p>　　(2) CString转换成char*</p>
<p>　　若将CString类转换成char*(LPSTR)类型，常常使用下列三种方法：</p>
<p>　　方法一，使用强制转换。例如：</p>
<p>CString theString( "This is a test" );<br>LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;</p>
<p>　　方法二，使用strcpy。例如：</p>
<p>CString theString( "This is a test" );<br>LPTSTR lpsz = new TCHAR[theString.GetLength()+1];<br>_tcscpy(lpsz, theString);</p>
<p>　　需要说明的是，strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI)，系统编译器将会自动对其进行转换。</p>
<p>　　方法三，使用CString::GetBuffer。例如：</p>
<p>CString s(_T("This is a test "));<br>LPTSTR p = s.GetBuffer();<br>// 在这里添加使用p的代码<br>if(p != NULL) *p = _T('\0');<br>s.ReleaseBuffer();<br>// 使用完后及时释放，以便能使用其它的CString成员函数</p>
<p>　　(3) BSTR转换成char*</p>
<p>　　方法一，使用ConvertBSTRToString。例如：</p>
<p>#include "comutil.h"<br>#pragma comment(lib, "comsupp.lib")<br>int _tmain(int argc, _TCHAR* argv[]){<br>BSTR bstrText = ::SysAllocString(L"Test");<br>char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);<br>SysFreeString(bstrText); // 用完释放<br>delete[] lpszText2;<br>return 0;<br>}</p>
<p><font color=#ff0000>&nbsp;&nbsp; ** 此方法不好，会造成内存泄露，SysFreeString也没有效果。</font></p>
<p><font color=#0000ff>　　方法二，使用_bstr_t的赋值运算符重载。例如：</font></p>
<p><font color=#0000ff><strong>_bstr_t b = bstrText;<br>char* lpszText2 = b;&nbsp;&nbsp;&nbsp; </strong><br></font></p>
<p><font color=#0000ff>* 不会有内存泄露，推荐方法</font></p>
<p>　　(4) char*转换成BSTR</p>
<p>　　方法一，使用SysAllocString等API函数。例如：</p>
<p>BSTR bstrText = ::SysAllocString(L"Test");<br>BSTR bstrText = ::SysAllocStringLen(L"Test",4);<br>BSTR bstrText = ::SysAllocStringByteLen("Test",4);</p>
<p>　　方法二，使用COleVariant或_variant_t。例如：</p>
<p>//COleVariant strVar("This is a test");<br>_variant_t strVar("This is a test");<br>BSTR bstrText = strVar.bstrVal;</p>
<p>　　方法三，使用_bstr_t，这是一种最简单的方法。例如：</p>
<p>BSTR bstrText = _bstr_t("This is a test");</p>
<p>　　方法四，使用CComBSTR。例如：</p>
<p>BSTR bstrText = CComBSTR("This is a test");</p>
<p>　　或</p>
<p>CComBSTR bstr("This is a test");<br>BSTR bstrText = bstr.m_str;</p>
<p>　　方法五，使用ConvertStringToBSTR。例如：</p>
<p>char* lpszText = "Test";<br>BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);</p>
<p>　　(5) CString转换成BSTR</p>
<p>　　通常是通过使用CStringT::AllocSysString来实现。例如：</p>
<p>CString str("This is a test");<br>BSTR bstrText = str.AllocSysString();<br>&#8230;<br>SysFreeString(bstrText); // 用完释放</p>
<p>　　(6) BSTR转换成CString</p>
<p>　　一般可按下列方法进行：</p>
<p>BSTR bstrText = ::SysAllocString(L"Test");<br>CStringA str;<br>str.Empty();<br>str = bstrText;</p>
<p>　　或</p>
<p>CStringA str(bstrText);</p>
<p>　　(7) ANSI、Unicode和宽字符之间的转换</p>
<p>　　方法一，使用MultiByteToWideChar将ANSI字符转换成Unicode字符，使用WideCharToMultiByte将Unicode字符转换成ANSI字符。</p>
<p>　　方法二，使用&#8220;_T&#8221;将ANSI转换成&#8220;一般&#8221;类型字符串，使用&#8220;L&#8221;将ANSI转换成Unicode，而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如：</p>
<p>TCHAR tstr[] = _T("this is a test");<br>wchar_t wszStr[] = L"This is a test";<br>String* str = S&#8221;This is a test&#8221;;</p>
<p>　　方法三，使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类，它具有如图3所示的统一形式：</p>
<p>　　其中，第一个C表示&#8220;类&#8221;，以便于ATL 3.0宏相区别，第二个C表示常量，2表示&#8220;to&#8221;，EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、T、W和OLE，其含义分别是ANSI、Unicode、&#8220;一般&#8221;类型和OLE字符串。例如，CA2CT就是将ANSI转换成一般类型的字符串常量。下面是一些示例代码：</p>
<p>LPTSTR tstr= CA2TEX&lt;16&gt;("this is a test");<br>LPCTSTR tcstr= CA2CT("this is a test");<br>wchar_t wszStr[] = L"This is a test";<br>char* chstr = CW2A(wszStr);</p>
<img src ="http://www.cppblog.com/tgh621/aggbug/60729.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tgh621/" target="_blank">大海</a> 2008-09-02 18:20 <a href="http://www.cppblog.com/tgh621/archive/2008/09/02/60729.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>