﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-C++ Coder-随笔分类-Windows编程</title><link>http://www.cppblog.com/jackdongy/category/20072.html</link><description>HCP高性能计算架构，实现，编译器指令优化，算法优化，
  LLVM   CLANG   OpenCL   CUDA   OpenACC    C++AMP   OpenMP   MPI</description><language>zh-cn</language><lastBuildDate>Thu, 15 Nov 2012 02:39:24 GMT</lastBuildDate><pubDate>Thu, 15 Nov 2012 02:39:24 GMT</pubDate><ttl>60</ttl><item><title>__stdcall,__cdecl区别简介(转)</title><link>http://www.cppblog.com/jackdongy/archive/2012/11/14/195184.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Wed, 14 Nov 2012 03:03:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/11/14/195184.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/195184.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/11/14/195184.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/195184.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/195184.html</trackback:ping><description><![CDATA[<h3><a href="http://icelander.javaeye.com/blog/413493"></a><a href="http://icelander.javaeye.com/blog/413493">__stdcall,__cdecl区别简介</a></h3>__stdcall,__cdecl,_cdecl,_stdcall,。__fastcall,_fastcall 区别简介<br /><br />1.<br /><br />今天写线程函数时，发现msdn中对ThreadProc的定义有要求：DWORD WINAPI ThreadProc(LPVOID lpParameter);<br /><br />不解为什么要用WINAPI宏定义，查了后发现下面的定义。于是乎需要区别__stdcall和__cdecl两者的区别； #define CALLBACK __stdcall<br />#define WINAPI __stdcall<br />#define WINAPIV __cdecl<br />#define APIENTRY WINAPI<br />#define APIPRIVATE __stdcall<br />#define PASCAL __stdcall<br />#define cdecl _cdecl<br />#ifndef CDECL<br />#define CDECL _cdecl<br />#endif<br /><br />几乎我们写的每一个WINDOWS API函数都是__stdcall类型的，首先，需要了解两者之间的区别： WINDOWS的函数调用时需要用到栈（STACK，一种先入后出的存储结构）。当函数调用完成后，栈需要清楚，这里就是问题的关键，如何清除？？如果我们的函数使用了_cdecl，那么栈的清除工作是由调用者，用COM的术语来讲就是客户来完成的。这样带来了一个棘手的问题，不同的编译器产生栈的方式不尽相同，那么调用者能否正常的完成清除工作呢？答案是不能。如果使用__stdcall，上面的问题就解决了，函数自己解决清除工作。所以，在跨（开发）平台的调用中，我们都使用__stdcall（虽然有时是以 WINAPI的样子出现）。那么为什么还需要_cdecl呢？当我们遇到这样的函数如fprintf()它的参数是可变的，不定长的，被调用者事先无法知道参数的长度，事后的清除工作也无法正常的进行，因此，这种情况我们只能使用_cdecl。到这里我们有一个结论，如果你的程序中没有涉及可变参数，最好使用__stdcall关键字。<br /><br />2.<br /><br />__cdecl,__stdcall是声明的函数调用协议.主要是传参和弹栈方面的不同.一般c++用的是__cdecl,windows里大都用的是__stdcall(API)<br /><br />__cdecl是C/C++和MFC程序默认使用的调用约定，也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时，函数参数按照从右到左的顺序入栈，并且由调用函数者把参数弹出栈以清理堆栈。因此，实现可变参数的函数只能使用该调用约定。由于每一个使用 __cdecl约定的函数都要包含清理堆栈的代码，所以产生的可执行文件大小会比较大。__cdecl可以写成_cdecl。<br />__stdcall调用约定用于调用Win32 API函数。采用__stdcall约定时，函数参数按照从右到左的顺序入栈，被调用的函数在返回前清理传送参数的栈，函数参数个数固定。由于函数体本身知道传进来的参数个数，因此被调用的函数可以在返回前用一条ret n指令直接清理传递参数的堆栈。__stdcall可以写成_stdcall。<br />__fastcall约定用于对性能要求非常高的场合。__fastcall约定将函数的从左边开始的两个大小不大于4个字节（DWORD）的参数分别放在ECX和EDX寄存器，其余的参数仍旧自右向左压栈传送，被调用的函数在返回前清理传送参数的堆栈。__fastcall可以写成 _fastcall<br /><br />3.<br /><br />__stdcall:<br /><br />_stdcall 调用约定相当于16位动态库中经常使用的PASCAL调用约定。<br /><br />&nbsp;<wbr><br />在32位的VC++5.0中PASCAL调用约定不再被支持（实际上它已被定义为__stdcall。除了__pascal 外，__fortran和__syscall也不被支持），取而代之的是__stdcall调用约定。两者实质上是一致的，即函数的参数自右向左通过栈传递，被调用的函数在返回前清理传送参数的内存栈，但不同的是函数名的修饰部分（关于函数名的修饰部分在后面将详细说明）。<br /><br />_stdcall是Pascal程序的缺省调用方式，通常用于Win32 Api中，函数采用从右到左的压栈方式，自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀，在函数名后加上"@"和参数的字节数。<br /><br />_cdecl:<br /><br />_cdecl c调用约定, 按从右至左的顺序压参数入栈，由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的（正因为如此，实现可变参数的函数只能使用该调用约定）。另外，在函数名修饰约定方面也有所不同。<br /><br />_cdecl是C和C＋＋程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码，所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。是MFC缺省调用约定。<br /><br />__fastcall:<br /><br />__fastcall调用约定是"人"如其名，它的主要特点就是快，因为它是通过寄存器来传送参数的（实际上，它用ECX和EDX传送前两个双字（DWORD）或更小的参数，剩下的参数仍旧自右向左压栈传送，被调用的函数在返回前清理传送参数的内存栈），在函数名修饰约定方面，它和前两者均不同。<br /><br />_fastcall方式的函数采用寄存器传递参数，VC将函数编译后会在函数名前面加上"@"前缀，在函数名后加上"@"和参数的字节数。<br /><br />thiscall:<br /><br />thiscall仅仅应用于"C++"成员函数。this指针存放于CX寄存器，参数从右到左压。thiscall不是关键词，因此不能被程序员指定。<br /><br />naked call:<br /><br />采用1-4的调用约定时，如果必要的话，进入函数时编译器会产生代码来保存ESI，EDI，EBX，EBP寄存器，退出函数时则产生代码恢复这些寄存器的内容。<br /><br />naked call不产生这样的代码。naked call不是类型修饰符，故必须和_declspec共同使用。<br /><br />另附:<br /><br />关键字 __stdcall、__cdecl和__fastcall可以直接加在要输出的函数前，也可以在编译环境的Setting...\C/C++ \Code Generation项选择。当加在输出函数前的关键字与编译环境中的选择不同时，直接加在输出函数前的关键字有效。它们对应的命令行参数分别为/Gz、 /Gd和/Gr。缺省状态为/Gd，即__cdecl。<br /><br />要完全模仿PASCAL调用约定首先必须使用__stdcall调用约定，至于函数名修饰约定，可以通过其它方法模仿。还有一个值得一提的是 WINAPI宏，Windows.h支持该宏，它可以将出函数翻译成适当的调用约定，在WIN32中，它被定义为__stdcall。使用WINAPI宏可以创建自己的APIs。<br /><br />名字修饰约定<br /><br />1、修饰名(Decoration name)<br />&#8220;C&#8221;或者&#8220;C++&#8221;函数在内部（编译和链接）通过修饰名识别。修饰名是编译器在编译函数定义或者原型时生成的字符串。有些情况下使用函数的修饰名是必要的，如在模块定义文件里头指定输出&#8220;C++&#8221;重载函数、构造函数、析构函数，又如在汇编代码里调用&#8220;C&#8221;&#8221;或&#8220;C++&#8221;函数等。<br /><br />修饰名由函数名、类名、调用约定、返回类型、参数等共同决定。<br /><br />2、名字修饰约定随调用约定和编译种类(C或C++)的不同而变化。函数名修饰约定随编译种类和调用约定的不同而不同，下面分别说明。<br /><br />a、C编译时函数名修饰约定规则：<br /><br />__stdcall调用约定在输出函数名前加上一个下划线前缀，后面加上一个&#8220;@&#8221;符号和其参数的字节数，格式为_functionname@number。<br /><br />__cdecl调用约定仅在输出函数名前加上一个下划线前缀，格式为_functionname。<br /><br />__fastcall调用约定在输出函数名前加上一个&#8220;@&#8221;符号，后面也是一个&#8220;@&#8221;符号和其参数的字节数，格式为@functionname@number。<br /><br />它们均不改变输出函数名中的字符大小写，这和PASCAL调用约定不同，PASCAL约定输出的函数名无任何修饰且全部大写。<br /><br />b、C++编译时函数名修饰约定规则：<br /><br />__stdcall调用约定：<br />1、以&#8220;?&#8221;标识函数名的开始，后跟函数名；<br />2、函数名后面以&#8220;@@YG&#8221;标识参数表的开始，后跟参数表；<br />3、参数表以代号表示：<br />X--void ，<br />D--char，<br />E--unsigned char，<br />F--short，<br />H--int，<br />I--unsigned int，<br />J--long，<br />K--unsigned long，<br />M--float，<br />N--double，<br />_N--bool，<br />....<br />PA--表示指针，后面的代号表明指针类型，如果相同类型的指针连续出现，以&#8220;0&#8221;代替，一个&#8220;0&#8221;代表一次重复；<br />4、参数表的第一项为该函数的返回值类型，其后依次为参数的数据类型,指针标识在其所指数据类型前；<br />5、参数表后以&#8220;@Z&#8221;标识整个名字的结束，如果该函数无参数，则以&#8220;Z&#8221;标识结束。<br /><br />其格式为&#8220;?functionname@@YG*****@Z&#8221;或&#8220;?functionname@@YG*XZ&#8221;，例如<br />int Test1（char *var1,unsigned long）-----&#8220;?Test1@@YGHPADK@Z&#8221;<br />void Test2（） -----&#8220;?Test2@@YGXXZ&#8221;<br /><br />__cdecl调用约定：<br />规则同上面的_stdcall调用约定，只是参数表的开始标识由上面的&#8220;@@YG&#8221;变为&#8220;@@YA&#8221;。<br /><br />__fastcall调用约定：<br />规则同上面的_stdcall调用约定，只是参数表的开始标识由上面的&#8220;@@YG&#8221;变为&#8220;@@YI&#8221;。<br />VC++对函数的省缺声明是&#8220;__cedcl&#8220;,将只能被C/C++调用.<br /><br />CB在输出函数声明时使用4种修饰符号<br />//__cdecl<br />cb的默认值，它会在输出函数名前加_，并保留此函数名不变，参数按照从右到左的顺序依次传递给栈，也可以写成_cdecl和cdecl形式。<br />//__fastcall<br />她修饰的函数的参数将尽肯呢感地使用寄存器来处理，其函数名前加@，参数按照从左到右的顺序压栈；<br />//__pascal<br />它说明的函数名使用Pascal格式的命名约定。这时函数名全部大写。参数按照从左到右的顺序压栈；<br />//__stdcall<br />使用标准约定的函数名。函数名不会改变。使用__stdcall修饰时。参数按照由右到左的顺序压栈，也可以是_stdcall；<br /><br />VC++对函数的省缺声明是"__cedcl",将只能被C/C++调用.<br /><br /><br /><br /><br /><br />注意：<br /><br />1、_beginthread需要__cdecl的线程函数地址，_beginthreadex和CreateThread需要__stdcall的线程函数地址。<br /><br />2、一般WIN32的函数都是__stdcall。而且在Windef.h中有如下的定义：<br /><br />#define CALLBACK __stdcall<br /><br />#define WINAPI　 __stdcall<br /><br />3、extern "C" _declspec(dllexport) int __cdecl Add(int a, int b);<br /><br />&nbsp;<wbr>&nbsp;<wbr> typedef int (__cdecl*FunPointer)(int a, int b);<br /><br />&nbsp;<wbr>&nbsp;<wbr> 修饰符的书写顺序如上。<br /><br />4、extern "C"的作用：如果Add(int a, int b)是在c语言编译器编译，而在c++文件使用，则需要在c++文件中声明：extern "C" Add(int a, int b)，因为c编译器和c++编译器对函数名的解释不一样（c++编译器解释函数名的时候要考虑函数参数，这样是了方便函数重载，而在c语言中不存在函数重载的问题），使用extern "C"，实质就是告诉c++编译器，该函数是c库里面的函数。如果不使用extern "C"则会出现链接错误。<br /><br />一般象如下使用：<br /><br />#ifdef _cplusplus<br /><br />#define EXTERN_C extern "C"<br /><br />#else<br /><br />#define EXTERN_C extern<br /><br />#endif<br /><br />#ifdef _cplusplus<br /><br />extern "C"{<br /><br />#endif<br /><br />EXTERN_C int func(int a, int b);<br /><br />#ifdef _cplusplus<br /><br />}<br /><br />#endif<br /><br />5、MFC提供了一些宏，可以使用AFX_EXT_CLASS来代替__declspec(DLLexport)，并修饰类名，从而导出类，AFX_API_EXPORT来修饰函数，AFX_DATA_EXPORT来修饰变量<br /><br />AFX_CLASS_IMPORT：__declspec(DLLexport)<br /><br />AFX_API_IMPORT：__declspec(DLLexport)<br /><br />AFX_DATA_IMPORT：__declspec(DLLexport)<br /><br />AFX_CLASS_EXPORT：__declspec(DLLexport)<br /><br />AFX_API_EXPORT：__declspec(DLLexport)<br /><br />AFX_DATA_EXPORT：__declspec(DLLexport)<br /><br />AFX_EXT_CLASS：#ifdef _AFXEXT<br /><br />&nbsp;<wbr>&nbsp;<wbr> AFX_CLASS_EXPORT<br /><br />&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr>&nbsp;<wbr> #else<br /><br />&nbsp;<wbr>&nbsp;<wbr> AFX_CLASS_IMPORT<br /><br />6、DLLMain负责初始化(Initialization)和结束(Termination)工作，每当一个新的进程或者该进程的新的线程访问DLL时，或者访问DLL的每一个进程或者线程不再使用DLL或者结束时，都会调用DLLMain。但是，使用TerminateProcess或 TerminateThread结束进程或者线程，不会调用DLLMain。<br /><br />7、一个DLL在内存中只有一个实例<br /><br />DLL程序和调用其输出函数的程序的关系：<br /><br />1)、DLL与进程、线程之间的关系<br /><br />DLL模块被映射到调用它的进程的虚拟地址空间。<br /><br />DLL使用的内存从调用进程的虚拟地址空间分配，只能被该进程的线程所访问。<br /><br />DLL的句柄可以被调用进程使用；调用进程的句柄可以被DLL使用。<br /><br />DLLDLL可以有自己的数据段，但没有自己的堆栈，使用调用进程的栈，与调用它的应用程序相同的堆栈模式。<br /><br />2)、关于共享数据段<br /><br />DLL定义的全局变量可以被调用进程访问；DLL可以访问调用进程的全局数据。使用同一DLL的每一个进程都有自己的DLL全局变量实例。如果多个线程并发访问同一变量，则需要使用同步机制；对一个DLL的变量，如果希望每个使用DLL的线程都有自己的值，则应该使用线程局部存储 (TLS，Thread Local Strorage)。<br /><br /><a href="http://blog.sina.com.cn/s/blog_494e45fe0100l4wv.html">http://blog.sina.com.cn/s/blog_494e45fe0100l4wv.html</a><br /><img src ="http://www.cppblog.com/jackdongy/aggbug/195184.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-11-14 11:03 <a href="http://www.cppblog.com/jackdongy/archive/2012/11/14/195184.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual Studio 2010控制台程序无法输出中文  </title><link>http://www.cppblog.com/jackdongy/archive/2012/11/03/194192.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Sat, 03 Nov 2012 03:09:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/11/03/194192.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/194192.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/11/03/194192.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/194192.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/194192.html</trackback:ping><description><![CDATA[<div><span style="font-size: 12px; font-family: Georgia; color: rgb(84,84,84); letter-spacing: 2px; line-height: 20px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px">
