COM 编程指南提纲.pdf
《COM 编程指南提纲.pdf》由会员分享,可在线阅读,更多相关《COM 编程指南提纲.pdf(179页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、关系您的软件工程技术实践关系您的软件工程技术实践COM编程指南此文档版权所有:刘晓华此文档版权所有:刘晓华 提纲相关知识COM基础COM开发提高篇相关知识调用约定输出使用回调函数DLL函数指针虚函数表内存布局C+对象内存布局国际化与编码BSTR类型字符串处理DLL的组成动态链接库代码初始化函数自定义函数数据局部数据全局数据输出表数据函数资源DLL初始化函数BOOL APIENTRY DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)switch(ul_reason_for_call)case DLL_PROCE
2、SS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;return TRUE;DLL自定义代码int Multiply(int i,int j)return i*j;函数Cdll0:Cdll0()return;int Cdll0:Foo(void)return 43;类DLL数据.h 文件中extern DLL0_API int ndll0;.cpp文件中int ndll0=0;全局数据静态变量函数局部变量局部数据DLL输出表_declspec(dllexport)模板定义文件
3、 def可指定序号输出方法输出函数输出类输出数据输出示例查看DLL 输出表执行VS 命令行工具Dumpbin命令Dll文件选项例如 dumpbin dll0.dll/示例:创建简单的DLL创建Win32 DLL创建头文件声明输出定义输出函数和数据使用DLL将DLL复制到客户端可执行文件目录将LIB库复制到某个目录链接到lib库声明引入的函数变量类使用静态链接将DLL复制到客户端可执行文件目录声明函数指针类型加载DLL库获得函数指针通过函数指针调用释放DLL库动态加载静态链接到LIB库使用编译指令#pragmacomment(lib,“dll0.lib)项目属性对话框中指定静态链接时声明引入_d
4、eclspec(dllimport)引入数据extern _declspec(dllimport)int ndll0;引入函数_declspec(dllimport)int fndll0(void);引入类class _declspec(dllimport)Cdll0 public:Cdll0(void);/TODO:add your methods here.int Foo(void);技巧:为输出引入准备一个头文件头文件中声明条件宏#ifdef DLL0_EXPORTS#define DLL0_API _declspec(dllexport)#else#define DLL0_API _d
5、eclspec(dllimport)#endifDLL项目中定义宏DLL0_EXPORT客户程序#include stdafx.h#include dll0.hint _tmain(int argc,_TCHAR*argv)int ret=fndll0();Cdll0 c;printf(%dn,c.Foo();printf(3*5=%dn,Multiply(3,5);return ret;C+项目中指定宏DLL动态加载#include stdafx.htypedef int(*LPFNMLTPLY)(int,int);int _tmain(int argc,_TCHAR*argv)HINSTA
6、NCE hClcltr=LoadLibrary(_T(dll0.dll);LPFNMLTPLY lpfnMuliply;lpfnMuliply=(LPFNMLTPLY)GetProcAddress(hClcltr,Multiply);printf(3*5=%dn,lpfnMuliply(3,5);FreeLibrary(hClcltr);return 0;按序号访问DLL函数声明合适的指针类型用MAKEINTRESOURCEA宏将序号转换为字符串要点#include stdafx.htypedef int(*LPFNMLTPLY)(int,int);int _tmain(int argc,_T
7、CHAR*argv)HINSTANCE hClcltr=LoadLibrary(_T(dll0.dll);LPFNMLTPLY lpfnMuliply;lpfnMuliply=(LPFNMLTPLY)GetProcAddress(hClcltr,MAKEINTRESOURCEA(1);printf(3*5=%dn,lpfnMuliply(3,5);FreeLibrary(hClcltr);return 0;示例访问DLL数据声明合适的指针类型指向DLL中的输出数据还是用:GetProcAddress步骤#include stdafx.hint _tmain(int argc,_TCHAR*ar
8、gv)HINSTANCE hClcltr=LoadLibrary(_T(dll0.dll);LPFNMLTPLY lpfnMuliply;int*pndll0=(int*)GetProcAddress(hClcltr,?ndll03HA);printf(%dn,(*pndll0);FreeLibrary(hClcltr);return 0;示例调用约定含义参数如何传递结果如何返回函数名如何修饰C C 调用约定调用约定(_(_CDECLCDECL)int _cdecl sumExample(int a,int b);C/C+缺省调用约定参数从右到左压栈调用者清理堆栈sumExample_ sum
9、Example当有 extern“C”编译后函数名加前缀 _ 支持变参标准调用约定标准调用约定(_(_STDCALLSTDCALL)int _stdcall sumExample(int a,int b);示例参数从右到左压栈函数清理堆栈sumExample_sumExample8当有 extern“C”编译后函数名加前缀 _ 函数名后加及堆栈字节数不支持变参 系统API的调用约定_FASTCALLFASTCALL调用约定调用约定int _fastcall sumExample(int a,int b);示例前两个参数分别放入ECX和EDX,其余参数从右到左压栈函数清理堆栈sumExample
10、_sumExample8当有 extern“C”编译后函数名加前缀 _ 函数名后加及堆栈字节数实际效果和stdcallstdcall差不多差不多THISCALLTHISCALL调用约定调用约定struct CSumint sum(int a,int b)return a+b;C+成员函数的调用约定参数从右到左压栈this 放到寄存器 ECX如果是变参,则调用规则改为c的调用约定,调用方清理堆栈函数清理堆栈CSum:sum?sumCSumQAEHHHZ编译后函数名加上了类名等修饰符EXTERN“C“有extern C DLL0_API int_stdcall fndll1(void);_fndl
11、l1无DLL0_API int _stdcallfndll1(void);?fndll1YGHXZ你需要了解的调用约定调用约定依赖于编译器的实现静态链接时,用同样的声明头文件即可当动态加载DLL时,声明函数指针类型时声明一致的调用约定回调函数通过函数指针调用的函数声明typedef int(*LPOP)(int,int);DLL0_API int fndll4(LPOP,int,int);实现int fndll4(LPOP func,int i,int j)if(func=NULL)return-1;return func(i,j);客户端传入有效的函数指针参数int add(int i,in
12、t j)return i+j;int _tmain(int argc,_TCHAR*argv)printf(3 op 5=%dn,fndll4(add,3,5);return 0;类成员作为回调函数问题由于this指针的作用,使得将一个CALLBACK型的成员函数作为回调函数安装时就会因为隐含的this指针使得函数参数个数不匹配,从而导致回调函数安装失败解决方案之一:使用静态成员函数静态成员函数不使用this指针作为隐含参数,这样就可以作为回调函数示例C+对象内存布局取决于编译器的具体实现C+对象大小取决于一个类及其基类的成员变量每个派生类的实例都包含了一份完整的基类实例数据实现虚函数引入的隐
13、藏成员实现虚继承引入的隐藏成员简单C+对象类声明class B public:int bm1;protected:int bm2;private:int bm3;static int bsm;void bf();static void bsf();typedef void*bpv;struct N ;布局示意单继承派生对象内存布局类声明class C public:int c1;void cf();class D:public C public:int d1;void df();布局示意多继承派生对象内存布局类声明class C public:int c1;void cf();class E
14、public:int e1;void ef();class F:public C,public E public:int f1;void ff();布局示意虚继承派生对象内存布局类声明class C public:int c1;void cf();class G:public virtual C int g1;void gf();class H:public virtual C public:int h1;void hf();class I:public virtual G,public virtual H public:int i1;void _if();布局示意多态:C+虚函数#inclu
15、de stdafx.hclass Apublic:void Foo1()printf(f1n);virtual void Foo2()printf(A:f2n);class B:public Apublic:virtual void Foo2()printf(B:f2n);int _tmain(int argc,_TCHAR*argv)B b;b.Foo1();A*pA=&b;pA-Foo2();return 0;一个函数指针,究竟执行哪个函数取决于调用对象带虚函数的C+对象内存布局类声明class P public:int p1;void pf();/newvirtual void pvf(
16、);/new;布局示意虚函数重载的C+对象内存布局类声明class P public:int p1;void pf();/newvirtual void pvf();/new;class Q:public P int q1;void pf();/overrides P:pfvoid qf();/newvoid pvf();/overrides P:pvfvirtual void qvf();/new;布局示意多重继承虚函数重载时的内存布局类声明class P public:int p1;void pf();/newvirtual void pvf();/new;class R public:i
17、nt r1;virtual void pvf();/new virtual void rvf();/new;class S:public P,public R public:int s1;void pvf();/overrides P:pvf and R:pvf void rvf();/overrides R:rvf void svf();/new;布局示意字符串编码一个字符一个字节单个字节的0结束ASCIIASCII一个字符两个字节两个字节的0结束UnicodeUnicode一个字符一个或多个字节(多为双字节)前导字节 0 x81-0 x9F 和 0 xE0-0 xFC之间,意味着和后一字节
18、构成一个字符单个字节的0结束MBCSMBCS字符串操作strcpy(),sprintf(),atol(),ASCIIASCIIwcscpy(),swprintf(),_wtol()UnicodeUnicode_mbsxxx()系列函数,如mbscat,wcslenMBCSMBCS国际化编码不要误用ASCII函数操作MBCS字符串字符串可能为MBCSTCHAR类型#ifdef UNICODEtypedef wchar_t TCHAR;#elsetypedef char TCHAR;#endif使用U指定合适的编码集使用TCHAR#include stdafx.hint _tmain(int ar
19、gc,_TCHAR*argv)TCHAR*szMsg=_T(Hello TCHAR);_tprintf(_T(%sn),szMsg);return 0;BSTR数据类型COM中的UNICODE字符串内存结构 四字节长度+Unicode字符串BSTR字符串 Bob“06 00 00 00 42 00 6F 00 62 00 00 00C+中,BSTR定义为 UNICODE字符串指针长度是不可见的,COM库使用BSTR字符串操作代码示例#include stdafx.h#include Objbase.h int _tmain(int argc,_TCHAR*argv)BSTR bstr=NULL
20、;bstr=SysAllocString(LBob);wprintf(L%sn,bstr);SysFreeString(bstr);return 0;说明 分配和释放BSTR调用COM相关方法 一旦获得BSTR,可以把当成const wchar_t*类型的变量使用用CCOMBSTR简化BSTR类型操作代码#include stdafx.h#include Objbase.h#include atlbase.hint _tmain(int argc,_TCHAR*argv)CComBSTR bstr2=LBob2;wprintf(L%sn,bstr2);bstr2=LBob3;wprintf(L
21、%sn,bstr2);return 0;说明任何使用BSTR类型的地方都可以使用CComBSTRCComBSTR自动管理BSTR内存分配和释放BSTR和其他类型字符串间转化代码void BSTRChange()/TCHAR-BSTRCComBSTR bstr=_T(Bob4);wprintf(L%sn,bstr);/BSTR-TCHARCW2CT szStr(bstr);_tprintf(_T(%sn),szStr);说明CComBST的构造函数接受其他类型字符串CW2CT 将BSTR字符串转换为TCHAR*字符串_ _BSTR_TBSTR_T:BSTR的另一种包装类包装了BSTR,但没有暴露
22、底层的BSTR提供了到wchar_t*的转化(潜在的设计缺陷)能替代BSTR类型,但不能替代out类型的BSTR建议用CComBSTR而不用_bstr_COM基础二进制(DLL或EXE)基本的部署单位组件更好的C+跨语言共享对象二进制必须满足一定规范对象内存布局规范模型COM发展简史1988微软的内部文章1991OLE1随win3.1发布1993OLE 2.01996DCOM2000COM+2002.NETCOM架构COM runtimeCOM componentCOM interfaceCOM classCOM COM接口一组函数指针每个接口有唯一标志每个接口都派生于IUnknow接口客户端
23、通过接口消费组件服务查询而非创建特点图示IUNKNOWN接口HRESULT QueryInterface(in REFIID riid,out void*ppv);查询所实现接口ULONG AddRef();增加对象引用计数ULONG Release();减少对象引用计数COM类至少实现IUnknow接口每个COM类有唯一标志每个COM类有一个特殊的类厂类客户不能创建COM类实例,委托COM库创建特点图示包容和聚合:COM对象的重用COM库COM对象的创建内存管理进程透明操作系统的一部分依赖于系统注册表通过一组API提供基本服务提供了一组DLL及相应头文件以调用COM库API预定义了一组标准接
24、口大大简化COM应用的开发COM类厂一个COM类对应一个COM类厂和COM类具有相同的标识符实现特殊的接口 IClassFactory接口创建COM类实例COM库要了解组件实现了哪些类厂COM库要负责创建COM类厂实例COM库和COM类长交互接口、COM类、类厂、COM库关系接口实例提供具体服务COM实例基于引用计数的生存期管理响应接口查询请求,返回接口实例类厂实例创建与之一一对应COM类实例COM库注册类厂类创建类厂实例进程内组件和进程间组件进程内DLL稳定性较差速度较快需要注册组件进程间EXE稳定性较好速度稍慢需要注册组件COM开发手工实现COM应用理解原理熟悉步骤ATL库实现了解框架提高
25、效率练习巩固提高掌握技巧手工开发COM应用DLL组件EXE组件COM 组件初始化COM库获取接口COM客户端DLL COM组件开发COM Rt类厂注册创建类厂对象类厂创建COM类实例DLL组件生存期管理COM类实现自定义接口、接口查询生存期管理接口声明接口声明接口标志符定义DEFINE_GUID(,0 x22fc47b0,0 x85c3,0 x49d0,0 xab,0 x6b,0 x90,0 x91,0 xcc,0 x6f,0 xf,0 x43);GUIDtypedef struct _GUID unsigned long Data1;unsigned short Data2;unsigned
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- COM 编程指南提纲 编程 指南 提纲
限制150内