三、纯手工创建一个COM组件1、从建工程到实现注册在这一过程中我们将完成三个步骤:创建dll的入口函数,定义接口文件,实现注册功能1.1创建一个类型为win32dll工程创建一个名为MathCOM的win32dll工程。在向导的第二步选择Asmipledllproject选项。当然如果你选择一个空的工程,那你自己完成DllMain定义吧。1.2定义接口文件生成一个名为MathCOM.idl的接口文件。并将此文件加入到刚才创建的那个工程里。viewsourceprint?01.//MathCOM.idl文件02.//MathCOM.idl:IDLsourceforMathCOM.dll03.//04.//ThisfilewillbeprocessedbytheMIDLtoolto05.//producethetypelibrary(MathCOM.tlb)andmarshallingcode.06.importoaidl.idl;07.importocidl.idl;08.[09.uuid(FAEAE6B7-67BE-42a4-A318-3256781E945A),10.helpstring(ISimpleMathInterface),11.object,12.pointer_default(unique)13.]14.interfaceISimpleMath:IUnknown15.{16.HRESULTAdd([in]intnOp1,[in]intnOp2,[out,retval]int*pret);17.HRESULTSubtract([in]intnOp1,[in]intnOp2,[out,retval]int*pret);18.HRESULTMultiply([in]intnOp1,[in]intnOp2,[out,retval]int*pret);19.HRESULTDivide([in]intnOp1,[in]intnOp2,[out,retval]int*pret);20.};21.22.[23.uuid(01147C39-9DA0-4f7f-B525-D129745AAD1E),24.helpstring(IAdvancedMathInterface),25.object,26.pointer_default(unique)27.]28.interfaceIAdvancedMath:IUnknown29.{30.HRESULTFactorial([in]intnOp1,[out,retval]int*pret);31.HRESULTFabonacci([in]intnOp1,[out,retval]int*pret);32.};33.[34.uuid(CA3B37EA-E44A-49b8-9729-6E9222CAE844),35.version(1.0),36.helpstring(MATHCOM1.0TypeLibrary)37.]38.39.40.41.42.libraryMATHCOMLib43.{44.importlib(stdole32.tlb);45.importlib(stdole2.tlb);46.47.[48.uuid(3BCFE27E-C88D-453C-8C94-F5F7B97E7841),49.helpstring(MATHCOMClass)50.]51.coclassMATHCOM52.{53.[default]interfaceISimpleMath;54.interfaceIAdvancedMath;55.};56.};在编译此工程之前请检查Project/Setting/MIDL中的设置。正确设置如下图:图1.4midl的正确设置在正确设置后,如编译无错误,那么将在工程的目录下产生四个文件名作用MathCOM.h接口的头文件,如果想声明或定义接口时使用此文件MathCOM_i.c定义了接口和类对象以及库,只有在要使用到有关与GUID有关的东西时才引入此文件,此文件在整个工程中只能引入一次,否则会有重复定义的错误MathCOM_p.c用于存根与代理dlldata.c不明1.3增加注册功能作为COM必须要注册与注销的功能。1.3.1增加一个MathCOM.def文件DEF文件是模块定义文件(ModuleDefinitionFile)。它允许引出符号被化名为不同的引入符号。viewsourceprint?01.//MathCOM.def文件02.;MathCOM.def:Declaresthemoduleparameters.03.04.LIBRARYMathCOM.DLL05.06.EXPORTS07.DllCanUnloadNow@1PRIVATE08.DllGetClassObject@2PRIVATE09.DllRegisterServer@3PRIVATE10.DllUnregisterServer@4PRIVATEDllUnregisterServer这是函数名称@4<――这是函数序号PRIVATE接下来大致介绍一下DllRegisterServer()和DllUnregisterServer()。(其他两个函数的作用将在后面介绍)1.3.2DllRegisterServer()和DllUnregisterServer()DllRegisterServer()函数的作用是将COM服务器注册到本机上。DllUnregisterServer()函数的作用是将COM服务器从本机注销。1.4MathCOM.cpp文件现在请将MathCOM.cpp文件修改成如下:viewsourceprint?01.//MATHCOM.cpp:DefinestheentrypointfortheDLLapplication.02.//03.#includestdafx.h04.#includeobjbase.h05.#includeinitguid.h06.#includeMathCOM.h07.//standardself-registrationtable08.constchar*g_RegTable[][3]={09.{CLSID\\{3BCFE27E-C88D-453C-8C94-F5F7B97E7841},0,MathCOM},10.{CLSID\\{3BCFE27E-C88D-453C-8C94-F5F7B97E7841}\\InprocServer32,11.0,12.(constchar*)-1/*表示文件名的值*/},13.{CLSID\\{3BCFE27E-C88D-453C-8C94-F5F7B97E7841}\\ProgID,0,tulip.MathCOM.1},14.{tulip.MathCOM.1,0,MathCOM},15.{tulip.MathCOM.1\\CLSID,0,{3BCFE27E-C88D-453C-8C94-F5F7B97E7841}},16.};17.HINSTANCEg_hinstDll;18.BOOLAPIENTRYDllMain(HANDLEhModule,19.DWORDul_reason_for_call,20.LPVOIDlpReserved21.)22.{23.g_hinstDll=(HINSTANCE)hModule;24.returnTRUE;25.}26./*********************************************************************27.*FunctionDeclare:DllUnregisterServer28.*Explain:self-unregistrationroutine29.*Parameters:30.*void--31.*Return:32.*STDAPI--33.*Author:tulip34.*Time:2003-10-2919:07:4235.*********************************************************************/36.STDAPIDllRegisterServer(void)37.{38.HRESULThr=S_OK;39.charszFileName[MAX_PATH];40.::GetModuleFileName(g_hinstDll,szFileName,MAX_PATH);41.42.intnEntries=sizeof(g_RegTable)/sizeof(*g_RegTable);43.for(inti=0;SUCCEEDED(hr)&&inEntries;i++)44.{45.constchar*pszKeyName=g_RegTable[i][0];46.constchar*pszValueName=g_RegTable[i][1];47.constchar*pszValue=g_RegTable[i][2];48.49.if(pszValue==(constchar*)-1)50.{51.pszValue=szFileName;52.}53.54.HKEYhkey;55.longerr=::RegCreateKey(HKEY_CLASSES_ROOT,pszKeyName,&hkey);56.if(err==ERROR_SUCCESS)57.{58.err=::RegSetValueEx(hkey,59.pszValueName,60.0,61.REG_SZ,62.(constBYTE*)pszValue,63.(strlen(pszValue)+1));64.::RegCloseKey(hkey);65.}66.if(err!=ERROR_SUCCESS)67.{68.::DllUnregisterServer();69.hr=E_FAIL;70.}71.72.}73.returnhr;74.}75.76.STDAPIDllGetClassObject(REFCLSIDrclsid,REFIIDriid,void**ppv)77.{78.returnCLASS_E_CLASSNOTAVAILABLE;79.}80.81.STDAPIDllCanUnloadNow(void)82.{83.returnE_FAIL;84.}我只是在此文件中加几个必要的头文件和几个全局变量。并实现了DllRegisterServer()和DllUnregisterServer()。而对于其他两引出函数我只返回一个错误值罢了。1.5小结现在我们的工程中应该有如下文件:文件名作用Stdafx.h和stdafx.cpp预编译文件MathCOM.cppDll入口函数及其他重要函数定义的地方MathCOM.def模块定义文件MathCOM.idl接口定义文件(在1.2后如果编译的话应该还有四个文件)好了到现在,我的所谓COM已经实现注册与注销功能。如果在命令行或运行菜单下项执行如下regsvr32绝对路径+MathCOM.dll就注册此COM组件。在执行完此命令后,请查看注册表项的HKEY_CLASSES_ROOT\CLSID项看看3BCFE27E-C88D-453C-8C94-F5F7B97E7841这一项是否存在(上帝保佑存在)。如同上方法再执行一下regsvr32-u绝对路径+MathCOM.dll,再看看注册表。其实刚才生成的dll根本不是COM组件,哈哈!!!因为他没有实现DllGetClassObject()也没有实现ISmipleMath和IAdvancedMath两个接口中任何一个。让我们继续前行吧!!!2、实现ISmipleMath,IAdvancedMath接口和DllGetClassObject()2.1实现ISmipleMath和IAdvancedMath接口让我们将原来的CMath类修改来实现ISmipleMath接口和IAdvanced