<p style="line-height: normal">Visual Studio 2008控制台程序无法输出中文！？解决方法只需要设置一下区域即可。没有设置区域前如下图：</p>
<p style="line-height: normal"><a style="font-size: 12px; font-family: Georgia; color: rgb(84,84,84); text-decoration: none; line-height: 20px" href="http://www.arelong.com/userfiles/Visual_studio_2008_chinese.jpg" rel="nofollow" target="_blank"><img style="line-height: normal" alt="Visual Studio 2008控制台程序无法输出中文 - 有何不可 - 不要辜负 期望" src="http://img.ph.126.net/BiH5ipB0nzqavUQOsNWzvQ==/3663678296866968535.jpg" width="782" height="589" __1351911559479__="ev_5838017479" /></a></p>
<p style="line-height: normal"><span style="font-size: large; line-height: normal">包含头文件：#include &lt;locale.h&gt;</span></p>
<p style="line-height: normal"><span style="font-size: large; line-height: normal">函数：_tsetlocale(LC_ALL, _T("chs"));</span></p>
<p style="line-height: normal"><span style="font-size: large; line-height: normal">设置区域后如下图：</span></p>
<p style="line-height: normal"><a style="font-size: 12px; font-family: Georgia; color: rgb(84,84,84); text-decoration: none; line-height: 20px" href="http://www.arelong.com/userfiles/Visual_studio_2008_chinese_ok.jpg" rel="nofollow" target="_blank"><img style="line-height: normal" alt="Visual Studio 2008控制台程序无法输出中文 - 有何不可 - 不要辜负 期望" src="http://img.ph.126.net/AclAiATJc_4wXAuaCQ8QqA==/3663678296866968536.jpg" width="782" height="589" __1351911559479__="ev_5168728791" /></a></p>
<p style="line-height: normal"><span style="font-size: large; line-height: normal">参考，摘自微软MSDN</span></p>
<p style="line-height: normal">控制台中的编码程序员在对控制台或&#8220;文本模式&#8221;应用程序编程时可同时使用 Unicode 和 SBCS 或 DBCS 编码。出于承袭方面的考虑，非 Unicode 控制台 I/O 函数使用控制台代码页（默认为 OEM 代码页）。Windows 中的所有其他非 Unicode 函数都使用 Windows 代码页。这意味着其他函数可能无法正确地处理由控制台函数返回的字符串，反之亦然。例如，如果 FindFirstFileA 返回了一个包含某个非 ASCII 字符的字符串，WriteConsoleA 将无法正常地显示该字符串。</p>
<p style="line-height: normal">要一直跟踪哪些函数需要哪些编码并正确转换文本参数的编码非常困难。函数 SetFileApisToOEM、SetFileApisToANSI 和帮助程序函数 AreFileApisANSI 的引入极大地简化了此项工作。前两个函数可接受或返回文件名称，对 KERNEL32.dll 导出的非 Unicode 函数有效果。顾名思义，SetFileApisToOEM 将这些函数设置为接受或返回与当前系统区域设置对应的 OEM 字符集中的文件名称，而 SetFileApisToANSI 用于为这些名称恢复默认值（Windows ANSI 编码）。使用 AreFileApisANSI 可查询到当前选定的编码。</p>
<p style="line-height: normal">利用 SetFileApisToOEM 可轻松地解决 WindFirstFileA（或 GetCurrentDirectoryA，或 Win32 API 的任何文件处理函数）的结果无法直接传送给 WriteConsoleA 这一问题：在调用 SetFileApisToOEM 后，WindFirstFileA 将返回以 OEM（而不是以 Windows ANSI 字符集）编码的文本。但此解决方案并非应对所有 Windows ANSI 与 OEM 不兼容情况的万能良方。设想您需要从某个文件处理函数中获取文本，然后将其输出到控制台，接着用其他函数（不受SetFileApisToOEM 的影响）处理该文本。这种绝对理想的情况需要更改编码。否则，您将需要调用 SetFileApisToOEM 以获取用于控制台输出的数据，然后调用SetFileApisToANSI 得到同一文本（使用另一种编码）进行内部处理。另一种 SetFileApisToOEM 无法发挥作用的情况对命令行参数的处理：当您的应用程序的入口点为 main（而不是 wmain）时，参数始终作为 Windows ANSI 字符串数组进行传递。这一切显然使编写非 Unicode 控制台应用程序的程序员的工作变得更复杂了。</p>
<p style="line-height: normal">更为复杂的是为控制台编写的 8 位代码需要处理两种不同类型的区域设置。在编写代码时，您可以使用 Win32 API 或 C 运行时库函数。Win32 API 的 ANSI 函数假定文本是针对当前控制台代码页（系统区域设置默认定义的）编码的。SetConsoleCP 和 SetConsoleOutputCP 函数可更改这些操作中使用的代码页。用户可在命令提示符下调用 chcp or mode con cp select= 命令，这将会更改当前控制台的代码页。设置固定的控制台代码页的另一种方法是用默认的代码页集创建控制台快捷方式（仅适用于东亚本地化版本的操作系统）。 应用程序应能够响应用户的操作。</p>
<p style="line-height: normal">C 运行时库（CRT 函数）中区分区域设置函数可依照 (_w)setlocale 调用所定义的设置处理文本。如果代码中未调用 (_w)setlocale，则 CRT 函数对这些操作使用 ANSI "C" 语言不变区域设置，这样就丢失了特定于语言的功能。</p>
<p style="line-height: normal">该函数的声明为：</p>
<p style="line-height: normal">setlocale( int category, const char *locale)或</p>
<p style="line-height: normal">_wsetlocale( int category, const wchar_t *locale)其中 "category" 用于定义受影响的特定于区域的设置（如果指定了 LC_ALL，则全部定义）。可变区域设置可以是显式区域设置名称或下面的某一项：</p>
<p style="line-height: normal">".OCP" 指与当前用户区域设置对应的 OEM 代码页<br style="line-height: normal" />".ACP" 或 "" 指与当前用户区域设置对应的 Windows 代码页<br style="line-height: normal" />".OCP" 和 ".ACP" 参数始终引用用户区域设置（而不是系统区域设置）的设置值。因此不能将它们用于设置 LC_CTYPE。此 "category" 定义了 Unicode 向 8 位转换的规则和其他文本处理程序，必须遵循控制台的设置（可使用 GetConsoleCP 和 GetConsoleOutputCP 访问）。</p>对控制台应用程序最佳的长期解决方案是使用 Unicode，因为 Unicode 接口是针对 Win32 API 和 C 运行时库定义的。今后的编程模型仍需要您显式地设置区域设置，但至少可肯定通过 Win32 和 CRT 看到的文本不再需要进行代码转换。</span></div><img src ="http://www.cppblog.com/jackdongy/aggbug/194192.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-11-03 11:09 <a href="http://www.cppblog.com/jackdongy/archive/2012/11/03/194192.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC DLL学习入门</title><link>http://www.cppblog.com/jackdongy/archive/2012/10/23/193722.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Tue, 23 Oct 2012 06:45:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/23/193722.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193722.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/23/193722.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193722.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193722.html</trackback:ping><description><![CDATA[<strong><a href="http://www.cnblogs.com/greatverve/archive/2010/11/19/vc-dll.html">http://www.cnblogs.com/greatverve/archive/2010/11/19/vc-dll.html</a><br /><br />1 用VC创建DLL动态链接库<br /></strong>1.1 创建dll项目<br /><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/greatverve/dll1.PNG" width="681" height="462" /><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/greatverve/dll2.PNG" width="615" height="449" /><br />1.2 为dll项目编写源文件<br /><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/greatverve/dll4.PNG" width="280" height="183" /><br />头文件dllDemo.h<br />
<div class="cnblogs_code">
<div><!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">&nbsp;_declspec(dllexport)&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Sum(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a,</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;b);</span><span style="color: #008000">//</span><span style="color: #008000">加法函数。</span><span style="color: #008000"><br /></span><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">&nbsp;_declspec(dllexport)&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Max(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;b);</span><span style="color: #008000">//</span><span style="color: #008000">取较大值函数</span><span style="color: #008000"><br /></span><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">&nbsp;_declspec(dllexport)&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Min(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;b);</span><span style="color: #008000">//</span><span style="color: #008000">取较小值函数</span></div></div>源文件dllDemo.cpp<br />
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div><img id="code_img_closed_0207250d-3fc8-453d-9f1a-6920ca7277f0" class="code_img_closed" style="display: none" alt="" src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" /><img id="code_img_opened_0207250d-3fc8-453d-9f1a-6920ca7277f0" class="code_img_opened" src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /><span class="cnblogs_code_collapse">大气象</span> 
<div id="cnblogs_code_open_0207250d-3fc8-453d-9f1a-6920ca7277f0">
<div><!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--><span style="color: #000000">#include&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">dllDemo.h</span><span style="color: #800000">"</span><span style="color: #000000"><br /></span><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">&nbsp;_declspec(dllexport)</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Sum(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;b)<br />{</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;a</span><span style="color: #000000">+</span><span style="color: #000000">b;}<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">&nbsp;_declspec(dllexport)</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Max(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;b)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(a</span><span style="color: #000000">&gt;=</span><span style="color: #000000">b)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;a;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;b;<br />}<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">&nbsp;_declspec(dllexport)</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Min(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;b)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(a</span><span style="color: #000000">&gt;=</span><span style="color: #000000">b)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;b;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;a;<br />}</span></div></div>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div></div>
<p>1.3 生成dll文件</p>
<p>编译源文件，如果没有出现错误提示，那么，在项目文件根目录的Debug文件夹内会生成一个dll文件&#8220;dllDemo.dll&#8221;。<br /><br /></p>
<p>调用<br />新建了个MFC单对话框项目，<br />将<strong>&#8220;</strong><strong>dllDemo.dll</strong><strong>&#8221;和&#8221;dllDemo.lib&#8221;</strong>文件复制到本项目的Debug目录下，<br />在VC工作空间的文件视图下面将&#8221;dllDemo.lib&#8221;添加到项目中<br /><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/greatverve/dll3.PNG" width="280" height="251" /><br />在对话框头文件添加引用：</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div><img id="code_img_closed_443ffa44-3f44-469d-a7b9-c1eb11926df0" class="code_img_closed" style="display: none" alt="" src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" /><img id="code_img_opened_443ffa44-3f44-469d-a7b9-c1eb11926df0" class="code_img_opened" src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif"  alt="" /><span class="cnblogs_code_collapse">大气象</span> 
<div id="cnblogs_code_open_443ffa44-3f44-469d-a7b9-c1eb11926df0">
<div><!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--><span style="color: #008000">//</span><span style="color: #008000">&nbsp;FileOperDlg.h&nbsp;:&nbsp;头文件<br /></span><span style="color: #008000">//<br /></span><span style="color: #000000"><br /></span><span style="color: #0000ff">#pragma</span><span style="color: #000000">&nbsp;once</span><span style="color: #000000"><br /><br /></span><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">_declspec(dllimport)&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Sum(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a,</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;b);<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">_declspec(dllimport)&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Max(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a,</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;b);<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">_declspec(dllimport)&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Min(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;a,</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;b);<br /></span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;CFileOperDlg&nbsp;对话框</span><span style="color: #008000"><br /></span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;CFileOperDlg&nbsp;:&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;CDialog<br />{<br /></span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;构造</span><span style="color: #008000"><br /></span><span style="color: #0000ff">public</span><span style="color: #000000">:<br />&nbsp;&nbsp;&nbsp;&nbsp;CFileOperDlg(CWnd</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;pParent&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;NULL);&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;标准构造函数<br /><br /></span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;对话框数据</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">enum</span><span style="color: #000000">&nbsp;{&nbsp;IDD&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;IDD_FILEOPER_DIALOG&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">protected</span><span style="color: #000000">:<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">virtual</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;DoDataExchange(CDataExchange</span><span style="color: #000000">*</span><span style="color: #000000">&nbsp;pDX);&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;DDX/DDV&nbsp;支持<br /><br /><br /></span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;实现</span><span style="color: #008000"><br /></span><span style="color: #0000ff">protected</span><span style="color: #000000">:<br />&nbsp;&nbsp;&nbsp;&nbsp;HICON&nbsp;m_hIcon;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;生成的消息映射函数</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">virtual</span><span style="color: #000000">&nbsp;BOOL&nbsp;OnInitDialog();<br />&nbsp;&nbsp;&nbsp;&nbsp;afx_msg&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;OnSysCommand(UINT&nbsp;nID,&nbsp;LPARAM&nbsp;lParam);<br />&nbsp;&nbsp;&nbsp;&nbsp;afx_msg&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;OnPaint();<br />&nbsp;&nbsp;&nbsp;&nbsp;afx_msg&nbsp;HCURSOR&nbsp;OnQueryDragIcon();<br />&nbsp;&nbsp;&nbsp;&nbsp;DECLARE_MESSAGE_MAP()<br /></span><span style="color: #0000ff">public</span><span style="color: #000000">:<br />&nbsp;&nbsp;&nbsp;&nbsp;CString&nbsp;m_info;<br />};<br /></span></div></div>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div></div>
<p>&nbsp;</p>
<p>调用：</p>
<div class="cnblogs_code">
<div><!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--><span style="color: #000000">CString&nbsp;str;<br /></span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;c</span><span style="color: #000000">=</span><span style="color: #000000">Sum(</span><span style="color: #800080">4</span><span style="color: #000000">,</span><span style="color: #800080">5</span><span style="color: #000000">);&nbsp;&nbsp;<br /></span><span style="color: #008000">//</span><span style="color: #008000">c=Max(5,6);&nbsp;&nbsp;<br /></span><span style="color: #008000">//</span><span style="color: #008000">c=Min(5,6);</span><span style="color: #008000"><br /></span><span style="color: #000000">str.Format(</span><span style="color: #800000">"</span><span style="color: #800000">%d</span><span style="color: #800000">"</span><span style="color: #000000">,c);<br />AfxMessageBox(str);</span></div></div>
<p>&nbsp;</p>
<p>调试<br />直接运行，选择一个调用dll的exe确定之后，就可以调试了，设置个断点试试。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>参考：<br /></p>
<p>VC++的DLL应用（含Demo演示）</p>
<p>作者：<a href="http://www.cnblogs.com/beer">一点一滴的Beer</a> <a href="http://beer.cnblogs.com/">http://beer.cnblogs.com/</a></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在大学大一的时候学的是C，然后后来大二的时候专业又开了C++这个课程，然后再后来自己又自学了一点VC++，大三的时候也试着编写过一个MFC的最简单的窗口程序。到大四的时候，自己又做了一个GIS的项目，是用C#.NET来编写的，然后发现C#上手好容易，而且还大部分语法规则都沿用了C，C++的习惯，于是觉得C++实在是没有一点优势可言啊。但这个暑假的实习经历又改变了我的观点：C++在写窗口程序虽然麻烦，但是却什么能做，而且对比C#来说，对运行环境的要求不高，不用像C#程序在安装之前还要安装100M多的运行.NET环境。C++和C#各有优缺，目前我对它们俩的定位是：C++用来写一些底层的程序，比如驱动，或者是一些算法类型的函数接口，然后用C#来调用这些接口并进行界面设计。如何函数的实现跨语言呢？显然DLL是个很重要的内容，故在此对VC++的DLL模块进行介绍。</p>
<p><strong>1 </strong><strong>用VC</strong><strong>创建DLL</strong><strong>动态连接库</strong></p>
<p>&nbsp;</p>
<p>1.1 创建dll项目</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image002_2.jpg"><img title="clip_image002" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; float: none; margin-left: auto; display: block; border-top-width: 0px; margin-right: auto" border="0" alt="clip_image002" src="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image002_thumb.jpg" width="558" height="368" /></a></p>
<p>然后选择&#8220;一个空的dll工程&#8221;，然后点击&#8220;确定&#8221;便完成了&#8220;创建dll项目&#8221;的流程。</p>
<p>&nbsp;</p>
<p>1.2 为dll项目编写源文件</p>
<p>新建两个文件：dllDemo.h， dllDemo.cpp </p>
<p>在头文件&#8221;dllDemo.h&#8221;中声明三个接口函数： </p>
<p>
<table cellspacing="0" cellpadding="0" border="1">
<tbody>
<tr>
<td valign="top" width="568"><pre><span style="color: #0000ff">extern</span> "<span style="color: #8b0000">C</span>" _declspec(dllexport) <span style="color: #0000ff">int</span> Sum(<span style="color: #0000ff">int</span> a,<span style="color: #0000ff">int</span> b);<span style="color: #008000">//加法函数。</span>
<span style="color: #0000ff">extern</span> "<span style="color: #8b0000">C</span>" _declspec(dllexport) <span style="color: #0000ff">int</span> Max(<span style="color: #0000ff">int</span> a, <span style="color: #0000ff">int</span> b);<span style="color: #008000">//取较大值函数</span>
<span style="color: #0000ff">extern</span> "<span style="color: #8b0000">C</span>" _declspec(dllexport) <span style="color: #0000ff">int</span> Min(<span style="color: #0000ff">int</span> a, <span style="color: #0000ff">int</span> b);<span style="color: #008000">//取较小值函数</span></pre></td></tr></tbody></table></p>
<p>&nbsp;</p>
<p>然后在&#8220;dllDemo.cpp&#8221;文件中实现三个接口函数：</p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div><pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">#include </span><span style="color: #800000">"</span><span style="color: #800000">dllDemo.h</span><span style="color: #800000">"</span><span style="color: #000000"><br /></span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000"> _declspec(dllexport)</span><span style="color: #0000ff">int</span><span style="color: #000000"> Sum(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a, </span><span style="color: #0000ff">int</span><span style="color: #000000"> b)<br />{<br /></span><span style="color: #0000ff">return</span><span style="color: #000000"> a</span><span style="color: #000000">+</span><span style="color: #000000">b;<br />}<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000"> _declspec(dllexport)</span><span style="color: #0000ff">int</span><span style="color: #000000"> Max(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a, </span><span style="color: #0000ff">int</span><span style="color: #000000"> b)<br />{<br /></span><span style="color: #0000ff">if</span><span style="color: #000000">(a</span><span style="color: #000000">&gt;=</span><span style="color: #000000">b)</span><span style="color: #0000ff">return</span><span style="color: #000000"> a;<br /></span><span style="color: #0000ff">else</span><span style="color: #000000"><br /></span><span style="color: #0000ff">return</span><span style="color: #000000"> b;<br />}<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000"> _declspec(dllexport)</span><span style="color: #0000ff">int</span><span style="color: #000000"> Min(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a, </span><span style="color: #0000ff">int</span><span style="color: #000000"> b)<br />{<br /></span><span style="color: #0000ff">if</span><span style="color: #000000">(a</span><span style="color: #000000">&gt;=</span><span style="color: #000000">b)</span><span style="color: #0000ff">return</span><span style="color: #000000"> b;<br /></span><span style="color: #0000ff">else</span><span style="color: #000000"><br /></span><span style="color: #0000ff">return</span><span style="color: #000000"> a;<br />}</span></div></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>1.3 生成dll文件</p>
<p>编译源文件，如果没有出现错误提示，那么，在项目文件根目录的Debug文件夹内会生成一个dll文件&#8220;dllDemo.dll&#8221;。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>2 DLL调用</strong></p>
<p><strong>&nbsp;</strong></p>
<p>2.1 用C++调用显式链接</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image004_2.jpg"><img title="clip_image004" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; float: none; margin-left: auto; display: block; border-top-width: 0px; margin-right: auto" border="0" alt="clip_image004" src="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image004_thumb.jpg" width="558" height="368" /></a></p>
<p>新建一个Win32的控制台程序进行显式调用:</p>
<p>1. 新建&#8220;dllConsoleEvident&#8221;的Win32控制台程序项目</p>
<p>2. 新建cpp文件&#8220;dllConsoleEvident.cpp&#8221;</p>
<p>3. 将在第一节中，在Debug目录下编译生成的&#8220;dllDemo.dll&#8221;（显式调用时只需要这一个文件就够了）文件复制到&#8220;dllConsoleEvident&#8221;项目下的Debug文件夹根目录下</p>
<p>4. 在&#8220;dllConsoleEvident.cpp&#8221;文件中编写以下代码对dll中的函数进行显式调用 </p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div><img id="code_img_closed_faf67461-e41b-442e-91af-70890c4590c9" class="code_img_closed" style="display: none" alt="" src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" jquery1290127399828="2" /><img id="code_img_opened_faf67461-e41b-442e-91af-70890c4590c9" class="code_img_opened" alt="" src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" /><span class="cnblogs_code_collapse">代码</span> 
<div id="cnblogs_code_open_faf67461-e41b-442e-91af-70890c4590c9" class="cnblogs_code_hide" style="display: block" jquery1290127399828="1"><pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #808080">////////////////////////////////////////////////////////////////////////</span><span style="color: #008000">//</span><span style="color: #808080"><br /></span><span style="color: #008000">//</span><span style="color: #008000">动态加载DLL文件</span><span style="color: #008000"><br /></span><span style="color: #000000">#include </span><span style="color: #000000">&lt;</span><span style="color: #000000">iostream.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />#include</span><span style="color: #000000">&lt;</span><span style="color: #000000">windows.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /></span><span style="color: #0000ff">void</span><span style="color: #000000"> main(</span><span style="color: #0000ff">void</span><span style="color: #000000">)<br />{<br />typedef </span><span style="color: #0000ff">int</span><span style="color: #000000">(</span><span style="color: #000000">*</span><span style="color: #000000">pMax)(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a,</span><span style="color: #0000ff">int</span><span style="color: #000000"> b);</span><span style="color: #008000">//</span><span style="color: #008000">函数指针</span><span style="color: #008000"><br /></span><span style="color: #000000">typedef </span><span style="color: #0000ff">int</span><span style="color: #000000">(</span><span style="color: #000000">*</span><span style="color: #000000">pMin)(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a,</span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br />pMax Max</span><span style="color: #000000">=</span><span style="color: #000000">NULL;<br />pMin Min</span><span style="color: #000000">=</span><span style="color: #000000">NULL;<br />HINSTANCE hDLL;<br />hDLL</span><span style="color: #000000">=</span><span style="color: #000000">LoadLibrary(</span><span style="color: #800000">"</span><span style="color: #800000">MyDll.dll</span><span style="color: #800000">"</span><span style="color: #000000">);</span><span style="color: #008000">//</span><span style="color: #008000">加载动态链接库MyDll.dll文件；</span><span style="color: #008000"><br /></span><span style="color: #000000">Max</span><span style="color: #000000">=</span><span style="color: #000000">(pMax)GetProcAddress(hDLL,</span><span style="color: #800000">"</span><span style="color: #800000">Max</span><span style="color: #800000">"</span><span style="color: #000000">);<br />Min</span><span style="color: #000000">=</span><span style="color: #000000">(pMin)GetProcAddress(hDLL,</span><span style="color: #800000">"</span><span style="color: #800000">Min</span><span style="color: #800000">"</span><span style="color: #000000">);<br /></span><span style="color: #0000ff">if</span><span style="color: #000000"> (Max)</span><span style="color: #008000">//</span><span style="color: #008000">如果取出函数成功，则执行下面的语句</span><span style="color: #008000"><br /></span><span style="color: #000000">{<br /></span><span style="color: #0000ff">int</span><span style="color: #000000"> A</span><span style="color: #000000">=</span><span style="color: #000000">Max(</span><span style="color: #800080">5</span><span style="color: #000000">,</span><span style="color: #800080">8</span><span style="color: #000000">);<br />cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #800000">"</span><span style="color: #800000">比较的结果为</span><span style="color: #800000">"</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">A;<br />}<br /></span><span style="color: #0000ff">if</span><span style="color: #000000"> (Min)<br />{<br /></span><span style="color: #0000ff">int</span><span style="color: #000000"> B</span><span style="color: #000000">=</span><span style="color: #000000">Min(</span><span style="color: #800080">5</span><span style="color: #000000">,</span><span style="color: #800080">8</span><span style="color: #000000">);<br />cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #800000">"</span><span style="color: #800000">比较的结果为</span><span style="color: #800000">"</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">B;<br />}<br />FreeLibrary(hDLL);</span><span style="color: #008000">//</span><span style="color: #008000">卸载MyDll.dll文件；</span><span style="color: #008000"><br /></span><span style="color: #000000">}</span></div></pre></div>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>2.2 用C++隐式链接（Win32控制台程序）</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image006_2.jpg"><img title="clip_image006" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; float: none; margin-left: auto; display: block; border-top-width: 0px; margin-right: auto" border="0" alt="clip_image006" src="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image006_thumb.jpg" width="558" height="368" /></a></p>
<p>新建一个Win32控制台程序演示静态调用</p>
<p>1. 利用向导新建&#8220;dllConsoleStaticDemo&#8221;的空工程</p>
<p>2. 将<strong>&#8220;</strong><strong>dllDemo.dll</strong><strong>&#8221;和&#8220;dllDemo.lib</strong><strong>&#8221;</strong>文件复制到Debug目录下，并在项目中包含&#8220;dllDemo.lib&#8221;文件（或者），否则会出现dll函数找不到的连接错误</p>
<p>3. 新建&#8220;dllConsoleStaticDemo.cpp&#8221;文件，并写入如下代码： </p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div><pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">_declspec(dllimport) </span><span style="color: #0000ff">int</span><span style="color: #000000"> Sum(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a,</span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">_declspec(dllimport) </span><span style="color: #0000ff">int</span><span style="color: #000000"> Max(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a,</span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">_declspec(dllimport) </span><span style="color: #0000ff">int</span><span style="color: #000000"> Min(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a,</span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br />#include </span><span style="color: #000000">&lt;</span><span style="color: #000000">iostream.h</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br /></span><span style="color: #0000ff">void</span><span style="color: #000000"> main()<br />{<br /></span><span style="color: #0000ff">int</span><span style="color: #000000"> c</span><span style="color: #000000">=</span><span style="color: #000000">Sum(</span><span style="color: #800080">4</span><span style="color: #000000">,</span><span style="color: #800080">5</span><span style="color: #000000">);<br />c</span><span style="color: #000000">=</span><span style="color: #000000">Max(</span><span style="color: #800080">5</span><span style="color: #000000">,</span><span style="color: #800080">6</span><span style="color: #000000">);<br />c</span><span style="color: #000000">=</span><span style="color: #000000">Min(</span><span style="color: #800080">5</span><span style="color: #000000">,</span><span style="color: #800080">6</span><span style="color: #000000">);<br />cout</span><span style="color: #000000">&lt;&lt;</span><span style="color: #800000">"</span><span style="color: #800000">Hello,dllConsoleTest~!</span><span style="color: #800000">"</span><span style="color: #000000">;<br />}</span></div></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>4．通过断点，可以看到dll函数调用成功</p>
<p>这种方式的静态调用的特点是：在程序一开始执行的时候，就将dll文件全部加载到程序中，不会释放。</p>
<p>&nbsp;</p>
<p>2.3 用C++隐式链接（MFC窗口程序）</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image008_2.jpg"><img title="clip_image008" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; float: none; margin-left: auto; display: block; border-top-width: 0px; margin-right: auto" border="0" alt="clip_image008" src="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image008_thumb.jpg" width="558" height="368" /></a></p>
<p>新建一个MFC基本对话框窗口程序进行调用：</p>
<p>1. 利用向导建立一个MFC基本对话框</p>
<p>2. 将<strong>&#8220;</strong><strong>dllDemo.dll</strong><strong>&#8221;和&#8221;dllDemo.lib&#8221;</strong>文件复制到本项目的Debug目录下，在VC工作空间的文件视图下面将&#8221;dllDemo.lib&#8221;添加到项目中</p>
<p>3. 在&#8220;dllMfcDemoDlg.h&#8221;头文件中的前面对来自外部的dll函数进行声明 </p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div><pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000">//</span><span style="color: #008000"> dllMfcDemoDlg.h : header file<br /></span><span style="color: #008000">//<br /></span><span style="color: #0000ff">#if</span><span style="color: #000000"> !defined(AFX_DLLMFCDEMODLG_H__E358B876_D188_48FD_8D83_794309C885A9__INCLUDED_)</span><span style="color: #000000"><br /></span><span style="color: #0000ff">#define</span><span style="color: #000000"> AFX_DLLMFCDEMODLG_H__E358B876_D188_48FD_8D83_794309C885A9__INCLUDED_</span><span style="color: #000000"><br /></span><span style="color: #0000ff">#if</span><span style="color: #000000"> _MSC_VER &gt; 1000</span><span style="color: #000000"><br /></span><span style="color: #0000ff">#pragma</span><span style="color: #000000"> once</span><span style="color: #000000"><br /></span><span style="color: #0000ff">#endif</span><span style="color: #000000"> </span><span style="color: #008000">//</span><span style="color: #008000"> _MSC_VER &gt; 1000</span><span style="color: #000000"><br /></span><span style="color: #808080">///////////////////////////////////////////////////////////////////////////</span><span style="color: #008000">//</span><span style="color: #808080"><br /></span><span style="color: #008000">//</span><span style="color: #008000"> CDllMfcDemoDlg dialog</span><span style="color: #008000"><br /></span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">_declspec(dllimport) </span><span style="color: #0000ff">int</span><span style="color: #000000"> Sum(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a,</span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">_declspec(dllimport) </span><span style="color: #0000ff">int</span><span style="color: #000000"> Max(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a,</span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br /></span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #800000">"</span><span style="color: #800000">C</span><span style="color: #800000">"</span><span style="color: #000000">_declspec(dllimport) </span><span style="color: #0000ff">int</span><span style="color: #000000"> Min(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a,</span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br />&#8230;&#8230;</span></div></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>4.在窗体界面上，双击&#8220;确定&#8221;按钮，进入到OnOk()的事件响应函数体，编写调用代码： </p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div><pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">void</span><span style="color: #000000"> CDllMfcDemoDlg::OnOK()<br />{<br /></span><span style="color: #008000">  //</span><span style="color: #008000"> TODO: Add extra validation here</span><span style="color: #008000"><br /></span><span style="color: #0000ff">  int</span><span style="color: #000000"> c</span><span style="color: #000000">=</span><span style="color: #000000">Sum(</span><span style="color: #800080">4</span><span style="color: #000000">,</span><span style="color: #800080">5</span><span style="color: #000000">);<br />  c</span><span style="color: #000000">=</span><span style="color: #000000">Max(</span><span style="color: #800080">5</span><span style="color: #000000">,</span><span style="color: #800080">6</span><span style="color: #000000">);<br />  c</span><span style="color: #000000">=</span><span style="color: #000000">Min(</span><span style="color: #800080">5</span><span style="color: #000000">,</span><span style="color: #800080">6</span><span style="color: #000000">);<br />  CDialog::OnOK();<br />}</span></div></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>通过设置断点单步运行就可以看到dll文件中的函数已经被成功调用了。</p>
<p>&nbsp;</p>
<p>2.4 用C#跨语言调用</p>
<p>C#控制台程序调用VC++建立一个dll：</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image010_2.jpg"><img title="clip_image010" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; float: none; margin-left: auto; display: block; border-top-width: 0px; margin-right: auto" border="0" alt="clip_image010" src="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image010_thumb.jpg" width="558" height="378" /></a></p>
<p>1. 用Visual Studio建立一个控制台程序</p>
<p>2. 将&#8220;dllDemo.dll&#8221;文件复制到项目的Debug目录下面</p>
<p>3. 在&#8220;Program.cs&#8221;中编写如下代码 </p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div><img id="code_img_closed_21c6bdcb-638a-428e-b3f1-dec0ad809e5f" class="code_img_closed" style="display: none" alt="" src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" jquery1290127399828="4" /><img id="code_img_opened_21c6bdcb-638a-428e-b3f1-dec0ad809e5f" class="code_img_opened" alt="" src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" /><span class="cnblogs_code_collapse">代码</span> 
<div id="cnblogs_code_open_21c6bdcb-638a-428e-b3f1-dec0ad809e5f" class="cnblogs_code_hide" style="display: block" jquery1290127399828="3"><pre><div><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">using</span><span style="color: #000000"> System;<br /></span><span style="color: #0000ff">using</span><span style="color: #000000"> System.Collections.Generic;<br /></span><span style="color: #0000ff">using</span><span style="color: #000000"> System.Text;<br /></span><span style="color: #0000ff">using</span><span style="color: #000000"> System.Runtime.InteropServices;</span><span style="color: #008000">//</span><span style="color: #008000">引入dll文件中的函数</span><span style="color: #008000"><br /></span><span style="color: #0000ff">namespace</span><span style="color: #000000"> ConsoleDllDemo<br />{<br /></span><span style="color: #0000ff">class</span><span style="color: #000000"> Program<br />{<br /></span><span style="color: #008000">//</span><span style="color: #008000">引入dll文件中的函数</span><span style="color: #008000"><br /></span><span style="color: #000000">[DllImport(</span><span style="color: #800000">"</span><span style="color: #800000">dllDemo.dll</span><span style="color: #800000">"</span><span style="color: #000000">)]<br /></span><span style="color: #0000ff">private</span><span style="color: #000000"> </span><span style="color: #0000ff">static</span><span style="color: #000000"> </span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #0000ff">int</span><span style="color: #000000"> Sum(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a, </span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br />[DllImport(</span><span style="color: #800000">"</span><span style="color: #800000">dllDemo.dll</span><span style="color: #800000">"</span><span style="color: #000000">)]<br /></span><span style="color: #0000ff">private</span><span style="color: #000000"> </span><span style="color: #0000ff">static</span><span style="color: #000000"> </span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #0000ff">int</span><span style="color: #000000"> Max(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a, </span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br />[DllImport(</span><span style="color: #800000">"</span><span style="color: #800000">dllDemo.dll</span><span style="color: #800000">"</span><span style="color: #000000">)]<br /></span><span style="color: #0000ff">private</span><span style="color: #000000"> </span><span style="color: #0000ff">static</span><span style="color: #000000"> </span><span style="color: #0000ff">extern</span><span style="color: #000000"> </span><span style="color: #0000ff">int</span><span style="color: #000000"> Min(</span><span style="color: #0000ff">int</span><span style="color: #000000"> a, </span><span style="color: #0000ff">int</span><span style="color: #000000"> b);<br /></span><span style="color: #0000ff">static</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span><span style="color: #000000"> Main(</span><span style="color: #0000ff">string</span><span style="color: #000000">[] args)<br />{<br /></span><span style="color: #0000ff">int</span><span style="color: #000000"> a </span><span style="color: #000000">=</span><span style="color: #000000"> Sum(</span><span style="color: #800080">3</span><span style="color: #000000">, </span><span style="color: #800080">5</span><span style="color: #000000">);<br />Console.WriteLine(a);<br />Console.WriteLine(Max(</span><span style="color: #800080">5</span><span style="color: #000000">,</span><span style="color: #800080">10</span><span style="color: #000000">));<br />Console.WriteLine(Min(</span><span style="color: #800080">12</span><span style="color: #000000">,</span><span style="color: #800080">25</span><span style="color: #000000">));<br />Console.ReadKey();</span><span style="color: #008000">//</span><span style="color: #008000">要按键才退出。</span><span style="color: #008000"><br /></span><span style="color: #000000">}<br />}<br />}</span></div></pre></div>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a title="复制代码" href="javascript:void(0);"><img alt="复制代码" src="http://common.cnblogs.com/images/copycode.gif" /></a></span></div></div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>然后断点单步运行，便可以看到调用函数的结果了。</p>
<p>关于DLL的调用的更详细内容可以参考另外一些文章：</p>
<p><a href="http://dev.firnow.com/course/3_program/c++/cppsl/2008127/97781.html">http://dev.firnow.com/course/3_program/c++/cppsl/2008127/97781.html</a></p>
<p><a href="http://dev.yesky.com/283/2640283_2.shtml">http://dev.yesky.com/283/2640283_2.shtml</a></p>
<p><strong>&nbsp;</strong></p>
<p><strong>3 </strong><strong>dll</strong><strong>调试方法</strong></p>
<p>在建立了dll项目后，并写好相应的实现代码，点击&#8220;运行&#8221;，会弹出现在的对话框：</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image012_2.jpg"><img title="clip_image012" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; float: none; margin-left: auto; display: block; border-top-width: 0px; margin-right: auto" border="0" alt="clip_image012" src="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image012_thumb.jpg" width="544" height="160" /></a></p>
<p>然后浏览，找到一个调用了此dll文件的执行文件&#8220;*.exe&#8221;文件，然后就可以对dll文件进行断点调试了。</p>
<p>这个&#8220;*.exe&#8221;文件可以是任何平台的，C++也可以，C也可以，C#也可以，只要这个执行文件调用了dll文件中的函数即可。</p>
<p>如果想更换调试的&#8220;*.exe&#8221;文件，可以在&#8220;工程－》设置&#8221;对话框中的&#8220;调试&#8221;选项卡进行设置，浏览找到用户需要的&#8220;*.exe&#8221;文件</p>
<p><a href="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image014_2.jpg"><img title="clip_image014" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; float: none; margin-left: auto; display: block; border-top-width: 0px; margin-right: auto" border="0" alt="clip_image014" src="http://images.cnblogs.com/cnblogs_com/beer/WindowsLiveWriter/2b02712ca0ca_D80A/clip_image014_thumb.jpg" width="557" height="374" /></a></p>
<p>说明：以VC++环境中调用此dll为例，运行dllDemo项目，然后会调用&#8220;*.exe&#8221;文件，如果此exe文件含有源文件，而且刚好在源文件的Debug目录下面，那么，可以同时在exe文件的源文件中设置断点，进行dll和调用dll两个程序的联调。（好像跨语言调用的时候不能进行联调，笔者只在C++互相调用的时候联调成功过，但C#调用的时候没有联调成功，这个问题有待解决）</p>
<p><strong>&nbsp;</strong></p>
<p><strong>&nbsp;</strong></p>
<p><strong>4. DLL返回数据类型探究</strong></p>
<p>目前写的DLL函数反返回值还仅限于整形，还没有尝试其它特殊类型的返回值。更丰富的返回值类型，还要今后慢慢学习和研究。等回学校了再研究吧。请见后续文章吧。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>附件：</p>
<p>VC_dll_Realse.rar中是VC编写DLL并引用DLL的相关源码文件</p>
<p>CShapr_ConsoleDllDemo.rar中是VS2005编写的C#引用VC编写的DLL函数的相关源码文件</p>
<p><a title="http://files.cnblogs.com/beer/VC_dll_Realese.rar" href="http://files.cnblogs.com/beer/VC_dll_Realese.rar">http://files.cnblogs.com/beer/VC_dll_Realese.rar</a></p>
<p><a title="http://files.cnblogs.com/beer/CSharp_ConsoleDllDemo.rar" href="http://files.cnblogs.com/beer/CSharp_ConsoleDllDemo.rar">http://files.cnblogs.com/beer/CSharp_ConsoleDllDemo.rar</a></p>
<p><em>------------------------------------------------------------------</em></p><img src ="http://www.cppblog.com/jackdongy/aggbug/193722.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-23 14:45 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/23/193722.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>win8注册 卸载 报错： 模块XXX已加载 但对DllUnregisterServer的调用失败 处理方法 </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/20/193571.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Sat, 20 Oct 2012 08:39:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/20/193571.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193571.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/20/193571.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193571.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193571.html</trackback:ping><description><![CDATA[<div>WIN8&nbsp;&nbsp;注册 卸载dll </div>
<div><strong>报错：</strong></div>
<p>模块"xxxx.dll"已加载，但对DllRegisterServer的调用失败，错误代码为 XXXXXXXXX</p>
<p><strong>解决方法：</strong></p>
<p>若为安装，首先要保证XXX.dll在system32中，或者给出DLL的完整路径。<br /></p>
<div>
<div>运行&nbsp; 输入 cmd&nbsp; 会显示cmd.exe&nbsp;右键&nbsp; <strong style="color: red">&#8220;以管理员身份运行&#8221;</strong>&nbsp;注册dll </div>
<div>
<p>&nbsp;</p>
<div>在cmd界面：</div>
<p>输入&nbsp; regsvr32 &nbsp;%systemroot%/system32/XXX.ocx (XXX.dll) 回车</p>
<p>&nbsp;</p></div>
<div>
<div><strong>卸载控件：</strong></div></div>
<div>&nbsp; 
<div>在cmd界面：</div></div>
<div>输入 regsvr32&nbsp;/u&nbsp; ****.dll&nbsp;&nbsp; 回车</div>
<div>输入 regsvr32&nbsp;/u&nbsp; ****.ocx&nbsp; 回车 </div></div><img src ="http://www.cppblog.com/jackdongy/aggbug/193571.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-20 16:39 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/20/193571.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>fatal error RC1004: unexpected end of file found处理方法</title><link>http://www.cppblog.com/jackdongy/archive/2012/10/20/193570.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Sat, 20 Oct 2012 08:33:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/20/193570.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193570.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/20/193570.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193570.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193570.html</trackback:ping><description><![CDATA[<br />资源文件.rc的代码如下：<br />&nbsp;
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_EXTRACT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;142</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_EXTRACT_HELP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;143</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;144</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS_HELP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;145</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_OPEN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;146</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_OPEN_HELP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;147</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_TEST&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;148</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_TEST_HELP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;149</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_CAPTION_HELP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;150</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_POPUP_CAPTION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;151</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_EXTRACT_HERE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;152</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_EXTRACT_HERE_HELP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;153</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_EXTRACT_TO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;154</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_EXTRACT_TO_HELP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;155</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS_TO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;156</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS_TO_HELP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;157</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS_EMAIL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;158</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS_EMAIL_HELP&nbsp;&nbsp;159</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS_TO_EMAIL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;160</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS_TO_EMAIL_HELP&nbsp;&nbsp;161</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_FOLDER&nbsp;&nbsp;170</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_ARCHIVE&nbsp;171</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS_GPU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;180</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">#define</span><span style="color: #000000">&nbsp;IDS_CONTEXT_COMPRESS_GPU_HELP&nbsp;&nbsp;181</span></div><br /><br />编译的时候出现<br />1&gt;------ 已启动生成: 项目: Explorer, 配置: Debug x64 ------<br />1&gt;&nbsp; ContextMenu.cpp<br />1&gt;resource.h(31): fatal error RC1004: unexpected end of file found<br />1&gt;&nbsp; <br />========== 生成: 成功 0 个，失败 1 个，最新 0 个，跳过 0 个 ==========<br />的错误提示。<br /><strong>解决方法：</strong><br /><span style="font-size: 16px; color: rgb(255,0,0)">资源编译器错误 RC1004 错误消息 遇到意外的文件结束 此错误是由于文本文件的最后一行中缺少<strong>换行符</strong>和<strong>回车符</strong>而造成的。</span><br /><img src ="http://www.cppblog.com/jackdongy/aggbug/193570.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-20 16:33 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/20/193570.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>也谈C++中char*与wchar_t*之间的转换  </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/18/193478.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Thu, 18 Oct 2012 09:21:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/18/193478.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193478.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/18/193478.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193478.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193478.html</trackback:ping><description><![CDATA[<a href="http://blog.163.com/tianshi_17th/blog/static/4856418920085209414977/">http://blog.163.com/tianshi_17th/blog/static/4856418920085209414977/</a> 
<p><span style="font-size: 11pt; font-family: 宋体">关于</span><span style="font-size: 11pt">C++</span><span style="font-size: 11pt; font-family: 宋体">中的</span><span style="font-size: 11pt">char*</span><span style="font-size: 11pt; font-family: 宋体">与</span><span style="font-size: 11pt">wchar_t*</span><span style="font-size: 11pt; font-family: 宋体">这两种类型的相互转换，网上说的大多很繁琐，可行性也不高。下面这个方法是在</span><span style="font-size: 11pt">MSDN</span><span style="font-size: 11pt; font-family: 宋体">里面找到的，个人认为还比较不错：</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-size: 14pt; font-family: 宋体">把</span></strong><strong><span style="font-size: 14pt">char*</span></strong><strong><span style="font-size: 14pt; font-family: 宋体">转换为</span></strong><strong><span style="font-size: 14pt">wchar_t*</span></strong></p>
<p><span style="font-size: 11pt; font-family: 宋体">用</span><span style="font-size: 11pt">stdlib.h</span><span style="font-size: 11pt; font-family: 宋体">中的</span><span style="font-size: 11pt">mbstowcs_s</span><span style="font-size: 11pt; font-family: 宋体">函数，可以通过下面的例子了解其用法：</span></p>
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">CStr&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">string&nbsp;to&nbsp;convert</span><span style="color: #000000">"</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />size_t&nbsp;len&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;strlen(CStr)&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />size_t&nbsp;converted&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />wchar_t&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">WStr;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />WStr</span><span style="color: #000000">=</span><span style="color: #000000">(wchar_t</span><span style="color: #000000">*</span><span style="color: #000000">)malloc(len</span><span style="color: #000000">*</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(wchar_t));<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />mbstowcs_s(</span><span style="color: #000000">&amp;</span><span style="color: #000000">converted,&nbsp;WStr,&nbsp;len,&nbsp;CStr,&nbsp;_TRUNCATE);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span></div>
<p align="left"><span style="font-size: 11pt; font-family: 宋体">其结果是</span><span style="font-size: 11pt">WStr</span><span style="font-size: 11pt; font-family: 宋体">中储存了</span><span style="font-size: 11pt">CStr</span><span style="font-size: 11pt; font-family: 宋体">的</span><span style="font-size: 11pt">wchar_t</span><span style="font-size: 11pt; font-family: 宋体">版本。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-size: 14pt; font-family: 宋体">把</span></strong><strong><span style="font-size: 14pt">wchar_t*</span></strong><strong><span style="font-size: 14pt; font-family: 宋体">转换为</span></strong><strong><span style="font-size: 14pt">char*</span></strong></p>
<p><span style="font-size: 11pt; font-family: 宋体">和上面的方法类似，用</span><span style="font-size: 11pt">stdlib.h</span><span style="font-size: 11pt; font-family: 宋体">中的</span><span style="font-size: 11pt">wcstombs_s</span><span style="font-size: 11pt; font-family: 宋体">函数，例子：</span></p>
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #000000">wchar_t&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">WStr&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;L</span><span style="color: #000000">"</span><span style="color: #000000">string&nbsp;to&nbsp;convert</span><span style="color: #000000">"</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />size_t&nbsp;len&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;wcslen(WStr)&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">1</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />size_t&nbsp;converted&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">CStr;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />CStr</span><span style="color: #000000">=</span><span style="color: #000000">(</span><span style="color: #0000ff">char</span><span style="color: #000000">*</span><span style="color: #000000">)malloc(len</span><span style="color: #000000">*</span><span style="color: #0000ff">sizeof</span><span style="color: #000000">(</span><span style="color: #0000ff">char</span><span style="color: #000000">));<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />wcstombs_s(</span><span style="color: #000000">&amp;</span><span style="color: #000000">converted,&nbsp;CStr,&nbsp;len,&nbsp;WStr,&nbsp;_TRUNCATE);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span></div>
<p>&nbsp;<span style="font-size: 11pt; font-family: 宋体">这时</span><span style="font-size: 11pt">WStr</span><span style="font-size: 11pt; font-family: 宋体">中的内容将被转化为</span><span style="font-size: 11pt">char</span><span style="font-size: 11pt; font-family: 宋体">版本储存在</span><span style="font-size: 11pt">CStr</span><span style="font-size: 11pt; font-family: 宋体">中。</span></p>
<p><span style="font-size: 11pt; font-family: 宋体">另外还可以通过流的方法来</span><span style="font-size: 11pt">char*</span><span style="font-size: 11pt; font-family: 宋体">类型转换为</span><span style="font-size: 11pt">wchar_t*</span><span style="font-size: 11pt; font-family: 宋体">类型，但这样的转换得到的结果将是</span><span style="font-size: 11pt">const</span><span style="font-size: 11pt; font-family: 宋体">类型，而类似的方法不能将</span><span style="font-size: 11pt">wchar_t*</span><span style="font-size: 11pt; font-family: 宋体">类型转换为</span><span style="font-size: 11pt">char*</span><span style="font-size: 11pt; font-family: 宋体">类型。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-size: 14pt; font-family: 宋体">把（</span></strong><strong><span style="font-size: 14pt">const</span></strong><strong><span style="font-size: 14pt; font-family: 宋体">）</span></strong><strong><span style="font-size: 14pt">char*</span></strong><strong><span style="font-size: 14pt; font-family: 宋体">转换为</span></strong><strong><span style="font-size: 14pt">const wchar_t*</span></strong></p>
<p><span style="font-size: 11pt; font-family: 宋体">需要用到</span><span style="font-size: 11pt"> sstream </span><span style="font-size: 11pt; font-family: 宋体">头文件：</span><strong></p>
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #0000ff">char</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">cstr</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">string&nbsp;to&nbsp;convert</span><span style="color: #000000">"</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />wstringstream&nbsp;wss;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />wss</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">cstr;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span></div>
<p></strong><span style="font-size: 11pt; font-family: 宋体">再调用</span><span style="font-size: 11pt">wss.str().c_str(); </span><span style="font-size: 11pt; font-family: 宋体">即可得到</span><span style="font-size: 11pt"> const wchar_t* </span><span style="font-size: 11pt; font-family: 宋体">类型的返回值。</span></p>
<p><span style="font-size: 11pt; font-family: 宋体">虽然</span><span style="font-size: 11pt">stringstream</span><span style="font-size: 11pt; font-family: 宋体">流不能将</span><span style="font-size: 11pt">wchar_t*</span><span style="font-size: 11pt; font-family: 宋体">转换成</span><span style="font-size: 11pt">char*</span><span style="font-size: 11pt; font-family: 宋体">，但可以用来进行数值类型和字符串之间的转换，例如：</span></p>
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #0000ff">double</span><span style="color: #000000">&nbsp;d</span><span style="color: #000000">=</span><span style="color: #000000">2734792.934f</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />stringstream&nbsp;ss;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />ss</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">d;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span></div>
<p align="left"><span style="font-size: 11pt; font-family: 宋体">调用</span><span style="font-size: 11pt">ss.str()</span><span style="font-size: 11pt; font-family: 宋体">可得到</span><span style="font-size: 11pt">string</span><span style="font-size: 11pt; font-family: 宋体">类型字符串</span><span style="font-size: 11pt"> &#8221;273479e+006&#8221;</span><span style="font-size: 11pt; font-family: 宋体">，又如：</span></p>
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #0000ff">string</span><span style="color: #000000">&nbsp;str(</span><span style="color: #000000">"</span><span style="color: #000000">299792458</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />stringstream&nbsp;ss;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">long</span><span style="color: #000000">&nbsp;i</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />ss</span><span style="color: #000000">&lt;&lt;</span><span style="color: #000000">str;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />ss</span><span style="color: #000000">&gt;&gt;</span><span style="color: #000000">i;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /></span></div>
<p align="left"><span style="font-size: 11pt; font-family: 宋体">此时</span><span style="font-size: 11pt">i=299792458</span><span style="font-size: 11pt; font-family: 宋体">。</span><strong></strong></p><img src ="http://www.cppblog.com/jackdongy/aggbug/193478.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-18 17:21 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/18/193478.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>进程启动命令行中怎么传递带空格的参数 </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/18/193476.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Thu, 18 Oct 2012 07:50:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/18/193476.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193476.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/18/193476.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193476.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193476.html</trackback:ping><description><![CDATA[<a href="http://blog.csdn.net/tangaowen/article/details/6436053">http://blog.csdn.net/tangaowen/article/details/6436053</a><br /><br />
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size: large">进程</span><span style="font-size: large">启动命令行中怎么传递带空格的参数</span></p>
<p><span style="font-size: large">&nbsp;&nbsp; </span></p>
<p><span style="font-size: large">&nbsp;<span style="font-size: medium">一般我们在一个exe里面启动另外一个exe使用 ShellExecute 命令函数：</span></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"><span style="font-size: medium">比如下面的代码：</p>
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000">std::</span><span style="color: #0000ff">string</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;strExePath</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">D:/MyExe.exe</span><span style="color: #000000">"</span><span style="color: #000000">;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />std::</span><span style="color: #0000ff">string</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;strMyParas</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">D:/config.ini</span><span style="color: #000000">"</span><span style="color: #000000">;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />ShellExecute(NULL,&nbsp;_T(</span><span style="color: #000000">"</span><span style="color: #000000">open</span><span style="color: #000000">"</span><span style="color: #000000">),&nbsp;strExePath.c_str(),&nbsp;strMyParas.c_str(),&nbsp;NULL,&nbsp;SW_SHOWNORMAL);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span></div>
<p>&nbsp;</p>
<p><span style="font-size: large"><span style="font-size: medium">要启动的exe位于D盘的根目录下面，要传递的命令行参数为一个路径：</span></span></p>
<p><span style="font-size: large"><span style="font-size: medium">D:/config.ini&nbsp; </span></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"><span style="font-size: medium">那么在MyExe.exe里面怎么获得传递过去的命令行参数呢，看下面的代码：</span></span></p>
<p>&nbsp;</p>
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;argc</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />LPWSTR&nbsp;&nbsp;&nbsp;</span><span style="color: #000000">*</span><span style="color: #000000">argv</span><span style="color: #000000">=</span><span style="color: #000000">::CommandLineToArgvW(::GetCommandLineW(),</span><span style="color: #000000">&amp;</span><span style="color: #000000">argc);&nbsp;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">(argc</span><span style="color: #000000">&gt;=</span><span style="color: #000000">2</span><span style="color: #000000">)<br /><img onclick="this.style.display='none'; Codehighlighter1_100_126_Open_Text.style.display='none'; Codehighlighter1_100_126_Closed_Image.style.display='inline'; Codehighlighter1_100_126_Closed_Text.style.display='inline';" id="Codehighlighter1_100_126_Open_Image" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockStart.gif"><img onclick="this.style.display='none'; Codehighlighter1_100_126_Closed_Text.style.display='none'; Codehighlighter1_100_126_Open_Image.style.display='inline'; Codehighlighter1_100_126_Open_Text.style.display='inline';" id="Codehighlighter1_100_126_Closed_Image" style="display: none" align="top" src="http://www.cppblog.com/images/OutliningIndicators/ContractedBlock.gif"></span><span id="Codehighlighter1_100_126_Closed_Text" style="border-top: #808080 1px solid; border-right: #808080 1px solid; border-bottom: #808080 1px solid; border-left: #808080 1px solid; display: none; background-color: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_100_126_Open_Text"><span style="color: #000000">{<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/InBlock.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;strIniPath</span><span style="color: #000000">=</span><span style="color: #000000">argv[</span><span style="color: #000000">1</span><span style="color: #000000">];<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/ExpandedBlockEnd.gif"  alt="" />}</span></span></div>
<p><font size="4">那么，我们从上面的代码可以得出，命令行参数为argc-1个，都放在argv这个数组中，其中 argv[0] 是程序本身的执行路径，所以argc&gt;=1 .</font> </p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"><span style="font-size: medium">我们通过argv[1]就可以获得第一个命令行参数，比如上面的代码，我们就获得了传递过来的命令行参数为D:/config.ini&nbsp;&nbsp; 。</span></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"><span style="font-size: medium">但是，当我改变传递的命令行参数的内容为D:/Program Files/config.ini的时候</p>
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000">std::</span><span style="color: #0000ff">string</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;strExePath</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">D:/MyExe.exe</span><span style="color: #000000">"</span><span style="color: #000000">;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />std::</span><span style="color: #0000ff">string</span><span style="color: #000000">&nbsp;&nbsp;&nbsp;strMyParas</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">D:/Program&nbsp;Files/config.ini</span><span style="color: #000000">"</span><span style="color: #000000">;<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />ShellExecute(NULL,&nbsp;_T(</span><span style="color: #000000">"</span><span style="color: #000000">open</span><span style="color: #000000">"</span><span style="color: #000000">),&nbsp;strExePath.c_str(),&nbsp;strMyParas.c_str(),&nbsp;NULL,&nbsp;SW_SHOWNORMAL);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span></div>
<p>&nbsp;</p>
<p><span style="font-size: large"><span style="font-size: medium">我的MyExe.exe程序对命令行参数的解析出问题了，解析的结果为：D:/Program,而且argc=3,显然，程序把我的一个参数&#8220;D:/Program Files/config.ini&#8221;解析为两个参数：</span></span></p>
<p><span style="font-size: large"><span style="font-size: medium">argv[1]="D:/Program" ,&nbsp; argv[2]="Files/config.ini" 了。</span></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"><span style="font-size: medium">这是个比较严重的bug ,那么怎么告诉系统我传递的是一个带有空格的参数，而不是多个参数呢？</span></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"></span></p>
<p><span style="font-size: large"><span style="font-size: medium">&nbsp;解决方法:</span></span></p>
<p><span style="font-size: large"><span style="font-size: medium">可以使用下面的代码：</p>
<div style="font-size: 13px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; border-bottom: #cccccc 1px solid; word-break: break-all; padding-bottom: 4px; padding-top: 4px; padding-left: 4px; border-left: #cccccc 1px solid; padding-right: 5px; width: 98%; background-color: #eeeeee"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;wstring&nbsp;&nbsp;strExePath</span><span style="color: #000000">=</span><span style="color: #000000">wstring(L</span><span style="color: #000000">"</span><span style="color: #000000">/</span><span style="color: #000000">""</span><span style="color: #000000">);</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strExePath.append(strExePath);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strExePath.append(wstring(L</span><span style="color: #000000">"</span><span style="color: #000000">/</span><span style="color: #000000">""</span><span style="color: #000000">));</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wstring&nbsp;&nbsp;strMyParas</span><span style="color: #000000">=</span><span style="color: #000000">wstring(L</span><span style="color: #000000">"</span><span style="color: #000000">/</span><span style="color: #000000">""</span><span style="color: #000000">);</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strMyParas.append(strMyParas);<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strMyParas.append(wstring(L</span><span style="color: #000000">"</span><span style="color: #000000">//</span><span style="color: #000000">"</span><span style="color: #000000">));<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strMyParas.append(wstring(L</span><span style="color: #000000">"</span><span style="color: #000000">/</span><span style="color: #000000">""</span><span style="color: #000000">));</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ShellExecute(NULL,&nbsp;_T(</span><span style="color: #000000">"</span><span style="color: #000000">open</span><span style="color: #000000">"</span><span style="color: #000000">),&nbsp;strExePath.c_str(),&nbsp;strMyParas.c_str(),&nbsp;NULL,&nbsp;SW_SHOWNORMAL);</span></div>
<p><font size="4">将要传递的参数用"/""&nbsp; 和 "/""&nbsp; 给包起来，然后传递给ShellExecute就不会出现问题了。&nbsp; </font><br /></span></span></p>
<p><br /></span></span>&nbsp;</p>
<p><br /></span></span></p><img src ="http://www.cppblog.com/jackdongy/aggbug/193476.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-18 15:50 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/18/193476.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何管理以编程方式在 Windows NT 中的用户权限(C 语言)</title><link>http://www.cppblog.com/jackdongy/archive/2012/10/18/193458.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Thu, 18 Oct 2012 02:29:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/18/193458.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193458.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/18/193458.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193458.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193458.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://www.cnblogs.com/bluesky_blog/archive/2009/04/29.html管理用户权限可以实现以编程方式使用下列步骤： 打开与 LsaOpenPolicy() 的目标计算机上的策略。 要授予的权限，打开 POLICY_CREATE_ACCOUNT 和 POLICY_LOOKUP_NAMES 访问策略。 若要吊销权限，打开 POLICY_LOOKUP_...&nbsp;&nbsp;<a href='http://www.cppblog.com/jackdongy/archive/2012/10/18/193458.html'>阅读全文</a><img src ="http://www.cppblog.com/jackdongy/aggbug/193458.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-18 10:29 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/18/193458.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GetVersion和GetVersionEx</title><link>http://www.cppblog.com/jackdongy/archive/2012/10/18/193457.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Thu, 18 Oct 2012 02:19:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/18/193457.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193457.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/18/193457.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193457.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193457.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: GetVersion和GetVersionEx出自：http://flyxxtt.blogbus.com/logs/42705986.htmlWindows API 中有两个函数可以得到系统版本信息：GetVersion和GetVersionEx。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetVersion这个函数曾经困扰了很多程序员，其本来设计的是在DW...&nbsp;&nbsp;<a href='http://www.cppblog.com/jackdongy/archive/2012/10/18/193457.html'>阅读全文</a><img src ="http://www.cppblog.com/jackdongy/aggbug/193457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-18 10:19 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/18/193457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>COM 组件设计与应用（四）——简单调用组件 </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/17/193446.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Wed, 17 Oct 2012 15:13:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/17/193446.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193446.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/17/193446.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193446.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193446.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 目录(?)[-] 一、前言二、组件的启动和释放三、内存分配和释放四、参数传递方向五、示例程序六、小结本文摘自：http://www.vckbase.net/index.php/wv/1211一、前言&nbsp; &nbsp; &nbsp;同志们、朋友们、各位领导，大家好。　&nbsp;&nbsp;VCKBASE 不得了，&nbsp;&nb...&nbsp;&nbsp;<a href='http://www.cppblog.com/jackdongy/archive/2012/10/17/193446.html'>阅读全文</a><img src ="http://www.cppblog.com/jackdongy/aggbug/193446.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-17 23:13 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/17/193446.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>COM 组件设计与应用（三）——数据类型 </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/17/193445.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Wed, 17 Oct 2012 14:52:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/17/193445.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193445.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/17/193445.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193445.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193445.html</trackback:ping><description><![CDATA[<p>本文摘自：http://www.vckbase.com/index.php/wv/1206</p>
<p>&nbsp;</p>
<p><strong>一、前言</strong></p>
<p>上回书介绍了GUID、CLSID、IID和接口的概念。本回的重点是介绍 COM 中的数据类型。咋还不介绍组件程序的设计步骤呀？咳......别着急，别着急！孔子曰：&#8220;饭要一口一口地吃&#8221;；老子语：&#8220;心急吃不了热豆腐&#8221;，孙子云：&#8220;走一步看一步吧&#8221; ...... 先掌握必要的知识，将来写起程序来才会得心应手也:-) </p>
<p>走入正题之前，请大家牢牢记住一条原则：<strong>COM 组件是运行在分布式环境中的</strong>。比如，你写了一个组件程序（DLL或EXE），那么使用者可能是在本机的某个进程内加载组件（INPROC_SERVER）；也可能是从另一个进程中调用组件的进程（LOCAL_SERVER）；也可能是在这台计算机上调用地球那边计算机上的组件（REMOTE_SERVER）。所以在理解和设计的时候，要时时刻刻想起这句话。快！拿出小本本，记下来！ </p>
<p><strong>二、HRESULT 函数返回值</strong></p>
<p>每个人在做程序设计的时候，都有他们各自的哲学思想。拿函数返回值来说，就有好多种形式。 </p>
<p>
<table cellspacing="1" border="1">
<tbody>
<tr>
<td width="32%" align="center"><strong>函数</strong></td>
<td width="9%" align="center"><strong>返回值</strong></td>
<td width="58%" align="center"><strong>返回值信息</strong></td></tr>
<tr>
<td width="32%">double sin(double)</td>
<td width="9%">
<p align="center">浮点数值 </p></td>
<td width="58%">计算正玄值</td></tr>
<tr>
<td width="32%">BOOL DeleteFile(LPCTSTR)</td>
<td width="9%">
<p align="center">布尔值 </p></td>
<td width="58%">文件删除是否成功。如失败，需要GetLastError()才能取得失败原因</td></tr>
<tr>
<td width="32%">void * malloc(size_t)</td>
<td width="9%">
<p align="center">内存指针 </p></td>
<td width="58%">内存申请，如果失败，返回空指针 NULL</td></tr>
<tr>
<td width="32%">LONG RegDeleteKey(HKEY,LPCTSTR)</td>
<td width="9%">
<p align="center">整数 </p></td>
<td width="58%">删除注册表项。0表示成功，非0失败，同时这个值就反映了失败的原因</td></tr>
<tr>
<td width="32%">UINT DragQueryFile(HDROP,UINT,LPTSTR,UINT)</td>
<td width="9%">
<p align="center">整数 </p></td>
<td width="58%">取得拖放文件信息。以不同的参数调用，则返回不同的含义：<br />一会儿表示文件个数，一会儿表示文件名长度，一会儿表示字符长度</td></tr>
<tr>
<td width="32%">...... ......</td>
<td width="9%">
<p align="center">... </p></td>
<td width="58%">...... ......</td></tr></tbody></table>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>如此纷繁复杂的返回值，如此含义多变的返回值，使得大家在学习和使用的过程中，增加了额外的困难。好了，COM 的设计规范终于对他们进行了统一。组件API及接口指针中，除了IUnknown::AddRef()和IUnknown::Release()两个函数外，其它所有的函数，都以 HRESULT 作为返回值。大家想象一个组件的接口函数比如叫Add()，完成2个整数的加法运算，在C语言中，我们可以如下定义：</p>
<div id="highlighter_369339" class="syntaxhighlighter ">
<div class="lines">
<div class="line alt1">
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="datatypes">long</span><span>&nbsp;Add(&nbsp;</span><span class="datatypes">long</span><span>&nbsp;n1,&nbsp;</span><span class="datatypes">long</span><span>&nbsp;n2&nbsp;)&nbsp;&nbsp;</span></li><li><span>{&nbsp;&nbsp;</span></li><li class="alt"><span class="keyword">return</span><span>&nbsp;n1&nbsp;+&nbsp;n2;&nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">long Add( long n1, long n2 )
{
return n1 + n2;
}</pre></div></div></div>
<p>还记得刚才我们说的原则吗？<strong>COM 组件是运行在分布式环境中的</strong>。也就是说，这个函数可能运行在&#8220;地球另一边&#8221;的计算机上，既然运行在那么遥远的地方，就有可能出现服务器关机、网络掉线、运行超时、对方不在服务区......等异常。于是，这个加法函数，除了需要返回运算结果以外，还应该返回一个值------函数是否被正常执行了。</p>
<div id="highlighter_863825" class="syntaxhighlighter ">
<div class="lines">
<div class="line alt1">
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="datatypes">HRESULT</span><span>&nbsp;Add(&nbsp;</span><span class="datatypes">long</span><span>&nbsp;n1,&nbsp;</span><span class="datatypes">long</span><span>&nbsp;n2,&nbsp;</span><span class="datatypes">long</span><span>&nbsp;*pSum&nbsp;)&nbsp;&nbsp;</span></li><li><span>{&nbsp;&nbsp;</span></li><li class="alt"><span>3*pSum&nbsp;=&nbsp;n1&nbsp;+&nbsp;n2;&nbsp;&nbsp;</span></li><li><span>&nbsp;<span class="keyword">return</span><span>&nbsp;S_OK;&nbsp;&nbsp;</span></span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">HRESULT Add( long n1, long n2, long *pSum )
{
3*pSum = n1 + n2;
 return S_OK;
}</pre></div></div></div>
<p>如果函数正常执行，则返回 S_OK，同时真正的函数运行结果则通过参数指针返回。如果遇到了异常情况，则COM系统经过判断，会返回相应的错误值。常见的返回值有： </p>
<table cellspacing="1" cellpadding="1" border="1">
<tbody>
<tr>
<td width="19%" align="center"><strong>HRESULT</strong></td>
<td width="13%" align="center"><strong>值</strong></td>
<td width="68%" align="center"><strong>含义</strong></td></tr>
<tr>
<td width="19%">S_OK</td>
<td width="13%" align="center">0x00000000</td>
<td width="68%">成功</td></tr>
<tr>
<td width="19%">S_FALSE</td>
<td width="13%" align="center">0x00000001</td>
<td width="68%">函数成功执行完成，但返回时出现错误</td></tr>
<tr>
<td width="19%">E_INVALIDARG</td>
<td width="13%" align="center">0x80070057</td>
<td width="68%">参数有错误</td></tr>
<tr>
<td width="19%">E_OUTOFMEMORY</td>
<td width="13%" align="center">0x8007000E</td>
<td width="68%">内存申请错误</td></tr>
<tr>
<td width="19%">E_UNEXPECTED</td>
<td width="13%" align="center">0x8000FFFF</td>
<td width="68%">未知的异常</td></tr>
<tr>
<td width="19%">E_NOTIMPL</td>
<td width="13%" align="center">0x80004001</td>
<td width="68%">未实现功能</td></tr>
<tr>
<td width="19%">E_FAIL</td>
<td width="13%" align="center">0x80004005</td>
<td width="68%">没有详细说明的错误。一般需要取得 Rich Error 错误信息(注1)</td></tr>
<tr>
<td width="19%">E_POINTER</td>
<td width="13%" align="center">0x80004003</td>
<td width="68%">无效的指针</td></tr>
<tr>
<td width="19%">E_HANDLE</td>
<td width="13%" align="center">0x80070006</td>
<td width="68%">无效的句柄</td></tr>
<tr>
<td width="19%">E_ABORT</td>
<td width="13%" align="center">0x80004004</td>
<td width="68%">终止操作</td></tr>
<tr>
<td width="19%">E_ACCESSDENIED</td>
<td width="13%" align="center">0x80070005</td>
<td width="68%">访问被拒绝</td></tr>
<tr>
<td width="19%">E_NOINTERFACE</td>
<td width="13%" align="center">0x80004002</td>
<td width="68%">不支持接口</td></tr></tbody></table>
<p><img border="0" alt="" src="http://www.vckbase.com/Public/Uploads/images/90/1330593364.jpg" /></p>
<p>图一、HRESULT 的结构 </p>
<p>HRESULT 其实是一个双字节的值，其最高位(bit)如果是0表示成功，1表示错误。具体参见 MSDN 之"Structure of COM Error Codes"说明。我们在程序中如果需要判断返回值，则可以使用比较运算符号；switch开关语句；也可以使用VC提供的宏： </p>
<div id="highlighter_269211" class="syntaxhighlighter ">
<div class="bar">
<div class="toolbar">
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="datatypes">HRESULT</span><span>&nbsp;hr&nbsp;=&nbsp;调用组件函数;&nbsp;&nbsp;</span></li><li><span class="keyword">if</span><span>(&nbsp;SUCCEEDED(&nbsp;hr&nbsp;)&nbsp;){...}&nbsp;</span><span class="comment">//&nbsp;如果成功</span><span>&nbsp;&nbsp;</span></li><li class="alt"><span>......&nbsp;&nbsp;</span></li><li><span class="keyword">if</span><span>(&nbsp;FAILED(&nbsp;hr&nbsp;)&nbsp;){...}&nbsp;</span><span class="comment">//&nbsp;如果失败</span><span>&nbsp;&nbsp;</span></li><li class="alt"><span>......&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">HRESULT hr = 调用组件函数;
if( SUCCEEDED( hr ) ){...} // 如果成功
......
if( FAILED( hr ) ){...} // 如果失败
......</pre></div></div></div>
<p><strong>三、UNICODE</strong></p>
<p>计算机发明后，为了在计算机中表示字符，人们制定了一种编码，叫ASCII码。ASCII码由一个字节中的7位(bit)表示，范围是0x00 - 0x7F 共128个字符。他们以为这128个数字就足够表示abcd....ABCD....1234 这些字符了。 </p>
<p>咳......说英语的人就是&#8220;笨&#8221;！后来他们突然发现，如果需要按照表格方式打印这些字符的时候，缺少了&#8220;制表符&#8221;。于是又扩展了ASCII的定义，使用一个字节的全部8位(bit)来表示字符了，这就叫扩展ASCII码。范围是0x00 - 0xFF 共256个字符。 </p>
<p>咳......说中文的人就是聪明！中国人利用连续2个扩展ASCII码的扩展区域（0xA0以后）来表示一个汉字，该方法的标准叫GB-2312。后来，日文、韩文、阿拉伯文、台湾繁体（BIG-5）......都使用类似的方法扩展了本地字符集的定义，现在统一称为 MBCS 字符集（多字节字符集）。这个方法是有缺陷的，因为各个国家地区定义的字符集有交集，因此使用GB-2312的软件，就不能在BIG-5的环境下运行（显示乱码），反之亦然。 </p>
<p>咳......说英语的人终于变&#8220;聪明&#8221;一些了。为了把全世界人民所有的所有的文字符号都统一进行编码，于是制定了UNICODE标准字符集。UNICODE 使用2个字节表示一个字符(unsigned shor int、WCHAR、_wchar_t、OLECHAR)。这下终于好啦，全世界任何一个地区的软件，可以不用修改地就能在另一个地区运行了。虽然我用 IE 浏览日本网站，显示出我不认识的日文文字，但至少不会是乱码了。UNICODE 的范围是 0x0000 - 0xFFFF 共6万多个字符，其中光汉字就占用了4万多个。嘿嘿，中国人赚大发了:0) </p>
<p>在程序中使用各种字符集的方法： </p>
<div id="highlighter_953672" class="syntaxhighlighter ">
<div class="bar">
<div class="toolbar">
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="keyword">const</span><span>&nbsp;</span><span class="datatypes">char</span><span>&nbsp;*&nbsp;p&nbsp;=&nbsp;</span><span class="string">"Hello"</span><span>;&nbsp;</span><span class="comment">//&nbsp;使用&nbsp;ASCII&nbsp;字符集</span><span>&nbsp;&nbsp;</span></li><li><span class="keyword">const</span><span>&nbsp;</span><span class="datatypes">char</span><span>&nbsp;*&nbsp;p&nbsp;=&nbsp;</span><span class="string">"你好"</span><span>;&nbsp;</span><span class="comment">//&nbsp;使用&nbsp;MBCS&nbsp;字符集，由于&nbsp;MBCS&nbsp;完全兼容&nbsp;ASCII，多数情况下，我们并不严格区分他们</span><span>&nbsp;&nbsp;</span></li><li class="alt"><span class="datatypes">LPCSTR</span><span>&nbsp;p&nbsp;=&nbsp;</span><span class="string">"Hello,你好"</span><span>;&nbsp;</span><span class="comment">//&nbsp;意义同上</span><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span class="keyword">const</span><span>&nbsp;</span><span class="datatypes">WCHAR</span><span>&nbsp;*&nbsp;p&nbsp;=&nbsp;L</span><span class="string">"Hello,你好"</span><span>;&nbsp;</span><span class="comment">//&nbsp;使用&nbsp;UNICODE&nbsp;字符集</span><span>&nbsp;&nbsp;</span></li><li><span>LPCOLESTR&nbsp;p&nbsp;=&nbsp;L<span class="string">"Hello,你好"</span><span>;&nbsp;</span><span class="comment">//&nbsp;意义同上</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span class="comment">//&nbsp;如果预定义了_UNICODE，则表示使用UNICODE字符集；如果定义了_MBCS,则表示使用&nbsp;MBCS</span><span>&nbsp;&nbsp;</span></li><li class="alt"><span class="keyword">const</span><span>&nbsp;</span><span class="datatypes">TCHAR</span><span>&nbsp;*&nbsp;p&nbsp;=&nbsp;_T(</span><span class="string">"Hello,你好"</span><span>);&nbsp;&nbsp;&nbsp;</span></li><li><span class="datatypes">LPCTSTR</span><span>&nbsp;p&nbsp;=&nbsp;_T(</span><span class="string">"Hello,你好"</span><span>);&nbsp;</span><span class="comment">//&nbsp;意义同上</span><span>&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">const char * p = "Hello"; // 使用 ASCII 字符集
const char * p = "你好"; // 使用 MBCS 字符集，由于 MBCS 完全兼容 ASCII，多数情况下，我们并不严格区分他们
LPCSTR p = "Hello,你好"; // 意义同上

const WCHAR * p = L"Hello,你好"; // 使用 UNICODE 字符集
LPCOLESTR p = L"Hello,你好"; // 意义同上

// 如果预定义了_UNICODE，则表示使用UNICODE字符集；如果定义了_MBCS,则表示使用 MBCS
const TCHAR * p = _T("Hello,你好"); 
LPCTSTR p = _T("Hello,你好"); // 意义同上</pre></div></div></div>
<p>在上面的例子中，T是非常有意思的一个符号（TCHAR、LPCTSTR、LPTSTR、_T()、_TEXT()...），它表示使用一种中间类型，既不明确表示使用 MBCS，也不明确表示使用 UNICODE。那到底使用哪种字符集那？嘿嘿......编译的时候决定吧。设置条件编译的方式是：VC6中，"Project\Settings...\C/C++卡片 Preprocessor definitions" 中添加或修改 _MBCS、_UNICODE；VC.NET中，"项目\属性\配置属性\常规\字符集"然后用组合窗进行选择。使用 T 类型，是非常好的习惯，严重推荐！ </p>
<p><strong>四、BSTR</strong></p>
<p>COM 中除了使用一些简单标准的数据类型外（注2），字符串类型需要特别重点地说明一下。还记得原则吗？<strong>COM 组件是运行在分布式环境中的</strong>。通俗地说，你不能直接把一个内存指针直接作为参数传递给COM函数。你想想，系统需要把这块内存的内容传递到&#8220;地球另一 边&#8221;的计算机上，因此，我至少需要知道你这块内存的尺寸吧？不然让我如何传递呀？传递多少字节呀？！而字符串又是非常常用的一种类型，因此 COM 设计者引入了 BASIC 中字符串类型的表示方式---BSTR。BSTR 其实是一个指针类型，它的内存结构是：（输入程序片段 BSTR p = ::SysAllocString(L"Hello,你好");断点执行，然后观察p的内存） </p>
<p><img class="newsEnd-c-img" style="height: 145px; width: 600px" alt="" src="http://www.vckbase.com/Public/Uploads/images/57/1330593364.jpg" width="676" height="164" /></p>
<p>图二、BSTR 内存结构 </p>
<p>BSTR 是一个指向 UNICODE 字符串的指针，且 BSTR 向前的4个字节中，使用DWORD保存着这个字符串的字节长度（ 没有含字符串的结束符）。因此系统就能够正确处理并传送这个字符串到&#8220;地球另一 边&#8221;了。特别需要注意的是，由于BSTR的指针就是指向 UNICODE 串，因此 BSTR 和 LPOLESTR 可以在一定程度上混用，但一定要注意： </p>
<p>有函数 fun(LPCOLESTR lp)，则你调用 BSTR p=...; fun(p); 正确 </p>
<p>有函数 fun(const BSTR bstr)，则你调用 LPCOLESTR p=...; fun(p); 错误！！！ </p>
<p>有关 BSTR 的处理函数： </p>
<table cellspacing="1" border="1">
<tbody>
<tr>
<td width="49%" align="center"><strong>API 函数</strong></td>
<td width="51%" align="center"><strong>说明</strong></td></tr>
<tr>
<td width="49%">SysAllocString()</td>
<td width="51%">申请一个 BSTR 指针，并初始化为一个字符串</td></tr>
<tr>
<td width="49%">SysFreeString()</td>
<td width="51%">释放 BSTR 内存</td></tr>
<tr>
<td width="49%">SysAllocStringLen()</td>
<td width="51%">申请一个指定字符长度的 BSTR 指针，并初始化为一个字符串</td></tr>
<tr>
<td width="49%">SysAllocStringByteLen()</td>
<td width="51%">申请一个指定字节长度的 BSTR 指针，并初始化为一个字符串</td></tr>
<tr>
<td width="49%">SysReAllocStringLen()</td>
<td width="51%">重新申请 BSTR 指针</td></tr>
<tr>
<td width="49%">
<p align="center"><strong>CString 函数</strong></p></td>
<td width="51%">
<p align="center"><strong>说明</strong></p></td></tr>
<tr>
<td width="49%">AllocSysString()</td>
<td width="51%">从 CString 得到 BSTR</td></tr>
<tr>
<td width="49%">SetSysString()</td>
<td width="51%">重新申请 BSTR 指针，并复制到 CString 中</td></tr>
<tr>
<td width="100%" colspan="2">
<p align="left"><strong>CComBSTR 函数</strong></p>
<p align="left">ATL 的 BSTR 包装类。在 atlbase.h 中定义 </p></td></tr>
<tr>
<td width="49%">Append()、AppendBSTR()、AppendBytes()、ArrayToBSTR()、BSTRToArray()、AssignBSTR()、Attach()、Detach()、Copy()、CopyTo()、Empty()、Length()、ByteLength()、ReadFromStream()、WriteToStream()、LoadString()、ToLower()、ToUpper()<br />运算符重载：!,!=,==,&lt;,&gt;,&amp;,+=,+,=,BSTR</td>
<td width="51%">太多了，但从函数名称不能看出其基本功能。详细资料，查看MSDN 吧。另外，左侧函数，有很多是 ATL 7.0 提供的，VC6.0 下所带的 ATL 3.0 不支持。<br />由于我们将来主要用 ATL 开发组件程序，因此使用 ATL 的 CComBSTR 为主。VC也提供了其它的包装类 _bstr_t。</td></tr></tbody></table>
<p><strong>五、各种字符串类型之间的转换</strong></p>
<p>1、函数 WideCharToMultiByte()，转换 UNICODE 到 MBCS。使用范例： </p>
<div id="highlighter_946787" class="syntaxhighlighter ">
<div class="bar         ">
<div class="toolbar">
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;LPCOLESTR&nbsp;lpw&nbsp;=&nbsp;L</span><span class="string">"Hello,你好"</span><span>;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">size_t</span><span>&nbsp;wLen&nbsp;=&nbsp;wcslen(&nbsp;lpw&nbsp;)&nbsp;+&nbsp;1;&nbsp;&nbsp;</span><span class="comment">//&nbsp;宽字符字符长度，+1表示包含字符串结束符</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;aLen=WideCharToMultiByte(&nbsp;&nbsp;</span><span class="comment">//&nbsp;第一次调用，计算所需&nbsp;MBCS&nbsp;字符串字节长度</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>CP_ACP,&nbsp;&nbsp;</span></li><li><span>0,&nbsp;&nbsp;</span></li><li class="alt"><span>lpw,&nbsp;&nbsp;<span class="comment">//&nbsp;宽字符串指针</span><span>&nbsp;&nbsp;</span></span></li><li><span>wLen,&nbsp;<span class="comment">//&nbsp;字符长度</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>NULL,&nbsp;&nbsp;</span></li><li><span>0,&nbsp;&nbsp;<span class="comment">//&nbsp;参数0表示计算转换后的字符空间</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>NULL,&nbsp;&nbsp;</span></li><li><span>NULL);&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">LPSTR</span><span>&nbsp;lpa&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;</span><span class="datatypes">char</span><span>&nbsp;[aLen];&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;WideCharToMultiByte(&nbsp;&nbsp;</span></li><li class="alt"><span>CP_ACP,&nbsp;&nbsp;</span></li><li><span>0,&nbsp;&nbsp;</span></li><li class="alt"><span>lpw,&nbsp;&nbsp;</span></li><li><span>wLen,&nbsp;&nbsp;</span></li><li class="alt"><span>lpa,&nbsp;&nbsp;<span class="comment">//&nbsp;转换后的字符串指针</span><span>&nbsp;&nbsp;</span></span></li><li><span>aLen,&nbsp;<span class="comment">//&nbsp;给出空间大小</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>NULL,&nbsp;&nbsp;</span></li><li><span>NULL);&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;此时，lpa&nbsp;中保存着转换后的&nbsp;MBCS&nbsp;字符串</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;...&nbsp;...&nbsp;...&nbsp;...&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">delete</span><span>&nbsp;[]&nbsp;lpa;&nbsp;&nbsp;</span></span></li></ol></div><pre class="cpp" style="display: none" name="code">    LPCOLESTR lpw = L"Hello,你好";
    size_t wLen = wcslen( lpw ) + 1;  // 宽字符字符长度，+1表示包含字符串结束符
    
    int aLen=WideCharToMultiByte(  // 第一次调用，计算所需 MBCS 字符串字节长度
CP_ACP,
0,
lpw,  // 宽字符串指针
wLen, // 字符长度
NULL,
0,  // 参数0表示计算转换后的字符空间
NULL,
NULL);

    LPSTR lpa = new char [aLen];

    WideCharToMultiByte(
CP_ACP,
0,
lpw,
wLen,
lpa,  // 转换后的字符串指针
aLen, // 给出空间大小
NULL,
NULL);

    // 此时，lpa 中保存着转换后的 MBCS 字符串
    ... ... ... ...
    delete [] lpa;</pre><br /></div></div></div>
<p>2、函数 MultiByteToWideChar()，转换 MBCS 到 UNICODE。使用范例： </p>
<div id="highlighter_773542" class="syntaxhighlighter ">
<div class="bar">
<div class="toolbar">
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="datatypes">LPCSTR</span><span>&nbsp;lpa&nbsp;=&nbsp;</span><span class="string">"Hello,你好"</span><span>;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">size_t</span><span>&nbsp;aLen&nbsp;=&nbsp;strlen(&nbsp;lpa&nbsp;)&nbsp;+&nbsp;1;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">int</span><span>&nbsp;wLen&nbsp;=&nbsp;MultiByteToWideChar(&nbsp;&nbsp;</span></span></li><li class="alt"><span>CP_ACP,&nbsp;&nbsp;</span></li><li><span>0,&nbsp;&nbsp;</span></li><li class="alt"><span>lpa,&nbsp;&nbsp;</span></li><li><span>aLen,&nbsp;&nbsp;</span></li><li class="alt"><span>NULL,&nbsp;&nbsp;</span></li><li><span>0);&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;LPOLESTR&nbsp;lpw&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;</span><span class="datatypes">WCHAR</span><span>&nbsp;[wLen];&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;MultiByteToWideChar(&nbsp;&nbsp;</span></li><li><span>CP_ACP,&nbsp;&nbsp;</span></li><li class="alt"><span>0,&nbsp;&nbsp;</span></li><li><span>lpa,&nbsp;&nbsp;</span></li><li class="alt"><span>aLen,&nbsp;&nbsp;</span></li><li><span>lpw,&nbsp;&nbsp;</span></li><li class="alt"><span>wLen);&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;...&nbsp;...&nbsp;...&nbsp;...&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">delete</span><span>&nbsp;[]&nbsp;lpw;&nbsp;&nbsp;</span></span></li></ol></div><pre class="cpp" style="display: none" name="code">    LPCSTR lpa = "Hello,你好";
    size_t aLen = strlen( lpa ) + 1;
    
    int wLen = MultiByteToWideChar(
CP_ACP,
0,
lpa,
aLen,
NULL,
0);
    
    LPOLESTR lpw = new WCHAR [wLen];
    MultiByteToWideChar(
CP_ACP,
0,
lpa,
aLen,
lpw,
wLen);
    ... ... ... ...
    delete [] lpw;</pre></div></div></div>
<p>3、使用 ATL 提供的转换宏。 </p>
<table class="dtTABLE" cellspacing="1" width="100%" border="1">
<tbody>
<tr valign="top">
<td width="226">A2BSTR</td>
<td width="226">OLE2A</td>
<td width="226">T2A</td>
<td width="227">W2A</td></tr>
<tr valign="top">
<td width="226">A2COLE</td>
<td width="226">OLE2BSTR</td>
<td width="226">T2BSTR</td>
<td width="227">W2BSTR</td></tr>
<tr valign="top">
<td width="226">A2CT</td>
<td width="226">OLE2CA</td>
<td width="226">T2CA</td>
<td width="227">W2CA</td></tr>
<tr valign="top">
<td width="226">A2CW</td>
<td width="226">OLE2CT</td>
<td width="226">T2COLE</td>
<td width="227">W2COLE</td></tr>
<tr valign="top">
<td width="226">A2OLE</td>
<td width="226">OLE2CW</td>
<td width="226">T2CW</td>
<td width="227">W2CT</td></tr>
<tr valign="top">
<td width="226">A2T</td>
<td width="226">OLE2T</td>
<td width="226">T2OLE</td>
<td width="227">W2OLE</td></tr>
<tr valign="top">
<td width="226">A2W</td>
<td width="226">OLE2W</td>
<td width="226">T2W</td>
<td width="227">W2T</td></tr></tbody></table>
<p>上表中的宏函数，其实非常容易记忆： </p>
<table cellspacing="1" width="100%" border="1">
<tbody>
<tr>
<td width="10%">2</td>
<td width="90%">好搞笑的缩写，to 的发音和 2 一样，所以借用来表示&#8220;转换为、转换到&#8221;的含义。</td></tr>
<tr>
<td width="10%">A</td>
<td width="90%">ANSI 字符串，也就是 MBCS。</td></tr>
<tr>
<td width="10%">W、OLE</td>
<td width="90%">宽字符串，也就是 UNICODE。</td></tr>
<tr>
<td width="10%">T</td>
<td width="90%">中间类型T。如果定义了 _UNICODE，则T表示W；如果定义了 _MBCS，则T表示A</td></tr>
<tr>
<td width="10%">C</td>
<td width="90%">const 的缩写</td></tr></tbody></table>
<p>使用范例：</p>
<div id="highlighter_802711" class="syntaxhighlighter ">
<div class="bar">
<div class="toolbar">
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/wangqiulin123456/article/details/8071588#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="preprocessor">#include&nbsp;&lt;&nbsp;atlconv.h&nbsp;&gt;</span><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span class="keyword">void</span><span>&nbsp;fun()&nbsp;&nbsp;</span></li><li><span>{&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;USES_CONVERSION;&nbsp;&nbsp;<span class="comment">//&nbsp;只需要调用一次，就可以在函数中进行多次转换</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="datatypes">LPCTSTR</span><span>&nbsp;lp&nbsp;=&nbsp;OLE2CT(&nbsp;L</span><span class="string">"Hello,你好"</span><span>)&nbsp;);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;...&nbsp;...&nbsp;...&nbsp;...&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;不用显式释放&nbsp;lp&nbsp;的内存，因为</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;由于&nbsp;ATL&nbsp;转换宏使用栈作为临时空间，函数结束后会自动释放栈空间。</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">#include &lt; atlconv.h &gt;

void fun()
{
    USES_CONVERSION;  // 只需要调用一次，就可以在函数中进行多次转换
    
    LPCTSTR lp = OLE2CT( L"Hello,你好") );
    ... ... ... ...
    // 不用显式释放 lp 的内存，因为
    // 由于 ATL 转换宏使用栈作为临时空间，函数结束后会自动释放栈空间。
}</pre></div></div></div>
<p>使用 ATL 转换宏，由于不用释放临时空间，所以使用起来非常方便。但是考虑到栈空间的尺寸（VC 默认2M），使用时要注意几点： </p>
<p>1、只适合于进行短字符串的转换； </p>
<p>2、不要试图在一个次数比较多的循环体内进行转换； </p>
<p>3、不要试图对字符型文件内容进行转换，因为文件尺寸一般情况下是比较大的； </p>
<p>4、对情况 2 和 3，要使用 MultiByteToWideChar() 和 WideCharToMultiByte()； </p>
<p><strong>六、VARIANT</strong></p>
<p>C++、BASIC、Java、Pascal、Script......计算机语言多种多样，而它们各自又都有自己的数据类型，COM 产生目的，其中之一就是要跨语言(注3)。而 VARIANT 数据类型就具有跨语言的特性，同时它可以表示（存储）任意类型的数据。从C语言的角度来讲，VARIANT 其实是一个结构，结构中用一个域(vt)表示------该变量到底表示的是什么类型数据，同时真正的数据则存贮在 union 空间中。结构的定义太长了（虽然长，但其实很简单）大家去看 MSDN 的描述吧，这里给出如何使用的简单示例： </p>
<p>学生：我想用 VARIANT 表示一个4字节长的整数，如何做？ </p>
<p>老师：VARIANT v; v.vt=VT_I4; v.lVal=100; </p>
<p>学生：我想用 VARIANT 表示布尔值&#8220;真&#8221;，如何做？ </p>
<p>老师：VARIANT v; v.vt=VT_BOOL; v.boolVal=VARIANT_TRUE; </p>
<p>学生：这么麻烦？我能不能 v.boolVal=true; 这样写？ </p>
<p>老师：不可以！因为　 </p>
<table cellspacing="1" width="70%" border="1">
<tbody>
<tr>
<td width="20%" align="center"><strong>类型</strong></td>
<td width="20%" align="center"><strong>字节长度</strong></td>
<td width="20%" align="center"><strong>假值</strong></td>
<td width="20%" align="center"><strong>真值</strong></td></tr>
<tr>
<td width="20%" align="center">bool</td>
<td width="20%" align="center">1(char)</td>
<td width="20%" align="center">0(false)</td>
<td width="20%" align="center">1(true)</td></tr>
<tr>
<td width="20%" align="center">BOOL</td>
<td width="20%" align="center">4(int)</td>
<td width="20%" align="center">0(FALSE)</td>
<td width="20%" align="center">1(TRUE)</td></tr>
<tr>
<td width="20%" align="center">VT_BOOL</td>
<td width="20%" align="center">2(short int)</td>
<td width="20%" align="center">0(VARIANT_FALSE)</td>
<td width="20%" align="center">-1(VARIANT_TRUE)</td></tr></tbody></table>
<p>所以如果你 v.boolVal=true 这样赋值，那么将来 if(VARIANT_TRUE==v.boolVal) 的时候会出问题(-1 != 1)。但是你注意观察，任何布尔类型的&#8220;假&#8221;都是0，因此作为一个好习惯，在做布尔判断的时候，不要和&#8220;真值&#8221;相比较，而要与&#8220;假值&#8221;做比较。 </p>
<p>学生：谢谢老师，你太牛了。我对老师的敬仰如滔滔江水，连绵不绝...... </p>
<p>学生：我想用 VARIANT 保存字符串，如何做？ </p>
<p>老师：VARIANT v; v.vt=VT_BSTR; v.bstrVal=SysAllocString(L"Hello,你好"); </p>
<p>学生：哦......我明白了。可是这么操作真够麻烦的，有没有简单一些的方法？ </p>
<p>老师：有呀，你可以使用现成的包装类 CComVariant、COleVariant、_variant_t。比如上面三个问题就可以这样书写：CComVariant v1(100),v2(true),v3("Hello,你好"); 简单了吧？！(注4) </p>
<p>学生：老师，我再问最后一个问题，我如何用 VARIANT 保存一个数组？ </p>
<p>老师：这个问题很复杂，我现在不能告诉你，我现在告诉你怕你印象不深......(注5) </p>
<p>学生：~!@#$%^&amp;*()......晕！ </p>
<p><strong>七、小结</strong></p>
<p>以上所介绍的内容，是基本功，必须熟练掌握。先到这里吧，休息一会儿......更多精彩内容，敬请关注《COM 组件设计与应用(四)》 </p>
<p><br /></p>
<p>注1：在后续的 ISupportErrorInfo 接口中介绍。 </p>
<p>注2：常见的数据类型，请参考 IDL 文件的说明。（别着急，还没写那......嘿嘿） </p>
<p>注3：跨语言就是各种语言中都能使用COM组件。但啥时候能跨平台呢？ </p>
<p>注4：CComVariant/COlevariant/_variant_t 请参看 MSDN。 </p>
<p>注5：关于安全数组 SafeArray 的使用，在后续的文章中讨论。</p><img src ="http://www.cppblog.com/jackdongy/aggbug/193445.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-17 22:52 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/17/193445.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>  COM组件设计与应用（二）——GUID和接口 </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/17/193442.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Wed, 17 Oct 2012 14:33:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/17/193442.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193442.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/17/193442.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193442.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193442.html</trackback:ping><description><![CDATA[<p><span style="font-size: 14px">本文摘自：<a href="http://blog.vckbase.com/teacheryang/archive/2005/06/27/8884.html">http://blog.vckbase.com/teacheryang/archive/2005/06/27/8884.html</a></span><span style="font-size: 14px"></span></p>
<p><span style="font-size: 14px"></span></p>
<p><span style="font-size: 14px"><strong>一、前言</strong></span><br /><span style="font-size: 14px">　　书接上回，话说在 doc(Word) 复合文件中，已经解决了保存 xls(Excel) 数据的问题了。那么，接下来又要解决另一个问题：当 WORD 程序读取复合文件，遇到了 xls 数据的时候，它该如何启动 Excel 呢？启动后，又如何让 Excel 自己去读入、解析、显示 xls 数据呢？</span><br /><br /><span style="font-size: 14px"><strong>二、CLSID 概念</strong></span><br /><span style="font-size: 14px">　　有一个非常简单的解决方案，那就是在对象数据的前面，保存有处理这个数据的程序名。（见下图左上）</span></p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2011/325507/2011082020383368.jpg" /><br /><span style="font-size: 14px">图一、CLSID 的概念</span><br /><span style="font-size: 14px">　　这的确是一个简单的方法，但同时问题也很严重。在&#8220;张三&#8221;的计算机上，Excel 的路径是："c:\office\Excel.exe"，如果把这个 doc 文件复制到&#8220;李四&#8221;的计算机上使用，而&#8220;李四&#8221;的 Excel 的路径是：</span><br /><span style="font-size: 14px">"d:\Program files\Microsoft Office\Office\Excel.exe"，完蛋了:-(</span><br /><span style="font-size: 14px">　　于是，微软想出了一个解决方案，那就是不使用直接的路径表示方法，而使用一个叫 CLSID（注1）的方式间接描述这些对象数据的处理程序路径。CLSID 其实就是一个号码，或者说是一个16字节的数。观察注册表（上图），在HKCR\CLSID\{......}主键下，LocalServer32（DLL组件使用InprocServer32） 中保存着程序路径名称。CLSID 的结构定义如下：<br /></span><span style="font-size: 14px">typedef struct _GUID { <br />　　</span><span style="font-size: 14px">DWORD Data1; // 随机数 <br />　　WORD Data2; // 和时间相关 <br />　　WORD Data3; // 和时间相关 <br />BYTE Data4[8]; // 和网卡MAC相关 <br />} GUID; <br /><br />typedef GUID CLSID; // 组件ID<br />typedef GUID IID; // 接口ID <br />#define REFCLSID const CLSID &amp; <br /><br />// 常见的声明和赋值方法<br />CLSID CLSID_Excel = {0x00024500,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; <br />struct __declspec(uuid("00024500-0000-0000-C000-000000000046")) CLSID_Excel;<br />class DECLSPEC_UUID("00024500-0000-0000-C000-000000000046") CLSID_Excel;<br /><br />// 注册表中的表示方法<br />{00024500-0000-0000-C000-000000000046} </span></p>
<p><span style="font-size: 14px">　　用一个号码间接表示程序名，的确是个 Good idea，实现了组件位置的透明性，并方便地扩展出 DCOM（远程组件）。但，但，但，但.....CLSID 有16个字节共128位二进制数，干吗用这么长的数字呀？遥想当年......我还在上幼儿园的时候，人们设计了 socket，用 TCP/IP 协议进行网络通讯。每个参与通讯的计算机都有一个4字节的 IP 表示编号地址，范围是 0,0,0,0 ~ 255,255,255,255 共42亿个地址。可是没想到啊，没想到，自从 Internet 选择了TCP/IP 协议后，42亿个地址就不够全世界的劳动人民分配啦。除了劳动人民，还有冰箱、彩电、电饭锅、手机、手提电脑......这些都需要连网呀。在办公室通过网络开启电饭锅给我焖饭，下班回家后就能吃现成的啦，多幸福呀？！（注：在我们家老婆是领导，所以是我做饭。咳......）</span><br /><span style="font-size: 14px">　　由于前车之鉴，微软这次设计 CLSID/IID 就使用了GUID概念的16个字节，这下好啦，全世界60亿人口，每个人每秒钟分配10亿个号码，那么需要分配1800亿年。反正等到地球没有了都不会使用完的:-)</span><br /><br /><span style="font-size: 14px"><strong>三、产生 CLSID<br />　　</strong>1、</span><span style="font-size: 14px">如果使用开发环境编写组件程序，则IDE会自动帮你产生 CLSID； <br />　　2、</span><span style="font-size: 14px">你可以手工写 CLSID，但千万不要和人家已经生成的 CLSID 重复呀，所以严重地不推荐；（可是微软的CLSID都是手工写的，这叫&#8220;只许州官放火，不许百姓点灯&#8221;） ； <br />　　3、</span><span style="font-size: 14px">程序中，可以用函数 CoCreateGuid() 产生 CLSID； <br />　　4、</span><span style="font-size: 14px">使用工具产生 GUID（注2）； </span></p>
<p><span style="font-size: 14px">　　vc6.0版本运行："vc目录\Common\Tools\GuidGen.exe"程序（你可以参照上回文章中介绍的方法，把这个工具程序加到开发环境中，方便调用）。vc.net版本，在菜单&#8220;工具\创建GUID&#8221;中，就可以执行了。</span><span style="font-size: 14px"> <br /><br /></span><span style="font-size: 14px"><strong>四、ProgID 概念</strong></span><br /><span style="font-size: 14px">　　每一个COM组件都需要指定一个 CLSID，并且不能重名。它之所以使用16个字节，就是要从概率上保证重复是&#8220;不可能&#8221;的。但是，（世界上就怕&#8220;但是&#8221;二字）微软为了使用方便，也支持另一个字符串名称方式，叫 ProgID(注3）。见上图注册表的ProgID 子键内容（注4）。由于 CLSID 和 ProgID 其实是一个概念的两个不同的表示形式，所以我们在程序中可以随便使用任何一种。（有些人就是讨厌，说话不算数。明明 GUID 的目的就是禁止重复，但居然又允许使用 ProgID？！ProgID 是一个字符串的名字，重复的可能性就太大了呀。赶明儿我也写个程序，我打算这个程序的 ProgID 叫&#8220;Excel.Application&#8221;,嘿嘿）下面介绍一下 CLSID 和 ProgID 之间的转换方法和相关的函数：</span></p>
<table style="width: 100%" cellspacing="1" border="1">
<tbody>
<tr>
<td width="41%" align="center"><span style="font-size: 14px"><strong>函数</strong></span></td>
<td width="59%" align="center"><span style="font-size: 14px"><strong>功能说明</strong></span></td></tr>
<tr>
<td width="41%"><span style="font-size: 14px">CLSIDFromProgID()、CLSIDFromProgIDEx()</span></td>
<td width="59%"><span style="font-size: 14px">由 ProgID 得到 CLSID。没什么好说的，你自己都可以写，查注册表贝</span></td></tr>
<tr>
<td width="41%"><span style="font-size: 14px">ProgIDFromCLSID()</span></td>
<td width="59%"><span style="font-size: 14px">由 CLSID 得到 ProgID，调用者使用完成后要释放 ProgID 的内存(注5)</span></td></tr>
<tr>
<td width="41%"><span style="font-size: 14px">CoCreateGuid()</span></td>
<td width="59%"><span style="font-size: 14px">随机生成一个 GUID</span></td></tr>
<tr>
<td width="41%"><span style="font-size: 14px">IsEqualGUID()、IsEqualCLSID()、IsEqualIID()</span></td>
<td width="59%"><span style="font-size: 14px">比较2个ID是否相等</span></td></tr>
<tr>
<td width="41%"><span style="font-size: 14px">StringFromCLSID()、StringFromGUID2()、StringFromIID()</span></td>
<td width="59%"><span style="font-size: 14px">由 CLSID,IID 得到注册表中CLSID样式的字符串，注意释放内存</span></td></tr></tbody></table>
<p>&nbsp;</p>
<p align="left"><span style="font-size: 14px"><strong>五、接口（Interface）的来历</strong></span><br /><span style="font-size: 14px">　　到此，我们已经知道了 CLSID 或 ProgID 唯一地表示一个组件服务程序，那么根据这些ID，就可以加载运行组件，并为客户端程序提供服务了。（启动组件程序的方法，会陆续介绍）。接下来先讨论如何调用组件提供的函数？-----接口。</span><br /><span style="font-size: 14px">　　作为客户端程序员，它希望或者说他要求：我的程序只写一次，然后不做任何修改就可以调用任意一个组件。举例来说： </span></p>
<ol><li>
<p align="left"><span style="font-size: 14px">你可以在 Word 中嵌入 Excel，也可以嵌入 Picture，也可以嵌入任何第三方发表的 ActiveX 文档......也就是说，连 Word 自己都不知道使用它的人将会在 doc 里面插入什么东东； </span></p></li><li>
<p align="left"><span style="font-size: 14px">你可以在 HTML 文件中插入一个 ActiveX，也可以插入一个程序脚本Script，......你自己写的插件也可以插入到 IE 环境中。为了完成你的功能， 你绝对也不会去让微软修改IE吧？！ </span></p></li></ol>
<p>&nbsp;</p>
<p align="left"><span style="font-size: 14px">　　这个要求实在有点难度，Office 开发停滞了。说来话巧，一天老O(Office 项目的总工程师)和小B(VB 项目的总工程师)一起喝酒，老O向小B倾诉了他的烦恼：</span><br /><span style="font-size: 14px">老O：怎么能让我写的程序C，可以调用其它人写的程序S中的函数？(C表示客户程序，S表示提供服务的程序)</span><br /><span style="font-size: 14px">小B：你是不是喝糊涂了？让S作成 DLL，你去 LoadLibrary()、GetProcAddress()、...FreeLibrary()？！</span><br /><span style="font-size: 14px">老O：废话！要是这么简单就好了。问题是，连我都不知道这个S程序是干什么的？能干什么？我怎么调用呀？</span><br /><span style="font-size: 14px">小B：哦......这个比较高级，但我现在不能告诉你，因为我怕你印象不深。</span><br /><span style="font-size: 14px">老O：~！&#183;#￥%&#8230;&#8230;&#8212;*......</span><br /><span style="font-size: 14px">小B：是这样的，在VB中，我们制定了一个标准，这个标准允许任何一个VB开发者，把他自己写的某个功能的小程序放在VB的工具栏上，这样就好象他扩展了 VB 的功能一样。</span><br /><span style="font-size: 14px">老O：哦？就是那个叫什么 VBX 的滥玩意儿？</span><br /><span style="font-size: 14px">小B：我呸......别看 VBX 这个东西不起眼儿，的确我也没看上它。但你猜怎么着？现在有成千上万的 VB 程序爱好者把他们写的各式各样功能的 VBX 小程序，放到网上，让大家共享那。</span><br /><span style="font-size: 14px">老O：哦~~~，那你们的这个 VBX 标准是什么？</span><br /><span style="font-size: 14px">小B：嘿嘿......其实特简单，就是在 VBX 中必须实现7个函数，这7个函数名称和功能必须是：初始化、释放、显示、消息处理......，而至于它内部想干什么，我也管不着。我只是在需要的时候调用我需要的这7个函数。</span><br /><span style="font-size: 14px">老O：哦~~~，这样呀......对了，我现有个急事，我先走了。88，你付帐吧......</span><br /><span style="font-size: 14px">小B：喂！喂喂...... 走这么急干什么，钱包都掉了:-)</span><br /><span style="font-size: 14px">　　老O虽然丢了钱包，仍然兴奋地冲回办公室，他开始了思考...... </span></p>
<p align="left"><span style="font-size: 14px">1、我的程序C，要能调用任何人写的程序B。那么B必须要按照我事先的要求，提供我需要的函数F1(),F2(),F3(),K1(),K2()。</span><br /><span style="font-size: 14px">2、BASIC 是解释执行，因此它的函数不用考虑书写顺序，只要给出函数名，解释器就能找到。但我使用的是 C++呀......</span><br /><span style="font-size: 14px">3、C++编译后的代码中没有函数名，只有函数地址，因此我必须改进为用VTAB（虚函数表）表示函数入口：</span></p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2011/325507/2011082020430198.jpg" /><br /><span style="font-size: 14px">图二、VTAB 的结构</span><br /><br /><span style="font-size: 14px">4、还不够好，需要改进一下，因为所有的函数地址都放在一个表中会不灵活、不好修改、不易扩展。恩，有了！按照函数功能的类型进行分类：</span></p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2011/325507/2011082020432516.jpg" /><br /><span style="font-size: 14px">图三、多个 VTAB 的结构</span><br /><br /><span style="font-size: 14px">5、问题又来了，现在有2个 VTAB 虚函数表，那么怎么能够从一个表找到另一个表那？恩又有办法了，我要求你必须要实现一个函数，并且这个函数地址必须放在所有表的开头（表中的第一个函数指针），这个函数就叫 QueryInterface()吧，完成从一个表查找到另一个表的功能：（除了QueryInterface()函数,顺便也完成另外两个函数，叫 AddRef() 和 Release()。这两个函数的功能以后再说）</span></p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2011/325507/2011082020440626.jpg" /><br /><span style="font-size: 14px">图四、COM 接口结构</span><br /><br /><span style="font-size: 14px">6、为了以后描述方便，不再使用上图（图四）的方法了，而使用图五这样简洁的样式：</span></p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2011/325507/2011082020442959.jpg" /><br /><span style="font-size: 14px">图五、COM 接口结构的简洁图示</span><br /><br /><br /><span style="font-size: 14px"><strong>六、接口（Interface）概念<br /></strong>1、函数是通过 VTAB 虚函数表提供其地址， 从另一个角度来看，不管用什么语言开发，编译器产生的代码都能生成这个表。这样就实现了组件的&#8220;二进制特性&#8221;轻松实现了组件的跨语言要求。</span><br /><span style="font-size: 14px">2、假设有一个指针型变量保存着 VTAB 的首地址，则这个变量就叫&#8220;接口指针&#8221;(注6)， 变量命名的时候，习惯上加上"I"开头。另外为了区分不同的接口，每个接口 也都要有一个名字，该名字就和 CLSID 一样，使用 GUID 方式，叫 IID。</span><br /><span style="font-size: 14px">3、接口一经发表，就不能再修改了。不然就会出现向前兼容的问题。这个性质叫&#8220;接口不变性&#8221;。</span><br /><span style="font-size: 14px">4、组件中必须有3个函数，QueryInterface、AddRef、Release，它们3个函数也组成一个接口，叫"IUnknown"。(注7)</span><br /><span style="font-size: 14px">5、任何接口，其实都包含了 IUnknown 接口。随着你接触到更多的接口就会了更体会解到接口的另一个性质&#8220;继承性&#8221;。</span><br /><span style="font-size: 14px">6、在任何接口上，调用表中的第一个函数,其实就是调用 QueryInterface()函数，就得到你想要的另外一个接口指针。这个性质叫&#8220;接口的传递性&#8221;</span><br /><span style="font-size: 14px">7、C/C++语言中需要事先对函数声明，那么就 会要求组件也必须提供C语言的头文件。不行！为了能使COM具有跨语言的能力，决定不再为任何语言提供对应的函数接口声明，而是独立地提供一个叫类型库（TLB）的声明。每个语言的IDE环境自己去根据TLB生成自己语言需要的包装。这个性质叫&#8220;接口声明的独立性&#8221;（注8）</span><br /><br /><span style="font-size: 14px"><strong>七、客户程序与组件之间的协商调用<br />　　</strong>回到我们的上一个话题，Word中嵌入一个组件，那么Word是如何协商使用这个组件的那？下面是容器和组件之间的一个模拟对话过程：</span></p>
<table style="width: 100%" cellspacing="1" border="1">
<tbody>
<tr>
<td width="3%" align="center">&nbsp;</td>
<td width="60%" align="center"><span style="font-size: 14px"><strong>容器 协商部分</strong></span></td>
<td width="87%" align="center"><span style="font-size: 14px"><strong>组件 应答部分</strong></span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">1</span></td>
<td width="60%"><span style="font-size: 14px">根据CLSID启动组件 。</span><br /><span style="font-size: 14px">CoCreateInstance()</span></td>
<td width="87%"><span style="font-size: 14px">生成对象，执行构造函数，执行初始化动作。</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">2</span></td>
<td width="41%"><span style="font-size: 14px">你有IUnknown接口吗？</span></td>
<td width="87%"><span style="font-size: 14px">有，给你！</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">3</span></td>
<td width="60%"><span style="font-size: 14px">恩，太好了，那么你有IPersistStorage接口吗？(注9)</span><br /><span style="font-size: 14px">IUnknown::QueryInterface(IID_IPersistStorage...)</span></td>
<td width="87%"><span style="font-size: 14px">没有！</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">4</span></td>
<td width="60%"><span style="font-size: 14px">真差劲，连这个都没有。那你有IPersistStreamInit接口吗？(注10)</span><br /><span style="font-size: 14px">IUnknown::QueryInterface(IID_IPersistStreamInit...)</span></td>
<td width="87%"><span style="font-size: 14px">哈，这个有，给！</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">5</span></td>
<td width="60%"><span style="font-size: 14px">好，好，这还差不多。你现在给我初始化吧。</span><br /><span style="font-size: 14px">IPersistStreamInit::InitNew()</span></td>
<td width="87%"><span style="font-size: 14px">OK，初始化完成了。</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">6</span></td>
<td width="60%"><span style="font-size: 14px">完成了？好！现在你读数据去吧。</span><br /><span style="font-size: 14px">IPersistStreamInit::Load()</span></td>
<td width="87%"><span style="font-size: 14px">读完啦。我根据数据，已经在窗口中显示出来了。</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">7</span></td>
<td width="60%"><span style="font-size: 14px">好，现在咱们各自处理用户的鼠标、键盘消息吧......</span></td>
<td width="87%"><span style="font-size: 14px">......</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">8</span></td>
<td width="60%"><span style="font-size: 14px">哎呀！用户要保存退出程序了。你的数据被用户修改了吗？</span><br /><span style="font-size: 14px">IPersistStreamInit::IsDirty()</span></td>
<td width="87%"><span style="font-size: 14px">改了，用户已经修改啦。</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">9</span></td>
<td width="60%"><span style="font-size: 14px">那好，那么用户修改后，你的数据需要多大的存储空间呀？</span><br /><span style="font-size: 14px">IPersistStreamInit::GetSizeMax()</span></td>
<td width="87%"><span style="font-size: 14px">恩，我算算呀......好了，总共需要500KB。</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">10</span></td>
<td width="60%"><span style="font-size: 14px">晕，你这么个小玩意居然占用这么大空间？！......好了，你可以存了。</span><br /><span style="font-size: 14px">IPersistStreamInit::Save()</span></td>
<td width="87%"><span style="font-size: 14px">谢谢，我已经存好了。</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">11</span></td>
<td width="60%"><span style="font-size: 14px">恩。拜拜了您那。(注11)</span><br /><span style="font-size: 14px">IPersistStreamInit::Release()；IUnknown::Release()</span></td>
<td width="87%"><span style="font-size: 14px">执行析构函数，删除对象。</span></td></tr>
<tr>
<td width="3%"><span style="font-size: 14px">12</span></td>
<td width="60%"><span style="font-size: 14px">我自己也该退出了......</span><br /><span style="font-size: 14px">PostQuitMessage()</span></td>
<td width="87%">&nbsp;</td></tr></tbody></table>
<p><span style="font-size: 14px">　　容器（或者说客户端）就是这样和组件进行对话，协商调用的。如果组件甲实现了 IA 接口，那么容器就会使用它，如果组件乙没有提供 IA 接口，但是它提供了 IB 接口，那么容器就会调用 IB 接口的函数......如此，容器程序根本就不需要知道组件到底是干什么的，组件到底是用什么语言开发的，组件的磁盘位置到底在哪里，它都可以正常运行。太奇妙了！太精彩了！怎一个&#8220;爽&#8221;字了得！</span><br /><br /><span style="font-size: 14px"><strong>八、小结</strong></span><br /><span style="font-size: 14px">　　第二回中，介绍了两个非常重要的概念：CLSID 和 Interface。由于全篇都是概念描述而没有示例程序相配合，可能读者的理解还不太深入、不彻底。别着急，我们马上就要进入到组件程序设计阶段了，到那个时候，你根据具体的程序代码，再回过头来再次阅读本回文章，没读懂？哦......再读！慢慢地您老人家就懂了:-)</span><br /><br /><span style="font-size: 14px">留作业啦......</span><br /><span style="font-size: 14px">1、IDispatch 接口的 IID 是多少？（哎~~~ 笨笨，在源程序中，用鼠标右键执行Go to definition 呀）</span><br /><span style="font-size: 14px">2、IPicture 接口有几个函数？功能是什么？（别玩了！你多大了？想不想在程序中显示 JPG 图像呀，看 MSDN 去）</span><br /><span style="font-size: 14px">　　想知道为什么COM函数总是返回 HRESULT 吗？想知道如何使用 BSTR、VARIANT 吗？想知道 COM 中应该如何使用内存吗？想知道如何使用 UNICODE 吗？......恩~~~，我现在不能告诉你，我现在告诉你，怕你印象不深！且听下回分解......</span></p>
<p>&nbsp;</p>
<hr />

<p>&nbsp;</p>
<p><span style="font-size: 14px">注1：CLSID = Class ID 上回书已经介绍了把CLSID写入复合文件的函数：WriteClassStg()、IStorage::SetClass()。</span><br /><span style="font-size: 14px">注2：GUID 全局唯一标示符，CLSID/IID 其实是借用了GUID的概念。</span><br /><span style="font-size: 14px">注3：ProgID = Program ID，等价于 CLSID, 是用字符串表示的。</span><br /><span style="font-size: 14px">注4：注册表子键 ProgID 和 VersionIndependentProgID 分别表示真正的 ProgID 和版本无关的 ProgID。比如在我计算机上安装的 Excel，它的 ProgID = "Excel.Application.9"，而 VersionIndependentProgID = "Excel.Application"。</span><br /><span style="font-size: 14px">注5：COM 组件的内存管理，见后续的文章。</span><br /><span style="font-size: 14px">注6：Interface = 接口，以前微软不叫它接口，而叫协议Protocol。其实我 到认为这个词更贴切一些。</span><br /><span style="font-size: 14px">注7：IUnknown 这个名字起的好，居然叫&#8220;我不知道&#8221;:-)，它的 IID 叫 IID_IUnknown，如果用注册表样式表示，那么它的值是{00000000-0000-0000-C000-000000000046}。</span><br /><span style="font-size: 14px">注8：TLB是由一个描述接口的文件 IDL 经过编译产生的。IDL 的说明，见后续的文章吧。</span><br /><span style="font-size: 14px">注9：IPersistStorage 是用复合文件的存储(Storage)功能来保存/读取数据用的一个接口。</span><br /><span style="font-size: 14px">注10：IPersistStreamInit 是用复合文件的流(Stream)功能来保存/读取数据用的一个接口。</span><br /><span style="font-size: 14px">注11：拜拜了您那 = 英语北京话，再见。</span></p><img src ="http://www.cppblog.com/jackdongy/aggbug/193442.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-17 22:33 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/17/193442.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>COM组件设计与应用（一）——起源及复合文件 </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/17/193440.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Wed, 17 Oct 2012 14:23:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/17/193440.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193440.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/17/193440.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193440.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193440.html</trackback:ping><description><![CDATA[<p><span style="font-size: 14px"><strong><span style="font-size: 14px">本文摘自：<a href="http://blog.vckbase.com/teacheryang/archive/2005/06/27/8883.html">http://blog.vckbase.com/teacheryang/archive/2005/06/27/8883.html</a></span><br /></strong></span></p>
<p><span style="font-size: 14px"><strong>一、前言</strong></span><br /><span style="font-size: 14px">　　公元一九九五年某个夜黑风高的晚上，我的一位老师跟我说：&#8220;小杨呀，以后写程序就和搭积木一样啦。你赶快学习一些OLE的技术吧......&#8221;，当时我心里就寻思 ：&#8220;开什么玩笑？搭积木方式写程序？再过100年吧......&#8221;，但作为一名听话的好学生，我开始在书店里&#8220;踅摸&#8221;（注1）有关OLE的书籍（注2）。功夫不负有心人，终于买到了我的第一本COM书《OLE2 高级编程技术》，这本800多页的大布头花费了我1/5的月工资呀......于是开始日夜耕读.....</span><br /><span style="font-size: 14px">功夫不负有心人，我坚持读完了全部著作，感想是：这本书，在说什么呐？</span><br /><span style="font-size: 14px">功夫不负有心人，我又读完了一遍大布头，感想是：咳~~~，没懂！</span><br /><span style="font-size: 14px">功夫不负有心人，我再，我再,我再读 ... 感想是：哦~~~，读懂了一点点啦，哈哈哈。</span><br /><span style="font-size: 14px">...... ......</span><br /><span style="font-size: 14px">功夫不负有心人，我终于，我终于懂了。</span><br /><span style="font-size: 14px">800页的书对现在的我来说，其实也就10几页有用。到这时候才体会出什么叫&#8220;书越读越薄&#8221;的道理了。到后来，能买到的书也多了，上网也更方便更便宜了......</span><br /><span style="font-size: 14px">　　为了让VCKBASE上的朋友，不再经历我曾经的痛苦、不再重蹈我&#8220;无头苍蝇&#8221;般探索的艰辛、为了VCKBASE的蓬勃发展、为了中国软件事业的腾飞（糟糕，吹的太也高了）......我打算节约一些在 BBS 上赚分的时间，写个系列论文，就叫&#8220;COM组件设计与应用&#8221;吧。今天是第一部分&#8212;&#8212;起源。</span><br /><br /><span style="font-size: 14px"><strong>二、文件的存储</strong></span><br /><span style="font-size: 14px">　　传说350年前，牛顿被苹果砸到了头，于是发现了万有引力。但到了二十一世纪的现在，任何一个技术的发明和发展，已经不再依靠圣人灵光的一闪。技术的进步转而是被社会的需求、商业的利益、竞争的压力、行业的渗透等推动的。微软在Windows平台上的组件技术也不例外，它的发明，有其必然因素。什么是这个因素那？答案是&#8212;&#8212;文件的存储。</span><br /><span style="font-size: 14px">　　打开记事本程序，输入了一篇文章后，保存。&#8212;&#8212;这样的文件叫&#8220;非结构化文件&#8221;；</span><br /><span style="font-size: 14px">　　打开电子表格程序，输入一个班的学生姓名和考试成绩，保存。&#8212;&#8212;这样的文件叫&#8220;标准结构化文件&#8221;；</span><br /><span style="font-size: 14px">　　在我们写的程序中，需要把特定的数据按照一定的结构和顺序写到文件中保存。&#8212;&#8212;这样的文件叫&#8220;自定义结构化文件&#8221;；（比如 *.bmp 文件）</span><br /><span style="font-size: 14px">　　以上三种类型的文件，大家都见的多了。那么文件存储就依靠上述的方式能满足所有的应用需求吗？恩~~~，至少从计算机发明后的50多年来，一直是够用的了。嘿嘿，下面看看商业利益的推动作用，对文件 的存储形式产生了什么变化吧。30岁以上的朋友，我估计以前都使用过以下几个著名的软件：WordStar（独霸DOS下的英文编辑软件），WPS（裘伯君写的中文编辑软件，据说当年的市场占有率高达90%，各种计算机培训班的必修课程），LOTUS-123（莲花公司出品的电子表格软件）......</span><br /><span style="font-size: 14px">微软在成功地推出 Windows 3.1 后，开始垂涎桌面办公自动化软件领域。微软的 OFFICE 开发部门，各小组分别独立地开发了 WORD 和 EXCEL 等软件，并采用&#8220;自定义结构&#8221;方式，对文件进行存储。在激烈的市场竞争下，为了打败竞争对手，微软自然地产生了一个念头------如果我能在 WORD 程序中嵌入 EXCEL，那么用户在购买了我 WORD 软件的情况下，不就没有必要再买 LOTUS-123 了吗？！&#8220;恶毒&#8221;（中国微软的同志们看到了这个词，不要激动，我是加了引号的呀）的计划产生后，他们开始了实施工作，这就是 COM 的前身 OLE 的起源（注3）。但立刻就遇到了一个严重的技术问题：需要把 WORD 产生的 DOC 文件和 EXCEL 产生的 XLS 文件保存在一起。</span></p>
<table style="width: 100%" cellspacing="1" border="1">
<tbody>
<tr>
<td width="33%">
<p align="center"><span style="font-size: 14px">方案</span></p></td>
<td width="31%">
<p align="center"><span style="font-size: 14px">优点</span></p></td>
<td width="103%">
<p align="center"><span style="font-size: 14px">缺点</span></p></td></tr>
<tr>
<td width="33%"><span style="font-size: 14px">建立一个子目录，把 DOC、XLS 存储在这同一个子目录中。</span></td>
<td width="31%"><span style="font-size: 14px">数据隔离性好，WORD 不用了解 EXCEL 的存储结构；容易扩展。</span></td>
<td width="103%"><span style="font-size: 14px">结构太松散，容易造成数据的损坏或丢失。</span><br /><span style="font-size: 14px">不易携带。</span></td></tr>
<tr>
<td width="33%"><span style="font-size: 14px">修改文件存储结构，在DOC结构基础上扩展出包容 XLS 的结构。</span></td>
<td width="31%"><span style="font-size: 14px">结构紧密，容易携带和统一管理。</span></td>
<td width="103%"><span style="font-size: 14px">WORD 的开发人员需要通晓 EXCEL 的存储格式；缺少扩展性，总不能新加一个类型就扩展一下结构吧？！</span></td></tr></tbody></table>
<p><span style="font-size: 14px">　　以上两个方案，都有严重的缺陷，怎么解决那？如果能有一个新方案，能够合并前两个方案的优点，消灭缺点，该多好呀......微软是作磁盘操作系统起家的，于是很自然地他们提出了一个非常完美的设计方案，那就是把磁盘文件的管理方式移植到文件中了------复合文件，俗称&#8220;文件中的文件系统&#8221;。连微软当年都没有想到，就这么一个简单的想法，居然最后就演变出了 COM 组件程序设计的方法。可以说，复合文件是 COM 的基石。下图是磁盘文件组织方式与复合文件组织方式的类比图：</span></p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2011/325507/2011082019394956.jpg" /><br /><span style="font-size: 14px">图一、左侧表示一个磁盘下的文件组织方式，右侧表示一个复合文件内部的数据组织方式。</span><br /><br /><span style="font-size: 14px"><strong>三、复合文件的特点</strong> <br />　　1、</span><span style="font-size: 14px">复合文件的内部是使用指针构造的一棵树进行管理的。编写程序的时候要注意，由于使用的是单向指针，因此当做定位操作的时候，向后定位比向前定位要快；<br />　　2、</span><span style="font-size: 14px">复合文件中的&#8220;流对象&#8221;，是真正保存数据的空间。它的存储单位为512字节。也就是说，即使你在流中只保存了一个字节的数据，它也要占据512字节的文件空间。啊~~~，这也太浪费了呀？不浪费！因为文件保存在磁盘上，即使一个字节也还要占用一个&#8220;簇&#8221;的空间那；<br />　　3、</span><span style="font-size: 14px">不同的进程，或同一个进程的不同线程可以同时访问一个复合文件的不同部分而互不干扰； <br />　　4、</span><span style="font-size: 14px">大家都有这样的体会，当需要往一个文件中插入一个字节的话，需要对整个文件进行操作，非常烦琐并且效率低下。而复合文件则提供了非常方便的&#8220;增量访问&#8221;能力；<br /></span><span style="font-size: 14px">　　5、当频繁地删除文件，复制文件后，磁盘空间会变的很零碎，需要使用磁盘整理工具进行重新整合。和磁盘管理非常相似，复合文件也会产生这个问题，在适当的时候也需要整理，但比较简单，只要调用一个函数就可以完成了。<br /></span></p>
<p><span style="font-size: 14px"><strong>四、浏览复合文件</strong></span><br /><span style="font-size: 14px">　　VC6.0 附带了一个工具软件&#8220;复合文件浏览器&#8221;，文件名是&#8220;vc目录\Common\Tools\DFView.exe&#8221;。为了方便使用该程序，可以把它加到工具(tools)菜单中。方法是：Tools\Customize...\Tools卡片中增加新的项目。运行 DFView.exe，就可以打开一个复合文件进行观察了（注4）。但奇怪的是，在 Microsoft Visual Studio .NET 2003 中，我反而找不到这个工具程序了,汗！不过这恰好提供给大家一个练习的机会，在你阅读完本篇文章并掌握了编程方法后，自己写一个&#8220;复合文件浏览编辑器&#8221;程序，又练手了，还有实用的价值。</span><br /><br /><span style="font-size: 14px"><strong>五、复合文件函数</strong></span><br /><span style="font-size: 14px">　　复合文件的函数和磁盘目录文件的操作非常类似。所有这些函数，被分为3种类型：WIN API 全局函数，存储 IStorage 接口函数，流 IStream 接口函数。什么是接口？什么是接口函数？以后的文章中再陆续介绍，这里大家只要把&#8220;接口&#8221;看成是完成一组相关操作功能的函数集合就可以了。</span></p>
<table style="width: 100%" cellspacing="1" border="1">
<tbody>
<tr>
<td width="17%">
<p align="center"><span style="font-size: 14px"><strong>WIN API 函数</strong></span></p></td>
<td width="46%">
<p align="center"><span style="font-size: 14px"><strong>功能说明</strong></span></p></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">StgCreateDocfile()</span></td>
<td width="47%"><span style="font-size: 14px">建立一个复合文件，得到根存储对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">StgOpenStorage()</span></td>
<td width="47%"><span style="font-size: 14px">打开一个复合文件，得到根存储对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">StgIsStorageFile()</span></td>
<td width="46%"><span style="font-size: 14px">判断一个文件是否是复合文件</span></td></tr>
<tr>
<td width="100%" colspan="2">
<p align="center">　</p></td></tr>
<tr>
<td width="16%">
<p align="center"><span style="font-size: 14px"><strong>IStorage 函数</strong></span></p></td>
<td width="46%">
<p align="center"><span style="font-size: 14px"><strong>功能说明</strong></span></p></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">CreateStorage()</span></td>
<td width="46%"><span style="font-size: 14px">在当前存储中建立新存储，得到子存储对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">CreateStream()</span></td>
<td width="46%"><span style="font-size: 14px">在当前存储中建立新流，得到流对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">OpenStorage()</span></td>
<td width="46%"><span style="font-size: 14px">打开子存储，得到子存储对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">OpenStream()</span></td>
<td width="46%"><span style="font-size: 14px">打开流，得到流对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">CopyTo()</span></td>
<td width="46%"><span style="font-size: 14px">复制存储下的所有对象到目标存储中，该函数可以实现&#8220;整理文件，释放碎片空间&#8221;的功能</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">MoveElementTo()</span></td>
<td width="46%"><span style="font-size: 14px">移动对象到目标存储中</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">DestoryElement()</span></td>
<td width="46%"><span style="font-size: 14px">删除对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">RenameElement()</span></td>
<td width="46%"><span style="font-size: 14px">重命名对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">EnumElements()</span></td>
<td width="46%"><span style="font-size: 14px">枚举当前存储中所有的对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">SetElementTimes()</span></td>
<td width="46%"><span style="font-size: 14px">修改对象的时间</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">SetClass()</span></td>
<td width="46%"><span style="font-size: 14px">在当前存储中建立一个特殊的流对象，用来保存CLSID（注5）</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">Stat()</span></td>
<td width="46%"><span style="font-size: 14px">取得当前存储中的系统信息</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">Release()</span></td>
<td width="46%"><span style="font-size: 14px">关闭存储对象</span></td></tr>
<tr>
<td width="62%" colspan="2">&nbsp;</td></tr>
<tr>
<td width="16%">
<p align="center"><span style="font-size: 14px"><strong>IStream 函数</strong></span></p></td>
<td width="46%">
<p align="center"><span style="font-size: 14px"><strong>功能说明</strong></span></p></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">Read()</span></td>
<td width="46%"><span style="font-size: 14px">从流中读取数据</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">Write()</span></td>
<td width="46%"><span style="font-size: 14px">向流中写入数据</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">Seek()</span></td>
<td width="46%"><span style="font-size: 14px">定位读写位置</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">SetSize()</span></td>
<td width="46%"><span style="font-size: 14px">设置流尺寸。如果预先知道大小，那么先调用这个函数，可以提高性能</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">CopyTo()</span></td>
<td width="46%"><span style="font-size: 14px">复制流数据到另一个流对象中</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">Stat()</span></td>
<td width="46%"><span style="font-size: 14px">取得当前流中的系统信息</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">Clone()</span></td>
<td width="46%"><span style="font-size: 14px">克隆一个流对象，方便程序中的不同模块操作同一个流对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">Release()</span></td>
<td width="46%"><span style="font-size: 14px">关闭流对象</span></td></tr>
<tr>
<td width="62%" colspan="2">&nbsp;</td></tr>
<tr>
<td width="16%" align="center"><span style="font-size: 14px"><strong>WIN API 补充函数</strong></span></td>
<td width="46%" align="center"><span style="font-size: 14px"><strong>功能说明</strong></span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">WriteClassStg()</span></td>
<td width="46%"><span style="font-size: 14px">写CLSID到存储中，同IStorage::SetClass()</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">ReadClassStg()</span></td>
<td width="46%"><span style="font-size: 14px">读出WriteClassStg()写入的CLSID，相当于简化调用IStorage::Stat()</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">WriteClassStm()</span></td>
<td width="46%"><span style="font-size: 14px">写CLSID到流的开始位置</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">ReadClassStm()</span></td>
<td width="46%"><span style="font-size: 14px">读出WriteClassStm()写入的CLSID</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">WriteFmtUserTypeStg()</span></td>
<td width="46%"><span style="font-size: 14px">写入用户指定的剪贴板格式和名称到存储中</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">ReadFmtUserTypeStg()</span></td>
<td width="46%"><span style="font-size: 14px">读出WriteFmtUserTypeStg()写入的信息。方便应用程序快速判断是否是它需要的格式数据。</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">CreateStreamOnHGlobal()</span></td>
<td width="46%"><span style="font-size: 14px">内存句柄 HGLOBAL 转换为流对象</span></td></tr>
<tr>
<td width="16%"><span style="font-size: 14px">GetHGlobalFromStream()</span></td>
<td width="46%"><span style="font-size: 14px">取得CreateStreamOnHGlobal()调用中使用的内存句柄</span></td></tr></tbody></table>
<p><span style="font-size: 14px">　　为了让大家快速地浏览和掌握基本方法，上面所列表的函数并不是全部，我省略了&#8220;事务&#8221;函数和未实现函数部分。更全面的介绍，请阅读 MSDN。</span><br /><span style="font-size: 14px">下面程序片段，演示了一些基本函数功能和调用方法。 </span><br /><span style="font-size: 14px">示例一：建立一个复合文件，并在其下建立一个子存储，在该子存储中再建立一个流，写入数据。<br /></span></p>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8063726#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/wangqiulin123456/article/details/8063726#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8063726#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/wangqiulin123456/article/details/8063726#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="keyword">void</span><span>&nbsp;SampleCreateDoc()&nbsp;&nbsp;</span></li><li><span>{&nbsp;&nbsp;</span></li><li class="alt"><span>　　::CoInitialize(NULL);&nbsp;　　<span class="comment">//&nbsp;COM&nbsp;初始化</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　　　　　　　　　　　　　&nbsp;<span class="comment">//&nbsp;如果是MFC程序，可以使用AfxOleInit()替代</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　<span class="datatypes">HRESULT</span><span>&nbsp;hr;&nbsp;　&nbsp;</span><span class="comment">//&nbsp;函数执行返回值</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　IStorage&nbsp;*pStg&nbsp;=&nbsp;NULL;&nbsp;<span class="comment">//&nbsp;根存储接口指针</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　IStorage&nbsp;*pSub&nbsp;=&nbsp;NULL;&nbsp;<span class="comment">//&nbsp;子存储接口指针</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　IStream&nbsp;*pStm&nbsp;=&nbsp;NULL;&nbsp;<span class="comment">//&nbsp;流接口指针</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>　　hr&nbsp;=&nbsp;::StgCreateDocfile(&nbsp;　<span class="comment">//&nbsp;建立复合文件</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　　　　　L<span class="string">"c:\\a.stg"</span><span>,&nbsp;</span><span class="comment">//&nbsp;文件名称</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　　　　　　　STGM_CREATE&nbsp;|&nbsp;STGM_WRITE&nbsp;|&nbsp;STGM_SHARE_EXCLUSIVE,&nbsp;<span class="comment">//&nbsp;打开方式</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　　　　　0,&nbsp;<span class="comment">//&nbsp;保留参数</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　　　　　　　&amp;pStg);&nbsp;<span class="comment">//&nbsp;取得根存储接口指针</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　ASSERT(&nbsp;SUCCEEDED(hr)&nbsp;);&nbsp;<span class="comment">//&nbsp;为了突出重点，简化程序结构，所以使用了断言。</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　&nbsp;　　　　　　　　　　　　　　<span class="comment">//&nbsp;在实际的程序中则要使用条件判断和异常处理</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>　　hr&nbsp;=&nbsp;pStg-&gt;CreateStorage(&nbsp;<span class="comment">//&nbsp;建立子存储</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　　　　　L<span class="string">"SubStg"</span><span>,&nbsp;</span><span class="comment">//&nbsp;子存储名称</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　　　　　　　STGM_CREATE&nbsp;|&nbsp;STGM_WRITE&nbsp;|&nbsp;STGM_SHARE_EXCLUSIVE,&nbsp;&nbsp;</span></li><li class="alt"><span>　　　　　　　　0,0,&nbsp;&nbsp;</span></li><li><span>　　　　　　　　&amp;pSub);&nbsp;<span class="comment">//&nbsp;取得子存储接口指针</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　ASSERT(&nbsp;SUCCEEDED(hr)&nbsp;);&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span>　　hr&nbsp;=&nbsp;pSub-&gt;CreateStream(&nbsp;　<span class="comment">//&nbsp;建立流</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　　　　　　　L<span class="string">"Stm"</span><span>,&nbsp;</span><span class="comment">//&nbsp;流名称</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　　　　　STGM_CREATE&nbsp;|&nbsp;STGM_WRITE&nbsp;|&nbsp;STGM_SHARE_EXCLUSIVE,&nbsp;&nbsp;</span></li><li><span>　　　　　　　　0,0,&nbsp;&nbsp;</span></li><li class="alt"><span>　　　　　　　　&amp;pStm);&nbsp;<span class="comment">//&nbsp;取得流接口指针</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　ASSERT(&nbsp;SUCCEEDED(hr)&nbsp;);&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>　　hr&nbsp;=&nbsp;pStm-&gt;Write(&nbsp;<span class="comment">//&nbsp;向流中写入数据</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　　　　　<span class="string">"Hello"</span><span>,&nbsp;</span><span class="comment">//&nbsp;数据地址</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　　　　　　　5,&nbsp;<span class="comment">//&nbsp;字节长度(注意，没有写入字符串结尾的\0)</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　　　　　NULL);&nbsp;<span class="comment">//&nbsp;不需要得到实际写入的字节长度</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　ASSERT(&nbsp;SUCCEEDED(hr)&nbsp;);&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>　　<span class="keyword">if</span><span>(&nbsp;pStm&nbsp;)&nbsp;pStm-&gt;Release();&nbsp;</span><span class="comment">//&nbsp;释放流指针</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　<span class="keyword">if</span><span>(&nbsp;pSub&nbsp;)&nbsp;pSub-&gt;Release();&nbsp;</span><span class="comment">//&nbsp;释放子存储指针</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　<span class="keyword">if</span><span>(&nbsp;pStg&nbsp;)&nbsp;pStg-&gt;Release();&nbsp;</span><span class="comment">//&nbsp;释放根存储指针</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li><span>　　::CoUninitialize()&nbsp;<span class="comment">//&nbsp;COM&nbsp;释放</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　　　　　　　　<span class="comment">//&nbsp;如果使用&nbsp;AfxOleInit(),则不调用该函数</span><span>&nbsp;&nbsp;</span></span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">void SampleCreateDoc()
{
　　::CoInitialize(NULL); 　　// COM 初始化
　　　　　　　　　　　　　　 // 如果是MFC程序，可以使用AfxOleInit()替代
　　HRESULT hr; 　 // 函数执行返回值
　　IStorage *pStg = NULL; // 根存储接口指针
　　IStorage *pSub = NULL; // 子存储接口指针
　　IStream *pStm = NULL; // 流接口指针

　　hr = ::StgCreateDocfile( 　// 建立复合文件
　　　　　　　　L"c:\\a.stg", // 文件名称
　　　　　　　　STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, // 打开方式
　　　　　　　　0, // 保留参数
　　　　　　　　&amp;pStg); // 取得根存储接口指针
　　ASSERT( SUCCEEDED(hr) ); // 为了突出重点，简化程序结构，所以使用了断言。
　　 　　　　　　　　　　　　　　// 在实际的程序中则要使用条件判断和异常处理

　　hr = pStg-&gt;CreateStorage( // 建立子存储
　　　　　　　　L"SubStg", // 子存储名称
　　　　　　　　STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,
　　　　　　　　0,0,
　　　　　　　　&amp;pSub); // 取得子存储接口指针
　　ASSERT( SUCCEEDED(hr) );

　　hr = pSub-&gt;CreateStream( 　// 建立流
　　　　　　　　L"Stm", // 流名称
　　　　　　　　STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,
　　　　　　　　0,0,
　　　　　　　　&amp;pStm); // 取得流接口指针
　　ASSERT( SUCCEEDED(hr) );

　　hr = pStm-&gt;Write( // 向流中写入数据
　　　　　　　　"Hello", // 数据地址
　　　　　　　　5, // 字节长度(注意，没有写入字符串结尾的\0)
　　　　　　　　NULL); // 不需要得到实际写入的字节长度
　　ASSERT( SUCCEEDED(hr) );

　　if( pStm ) pStm-&gt;Release(); // 释放流指针
　　if( pSub ) pSub-&gt;Release(); // 释放子存储指针
　　if( pStg ) pStg-&gt;Release(); // 释放根存储指针

　　::CoUninitialize() // COM 释放
　　　　　　　　　　　// 如果使用 AfxOleInit(),则不调用该函数
}</pre><br />
<p>&nbsp;</p>
<p><img alt="" src="http://pic002.cnblogs.com/images/2011/325507/2011082019493888.jpg" /><br /><span style="font-size: 14px">图二、运行示例程序一后，使用 DFView.exe 打开观察复合文件的效果图</span><br /><br /><span style="font-size: 14px">示例二：打开一个复合文件，枚举其根存储下的所有对象。</span></p>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a title="view plain" class="ViewSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8063726#"><u><font color="#0066cc">view plain</font></u></a><a title="copy" class="CopyToClipboard" href="http://blog.csdn.net/wangqiulin123456/article/details/8063726#"><u><font color="#0066cc">copy</font></u></a><a title="print" class="PrintSource" href="http://blog.csdn.net/wangqiulin123456/article/details/8063726#"><u><font color="#0066cc">print</font></u></a><a title="?" class="About" href="http://blog.csdn.net/wangqiulin123456/article/details/8063726#"><u><font color="#0066cc">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="preprocessor">#include&nbsp;//&nbsp;ANSI、MBCS、UNICODE&nbsp;转换</span><span>&nbsp;&nbsp;</span></li><li><span class="keyword">void</span><span>&nbsp;SampleEnum()&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>{&nbsp;&nbsp;&nbsp;</span></li><li><span>　　<span class="comment">//&nbsp;假设你已经做过&nbsp;COM&nbsp;初始化了</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　<span class="datatypes">LPCTSTR</span><span>&nbsp;lpFileName&nbsp;=&nbsp;_T(&nbsp;</span><span class="string">"c:\\a.stg"</span><span>&nbsp;);&nbsp;&nbsp;</span></span></li><li><span>　　<span class="datatypes">HRESULT</span><span>&nbsp;hr;&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　IStorage&nbsp;*pStg&nbsp;=&nbsp;NULL;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span>　　USES_CONVERSION;&nbsp;<span class="comment">//&nbsp;（注6）</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　LPCOLESTR&nbsp;lpwFileName&nbsp;=&nbsp;T2COLE(&nbsp;lpFileName&nbsp;);&nbsp;<span class="comment">//&nbsp;转换T类型为宽字符</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　hr&nbsp;=&nbsp;::StgIsStorageFile(&nbsp;lpwFileName&nbsp;);&nbsp;<span class="comment">//&nbsp;是复合文件吗？</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　<span class="keyword">if</span><span>(&nbsp;FAILED(hr)&nbsp;)&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　<span class="keyword">return</span><span>;&nbsp;&nbsp;</span></span></li><li><span>　　hr&nbsp;=&nbsp;::StgOpenStorage(&nbsp;<span class="comment">//&nbsp;打开复合文件</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　　　　　lpwFileName,&nbsp;<span class="comment">//&nbsp;文件名称</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　　　　　　　NULL,&nbsp;&nbsp;</span></li><li class="alt"><span>　　　　　　　　STGM_READ&nbsp;|&nbsp;STGM_SHARE_DENY_WRITE,&nbsp;&nbsp;</span></li><li><span>　　　　　　　　0,&nbsp;&nbsp;</span></li><li class="alt"><span>　　　　　　　　0,&nbsp;&nbsp;</span></li><li><span>　　　　　　　　&amp;pStg);&nbsp;<span class="comment">//&nbsp;得到根存储接口指针</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　IEnumSTATSTG&nbsp;*pEnum=NULL;&nbsp;<span class="comment">//&nbsp;枚举器</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　hr&nbsp;=&nbsp;pStg-&gt;EnumElements(&nbsp;0,&nbsp;NULL,&nbsp;0,&nbsp;&amp;pEnum&nbsp;);&nbsp;&nbsp;</span></li><li class="alt"><span>　　ASSERT(&nbsp;SUCCEEDED(hr)&nbsp;);&nbsp;&nbsp;</span></li><li><span>　　STATSTG&nbsp;statstg;&nbsp;&nbsp;</span></li><li class="alt"><span>　　<span class="keyword">while</span><span>(&nbsp;NOERROR&nbsp;==&nbsp;pEnum-&gt;Next(&nbsp;1,&nbsp;&amp;statstg,&nbsp;NULL)&nbsp;)&nbsp;&nbsp;</span></span></li><li><span>　　{&nbsp;&nbsp;</span></li><li class="alt"><span>　　　　<span class="comment">//&nbsp;statstg.type&nbsp;保存着对象类型&nbsp;STGTY_STREAM&nbsp;或&nbsp;STGTY_STORAGE</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　　　<span class="comment">//&nbsp;statstg.pwcsName&nbsp;保存着对象名称</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　　　<span class="comment">//&nbsp;......&nbsp;还有时间，长度等很多信息。请查看&nbsp;MSDN</span><span>&nbsp;&nbsp;</span></span></li><li><span>　　　　::CoTaskMemFree(&nbsp;statstg.pwcsName&nbsp;);&nbsp;<span class="comment">//&nbsp;释放名称所使用的内存（注6）</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>　　}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li class="alt"><span>　　<span class="keyword">if</span><span>(&nbsp;pEnum&nbsp;)&nbsp;pEnum-&gt;Release();&nbsp;&nbsp;</span></span></li><li><span>　　<span class="keyword">if</span><span>(&nbsp;pStg&nbsp;)&nbsp;pStg-&gt;Release();&nbsp;&nbsp;</span></span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="cpp" style="display: none" name="code">#include // ANSI、MBCS、UNICODE 转换
void SampleEnum() 
{ 
　　// 假设你已经做过 COM 初始化了
　　LPCTSTR lpFileName = _T( "c:\\a.stg" );
　　HRESULT hr;
　　IStorage *pStg = NULL;

　　USES_CONVERSION; // （注6）
　　LPCOLESTR lpwFileName = T2COLE( lpFileName ); // 转换T类型为宽字符
　　hr = ::StgIsStorageFile( lpwFileName ); // 是复合文件吗？
　　if( FAILED(hr) )
　　　　return;
　　hr = ::StgOpenStorage( // 打开复合文件
　　　　　　　　lpwFileName, // 文件名称
　　　　　　　　NULL,
　　　　　　　　STGM_READ | STGM_SHARE_DENY_WRITE,
　　　　　　　　0,
　　　　　　　　0,
　　　　　　　　&amp;pStg); // 得到根存储接口指针
　　IEnumSTATSTG *pEnum=NULL; // 枚举器
　　hr = pStg-&gt;EnumElements( 0, NULL, 0, &amp;pEnum );
　　ASSERT( SUCCEEDED(hr) );
　　STATSTG statstg;
　　while( NOERROR == pEnum-&gt;Next( 1, &amp;statstg, NULL) )
　　{
　　　　// statstg.type 保存着对象类型 STGTY_STREAM 或 STGTY_STORAGE
　　　　// statstg.pwcsName 保存着对象名称
　　　　// ...... 还有时间，长度等很多信息。请查看 MSDN
　　　　::CoTaskMemFree( statstg.pwcsName ); // 释放名称所使用的内存（注6）
　　}

　　if( pEnum ) pEnum-&gt;Release();
　　if( pStg ) pStg-&gt;Release();
}</pre><br />
<p>&nbsp;</p>
<p><span style="font-size: 14px"><strong>六、小结</strong></span><br /><span style="font-size: 14px">　　复合文件，结构化存储，是微软组件思想的起源，在此基础上继续发展出了持续性、命名、ActiveX、对象嵌入、现场激活......一系列的新技术、新概念。因此理解</span>和掌握 复合文件是非常重要的，即使在你的程序中并没有全面使用组件技术，复合文件技术也是可以单独被应用的。祝大家学习快乐，为社会主义软件事业而奋斗:-)<br /><br />留作业啦......<br />作业1：写个小应用程序，从 MSWORD 的 doc 文件中，提取出附加信息（作者、公司......）。<br />作业2：写个全功能的&#8220;复合文件浏览编辑器&#8221;。<br /><br />注1：踅摸(xuemo)，动词，北方方言，寻找搜索的意思。<br />注2：问：为什么不上网查资料学习？<br />答：开什么国际玩笑！在那遥远的1995年代，我的500块工资，不吃不喝正好够上100小时的Internet网。<br />注3：OLE，对象的连接与嵌入。<br />注4：可以用 DFView.exe 打开 MSWORD 的 DOC 文件进行复合文件的浏览。但是该程序并没有实现国际化，不能打开中文文件名的复合文件，因此需要改名后才能浏览。<br />注5：CLSID，在后续的文章中介绍。<br />注6：关于 COM 中内存使用的问题，在后续的文章中介绍。</p><img src ="http://www.cppblog.com/jackdongy/aggbug/193440.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-17 22:23 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/17/193440.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入研究Windows内部原理绝对经典的资料 </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/17/193439.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Wed, 17 Oct 2012 14:21:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/17/193439.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193439.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/17/193439.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193439.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193439.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （为了方便大家下，我打包了放在一下地址： 
<p><span style="white-space: pre"></span>1-6：<a href="http://download.csdn.net/detail/wangqiulin123456/4601530"></a><a href="http://download.csdn.net/detail/wangqiulin123456/4601509"></a><a href="http://download.csdn.net/detail/wangqiulin123456/4601530">http://download.csdn.net/detail/wangqiulin123456/4601530</a></p>
<p><span style="white-space: pre"></span>7-12：<a href="http://download.csdn.net/detail/wangqiulin123456/4601508">http://download.csdn.net/detail/wangqiulin123456/4601508</a></p>
<p><span style="white-space: pre"></span>13-16：<a href="http://download.csdn.net/detail/wangqiulin123456/4601493">http://download.csdn.net/detail/wangqiulin123456/4601493</a>）</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 来自微软的权威技术专家将向您解释Windows操作系统的内部工作原理，从系统架构的大局观出发，逐步展示进程、线程、安全机制、内存管理和存储管理等子系统的工作方式。通过对底层原理的揭示，使您更进一步的理解Windows上各类程序的工作方式和如何进行错误诊断及性能优化。 本次课程的内容编排得到了国内知名技术作家，《Windows Internals》一书的中文译者，潘爱民先生的大力支持，同时TechNet也邀请到了众多微软一线技术专家进行讲解。这是一个为IT专业人员量身定做的Windows内部知识课程，在介绍原理的同时，也紧密地围绕实际案例和常见的故障进行分析点评。这是一个系统的学习Windows底层工作机制的好机会，课程内容深入浅出，精彩纷呈，绝对不容错过。</p>
<p>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032327394&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之一：Windows的昨天、今天和明天</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：潘爱民</strong><br /><em>2007年01月25日 14:00-15:30<br />Level: 300</em></p>
<p>著名技术作家、微软亚洲研究院研究员潘爱民老师将在这次课程中跟听众分享Windows的发展历程和技术精萃，描绘操作系统的体系架构、Vista的内核变更以及今后版本Windows的发展趋势。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032327403&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之二：Windows体系结构-从操作系统的角度</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：张银奎</strong><br /><em>2007年01月26日 14:00-15:30<br />Level: 400</em></p>
<p>操作系统是计算机系统的灵魂和管理中心，也是软件系统中最复杂的部分。本讲座将以生动的讲解和丰富的演示带您领略Windows操作系统的核心架构和主要组件，包括HAL、内核、执行体、系统进程（IDLE、SMSS.EXE、WinLogon.EXE）和Windows子系统（CSRSS.EXE、WIN32K.SYS以及子系统DLL）等。并讨论中断管理、对象管理、和异常分发等系统机制和实现这些机制的基本数据结构。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032328792&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之三：Windows体系结构-从应用程序的角度</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：曾震宇</strong><br /><em>2007年01月29日 14:00-15:30<br />Level: 400</em></p>
<p>从服务器软件到Office办公应用，从联网游戏到即时消息，不管这些应用的复杂程度如何，他们都是一个个在操作系统控制和管理之下的可执行程序。本次课程邀请微软全球技术中心专家级工程师，为各位讲解一个程序是如何经历从启动、分配资源、运行、结束这一连串的过程，并且介绍其中的重要概念和排错诊断技巧。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032328796&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之四：Windows操作系统中的重要基本概念</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：高宇</strong><br /><em>2007年01月30日 14:00-15:30<br />Level: 400</em></p>
<p>进程、线程、资源分配、内存管理、Win32 API、服务、安全，这些是工作中常常提及但是又无法深入理解的神秘概念。在这次课程中，讲师将介绍Windows中最常见与最重要的一些基本概念. 使大家能够顺利地参与到本系列之后的讨论中去。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032328800&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之五：Windows Sysinternals工具集介绍</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：彭爱华</strong><br /><em>2007年01月31日 14:00-15:30<br />Level: 400</em></p>
<p>Sysinternals Suite(Windows Sysinternals工具集)包含一系列免费的系统工具，其中有大名鼎鼎的Process Explorer、FileMon、RegMon等(在Windows Vista下，FileMon和RegMon则被Process Monitor所代替)，如果把系统管理员比喻成战士的话，那么Sysinternals Suite就是我们手中的良兵利器。熟悉和掌握这些工具，并且对Windows的体系有一定的了解，将大幅度的提高日常的诊断和排错能力。本课程将以任务驱动的模式，介绍几个经典的应用案例，来介绍Sysinternals Suite的强大功能。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032329739&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之六：Vista新特性底层揭秘</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：彭爱华</strong><br /><em>2007年02月01日 14:00-15:30<br />Level: 400</em></p>
<p>Windows Vista绝非仅仅是具有诸如3D切换、毛玻璃等炫目的界面效果，花钱购买了Windows Vista，而仅仅为了使用其界面效果，难免有点&#8220;买椟还珠&#8221;的感觉。实际上Windows Vista值得称道的是它具有很多全新的安全特性，例如用户帐户控制、IE保护模式、服务隔离和Windows资源保护等等。有了这些全新的安全特性，我们就可以在相当的程度上摆脱恶意软件的滋扰。Windows之父Jim Allchin曾经说过不要满足于只知道How-to、小技巧之类的知识，而是应该深入底层了解其内部原理。只有了解了这些安全特性的内在原理，才能真正了解Windows Vista是怎样精心替我们解决安全问题的，才能真正利用好这些安全特性。本课程将以UAC、IE保护模式为例，介绍这些安全特性的内在原理。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032329741&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之七：开机引导过程</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：张银奎</strong><br /><em>2007年02月02日 14:00-15:30<br />Level: 400</em></p>
<p>Windows的启动是一个复杂的过程，从加载器（NTLDR或WinLoad）开始工作到Windows子系统准备就绪，中间经历了若干个复杂的步骤，包括内核和执行体的初始化，创建系统进程和线程，对象管理器初始化基本对象，I/O管理器枚举设备并安装驱动程序，启动SMSS和WinLogon进程，运行Windows子系统进程。本讲座将解析以上各个步骤的来龙去脉，并探讨驱动的加载顺序、用户登录(Gina，SAM数据库，域身份验证)、系统服务程序、Shell等等启动过程密切相关的问题。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032329742&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之八：内存管理揭秘</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：徐晓卓</strong><br /><em>2007年02月05日 14:00-15:30<br />Level: 400</em></p>
<p>工欲善其事，必先利其器。如果能够深入了解Windows内存管理机制，那么无论在系统配置还是在故障排错方面，都能让我们直达根源，起到事半功倍的效果。本课程将全面介绍Windows内部内存管理机制，包括寻址原理、进程内存空间分布、核心态用户态内存管理原理以及虚拟内存管理原理等。同时将讨论应用程序中内存的使用问题，内存泄露的发生以及排除方法。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032329900&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之九：Windows的安全机制和实现</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：张瞰</strong><br /><em>2007年02月06日 14:00-15:30<br />Level: 400</em></p>
<p>Windows如何从操作系统层面保障所有程序的安全？访问控制列表，令牌、系统帐号、SAM数据库、GINA、交互式登陆、COM+，这些概念如何组成一个完整的Windows安全平台？这次课程将解答您这方面的疑问。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032329901&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之十：驱动和硬件的管理</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：张伟伟</strong><br /><em>2007年02月07日 14:00-15:30<br />Level: 400</em></p>
<p>驱动程序如何被Windows识别、加载和管理？随着Windows的发展，驱动程序的类型和作用经历了怎么样的变化？inf文件在驱动安装过程中起到了怎样的作用？Vista的驱动程序有哪些新变化？如果这方面的问题一直困扰着您，那这次课程是绝对不容错过的。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032330155&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之十一：存储和文件系统</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：高宇</strong><br /><em>2007年02月08日 14:00-15:30<br />Level: 400</em></p>
<p>课程将在宏观上简要介绍Windows的存储体系, 观察磁盘上的扇区怎样变成用户眼中的文件. 然后深入观察磁盘上的数据结构. 在分析枯燥的16进制数据的同时, 也会和大家讨论一些有趣和常见的错误现象。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032330174&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之十二：网络协议的构成和实现</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：高宇</strong><br /><em>2007年02月09日 14:00-15:30<br />Level: 400</em></p>
<p>课程内容包括Windows中的网络组件， 网络协议，重要网络服务的实现与特点。 Windows中的TCP/IP以及其上的服务将是本节的主要部分。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032331994&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之十三：如何诊断和调试蓝屏错误</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：张银奎</strong><br /><em>2007年02月12日 14:00-15:30<br />Level: 400</em></p>
<p>当Windows操作系统检测到来源于系统硬件或内核代码的严重错误时，为了避免继续运行可能导致的更严重后果，Windows会通过蓝屏报告错误并让整个系统以可控的方式停止运行（BSOD）。Windows提供了多种方法来诊断和调试蓝屏错误，包括故障转储文件（DUMP）、内核调试以及通过驱动程序注册并接收错误信息。本讲座将解释蓝屏产生的原因和过程，引发蓝屏错误典型的根源，并向您介绍使用WinDbg分析DUMP文件的高级技巧。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032334263&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之十四：用户模式的程序排错(上)</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：喻勇</strong><br /><em>2007年03月09日 14:00-15:30<br />Level: 400</em></p>
<p>&#8220;该程序执行了非法操作，即将被关闭&#8221;，这是我们耳熟能详的出错报告。程序为什么会崩溃？如何发现崩溃的原因并进行解决？在全面了解了Windows的体系结构和程序运行方式后，我们将进一步介绍访问越界、缓冲溢出、内存泄露等故障的原理，并理论联系实际，带领大家使用调试工具来解决一些常见的问题。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032335232&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之十五：用户模式的程序排错(下)</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：喻勇</strong><br /><em>2007年03月13日 14:00-15:30<br />Level: 400</em></p>
<p>&#8220;该程序执行了非法操作，即将被关闭&#8221;，这是我们耳熟能详的出错报告。程序为什么会崩溃？如何发现崩溃的原因并进行解决？在全面了解了Windows的体系结构和程序运行方式后，我们将进一步介绍访问越界、缓冲溢出、内存泄露等故障的原理，并理论联系实际，带领大家使用调试工具来解决一些常见的问题。</p></td></tr></tbody></table>
<table style="padding-bottom: 20px" cellspacing="0" cellpadding="0" width="98%" border="0">
<tbody>
<tr>
<td style="padding-bottom: 10px" colspan="2" align="left"><a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032335843&amp;Culture=zh-CN"><strong>深入研究Windows内部原理系列之十六：使您成为Windows专家的一些学习习惯</strong></a></td></tr>
<tr>
<td valign="top" align="left">&nbsp;</td>
<td style="padding-left: 12px" valign="top" width="100%" align="left">
<p><strong>讲师信息：喻勇</strong><br /><em>2007年03月15日 14:00-15:30<br />Level: 200</em></p>
<p>在系统的学习了前面的Windows内部原理之后，大家一定对这么多的技术细节和深入分析大呼过瘾，也一定想尽快地掌握这些知识。如何学好Windows？如何成为一个技术过硬的IT专业人士？作为这个技术大餐的最后一讲，讲师将跟大家分享一些学习的心得，如何找对突破方向和知识重点，循序渐进的进行系统的技术学习。同时也会指出常见的一些学习弊病和改进方法。最后，老师将推荐一些重要的书籍和学习资料供听众参考。</p></td></tr></tbody></table></p><img src ="http://www.cppblog.com/jackdongy/aggbug/193439.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-17 22:21 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/17/193439.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>COM编程入门不得不看的文章 ：第二部分 深入COM服务器 </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/17/193438.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Wed, 17 Oct 2012 14:15:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/17/193438.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193438.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/17/193438.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193438.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193438.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://blog.csdn.net/wangqiulin123456/article/details/8072545目录(?)[-] 走马观花看COM服务器服务器生命其管理实现接口，从IUnknown开始构造器和析构器AddRef() 和 Release()QueryInterface()深入CoCreateInstance()COM服务器注册创建COM对象&#8212;&#8212;类...&nbsp;&nbsp;<a href='http://www.cppblog.com/jackdongy/archive/2012/10/17/193438.html'>阅读全文</a><img src ="http://www.cppblog.com/jackdongy/aggbug/193438.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-17 22:15 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/17/193438.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>COM编程入门不得不看的文章 ：第一部分 什么是COM，如何使用COM </title><link>http://www.cppblog.com/jackdongy/archive/2012/10/17/193437.html</link><dc:creator>jackdong</dc:creator><author>jackdong</author><pubDate>Wed, 17 Oct 2012 14:13:00 GMT</pubDate><guid>http://www.cppblog.com/jackdongy/archive/2012/10/17/193437.html</guid><wfw:comment>http://www.cppblog.com/jackdongy/comments/193437.html</wfw:comment><comments>http://www.cppblog.com/jackdongy/archive/2012/10/17/193437.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jackdongy/comments/commentRss/193437.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jackdongy/services/trackbacks/193437.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://blog.csdn.net/wangqiulin123456/article/details/8026270目录(?)[-] COM到底是什么基本元素的定义创建一个新对象删除对象创建COM对象删除COM对象接下来将详细讨论IUnknown接口基本接口&#8213;&#8213;IUnknown仔细做好串处理WideCharToMultiByte()wcstombs...&nbsp;&nbsp;<a href='http://www.cppblog.com/jackdongy/archive/2012/10/17/193437.html'>阅读全文</a><img src ="http://www.cppblog.com/jackdongy/aggbug/193437.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jackdongy/" target="_blank">jackdong</a> 2012-10-17 22:13 <a href="http://www.cppblog.com/jackdongy/archive/2012/10/17/193437.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>