??xml version="1.0" encoding="utf-8" standalone="yes"?>久久久久久国产a免费观看黄色大片,99久久精品日本一区二区免费,亚洲人成精品久久久久http://www.shnenglu.com/tgh621/category/8150.html专注技术开?/description>zh-cnWed, 11 Feb 2009 17:37:41 GMTWed, 11 Feb 2009 17:37:41 GMT60MFCH口的清除过E[转]http://www.shnenglu.com/tgh621/archive/2009/02/11/73433.html大v大vWed, 11 Feb 2009 02:50:00 GMThttp://www.shnenglu.com/tgh621/archive/2009/02/11/73433.htmlhttp://www.shnenglu.com/tgh621/comments/73433.htmlhttp://www.shnenglu.com/tgh621/archive/2009/02/11/73433.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/73433.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/73433.html对于vc++初学者来?总觉得窗口对象的清除q程有些莫名其妙.在程序中看不到对delete的显式调?q似乎违反了(jin)c++中有兛_始化和清除的规则.那么,E序是怎样取消一个窗口对?

要消除窗口对?必须清楚H口对象的构?在一个通常的程序中Q先创徏c++H口对象,然后由Windows创徏实际的窗口结?q返回句柄与c++对象q接.也就是说,H口对象包含c++H口对象和W(xu)indowsH口对象,两者通过句柄HWND联系.

现在,让我们看?正规"的窗口对象清除流E?所谓对象的清除是指释放对象所占的资源,H口对象中WindowsH口对象占有的是pȝ资源,c++对象占有的是内存资源.释放pȝ资源相对要简单一?调用虚函数DestroyWindow删除WindowsH口对象.如果DestroyWindow删除的是父窗?Windows?x)自动?f)子窗口调用DestroyWindow.一般来?E序不必调用DestroyWindow.因ؓ(f)当用户关闭窗口时,Windows便发送WM_CLOSE消息,WM_CLOSE的缺省消息处理函数CWnd::OnClose调用DestroyWindow.

到这?清除工作已经完成?jin)一?屏幕上的H口已经不见?但是别忘?在内存中q有一个c++H口对象.让我们再看看c++对象清除的过E?当窗口被取消?H口最后发送的一个消息是WM_NCDESTROY.它缺省的消息处理函数CWnd::OnNcDestroy把c++H口对象与句柄HWND分离,q调用一个很重要的虚函数PostNcDestroy.q个函数是搞清窗口对象清除的关键.Cwnd中的PostNcDestroy什么都不做.有些MFCH口cM(x)重蝲?q加入delete this代码删除c++对象.q些H口cd常是以new操作W徏立在堆中?׃重蝲?jin)PostNcDestroy,使窗口有自动清除功能.因此,我们不用兛_(j)清除问题?另外的一些MFCH口cM般是以变量Ş式创建的,MFC没有Z没必要ؓ(f)它们重蝲PostNcDestroy函数.

不具备自动清除功能的H口c?一般在堆栈中创建或嵌入于其它c++对象?

所有标准的Windows控gc?如CStatic, CEdit, CListBox{等)

由CWndcȝ接派生出来的子窗口对?如用户定制的控g)

拆分H口c?CSplitterWnd)

~省的控制条c?CControlBar的派生类)

对话框类(CDialog)在堆栈上创徏的模态对话框c?/p>

所有的Windows通用对话?除CFindReplaceDialog)

由ClassWizard创徏的对话框

h自动清除功能的窗口类,一般在堆中创徏:

L架窗口类(直接或间接从CFrameWndcL?

视图c?直接或间接从CViewcL?

从某U程度上来说,MFC?服务到家"使初学者有些找不着?不过,不得不承?MFCq的很漂?

谈到q里,我们应该明白c++里一条重要的准则:用DestroyWindow清除H口对象,不要?delete".

对于不具备自动清除功能的H口cM?delete"?"delete"先调用析构函数里的DestroyWindow,׃在析构函C,虚机制不起作?q里只能调用本地版本(Cwndc?DestroyWindow函数,昄q不是我们想要的.对于有自动清除功能的H口c?好象问题更严重一?前面提到?jin)重载的PostNcDestroy已经含有?delete this",q样c++对象p释放?jin)两?

很多?vc++同vb一?是一个完全可视化的?不用在看c++的书?通过上面对窗口对象的清除的介l?可以发现,WindowsE序是与Windows紧密l合?而且牉|到很多c++的知?如虚函数、析构函数、new操作W等).要对vc++有进一步理?必须理解Windows机制,深入学习(fn)c++.



