﻿<?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>博客园-日日新</title><link>http://www.cnblogs.com/Wiseman/</link><description>苟日新</description><language>zh-cn</language><lastBuildDate>Sun, 23 Nov 2008 08:51:50 GMT</lastBuildDate><pubDate>Sun, 23 Nov 2008 08:51:50 GMT</pubDate><ttl>60</ttl><item><title>动态库的调用等技术</title><link>http://www.cnblogs.com/Wiseman/archive/2006/03/13/348758.html</link><dc:creator>吴文力</dc:creator><author>吴文力</author><pubDate>Mon, 13 Mar 2006 01:37:00 GMT</pubDate><guid>http://www.cnblogs.com/Wiseman/archive/2006/03/13/348758.html</guid><wfw:comment>http://www.cnblogs.com/Wiseman/comments/348758.html</wfw:comment><comments>http://www.cnblogs.com/Wiseman/archive/2006/03/13/348758.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnblogs.com/Wiseman/comments/commentRss/348758.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/Wiseman/services/trackbacks/348758.html</trackback:ping><description><![CDATA[较大的应用程序都由很多模块组成，这些模块分别完成相对独立的功能，它们彼此协作来完成整个软件系统的工作。在构造软件系统时，如果将所有模块的源代码都静态编译到整个应用程序的EXE文件中，会产生一些问题：一个缺点是增加了应用程序的大小，它会占用更多的磁盘空间，程序运行时也会消耗较大的内存空间，造成系统资源的浪费；另一个缺点是，在编写大的EXE程序时，在每次修改重建时都必须调整编译所有源代码，增加了编译过程的复杂性，也不利于阶段性的单元测试；而且，一些模块的功能可能较为通用，在构造其它软件系统时仍会被使用。<BR>　　<BR>　　Windows系统平台上提供了一种完全不同的较有效的编程和运行环境，你可以将独立的程序模块创建为较小的动态链接库(Dynamic Linkable Library，DLL)文件，并可对它们单独编译和测试。在运行时，只有当EXE程序确实要调用这些DLL模块的情况下，系统才会将它们装载到内存空间中。这种方式不仅减少了EXE文件的大小和对内存空间的需求，而且使这些DLL模块可以同时被多个应用程序使用。<BR>　　<BR>　　动态链接库概述<BR>　　<BR>　　动态链接库技术是Windows最重要的实现技术之一，Windows的许多新功能、新特性都是通过DLL来实现的。其实，Windows本身就是由许多DLL组成的，它最基本的三大组成模块Kernel、GDI和User都是DLL。<BR>　　<BR>　　一般来说，DLL是一种磁盘文件，以.dll、.DRV、.FON、.SYS和许多以.EXE为扩展名的系统文件都可以是DLL。它由全局数据、服务函数和资源组成，在运行时被系统加载到进程的虚拟空间中，成为调用进程的一部分。如果与其它DLL之间没有冲突，该文件通常映射到进程虚拟空间的同一地址上。DLL模块中包含各种导出函数，用于向外界提供服务，Windows在加载DLL模块时将进程函数调用与DLL文件的导出函数相匹配。DLL可以有自己的数据段，但没有自己的堆栈，DLL模块需要的堆栈内存都是从运行进程的堆栈中分配出来的，使用与调用它的应用程序相同的堆栈模式；一个DLL在内存中只有一个实例；DLL实现了代码封装性；DLL的编制与具体的编程语言及编译器无关。<BR>　　<BR>　　动态链接库的分类<BR>　　<BR>　　微软的Visual C++支持三种DLL，它们分别是Non-MFC Dll（非MFC动态库）、Regular Dll（常规DLL）、Extension Dll（扩展DLL）。<BR>　　<BR>　　1、Non-MFC DLL（非MFC动态库）<BR>　　<BR>　　这种动态链接库指的是不用MFC的类库结构，直接用C语言写的DLL，其导出的函数是标准的C接口，能被非MFC或MFC编写的应用程序所调用。如果建立的DLL不需要使用MFC，那么应该建立Non-MFC DLL，因为使用MFC会增大用户库的大小，从而浪费用户的磁盘和内存空间。<BR>　　<BR>　　2、Regular DLL（常规DLL）<BR>　　<BR>　　这种动态链接库和下述的Extension Dll一样，是用MFC类库编写的，它的一个明显的特点是在源文件里有一个继承CWinApp的类（注意：此类DLL虽然从CWinApp派生，但没有消息循环）,被导出的函数是C函数、C++类或者C++成员函数（注意不要把术语C++类与MFC的微软基础C++类相混淆），调用常规DLL的应用程序不必是MFC应用程序，只要是能调用类C函数的应用程序就可以，它们可以是在Visual C++、Delphi、Visual Basic、Borland C等编译环境下利用DLL开发应用程序。常规DLL又可细分成静态链接到MFC和动态链接到MFC两种：<BR>　　<BR>　　（1）静态连接到MFC的动态连接库只被VC的专业般和企业版所支持。该类DLL里的输出函数可以被任意Win32程序使用，包括使用MFC的应用程序。输出函数有如下形式：<BR>　　<BR>　　extern "C" EXPORT YourExportedFunction( );<BR>　　<BR>　　如果没有extern "C"修饰，输出函数仅仅能从C++代码中调用。<BR>　　<BR>　　（2）动态链接到MFC的常规DLL里的输出函数可以被任意Win32程序使用，包括使用MFC的应用程序。所有从DLL输出的函数应该以如下语句开始：<BR>　　<BR>　　AFX_MANAGE_STATE(AfxGetStaticModuleState( ))<BR>　　<BR>　　此语句用来正确地切换MFC模块状态。<BR>　　<BR>　　3、Extension Dll（扩展DLL）<BR>　　<BR>　　这种动态链接库是使用MFC的动态链接版本所创建的，并且它只被用MFC类库所编写的应用程序所调用。例如你已经创建了一个从MFC的CtoolBar类的派生类用于创建一个新的工具栏，为了导出这个类，你必须把它放到一个MFC扩展的DLL中。扩展DLL 和常规DLL不一样，它没有一个从CWinApp继承而来的类的对象，所以，开发人员必须在DLL中的DllMain函数添加初始化代码和结束代码。与常规DLL相比，扩展的DLL有如下不同点：<BR>　　<BR>　　1) 它没有一个从CWinApp派生的对象；<BR>　　<BR>　　2) 它必须有一个DLLMain函数；<BR>　　<BR>　　3) DLLMain调用AfxInitExtensionModule函数，必须检查该函数的返回值，如果返回0，DLLMmain也返回0；<BR>　　<BR>　　4) 如果它希望输出CRuntimeClass类型的对象或者资源(Resources)，则需要提供一个初始化函数来创建一个CDynLinkLibrary对象。并且，有必要把初始化函数输出；<BR>　　<BR>　　5) 使用扩展DLL的MFC应用程序必须有一个从CWinApp派生的类，而且，一般在InitInstance里调用扩展DLL的初始化函数。<BR>　　<BR>　　动态连接库的建立<BR>　　<BR>　　1、Non-MFC DLL的建立<BR>　　<BR>　　每一个DLL必须有一个入口点，就象用C编写的应用程序时，必须有一个WINMAIN函数一样。在Non-MFC DLL中DllMain是一个缺省的入口函数，你不需要编写自己的DLL入口函数，用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化。如果应用程序的DLL需要分配额外的内存或资源，或者说需要对每个进程或线程初始化和清除操作时，需要在相应的DLL工程的.CPP文件中对DllMain()函数按照下面的格式书写。<BR>　　<BR>　　BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)<BR>　　{<BR>　　switch( ul_reason_for_call )<BR>　　{<BR>　　case DLL_PROCESS_ATTACH:<BR>　　.......<BR>　　case DLL_THREAD_ATTACH:<BR>　　.......<BR>　　case DLL_THREAD_DETACH:<BR>　　.......<BR>　　case DLL_PROCESS_DETACH:<BR>　　.......<BR>　　}<BR>　　return TRUE;<BR>　　}<BR>　　<BR>　　参数中，hMoudle是动态库被调用时所传递来的一个指向自己的句柄(实际上，它是指向_DGROUP段的一个选择符)；<BR>　　ul_reason_for_call是一个说明动态库被调原因的标志，当进程或线程装入或卸载动态链接库的时候，操作系统调用入口函数，并说明动态链接库被调用的原因，它所有的可能值为：<BR>　　<BR>　　(1)DLL_PROCESS_ATTACH: 进程被调用或调用Load Library，DLL被链接到当前进程的地址空间并被初始化；<BR>　　<BR>　　(2)DLL_THREAD_ATTACH: 当前进程创建一个新线程，DLL在新线程正文内被调用；<BR>　　<BR>　　(3)DLL_PROCESS_DETACH: 调用DLL的进程被终止，DLL被卸载；<BR>　　<BR>　　(4)DLL_THREAD_DETACH: 调用DLL的线程被终止，DLL被卸载；<BR>　　<BR>　　lpReserved为保留参数。<BR>　　<BR>　　如果在DLL中加入想要输出的函数、变量、C++类或其它函数，可以调用VC的关键字_declspec(dllexport)。<BR>　　<BR>　　2、MFC AppWizard[dll]方式下Regular DLL和Extension DLL的建立<BR>　　<BR>　　在MFC AppWizard[dll]下生成的DLL文件有三种方式：静态链接到MFC的常规DLL、动态链接到MFC的常规DLL以及MFC扩展DLL，在创建DLL是，要根据实际情况选择创建DLL的方式。<BR>　　<BR>　　静态链接到MFC的常规DLL和静态连接到MFC常规DLL的区别是：前者使用的是MFC的静态链接库，生成的DLL文件长度大，一般不使用这种方式；后者使用MFC的动态链接库，生成的DLL文件长度小；动态链接到MFC的常规DLL所有输出的函数应该以如下语句开始：<BR>　　<BR>　　AFX_MANAGE_STATE(AfxGetStaticModuleState( )) //此语句用来正确地切换MFC模块状态<BR>　　<BR>　　MFC扩展DLL的特点是用来建立MFC的派生类，Dll只被用MFC类库所编写的应用程序所调用。Extension DLLs 和Regular DLLs不一样，它没有一个从CWinApp继承而来的类的对象，编译器默认了一个DLL入口函数DLLMain()作为对DLL的初始化，你可以在此函数中实现初始化,代码如下：<BR>　　<BR>　　BOOL WINAPI APIENTRY DLLMain(HINSTANCE hinstDll，DWORD reason ，LPVOID flmpload)<BR>　　{<BR>　　switch(reason)<BR>　　{<BR>　　&#8230;&#8230;&#8230;&#8230;&#8230;//初始化代码；<BR>　　}<BR>　　return true;<BR>　　}<BR>　　<BR>　　参数hinstDll存放DLL的句柄，参数reason指明调用函数的原因，lpReserved是一个被系统所保留的参数。对于隐式链接是一个非零值，对于显式链接值是零。<BR>　　<BR>　　动态连接库的调用<BR>　　<BR>　　动态链接库的调用可以分为两种：一种是隐式调用，一种是显示调用。<BR>　　<BR>　　1、隐式的调用<BR>　　<BR>　　这种调用方式需要把产生动态连接库时产生的.LIB文件加入到应用程序的工程中，在使用DLL中的函数时，只须说明一下后就可以直接通过函数名调用DLL的输出函数，调用方法和程序内部其他的函数是一样的。隐式调用不需要调用Load Library()和Free Library()。程序员在建立一个DLL文件时，链接程序会自动生成一个与之对应的LIB导入文件。该文件包含了每一个DLL导出函数的符号名和可选的标识号，但是并不含有实际的代码。LIB文件作为DLL的替代文件被编译到应用程序项目中。<BR>　　<BR>　　当程序员通过隐式调用方式编译生成应用程序时，应用程序中的调用函数与LIB文件中导出符号相匹配，这些符号或标识号被写入到生成的EXE文件中。LIB文件中也包含了对应的DLL文件名（但不是完全的路径名），链接程序也将其存储在EXE文件内部。当应用程序运行过程中需要加载DLL文件时，Windows根据这些信息发现并加载DLL，然后通过符号名或标识号实现对DLL函数的动态链接。所有被应用程序调用的DLL文件都会在应用程序EXE文件加载时被加载在到内存中。<BR>　　<BR>　　2、显式调用<BR>　　<BR>　　这种调用方式是指在应用程序中用Load Library或MFC提供的AfxLoadLibrary显式的将自己所做的动态连接库调进来，并指定DLL的路径作为参数。LoadLibary返回HINSTANCE参数，应用程序在调用GetProcAddress函数时使用这一参数。当完成对动态链接库的导入以后，再使用GetProcAddress()获取想要引入的函数，该函数将符号名或标识号转换为DLL内部的地址，之后就可以象使用本应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前，应该用Free Library或MFC提供的AfxFreeLibrary释放动态连接库。<BR>　　<BR>　　使用显式调用方式可以让程序员来决定DLL文件何时加载或不加载，而操作系统在载入应用程序时不必要将所有该应用程序所引用的DLL都一起加载到内存中，只要在使用某个DLL时再将其载入，这样就可以减少应用程序在初始加载时所使用的时间和对内存的消耗。在对DLL加载的过程中，Windows将遵循下面的搜索顺序来定位DLL：<BR>　　<BR>　　①包含EXE文件的目录；<BR>　　<BR>　　②进程的当前工作目录 ；<BR>　　<BR>　　③Windows系统目录 ；<BR>　　<BR>　　④Windows目录 ；<BR>　　<BR>　　⑤列在Path环境变量中的一系列目录。<BR>　　<BR>　　总结<BR>　　<BR>　　在Windows操作系统中使用动态链接库（DLL）有很多优点，最主要的一点是多个应用程序、甚至是不同语言编写的应用程序可以共享一个DLL文件，真正实现了资源"共享"，大大缩小了应用程序的执行代码，更加有效地利用了内存；使用DLL的另一个优点是DLL文件作为一个单独的程序模块，封装性、独立性好，在软件需要升级的时候，开发人员只需要修改相应的DLL文件就可以了，而且，当DLL中的函数改变后，如果没有修改参数,程序代码并不需要重新编译。这在编程时十分有用，大大提高了软件开发和维护的效率。<img src ="http://www.cnblogs.com/Wiseman/aggbug/348758.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43630/" target="_blank">[新闻]Silverlight 2 SDK中文版发布</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>VC小技巧 15个问题</title><link>http://www.cnblogs.com/Wiseman/archive/2006/03/11/347868.html</link><dc:creator>吴文力</dc:creator><author>吴文力</author><pubDate>Sat, 11 Mar 2006 05:45:00 GMT</pubDate><guid>http://www.cnblogs.com/Wiseman/archive/2006/03/11/347868.html</guid><wfw:comment>http://www.cnblogs.com/Wiseman/comments/347868.html</wfw:comment><comments>http://www.cnblogs.com/Wiseman/archive/2006/03/11/347868.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnblogs.com/Wiseman/comments/commentRss/347868.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/Wiseman/services/trackbacks/347868.html</trackback:ping><description><![CDATA[一、<I></I>&nbsp;一次只运行一个程序实例<BR>下列两种方式都可以实现，建议采用第二种方式：<BR>1、<I></I>&nbsp;if(<I></I>&nbsp;FindWindow(NULL,"程序标题"))<I></I>&nbsp;<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;exit(0);<BR>2、BOOL<I></I>&nbsp;CDemoTBarEApp::InstanceIsRun()<BR>{<BR><I></I>&nbsp;HANDLE<I></I>&nbsp;m_hMutex;<BR><I></I>&nbsp;m_hMutex<I></I>&nbsp;=<I></I>&nbsp;::CreateMutex(NULL,<I></I>&nbsp;TRUE,<I></I>&nbsp;_T("YourApplication"));<BR><I></I>&nbsp;ASSERT(m_hMutex);<BR><I></I>&nbsp;if<I></I>&nbsp;(GetLastError()<I></I>&nbsp;==<I></I>&nbsp;ERROR_ALREADY_EXISTS)<BR><I></I>&nbsp;{<BR><I></I>&nbsp;<I></I>&nbsp;m_hMutex<I></I>&nbsp;=<I></I>&nbsp;NULL;<BR><I></I>&nbsp;<I></I>&nbsp;return<I></I>&nbsp;TRUE;//实例已经运行<BR><I></I>&nbsp;}<BR><I></I>&nbsp;return<I></I>&nbsp;FALSE;//实例未运行<BR>} 
<P></P>
<P>二、<I></I>&nbsp;装载光标<BR>SetCursor(AfxGetApp()-&gt;LoadStandardCursor(IDC_WAIT));<BR>　　其中::SetCursor()是全局函数，用来设置整个例程的光标参数是宏定义光标句柄。AfxGetApp<I></I>&nbsp;()是一个系统函数，它返回当前的一个CWinApp对象。其成员函数LoadStandardCursor()用来读取一个系统指针，每一种系统指针的具体宏定义如下：<BR>IDC_APPSTARTING<I></I>&nbsp;<I></I>&nbsp;带小沙漏的标准箭头<BR>IDC_ARROW<I></I>&nbsp;<I></I>&nbsp;标准箭头<BR>IDC_CROSS<I></I>&nbsp;<I></I>&nbsp;十字光标（用于定位）<BR>IDC_HAND<I></I>&nbsp;<I></I>&nbsp;Windows<I></I>&nbsp;2000：手型<BR>IDC_HELP<I></I>&nbsp;<I></I>&nbsp;带问号的箭头<BR>IDC_IBEAM<I></I>&nbsp;<I></I>&nbsp;I型标<BR>IDC_ICON<I></I>&nbsp;<I></I>&nbsp;Obsolete<I></I>&nbsp;for<I></I>&nbsp;applications<I></I>&nbsp;marked<I></I>&nbsp;version<I></I>&nbsp;4.0<I></I>&nbsp;or<I></I>&nbsp;later.<I></I>&nbsp;<BR>IDC_NO<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;禁止符号<BR>IDC_SIZE<I></I>&nbsp;<I></I>&nbsp;Obsolete<I></I>&nbsp;for<I></I>&nbsp;applications<I></I>&nbsp;marked<I></I>&nbsp;version<I></I>&nbsp;4.0<I></I>&nbsp;or<I></I>&nbsp;later.<I></I>&nbsp;Use<I></I>&nbsp;IDC_SIZEALL.<I></I>&nbsp;<BR>IDC_SIZEALL<I></I>&nbsp;<I></I>&nbsp;十字箭头<BR>IDC_SIZENESW<I></I>&nbsp;<I></I>&nbsp;指向东北和西南的双向箭头<BR>IDC_SIZENS<I></I>&nbsp;<I></I>&nbsp;指向南和北的双向箭头<BR>IDC_SIZENWSE<I></I>&nbsp;<I></I>&nbsp;指向西北和东南的双向箭头<BR>IDC_SIZEWE<I></I>&nbsp;<I></I>&nbsp;指向东西的双向箭头<BR>IDC_UPARROW<I></I>&nbsp;<I></I>&nbsp;上箭头<BR>IDC_WAIT<I></I>&nbsp;<I></I>&nbsp;沙漏</P>
<P>三、获得主框架：<I></I>&nbsp;<BR>CMainFrame<I></I>&nbsp;*<I></I>&nbsp;pMainframe<I></I>&nbsp;=<I></I>&nbsp;(CMainFrame<I></I>&nbsp;*)<I></I>&nbsp;AfxGetApp()-&gt;m_pMainWnd;<BR>.获取应用程序的实例句柄：<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;Example:<I></I>&nbsp;HANDLE<I></I>&nbsp;hInstance=AfxGetInstanceHandle();</P>
<P>获得应用程序主窗口的指针：<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;Example:<I></I>&nbsp;AfxGetMainWnd()<I></I>&nbsp;-&gt;ShowWindow(SW_SHOWMAXMIZED);<I></I>&nbsp;//使程序最大化</P>
<P>四、重新建立字体的代码<BR><I></I>&nbsp;if(m_fontLogo.m_hObject)<BR><I></I>&nbsp;<I></I>&nbsp;m_fontLogo.Detach();</P>
<P><I></I>&nbsp;m_fontLogo.CreateFont(nHeight,<I></I>&nbsp;0,<I></I>&nbsp;0,<I></I>&nbsp;0,<I></I>&nbsp;nWeight,<I></I>&nbsp;bItalic,<I></I>&nbsp;bUnderline,0,0,0,0,0,0,<I></I>&nbsp;Name);</P>
<P>五、用指定颜色填充区域<BR><I></I>&nbsp;dc.FillSolidRect(rect,<I></I>&nbsp;::GetSysColor(COLOR_3DFACE));</P>
<P>六、绘制立体字体效果的字体，很值得一看<BR>void<I></I>&nbsp;CTestView::OnPaint()<I></I>&nbsp;<BR>{<BR><I></I>&nbsp;CPaintDC<I></I>&nbsp;dc(this);<I></I>&nbsp;//<I></I>&nbsp;device<I></I>&nbsp;context<I></I>&nbsp;for<I></I>&nbsp;painting<BR><I></I>&nbsp;<BR><I></I>&nbsp;CRect<I></I>&nbsp;rect;<BR><I></I>&nbsp;GetWindowRect(rect);</P>
<P><I></I>&nbsp;CFont<I></I>&nbsp;<I></I>&nbsp;m_fontLogo;<BR><I></I>&nbsp;m_fontLogo.CreateFont(24,<I></I>&nbsp;0,<I></I>&nbsp;0,<I></I>&nbsp;0,<I></I>&nbsp;FW_BOLD,<I></I>&nbsp;true,<BR><I></I>&nbsp;<I></I>&nbsp;FALSE,0,0,0,0,0,0,<I></I>&nbsp;"Arial");<BR><I></I>&nbsp;CString<I></I>&nbsp;m_LogoText;<BR><I></I>&nbsp;m_LogoText=_T("Benlux<I></I>&nbsp;Pro3D<I></I>&nbsp;System");<BR><I></I>&nbsp;dc.SetBkMode(TRANSPARENT);</P>
<P><I></I>&nbsp;CFont<I></I>&nbsp;*<I></I>&nbsp;OldFont<I></I>&nbsp;=<I></I>&nbsp;dc.SelectObject(&amp;m_fontLogo);</P>
<P><I></I>&nbsp;//<I></I>&nbsp;draw<I></I>&nbsp;text<I></I>&nbsp;in<I></I>&nbsp;DC<BR><I></I>&nbsp;COLORREF<I></I>&nbsp;OldColor<I></I>&nbsp;=<I></I>&nbsp;dc.SetTextColor(<I></I>&nbsp;::GetSysColor(<I></I>&nbsp;COLOR_3DHILIGHT));</P>
<P><I></I>&nbsp;rect.right<I></I>&nbsp;=<I></I>&nbsp;rect.Width();<BR><I></I>&nbsp;rect.bottom<I></I>&nbsp;=<I></I>&nbsp;rect.Height();<BR><I></I>&nbsp;rect.left<I></I>&nbsp;=<I></I>&nbsp;rect.top<I></I>&nbsp;=<I></I>&nbsp;0;<BR><I></I>&nbsp;dc.FillSolidRect(rect,<I></I>&nbsp;::GetSysColor(COLOR_3DFACE));</P>
<P><BR><I></I>&nbsp;dc.DrawText(<I></I>&nbsp;m_LogoText,<I></I>&nbsp;rect<I></I>&nbsp;+<I></I>&nbsp;CPoint(1,1),<I></I>&nbsp;DT_SINGLELINE<I></I>&nbsp;|<I></I>&nbsp;DT_LEFT<I></I>&nbsp;|<I></I>&nbsp;DT_VCENTER);<BR><I></I>&nbsp;dc.SetTextColor(<I></I>&nbsp;::GetSysColor(<I></I>&nbsp;COLOR_3DSHADOW));<BR><I></I>&nbsp;dc.DrawText(<I></I>&nbsp;m_LogoText,<I></I>&nbsp;rect,<I></I>&nbsp;DT_SINGLELINE<I></I>&nbsp;|<I></I>&nbsp;DT_LEFT<I></I>&nbsp;|<I></I>&nbsp;DT_VCENTER);</P>
<P><I></I>&nbsp;//<I></I>&nbsp;restore<I></I>&nbsp;old<I></I>&nbsp;text<I></I>&nbsp;color<BR><I></I>&nbsp;dc.SetTextColor(<I></I>&nbsp;OldColor);<BR><I></I>&nbsp;//<I></I>&nbsp;restore<I></I>&nbsp;old<I></I>&nbsp;font<BR><I></I>&nbsp;dc.SelectObject(OldFont);<I></I>&nbsp;<BR><I></I>&nbsp;//<I></I>&nbsp;Do<I></I>&nbsp;not<I></I>&nbsp;call<I></I>&nbsp;CView::OnPaint()<I></I>&nbsp;for<I></I>&nbsp;painting<I></I>&nbsp;messages<BR>}</P>
<P>七、简单的消息检索和抽取函数，能够让系统响应其它操作<BR>BOOL<I></I>&nbsp;PeekAndPump()<BR>{<BR><I></I>&nbsp;static<I></I>&nbsp;MSG<I></I>&nbsp;msg;</P>
<P><I></I>&nbsp;while<I></I>&nbsp;(::PeekMessage(&amp;msg,NULL,0,0,PM_NOREMOVE))<I></I>&nbsp;{<BR><I></I>&nbsp;<I></I>&nbsp;if<I></I>&nbsp;(!AfxGetApp()-&gt;PumpMessage())<I></I>&nbsp;{<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;::PostQuitMessage(0);<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;return<I></I>&nbsp;FALSE;<BR><I></I>&nbsp;<I></I>&nbsp;}<I></I>&nbsp;<BR><I></I>&nbsp;}<BR><I></I>&nbsp;return<I></I>&nbsp;TRUE;<BR>}</P>
<P>八、在你的程序中用动画光标替换默认的等待光标<I></I>&nbsp;(ANI光标的使用)<BR><I></I>&nbsp;HCURSOR<I></I>&nbsp;m_hAniCursor=NULL;<BR><I></I>&nbsp;BeginWaitCursor();<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//begin<I></I>&nbsp;wait<I></I>&nbsp;cursor<I></I>&nbsp;for<I></I>&nbsp;api<I></I>&nbsp;function<BR><I></I>&nbsp;<BR><I></I>&nbsp;//load<I></I>&nbsp;ani<I></I>&nbsp;cursor<I></I>&nbsp;from<I></I>&nbsp;file<I></I>&nbsp;in<I></I>&nbsp;current<I></I>&nbsp;path<BR><I></I>&nbsp;TCHAR<I></I>&nbsp;cursorPath[MAX_PATH];<I></I>&nbsp;GetModuleFileName(NULL,cursorPath,MAX_PATH);<BR><I></I>&nbsp;char<I></I>&nbsp;drive[_MAX_DRIVE];<BR><I></I>&nbsp;char<I></I>&nbsp;dir[_MAX_DIR];<BR><I></I>&nbsp;char<I></I>&nbsp;fname[_MAX_FNAME];<BR><I></I>&nbsp;char<I></I>&nbsp;ext[_MAX_EXT];<BR><I></I>&nbsp;_splitpath(cursorPath,<I></I>&nbsp;drive,<I></I>&nbsp;dir,<I></I>&nbsp;fname,<I></I>&nbsp;ext<I></I>&nbsp;);<BR><I></I>&nbsp;sprintf(cursorPath,"%s%s\wait.ani",drive,dir);<I></I>&nbsp;<I></I>&nbsp;//ani<I></I>&nbsp;cursor<I></I>&nbsp;file<I></I>&nbsp;name<I></I>&nbsp;is<I></I>&nbsp;wait.ani<BR><I></I>&nbsp;<BR><I></I>&nbsp;m_hAniCursor=<I></I>&nbsp;LoadCursorFromFile(cursorPath);<BR><I></I>&nbsp;HCURSOR<I></I>&nbsp;oldCursor;<BR><I></I>&nbsp;if(m_hAniCursor<I></I>&nbsp;!=<I></I>&nbsp;NULL)<BR><I></I>&nbsp;<I></I>&nbsp;oldCursor=SetCursor(m_hAniCursor);<BR><I></I>&nbsp;<BR><I></I>&nbsp;for(long<I></I>&nbsp;i=0;i&lt;1000;i++)<I></I>&nbsp;<I></I>&nbsp;<BR><I></I>&nbsp;<I></I>&nbsp;Sleep(5);<BR><I></I>&nbsp;<BR><I></I>&nbsp;oldCursor=NULL;<BR><I></I>&nbsp;m_hAniCursor=NULL;<BR><I></I>&nbsp;EndWaitCursor();<I></I>&nbsp;<I></I>&nbsp;//end<I></I>&nbsp;wait<I></I>&nbsp;cursor<I></I>&nbsp;for<I></I>&nbsp;api<I></I>&nbsp;function</P>
<P>九、如何限制编辑框中的准许字符<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;如果用户在编辑控件中只允许接收数字，可以使用一个标准的编辑控件并指<BR>定新的创建标志ES_NUMBERS,它是Windows<I></I>&nbsp;95新增加的标志，该标志限制<I></I>&nbsp;编辑控<BR>件只按收数字字符。<BR>如果用户需要复杂的编辑控件，可以使用Microsoft<I></I>&nbsp;的屏蔽编辑控件，它是一个很有用的OLE定制控件。<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;如果希望不使用OLE<I></I>&nbsp;定制控件自己处理字符，可以派生一个CEdit<I></I>&nbsp;类并处理WM_CHAR消息，然后从编辑控件中过滤出特定的字符。首先，使用ClassWizard<I></I>&nbsp;建立一个<I></I>&nbsp;CEdit的派生类，其次，在对话类中指定一个成员变量将编辑控件分类在OnInitdialog<I></I>&nbsp;中调用CWnd:<I></I>&nbsp;:<I></I>&nbsp;SubclassDlgItem<I></I>&nbsp;.</P>
<P>//In<I></I>&nbsp;your<I></I>&nbsp;dialog<I></I>&nbsp;class<I></I>&nbsp;declaration<I></I>&nbsp;(.H<I></I>&nbsp;file<I></I>&nbsp;)<BR>private<I></I>&nbsp;:<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CMyEdit<I></I>&nbsp;m_wndEdit<I></I>&nbsp;;<I></I>&nbsp;//<I></I>&nbsp;Instance<I></I>&nbsp;of<I></I>&nbsp;your<I></I>&nbsp;new<I></I>&nbsp;edit<I></I>&nbsp;control<I></I>&nbsp;.</P>
<P>//In<I></I>&nbsp;you<I></I>&nbsp;dialog<I></I>&nbsp;class<I></I>&nbsp;implementation<I></I>&nbsp;(.CPP<I></I>&nbsp;file<I></I>&nbsp;)<BR>BOOL<I></I>&nbsp;CSampleDialog<I></I>&nbsp;:<I></I>&nbsp;:<I></I>&nbsp;OnInitDialog<I></I>&nbsp;(<I></I>&nbsp;)<BR>{</P>
<P><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Subclass<I></I>&nbsp;the<I></I>&nbsp;edit<I></I>&nbsp;lontrod<I></I>&nbsp;.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;m_wndEdit<I></I>&nbsp;.SubclassDlgItem<I></I>&nbsp;<I></I>&nbsp;(IDC_EDIT,this<I></I>&nbsp;);<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;&#8230;<BR>}<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;使用ClassWizard处理WM_CHAR消息，计算nChar参量并决定所执行的操作，用户可以确定是否修改、传送字符。下例说明了如何显示字母字符，如果字符是字母字符，则调用CWnd<I></I>&nbsp;;<I></I>&nbsp;OnChar，否则不调用OnChar.<BR>//Only<I></I>&nbsp;display<I></I>&nbsp;alphabetic<I></I>&nbsp;dharacters<I></I>&nbsp;.<BR>void<I></I>&nbsp;CMyEdit<I></I>&nbsp;:<I></I>&nbsp;:<I></I>&nbsp;OnChar<I></I>&nbsp;(UINT<I></I>&nbsp;nChar<I></I>&nbsp;,<I></I>&nbsp;UINT<I></I>&nbsp;nRepCnt<I></I>&nbsp;,<I></I>&nbsp;UITN<I></I>&nbsp;nFlags<I></I>&nbsp;)<BR>{<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Determine<I></I>&nbsp;if<I></I>&nbsp;nChar<I></I>&nbsp;is<I></I>&nbsp;an<I></I>&nbsp;alphabetic<I></I>&nbsp;character<I></I>&nbsp;.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;if<I></I>&nbsp;(:<I></I>&nbsp;:<I></I>&nbsp;IsCharAlpha<I></I>&nbsp;<I></I>&nbsp;(<I></I>&nbsp;(<I></I>&nbsp;TCHAR)<I></I>&nbsp;nChar<I></I>&nbsp;)<I></I>&nbsp;)<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CEdit<I></I>&nbsp;:<I></I>&nbsp;:<I></I>&nbsp;OnChar<I></I>&nbsp;(nChar,<I></I>&nbsp;nRepCnt<I></I>&nbsp;,<I></I>&nbsp;nFlags<I></I>&nbsp;);<BR>}<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;如果要修改字符，则不能仅仅简单地用修改过的nChar调用CEdit<I></I>&nbsp;:<I></I>&nbsp;:<I></I>&nbsp;OnChar。要修改一个字符，需要首先修改nChar，然后用修改过的nChar调用CWnd:<I></I>&nbsp;:<I></I>&nbsp;DefWindowProc。下例说明了如何将字符转变为大写：<BR>//Make<I></I>&nbsp;all<I></I>&nbsp;characters<I></I>&nbsp;uppercase<BR>void<I></I>&nbsp;CMyEdit<I></I>&nbsp;:<I></I>&nbsp;:<I></I>&nbsp;OnChar<I></I>&nbsp;(UINT<I></I>&nbsp;nChar<I></I>&nbsp;,<I></I>&nbsp;UINT<I></I>&nbsp;nRepCnt<I></I>&nbsp;,<I></I>&nbsp;UINT<I></I>&nbsp;nFlags<I></I>&nbsp;)<BR>{<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Make<I></I>&nbsp;sure<I></I>&nbsp;character<I></I>&nbsp;is<I></I>&nbsp;uppercase<I></I>&nbsp;.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;if<I></I>&nbsp;(:<I></I>&nbsp;:<I></I>&nbsp;IsCharAlpha<I></I>&nbsp;<I></I>&nbsp;(<I></I>&nbsp;.(<I></I>&nbsp;TCHAR)<I></I>&nbsp;nChar)<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;nChar=:<I></I>&nbsp;:<I></I>&nbsp;CharUpper<I></I>&nbsp;(nChar<I></I>&nbsp;)<I></I>&nbsp;;<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Bypass<I></I>&nbsp;default<I></I>&nbsp;OnChar<I></I>&nbsp;processing<I></I>&nbsp;and<I></I>&nbsp;directly<I></I>&nbsp;call<I></I>&nbsp;<I></I>&nbsp;default<I></I>&nbsp;window<I></I>&nbsp;proc.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;DefWindProc<I></I>&nbsp;(WM_CHAR,<I></I>&nbsp;nChar<I></I>&nbsp;,<I></I>&nbsp;MAKELPARAM<I></I>&nbsp;(nRepCnt<I></I>&nbsp;,<I></I>&nbsp;nFlags<I></I>&nbsp;))<I></I>&nbsp;;<BR>}</P>
<P>十、串太长时如何在其末尾显示一个省略号<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;调用CDC::<I></I>&nbsp;DrawText并指定DT_END_ELLIPSIS标志，这样就可以用小略号取代串末尾的字符使其适合于指定的边界矩形。如果要显示路径信息，指定DT_END_ELLIPSIS标志并省略号取代串中间的字符。<BR>void<I></I>&nbsp;CSampleView::<I></I>&nbsp;OnDraw<I></I>&nbsp;(CDC*<I></I>&nbsp;pDC)<BR>{<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CTestDoc*<I></I>&nbsp;pDoc=GetDocument<I></I>&nbsp;();<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;ASSERT_VALID<I></I>&nbsp;(pDoc);<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Add<I></I>&nbsp;ellpsis<I></I>&nbsp;to<I></I>&nbsp;end<I></I>&nbsp;of<I></I>&nbsp;string<I></I>&nbsp;if<I></I>&nbsp;it<I></I>&nbsp;does<I></I>&nbsp;not<I></I>&nbsp;fit<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDC-&gt;Drawtext<I></I>&nbsp;(CString<I></I>&nbsp;("This<I></I>&nbsp;is<I></I>&nbsp;a<I></I>&nbsp;long<I></I>&nbsp;string"),<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CRect<I></I>&nbsp;(10,<I></I>&nbsp;10,<I></I>&nbsp;80,<I></I>&nbsp;30),<I></I>&nbsp;DT_LEFT<I></I>&nbsp;|<I></I>&nbsp;DT_END_ELLIPSIS);</P>
<P><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Add<I></I>&nbsp;ellpsis<I></I>&nbsp;to<I></I>&nbsp;middle<I></I>&nbsp;of<I></I>&nbsp;string<I></I>&nbsp;if<I></I>&nbsp;it<I></I>&nbsp;does<I></I>&nbsp;not<I></I>&nbsp;fit<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDC-&gt;DrawText<I></I>&nbsp;(AfxgetApp<I></I>&nbsp;()<I></I>&nbsp;-&gt;m_pszhelpfilePath,<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CRect<I></I>&nbsp;(10,<I></I>&nbsp;40,<I></I>&nbsp;200,<I></I>&nbsp;60),<I></I>&nbsp;DT_LEFT<I></I>&nbsp;|<I></I>&nbsp;DT_PATH_ELLIPSIS);<BR>}</P>
<P>十一、如何实现一个橡皮区矩形(具有踪迹矩形并可移动、缩放的矩形)<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CRectTracker是一个很有用的类，可以通过调用CRectTracker::<I></I>&nbsp;TrackRubberBand响应WM_LBUTTONDOWN消息来创建一个橡皮区矩形。下例表明使用CRectTracker移动和重置视窗中的蓝色椭圆的大小是很容易的事情。<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;首先，在文档类中声明一个CRectTracker数据成员：<BR>class<I></I>&nbsp;CTestDoc:<I></I>&nbsp;Public<I></I>&nbsp;CDocument<BR>{&#8230;<BR>public:<BR><I></I>&nbsp;CRectTracker<I></I>&nbsp;m_tracker;<BR>&#8230;<BR>};<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;其次，在文档类的构造函数中初始化CRectTracker<I></I>&nbsp;对象：<BR>CTestDoc::CTestDoc()<BR>{<BR><I></I>&nbsp;m_tracker.m_rect.SetRect<I></I>&nbsp;(10,<I></I>&nbsp;10,<I></I>&nbsp;300,<I></I>&nbsp;300);<BR><I></I>&nbsp;m_tracker.m_nStyle=CRectTracker::<I></I>&nbsp;resizeInside<I></I>&nbsp;<I></I>&nbsp;|<BR><I></I>&nbsp;<I></I>&nbsp;CRectTracker::<I></I>&nbsp;dottedLine;<I></I>&nbsp;<BR>}<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;然后，在视图类的OnDraw函数中画椭圆和踪迹矩形：<BR>void<I></I>&nbsp;CTestView::OnDraw(CDC*<I></I>&nbsp;pDC)<BR>{<BR><I></I>&nbsp;CTestDoc*<I></I>&nbsp;pDoc<I></I>&nbsp;=<I></I>&nbsp;GetDocument();<BR><I></I>&nbsp;ASSERT_VALID(pDoc);</P>
<P>//Select<I></I>&nbsp;blue<I></I>&nbsp;brush<I></I>&nbsp;into<I></I>&nbsp;device<I></I>&nbsp;context.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CBrush<I></I>&nbsp;brush<I></I>&nbsp;(RGB<I></I>&nbsp;(0,<I></I>&nbsp;0,<I></I>&nbsp;255));<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CBrush*<I></I>&nbsp;pOldBrush=pDC-&gt;SelectObject<I></I>&nbsp;(&amp;brush);</P>
<P><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//draw<I></I>&nbsp;ellipse<I></I>&nbsp;in<I></I>&nbsp;tracking<I></I>&nbsp;rectangle.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CRect<I></I>&nbsp;rcEllipse;<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDoc-&gt;m_tracker.GetTrueRect<I></I>&nbsp;(rcEllipse);<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDC-&gt;Ellipse<I></I>&nbsp;(rcEllipse);</P>
<P><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Draw<I></I>&nbsp;tracking<I></I>&nbsp;rectangle.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDoc-&gt;m_tracker.Draw<I></I>&nbsp;(pDC);<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Select<I></I>&nbsp;blue<I></I>&nbsp;brush<I></I>&nbsp;out<I></I>&nbsp;of<I></I>&nbsp;device<I></I>&nbsp;context.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDC-&gt;SelectObject(pOldBrush);<BR>}<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;最后，视图类中处理WM_LBUTTONDOWN消息，并增加下述代码。该段代码根据鼠标击键情况可以拖放、移动或者重置椭圆的大小。</P>
<P>void<I></I>&nbsp;CTestView::OnLButtonDown(UINT<I></I>&nbsp;nFlags,<I></I>&nbsp;CPoint<I></I>&nbsp;point)<I></I>&nbsp;<BR>{<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Get<I></I>&nbsp;pointer<I></I>&nbsp;to<I></I>&nbsp;document.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CTestDoc*<I></I>&nbsp;pDoc=GetDocument();<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;ASSERT_VALID<I></I>&nbsp;(pDoc);</P>
<P><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//If<I></I>&nbsp;clicked<I></I>&nbsp;on<I></I>&nbsp;ellipse,<I></I>&nbsp;drag<I></I>&nbsp;or<I></I>&nbsp;resize<I></I>&nbsp;it.<I></I>&nbsp;Otherwise<I></I>&nbsp;create<I></I>&nbsp;a<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//rubber-band<I></I>&nbsp;rectangle<I></I>&nbsp;nd<I></I>&nbsp;create<I></I>&nbsp;a<I></I>&nbsp;new<I></I>&nbsp;ellipse.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;BOOL<I></I>&nbsp;bResult=pDoc-&gt;m_tracker.HitTest<I></I>&nbsp;(point)!=<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;CRectTracker::hitNothing;</P>
<P><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Tracker<I></I>&nbsp;rectangle<I></I>&nbsp;changed<I></I>&nbsp;so<I></I>&nbsp;update<I></I>&nbsp;views.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;if<I></I>&nbsp;(bResult)<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;{<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDoc-&gt;m_tracker.Track<I></I>&nbsp;(this,point,TRUE);<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDoc-&gt;SetModifiedFlag<I></I>&nbsp;();<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDoc-&gt;UpdateAllViews<I></I>&nbsp;(NULL);<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;}<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;else<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;pDoc-&gt;m_tracker.TrackRubberBand<I></I>&nbsp;(this,point,TRUE);</P>
<P><I></I>&nbsp;CView::OnLButtonDown(nFlags,<I></I>&nbsp;point);<BR>}</P>
<P>十二、如何在临时目录创建一个临时文件<BR>如果你要在临时目录下创建临时文件，下面的代码能帮到你的忙。<BR>bool<I></I>&nbsp;GetuniqueTempName<I></I>&nbsp;(CString&amp;<I></I>&nbsp;strTempName)<BR>{<BR><I></I>&nbsp;<I></I>&nbsp;strTempName="";<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Get<I></I>&nbsp;the<I></I>&nbsp;temporary<I></I>&nbsp;files<I></I>&nbsp;directory.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;TCHAR<I></I>&nbsp;szTempPath<I></I>&nbsp;[MAX_PATH];<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;DWORD<I></I>&nbsp;dwResult=::<I></I>&nbsp;GetTempPath<I></I>&nbsp;(MAX_PATH,<I></I>&nbsp;szTempPath);<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;if<I></I>&nbsp;(dwResult==0)<I></I>&nbsp;<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;return<I></I>&nbsp;false;</P>
<P><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//Create<I></I>&nbsp;a<I></I>&nbsp;unique<I></I>&nbsp;temporary<I></I>&nbsp;file.<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;TCHAR<I></I>&nbsp;szTempFile[MAX_PATH];<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;UINT<I></I>&nbsp;nResult=GetTempFileName<I></I>&nbsp;(szTempPath,<I></I>&nbsp;_T<I></I>&nbsp;("~ex"),0,szTempFile);<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;if<I></I>&nbsp;(dwResult==0)<I></I>&nbsp;<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;return<I></I>&nbsp;false;</P>
<P><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;strTempName=szTempFile;<BR><I></I>&nbsp;<I></I>&nbsp;return<I></I>&nbsp;true;<BR>}</P>
<P>十三、如何限制窗口的最小范围<BR>要限制窗体的大小，下面的代码能帮到你的忙。<BR>在CMainFrame中增加WM_GETMAXMININFO消息的处理函数，然后在这个函数中写代码如下:<BR>//限制主窗体的最小高度和宽度<BR>void<I></I>&nbsp;CMainFrame::OnGetMinMaxInfo(MINMAXINFO<I></I>&nbsp;FAR*<I></I>&nbsp;lpMMI)<I></I>&nbsp;<BR>{<BR><I></I>&nbsp;lpMMI-&gt;ptMinTrackSize.x=600;<BR><I></I>&nbsp;lpMMI-&gt;ptMinTrackSize.y=400;<BR><I></I>&nbsp;CNewFrameWnd::OnGetMinMaxInfo(lpMMI);<BR>}</P>
<P>十四、怎样删除文件到回收站中<BR><I></I>&nbsp;要删除文件到回收站，很简单。只要用SHFileOperation函数就行了，下面的代码我将为你演示了这一个函数的用法。当然你可以直接拷贝到你的项目中。<BR>//删除文件到回收站中<BR>//pszPath<I></I>&nbsp;<I></I>&nbsp;:<I></I>&nbsp;待删除的全路径文件名<BR>//bDelete<I></I>&nbsp;<I></I>&nbsp;:<I></I>&nbsp;TRUE<I></I>&nbsp;删除，不移到回收站，FALSE:移到回收站<BR>一、<I></I>&nbsp;//返回<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;:<I></I>&nbsp;TRUE<I></I>&nbsp;删除成功<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;FALSE<I></I>&nbsp;删除失败<BR>BOOL<I></I>&nbsp;CDelFileToRecycleDlg::Recycle(LPCTSTR<I></I>&nbsp;pszPath,<I></I>&nbsp;BOOL<I></I>&nbsp;bDelete/*=FALSE*/)<BR>{<BR><I></I>&nbsp;SHFILEOPSTRUCT<I></I>&nbsp;<I></I>&nbsp;shDelFile;<BR><I></I>&nbsp;memset(&amp;shDelFile,0,sizeof(SHFILEOPSTRUCT));<BR><I></I>&nbsp;shDelFile.fFlags<I></I>&nbsp;|=<I></I>&nbsp;FOF_SILENT;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;don't<I></I>&nbsp;report<I></I>&nbsp;progress<BR><I></I>&nbsp;shDelFile.fFlags<I></I>&nbsp;|=<I></I>&nbsp;FOF_NOERRORUI;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;don't<I></I>&nbsp;report<I></I>&nbsp;errors<BR><I></I>&nbsp;shDelFile.fFlags<I></I>&nbsp;|=<I></I>&nbsp;FOF_NOCONFIRMATION;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;don't<I></I>&nbsp;confirm<I></I>&nbsp;delete<BR><I></I>&nbsp;//<I></I>&nbsp;Copy<I></I>&nbsp;pathname<I></I>&nbsp;to<I></I>&nbsp;double-NULL-terminated<I></I>&nbsp;string.<BR><I></I>&nbsp;//<BR><I></I>&nbsp;TCHAR<I></I>&nbsp;buf[_MAX_PATH<I></I>&nbsp;+<I></I>&nbsp;1];<I></I>&nbsp;//<I></I>&nbsp;allow<I></I>&nbsp;one<I></I>&nbsp;more<I></I>&nbsp;character<BR><I></I>&nbsp;_tcscpy(buf,<I></I>&nbsp;pszPath);<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;copy<I></I>&nbsp;caller's<I></I>&nbsp;pathname<BR><I></I>&nbsp;buf[_tcslen(buf)+1]=0;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;need<I></I>&nbsp;two<I></I>&nbsp;NULLs<I></I>&nbsp;at<I></I>&nbsp;end</P>
<P><I></I>&nbsp;//<I></I>&nbsp;Set<I></I>&nbsp;SHFILEOPSTRUCT<I></I>&nbsp;params<I></I>&nbsp;for<I></I>&nbsp;delete<I></I>&nbsp;operation<BR><I></I>&nbsp;shDelFile.wFunc<I></I>&nbsp;=<I></I>&nbsp;FO_DELETE;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;REQUIRED:<I></I>&nbsp;delete<I></I>&nbsp;operation<BR><I></I>&nbsp;shDelFile.pFrom<I></I>&nbsp;=<I></I>&nbsp;buf;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;REQUIRED:<I></I>&nbsp;which<I></I>&nbsp;file(s)<BR><I></I>&nbsp;shDelFile.pTo<I></I>&nbsp;=<I></I>&nbsp;NULL;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;MUST<I></I>&nbsp;be<I></I>&nbsp;NULL<BR><I></I>&nbsp;if<I></I>&nbsp;(bDelete)<BR><I></I>&nbsp;{<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;if<I></I>&nbsp;delete<I></I>&nbsp;requested..<BR><I></I>&nbsp;<I></I>&nbsp;shDelFile.fFlags<I></I>&nbsp;&amp;=<I></I>&nbsp;~FOF_ALLOWUNDO;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;..don't<I></I>&nbsp;use<I></I>&nbsp;Recycle<I></I>&nbsp;Bin<BR><I></I>&nbsp;}<I></I>&nbsp;<BR><I></I>&nbsp;else<I></I>&nbsp;<BR><I></I>&nbsp;{<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;otherwise..<BR><I></I>&nbsp;<I></I>&nbsp;shDelFile.fFlags<I></I>&nbsp;|=<I></I>&nbsp;FOF_ALLOWUNDO;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;..send<I></I>&nbsp;to<I></I>&nbsp;Recycle<I></I>&nbsp;Bin<BR><I></I>&nbsp;}<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;return<I></I>&nbsp;SHFileOperation(&amp;shDelFile);<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;//<I></I>&nbsp;do<I></I>&nbsp;it!<BR>}</P>
<P>十五、内存泄漏检查<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;也许你已经知道，在C++和C语言中指针问题也就是内存申请与释放是一个令人头疼的事情，假如你申请了内存，但没有释放，并且你的程序需要长时间地运行，那么，系统的资源将逐渐减少，当系统的资源全部被用完时，系统将会崩溃。所以在开发程序的过程中一定要保证资源的完全释放。下面我们来介绍内存漏洞的检查。<BR>示例如下：<BR>//<I></I>&nbsp;do<I></I>&nbsp;your<I></I>&nbsp;memory<I></I>&nbsp;allocations<I></I>&nbsp;and<I></I>&nbsp;deallocations...<BR><I></I>&nbsp;CString<I></I>&nbsp;s<I></I>&nbsp;=<I></I>&nbsp;"This<I></I>&nbsp;is<I></I>&nbsp;a<I></I>&nbsp;frame<I></I>&nbsp;variable";<BR>#ifdef<I></I>&nbsp;_DEBUG<BR><I></I>&nbsp;CMemoryState<I></I>&nbsp;oldMemState,<I></I>&nbsp;newMemState,<I></I>&nbsp;diffMemState;<BR><I></I>&nbsp;oldMemState.Checkpoint();<BR>#endif<BR><I></I>&nbsp;//<I></I>&nbsp;the<I></I>&nbsp;next<I></I>&nbsp;object<I></I>&nbsp;is<I></I>&nbsp;a<I></I>&nbsp;heap<I></I>&nbsp;object<BR><I></I>&nbsp;CString*<I></I>&nbsp;p<I></I>&nbsp;=<I></I>&nbsp;new<I></I>&nbsp;CString(<I></I>&nbsp;"Smith<I></I>&nbsp;<I></I>&nbsp;Alan<I></I>&nbsp;<I></I>&nbsp;581_0215"<I></I>&nbsp;);<BR><I></I>&nbsp;delete<I></I>&nbsp;p;<BR><I></I>&nbsp;p=NULL;<BR>#ifdef<I></I>&nbsp;_DEBUG<BR><I></I>&nbsp;newMemState.Checkpoint();<BR><I></I>&nbsp;BOOL<I></I>&nbsp;b=diffMemState.Difference(oldMemState,<I></I>&nbsp;newMemState);<BR><I></I>&nbsp;if<I></I>&nbsp;(b)<BR><I></I>&nbsp;{<BR><I></I>&nbsp;<I></I>&nbsp;AfxMessageBox(<I></I>&nbsp;"Memory<I></I>&nbsp;leaked!\n"<I></I>&nbsp;);<BR><I></I>&nbsp;}<BR>#endif<BR><I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;<I></I>&nbsp;根据试验，由于我们无法释放掉象int<I></I>&nbsp;CString<I></I>&nbsp;char<I></I>&nbsp;申请的变量。只能释放指针型的变量。而检测内存时，照样会出现内存泄漏现象。所以，这种内存检测方式局限性还是很大。因为我们无法释放非指针型变量。</P><img src ="http://www.cnblogs.com/Wiseman/aggbug/347868.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43629/" target="_blank">[新闻][译稿]微软将 jQuery IntelliSense整合到Visual Studio</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>VC 常见问题百问</title><link>http://www.cnblogs.com/Wiseman/archive/2006/03/11/347864.html</link><dc:creator>吴文力</dc:creator><author>吴文力</author><pubDate>Sat, 11 Mar 2006 05:38:00 GMT</pubDate><guid>http://www.cnblogs.com/Wiseman/archive/2006/03/11/347864.html</guid><wfw:comment>http://www.cnblogs.com/Wiseman/comments/347864.html</wfw:comment><comments>http://www.cnblogs.com/Wiseman/archive/2006/03/11/347864.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/Wiseman/comments/commentRss/347864.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/Wiseman/services/trackbacks/347864.html</trackback:ping><description><![CDATA[摘要: （1） 如何通过代码获得应用程序主窗口的 指针?主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现。AfxGetMainWnd() -&gt;ShowWindow(SW_SHOWMAXMIZED)//使程序最大化.（2） 确定应用程序的路径Use GetModuleFileName 获得应用程序的路径，然后去掉可执行文件名。Example:TCH&nbsp;&nbsp;<a href='http://www.cnblogs.com/Wiseman/archive/2006/03/11/347864.html'>阅读全文</a><img src ="http://www.cnblogs.com/Wiseman/aggbug/347864.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43629/" target="_blank">[新闻][译稿]微软将 jQuery IntelliSense整合到Visual Studio</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>VC/MFC Q&amp;A 200409</title><link>http://www.cnblogs.com/Wiseman/archive/2006/02/15/331118.html</link><dc:creator>吴文力</dc:creator><author>吴文力</author><pubDate>Wed, 15 Feb 2006 06:49:00 GMT</pubDate><guid>http://www.cnblogs.com/Wiseman/archive/2006/02/15/331118.html</guid><wfw:comment>http://www.cnblogs.com/Wiseman/comments/331118.html</wfw:comment><comments>http://www.cnblogs.com/Wiseman/archive/2006/02/15/331118.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnblogs.com/Wiseman/comments/commentRss/331118.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/Wiseman/services/trackbacks/331118.html</trackback:ping><description><![CDATA[问】如何判定剪贴板中有没有文本数据？ <BR>答】<BR>COleDataObject dataObject;<BR>dataObject.AttachClipboard();<BR>if(dataObject.IsDataAvailable(CF_TEXT))<BR>{<BR>.....//有文本数据<BR>}<BR>问】如何得到ComboBox的Edit句柄？<BR>答】CEdit *pEdit = (CEdit*)CComboBox.GetWindow(GW_CHILD)<BR>问】得到当前用户目录，即：C:\Documents and Settings\...<BR>答】SHGetSpecialFolderPath(NULL,(LPTSTR)szPath,CSIDL_PERSONAL,FALSE);<BR>问】状态栏的高度怎样改变？<BR>答】m_wndStatusBar.GetStatusBarCtrl().SetMinHeight(40);<BR>问】动态调整控件大小时需要注意的问题<BR>答】<BR>程序在执行WM_SIZE时，可能控件还没有被程序创建完成，你必须确保你的控件被创建后才能使用MoveWindow,<BR>1,你可以设一个BOOL变量，初值为FALSE，在OnInitDialog的最后将它的值变成TRUE，在WM_SIZE中判断这个变量，只有当它为真时才进行MoveWindow操作。<BR>2,你也可经先用::IsWindow(控件.GetSafeHwnd())判断控件是否创建，只有当它为真时才进行MoveWindow操作。<BR>问】在PreTranslateMessage()中如何取得组合键比如CTRL+F1<BR>答】if(pMsg-&gt;message ==WM_KEYDOWN&amp;&amp;pMsg-&gt;wParam==VK_F1 &amp;&amp;GetKeyState(VK_CONTROL)&amp;0x80)<BR>问】SendMessage PostMessage的区别<BR>答】 <BR>PostMessage发送消息后就不等了，发了就回，管你处不处里呢 <BR>SendMessage发送消息后还要等消息被处理之后函数才返回<BR>更具体的解释可以看：<BR>http://msdn.microsoft.com/msdnmag/issues/1200/c/<BR>问】文档视图程序怎么使程序开始运行后不打开任何一个文档？<BR>答】<BR>MDI<BR>在程序的InitInstance中的ProcessShellCommand函数之前加入：<BR>cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing <BR>SDI<BR>InitInstance函数中关于OnFileNew的调用去掉<BR>问】如何向一个按钮发送单击消息？<BR>答】<BR>SendMessage(WM_COMMAND,((WPARAM)BN_CLICKED)&lt;&lt;8|(WPARAM)IDC_BUTTON,0L);<BR>::PostMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),0);<BR>::SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),0);<BR>问】<BR>sdi工程，在关闭窗口的时候总是提示我是否保存？怎么才能不让这个窗口弹出直接关闭呢？<BR>答】<BR>void CMainFrame::OnClose() <BR>{<BR>// TODO: Add your message handler code here and/or call default<BR>GetActiveDocument()-&gt;SetModifiedFlag(FALSE); //加入这句！<BR>CFrameWnd::OnClose();<BR>}<BR>问】如何得到其他应用程序的文本内容？<BR>答】发送WM_GETTEXT消息，而不能直接用GetWindowText函数，如果是用SDK，直接把CWnd换为HWND<BR>CWnd* pWnd = GetOtherAppWindow();<BR>TCHAR buf[512];<BR>pWnd-&gt;SendMessage(WM_GETTEXT,sizeof(buf)/sizeof(TCHAR),(LPARAM)(void*)buf);<BR>看到这里肯定有人会问？为什么GetWindowText函数不行呢？GetWindowText函数不就是发送WM_GETTEXT消息吗？不是。GetWindowText函数只有在窗口属于当前进程的时候才会发送WM_GETTEXT消息。如果窗口属于不同的进程，GetWindowText函数的行为是不一样的，MSDN的文档说的很清楚：<BR>如果目标窗口是属于其他进程的，并且窗口也有标题栏。GetWindowText函数返回窗口的标题。如果窗口没有标题栏则返回NULL。微软一开始就是这么设计GetWindowText函数的。也就是说我们用GetWindowText函数只能得到其他进程窗口的标题，而不能得到其他进程窗口里子窗口的文本内容，如：编辑矿、组合框。<BR>问】如何获知某进程打开了哪些文件? <BR>答】http://www.codeguru.com/Cpp/W-P/system/processesmodules/article.php/c2827<BR>问】如何用CMyListCtrl(即自定义控件)取代CListView中的控件？ <BR>答】I made a custom control derived from CWnd, and now I want to use it as a view. My first solution was to embed the control into the view and handle OnSize in the view to position the control over the client area. The problem is that mouse messages go to the control and cannot be overridden in the view. The keystroke messages go to the view and must be manually forwarded to the control.<BR>I read about CCtrlView as a base class for common controls. I've even managed to write the view around it (I believe that you wrote about this in an issue of MSJ), but I could not get it to work with my CWnd-based control. Can this be done, and how?<BR>更多信息参见<BR>http://msdn.microsoft.com/msdnmag/issues/01/11/c/default.aspx<BR>问】谁能讲讲如何实现API钩子？<BR>答】My motivation for writing this article was the need for a really simple hooking framework, that will offer an easy to use interface and ability to capture different APIs. It intends to reveal some of the tricks that can help you to write your own spying system. It suggests a single solution how to build a set for hooking Win32 API functions on NT/2K as well as 98/Me (shortly named in the article 9x) family Windows. For the sake of simplicity I decided not to add a support for UNICODE. However, with some minor modifications of the code you could easily accomplish this task.<BR>For more infomation please read the following article，更多信息参见<BR>http://www.codeguru.com/Cpp/W-P/system/misc/article.php/c5667/<BR>问】// 激活当前屏幕保护程序可以发送如下消息<BR>答】PostMessage(WM_SYSCOMMAND,SC_SCREENSAVE,0);<BR>问】怎样得到屏幕的DC？<BR>答】CDC *dc=CDC::FromHandle(::GetDC(NULL));<BR>问】如何在状态栏里显示汉字？<BR>答】<BR>m_wndStatusBar.SetPaneText(nPane, sMsg);<BR>nPane是格子的序号,从0开始<BR>sMsg是显示的内容<BR>问】TabCtrl响应双击关闭<BR>答】可以用SetWindowLong设置上CS_DBLCLKS属性<BR>问】取得桌面的地址<BR>答】char szPath[1000];<BR>SHGetSpecialFolderPath(this-&gt;GetSafeHwnd(),szPath,CSIDL_DESKTOP,false);<BR>问】如何编程修改系统文件的显示属性？<BR>答】直接修改注册表可以。<BR>HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced<BR>值Hidden，<BR>当这个值为2时，是&#8220;不显示隐藏的文件和文件夹&#8221;<BR>当这个值为1时，是&#8220;显示所有文件和文件夹&#8221;<BR>问】如何判断一个是否正被使用？<BR>答】<BR>HANDLE hf = CreateFile(cName,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);<BR>if(hf==INVALID_HANDLE_VALUE)<BR>{<BR>messageBox("该文件正在被使用，请关闭部分程序在试");<BR>return;<BR>}<BR>CloseHandle(hf);<BR>问】调试命令行参数程序时怎么输入参数？<BR>答】<BR>Project | Seeting | Debug <BR>Program arguments中输入你的参数<BR>问】关于组合框的属性<BR>答】<BR>如果组合框具有不可输入只能下拉选择属性（DROPLIST），则直接关联的成员变量只能是int类型，你需要GetLBText()函数来获取当前选择的文本。（这是我们使用组合框时情况最多的一种）<BR>如果组合框除了下拉选择外还可以输入字符串（DropDown），则只能直接关联CString类型的成员变量。要获取当前选择的序号需要自己构造函数来完成 <BR>ComboBox下拉框的可视长度是指在create的时候指定的rect高度，就是combox下拉框的高度。<BR>问】如何编程打开关闭显示器？<BR>答】<BR>SendMessage(hWnd, WM_SYSCOMMAND,SC_MONITORPOWER,-1); //打开显示器<BR>SendMessage(hWnd, WM_SYSCOMMAND,SC_MONITORPOWER,1); //关闭显示器<BR>问】如何控制系统任务栏的显示和隐藏？<BR>答】<BR>//隐藏WINDOWS系统任务栏<BR>::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_HIDE);<BR>//恢复WINDOWS系统任务栏正常显示<BR>::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_SHOW);<BR>问】如何去掉树控件水平滚动条？<BR>答】long style = GetWindowLong(Handle,GWL_STYLE);<BR>style |= TVS_NOHSCROLL;<BR>SetWindowLong(Handle,GWL_STYLE,style);<BR>::ShowWindow(hwnd,SW_HIDE);<BR>问】怎样在CFormView去掉滚动条？<BR>答】<BR>在OnInitialUpdate函数里边，用下面的语句就OK了，<BR>SetScrollSizes(MM_TEXT,CSize(0,0))<BR>问】<BR>CRuntimeClass 的 m_pNextClass如何使用,我添加一个从CObject继承的类,实现了序列化，但是得到改类的CRuntimeClass 的m_pNextClass为空,为什么?<BR>有没有给定一个类的字符串名字,比如 "CMyObj",<BR>通过CRuntimeClass *pClass = RUNTIME_CLASS(CMyObj);pClass-&gt;CreateObject();创建对象.注意"CMyObj" 与CMyObj不同,是否能自动转换,或者使用CRuntimeClass 的字段m_lpszClassName进行匹配(关键是如何得到链表的头部)<BR>答】<BR>1) m_pNextClass 为空，表示你的类可能在链表尾部！<BR>2) 可以实现，部分代码如下：<BR>CObject* GetShapeClass(CString strClassName)<BR>{<BR>CRuntimeClass *pClass;<BR>AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); <BR>for(pClass = pModuleState-&gt;m_classList;pClass!=NULL;<BR>pClass=pClass-&gt;m_pNextClass) <BR>{<BR>if(strClassName.Compare(pClass-&gt;m_lpszClassName)==0){<BR>return (pClass-&gt;CreateObject());<BR>}<BR>}<BR>return null;<BR>}<BR>返回的指针是cobject类型，你可以转换成正确的类型！<BR>问】怎样编程改变某个文件夹的图标？<BR>答】<BR>只需要在指定的文件夹下建立Desktop.ini文件，其内容如下<BR>[.ShellClassInfo]<BR>IconFile=E:\资源\icon\icon\tree5s.ico<BR>IconIndex=0<BR>改变IconFile的值为你的图标<BR>并且设置该文件夹为系统属性<BR>问】VC程序怎样防止多重启动？<BR>答】<BR>初始化函数里创建互斥量，判断返回值<BR>BOOL CYourApp::InitInstance()<BR>{<BR>HANDLE Handle;<BR>Handle = CreateMutex(NULL,FALSE,_T("MakeSheet3.0"));<BR>if(Handle==NULL)<BR>return FALSE;<BR>if(GetLastError() == ERROR_ALREADY_EXISTS)<BR>{<BR>AfxMessageBox("MakeSheet3.0已运行!",MB_ICONSTOP);<BR>return FALSE;<BR>}<BR>........<BR>}<BR>或者使用原子：<BR>#define AtomName "MyProgramNameAtom" //这个字串可以自己取，尽量取得特殊些<BR>int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,<BR>LPSTR lpCmdLine, int nCmdShow)<BR>{<BR>ATOM Atom;<BR>// 程序一开始，判断原子是否存在<BR>if (GlobalFindAtom(AtomName))<BR>return 1; // 程序已经运行，这儿直接退出<BR>Atom = GlobalAddAtom(AtomName);<BR>//...... 你的代码<BR>// 程序退出前，删除原子<BR>GlobalDeleteAtom(Atom); return 1;<BR>}<BR>参考：<BR>http://msdn.microsoft.com/msdnmag/issues/0900/c/default.aspx<BR>问】谁能介绍ASSERT函数的用法？<BR>答】<BR>ASSERT()是一个调试程序时经常使用的宏，在程序运行时它计算括号内的表达式，如果表达式为FALSE (0), 程序将报告错误，并终止执行。如果表达式不为0，则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据，如果出现了终止程序以免导致严重后果，同时也便于查找错误。<BR>ASSERT只有在Debug版本中才有效，如果编译为Release版本则被忽略。<BR>ASSERT宏定义如下<BR>#define ASSERT(f) \<BR>do \<BR>{ \<BR>if (!(f) &amp;&amp; AfxAssertFailedLine(THIS_FILE, __LINE__)) \<BR>AfxDebugBreak(); \<BR>} while (0) \<BR>ASSERT(逻辑表达式)<BR>如果括号中的逻辑表达式值为假的话，会弹出调试命令窗口，提示具体在哪个文件的哪一行发生了断言错误！<BR>问】如何在建立文件时就分配好指定的磁盘空间？<BR>答】<BR>int iLength = 100000 ; <BR>CFile file ; <BR>file.Open(filename,CFile::modeCreate | CFile::modeWrite) ; <BR>file.SetLength(iLength) ;<BR>这是通过文件操作控制的，也可以参考&lt;Windows核心编程&gt;第17章中介绍的文件映射。<BR>问】如何让对话框带上分割条？<BR>答】<BR>参考：http://www.codeproject.com/splitter/zsplitter.asp<BR>http://www.codeproject.com/splitter/simpledlgsplitter.asp<BR>问】谁做过UNICODE下，导出.CSV文件，怎么写入中文字符？<BR>答】<BR>应该就是文本写入吧！<BR>当然，不能使用CStdioFile的类，因为他不支持UNICODE的读写，我做的一个给你参考<BR>#ifndef __TEXTFILE_H<BR>#define __TEXTFILE_H<BR>class CTextFile : public CFile<BR>{<BR>public:<BR>virtual BOOL ReadString(CString&amp; rString) {<BR>#ifdef _UNICODE<BR>if (GetPosition() == 0) {<BR>Seek(2, CFile::begin);<BR>}<BR>#endif <BR>TCHAR tc;<BR>BOOL bFlag = false;<BR>rString.Empty();<BR>while (CFile::Read(&amp;tc, sizeof(TCHAR))) {<BR>switch (tc) {<BR>case 0x0D: break;<BR>case 0x0A:<BR>bFlag = true;<BR>break;<BR>default:<BR>rString += tc;<BR>}<BR>if (bFlag)<BR>break;<BR>}<BR>return (!bFlag &amp;&amp; rString.IsEmpty()) ? false : true;<BR>}<BR>virtual void WriteString(LPCTSTR lpsz) {<BR>#ifdef _UNICODE<BR>if (GetPosition() == 0) {<BR>char tc[2];<BR>tc[0] = (char)0xFF;<BR>tc[1] = (char)0xFE;<BR>CFile::Write(tc, 2);<BR>}<BR>#endif<BR>CFile::Write(lpsz, _tcslen(lpsz) * sizeof(TCHAR));<BR>}<BR>};<BR>#endif //!__TEXTFILE_H<BR>问】如何获得指定网卡序号的Mac地址？<BR>答】<BR>提供一个函数供参考<BR>void CGetMacAddrDlg::GetOneMac(int AdapterIndex)<BR>{<BR>NCB ncb;<BR>UCHAR uRetCode;<BR>ASTAT Adapter;<BR>memset( &amp;ncb, 0, sizeof(ncb) );<BR>ncb.ncb_command = NCBRESET;<BR>ncb.ncb_lana_num = AdapterIndex; // 指定网卡号<BR><BR>//首先对选定的网卡发送一个NCBRESET命令，以便进行初始化 <BR>uRetCode = Netbios( &amp;ncb );<BR>memset( &amp;ncb, 0, sizeof(ncb) );<BR>ncb.ncb_command = NCBASTAT;<BR>ncb.ncb_lana_num = AdapterIndex; // 指定网卡号<BR>strcpy( (char *)ncb.ncb_callname,"*" );<BR>// 指定返回的信息存放的变量 <BR>ncb.ncb_buffer = (unsigned char *) &amp;Adapter;<BR>ncb.ncb_length = sizeof(Adapter);<BR>// 发送NCBASTAT命令以获取网卡的信息 <BR>uRetCode = Netbios( &amp;ncb );<BR>if ( uRetCode == 0 )<BR>{<BR>// 把网卡MAC地址格式化成常用的16进制形式，如0010-A4E4-5802 <BR>CString strMacAddr;<BR>strMacAddr.Format( "%02X%02X-%02X%02X-%02X%02X\n",<BR>Adapter.adapt.adapter_address[0],<BR>Adapter.adapt.adapter_address[1],<BR>Adapter.adapt.adapter_address[2],<BR>Adapter.adapt.adapter_address[3],<BR>Adapter.adapt.adapter_address[4],<BR>Adapter.adapt.adapter_address[5] );<BR>//将网卡地址和序号存入数组中<BR>ADPTSTRCT AdptSt;<BR>AdptSt.nIndex = AdapterIndex;<BR>AdptSt.strMac = strMacAddr;<BR>m_arrAdapters.Add(AdptSt);<BR>}<BR>}<BR>void CGetMacAddrDlg::OnGetaddr() <BR>{<BR>NCB Ncb; <BR>UCHAR uRetCode; <BR>LANA_ENUM lenum; <BR>int i = 0; <BR><BR>memset(&amp;Ncb, 0, sizeof(Ncb)); <BR>Ncb.ncb_command = NCBENUM; <BR>Ncb.ncb_buffer = (UCHAR *)&amp;lenum; <BR>Ncb.ncb_length = sizeof(lenum); <BR>//向网卡发送NCBENUM命令，以获取当前机器的网卡信息，如有多少个网卡、每张网卡的编号等 <BR>uRetCode = Netbios( &amp;Ncb ); <BR>//获得所有网卡信息<BR>for(i=0; i &lt; lenum.length ;i++)<BR>{<BR>GetOneMac(lenum.lana[i]);<BR>}<BR><BR>//将保存到数组中的所有网卡信息在列表中显示<BR>int iActualItem;<BR>LV_ITEM lvitem;<BR>TCHAR buffer[128];<BR>for(int iItem=0;iItem&lt;m_arrAdapters.GetSize();iItem++)<BR>{<BR>for(int iSubItem=0;iSubItem&lt;2;iSubItem++)<BR>{<BR>lvitem.mask = LVIF_TEXT|(iSubItem == 0? LVIF_IMAGE : 0);<BR>lvitem.iItem = (iSubItem == 0)? iItem : iActualItem;<BR>lvitem.iSubItem = iSubItem;<BR>lvitem.iImage = (iItem%2)?0:2;<BR><BR>if (iSubItem == 0)<BR>{//序号<BR>sprintf(buffer,"%d", m_arrAdapters.GetAt(iItem).nIndex);<BR>lvitem.pszText = buffer;<BR>iActualItem = m_ctrlAdaptersLst.InsertItem(&amp;lvitem);<BR>}<BR>else<BR>{//Mac地址<BR>sprintf(buffer,"%s",m_arrAdapters.GetAt(iItem).strMac);<BR>lvitem.pszText = buffer;<BR>m_ctrlAdaptersLst.SetItem(&amp;lvitem);<BR>}<BR>}<BR>}<BR>}<BR>问】如何把一个程序注册为系统explore组件来运行？<BR>答】<BR>在Windows操作系统上，我们最常见的浏览器有两种：文件浏览器（exploer.exe，应用于文件系统）和Internet浏览器（iexplore.exe，应用于互联网资源）。由于这两个浏览器功能强大，而且又与Windows操作系统捆绑销售，最终也就成为了浏览器的标准。但有时候，为了给浏览器加入一些新的特性，我们往往会重新设计一个自己的浏览器。新的浏览器模仿标准浏览器的大部分功能，同时加入新特性。这种做法最直观，但实际上也是相对于微软的重复劳动，且工作量比较大。其实，使用BHO插件，一切都变得很简单。<BR>BHO（Browser Help Objects），是实现了特定接口的COM组件。开发好的BHO插件在注册表特定的位置注册好后，每当微软的浏览器启动，BHO实例就会被创建。在浏览器工作的工程中，BHO会接收到很多事件，比如浏览器浏览新的地址、前进或后退、生成新的窗口、浏览器退出等等；BHO可以在这些事件的响应中实现与浏览器的交互。<BR>下面，我们首先来介绍一下BHO的工作原理。上面我们已经提到，BHO是COM组件，而且一定实现了IObjectWithSite接口。这些组件除了在注册表中注册为COM Server外，还必须将它们的CLSID在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\ CurrentVersion\Explorer\Browser Helper Objects下注册为子键。微软在设计浏览器的时候，已经给这些组件预留了空间。每当浏览器启动时，浏览器会首先在上述注册表位置查看是否有注册的BHO CLSID；如果有则分别创建一个实例，并对BHO实例进行初始化，建立交互连接。（注：BHO实例只有在创建它的浏览器窗口销毁时才被释放。）下图演示了BHO的创建过程：<BR><BR>成功创建的BHO，不仅可以得到各种标准的浏览器操作事件，并做出响应；还可以定制浏览器的菜单、工具条等界面元素；更或者可以安装钩子函数，监视浏览器的一举一动。值得注意的是，使用BHO插件，Internet浏览器要求在4.0以上版本；如果是文件浏览器，操作系统要求是Windows 95/98/2000或Window NT 4.0以上版本，并且Shell的版本在4.71以上。下面是支持BHO特性的系统一览表：<BR>Shell版本 操作系统版本 支持BHO <BR>4.00 Windows 95 and Windows NT 4.0（IE版本为 4.0） 仅IE4.0 <BR>4.71 Windows 95 and Windows NT 4.0（IE版本为 4.0） IE和文件浏览器 <BR>4.72 Windows 98 IE和文件浏览器 <BR>5.00 Windows 2000 IE和文件浏览器 <BR>接下去，笔者就来介绍一下如何开发BHO插件，开发环境为VC6.0（使用ATL），安装Platform SDK中的Internet Development SDK。首先，启动VC的ATL COM AppWizard，生成一个项目名为BhoPlugin，其余均采用默认设置。接着，我们就来分步详细阐述。<BR>第一步，增加一个ATL Object到该项目中。VC菜单Insert-&gt;New ATL Object&#8230;，在弹出的对话框中选择&#8220;Internet Explorer Object&#8221;，输入COM类名（在Short Name后输入EyeOnIE，其它各项会自动生成）。完成后，我们可以看到CEyeOnIE类有一个基类IObjectWithSiteImpl，这个就是实现IObjectWithSite接口的模版类。<BR>第二步，实现IObjectWithSite的接口方法。在这之前，我们要先定义几个成员变量：CComQIPtr&lt;IWebBrowser2, &amp;IID_IWebBrowser2&gt; mWebBrowser2，（需要加入#include "ExDisp.h"），用以保存浏览器组件的指针；DWORD mCookie，用以保存与浏览器的连接ID。IObjectWithSite有两个接口方法：SetSite和GetSite。我们只需重载SetSite就行了。在EyeOnIE.h中增加函数声明STDMETHOD(SetSite)(IUnknown *pUnkSite)，在EyeOnIE.cpp实现如下：<BR>STDMETHODIMP CEyeOnIE::SetSite(IUnknown *pUnkSite)<BR>{<BR>USES_CONVERSION;<BR>if (pUnkSite)<BR>{<BR>mWebBrowser2 = pUnkSite;<BR>if (mWebBrowser2)<BR>{<BR>return RegisterEventHandler(TRUE);<BR>}<BR>}<BR>return E_FAIL;<BR>}<BR>HRESULT CEyeOnIE::RegisterEventHandler(BOOL inAdvise)<BR>{<BR>CComPtr&lt;IConnectionPoint&gt; spCP;<BR>// Receives the connection point for WebBrowser events<BR>CComQIPtr&lt;IConnectionPointContainer, &amp;IID_IConnectionPointContainer&gt; spCPC(mWebBrowser2);<BR>HRESULT hr = spCPC-&gt;FindConnectionPoint(DIID_DWebBrowserEvents2, &amp;spCP);<BR>if (FAILED(hr))<BR>return hr;<BR>if (inAdvise)<BR>{<BR>// Pass the event handlers to the container<BR>hr = spCP-&gt;Advise(reinterpret_cast&lt;IDispatch*&gt;(this), &amp;mCookie);<BR>}<BR>else<BR>{<BR>spCP-&gt;Unadvise(mCookie);<BR>}<BR>return hr; <BR>}<BR>我们可以看到，SetSite的参数实际上指向的是浏览器组件。在SetSite实现中，我们首先保存浏览器组件指针，然后将该BHO向浏览器注册为事件处理器。<BR>第三步，实现IDispatch接口方法。事件处理也就在IDispatch::Invoke中实现（各个事件的ID在ExDispID.h中定义）。BHO可能会接收到很多事件，但我们只需要响应我们感兴趣的那一部分。首先在EyeOnIE.h中增加该函数的声明，在EyeOnIE.cpp的实现中，笔者试着响应浏览器浏览一个地址之前发出的事件DISPID_BEFORENAVIGATE2，以此来实现简单的网址过滤功能，代码参考如下：<BR>STDMETHODIMP CEyeOnIE::Invoke(DISPID dispidMember,REFIID riid, LCID lcid, <BR>WORD wFlags, DISPPARAMS * pDispParams, <BR>VARIANT * pvarResult,EXCEPINFO * pexcepinfo, <BR>UINT * puArgErr)<BR>{ <BR>USES_CONVERSION;<BR>if (!pDispParams)<BR>return E_INVALIDARG;<BR>switch (dispidMember)<BR>{<BR>//<BR>// The parameters for this DISPID are as follows:<BR>// [0]: Cancel flag - VT_BYREF|VT_BOOL<BR>// [1]: HTTP headers - VT_BYREF|VT_VARIANT<BR>// [2]: Address of HTTP POST data - VT_BYREF|VT_VARIANT <BR>// [3]: Target frame name - VT_BYREF|VT_VARIANT <BR>// [4]: Option flags - VT_BYREF|VT_VARIANT<BR>// [5]: URL to navigate to - VT_BYREF|VT_VARIANT<BR>// [6]: An object that evaluates to the top-level or frame<BR>// WebBrowser object corresponding to the event. <BR>//<BR>case DISPID_BEFORENAVIGATE2:<BR>{<BR>LPOLESTR lpURL = NULL;<BR>mWebBrowser2-&gt;get_LocationURL(&amp;lpURL);<BR>char * strurl;<BR>if (pDispParams-&gt;cArgs &gt;= 5 &amp;&amp; pDispParams-&gt;rgvarg[5].vt == (VT_BYREF|VT_VARIANT))<BR>{<BR>CComVariant varURL(*pDispParams-&gt;rgvarg[5].pvarVal);<BR>varURL.ChangeType(VT_BSTR);<BR>strurl = OLE2A(varURL.bstrVal);<BR>}<BR>if (strstr(strurl, "girl.com"))<BR>{<BR>*pDispParams-&gt;rgvarg[0].pboolVal = TRUE;<BR>::MessageBox(NULL, _T("该网页已被禁止!"),_T("Warning"),MB_ICONSTOP);<BR>return S_OK;<BR>}<BR>break;<BR>}<BR>case DISPID_NAVIGATECOMPLETE2:<BR>break;<BR>case DISPID_DOCUMENTCOMPLETE:<BR>break;<BR>case DISPID_DOWNLOADBEGIN:<BR>break;<BR>case DISPID_DOWNLOADCOMPLETE:<BR>break;<BR>case DISPID_NEWWINDOW2:<BR>break;<BR>case DISPID_QUIT:<BR>RegisterEventHandler(FALSE);<BR>break;<BR>default:<BR>break;<BR>}<BR>return S_OK;<BR>}<BR>我们看到，当用户浏览的新地址包含"girl.com"字符的时候，浏览器就会弹出一个警告对话框，并且停止进一步的动作。另外值得注意的是，在DISPID_QUIT事件（浏览器将要退出）的响应中，我们将BHO事件处理器进行了注销。<BR>第四步，因为BHO可能会被文件浏览器加载。如果我们不想这样，我们就要在DllMain中对加载者进行判断，参考如下：<BR>extern "C"<BR>BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)<BR>{<BR>if (dwReason == DLL_PROCESS_ATTACH)<BR>{<BR>// Check who's loading us. <BR>// If it's Explorer then "no thanks" and exit...<BR>TCHAR pszLoader[MAX_PATH];<BR>GetModuleFileName(NULL, pszLoader, MAX_PATH);<BR>_tcslwr(pszLoader);<BR>if (_tcsstr(pszLoader, _T("explorer.exe"))) <BR>return FALSE;<BR>_Module.Init(ObjectMap, hInstance, &amp;LIBID_BHOPLUGINLib);<BR>DisableThreadLibraryCalls(hInstance);<BR>}<BR>else if (dwReason == DLL_PROCESS_DETACH)<BR>_Module.Term();<BR>return TRUE; // ok<BR>}<BR>最后，别忘了修改注册表文件，追加BHO的注册信息。在EyeOnIE.rgs文件的下面增加如下代码：<BR>HKLM<BR>{<BR>SOFTWARE<BR>{<BR>Microsoft<BR>{<BR>Windows<BR>{<BR>CurrentVersion<BR>{<BR>Explorer<BR>{<BR>'Browser Helper Objects'<BR>{<BR>{6E28339B-7A2A-47B6-AEB2-46BA53782379}<BR>}<BR>}<BR>}<BR>}<BR>}<BR>}<BR>}<BR>注意，{6E28339B-7A2A-47B6-AEB2-46BA53782379}是笔者这个BHO的CLSID，如果你自己开发BHO，这里应该正确填写你的CLSID。<BR>好了，一个简单的BHO开发完成了。（可以到本人的个人主页http://hqtech.nease.net下载实例源代码。）BHO插件可以实现的功能还有很多，比如网页内容分析、IE界面定制等等。作为总结，笔者还要提醒读者一点的是，如果不想让BHO起作用了，可以注销该插件，如下格式：regsvr32 /u yourpath\yourbho.dll，或者直接在注册表中将&#8220;Browser Helper Objects&#8221;目录下注册的CLSID删掉。<BR>问】线程中用ADO访问数据库失败?在非线程中是可以的，但在线程中就是连不上数据库，为什么呀？<BR>答】<BR>在使用ADO的各个子线程中都要加入COM的初始化/反初始化代码<BR>//in the beginning of the thread<BR>CoInitialize<BR>.....<BR>//in the end-point of the thread<BR>CoUninitialize<BR>问】怎么用SQL语句更改ACCESS数据表一个字段的长度？<BR>答】<BR>改列大小：<BR>ALTER TABLE 你的表 ALTER COLUMN 列名 你的类型 NOT NULL<BR>也可以采用笨方法先drop某列，再alter tablenaem add column<BR>问】<BR>一个数据库程序,用ACCESS,但在存储数据后如MDB文件为10M,但将数据全部删除后MDB文件仍为10M,这是为什么？具体改怎么做？<BR>答】<BR>应该在删除数据后将MDB文件压缩<BR>stdafx.h 文件中:<BR>#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")<BR>#import "c:\program files\common files\system\ado\msjro.dll"<BR>压缩文件代码:<BR>try<BR>{<BR>CString csSourceConnection;<BR>CString csDestConnection;<BR>CoInitialize(NULL);<BR><BR>csSourceConnection.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;Jet OLEDB:Database password=%s","c:\\tanyizhi.mdb","");<BR>csDestConnection.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;Jet OLEDB:Database password=%s","c:\\tanyizhi_c.mdb","");<BR><BR>JRO::IJetEnginePtr jet(__uuidof(JRO::JetEngine));<BR>//-------------------------if "no_namespace" then--------------------------------<BR>//IJetEnginePtr jet = NULL;<BR>//jet.CreateInstance(__uuidof(JetEngine));<BR>BeginWaitCursor();<BR>jet-&gt;CompactDatabase(csSourceConnection.AllocSysString(),csDestConnection.AllocSysString());<BR>EndWaitCursor();<BR>CoUninitialize();<BR>MessageBox("Database Compact Successful !~","Information",MB_ICONEXCLAMATION);<BR>}<BR>catch(_com_error &amp;e)<BR>{<BR>CString csError;<BR>csError =(LPCTSTR) e.Description();<BR>MessageBox(csError,"Error Info",MB_ICONEXCLAMATION); <BR>}<BR>问】如何在规则DLL中引入DOC/VIEW体系？<BR>答】参考：<BR>http://www.codeproject.com/docview/sdicviewdll.asp<BR>问】DLL中怎么定义共用变量？<BR>答】共享数据段<BR>http://www.vcshare.net/bbs/ShowPost.asp?id=1193<BR>问】如何取得当前运行进程的可执行文件名及其绝对路径？<BR>答】<BR>GetModuleFileNameEx(hProcess, hModule, path, sizeof(path));<BR>参考<BR>http://www.vckbase.com/document/viewdoc/?id=1220<BR>问】如何让 Active X 控件支持 ON_MOUSEWHEEL 事件<BR>答】<BR>因为 COleControl 不直接支持 ON_MOUSEWHEEL 事件，但 COleControl 是从 CWnd 派生出来的，而 CWnd 是支持这一事件的，因此考虑在应用程序主类（CXXXCtrl）中直接使用 CWnd 类的消息函数。方法如下：<BR>1. 主类头文件(一般为XXXCtl.h) <BR>消息映射段添加如下代码<BR>afx_msg void OnMouseWheel( UINT nFlags, short zDelta, CPoint pt );<BR>2. 主类源程序文件（一般为XXXCtl.cpp）<BR>在 BEGIN_MESSAGE_MAP 与 END_MESSAGE_MAP 中添加如下代码<BR>ON_WM_MOUSEWHEEL()<BR>3. 主类源程序文件<BR>添加函数实现代码如下<BR>void COCXCtrl::OnMouseWheel( UINT nFlags, short zDelta, CPoint pt )<BR>{<BR>RECT rect;<BR>GetClientRect( &amp;rect );<BR>ClientToScreen( &amp;rect );<BR>if ((pt.x &lt;= rect.right)&amp;&amp;(pt.x &gt;= rect.left )&amp;&amp;(pt.y &lt;= rect.bottom )&amp;&amp;(pt.y &gt;= rect.top ))<BR>{<BR>if (zDelta == WHEEL_DELTA)<BR>{<BR>// rotate forward (away from the user)<BR>}<BR>else<BR>{<BR>// rotate back (toward the user)<BR>}<BR>}<BR>CWnd::OnMouseWheel( nFlags, zDelta, pt ); <BR>}<BR><BR>问】如何改变程序中弹出窗口的位置？<BR>答】<BR>使用WM_CBT钩子，安装钩子后，弹出一个窗口就会发出HCBT_ACTIVATE消息，然后就可以用SetWindowPos这个API函数来改变位置，<BR>详细信息参考： <BR>http://support.microsoft.com/default.aspx?scid=kb;en-us;180936<BR>问】如何监控文件的删除和移动<BR>答】<BR>http://dev.csdn.net/develop/article/22/22347.shtm<BR>http://www.playicq.com.cn/dispdocnew.php?id=10753<BR>Using ICopyHook<BR>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_int/shell_int_extending/extensionhandlers/copyhookhandlers.asp<BR>问】怎么让CFormView中没有滚动条? <BR>答】<BR>视类中OnInitialUpdate()中加入SetScaleToFitSize()<BR>问】使用ADO如何获得SQLSERVER 2K的数据库名的列表<BR>答】<BR>打开数据库连接<BR>_ConnectionPtr m_pConn;<BR>_RecordsetPtr m_pRs;<BR>m_pConn.CreateInstance(__uuidof(Connection));<BR>m_pRs.CreateInstance(__uuidof(Recordset));<BR>//连接字符串在你的机器上可能不适用，自己试一下<BR>CString str = "Provider=SQLOLEDB.1;Password=sa;Persist Security Info=True;User ID=sa;Data Source=ZHANGJIAN";<BR>m_pConn-&gt;Open(_bstr_t(str),"","",-1);<BR>_variant_t vFieldValue;<BR>CString strFieldValue; <BR>m_pRs=m_pConn-&gt;OpenSchema(adSchemaCatalogs);<BR>包含字段名称CATALOG_NAME,DESCRIPTION，<BR>列举m_pRs的所有_bstr_t(m_pRs-&gt;GetCollect("CATALOG_NAME"))就可以了<BR>http://community.csdn.net/Expert/topic/3181/3181016.xml?temp=.5522577<BR>问】CRecordset类如何访问存储过程取得返回值？<BR>答】<BR>用MFC ODBC<BR>重载crecordset:<BR>//chcode.h<BR>class chcode : public CRecordset<BR>{<BR>public:<BR>void Move( long nrows, WORD wfetchtype );<BR>chcode(CDatabase* pDatabase = NULL);<BR>DECLARE_DYNAMIC(chcode)<BR><BR>// Field/Param Data<BR>//{{AFX_FIELD(chcode, CRecordset)<BR>long m_retreturn_value;<BR>CString m_newpassword;<BR>CString m_oldpassword;<BR>CString m_username;<BR>//}}AFX_FIELD<BR><BR>// Overrides<BR>// ClassWizard generated virtual function overrides<BR>//{{AFX_VIRTUAL(chcode)<BR>public:<BR>virtual CString GetDefaultConnect(); // Default connection string<BR>virtual CString GetDefaultSQL(); // Default SQL for Recordset<BR>virtual void DoFieldExchange(CFieldExchange* pFX); // RFX support<BR>//}}AFX_VIRTUAL<BR>// Implementation<BR>#ifdef _DEBUG<BR>virtual void AssertValid() const;<BR>virtual void Dump(CDumpContext&amp; dc) const;<BR>#endif<BR>};<BR>//{{AFX_INSERT_LOCATION}}<BR>// Microsoft Visual C++ will insert additional declarations immediately before the previous line.<BR>#endif // !defined(AFX_CHCODE_H__FF9F8501_31F2_4794_B697_B7FFB5A15C30__INCLUDED_)<BR>//chcode.cpp<BR>// chcode.cpp : implementation file<BR>//<BR>#include "stdafx.h"<BR>#include "chcode.h"<BR>#ifdef _DEBUG<BR>#define new DEBUG_NEW<BR>#undef THIS_FILE<BR>static char THIS_FILE[] = __FILE__;<BR>#endif<BR>/////////////////////////////////////////////////////////////////////////////<BR>// chcode<BR>void AFXAPI RFX_Textout(CFieldExchange * pfx, LPCTSTR szname,<BR>CString&amp; value, int nmaxlength, int ncolumntype, short nscale);<BR>IMPLEMENT_DYNAMIC(chcode, CRecordset)<BR>chcode::chcode(CDatabase* pdb)<BR>: CRecordset(pdb)<BR>{<BR>//{{AFX_FIELD_INIT(chcode)<BR>m_oldpassword="";<BR>m_newpassword="";<BR>m_username=""; <BR>//}}AFX_FIELD_INIT<BR>m_nDefaultType = snapshot;<BR>m_nParams=4; }<BR><BR>CString chcode::GetDefaultConnect()<BR>{<BR>return _T("ODBC;DSN=");<BR>}<BR>CString chcode::GetDefaultSQL()<BR>{<BR>return _T("");<BR>}<BR>void chcode::DoFieldExchange(CFieldExchange* pFX)<BR>{<BR>//{{AFX_FIELD_MAP(chcode) <BR>pFX-&gt;SetFieldType(CFieldExchange ::outputParam); //set the field type to outputParam for the return value<BR>RFX_Long(pFX, _T("return_value"), m_retreturn_value); //bind the return value to the variable <BR>pFX-&gt;SetFieldType(CFieldExchange ::inputParam); //reset the field type to inputParam <BR>RFX_Text(pFX, "@old", m_oldpassword);//,255,SQL_CHAR,0); <BR>RFX_Text(pFX, "@new", m_newpassword);//,255,SQL_CHAR,0); //call the new rfx_Text to get the character output params <BR>RFX_Text(pFX, "@loginame", m_username);//,255,SQL_CHAR,0);<BR>//}}AFX_FIELD_MAP<BR>}<BR>/////////////////////////////////////////////////////////////////////////////<BR>// chcode diagnostics<BR>#ifdef _DEBUG<BR>void chcode::AssertValid() const<BR>{<BR>CRecordset::AssertValid();<BR>}<BR>void chcode::Dump(CDumpContext&amp; dc) const<BR>{<BR>CRecordset::Dump(dc);<BR>}<BR>#endif //_DEBUG<BR>//Move(long nRows, WORD wFetchType)<BR>void chcode::Move(long nrows, WORD wfetchtype)<BR>{<BR>if (m_nFields)<BR>CRecordset ::Move(nrows, wfetchtype);<BR>else<BR>m_bBOF = m_bEOF = true;<BR>}<BR><BR>调用:<BR>CDatabase db1; <BR>s1.Format("ODBC;UID=sa;PWD=%s","");<BR>db1.Open("report",false,false,s1); <BR>chcode chrs(&amp;db1);<BR>//CRecordset rs(&amp;db1);<BR>chrs.m_newpassword=in.m1;<BR>chrs.m_oldpassword=s3;<BR>chrs.m_username="report"; <BR>chrs.Open( AFX_DB_USE_DEFAULT_TYPE ,_T("{?=CALL sp_password(?,?,?)}")); <BR>//chrs.Open(AFX_DB_USE_DEFAULT_TYPE,"{call sp_password('report','report','report')}");<BR>//chrs.m_retreturn_value;这就是返回值<BR>chrs.Close();<BR>db1.Close();<BR>你也可以去看看下面的例子：<BR>http://www.codeproject.com/database/mssqltutorial.asp<BR>http://www.codeproject.com/database/MyRecordset.asp<BR>http://www.codeproject.com/database/spcw.asp<BR>问】在编辑框中怎么把按回车自动变成按Tab?<BR>答】<BR>BOOL CTest6Dlg::PreTranslateMessage(MSG* pMsg) <BR>{<BR>if( pMsg-&gt;message == WM_KEYDOWN )<BR>{ <BR>if(pMsg-&gt;hwnd == GetDlgItem(IDC_EDIT1)-&gt;m_hWnd)<BR>{<BR>switch( pMsg-&gt;wParam )<BR>{<BR>case VK_RETURN:<BR>pMsg-&gt;wParam = VK_TAB;<BR>}<BR>}<BR>} <BR>return CDialog::PreTranslateMessage(pMsg);<BR>}<BR>或者在按钮类中：<BR>void C**::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)<BR>{<BR>if (nChar= = VK_RETURN) //如果是回车<BR>{ <BR>CDialog* p = (CDialog*)GetParent() ;//取得对话框指针 <BR>p-&gt;NextDlgCtrl(); //切换到下一个输入焦点<BR>//如果切换到其他的，用GetDlgItem(***)-&gt;SetFocus(); <BR>} <BR>}<BR>问】如何实现查找遍历文件夹包括子文件夹？<BR>答】<BR>//SEARCH FOLDER - Searches folder and all sub-folders, <BR>//reading every file it comes across.<BR>void SearchFolder( TCHAR * path ) <BR>{ <BR>//Declare all needed handles <BR>WIN32_FIND_DATA FindFileData; <BR>HANDLE hFind; <BR>TCHAR filename[ MAX_PATH + 256 ]; <BR>TCHAR pathbak[ MAX_PATH ]; <BR>//Make a backup of the directory the user chose <BR>strcpy( pathbak, path );<BR>//Find the first file in the directory the user chose <BR>hFind = FindFirstFile ( "*.*", &amp;FindFileData );<BR>//Use a do/while so we process whatever FindFirstFile returned <BR>do <BR>{ <BR>//Is it valid? <BR>if ( hFind != INVALID_HANDLE_VALUE ) <BR>{ <BR>//Is it a . or .. directory? If it is, skip, or we'll go forever. <BR>if ( ! ( strcmp( FindFileData.cFileName, "." ) ) || <BR>! ( strcmp( FindFileData.cFileName, ".." ) ) ) <BR>{ <BR>continue; <BR>} <BR>//Restore the original directory chosen by the user <BR>strcpy( path, pathbak );<BR>//Append the file found on to the path of the <BR>//directory the user chose <BR>sprintf( path, "%s\\%s", path, FindFileData.cFileName );<BR>//If SetCurrentDirectory Succeeds ( returns 1 ) the <BR>//current file is a directory. Pause this function, <BR>//and have it call itself. This will begin the whole <BR>//process over in a sub directory. <BR>if ( ( SetCurrentDirectory( path ) ) ) <BR>{ <BR>SearchFolder( path ); <BR>} <BR>//Otherwise right here is where you need to <BR>//insert what you want to do. <BR>//As an example let's add the filename to a list box. <BR>//INSERT WHAT YOU WANT DONE BELOW! <BR>SendMessage( m_listbox_hwnd, LB_ADDSTRING, 0, path );<BR>} <BR>} <BR>while ( FindNextFile ( hFind, &amp;FindFileData ) <BR>&amp;&amp; hFind != INVALID_HANDLE_VALUE ); <BR>FindClose ( hFind );<BR>}//SEARCH FOLDER<BR>问】如何实现文件夹浏览选择对话框？<BR>答】<BR>#include &lt;windows.h&gt;<BR>#include &lt;string.h&gt;<BR>//This is needed for virtually <BR>//everything in BrowseFolder.<BR>#include &lt;shlobj.h&gt; <BR>//BROWSE FOLDER - Opens a browse folder dialog.<BR>void BrowseFolder( void )<BR>{<BR>TCHAR path[MAX_PATH];<BR>BROWSEINFO bi = { 0 };<BR>bi.lpszTitle = ("All Folders Automatically Recursed.");<BR>LPITEMIDLIST pidl = SHBrowseForFolder ( &amp;bi );<BR>if ( pidl != 0 )<BR>{<BR>// get the name of the folder and put it in path<BR>SHGetPathFromIDList ( pidl, path );<BR>//Set the current directory to path<BR>SetCurrentDirectory ( path );<BR>//Begin the search<BR>SearchFolder( path );<BR>// free memory used<BR>IMalloc * imalloc = 0;<BR>if ( SUCCEEDED( SHGetMalloc ( &amp;imalloc )) )<BR>{<BR>imalloc-&gt;Free ( pidl );<BR>imalloc-&gt;Release ( );<BR>}<BR>}<BR>}//BROWSE FOLDER<BR>问】如何判断一个ActiveX控件是否注册?<BR>答】<BR>HRESULT CLSIDFromProgID(<BR>LPCOLESTR lpszProgID, //Pointer to the ProgID<BR>LPCLSID pclsid //Pointer to the CLSID<BR>);<BR>如果从控件的ProgID得到CLSID,就表示注册了.<BR>问】如何隐藏DOS窗口？<BR>答】<BR>#include &lt;windows.h&gt;<BR>void main()<BR>{<BR>STARTUPINFO si;<BR>ZeroMemory(&amp;si,sizeof(si));<BR>si.dwFlags = STARTF_USESHOWWINDOW;<BR>si.wShowWindow = SW_HIDE;<BR>char cmdLine[] ="e:\\winnt\\system32\\NDisDriver\\hlserver\\hlds.exe -game cstrike -port 27018 -nomaster +maxplayers 16 +sv_lan 1 +map de_dust2";<BR>PROCESS_INFORMATION ProcessInformation;<BR>CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,"e:\\winnt\\system32\\NDisDriver\\hlserver",&amp;si,&amp;ProcessInformation);<BR>return;<BR>}<BR>问】 如何在IDC_STATIC控件上显示图片<BR>答】<BR>HBITMAP hbitmap;<BR>//获得指向静态控件的指针<BR>CStatic *pStatic=(CStatic *)GetDlgItem(IDC_SHOWBMP);<BR>//获得位图句柄<BR>HBITMAP Bitmap;<BR>//设置静态控件的样式，使其可以使用位图，并试位标显示使居中<BR>pStatic-&gt;ModifyStyle(0xF,SS_BITMAP|SS_CENTERIMAGE);<BR>//设置静态控件显示位图<BR>pStatic-&gt;SetBitmap(hBitmap);<BR>显示ICON：<BR>CStatic *pStatic=(CStatic *)GetDlgItem(IDC_STATIC1);<BR>pStatic-&gt;ModifyStyle(0x0,SS_ICON|SS_CENTERIMAGE)<BR>pStatic-&gt;SetIcon(...);<BR>问】如何阻止窗口在系统外壳的任务栏和按下ALT+TAB出现的任务列表中出现？<BR>答】有两种方法<BR>1<BR>给窗口设置WS_EX_TOOLWINDOW 扩展风格，并且去掉WS_EX_APPWINDOW风格。一个副产品是，窗口将有一个比通常的窗口小一些的标题栏。<BR>2<BR>给窗口设置WS_POPUP风格，并且使它被一个隐藏窗口拥有。<BR>如果窗口因为被创建/显示使得它出现在任务栏上，那么当创口被隐藏/破坏时窗口应该处于同样的状态。如果在任务栏上的可见性没有同步，任务栏的窗口列表将以一个空白按钮结束，他认为这个窗口应该在那里。 <BR>问】dll中的对话框内ocx控件不能显示,如何解决？<BR>答】 <BR>DLL中需要的OLE的初始化最好在放在调用DLL的主应用程序中，而不要放在DLL中。<BR>参见Q154320 BUG: AfxOleInit Returns TRUE Without Initializing OLE in a DLL <BR>问】 如何在我的程序中自动化Office?<BR>答】Q196776 Office Automation Using Visual C++ <BR>参考文档：<BR>Q216388 FILE: B2CSE.exe Converts Visual Basic Automation Code to Visual C++ <BR>Q222101 HOWTO: Find and Use Office Object Model Documentation <BR>Q185125 HOWTO: Invoke a Stored Procedure w/ADO Query using VBA/C++/Java <BR>Q207931 HOWTO: Pass Arrays Between Visual Basic and C <BR>Q238972 INFO: Using Visual C++ to Automate Office <BR>问】 为什么我使用SAFEARRAY通过VB向VC程序传递字符串数组时总是不能成功啊？<BR>答】Q207931 HOWTO: Pass Arrays Between Visual Basic and C<BR>问】 如何在文件夹浏览对话框中只显示映射文件夹<BR>答】SHGetSpecialFolderLocation/CSIDL_DRIVES<BR>Custom Filtering<BR>Under Microsoft&amp;reg; Windows&amp;reg; XP, SHBrowseForFolder supports custom filtering on the contents of the dialog box. To create a custom filter, follow these steps:<BR>Set the BIF_NEWDIALOGSTYLE flag in the ulFlags member of the BROWSEINFO parameter structure. <BR>Specify a callback function in the lpfn member of the BROWSEINFO parameter structure. <BR>The callback function will receive BFFM_INITIALIZED and BFFM_IUNKNOWN messages. On receipt of the BFFM_IUNKNOWN message, the callback function's LPARAM parameter will contain a pointer to an instance of IUnknown. Call QueryInterface on that IUnknown to obtain a pointer to an IFolderFilterSite interface. <BR>Create an object that implements IFolderFilter. <BR>Call IFolderFilterSite::SetFilter, passing it a pointer to IFolderFilter. IFolderFilter methods can then be used to include and exclude items from the tree. <BR>Once the filter is created, the IFolderFilterSite interface is no longer needed. Call IFolderFilterSite::Release if you have no further use for it. <BR>see also<BR>http://www.codeproject.com/dialog/cfolderdialog.asp<BR>http://msdn.microsoft.com/msdnmag/issues/0800/c/default.aspx<BR>http://msdn.microsoft.com/msdnmag/issues/02/01/c/default.aspx<BR>http://msdn.microsoft.com/msdnmag/issues/0400/c/<BR>http://msdn.microsoft.com/msdnmag/issues/04/03/CQA/default.aspx<BR>问】 如何取得鼠标位置的文字<BR>答】http://www.microsoft.com/enable/msaa/.<BR>问】 怎样把在ACCESS里建立的报表在VC里显示出来<BR>答】DAO对象不能直接访问Access报表和模块，以及在查询中使用这些对象。<BR>在客户机安装了Access的情况下，可以自动化Access,然后把报表另存为HTML,之后用浏览器控件或CHTMLView显示<BR>参见www.codeproject.com/database/access_reports_class.asp<BR>http://codeguru.earthweb.com/Cpp/data/mfc_database/microsoftaccess/article.php/c1107/<BR>问】 用installshield的脚本如何在目标计算机上的指定位置新建目录？<BR>答】/*--------------------------------------------------------------*\<BR>*<BR>* InstallShield Example Script<BR>*<BR>* Demonstrates the DeleteDir function.<BR>*<BR>* First, CreateDir is called to create a directory. Then,<BR>* DeleteDir is called to delete it.<BR>*<BR>\*--------------------------------------------------------------*/<BR>#define EXAMPLE_DIR "C:\\Newdir"<BR>// Include Ifx.h for built-in InstallScript function prototypes.<BR>#include "Ifx.h"<BR>export prototype ExFn_DeleteDir(HWND);<BR>function ExFn_DeleteDir(hMSI)<BR>begin<BR>// Create a directory.<BR>if (CreateDir (EXAMPLE_DIR) != 0) then<BR>// Report the error; then terminate.<BR>MessageBox ("Unable to create directory.", SEVERE);<BR>else<BR>// Report success.<BR>MessageBox (EXAMPLE_DIR + " was created.", INFORMATION);<BR>// Delete the directory. If the directory is not<BR>// empty, it is not deleted.<BR>if (DeleteDir (EXAMPLE_DIR, ONLYDIR) = 0) then<BR>// Report success.<BR>MessageBox (EXAMPLE_DIR + " was deleted.", INFORMATION);<BR>else<BR>MessageBox ("Unable to delete directory.", SEVERE);<BR>endif;<BR>endif;<BR>end;<BR>问】 GetCommandLine()获得所有的参数<BR>答】http://www.microsoft.com/msj/1099/c/c1099.aspx<BR>问】 如何打印一个文件？<BR>答】ShellExecute(0,"print", "c:\\1.xls","","", SW_SHOW );<BR>问】 VC操作Word中，如何设置页眉和页脚？<BR>答】<BR>http://oldlook.experts-exchange.com:8080/Programming/Programming_Languages/MFC/Q_20806283.html<BR>问】 <BR>1、怎样让多个ControlBar竖直排成一列，另外一个ControlBar单独占一列？<BR>2、这些ControlBar的上边框都要显示字符,就象.net编辑器里属性窗口的风格而不是象VC6编辑器那种Controlbar的风格？<BR>答】可以在DockControlBar的时候传递区域来指定其停靠位置。 <BR>DockControlBar(&amp;m_wndDirTreeBar, AFX_IDW_DOCKBAR_LEFT);<BR>RecalcLayout();<BR>CRect rBar;<BR>m_wndDirTreeBar.GetWindowRect(rBar);<BR>rBar.OffsetRect(0, 1);<BR>DockControlBar(&amp;m_wndDirTreeBar1, AFX_IDW_DOCKBAR_LEFT, rBar);<BR>rBar.OffsetRect(0, 1);<BR>DockControlBar(&amp;m_wndDirTreeBar2, AFX_IDW_DOCKBAR_LEFT, rBar);<BR>问】 Win32下面进程间通讯的方式，以及各种通讯方式的效率比较，特别是进程间大数据量传输的情况？<BR>答】<BR>进程之间的通讯，有很多种办法，包括消息、内核对象、管道、套接字(Socket)、邮槽(邮路)、共享内存等等。<BR>一般来说，简单的指令型通讯采用消息，进程间同步和互斥使用关键段、事件之类的内核对象，小数据量高安全性的通讯使用管道，网络间通讯采用Socket，小数据量快速通讯采用邮路，大数据量高自由度采用共享内存。<BR>进程间大数据量的传输，最合适的办法是共享内存。<BR>问】 如何连接局域网内另外的计算机上的ACCESS数据库？<BR>已知计算机的IP:192.168.1.10,机器名：ABC,在硬盘上的位置：C:\PROGRAM FILES\DDD\DATA\H.MDB。如何从局域网内另外的计算机连接该ACCESS数据库？<BR>请帮忙写个连接？<BR>答】不建议采取文件共享的方式访问远程数据库，这样可能造成数据库损坏。<BR>因为 Access数据库的数据运算和处理都是在客户端完成的（甚至包括数据库中定义的各种约束条件），服器端仅仅负责完成数据的写入工作（因为采取的是文件共享方式共享数据库，服务器端根本不用安装Access数据库引擎）。也就是说&#8220;就算客户端程序运行完全正确，但只要在从客户端传到服务器端的任何一个环节出错（比如信号干扰，网线接触不良），就有可能导致服务器端接收的数据是错误的。这时候服务器端写入数据，完全可能导致数据库中的数据紊乱&#8221;。<BR>建议采用SQL Server等基于服务器的数据库，或者使用C/S或者B/S程序、使用RDS同步数据库操作、WebService来进行客户端和服务器端的交互，客户端控制服务器来完成数据库操作<BR>更多信息参见<BR>HOW TO: Keep a Jet 4.0 Database in Top Working Condition<BR>http://support.microsoft.com/?id=300216<BR>问】 怎样打开一个位图文件,然后在X,Y位置写上"OK",后再保存为位图文件<BR>答】<BR>#include &lt;windows.h&gt;<BR>#include &lt;gdiplus.h&gt;<BR>#include &lt;stdio.h&gt;<BR>using namespace Gdiplus;<BR>INT main()<BR>{<BR>// Initialize &lt;tla rid="tla_gdiplus"/&gt;.<BR>GdiplusStartupInput gdiplusStartupInput;<BR>ULONG_PTR gdiplusToken;<BR>GdiplusStartup(&amp;gdiplusToken, &amp;gdiplusStartupInput, NULL);<BR>UINT size = 0;<BR>UINT count = 0;<BR>Bitmap* bitmap = new Bitmap(L"FakePhoto.jpg");<BR>Graphics graphics(bitmap);<BR>FontFamily fontFamily(L"Times New Roman");<BR>Font font(&amp;fontFamily, 24, FontStyleRegular, UnitPixel);<BR>PointF pointF(30.0f, 10.0f);<BR>SolidBrush solidBrush(Color(255, 0, 0, 255));<BR>graphics.DrawString(L"Hello", -1, &amp;font, pointF, &amp;solidBrush); <BR>delete bitmap;<BR>GdiplusShutdown(gdiplusToken);<BR>return 0;<BR>}<BR>问】 如何在对话框上使用切分窗口<BR>答】http://www.codeguru.com/article.php/c1979<BR>问】 做一个纯资源文件的DLL文件<BR>答】新建一个MFC Extension DLL，删除向导生成的资源文件，把你的程序的资源文件加入工程并且编译。<BR>参考知识库文章 Q198846 HOWTO: Create Localized Resource DLLs for MFC Application <BR>MFC技术文章TN057: Localization of MFC Components<BR>问】 在工作线程中调用UpdateData（）函数怎么抛出异常呢？<BR>答】简单的说，不能跨线程访问MFC窗口对象。MFC句柄封装类只在创建句柄的线程中有效，在其它线程中访问会出现无法预料的结果。适当的访问方式是直接访问句柄。更多信息参见http://www.csdn.net/develop/read_article.asp?id=23171<BR>你需要另外想办法，例如在线程类中声明一个指针，AfxBeginThread的时候以暂停方式启动线程，设置指针为文档指针之后继续线程的运行。<BR>参考http://support.microsoft.com/default.aspx?scid=kb;en-us;147578<BR>问】 如何在MDI环境下枚举所有打开的窗口？<BR>答】<BR>In MFC, each CMDIChildWnd created by the framework is managed as a child window of the MDIClient window. This MDIClient window is a child of the mainframe window and fills its client area. For MDI applications, the mainframe window is encapsulated by the CMDIFrameWnd class. This class has a public embedded HWND member (m_hWndMDIClient), which is the handle to the MDIClient window. For MDI applications, AppWizard derives the CMainFrame class from CMDIFrameWnd.<BR>The MDIClient maintains an internal list of child windows. In an MFC application, these child windows are either a CMDIChildWnd object or an internal window used to display the title of an iconized window. Note that this is an internal list controlled by Windows; don't make assumptions about the ordering of children in the list after an API function is called. <BR>//**mainfrm.h***************************************************<BR>class CMainFrame : public CMDIFrameWnd<BR>{<BR>...<BR>public:<BR>CWnd m_wndMDIClient;<BR>CWnd* m_pWndCurrentChild;<BR>CMDIChildWnd* GetNextMDIChildWnd();<BR>int GetCountCMDIChildWnds();<BR>...<BR>}<BR>//**mainfrm.cpp**************************************************<BR>CMainFrame::CMainFrame():m_pWndCurrentChild(NULL)<BR>{<BR>//.................<BR>}<BR>CMainFrame::~CMainFrame()<BR>{<BR>m_wndMDIClient.Detach();<BR>//.................<BR>}<BR>int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)<BR>{<BR>if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)<BR>return -1;<BR>if (m_wndMDIClient.Attach(m_hWndMDIClient) == 0)<BR>{<BR>TRACE0("Failed to attach MDIClient.\n");<BR>return -1; // fail to create<BR>}<BR>//.................<BR>}<BR>//----------------------------------------------------------------<BR>// This function finds the CMDIChildWnd in the list of windows<BR>// maintained by the application's MDIClient window following the<BR>// one pointed to by the member variable m_pWndCurrentChild. If no<BR>// further CMDIChildWnds are in the list, NULL is returned.<BR>//----------------------------------------------------------------<BR>CMDIChildWnd* CMainFrame::GetNextMDIChildWnd()<BR>{<BR>if (!m_pWndCurrentChild)<BR>{<BR>// Get the first child window.<BR>m_pWndCurrentChild = m_wndMDIClient.GetWindow(GW_CHILD);<BR>}<BR>else<BR>{<BR>// Get the next child window in the list.<BR>m_pWndCurrentChild=<BR>(CMDIChildWnd*)m_pWndCurrentChild-&gt;GetWindow(GW_HWNDNEXT);<BR>}<BR>if (!m_pWndCurrentChild)<BR>{<BR>// No child windows exist in the MDIClient,<BR>// or you are at the end of the list. This check<BR>// will terminate any recursion.<BR>return NULL;<BR>}<BR>// Check the kind of window<BR>if (!m_pWndCurrentChild-&gt;GetWindow(GW_OWNER))<BR>{<BR>if (m_pWndCurrentChild-&gt;<BR>IsKindOf(RUNTIME_CLASS(CMDIChildWnd)))<BR>{<BR>// CMDIChildWnd or a derived class.<BR>return (CMDIChildWnd*)m_pWndCurrentChild;<BR>}<BR>else<BR>{<BR>// Window is foreign to the MFC framework.<BR>// Check the next window in the list recursively.<BR>return GetNextMDIChildWnd();<BR>}<BR>}<BR>else<BR>{<BR>// Title window associated with an iconized child window.<BR>// Recurse over the window manager's list of windows.<BR>return GetNextMDIChildWnd();<BR>}<BR>}<BR>//-----------------------------------------------------------------<BR>// This function counts the number of CMDIChildWnd objects<BR>// currently maintained by the MDIClient.<BR>//-----------------------------------------------------------------<BR>int CMainFrame::GetCountCMDIChildWnds()<BR>{<BR>int count = 0;<BR>CMDIChildWnd* pChild = GetNextMDIChildWnd();<BR>while (pChild)<BR>{<BR>count++;<BR>pChild = GetNextMDIChildWnd();<BR>}<BR>return count;<BR>}<BR>问】 我想实现一个功能，就是检测一个目录或文件，看它是否存在，如果不存在就创建这个目录或文件。<BR>答】<BR>可以用Win32文件查找来查找文件或者文件夹是否存在，也可以用PathFileExists来判断。GetFileAttributes和PathIsDirectory可以用于判断文件是否是目录。创建文件可以用CreateDirectory或者MakeSureDirectoryPathExists。<BR>bool FileExists(CString FileName)<BR>{<BR>WIN32_FIND_DATA FindFileData;<BR>HANDLE hFind;<BR>bool FindFlag=false;<BR>hFind = FindFirstFile(FileName , &amp;FindFileData);<BR>if (hFind == INVALID_HANDLE_VALUE) {<BR>FindFlag= false;<BR>} <BR>else <BR>{<BR>FindFlag=true;<BR>}<BR>FindClose(hFind);<BR>return FindFlag;<BR>}<BR>DWORD dwFlag = GetFileAttributes(pathname);<BR>if ( 0xFFFFFFFF == dwFlag ) 不存在；<BR>if ( FILE_ATTRIBUTE_DIRECTORY &amp; dwFlag ) 是文件夹<BR>else 是文件<BR>问】 播放MP3<BR>答】system("start \"mp3\" /B \"D:\\一剪梅.mp3 \"");<BR>问】 如何使CTreeCtrl的节点即使没有子节点也显示+号？<BR>答】http://www.microsoft.com/msj/archive/S563.aspx<BR>问】怎样把某项菜单置灰?<BR>答】<BR>1<BR>menu.EnableMenuItem(ID_VIEW_MYCONTROL_BAR, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);<BR>2<BR>用OnUpdataCommandUI( CCmdUI* pCmdUI) <BR>pCmdUI-&gt;Enable( FALSE );<BR>------<BR>问】如何动态改变菜单？<BR>答】<BR>1<BR>CMenu cMenu;<BR>//调用新的以IDR_NEWMENU表示的菜单资源； <BR>cMenu.LoadMenu(IDR_NEWMENU);<BR>//将cMenu设置为当前菜单； <BR>SetMenu(&amp;cMenu);<BR>//释放菜单句柄 <BR>cMenu.Detach();<BR>//重画菜单条；<BR>DrawMenuBar();<BR>//重新绘制窗口区域；<BR>RecalcLayout(TRUE);<BR>2<BR>//装载菜单资源：<BR>m_Menu.LoadMenu(IDR_MENU_REPORT);<BR>//销毁原菜单：<BR>this-&gt;SetMenu(NULL);<BR>::DestroyMenu(this-&gt;m_hMenuShared); //m_hMenuShared指框架主菜单 m_hMenuDefault视图菜单<BR>//设置新的菜单：<BR>this-&gt;SetMenu(&amp;m_Menu);<BR>this-&gt;m_hMenuShared = m_Menu.GetSafeHmenu();<BR>//重画菜单条<BR>this-&gt;DrawMenuBar();<BR>问】当程序窗口隐藏时的弹出菜单问题？<BR>答】<BR>如果使用TrackPopupMenu并且如果不加SetForegroundWindow()的话，菜单就会一直显示着，除非你选择了其中某一个菜单项。所以在使用TrackPopupMenu()的时候前面一定要加句SetForegroundWindow()。<BR>问】当单击最小化菜单时，如何获取他的消息<BR>答】<BR>在OnSize函数里拦截消息进行判断<BR>void C****::OnSize(UINT nType, int cx, int cy) <BR>{<BR>CDialog::OnSize(nType,cx,cy);<BR>if (nType == SIZE_MINIMIZED)<BR>{<BR>AfxMessageBox("minbox");<BR>} <BR>}<BR>问】在TreeView的WM_CONTEXTMENU里用TrackPopupMenu函数不能显示右键菜单，双击右键却正常显示？<BR>答】<BR>1<BR>在右键之后，发送消息看看。在RichEditView里碰到类似的问题。<BR>void CAdminView::OnRButtonDown(UINT nFlags, CPoint pt) <BR>{<BR>CRichEditView::OnRButtonDown(nFlags, pt);<BR>ClientToScreen (&amp;pt);<BR>SendMessage(WM_CONTEXTMENU,(WPARAM)m_hWnd,MAKELPARAM(pt.x, pt.y));<BR>}<BR>2<BR>把WM_RBUTTONDOWN消息屏蔽了<BR>void Cxxx::OnRButtonDown(...)<BR>{<BR>// don't call the base OnRButtonDown<BR>}<BR>问】如何发消息使某个菜单响应？<BR>答】<BR>::SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(ID_MENUITEM, 0), NULL);<BR>其中ID_MENUITEM是菜单项的ID，而hwnd是View或FrameWnd的句柄（无论消息发给View还是FrameWnd，都将按照View、Document、FrameWnd、theApp的顺序进行，当然只是针对WM_COMMAND消息），当然，直接发给消息响应函数所在的窗口（如果它是一个窗口的话）那是最好不过的了。<BR>问】如何用windowsAPI制作多级菜单？<BR>答】<BR>CMenu MainMenu;<BR>CMenu SonMenu;<BR>MainMenu.CreatePopupMenu();<BR>MainMenu.AppendMenu(MF_STRING | MF_ENABLED, 42, "Apples");<BR>MainMenu.AppendMenu(MF_STRING | MF_ENABLED, 43, "Pears");<BR>MainMenu.AppendMenu(MF_STRING | MF_ENABLED, 43, "Grapes");<BR>SonMenu.CreatePopupMenu();<BR>SonMenu.AppendMenu(MF_STRING | MF_ENABLED, 40, "Mangos");<BR>SonMenu.AppendMenu(MF_STRING | MF_ENABLED, 41, "Tomatoes");<BR>MainMenu.AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,<BR>(UINT)MiscFruitMenu.m_hMenu, "Son Menu");<BR>MainMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this, NULL); <BR>问】怎样加载DLL中的菜单资源啊？<BR>答】<BR>按照以下步骤就可以：<BR>1<BR>资源DLL的建立,新建一个MFC Extension DLL，删除向导生成的资源文件，把你的程序的资源文件加入工程并且编译。<BR>参考知识库文章 Q198846 HOWTO: Create Localized Resource DLLs for MFC Application <BR>MFC技术文章TN057: Localization of MFC Components<BR>注意在PROJECT SETTING / LINK / PROJECT OPTION 中添加 /NOENTRY<BR>具体说明看MSDN，还有别忘了在EXE中包含RESOURCE.H<BR>2<BR>EXE的测试：<BR>BOOL CTestResOnlyDLLDlg::OnInitDialog()<BR>{<BR>m_hInst = 0;<BR>m_hInst = LoadLibrary("ResOnlyDll.dll");<BR>ASSERT(m_hInst);<BR>m_hMenu = ::LoadMenu(m_hInst,MAKEINTRESOURCE(IDR_MENU_DLL));<BR>ASSERT(m_hMenu);<BR>m_cMenu.Attach(m_hMenu);<BR>SetMenu(&amp;m_cMenu);<BR>...<BR>return TRUE;<BR>}<BR>void CTestResOnlyDLLDlg::OnDestroy() <BR>{<BR>CDialog::OnDestroy();<BR>FreeLibrary(m_hInst);<BR>}<BR>菜单的消息映射跟原来一样。<BR>问】如何确定视图右键菜单的位置？<BR>答】<BR>DWORD dwPos = GetMessagePos(); ////////////<BR>CPoint point( LOWORD(dwPos), HIWORD(dwPos) );<BR>m_list.ScreenToClient(&amp;point);<BR>m_list.ClientToScreen(&amp;point);<BR>CMenu*pPopMenu=new CMenu;<BR>pPopMenu-&gt;LoadMenu(IDR_MENU1);<BR>CMenu*pFileMenu=pPopMenu-&gt;GetSubMenu(0);<BR>pFileMenu-&gt;TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);<BR>delete pPopMenu;<BR>问】如何屏蔽ie菜单中的查看--&gt;源文件项？<BR>答】<BR>1<BR>http://dev.csdn.net/article/19/19627.shtm<BR>2<BR>M$抠出的一段代码<BR>==<BR>HRESULT CClientView::OnShowContextMenu(DWORD dwID, LPPOINT ppt, LPUNKNOWN pcmdTarget, LPDISPATCH pdispObject)<BR>{<BR>#define IDR_BROWSE_CONTEXT_MENU 24641<BR>#define IDR_FORM_CONTEXT_MENU 24640<BR>#define SHDVID_GETMIMECSETMENU 27<BR>#define SHDVID_ADDMENUEXTENSIONS 53<BR>HRESULT hr;<BR>HINSTANCE hinstSHDOCLC;<BR>HWND hwnd;<BR>HMENU hMenu;<BR>CComPtr&lt;IOleCommandTarget&gt; spCT;<BR>CComPtr&lt;IOleWindow&gt; spWnd;<BR>MENUITEMINFO mii={0};<BR>CComVariant var, var1, var2;<BR>hr = pcmdTarget-&gt;QueryInterface(IID_IOleCommandTarget, (void**)&amp;spCT);<BR>hr = pcmdTarget-&gt;QueryInterface(IID_IOleWindow, (void**)&amp;spWnd);<BR>hr = spWnd-&gt;GetWindow(&amp;hwnd);<BR>hinstSHDOCLC = LoadLibrary(TEXT("SHDOCLC.DLL"));<BR>if (hinstSHDOCLC == NULL)<BR>{<BR>// 载入模块错误 -- 尽可能安全地失败<BR>return S_FALSE;<BR>}<BR>hMenu=LoadMenu(hinstSHDOCLC, MAKEINTRESOURCE(IDR_BROWSE_CONTEXT_MENU));<BR>hMenu=GetSubMenu(hMenu,dwID);<BR>//获得语言子菜单<BR>hr = spCT-&gt;Exec(&amp;CGID_ShellDocView, SHDVID_GETMIMECSETMENU, 0, NULL, &amp;var);<BR>mii.cbSize = sizeof(mii);<BR>mii.fMask = MIIM_SUBMENU;<BR>mii.hSubMenu = (HMENU) var.byref;<BR>//加入语言子菜单到编码上下文菜单<BR>SetMenuItemInfo(hMenu, IDM_LANGUAGE, FALSE, &amp;mii);<BR>//插入来自注册表的快捷菜单扩展<BR>V_VT(&amp;var1) = VT_INT_PTR;<BR>V_BYREF(&amp;var1) = hMenu;<BR>V_VT(&amp;var2) = VT_I4;<BR>V_I4(&amp;var2) = dwID;<BR>hr = spCT-&gt;Exec(&amp;CGID_ShellDocView, SHDVID_ADDMENUEXTENSIONS, 0, &amp;var1, &amp;var2);<BR>//删除查看源代码<BR>DeleteMenu(hMenu, IDM_VIEWSOURCE, MF_BYCOMMAND);<BR>//显示快捷菜单<BR>int iSelection = ::TrackPopupMenu(hMenu,<BR>TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,<BR>ppt-&gt;x,<BR>ppt-&gt;y,<BR>0,<BR>hwnd,<BR>(RECT*)NULL);<BR>//发送选定的快捷菜单项目指令到外壳<BR>LRESULT lr = ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);<BR>FreeLibrary(hinstSHDOCLC);<BR>return S_OK;<BR>}<BR>问】如何在treeview里实现在节点上点击右键出现右键菜单？<BR>答】<BR>响应WM_CONTEXT消息<BR>====&gt;CTreeCtrl::HitTest可以得到结点<BR>=====&gt;生成一个CMenu对象<BR>=====&gt;CMenu::LoadMenu<BR>====&gt;CMenu::TrackPopupMenu来显示弹出菜单.<BR>点击后,====&gt;进行菜单项的处理.<BR>void CLeftView::OnRclick(NMHDR* pNMHDR, LRESULT* pResult) <BR>{<BR>// TODO: Add your control notification handler code here<BR>TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; <BR>CPoint pt ;//= point;<BR>GetCursorPos(&amp;pt);<BR>ScreenToClient(&amp;pt);<BR>UINT uFlags;<BR>HTREEITEM hItem = GetTreeCtrl().HitTest(pt, &amp;uFlags);<BR>if ((hItem != NULL) &amp;&amp; (TVHT_ONITEM &amp; uFlags))<BR>{<BR>GetTreeCtrl().SetFocus();<BR>GetTreeCtrl().Select(hItem,TVGN_CARET);<BR>CWnd* mwnd = GetFocus();<BR>CMenu PopMenu;<BR>PopMenu.LoadMenu(IDR_POP_ITEM);<BR>PopMenu.GetSubMenu(0)-TrackPopupMenu<BR>(TPM_LEFTALIGN|TPM_RIGHTBUTTON,pt.x,pt.y,this); <BR>}<BR>}<BR>同时如果是根结点的话，你可以用CTreeCtrl::GetRootItem()得到根结点，然后再判断CTreeCtrl::HitTest得到的结点是否是根结点，如果是判断一个结点是否还有子结点可以用CTreeCtrl::ItemHasChildren(hItem)<BR>问】当MDI程序启动时,子窗口最大化显示?<BR>答】重载ActivateFrame函数：<BR>void CChildFrame::ActivateFrame(int nCmdShow)<BR>{<BR>nCmdShow = SW_MAXIMIZE;<BR>CMDIChildWnd::ActivateFrame(nCmdShow);<BR>}<BR>问】讲一下NetBios究竟有什么用<BR>答】NetBIOS网络协议对于很多读者来说可能比较陌生，但其实它是由IBM开发的一个很古老的协议，当年在LAN上也风光一时。说它老，其实也不过10年光景，IT业的发展实在是太快。由于NetBIOS不具备路由功能，也就是说它的数据包无法跨网段传输，因此在广域网、城域网大行其道的今天，它已退居配角。如果你有心的话，能够发现在Window95/98的网络协议中仍然保留着NetBIOS，不过它已经改名叫NetBEUI<BR>(NetBIOS扩展用户接口)，是NetBIOS的Microsoft改进版。另外在TCP/IP以及IPX/SPX协议中，也依然保留了对NetBIOS的支持，只要查看网络协议属性中的高级，就能看到启用NetBIOS的选项。之所以这样是有原因的。NetBIOS协议短小精悍，非常适用于小型局域网，特别是一些对实时性要求较高的网络境。NetBIOS的广播功能由于有开发使用方便、系统开销小的优点，所以在很多场合仍然被大量使用<BR><img src ="http://www.cnblogs.com/Wiseman/aggbug/331118.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43628/" target="_blank">[新闻]微软：不裁员也不削减研发开支</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>DELL 电脑的区别</title><link>http://www.cnblogs.com/Wiseman/archive/2006/02/09/327825.html</link><dc:creator>吴文力</dc:creator><author>吴文力</author><pubDate>Thu, 09 Feb 2006 08:59:00 GMT</pubDate><guid>http://www.cnblogs.com/Wiseman/archive/2006/02/09/327825.html</guid><wfw:comment>http://www.cnblogs.com/Wiseman/comments/327825.html</wfw:comment><comments>http://www.cnblogs.com/Wiseman/archive/2006/02/09/327825.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnblogs.com/Wiseman/comments/commentRss/327825.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/Wiseman/services/trackbacks/327825.html</trackback:ping><description><![CDATA[<P>Dell Inspiron(TM) 1300 n-Series Notebook&nbsp; <BR>Price&nbsp; RMB 6,699.42&nbsp; <BR>底座&nbsp; Inspiron(TM) 1300 英特尔(R)奔腾(R) M 处理器 735&nbsp; <BR>DOS 操作系统&nbsp; DOS 非工厂预装(英文)&nbsp; <BR>戴尔服务: 硬件维修 (H)&nbsp; 1年消费者下一工作日 (8x5)上门响应 (部件+人工)&nbsp; <BR>戴尔服务:安装 (H)&nbsp; 不要求基本安装&nbsp; <BR>Dell Services: Zone Charges for Installation&nbsp; 区域 A,B,C 收费&nbsp; <BR>Dell Services: Future Technical Support&nbsp; 未来技术升级&nbsp; <BR>Item included in the System&nbsp; 集成立体声扬声器&nbsp; <BR>Item included in the System&nbsp; 前置立体声音箱，获得完整多媒体感受&nbsp; <BR>Item included in the System&nbsp; 3-USB 2.0, 音频输出口(耳机), 外置麦克风&nbsp; <BR>Item included in the System&nbsp; VGA, RJ45, RJ11,1 ExpressCard 插槽&nbsp; <BR>Item included in the System&nbsp; 英特尔(R) GMA900图形卡&nbsp; <BR>Item included in the System&nbsp; 铰链盖&nbsp; <BR>Item included in the System&nbsp; 付运文档（中国）&nbsp; <BR>DIMM 内存&nbsp; 512MB (2x256) DDR2 SDRAM内存&nbsp; <BR>网上订购客户额外优惠&nbsp; 本周网上购买即可获得RMB400元现金折扣!(总价已包含此折扣)&nbsp; <BR>限时优惠&nbsp; 本周购买即可获得RMB400元现金折扣!(总价已包含此折扣)&nbsp; <BR>限时优惠4&nbsp; 本周购买即可免费升级内存至512MB&nbsp; <BR>备注&nbsp; 折扣仅在以上配置选用了相应升级部件时才适用。&nbsp; <BR>备注&nbsp; 限时促销仅限本星期五前付款的订单. 不能与其他折扣同时使用&nbsp; <BR>备注&nbsp; 每个客户限购5台&nbsp; <BR>软驱&nbsp; 无软驱&nbsp; <BR>EIDE 硬盘&nbsp; 40GB Ultra ATA (5400 RPM) 硬盘&nbsp; <BR>光驱&nbsp; 内置的24X CD-RW/DVD 一体化光驱&nbsp; <BR>无线解决方案&nbsp; Dell(TM) Truemobile(TM) 1370 802.11 b/g 54Mbps Mini-PCI 无线网卡&nbsp; <BR>主板集成网卡&nbsp; 集成 10/100 快速以太网卡&nbsp; <BR>调制解调器&nbsp; 内置56K v.92 传真调制解调器&nbsp; <BR>键盘&nbsp; 内置 戴尔(TM) 87 键 键盘 (简体中文)&nbsp; <BR>主电池&nbsp; 4芯锂离子电池 (1 年保修)&nbsp; <BR>便携包和运输包装&nbsp; 不含便携包&nbsp; <BR>LCD Option&nbsp; 14.1" WXGA TFT显示器分辩率: 1280x800&nbsp; <BR>适配器&nbsp; 60W Primary AC Adapter (110V/220V)&nbsp; <BR>运费&nbsp; Inspiron(TM) 保险及杂费 (中国)&nbsp; <BR>总数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>税前金额 5,726.00 <BR>增值税- 中国大陆- 17% 973.42&nbsp; <BR>总金额 RMB 6,699.42 </P>
<P>戴尔 Latitude D510(P-M 740/14寸) 详细参数 <BR>&nbsp;<BR>　基本参数 <BR>　　型号 　Latitude D510(P-M 740/14寸) <BR>　　上市时间 　2005 <BR>　　处理器 　Intel Pentium M(Dothan) 740(1.73G)&nbsp; <BR>　　处理器最高主频 　1730MHz <BR>　　二级缓存 　2048KB L2 <BR>　　系统总线 　533MHz <BR>　　主板芯片组 　Intel 915GM <BR>　　内存容量 　512M <BR>　　内存类型 　DDR2 <BR>　　最大支持内存 　2G <BR>　存储设备 <BR>　　硬盘类型 　ATA-100 <BR>　　硬盘参数 　5400转 <BR>　　硬盘容量 　60G <BR>　　光驱类型 　内置,DVD-ROM <BR>　　光驱速度 　8X <BR>　　软驱 　无软驱 <BR>　显示屏 <BR>　　屏幕尺寸 　14.1寸 <BR>　　显示屏类型 　XGA <BR>　　显示屏性能 　1024 x 768分辨率 <BR>　音频视频 <BR>　　显示芯片 　集成Intel GMA900芯片 <BR>　　显存容量 　最大共享128M内存 <BR>　　音频系统 　集成AC97 音频 <BR>　　音箱 　2声道 <BR>　通　　讯 <BR>　　MODEM 　56K V.92 <BR>　　网卡 　内置10-100M网卡 <BR>　　无线通讯 　802.11b/g无线网卡 <BR>　输入输出 <BR>　　鼠标替代设备 　触摸板 <BR>　　USB 　4个,USB2.0 <BR>　　PCMCIA卡/Express卡 　1个,Type II <BR>　　其它接口 　并口,串口,1个IEEE1394a,VGA接口,S-VIDEO接口,扩展槽接口,RJ11,RJ45,麦克风,声音输出孔,AC电源插孔 <BR>　结构特征 <BR>　　重量 　约2.1Kg <BR>　　规格 　338.3&#215;273&#215;35.5mm <BR>　电能规格 <BR>　　电池类型 　4芯锂离子电池 <BR>　　电源适配器 　65W 主交流电适配器(110V/220V) <BR>　其　　它 <BR>　　操作系统 　DOS系统 <BR>　　可选配件 　蓝牙 <BR>　　保修时间、方式 　1年保修 <BR>　　其它性能 　Strike Zone减震垫 </P><img src ="http://www.cnblogs.com/Wiseman/aggbug/327825.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/43625/" target="_blank">[新闻]2008年11月22日科技博客精选</a><br/><a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻频道</a>&nbsp;<a href="http://space.cnblogs.com/group.htm" target="_blank">小组</a>&nbsp;<a href="http://space.cnblogs.com/q" target="_blank">博问</a>&nbsp;<a href="http://wz.cnblogs.com/" target="_blank">网摘</a>&nbsp;<a href="http://space.cnblogs.com/ing" target="_blank">闪存</a>]]></description></item><item><title>报表式CListCtrl的使用详解初稿</title><link>http://www.cnblogs.com/Wiseman/archive/2006/01/20/320857.html</link><dc:creator>吴文力</dc:creator><author>吴文力</author><pubDate>Fri, 20 Jan 2006 06:24:00 GMT</pubDate><guid>http://www.cnblogs.com/Wiseman/archive/2006/01/20/320857.html</guid><wfw:comment>http://www.cnblogs.com/Wiseman/comments/320857.html</wfw:comment><comments>http://www.cnblogs.com/Wiseman/archive/2006/01/20/320857.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/Wiseman/comments/commentRss/320857.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/Wiseman/services/trackbacks/320857.html</trackback:ping><description><![CDATA[<P align=left><STRONG><FONT size=4>严格说来本文是别人成果的集合，加入了本人使用的一点心得，而且文章内容是本人在实际开发中试验过可以使用的。这只是初稿，还有很多内容没有加入，原因是没有经过验证，以后会陆续加入，形成一个CListCtrl的使用完全指南。</FONT></STRONG></P>
<P>创建图形列表并和CListCtrl关联：<BR>&nbsp;m_image_list.Create(IDB_CALLER2, 16, 10, RGB(192,192, 192));<BR>&nbsp;m_image_list.SetBkColor( GetSysColor( COLOR_WINDOW ) );<BR>&nbsp;m_caller_list.SetImageList( &amp;m_image_list, LVSIL_SMALL);<BR>为报表添加4列：<BR>&nbsp;&nbsp;char *szColumn[]={"昵称","IP地址","登陆时间","状态"};<BR>&nbsp;&nbsp;int widths[]={100,98,70,55};<BR>&nbsp;&nbsp;LV_COLUMN lvc;<BR>&nbsp;&nbsp;lvc.mask=LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;<BR>&nbsp;&nbsp;lvc.fmt=LVCFMT_LEFT;<BR>&nbsp;&nbsp;for(int i=0;i&lt;4;i++) {//插入各列<BR>&nbsp;&nbsp;&nbsp;lvc.pszText=szColumn[i];<BR>&nbsp;&nbsp;&nbsp;lvc.cx=widths[i];<BR>&nbsp;&nbsp;&nbsp;lvc.iSubItem=i;<BR>&nbsp;&nbsp;&nbsp;m_caller_list.InsertColumn(i,&amp;lvc);<BR>&nbsp;&nbsp;}<BR>为报表添加两项，以附加方式添加：<BR>&nbsp;char* data[4];<BR>&nbsp;data[0]="所有人";<BR>&nbsp;data[1]="0.0.0.0";<BR>&nbsp;data[3]="在线";<BR>&nbsp;data[2]=new char;<BR>&nbsp;CTime now=CTime::GetCurrentTime();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CString temp = now.Format("%H:%M:%S");<BR>&nbsp;data[2]=temp.GetBuffer(1);<BR>&nbsp;LV_ITEM lvi;<BR>&nbsp;lvi.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;<BR>&nbsp;lvi.iSubItem=0;<BR>&nbsp;lvi.pszText=(char *)data[0];<BR>&nbsp;lvi.iImage = 0;<BR>&nbsp;lvi.iItem=0;<BR>&nbsp;m_caller_list.InsertItem(&amp;lvi);<BR>&nbsp;for (int j=0;j&lt;4;j++) m_caller_list.SetItemText(count,j,data[j]);<BR>&nbsp;count++;<BR>&nbsp;lvi.iImage = 1;<BR>&nbsp;lvi.iItem=count;<BR>&nbsp;m_caller_list.InsertItem(&amp;lvi);<BR>&nbsp;data[0]="cherami";<BR>&nbsp;data[1]="127.0.0.1";&nbsp;<BR>&nbsp;for (int n=0;n&lt;4;n++) m_caller_list.SetItemText(count,n,data[n]);<BR>&nbsp;count++;</P>
<P>设置报表的样式<BR>选中一整行：<BR>m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_FULLROWSELECT);&nbsp; <BR>绘制表格：<BR>m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_GRIDLINES); <BR>带复选框：<BR>m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_CHECKBOXES); <BR>自动切换：<BR>m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle()|LVS_EX_TRACKSELECT); </P>
<P>选定一行：<BR>设置CListCtrl的Show selection always选项<BR>SetItemState (iIndex, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED) <BR>&nbsp;<BR>选中一个或多个项目时,会发送LVN_ITEMCHANGED消息，可以使用<BR>GetSelectedCount()方法得到被选定的项的数目。</P>
<P>点击列头的消息响应：<BR>ON_NOTIFY(HDN_ITEMCLICKW, 0, ResponseFunc)<BR>消息，需要自己添加 <BR>或者：<BR>ON_NOTIFY(LVN_COLUMNCLICK, ID_yourCtrl,&nbsp; ResponseFunc)//向导添加<BR>前者后响应，后者先响应</P>
<P>响应函数：<BR>ResponseFunc(NMHDR *pNMHDR, LRESULT *pResult) </P>
<P>双击CListCtrl中的ITEM的消息是及消息函数：<BR>ON_NOTIFY(NM_DBLCLK, ID_yourCtrl, ResponseFunc) </P>
<P>单击ITEM的消息响应：<BR>ON_NOTIFY(NM_CLICK, ID_yourCtrl, ResponseFunc)<BR>ResponseFunc(NMHDR *pNMHDR, LRESULT *pResult) </P>
<P><BR>HDN_ITEMCLICK&nbsp;&nbsp;&nbsp; 就是Header control Notify message for mouse left click on the Header control!<BR>而HDN_ITEMCLICK是当List View中存在一个Header Contrl时，Header Ctrl通知父窗口List View的！</P>
<P>CListCtrl中的Item被选中触发LBN_SELCHANGE(通过WM_COMMAND)消息！</P>
<P>删除CListCtrl中选定的项：<BR>POSITION pos;<BR>int nIndex;</P>
<P>for(; pos= GetFirstSelectedItemPosition();)<BR>{<BR>nIndex = GetNextSelectedItem(pos);<BR>DeleteItem(nIndex);<BR>}</P>
<P>在ListCtrl中进行排序<BR>列表控件（CListCtrl）的顶部有一排按钮，用户可以通过选择不同的列来对记录进行排序。但是 CListCtrl并没有自动排序的功能，我们需要自己添加一个用于排序的回调函数来比较两个数据的大小，此外还需要响应排序按钮被点击的消息。下面讲述一下具体的做法。</P>
<P>CListCtrl提供了用于排序的函数，函数原型为：BOOL CListCtrl::SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData )。其中第一个参数为全局排序函数的地址，第二个参数为用户数据，你可以根据你的需要传递一个数据或是指针。该函数返回-1代表第一项排应在第二项前面，返回1代表第一项排应在第二项后面，返回0代表两项相等。</P>
<P>用于排序的函数原形为：int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)，其中第三个参数为调用者传递的数据（即调用SortItems时的第二个参数dwData）。第一和第二个参数为用于比较的两项的ItemData，你可以通过DWORD CListCtrl::GetItemData( int nItem )/BOOL CListCtrl::SetItemData( int nItem, DWORD dwData )来对每一项的ItemData进行存取。在添加项时选用特定的CListCtrl::InsertItem也可以设置该值。由于你在排序时只能通过该值来确定项的位置所以你应该比较明确的确定该值的含义。</P>
<P>最后一点，我们需要知道什么时候需要排序，实现这点可以在父窗口中对LVN_COLUMNCLICK消息进行处理来实现。 </P>
<P>下面我们看一个例子，这个例子是一个派生类，并支持顺序/倒序两种方式排序。为了简单我对全局数据进行排序，而在实际应用中会有多组需要排序的数据，所以需要通过传递参数的方式来告诉派序函数需要对什么数据进行排序。</P>
<P><BR>//全局数据<BR>struct DEMO_DATA<BR>{<BR>&nbsp;char szName[20];<BR>&nbsp;int iAge;<BR>}strAllData[5]={{"王某",30},{"张某",40},{"武某",32},{"陈某",20},{"李某",36}};</P>
<P>//CListCtrl派生类定义<BR>class CSortList : public CListCtrl<BR>{<BR>// Construction<BR>public:<BR>&nbsp;CSortList();<BR>&nbsp;BOOL m_fAsc;//是否顺序排序<BR>&nbsp;int m_nSortedCol;//当前排序的列<BR>protected:<BR>&nbsp;//{{AFX_MSG(CSortList)<BR>&nbsp;//}}AFX_MSG<BR>...<BR>};</P>
<P>//父窗口中包含该CListCtrl派生类对象<BR>class CSort_in_list_ctrlDlg : public CDialog<BR>{<BR>// Construction<BR>public:<BR>&nbsp;CSort_in_list_ctrlDlg(CWnd* pParent = NULL);&nbsp;// standard constructor</P>
<P>// Dialog Data<BR>&nbsp;//{{AFX_DATA(CSort_in_list_ctrlDlg)<BR>&nbsp;enum { IDD = IDD_SORT_IN_LIST_CTRL_DIALOG };<BR>&nbsp;CSortList&nbsp;m_listTest;<BR>&nbsp;//}}AFX_DATA<BR>}</P>
<P>//在父窗口中定义LVN_COLUMNCLICK消息映射<BR>BEGIN_MESSAGE_MAP(CSort_in_list_ctrlDlg, CDialog)<BR>&nbsp;//{{AFX_MSG_MAP(CSort_in_list_ctrlDlg)<BR>&nbsp;ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnColumnclickList1)<BR>&nbsp;//}}AFX_MSG_MAP<BR>END_MESSAGE_MAP()</P>
<P>//初始化数据<BR>BOOL CSort_in_list_ctrlDlg::OnInitDialog()<BR>{<BR>&nbsp;CDialog::OnInitDialog();</P>
<P>&nbsp;//初始化ListCtrl中数据列表<BR>&nbsp;m_listTest.InsertColumn(0,"姓名");<BR>&nbsp;m_listTest.InsertColumn(1,"年龄");<BR>&nbsp;m_listTest.SetColumnWidth(0,80);<BR>&nbsp;m_listTest.SetColumnWidth(1,80);<BR>&nbsp;for(int i=0;i&lt;5;i++)<BR>&nbsp;{<BR>&nbsp;&nbsp;m_listTest.InsertItem(i,strAllData[i].szName);<BR>&nbsp;&nbsp;char szAge[10];<BR>&nbsp;&nbsp;sprintf(szAge,"%d",strAllData[i].iAge);<BR>&nbsp;&nbsp;m_listTest.SetItemText(i,1,szAge);<BR>&nbsp;&nbsp;//设置每项的ItemData为数组中数据的索引<BR>&nbsp;&nbsp;//在排序函数中通过该ItemData来确定数据<BR>&nbsp;&nbsp;m_listTest.SetItemData(i,i);<BR>&nbsp;}<BR>&nbsp;return TRUE;&nbsp; // return TRUE&nbsp; unless you set the focus to a control<BR>}</P>
<P>//处理消息<BR>void CSort_in_list_ctrlDlg::OnColumnclickList1(NMHDR* pNMHDR, LRESULT* pResult) <BR>{<BR>&nbsp;NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;<BR>&nbsp;//设置排序方式<BR>&nbsp;if( pNMListView-&gt;iSubItem == m_listTest.m_nSortedCol )<BR>&nbsp;&nbsp;m_listTest.m_fAsc = !m_listTest.m_fAsc;<BR>&nbsp;else<BR>&nbsp;{<BR>&nbsp;&nbsp;m_listTest.m_fAsc = TRUE;<BR>&nbsp;&nbsp;m_listTest.m_nSortedCol = pNMListView-&gt;iSubItem;<BR>&nbsp;}<BR>&nbsp;//调用排序函数<BR>&nbsp;m_listTest.SortItems( ListCompare, (DWORD)&amp;m_listTest );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;*pResult = 0;<BR>}</P>
<P>//排序函数实现<BR>int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)<BR>{<BR>&nbsp;//通过传递的参数来得到CSortList对象指针，从而得到排序方式<BR>&nbsp;CSortList* pV=(CSortList*)lParamSort;<BR>&nbsp;<BR>&nbsp;//通过ItemData来确定数据<BR>&nbsp;DEMO_DATA* pInfo1=strAllData+lParam1;<BR>&nbsp;DEMO_DATA* pInfo2=strAllData+lParam2;<BR>&nbsp;CString szComp1,szComp2;<BR>&nbsp;int iCompRes;<BR>&nbsp;switch(pV-&gt;m_nSortedCol)<BR>&nbsp;{<BR>&nbsp;case(0):<BR>&nbsp;&nbsp;//以第一列为根据排序<BR>&nbsp;&nbsp;szComp1=pInfo1-&gt;szName;<BR>&nbsp;&nbsp;szComp2=pInfo2-&gt;szName;<BR>&nbsp;&nbsp;iCompRes=szComp1.Compare(szComp2);<BR>&nbsp;&nbsp;break;<BR>&nbsp;case(1):<BR>&nbsp;&nbsp;//以第二列为根据排序<BR>&nbsp;&nbsp;if(pInfo1-&gt;iAge == pInfo2-&gt;iAge)<BR>&nbsp;&nbsp;&nbsp;iCompRes = 0;<BR>&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;iCompRes=(pInfo1-&gt;iAge &lt; pInfo2-&gt;iAge)?-1:1;<BR>&nbsp;&nbsp;break;<BR>&nbsp;default:<BR>&nbsp;&nbsp;ASSERT(0);<BR>&nbsp;&nbsp;break;<BR>&nbsp;}<BR>&nbsp;//根据当前的排序方式进行调整<BR>&nbsp;if(pV-&gt;m_fAsc)<BR>&nbsp;&nbsp;return iCompRes;<BR>&nbsp;else<BR>&nbsp;&nbsp;return iCompRes*-1;<BR>}</P>
<P>排序最快：<BR>CListCtrl::SortItems<BR>Example</P>
<P>// Sort the item in reverse alphabetical order.<BR>static int CALLBACK <BR>MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)<BR>{<BR>&nbsp; // lParamSort contains a pointer to the list view control.<BR>&nbsp; // The lParam of an item is just its index.<BR>&nbsp; CListCtrl* pListCtrl = (CListCtrl*) lParamSort;<BR>&nbsp; CString&nbsp;&nbsp;&nbsp; strItem1 = pListCtrl-&gt;GetItemText(lParam1, 0);<BR>&nbsp; CString&nbsp;&nbsp;&nbsp; strItem2 = pListCtrl-&gt;GetItemText(lParam2, 0);</P>
<P>&nbsp; return strcmp(strItem2, strItem1);<BR>}</P>
<P>void snip_CListCtrl_SortItems()<BR>{<BR>&nbsp; // The pointer to my list view control.<BR>&nbsp; extern CListCtrl* pmyListCtrl;</P>
<P>&nbsp; // Sort the list view items using my callback procedure.<BR>&nbsp; pmyListCtrl-&gt;SortItems(MyCompareProc, (LPARAM) pmyListCtrl);<BR>}</P>
<P><BR>If you don&#8217;t want to allow the users to sort the list by clicking on the header, you can use the style LVS_NOSORTHEADER. However, if you do want to allow sorting, you do not specify the LVS_NOSORTHEADER. The control, though, does not sort the items. You have to handle the HDN_ITEMCLICK notification from the header control and process it appropriately. In the code below, we have used the sorting function SortTextItems() developed in a previous section. You may choose to sort the items in a different manner. <BR>Step 1: Add two member variables<BR>Add two member vari