所属类别:技术博客
文章作者:dansin
特别推荐:免费发布信息 承包关键词~~抢爆了!HOT!
简单的说,COM比之DLL的优势在于.给定一个COM,即便程序员不知道COM导出了什么样的符号,他依然可以使用它.而DLL则不能.这就是为什么在WORD里可以引用EXECL电子文档的原因.COM的出现有它的必然性,它的前身就是OLE技术.在本质上说,COM与DLL并无区别,但是在结构上,COM有标准,而DLL则没有.所以,程序员可以根据这些标准使用COM.这里我讲一讲如何手动的构建一个COM.(以Visual C++为例)1.建立一个空的DLL项目,并定义它的导出文件(*.def)如下:LIBRARY"TestCom.dll"EXPORTSDllCanUnloadNow @1 PRIVATEDllGetClassObject @2 PRIVATEDllRegisterServer @3 PRIVATEDllUnregisterServer@4 PRIVATE2.建立idl文件(定义COM的接口,举例如下)import "oaidl.idl";import "ocidl.idl";[uuid(FAEAE6B8-67BE-42a4-A318-3256781E945A),helpstring("TestCom2 Interface"),object,pointer_default(unique)]interface ITestCom2 : IUnknown{HRESULT Sum([in]int nOp1,[in]int nOp2,[out,retval]int * pret);};[uuid(CA3B37EB-E44A-49b8-9729-6E9222CAE844),version(1.0),helpstring("TESTCOM2 1.0 Type Library")]library TESTCOM2Lib{importlib("stdole32.tlb");importlib("stdole2.tlb");[uuid(3BCFE27D-C88D-453C-8C94-F5F7B97E7841),helpstring("TestCom2 Class")]coclass TESTCOM2{[default] interface ITestCom2;};};3.建立完idl文件后,编绎这个文件.系统会生成两个.c和一个.h文件,这三个文件是后面程序需要include的,关于interface的头文件4.实现DllCanUnloadNowDllGetClassObjectDllRegisterServerDllUnregisterServer四个函数,这四个函数是COM向系统注册以及撤消里需要用到的.给出实例如下:const char * g_RegTable[][3]={{"CLSID\\{3BCFE27D-C88D-453C-8C94-F5F7B97E7841}",0,"TestCom2"},{"CLSID\\{3BCFE27D-C88D-453C-8C94-F5F7B97E7841}\\InprocServer32",0,(const char * )-1 /*表示文件名的值*/},{"CLSID\\{3BCFE27D-C88D-453C-8C94-F5F7B97E7841}\\ProgID",0,"tulip.TestCom2.1"},{"tulip.TestCom2.1",0,"TESTCOM2"},{"tulip.TestCom2.1\\CLSID",0,"{3BCFE27D-C88D-453C-8C94-F5F7B97E7841}"},};HINSTANCE g_hinstDll;BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){g_hinstDll=(HINSTANCE)hModule; return TRUE;}STDAPI DllUnregisterServer(void){HRESULT hr=S_OK;char szFileName [MAX_PATH];::GetModuleFileNameA(g_hinstDll,szFileName,MAX_PATH);int nEntries=sizeof(g_RegTable)/sizeof(*g_RegTable);for(int i =0;SUCCEEDED(hr)&&iQueryInterface(riid,ppv);return CLASS_E_CLASSNOTAVAILABLE;}STDAPI DllCanUnloadNow(void){return S_OK;}5.建立C++的类文件.h以及.cpp,实现一个CTestCom继承刚才定义的接口.并实现QueryInterface,AddRef,Release函数,当然,这里面可以包函自定义的工具函数.class CTestCom2 : public ITestCom2{private:ULONG m_cRef;public:CTestCom2();//IUnknown MethodSTDMETHOD(QueryInterface)(REFIID riid, void **ppv);STDMETHOD_(ULONG, AddRef)();STDMETHOD_(ULONG, Release)();//functionSTDMETHOD (Sum)(int nOp1, int nOp2,int * pret);};STDMETHODIMP CTestCom2::QueryInterface(REFIID riid, void **ppv){if(riid == IID_ITestCom2){*ppv = static_cast(this);}else if(riid == IID_IUnknown)*ppv = static_cast(this);else{*ppv = 0;return E_NOINTERFACE;}reinterpret_cast(*ppv)->AddRef();//这里要这样是因为引用计数是针对组件的return S_OK;}STDMETHODIMP_(ULONG) CTestCom2::AddRef(){return ++m_cRef;}STDMETHODIMP_(ULONG) CTestCom2::Release(){ULONG res = --m_cRef;// 使用临时变量把修改后的引用计数值缓存起来if(res == 0)//因为在对象已经销毁后再引用这个对象的数据将是非法的delete this;return res;}CTestCom2::CTestCom2(){m_cRef = 0;}STDMETHODIMP CTestCom2::Sum(int nOp1, int nOp2,int * pret){ *pret=nOp1+nOp2; return S_OK;}6.定义完上述文件后,可以build了,build成功后,下列代码可以完成COM的调用测试.HRESULT hr;hr = ::CoInitialize(0);ITestCom2 *TCom2 = NULL;int nReturnValue = 0;hr=::CoGetClassObject(CLSID_TESTCOM2,CLSCTX_INPROC,NULL,IID_ITestCom2,(void **)&TCom2);//hr=::CoCreateInstance(CLSID_TESTCOM2,NULL,CLSCTX_INPROC,IID_ITestCom2,(void **)&TCom2);if(SUCCEEDED(hr)){hr=TCom2->Sum(55,66,&nReturnValue);if(SUCCEEDED(hr))cout << "55 + 66 = " <Release();::CoUninitialize();以上只是写了构建一个简单COM的基本步骤,至于为什么这么做,我并没有详细介绍.如果读者能够对COM有一定的了解后,我想了解这个过程将更加容易.发表于 @ 2006年09月19日 15:03:00评论(loading...AddFeedbackCountStack("1245987"))编辑新一篇:summation of theoretical computer science旧一篇:P与NP问题
相关信息· Linux下NTP服务的配置注意事项
· 相对路径与绝对路径的区别
· Internet文件传输(FTP)
· 简析J2EE应用程序数据库类设计模式
23224
42873