大v 2009-02-11 10:50 发表评论
]]>
[转]可在q行时编辑的加速键?/title><link>http://www.shnenglu.com/tgh621/archive/2009/01/12/71821.html</link><dc:creator>大v</dc:creator><author>大v</author><pubDate>Mon, 12 Jan 2009 09:22:00 GMT</pubDate><guid>http://www.shnenglu.com/tgh621/archive/2009/01/12/71821.html</guid><wfw:comment>http://www.shnenglu.com/tgh621/comments/71821.html</wfw:comment><comments>http://www.shnenglu.com/tgh621/archive/2009/01/12/71821.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/tgh621/comments/commentRss/71821.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tgh621/services/trackbacks/71821.html</trackback:ping><description><![CDATA[Q*Q简 介*Q* <p>  本文首先要介l了(jin)一?a target=_blank><u><font color=#0000ff>Windows</font></u></a>中的几个?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表有关的API函数?qing)结构。然后对在WIN32位程序中实现<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行了(jin)探讨Q分别就API下的E序设计?qing)MFC下的E序设计q行?jin)叙q?br>  对于q行时可~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表仅在MFC下进行了(jin)详细描述。包括其实现原理Qƈ引导大家建立?jin)一个用于编?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的对话框Q含详细的代码。关于在API下实现运行时的可~辑<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表不再叙qͼ可参考MFC下的代码?br>  我们通常希望编辑过?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存v来,以便下次q行E序时保持我们编辑后的风根{在本文的最后,介绍?jin)如何?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存至文g中,q从文g中读取我们保存的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。你若是有意?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存至<a target=_blank><u><font color=#0000ff>注册?/font></u></a>或其它什么地方,可参考其它的有关资料。本人徏议保存至文g比较恰当?br>  本文介绍的所有方法及(qing)代码都是?Windows98SE + Microsoft Visual <a 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函数Q关于这几个函数的详l说明请参考有关书c)(j)Q?br>  HACCEL LoadAccelerators(HINSTANCE hInstance, LPCTSTR lpTableNAme);<br>  LoadAccelerators函数从程序的资源中加载一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表,加蝲成功后返回一个加速健表的句柄。其中:(x)<br>  hInstance  应用E序的实例句柄?br>  lpTableName 指向<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表名U字W串的指针?/p> <p>  HACCEL CreateAcceleratorTable(LPACCEL lpaccl, int cEntries);<br>  CreateAcceleratorTable函数Ҏ(gu)一个ACCELl构数组创徏一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。该函数与LoadAccelerators不同的是QLoadAccelerators函数加蝲?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表在E序l束后系l会(x)自动该<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表从内存中清除,但CreateAcceleratorTable函数创徏?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表需要用函数DestoryAceleratorTable函数q行清除?br>  lpaccl   一个指向ACCELl构数组的指针?br>  cEntries  数组中元素的个数?/p> <p>  BOOL DestoryAcceleratorTable(HACCEL hAccel);<br>  DestoryAcceleratorTable函数清除由CreateAcceleratorTable函数创徏?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表,成功则返回TRUE。其中:(x)<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>。其中:(x)<br>  hWnd     H口句柄Q翻译后的消息将被发往该窗?br>  hAccTable  <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表句柄?br>  lpMsg    指向MSGl构的指针?/p> <p>  ACCELl构的定义:(x)<br>typedef struct tagACCEL{<br>    BYTE    fVirt;<br>    WORD    key;<br>    WORD    cmd;<br>}ACCEL,*LPACCEL;</p> <p>其中Q?br>  fVirt   <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的标记?br>  key    键的代码。如fVirt成员包含FVIRTKEY标志Q则key指一个虚键码Q否则是一个ASCII码?br>  cmd    命o(h)IDP该参数将被放入WMQCOMMAND或WMQSYSCOMMAND消息的wParam参数的低位字发至H口?/p> <p><br>  二、在windows下如何?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表?/p> <p>  在window下?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表一般有两种Ҏ(gu)Q?Q创Z?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>资源Q在E序中用API函数LoadAccelerators来将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表加载入内存。ƈ在消息@环中使用API函数TranslateAccelerator来翻译该<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表?、在E序中填充一个ACCEL数组。然后调用API函数CreateAcceleratorTable来创建加速表Q翻?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>同上Q但不要忘记在退出程序前使用API函数DestoryAcceleratorTable来清除它。下面分别给Z个例子:(x)</p> <p>/*?:使用LoadAccelerators?br> 假设你已l徏立了(jin)一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>资源QID为IDRQACCEL?br> 假设你已l定义了(jin)初始化函数InitApplication(HINSTANCE hInstance,int nCmdShow),<br> 该函数执行注册窗口类和创建窗口操作?br>*/<br>#include <windows.h><br>#include "rc/resource.h"<br>BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);</p> <p>int APIENTRY WinMain(HINSTANCE hInstance,<br>                     HINSTANCE hPrevInstance,<br>                     LPSTR     lpCmdLine,<br>                     int       nCmdShow) <br>{<br>     MSG msg;<br>     HANDLE hAccelTable;<br>     // 初始化应用程序,q生成主H口.<br>     if (!InitApplication(hInstance, nCmdShow))<br>     {<br>         return FALSE;           // 初始化失?br>     }<br>      //使用函数LoadAccelerators从程序资源中加蝲<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?br>      hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL));<br>      // 取得q分发消息直到接收到 WM_QUIT 消息.<br>     while (GetMessage(&msg, NULL, 0, 0))<br>     {<br>         //在分发消息前首先试着?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行翻译,如果是一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>则由<br>         //TranslateAccelerator函数q行译Q不再l处理该消息?br>         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))<br>         {<br>             TranslateMessage(&msg);<br>             DispatchMessage(&msg);<br>         }<br>     }<br>     return msg.wParam;  // Returns the value from PostQuitMessage <br>} <br> </p> <p><br>/*?:使用CreateAcceleratorTable?br> 假设你已l定义了(jin)初始化函数InitApplication(HINSTANCE hInstance,int nCmdShow),<br> 该函数执行注册窗口类和创建窗口操作?br>*/</p> <p>#include <windows.h><br>#include "rc/resource.h"</p> <p>Qdefine ID_CMD_A      0x00000230<br>Qdefine ID_CMD_B      0x00000231<br>Qdefine ID_CMD_C      0x00000232<br>Qdefine ID_CMD_D      0x00000233<br>Qdefine ID_CMD_E      0x00000234<br>Qdefine ID_CMD_F      0x00000235<br>Qdefine ID_CMD_G      0x00000236</p> <p>//定义?jin)七?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>,请在消息回调函数中处理这七个命o(h)ID?br>static ACCEL accel[]={<br>    {FVIRTKEY|FCONTROL,VK_F5,ID_CMD_A},<br>    {FVIRTKEY|FCONTROL,VK_F6,ID_CMD_B},<br>    {FVIRTKEY|FCONTROL,VK_HOME,ID_CMD_C},<br>    {FVIRTKEY|FCONTROL,VK_END,ID_CMD_D},<br>    {FVIRTKEY|FCONTROL,"G",ID_CMD_E},<br>    {FVIRTKEY|FCONTROL,VK_SPACE,ID_CMD_F},<br>    {FVIRTKEY|FCONTROL,"K",ID_CMD_G},<br>};    </p> <p>BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);</p> <p>int APIENTRY WinMain(HINSTANCE hInstance,<br>                     HINSTANCE hPrevInstance,<br>                     LPSTR     lpCmdLine,<br>                     int       nCmdShow) <br>{<br>     MSG msg;<br>     HANDLE hAccelTable;<br>     // 初始化应用程序,q生成主H口.<br>     if (!InitApplication(hInstance, nCmdShow))<br>     {<br>         return FALSE;           // 初始化失?br>     }<br>      //使用函数CreateAcceleratorTable从数laccel中加?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?br>      hAccelTable = CreateAcceleratorTable(accel, sizeof(accel)/sizeof(ACCEL));<br>      // 取得q分发消息直到接收到 WM_QUIT 消息.<br>     while (GetMessage(&msg, NULL, 0, 0))<br>     {<br>         //在分发消息前首先试着?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行翻译,如果是一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>则由<br>         //TranslateAccelerator函数q行译Q不再l处理该消息?br>         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))<br>         {<br>             TranslateMessage(&msg);<br>             DispatchMessage(&msg);<br>         }<br>     }<br>     //删除<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?br>     DestoryAcceleratorTable(hAccelTable);<br>     return msg.wParam;  // Returns the value from PostQuitMessage <br>} <br> </p> <p><br>  在MFCE序设计中,有关?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的操作已经被CFrameWndc进行了(jin)装。通常Q我们的E序的主框架cCMainFrame从CFrameWndcL生(SDI界面E序Q,或者从CMDIFrameWndcL生(MDI界面E序Q,而CMDIFrameWndcM是从CFrameWndcL生的。所以,我们q不用去兛_(j)那个资源号ؓ(f)IDR_MAINFRAME?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表是如何加蝲的,如果你只是需要一个这L(fng)?rn)态的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的话?br>  那么我们能不能用自q<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表呢Q答案是Q可以的?br>  创徏<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的Ҏ(gu)同前。由于在MFC中,W(xu)inMain函数被隐藏,我们不能直接修改WinMain函数Q所以,<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的创徏在CMainFrame的OnCreate函数中创建?br>  1、在CMainFramecMd一个HACCELcd保护成员变量Qm_hMyAccel。在构造函C初始化ؓ(f)NULL?br>  2、在CMainFrame::OnCreate函数?“return 0;”句前增加创徏<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的代码。返回的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表句柄保存在m_hMyAccel中:(x)</p> <p>   Ҏ(gu)1Q?IDRQMYACCELZ定义?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表资源号)<br>   m_hMyAccel=LoadAccelerators(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_MYACCEL));</p> <p>   Ҏ(gu)2Q?accel同前面的例子一样在本文件的开头部分进行定?<br>   m_hMyAccel=CreateAcceleratorTable(accel,sizeof(accel)/sizeof(ACCEL));</p> <p>  3、如果是使用CreateAccelTable函数创徏的,则重载虚拟函数DestoryWindow()。在该函数的“return CMDIFrameWnd::DestroyWindow();”前增加如下代?</p> <p>    if(m_hMyAccel!=NULL){<br>        DestroyAcceleratorTable(m_hMyAccel);<br>        m_hMyAccel=NULL;<br>    }</p> <p>  通过前面的三步,<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表已l能正确地被创徏和删除了(jin)Q但是它q没有工作。下面就是要让我们刚才所创徏?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表工作v来?br>  在APIE序设计中大家已l知道了(jin)<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>是如何工作的。也是在消息还没有分发出去之前先检查是不是一?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>。我们通过API函数TranslateAccelerator来实现。在MFC中,消息机制已经被封装了(jin)Q我们不能去修改消息循环。但是,框架在分发消息前?x)调用虚拟函数PerTranslateMessageQƈ且如果该函数q回TRUEQ则不再处理该消息。这正是我们所需要的?br>  让我们再回到CMainFramec,生成PerTranslateMessage函数的覆盖版本。修改函C如下Q?/p> <p>BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) <br>{<br>    // TODO: Add your specialized code here and/or call the base class<br>    if(m_hMyAccel&&TranslateAccelerator(m_hWnd, m_hMyAccel, pMsg))<br>        return TRUE;<br>    return CMDIFrameWnd::PreTranslateMessage(pMsg);<br>}</p> <p>  好了(jin)Q现在我们的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>已经能正常地工作?jin)。以上方法用在其它窗口同h效(如对话框中,你不妨在对话框中试试Q?/p> <p><br>  三、可在运行时~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表?/p> <p>  通过上面的叙qͼ你可能已l对可编辑的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表有?jin)一定的轮廓。其实其实现思想很简单:(x)只要对一个ACCEL数组q行修改Q然后重新生?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表就行了(jin)?br>  Z(jin)区分命o(h)Q我们ؓ(f)每个命o(h)取一个名字。在CMainFramecd义的前面加上下面的一个结构定义:(x)</p> <p>typedef struct{<br>    char cCmd[32];<br>    ACCEL accel;<br>}ACCELITEM,*LPACCELITEM;</p> <p>  我们用该l构来保?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的数据。在CMainFramecMd两个保护成员变量Q?/p> <p>    LPACCELITEM m_lpAccel;<br>    DWORD m_dwAccelCount;</p> <p>  在构造函Cm_lpAccel初始化ؓ(f)NULLQm_dwAccelCount初始化ؓ(f)0。在数组accel的定义下面增加一个字W串数组的静(rn)态变量的定义Q用来指定命令的名称,请仿照下面自己定义,个数多少不限Q字W串长度不要过31个字W)(j)Q?/p> <p>static char strCmd[][32]={<br>    "Command One",<br>    "Command Two",<br>    "Command Three",<br>    "Command Four",<br>    "Command Five"<br>};</p> <p><br>  在CMainFramecMd一个保护成员函数LoadAccel(),该函数用来将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表装入,定义如下Q?/p> <p>BOOL CMainFrame::LoadAccel()<br>{<br>    ASSERT(m_hActAccel==NULL);<br>    ASSERT(m_lpAccel==NULL);<br>    m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);<br>    m_lpAccel=new ACCELITEM[m_dwAccelCount];<br>    memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);<br>    DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[32]);<br>    for(DWORD dw=0;dw<m_dwAccelCount;dw++){<br>        m_lpAccel[dw].accel=accel[dw];<br>        strcpy(m_lpAccel[dw].cCmd,dw<dwCmdStr?strCmd[dw]:"Command Unknow");<br>    }</p> <p>    m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);<br>    return TRUE;</p> <p>}</p> <p>  删除OnCreate函数中原来创?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表的代码Q改成对LoadAccel()的调用:(x)</p> <p>    LoadAccel();</p> <p>  在CMainFrame的析构函C增加以下内容Q?/p> <p>    if(m_lpAccel)<br>        delete[] m_lpAccel;</p> <p>  Z(jin)能够?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>数据q行~辑Q我们在工程中添加一个对话框资源QID?#8220;IDD_ACCELEDIT”Q在对话框上攄三个成组框(Group BoxQ,左边一个标题ؓ(f)“命o(h)”Q中间一个标题ؓ(f)“l合?#8221;Q右边一个标题ؓ(f)“虚键?#8221;。在左边成组框中攄一个列表框QList BoxQ,ID?#8220;IDC_LST_CMD”。在中间成组框中攄三个栔R框QCheck BoxQ,上下排列。上面的栔R框的ID?#8220;IDC_CHK_ALT”Q标题ؓ(f)“Alt”QƈN?#8220;Group”属性;中间的核选框的ID?#8220;IDC_CHK_SHIFT”Q标题ؓ(f)“Shift”Q取?#8220;Group”属性;下面的核选框的ID?#8220;IDC_CHK_CTRL”Q标题ؓ(f)“Ctrl”Q取?#8220;Group”属性。在双的成l框中放|一个列表框QID?#8220;IDC_LST_KEY”。调整各个控件的寸?qing)位|至合适。设|控件的TAB跌{序Q从左至叟뀁从上到下。依ơؓ(f)Q左成组框、IDC_LST_CMD列表框、中成组框、IDC_CHK_ALT栔R框、IDC_CHK_SHIFT栔R框、IDC_CHK_CTRL栔R框、右成组框、IDC_LST_KEY列表框、OK按钮、CANCEL按钮?br>  打开cd|为对话框新徏一个类Q类名ؓ(f)“CDlgEditAccel”。ؓ(f)两个列表框和三个栔R框映射变量Q如下:(x)<br>  控gID:ID_LST_CMDQ类?Control/CListBoxQ名U?m_LstCmdQ?br>  控gID:ID_LST_KEYQ类?Control/CListBoxQ名U?m_LstKeyQ?br>  控gID:ID_CHK_ALTQ类?Control/CButtonQ名U?m_ChkAltQ?br>  控gID:ID_CHK_SHIFTQ类?Control/CButtonQ名U?m_ChkShiftQ?br>  控gID:ID_CHK_CTRLQ类?Control/CButtonQ名U?m_ChkCtrlQ?/p> <p>  在类CDlgEditAccel的定义前加入下面的定义:(x)<br>typedef struct tag_KeyName{<br>    CString m_strName;<br>    WORD m_wID;<br>    tag_KeyName(CString str,WORD id){m_strName=str,m_wID=id;}<br>}KEYNAME,*LPKEYNAME;</p> <p>typedef struct tag_ActAccel{<br>    CString m_strCmd;<br>    ACCEL m_Accel;<br>}ACTACCEL,*LPACTACCEL;</p> <p>class CActAccelList<br>{<br>public:<br>    CActAccelList();<br>    ~CActAccelList();</p> <p>protected:<br>    LPACTACCEL m_lpActAccel;<br>    int m_iCount;</p> <p>public:<br>    ACTACCEL& operator[](int index);<br>    BOOL SetSize(int iSize);<br>    int GetSize();<br>};</p> <p><br>  在文件DlgEditAccel.cpp文g中定义类CActAccelList的成员函敎ͼ代码如下Q?br>CActAccelList::CActAccelList()<br>{<br>    m_lpActAccel=NULL;<br>   m_iCount=0;<br>}</p> <p>CActAccelList::~CActAccelList()<br>{<br>    if(m_iCount>0&&m_lpActAccel)<br>        delete[] m_lpActAccel;<br>}</p> <p>int CActAccelList::GetSize()<br>{<br>    return m_iCount;<br>}</p> <p>ACTACCEL& CActAccelList::operator []( int index)<br>{<br>    if(!(index>=0&&index<m_iCount))<br>    AfxThrowMemoryException();<br>    return m_lpActAccel[index];<br>}</p> <p>BOOL CActAccelList::SetSize(int iSize)<br>{<br>    if(iSize<0)<br>        return FALSE;<br>    if(m_iCount>0&&m_lpActAccel)<br>        delete[] m_lpActAccel;<br>    m_iCount=0;<br>    m_lpActAccel=new ACTACCEL[iSize];<br>    if(m_lpActAccel==NULL)<br>        return FALSE;<br>    m_iCount=iSize;<br>    return TRUE;<br>}</p> <p><br>  在DlgAccelEdit.cpp文g头部定义全局变量Q-数组keyQ?br>static KEYNAME key[]={<br>    KEYNAME("Left mouse button",VK_LBUTTON),<br>    KEYNAME("Right mouse button",VK_RBUTTON),<br>    KEYNAME("Control-break processing",VK_CANCEL),<br>    KEYNAME("Middle mouse button",VK_MBUTTON),<br>    KEYNAME("Back Space",VK_BACK),<br>    KEYNAME("Tab",VK_TAB),<br>    KEYNAME("Clear",VK_CLEAR),<br>    KEYNAME("Enter",VK_RETURN),<br>    KEYNAME("Shift",VK_SHIFT),<br>    KEYNAME("Ctrl",VK_CONTROL),<br>    KEYNAME("Alt",VK_MENU),<br>    KEYNAME("Pause",VK_PAUSE),<br>    KEYNAME("Caps Lock",VK_CAPITAL),<br>    KEYNAME("Esc",VK_ESCAPE),<br>    KEYNAME("Space",VK_SPACE),<br>    KEYNAME("Page Up",VK_PRIOR),  <br>    KEYNAME("Page Down",VK_NEXT),<br>    KEYNAME("End",VK_END),<br>    KEYNAME("Home",VK_HOME),<br>    KEYNAME("Left",VK_LEFT),<br>    KEYNAME("Up",VK_UP),<br>    KEYNAME("Right",VK_RIGHT),<br>    KEYNAME("Down",VK_DOWN),<br>    KEYNAME("Select",VK_SELECT),<br>    KEYNAME("Excute",VK_EXECUTE),<br>    KEYNAME("Print Screen",VK_SNAPSHOT),<br>    KEYNAME("Insert",VK_INSERT),<br>    KEYNAME("Delete",VK_DELETE),<br>    KEYNAME("Help",VK_HELP),<br>    KEYNAME("0",'0'),<br>    KEYNAME("1",'1'),<br>    KEYNAME("2",'2'),<br>    KEYNAME("3",'3'),<br>    KEYNAME("4",'4'),<br>    KEYNAME("5",'5'),<br>    KEYNAME("6",'6'),<br>    KEYNAME("7",'7'),<br>    KEYNAME("8",'8'),<br>    KEYNAME("9",'9'),<br>    KEYNAME("A",'A'),<br>    KEYNAME("B",'B'),<br>    KEYNAME("C",'C'),<br>    KEYNAME("D",'D'),<br>    KEYNAME("E",'E'),<br>    KEYNAME("F",'F'),<br>    KEYNAME("G",'G'),<br>    KEYNAME("H",'H'),<br>    KEYNAME("I",'I'),<br>    KEYNAME("J",'J'),<br>    KEYNAME("K",'K'),<br>    KEYNAME("L",'L'),<br>    KEYNAME("M",'M'),<br>    KEYNAME("N",'N'),<br>    KEYNAME("O",'O'),<br>    KEYNAME("P",'P'),<br>    KEYNAME("Q",'Q'),<br>    KEYNAME("R",'R'),<br>    KEYNAME("S",'S'),<br>    KEYNAME("T",'T'),<br>    KEYNAME("U",'U'),<br>    KEYNAME("V",'V'),<br>    KEYNAME("W",'W'),<br>    KEYNAME("X",'X'),<br>    KEYNAME("Y",'Y'),<br>    KEYNAME("Z",'Z'),<br>    KEYNAME("Left windows",VK_LWIN),<br>    KEYNAME("Right windows",VK_RWIN),<br>    KEYNAME("Applications",VK_APPS),<br>    KEYNAME("Numeric keypad 0", VK_NUMPAD0),<br>    KEYNAME("Numeric keypad 1", VK_NUMPAD1),<br>    KEYNAME("Numeric keypad 2", VK_NUMPAD2),<br>    KEYNAME("Numeric keypad 3", VK_NUMPAD3),<br>    KEYNAME("Numeric keypad 4", VK_NUMPAD4),<br>    KEYNAME("Numeric keypad 5", VK_NUMPAD5),<br>    KEYNAME("Numeric keypad 6", VK_NUMPAD6),<br>    KEYNAME("Numeric keypad 7", VK_NUMPAD7),<br>    KEYNAME("Numeric keypad 8", VK_NUMPAD8),<br>    KEYNAME("Numeric keypad 9", VK_NUMPAD9), <br>    KEYNAME("Multiply",VK_MULTIPLY),<br>    KEYNAME("Add",VK_ADD),<br>    KEYNAME("Separator",VK_SEPARATOR),<br>    KEYNAME("Subtract",VK_SUBTRACT),<br>    KEYNAME("Decimal Point",VK_DECIMAL),<br>    KEYNAME("Divide",VK_DIVIDE),<br>    KEYNAME("F1",VK_F1),<br>    KEYNAME("F2",VK_F2),<br>    KEYNAME("F3",VK_F3),<br>    KEYNAME("F4",VK_F4),<br>    KEYNAME("F5",VK_F5),<br>    KEYNAME("F6",VK_F6),<br>    KEYNAME("F7",VK_F7),<br>    KEYNAME("F8",VK_F8),<br>    KEYNAME("F9",VK_F9),<br>    KEYNAME("F10",VK_F10),<br>    KEYNAME("F11",VK_F11),<br>    KEYNAME("F12",VK_F12),<br>    KEYNAME("F13",VK_F13),<br>    KEYNAME("F14",VK_F14),<br>    KEYNAME("F15",VK_F15),<br>    KEYNAME("F16",VK_F16),<br>    KEYNAME("F17",VK_F17),<br>    KEYNAME("F18",VK_F18),<br>    KEYNAME("F19",VK_F19),<br>    KEYNAME("F20",VK_F20),<br>    KEYNAME("F21",VK_F21),<br>    KEYNAME("F22",VK_F22),<br>    KEYNAME("F23",VK_F23),<br>    KEYNAME("F24",VK_F24),<br>    KEYNAME("Attn",VK_ATTN),<br>    KEYNAME("CrSel",VK_CRSEL),<br>    KEYNAME("ExSel",VK_EXSEL),<br>    KEYNAME("Erase",VK_EREOF),<br>    KEYNAME("Play",VK_PLAY),<br>    KEYNAME("Zoom",VK_ZOOM),<br>    KEYNAME("Reserved for future use",VK_NONAME ),<br>    KEYNAME("PA1",VK_PA1),<br>    KEYNAME("Clear(OEM)",VK_OEM_CLEAR ),</p> <p>    KEYNAME("<a href="file://%22,'//'"><u><font color=#0000ff>file://",'//'</font></u></a>),<br>    KEYNAME("-",'-'),<br>    KEYNAME("=",'='),<br>    KEYNAME("[",'['),<br>    KEYNAME("]",']'),<br>    KEYNAME(";",';'),<br>    KEYNAME("\'",'\''),<br>    KEYNAME(",",','),<br>    KEYNAME(".",'.'),<br>    KEYNAME("/",'/'),<br>    KEYNAME("`",'`')<br>};</p> <p><br>  在类CDlgAccelEdit中响应Windows消息QWM_INITDIALODQ代码如下:(x)<br>BOOL CDlgEditAccel::OnInitDialog() <br>{<br>    CDialog::OnInitDialog();</p> <p>    // TODO: Add extra initialization here<br>    SetWindowText("Edit Accelerator Table");</p> <p>    int iCount=m_AccelList.GetSize();<br>    int i;<br>    for(i=0;i<iCount;i++){<br>        m_LstCmd.AddString(m_AccelList[i].m_strCmd);<br>    }<br>    for(i=0;i<sizeof(key)/sizeof(KEYNAME);i++)<br>    {<br>        m_LstKey.AddString(key[i].m_strName);<br>    }<br>    m_LstCmd.SetCurSel(0);<br>    OnSelchangeLstCmd();<br>    return TRUE;  // return TRUE unless you set the focus to a control<br>                  // EXCEPTION: OCX Property Pages should return FALSE<br>}</p> <p><br>  为类CDglAccelEdit增加一个保护成员函敎ͼ(x)<br>    void SaveChange(int index=-1);</p> <p>  在文件DlgAccelEdit中定义该函数Q代码如下:(x)</p> <p>void CDlgEditAccel::SaveChange(int index)<br>{<br>    if(index>=0||(index=m_LstCmd.GetCurSel())>=0)<br>    {<br>        if(m_LstKey.GetCurSel()<0){<br>            AfxMessageBox("你必需选择一个键?");<br>            return;<br>        }<br>        BYTE btCmp=((m_ChkAlt.GetCheck()==1)?FALT:NULL)|<br>                   ((m_ChkCtrl.GetCheck()==1)?FCONTROL:NULL)|<br>                   ((m_ChkShift.GetCheck()==1)?FSHIFT:NULL)|FVIRTKEY;<br>        WORD wKey=key[m_LstKey.GetCurSel()].m_wID;</p> <p>        m_AccelList[index].m_Accel.fVirt=btCmp;<br>        m_AccelList[index].m_Accel.key=wKey;<br>        return;<br>    }<br>}</p> <p>  响应列表框ID_LST_CMD的通知消息“LBN_SELCHANGE”Q函C码如下:(x)<br>void CDlgEditAccel::OnSelchangeLstCmd() <br>{<br>    // TODO: Add your control notification handler code here<br>    int iCmd=m_LstCmd.GetCurSel();<br>    WORD wKey=m_AccelList[iCmd].m_Accel.key;<br>    BYTE btCmp=m_AccelList[iCmd].m_Accel.fVirt;<br>    m_ChkAlt.SetCheck(btCmp&FALT);<br>    m_ChkCtrl.SetCheck(btCmp&FCONTROL);<br>    m_ChkShift.SetCheck(btCmp&FSHIFT);<br>    int iCount=sizeof(key)/sizeof(KEYNAME);<br>    int id=-1;<br>    for(int i=0;i<iCount;i++)<br>    {<br>        if(key[i].m_wID==wKey){<br>            id=i;<br>            break;<br>        }<br>    }<br>    m_LstKey.SetCurSel(id);</p> <p>}</p> <p>  响应列表框ID_LST_KEY的通知消息“LBN_SELCHANGE”Q函C码如下:(x)<br>void CDlgEditAccel::OnSelchangeLstKey() <br>{<br>    SaveChange(); <br>}</p> <p>  响应栔R框ID_CHK_ALT的通知消息“BN_CLICKED”Q函C码如下:(x)<br>void CDlgEditAccel::OnChkAlt() <br>{<br>    SaveChange();<br>}</p> <p>  响应栔R框ID_CHK_SHIFT的通知消息“BN_CLICKED”Q函C码如下:(x)<br>void CDlgEditAccel::OnChkShift() <br>{<br>    SaveChange();<br>}</p> <p>  响应栔R框ID_CHK_CTRL的通知消息“BN_CLICKED”Q函C码如下:(x)<br>void CDlgEditAccel::OnChkCtrl() <br>{<br>    SaveChange();<br>}</p> <p>  xQ用于编?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的对话框已经完成。我们现在要做的是在程序中打开对话框来~辑?jin)。让我们回到CMainFramecM。我们将在该cM响应一个命令来打开~辑对话框,?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表进行编辑。完成后Ҏ(gu)OK回到ȝ序中Q然后更?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。这样后Q我们刚刚编辑好?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表就开始v作用?jin)?br>  首先Q打开菜单。在“查看”后增加一?#8220;工具(&T)”下拉菜单Q在下拉菜单中增加一个了(jin)菜单Q?#8220;~辑<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?&A)...”QID?#8220;ID_TOOL_ACCELEDIT”。打开cd|选择CMainFramec,响应“ID_TOOL_ACCELEDIT”命o(h)。编辑响应函数如下:(x)</p> <p>void CMainFrame::OnToolAcceledit() <br>{<br>    // TODO: Add your command handler code here<br>    CDlgEditAccel dlg;</p> <p>    DWORD i;<br>    dlg.m_AccelList.SetSize(m_dwAccelCount);<br>    for(i=0;i<m_dwAccelCount;i++){<br>        dlg.m_AccelList[i].m_strCmd=m_lpAccel[i].cCmd;<br>        dlg.m_AccelList[i].m_Accel=m_lpAccel[i].accel;<br>    }<br>    if(IDOK==dlg.DoModal()){<br>        ACCEL* pAccel=new ACCEL[m_dwAccelCount];<br>        for(DWORD dw=0;dw<m_dwAccelCount;dw++){<br>            m_lpAccel[dw].accel=pAccel[dw]=dlg.m_AccelList[dw].m_Accel;<br>        }</p> <p>        if(m_hActAccel!=NULL)<br>        DestroyAcceleratorTable(m_hActAccel);<br>        m_hActAccel=CreateAcceleratorTable(pAccel,m_dwAccelCount);<br>    }<br>}</p> <p>  在该文g的头部包含类CDlgEditAccel的头文gQ?/p> <p>#include "DlgEditAccel.h"</p> <p>  xQ可~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表已l完成了(jin)。不妨试试看?/p> <p>  三、将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存至文gQƈ在程序运行时自动从文件中加蝲?/p> <p>  上面我们实现?jin)可~辑?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表。但是,当程序退出后Q我们编辑过?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>数据消׃(jin)Q下ơ运行程序时q是和以前一样了(jin)。将<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存v来以备下ơ用,q是我们所希望的。下面讨论的Ҏ(gu)是用文件来保存我们?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表?br>  首先Q在MainFrm.cpp文g的头部定义一个全局字符Ԍ也就是用于保?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>的文件名Q?/p> <p>static char strAccelFileName[]="Accel.cus";</p> <p>  定义一个DWORDg为文件头Q我们通过该DWORD值来判断是否是一个有效格式的文gQ?/p> <p>#define ACCEL_FILE_HEAD 0x00434341</p> <p><br>  其次Qؓ(f)CMainFramecL加一个保护的成员函数Q?#8220;BOOL SaveAccel()”Q编辑其代码如下Q?br>BOOL CMainFrame::SaveAccel()<br>{<br>    char lpAppName[256];<br>    char lpAppPath[256];<br>    char* lpFilePart=NULL;<br>    GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);<br>    GetFullPathName(lpAppName,255,lpAppPath,&lpFilePart);<br>    TRACE1("Application File Name:%s.\n",lpAppName);<br>    strcpy(lpFilePart,strAccelFileName);<br>    TRACE1("Accelerator File Name:%s.\n",lpAppPath);<br>    try<br>    {<br>        DWORD dwHead=ACCEL_FILE_HEAD;<br>        DWORD dwCount=m_dwAccelCount;</p> <p>        CFile fAccel(lpAppPath,CFile::modeCreate|CFile::modeWrite);<br>        fAccel.SeekToBegin();<br>        fAccel.Write(&dwHead,sizeof(DWORD));<br>        fAccel.Write(&dwCount,sizeof(DWORD));<br>        for(DWORD dw=0;dw<dwCount;dw++)<br>        {<br>            fAccel.Write(m_lpAccel+dw,sizeof(ACCELITEM));<br>        }</p> <p>        return TRUE;</p> <p>    }</p> <p>    catch(CFileException* e)<br>    {<br>        char buf[256];<br>        char buf2[512];<br>        int iError;<br>        iError=e->m_cause;<br>        e->GetErrorMessage(buf,256);<br>        sprintf(buf2,"?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表保存到文g \"%s\" 中时发生错误!\n"<br>                     "???%d\n"<br>                     "错误描述:%s\n"<br>                     "\0",<br>                     strAccelFileName,iError,buf);<br>        AfxMessageBox(buf2,MB_OK|MB_ICONSTOP|MB_DEFBUTTON1);<br>        return FALSE;<br>    }<br>}</p> <p>  再次Q修改LoadAccel()函数如下Q?/p> <p>BOOL CMainFrame::LoadAccel()<br>{<br>    char lpAppName[256];<br>    char lpAppPath[256];<br>    char* lpFilePart=NULL;<br>    GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);<br>    GetFullPathName(lpAppName,255,lpAppPath,&lpFilePart);<br>    TRACE1("Application File Name:%s.\n",lpAppName);<br>    strcpy(lpFilePart,strAccelFileName);<br>    TRACE1("Accelerator File Name:%s.\n",lpAppPath);<br>    try<br>    {<br>        DWORD dwHead;<br>        DWORD dwCount;</p> <p>        CFile fAccel(lpAppPath,CFile::modeRead);<br>        fAccel.SeekToBegin();<br>        if(fAccel.Read(&dwHead,sizeof(DWORD))!=sizeof(DWORD))<br>            AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);<br>        if(dwHead!=ACCEL_FILE_HEAD)<br>            AfxThrowFileException(CFileException::invalidFile,13,lpAppPath);</p> <p>        if(fAccel.Read(&dwCount,sizeof(DWORD))!=sizeof(DWORD))<br>            AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);<br>        <br>        ASSERT(m_lpAccel==NULL);<br>        <br>        m_lpAccel=new ACCELITEM[dwCount];<br>        memset(m_lpAccel,0,sizeof(ACCELITEM)*dwCount);<br>        m_dwAccelCount=dwCount;</p> <p>        for(DWORD dw=0;dw<dwCount;dw++)<br>        {<br>            if(fAccel.Read(m_lpAccel+dw,sizeof(ACCELITEM))!=sizeof(ACCELITEM))<br>                AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);<br>        }</p> <p>        ACCEL* pAccel=new ACCEL[dwCount];<br>        for(dw=0;dw<dwCount;dw++){<br>            pAccel[dw]=m_lpAccel[dw].accel;<br>        }</p> <p>        m_hActAccel=CreateAcceleratorTable(pAccel,dwCount);</p> <p>        return TRUE;</p> <p>    }</p> <p>    catch(CFileException* e)<br>    {<br>        char buf[256];<br>        char buf2[512];<br>        int iError;<br>        iError=e->m_cause;<br>        e->GetErrorMessage(buf,256);<br>        sprintf(buf2,"从文?\"%s\" 中加?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表时发生错误!\n"<br>                     "???%d\n"<br>                     "错误描述:%s\n"<br>                     "是否生成默认?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>?\n\0",<br>                     strAccelFileName,iError,buf);<br>        if(IDYES==AfxMessageBox(buf2,MB_YESNO|MB_SYSTEMMODAL|MB_ICONSTOP|MB_DEFBUTTON1))<br>        {<br>            ASSERT(m_hActAccel==NULL);<br>            ASSERT(m_lpAccel==NULL);<br>            m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);<br>            m_lpAccel=new ACCELITEM[m_dwAccelCount];<br>            memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);<br>            DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[30]);<br>            for(DWORD dw=0;dw<m_dwAccelCount;dw++){<br>                m_lpAccel[dw].accel=accel[dw];<br>                strcpy(m_lpAccel[dw].cCmd,dw<dwCmdStr?strCmd[dw]:"Command Unknow");<br>            }<br>            <br>            m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);<br>            SaveAccel();<br>            return TRUE;<br>        }<br>        return FALSE;<br>    }<br>}</p> <p>  最后,在DestroyWindow()函数头部增加对SaveAccel()函数的调用:(x)</p> <p>    SaveAccel();<br>    ...</p> <p>  好了(jin)Q你自己?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>数据已经能保存在文g中了(jin)Qƈ能从中正加载。如果文件不存在或程序读取时发现错误则提醒你是否建立~省?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表,如你认的话则生成缺省的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速键</strong>表ƈ立刻保存x件中?br>  ׃水^有限Q其中难免有误,Ƣ迎批评指正、发表你的意见。本Z胜感Ȁ?br></p> <img src ="http://www.shnenglu.com/tgh621/aggbug/71821.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tgh621/" target="_blank">大v</a> 2009-01-12 17:22 <a href="http://www.shnenglu.com/tgh621/archive/2009/01/12/71821.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Z?char** 不能自动转化?const char** (? http://www.shnenglu.com/tgh621/archive/2008/11/11/66588.html大v大vTue, 11 Nov 2008 03:23:00 GMThttp://www.shnenglu.com/tgh621/archive/2008/11/11/66588.htmlhttp://www.shnenglu.com/tgh621/comments/66588.htmlhttp://www.shnenglu.com/tgh621/archive/2008/11/11/66588.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/66588.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/66588.html

一ơ偶然的情况下我发现以下代码竟然无法被编译通过Q如果你的编译器Q比如VC6或VC2003Q允许它~译通过Q我想你首先应该换个~译器,比如GCC或VC2005Q:(x)
void foo( const char* [] ) { }
int main( void )
{
    char* s[2];
    foo( s );
}

化成更一般的形式是:(x)
char** p1 = 0;
const char** p2 = p1;

错误是:(x)invalid conversion from `char**' to `const char**'.

lostpencil更加仔细Q用C~译器给出的是一个警告:(x)
initialization from incompatible pointer type.

随后hphol出?jin)合理的解释Q同?a target=_blank>comp.lang.c++.moderated上的Ulrich Eckhardt也用代码q行?jin)说明?/p>

用代码来说明最直观?jin)?x)
const char* s = "abc";
int main( void )
{
    char* p0 = 0;
    char** p1 = &p0;
    const char** p2 = p1;
// 先假设这一句是合法?( 试Ӟ可以先强制类?strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">?/strong>化一?)
    *p2 = s;
    *p0 = 'A';
// 通过p0在修改不应该被修改的sQ这昄?strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">const相违背,其运行结果不可知?br>}




看了(jin) **?惛_?br>tekyDec 29, 2005 -  Show original item

看完?明白**讲的Z?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">char** 不能自动?/strong>化ؓ(f) const char**,(原文)但对我媄(jing)响最q是下面的?

==================================================================
char *p="abc" 能不能编译通过要看你用的~译器。鉴于大量遗留代码的存在Q大部分~译器允许其通过Q或者给个警告。当?dng)E序员自己必M证绝不去修改其倹{?

E序员不应该在代码中出现*p='A'q样的语句。这是当初约定好?jin)的Q编译器允许char *p="abc"通过Q而程序员保证不去修改它?
b. *p='A'~译时应该允?dng)R过Q因为单p条语句而言Q它完全合法?
c. q行?p='A'能不能通过要看实际的运行环境,包括你用的操作pȝ、编译器、编译器选项 {等Q一句话Q其q行l果׃得你Q且不应该由你去兛_(j)Q因U行为本w已l违反约定了(jin)?
==================================================================

工作关系?用CString 和string用的太多?很少q样定义字符?char *p=“abcde“?br>匝一?q不适应,:(,渐渐的回x惌v一些来(?q是太生?赶快写下?以后别忘?

q样定义的字W串char *p=“abcde“ ; char *p1=“123445667“;

正如上面提到的是不能?*p='A',q行的时候会(x)出错,同样,strcpy(p,p1)也会(x)出错?

"abcde"字符串可以看做是个常量字W串?是不能被修改?

但如?char p[]=“abcde“ q样定义,没有问?你可以修?p='A',只要不越界就ok.

q且发现q样两种定义
char *p=“abcde“

char p[]=“abcde“

在运行的时?p指向的地址也不是一L(fng),可见char *p=“abcde“q是有特D的处理 :),具体怎么处理׃知道?高手h?)


随着试,又发C问题,可能是个老问题了(jin)?


int main(int argc, char* argv[])
{
 int t[10];
 char p1[7]="123456";
 const char *p2="1234567890123213123";
 
 int len(0);
 
  //*p1='C';  err

 len=strlen(p1);
 printf("%d\n",len);
 
 strcpy(p1,p2);   ///??????????
 
 printf("%s\n",p1);
 
 len=strlen(p1);
 
 printf("%d\n",len);
 return 0;
}

我定义的?个字W数l? 但用strcpy把p2拷到p1?p1是放不下?但程序却正常执行,warning ,err都没?q行也正?


输出

6
1234567890123213123
19

应该是用内存越界了(jin)??怎么?x)正常运行?

N对于内存界的?q气好才崩溃表现出来,q气不好正常运??

posted on 2006-02-22 13:04 Vincent.Chen 阅读(232) 评论(0)  ~辑  收藏 所属分c? ?/font>



大v 2008-11-11 11:23 发表评论
]]>
【{】向Lq程注入DLLhttp://www.shnenglu.com/tgh621/archive/2008/09/28/62974.html大v大vSun, 28 Sep 2008 04:24:00 GMThttp://www.shnenglu.com/tgh621/archive/2008/09/28/62974.htmlhttp://www.shnenglu.com/tgh621/comments/62974.htmlhttp://www.shnenglu.com/tgh621/archive/2008/09/28/62974.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/62974.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/62974.html可能q对高手来说已经是老掉牙的东西?

q是来说说原理把(本h也是菜鸟?!
q程注入是在目标进E中用VirtualAllocEx甌一D内?
然后用WriteProcessMemory函数自己dll的完整\径复制到q程q程?
然后在Kernel32中计LoadLibraryA的地址,再调用LoadLibraryA函数加蝲q程dll,
q在CreateRemoteThread创徏q程q程!
Code Language : C
#include \"stdafx.h\"
#include \"windows.h\"
#include \"tlhelp32.h\"
#include \"stdio.h\"
#pragma comment(lib,\"ws2_32\")
 
int EnableDebugPriv(const char * name)//提提权函?br>{
  HANDLE hToken;
  TOKEN_PRIVILEGES tp;
  LUID luid;
  //打开q程令牌?br>  if(!OpenProcessToken(GetCurrentProcess(),
  TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
    &hToken))
  {
    MessageBox(NULL,\"OpenProcessToken Error!\",\"Error!\",MB_OK);
     return 1;
 }
 //获得q程本地唯一ID
 if(!LookupPrivilegeValue(NULL,name,&luid))
 {
   MessageBox(NULL,\"LookupPrivivlegeValue Error!\",\"Error\",MB_OK);
 }
 tp.PrivilegeCount=1;
 tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
 tp.Privileges[0].Luid=luid;
 //调整权限
 if(!AdjustTokenPrivileges(hToken,0,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))
 {
   MessageBox(NULL,\"AdjustTokenPrivileges Error!\",\"Error\",MB_OK);
   return 1;
 }
 return 0;
}
BOOL injectit(const char *DllPath,const DWORD dwRemoteProcessld)//注入d?br>{
 HANDLE hrp;
 if(EnableDebugPriv(SE_DEBUG_NAME))
 {
   MessageBox(NULL,\"Add Privilege Error!\",\"Error\",MB_OK);
   return FALSE;
 }
 if((hrp=OpenProcess(PROCESS_CREATE_THREAD|//允许q程创徏U程
   PROCESS_VM_OPERATION|//允许q程VM操作
   PROCESS_VM_WRITE,//允许q程VM?br>   FALSE,dwRemoteProcessld))==NULL)
 {
   MessageBox(NULL,\"OpenProcess Error!\",\"Error\",MB_OK);
   return FALSE;
 }
 char *psLibFileRemote;
 //使用VirtualAllocEx函数在远E进E的内存地址I间分配DLL文g名缓?br> psLibFileRemote=(char *)VirtualAllocEx(hrp,NULL,lstrlen(DllPath)+1,
   MEM_COMMIT,PAGE_READWRITE);
 if(psLibFileRemote==NULL)
 {
   MessageBox(NULL,\"VirtualAllocEx Error!\",\"Error\",MB_OK);
   return FALSE;
 }
 //使用WriteProcessMemory函数DLL的\径名复制到远E的内存I间
 if(WriteProcessMemory(hrp,psLibFileRemote,(void *)DllPath,lstrlen(DllPath)+1,NULL)==0)
 {
   MessageBox(NULL,\"WriteProcessMemory Error!\",\"Error\",MB_OK);
   return FALSE;
 }
 //计算LoadLibraryA的入口地址
 PTHREAD_START_ROUTINE pfnStartAddr=(PTHREAD_START_ROUTINE)
   GetProcAddress(GetModuleHandle(TEXT(\"Kernel32\")),\"LoadLibraryA\");
 if(pfnStartAddr==NULL)
 {
   MessageBox(NULL,\"GetProcAddress Error!\",\"Error\",MB_OK);
   return FALSE;
 }
 //pfnStartAddr地址是LoadLibraryA的入口地址
 
 
 HANDLE hrt;
 if((hrt=CreateRemoteThread(hrp,
   NULL,
   0,
   pfnStartAddr,
   psLibFileRemote,
   0,
   NULL))==NULL)
 {
   MessageBox(NULL,\"CreateRemote Error!\",\"Error\",MB_OK);
   return FALSE;
 }
 return TRUE;
}
unsigned long getpid(char *pn)//得到q程pid
{
 BOOL b;
 HANDLE hnd;
 PROCESSENTRY32 pe;
 //得到q程快照
 hnd=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 pe.dwSize=sizeof(pe);
 b=Process32First(hnd,&pe);
 while(b)
 {
   if(strcmp(pn,pe.szExeFile)==0)
     return pe.th32ProcessID;
   b=Process32Next(hnd,&pe);
 }
}
 
int main(int argc, char* argv[])
{
 if(argc<2)
 {
   printf(\"++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\");
   printf(\"injectpro V1.0!\nAuthor:text QQ:52674548\nusage:\n injectpro.exe targetprocess youdll\n\");
   printf(\" eg:injectpro.exe iexplorer.exe c:\\youdll.dll\n\");
   printf(\"++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\");
   return 0;
 }
 EnableDebugPriv(SE_DEBUG_NAME);//自n提权
 DWORD pid=getpid(argv[1]);
 //printf(\"%d\",pid);
 if(pid==0)
   return 1;
   if(injectit(argv[2],pid))
   {
     printf(\"inject success!\");
   }
   else
   {
     printf(\"inject error!\");
   }
 return 0;
}

本篇文章来源?黑反在线-信息安全W一?原文链接Q?a >http://www.hf110.com/hack/hackprg/200809/203556.html



大v 2008-09-28 12:24 发表评论
]]>
[转]怎样自qDLL加蝲到Explorer.exehttp://www.shnenglu.com/tgh621/archive/2008/09/28/62966.html大v大vSun, 28 Sep 2008 03:34:00 GMThttp://www.shnenglu.com/tgh621/archive/2008/09/28/62966.htmlhttp://www.shnenglu.com/tgh621/comments/62966.htmlhttp://www.shnenglu.com/tgh621/archive/2008/09/28/62966.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/62966.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/62966.html




  本文讨ZU将动态连接库注入到其他进E中的一U新Ҏ(gu)。它的思\与用函数CreateRemoteThread的方法相cMQ只不过可以使用在Win9x,Win2k,WinXP{操作系l下。在q里我们向读者演C我们是如何DLL(InjectDll.dll)注入到Explorer.exeq程中!





E序的思\如下

1Q得到Explorer.exeq程中Q意一个线E的ID.

2Q根据这个线E的IDQ得到这个线E的句柄Handle

3Q挂赯个线E,q保存线E当前的“上下?#8221;

4Q改变这个线E的EIP指针Q它指向我们装载DLL的函敎ͼInjectCodeFunQ,然后恢复q个U程?br>
5Q我们的装蝲DLL的函数运行完成后Q再ơ挂赯个线E,使用我们以前保存?#8220;上下?#8221;Q恢复这个线E到它被改变前的状态,ql运行?br>
l过上述几个步骤QExplorer.exeq程中就?x)替我们装蝲我们的DLL(InjectDll.dll)?jin),有趣的是Explorer.exeҎ(gu)丝毫没有察觉M异常 Q?br>




下面我们详l解释一下如何编E实Cq过E?br>
步骤1的实现是很容易的Q我们只需要调用ToolHelp的函数就可以得到我们所要得Q这里我们就不详l说明了(jin)Q请参考源代码中GetProcessID, GetThreadID 两个函数?br>


步骤2比较麻?ch)?jin)Q在Win9x中没有提供一个函数可以由Thread ID得到Thread HandleQ幸q的是Win2K提供q种功能Q。好在我们在国外一些BBS上可以找到这个函敎ͼ它用了(jin)一些未公开的结构,本文的目的不是讨个问题,读者如果有兴趣的话Q可以参考我们的源代码OpenThread2函数。这个函数的作用是传入一个Thread ID参数q回相应?Thread Handle?br>


步骤3 的实C是很Ҏ(gu)和规范的Q我们可以用SuspendThreadQGetThreadContext{SDK函数L完成?br>


步骤4 q个步骤是最重要的步骤了(jin)。ؓ(f)?jin)说明方便,我们引用我们源代码中的语句Q请读者参考源代码中InjectCodeIntoThread 函数?br>
首先改变U程的EIP指针Q我们可以用下列代码完成

ThreadContext.Eip = (DWORD)m_lpCodeBase;

SetThreadContext(m_hInjectThread,&ThreadContext)Q?br>
变量m_lpCodeBase指向我们的装载DLL的函敎ͼInjectCodeFunQ的首地址?br>
q里最关键的部分是我们如何产生我们的装载DLL的函敎ͼInjectCodeFunQ。注意我们不能简单地在我们的E序里写一个函敎ͼ然后它的首地址赋值给EIP。这是因载DLL的函数是要运行在Explorer.exe地址I间中的Q如果我们用自己地址I间中的函数的话Q那么必然会(x)Dpȝ崩溃。解决的办法是将我们写的装蝲DLL函数QInjectCodeFunQ放在所有程序共享的地址I间中去Q在Win9x?x80000000 ~ 0xFFFFFFFFq段地址是我们惌的共享地址I间Q那么如何将我们写的装蝲DLL函数攑֜q段地址I间?Q方法有很多Q我们用一U规范的Ҏ(gu)“内存映像文g”来解册个问题。我们通过函数CreateFileMapping来分配一D共享地址I间Q然后将我们写的装蝲DLL函数拯到这D地址I间中去。具体代码请参源代码中InitInject函数?br>
在我们写的装载DLL函数QInjectCodeFunQ中q有两个问题我们需要解释一下,W一 在这个函C我们不能使用M我们自己E序中定义的变量Q道理跟上面讲的一P因ؓ(f)地址I间不同。还有我们不能直接调用函敎ͼ例如在InjectCodeFun中直接用LoadLibray。这是因为如果直接用LoadLibray那么需要经q程序的Import表,跌{一下才能到辄正的Windows的LoadLibray函数。但是不同的q程有不同的ImportQ所以我们不能直接调用函数。我们可以用一U叫?#8220;动态构造函?#8221;的技术来创徏我们的函数。首先用GetProcAddress得到函数LoadLibray的直接地址Q然后在调用LoadLibray的地方,使用一个特D的数字来代替它?0x11111111Q最后在我们的函数拯到共享地址I间之后Q搜索共享内存找到这个特D数字,用我们先前得到的正确地址替换它既可。第二个有趣的现象是我们所写的装蝲DLL函数QInjectCodeFunQ是不应该返回的。这是因个函数是在Explorer的线E中q行的,我们不知道堆栈的正确内容Q不知道ESP所指向的地址是什么,如果函数q回的话Q我们将失去对程序的控制。我们的办法是,当调用完LoadLibray之后Q向我们的主E序发送一个自定义消息Q通告我们的程序已l完成装载Q务,然后让线E进入死循环状态?br>


步骤5当我们的E序接受C(jin)自定义消息后Q就?x)再ơ挂赯个线E,把我们以前保存的U程?#8220;上下?#8221;用函数SetThreadContext恢复Q然后恢复运行这个线E。结果是Explorer.exe丝毫没有感觉到自p中断q?br>




以上是我们所介绍的方法,读者可以参考我们的源代码来具体?jin)解上述?gu)。源代码的功能是我们的DLL(InjectDll.dll)注入到Explorer.exe 中,在InjectDll.dll中我们创Z(jin)一个新的线E,然后在屏q的左上角显C当前的旉。源代码分ؓ(f)Win9x版本和W(xu)in2k版本Q这两个版本的主要差别是分配׃n内存的方法不同而已。源代码已经在PWn98,PwinMe,Win2k,WinXP{操作系l下Q用VC6~译通过?

大v 2008-09-28 11:34 发表评论
]]>
UNICODE串{换成charcd串的四种Ҏ(gu)[转]http://www.shnenglu.com/tgh621/archive/2008/09/27/62924.html大v大vSat, 27 Sep 2008 10:11:00 GMThttp://www.shnenglu.com/tgh621/archive/2008/09/27/62924.htmlhttp://www.shnenglu.com/tgh621/comments/62924.htmlhttp://www.shnenglu.com/tgh621/archive/2008/09/27/62924.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/62924.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/62924.html1. 调用 WideCharToMultiByte() API

int WideCharToMultiByte (
    UINT    CodePage,                
//1 Unicode~码的字W页QUnicode~码有字W页的概念,比如gb2312/936Qbig5/950{?/span>
    DWORD   dwFlags,                //2 如何处理复合unicode字符Q详l查google
    LPCWSTR lpWideCharStr,        //3 待{换的unicode?/span>
    int     cchWideChar,                //4 表示参数3的长?nbsp; 传?1表示?x00l尾
    LPSTR   lpMultiByteStr,            //5 接受转换后的串的字符~冲
    int     cbMultiByte,                    //6 表示参数5lpMutiByteStr的字节大?nbsp;通常sizeof一?/span>
    LPCSTR  lpDefaultChar,        //7 NULL 具体google
    LPBOOL  lpUsedDefaultChar//8 NULL 具体google
);

2. 调用CRT函数wcstombs()

size_t wcstombs (
    
char*          mbstr,
    
const wchar_t* wcstr,
    size_t         count );

3. 使用CString构造器或赋值操?/p>

// 假设有一个Unicode串wszSomeString

CString str1 ( wszSomeString ); 
// 用构造器转换
CString str2;

str2 
= wszSomeString; // 用赋值操作{?/span>

4. 使用ATL串{换宏

#include <atlconv.h>

// q是假设有一个Unicode串wszSomeString

{
    
char szANSIString [MAX_PATH];
    USES_CONVERSION; 
// 声明q个宏要使用的局部变?/span>

    lstrcpy ( szANSIString, OLE2A(wszSomeString) );
}



大v 2008-09-27 18:11 发表评论
]]>
自绘按钮补遗【{?/title><link>http://www.shnenglu.com/tgh621/archive/2008/09/25/62779.html</link><dc:creator>大v</dc:creator><author>大v</author><pubDate>Thu, 25 Sep 2008 12:19:00 GMT</pubDate><guid>http://www.shnenglu.com/tgh621/archive/2008/09/25/62779.html</guid><wfw:comment>http://www.shnenglu.com/tgh621/comments/62779.html</wfw:comment><comments>http://www.shnenglu.com/tgh621/archive/2008/09/25/62779.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/tgh621/comments/commentRss/62779.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tgh621/services/trackbacks/62779.html</trackback:ping><description><![CDATA[     摘要:   <a href='http://www.shnenglu.com/tgh621/archive/2008/09/25/62779.html'>阅读全文</a><img src ="http://www.shnenglu.com/tgh621/aggbug/62779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tgh621/" target="_blank">大v</a> 2008-09-25 20:19 <a href="http://www.shnenglu.com/tgh621/archive/2008/09/25/62779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决Visual C++ ~译器中混合 .c 文g时收?C1853 预编译头错误的方法(转)(j)http://www.shnenglu.com/tgh621/archive/2008/09/25/62764.html大v大vThu, 25 Sep 2008 08:02:00 GMThttp://www.shnenglu.com/tgh621/archive/2008/09/25/62764.htmlhttp://www.shnenglu.com/tgh621/comments/62764.htmlhttp://www.shnenglu.com/tgh621/archive/2008/09/25/62764.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/62764.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/62764.html阅读全文

大v 2008-09-25 16:02 发表评论
]]>
字符串{换_BSTR/LPSTR/LPWSTR/Char http://www.shnenglu.com/tgh621/archive/2008/09/02/60729.html大v大vTue, 02 Sep 2008 10:20:00 GMThttp://www.shnenglu.com/tgh621/archive/2008/09/02/60729.htmlhttp://www.shnenglu.com/tgh621/comments/60729.htmlhttp://www.shnenglu.com/tgh621/archive/2008/09/02/60729.html#Feedback0http://www.shnenglu.com/tgh621/comments/commentRss/60729.htmlhttp://www.shnenglu.com/tgh621/services/trackbacks/60729.html一、BSTR、LPSTR和LPWSTR
在Visual C++.NET的所有编E方式中Q我们常常要用到q样的一些基本字W串cdQ如BSTR、LPSTR和LPWSTR{。之所以出现类gq的q些数据cdQ是因ؓ(f)不同~程语言之间的数据交换以?qing)对ANSI、Unicode和多字节字符?MBCS)的支持?/p>

  那么什么是BSTR、LPSTR以及(qing)LPWSTR呢?

  BSTR(Basic STRingQBasic字符?是一个OLECHAR*cd的Unicode字符丌Ӏ它被描q成一个与自动化相兼容的类型。由于操作系l提供相应的API函数(如SysAllocString)来管理它以及(qing)一些默认的调度代码Q因此BSTR实际上就是一个COM字符Ԍ但它却在自动化技术以外的多种场合下得到广泛用。图1描述?jin)BSTR的结构,其中DWORD值是字符串中实际所占用的字节数Q且它的值是字符串中Unicode字符的两倍?/p>

  LPSTR和LPWSTR是Win32和VC++所使用的一U字W串数据cd。LPSTR被定义成是一个指向以NULL(‘\0’)l尾?位ANSI字符数组指针Q而LPWSTR是一个指向以NULLl尾?6位双字节字符数组指针。在VC++中,q有cM的字W串cdQ如LPTSTR、LPCTSTR{,它们的含义如?所C?/p>

  例如QLPCTSTR是指“long pointer to a constant generic string”Q表C?#8220;一个指向一般字W串帔R的长指针cd”Q与C/C++的const char*相映,而LPTSTR映射?char*?/p>

  一般地Q还有下列类型定义:(x)

#ifdef UNICODE
typedef LPWSTR LPTSTR;
typedef LPCWSTR LPCTSTR;
#else
typedef LPSTR LPTSTR;
typedef LPCSTR LPCTSTR;
#endif

二、CString、CStringA ?CStringW

  Visual C++.NET中将CStringT作ؓ(f)ATL和MFC的共享的“一?#8221;字符串类Q它有CString、CStringA和CStringW三种形式Q分别操作不同字W类型的字符丌Ӏ这些字W类型是TCHAR、char和wchar_t。TCHAR在Unicodeq_中等同于WCHAR(16位Unicode字符)Q在ANSI中等价于char。wchar_t通常定义为unsigned short。由于CString在MFC应用E序中经常用刎ͼq里不再重复?/p>

三、VARIANT、COleVariant 和_variant_t

  在OLE、ActiveX和COM中,VARIANT数据cd提供?jin)一U非常有效的机制Q由于它既包含了(jin)数据本nQ也包含?jin)数据的cdQ因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文g中VARIANT定义的一个简化版Q?/p>

struct tagVARIANT {
VARTYPE vt;
union {
short iVal; // VT_I2.
long lVal; // VT_I4.
float fltVal; // VT_R4.
double dblVal; // VT_R8.
DATE date; // VT_DATE.
BSTR bstrVal; // VT_BSTR.

short * piVal; // VT_BYREF|VT_I2.
long * plVal; // VT_BYREF|VT_I4.
float * pfltVal; // VT_BYREF|VT_R4.
double * pdblVal; // VT_BYREF|VT_R8.
DATE * pdate; // VT_BYREF|VT_DATE.
BSTR * pbstrVal; // VT_BYREF|VT_BSTR.
};
};

  昄QVARIANTcd是一个Cl构Q它包含?jin)一个类型成员vt、一些保留字节以?qing)一个大的unioncd。例如,如果vt为VT_I2Q那么我们可以从iVal中读出VARIANT的倹{同P当给一个VARIANT变量赋值时Q也要先指明其类型。例如:(x)

VARIANT va;
:: VariantInit(&va); // 初始?br>int a = 2002;
va.vt = VT_I4; // 指明long数据cd
va.lVal = a; // 赋?/p>

  Z(jin)方便处理VARIANTcd的变量,W(xu)indowsq提供了(jin)q样一些非常有用的函数Q?/p>

  VariantInit —?变量初始化为VT_EMPTYQ?/p>

  VariantClear —?消除q初始化VARIANTQ?/p>

  VariantChangeType —?改变VARIANT的类型;

  VariantCopy —?释放与目标VARIANT相连的内存ƈ复制源VARIANT?/p>

  COleVariantcL对VARIANTl构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInitq行初始化,然后Ҏ(gu)参数中的标准cd调用相应的构造函敎ͼq用VariantCopyq行转换赋值操作,当VARIANT对象不在有效范围Ӟ它的析构函数׃(x)被自动调用,׃析构函数调用?jin)VariantClearQ因而相应的内存׃(x)被自动清除。除此之外,COleVariant的赋值操作符在与VARIANTcd转换中ؓ(f)我们提供极大的方ѝ例如下面的代码Q?/p>

COleVariant v1("This is a test"); // 直接构?br>COleVariant v2 = "This is a test";
// l果是VT_BSTRcdQgؓ(f)"This is a test"
COleVariant v3((long)2002);
COleVariant v4 = (long)2002;
// l果是VT_I4cdQgؓ(f)2002

  _variant_t是一个用于COM的VARIANTc,它的功能与COleVariant怼。不q在Visual C++.NET的MFC应用E序中用时需要在代码文g前面d下列两句Q?/p>

  #include "comutil.h"

  #pragma comment( lib, "comsupp.lib" )

四、CComBSTR和_bstr_t

  CComBSTR是对BSTR数据cd装的一个ATLc,它的操作比较方便。例如:(x)

CComBSTR bstr1;
bstr1 = "Bye"; // 直接赋?br>OLECHAR* str = OLESTR("ta ta"); // 长度?的宽字符
CComBSTR bstr2(wcslen(str)); // 定义长度?
wcscpy(bstr2.m_str, str); // 宽字符串复制到BSTR?br>CComBSTR bstr3(5, OLESTR("Hello World"));
CComBSTR bstr4(5, "Hello World");
CComBSTR bstr5(OLESTR("Hey there"));
CComBSTR bstr6("Hey there");
CComBSTR bstr7(bstr6);
// 构造时复制Q内容ؓ(f)"Hey there"

  _bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数Q其他操作是借用BSTR API函数。与_variant_t怼Q用时也要dcomutil.h和comsupp.lib?/p>

五、BSTR、char*和CString转换

  (1) char*转换成CString

  若将char*转换成CStringQ除?jin)直接赋值外Q还可用CString::Formatq行。例如:(x)

char chArray[] = "This is a test";
char * p = "This is a test";

  ?/p>

LPSTR p = "This is a test";

  或在已定义Unicode应的用程序中

TCHAR * p = _T("This is a test");

  ?/p>

LPTSTR p = _T("This is a test");
CString theString = chArray;
theString.Format(_T("%s"), chArray);
theString = p;

  (2) CString转换成char*

  若将CStringc{换成char*(LPSTR)cdQ常怋用下列三U方法:(x)

  Ҏ(gu)一Q用强制{换。例如:(x)

CString theString( "This is a test" );
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;

  Ҏ(gu)二,使用strcpy。例如:(x)

CString theString( "This is a test" );
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
_tcscpy(lpsz, theString);

  需要说明的是,strcpy(或可UdUnicode/MBCS的_tcscpy)的第二个参数?const wchar_t* (Unicode)或const char* (ANSI)Q系l编译器会(x)自动对其q行转换?/p>

  Ҏ(gu)三,使用CString::GetBuffer。例如:(x)

CString s(_T("This is a test "));
LPTSTR p = s.GetBuffer();
// 在这里添加用p的代?br>if(p != NULL) *p = _T('\0');
s.ReleaseBuffer();
// 使用完后?qing)时释放Q以便能使用其它的CString成员函数

  (3) BSTR转换成char*

  Ҏ(gu)一Q用ConvertBSTRToString。例如:(x)

#include "comutil.h"
#pragma comment(lib, "comsupp.lib")
int _tmain(int argc, _TCHAR* argv[]){
BSTR bstrText = ::SysAllocString(L"Test");
char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
SysFreeString(bstrText); // 用完释放
delete[] lpszText2;
return 0;
}

   ** 此方法不好,?x)造成内存泄露QSysFreeString也没有效果?/font>

  Ҏ(gu)二,使用_bstr_t的赋D符重蝲。例如:(x)

_bstr_t b = bstrText;
char* lpszText2 = b;   

* 不会(x)有内存泄Ԍ推荐Ҏ(gu)

  (4) char*转换成BSTR

  Ҏ(gu)一Q用SysAllocString{API函数。例如:(x)

BSTR bstrText = ::SysAllocString(L"Test");
BSTR bstrText = ::SysAllocStringLen(L"Test",4);
BSTR bstrText = ::SysAllocStringByteLen("Test",4);

  Ҏ(gu)二,使用COleVariant或_variant_t。例如:(x)

//COleVariant strVar("This is a test");
_variant_t strVar("This is a test");
BSTR bstrText = strVar.bstrVal;

  Ҏ(gu)三,使用_bstr_tQ这是一U最单的Ҏ(gu)。例如:(x)

BSTR bstrText = _bstr_t("This is a test");

  Ҏ(gu)四,使用CComBSTR。例如:(x)

BSTR bstrText = CComBSTR("This is a test");

  ?/p>

CComBSTR bstr("This is a test");
BSTR bstrText = bstr.m_str;

  Ҏ(gu)五,使用ConvertStringToBSTR。例如:(x)

char* lpszText = "Test";
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);

  (5) CString转换成BSTR

  通常是通过使用CStringT::AllocSysString来实现。例如:(x)

CString str("This is a test");
BSTR bstrText = str.AllocSysString();

SysFreeString(bstrText); // 用完释放

  (6) BSTR转换成CString

  一般可按下列方法进行:(x)

BSTR bstrText = ::SysAllocString(L"Test");
CStringA str;
str.Empty();
str = bstrText;

  ?/p>

CStringA str(bstrText);

  (7) ANSI、Unicode和宽字符之间的{?/p>

  Ҏ(gu)一Q用MultiByteToWideCharANSI字符转换成Unicode字符Q用WideCharToMultiByteUnicode字符转换成ANSI字符?/p>

  Ҏ(gu)二,使用“_T”ANSI转换?#8220;一?#8221;cd字符Ԍ使用“L”ANSI转换成UnicodeQ而在托管C++环境中还可用SANSI字符串{换成String*对象。例如:(x)

TCHAR tstr[] = _T("this is a test");
wchar_t wszStr[] = L"This is a test";
String* str = S”This is a test”;

  Ҏ(gu)三,使用ATL 7.0的{换宏和类。ATL7.0在原?.0基础上完善和增加?jin)许多字W串转换宏以?qing)提供相应的c,它具有如?所C的l一形式Q?/p>

  其中Q第一个C表示“c?#8221;Q以便于ATL 3.0宏相区别Q第二个C表示帔RQ?表示“to”QEX表示要开辟一定大的~冲。SourceType和DestinationType可以是A、T、W和OLEQ其含义分别是ANSI、Unicode?#8220;一?#8221;cd和OLE字符丌Ӏ例如,CA2CT是ANSI转换成一般类型的字符串常量。下面是一些示例代码:(x)

LPTSTR tstr= CA2TEX<16>("this is a test");
LPCTSTR tcstr= CA2CT("this is a test");
wchar_t wszStr[] = L"This is a test";
char* chstr = CW2A(wszStr);



大v 2008-09-02 18:20 发表评论
]]>
þþþþþۺձ| þùƷ԰| þþ| ٸþþþþñŪ߳| һɫۺϾþ| þþƷwwwˬ| þþþƷ| ޹Ʒ˾þ| Ʒþþþ| þþþ| һƷ˾þ| ˼˼þ99ֻƵƷ66| þ޹ӰԺվ| ձƷþþþþþþ| þ¾ƷĻ| þоƷ| ղƷþþþþþ| 91Ʒþþþþ | ?VþþƷ| þһ99| 㽶þþþþúݺɫ| 99REþþƷﶼǾƷ| ޹徫Ʒ߾þ| ɫݺݾþۺ| þþþAvר| ݹ˾þ91| þü¶| Ʒþþһ| ɫþþۺ | ӰԺ˾þ| þøƬ| þþƷAVӰԺ | 91Ըߺþþþ| ձþþþþþþþ| ۺϾþùһ鶹| ھƷþþӰԺ| ۲ӰԺþùƷ| ˳ɵӰվþ| Ʒþù鶹99վ| ھƷþþþþĻ| þ99þ99Ʒӿ |