手动编写以DLL为载体的COM

    技术2022-05-11  114

    一、基础知识――DLL 的调试

     

    方法①: 对DLL的工程DEBUG,在DLL工程的Project Setting->Debug->Executable for debug session中加入你的.exe的路径和名字。可以在dll中设置断点,.exe程序必须要调用dll中函数。

     

    方法②: 对调用程序DEBUG:在settings/debug中category选additional dlls,然后将你要调试的dll加进来。这样,即使你用loadlibrary动态加载dll,也可以加断点了

     

    集中调试方法:

     

    1。建立dll 工程hook,建立调用工程Test

     

    2。在Test工程中需要用到hook.dll的源文件中(或stdafx.h中)加入     #include "./hook/hook.h"   这样在该源文件中使用"::"就可以索引到hook.h中所有的导出函数、变量以及类   3。在Test的工程设置->Link->Object/library modules中加入:../hook/debug/hook.lib

     

    4。为了找到DLL,需要在工程设置->Debug->Working directory中加入:e:/hook/debug/

     

    5。通过工程->Insert Project into Workspace将hook.dsp工程加入Test项目中。

     

    6。设置hook工程为活动工程,在工程>Debug>Executable for Debug session中加入:      e:/test/debug/test.exe

     

    7。现在设置断点,按F5可以正常调试了

     

    注意:当调试的DLL被映射到其他的应用程序(非TEST)进程空间并运行时,在该DLL中设置的断点无效,当然可以通过MessageBox来查看变量,若该DLL是MFC扩展DLL,则还可以用TRACE或afxDump来查看变量。

     

    二、基础知识――DLL 的调用

     

    1. 静态连接:copy *.dll、*.lib、*.h

     

    2. 动态连接:LoadLibrary(…); GetProcAddress();

     

    三、正文――手工定制简单COM组件

     

    1、从建工程到实现注册在这一过程中我们将完成两个个步骤:创建dll的入口函数,实现注册功能1.1创建一个类型为win32 dll工程创建一个名为MathCOM的win32 dll工程。在向导的第二步选择"A smiple dll project"选项。当然如果你选择一个空的工程,那你自己定义DllMain。1.2 增加注册功能作为COM必须要注册与注销的功能。增加一个MathCOM.def文件:DEF文件是模块定义文件(Module Definition File)。它允许引出符号被化名为不同的引入符号。

     

    //MathCOM.def文件

     

    ; MathCOM.def : Declares the module parameters.

     

    LIBRARY      "MathCOM.DLL"

     

    EXPORTS

     

            DllCanUnloadNow     @1 PRIVATE

     

            DllGetClassObject   @2 PRIVATE

     

            DllRegisterServer   @3 PRIVATE

     

            DllUnregisterServer @4 PRIVATE  

     

    DllUnregisterServer 这是函数名称 @4<――这是函数序号 PRIVATEDllRegisterServer() 函数的作用是将COM服务器注册到本机上。DllUnregisterServer() 函数的作用是将COM服务器从本机注销。1.3 MathCOM.cpp文件现在请将 MathCOM.cpp 文件修改成如下:

      // MATHCOM.cpp : Defines the entry point for the DLL application.

     

      //

     

      #include "stdafx.h"

     

      #include <objbase.h>

     

      #include <initguid.h>

     

      #include "MathCOM.h"

     

       

     

      //standard self-registration table

     

     

    constchar * g_RegTable[][3]={

     

             {"CLSID//{00000000-0000-0003-0000-000000000000}",0,"MathCOM"},

     

             {"CLSID//{00000000-0000-0003-0000-000000000000}//InprocServer32",

     

             0,

     

             (constchar * )-1 /*表示文件名的值*/},

     

             {"CLSID//{00000000-0000-0003-0000-000000000000}//ProgID",0,"nomad.MathCOM.1"},

     

             {"nomad.MathCOM.1",0,"MathCOM"},

     

             {"nomad.MathCOM.1//CLSID",0,"{00000000-0000-0003-0000-000000000000}"},

      };

     

      HINSTANCE g_hinstDll;

     

      BOOL APIENTRY DllMain( HANDLE hModule,

     

                             DWORD ul_reason_for_call,

     

                             LPVOID lpReserved

     

                                      )

     

      {

     

          g_hinstDll=(HINSTANCE)hModule;

     

          return TRUE;

     

      }

     

      /********************************************************************

     

      * Function Declare : DllRegisterServer

     

      * Explain : self Registration routine

     

      ********************************************************************/

     

      STDAPI DllRegisterServer(void)

     

      {

     

              HRESULT hr=S_OK;

     

              char szFileName [MAX_PATH];

     

              ::GetModuleFileName(g_hinstDll,szFileName,MAX_PATH);

     

              int nEntries=sizeof(g_RegTable)/sizeof(*g_RegTable);

     

              for(int i =0;SUCCEEDED(hr)&&i<nEntries;i++)

     

              {

     

                      const char * pszKeyName=g_RegTable[i][0];

     

                      const char * pszValueName=g_RegTable[i][1];

     

                      const char * pszValue=g_RegTable[i][2];

     

                      if(pszValue==(const char *)-1)

     

                      {

     

                          pszValue=szFileName;

     

                      }

     

                      HKEY hkey;

     

                      long err=::RegCreateKey(HKEY_CLASSES_ROOT,pszKeyName,&hkey);

     

                      if(err==ERROR_SUCCESS)

     

                      {

     

                          err=::RegSetValueEx( hkey,

     

                                      pszValueName,

     

                                      0,

     

                                      REG_SZ,

     

                                      ( const BYTE*)pszValue,

     

                                      ( strlen(pszValue)+1 ) );

     

                          ::RegCloseKey(hkey);

     

                      }

     

                      if(err!=ERROR_SUCCESS)

     

                      {

     

                          ::DllUnregisterServer();

     

                          hr=E_FAIL;

     

                      }

     

              }

     

         return hr;

     

      }

     

      /********************************************************************

     

      * Function Declare : DllUnregisterServer

     

      * Explain : self-unregistration routine

     

      ********************************************************************/

     

      STDAPI DllUnregisterServer(void)

     

      {

     

              HRESULT hr=S_OK;

     

              char szFileName [MAX_PATH];

     

              ::GetModuleFileName(g_hinstDll,szFileName,MAX_PATH);

     

              int nEntries=sizeof(g_RegTable)/sizeof(*g_RegTable);

     

              for(int i =0;SUCCEEDED(hr)&&i<nEntries;i++)

     

              {

     

                      const char * pszKeyName=g_RegTable[i][0];

     

                      long err=::RegDeleteKey(HKEY_CLASSES_ROOT,pszKeyName);

     

                      if(err!=ERROR_SUCCESS)

     

                          hr=S_FALSE;

     

              }

     

              return hr;

     

      }

     

      STDAPI DllGetClassObject(REFCLSID rclsid ,REFIID riid,void **ppv)

     

      {

     

              return CLASS_E_CLASSNOTAVAILABLE;

     

      }

     

      STDAPI DllCanUnloadNow(void)

     

      {

     

              return E_FAIL;

     

     

    }1.4好了到现在,我的所谓COM已经实现注册与注销功能。如果在命令行或"运行"菜单下项执行如下"regsvr32 绝对路径+MathCOM.dll"就注册此COM组件。在执行完此命令后,请查看注册表项的HKEY_CLASSES_ROOT/CLSID项看看{00000000-0000-0003-0000-000000000000}这一项是否存在。如同上方法再执行一下"regsvr32 -u 绝对路径+MathCOM.dll",再看看注册表,这一项就会消失。

     

    2、实现IMathIPersist接口和DllGetClassObject()

     

    2.1 声明IMathIPersist接口  IMath和IPersist接口都包括在CoMath类中(参看深入解析MFC):#if !defined(DLLCOM_H)#define DLLCOM_H

     

    #ifdef DLLCOM_EXPORTS#define DLLCOM_API _declspec(dllexport)

     

    #else

     

    #define DLLCOM_API_declspec(dllimport)

     

    #endif

     

     

     

    #include "unknwn.h"

     

    //IID_IMath

     

    //{00000000-0000-0010-0000-000000000000}

     

    staticconstGUIDIID_IMath={0,0,2,{0,0,0,0,0,0,0,0}};

     

    //CLSID_CoMath

     

    //{00000000-0000-0011-0000-000000000000}

     

    staticconstCLSIDCLSID_CoMath={0,0,3,{0,0,0,0,0,0,0,0}};

     

    ///

     

    //com of IMath

     

    DECLARE_INTERFACE_(IMath,IUnknown)

     

    {

     

        //IUnknown method

     

        STDMETHOD_(ULONG,AddRef)(THIS) PURE;

     

        STDMETHOD_(ULONG,Release)(THIS) PURE;

     

        STDMETHOD(QueryInterface)(REFIIDriid,LPVOIDFAR* ppvObject) PURE;

     

       

     

        //IMath method

     

        STDMETHOD(Add) (THIS_INT,INT,LPLONG) PURE;

     

        STDMETHOD(Subtract)(THIS_INT,INT,LPLONG) PURE;

     

    };

     

    ///

     

    com of CoMath

     

    classCoMath:publicIUnknown

     

    {

     

    private:

     

        DWORDm_dwRefCount;

     

    public:

     

        CoMath();

     

        virtual ~CoMath(); 

     

        //IUnknown methods

     

        STDMETHODIMP_(DWORD) AddRef(VOID);

     

        STDMETHODIMP_(DWORD) Release(VOID);

     

        STDMETHODIMPQueryInterface(REFIIDriid,LPVOIDFAR* ppvObject);

     

       

     

        classPersistObj:publicIPersist

     

        {

     

        public:

     

            CoMath* m_pParent;

     

           

     

            STDMETHODIMP_(DWORD) AddRef(VOID);

     

            STDMETHODIMP_(DWORD) Release(VOID);

     

            STDMETHODIMPQueryInterface(REFIIDriid,LPVOIDFAR* ppvObject);

     

           

     

            STDMETHODIMPGetClassID(LPCLSIDpclsid);

     

        }m_persistObj;

     

       

     

        classMathObj:publicIMath

     

        {

     

        public:

     

            CoMath* m_pParent;

     

           

     

            STDMETHODIMP_(DWORD) AddRef(VOID);

     

            STDMETHODIMP_(DWORD) Release(VOID);

     

            STDMETHODIMPQueryInterface(REFIIDriid,LPVOIDFAR* ppvObject);

     

           

     

            STDMETHODIMPAdd(INT,INT,LPLONG);

     

            STDMETHODIMPSubtract(INT,INT,LPLONG);

     

        }m_mathObj;

     

    };

     

    ///

     

    class factory of CoMath

     

    classCoMathClassFactory:publicIClassFactory

     

    {

     

    public:

     

        CoMathClassFactory();

     

        ~CoMathClassFactory();

     

       

     

        STDMETHODIMP_(DWORD) AddRef(VOID);

     

        STDMETHODIMP_(DWORD) Release(VOID);

     

        STDMETHODIMPQueryInterface(REFIIDriid,LPVOIDFAR* ppv);

     

       

     

        STDMETHODIMPCreateInstance(IUnknown* pUnkOuter,REFIIDriid,VOID** ppvObject);

     

        STDMETHODIMPLockServer(BOOLfLook);

     

    private:

     

        DWORDm_dwRefCount;

     

    };

     

     

    funtion

     

    STDAPIDllGetClassObject(REFCLSIDrclsid, REFIIDriid, LPVOIDFAR* ppv);

     

    STDAPIDllRegisterServer(void);

     

    STDAPIDllUnregisterServer(void);

     

    STDAPIDllCanUnloadNow(void);

     

    DLLCOM_APIintComAdd(intx,inty);// ComAdd   @5 PRIVATE

     

    #endif    //#if !defined(DLLCOM_H)

     

    2.2 定义IMathIPersist接口

     

    /

     

    CoMath

     

    CoMath::CoMath()

     

    {

     

             m_dwRefCount=0;

     

             m_persistObj.m_pParent=this;

     

             m_mathObj.m_pParent=this;

     

    }

     

    CoMath::~CoMath()

     

    {

     

    }

     

    DWORDCoMath::AddRef()

     

    {

     

             return ++m_dwRefCount;

     

    }

     

    DWORDCoMath::Release()

     

    {

     

             DWORDdwResult=--m_dwRefCount;

     

             if(!dwResult)

     

                       deletethis;

     

             returndwResult;

     

    }

     

    HRESULTCoMath::QueryInterface(REFIIDriid,LPVOIDFAR* ppvObject)

     

    {

     

             if(riid==IID_IUnknown)

     

             {

     

                      *ppvObject=(LPUNKNOWN)this;

     

                      AddRef();

     

                       returnNOERROR;

     

             }

     

             elseif(riid==IID_IPersist)

     

             {

     

                      *ppvObject=(LPPERSIST)&m_persistObj;

     

                      AddRef();

     

                       returnNOERROR;

     

             }

     

             elseif(riid==IID_IMath)

     

             {

     

                      *ppvObject=(IMath*)&m_mathObj;

     

                      AddRef();

     

                       returnNOERROR;

     

             }

     

             returnResultFromScode(E_NOINTERFACE);

     

    }

     

    //Persist

     

    ULONGCoMath::PersistObj::AddRef()

     

    {

     

             returnm_pParent->AddRef();

     

    }

     

    ULONGCoMath::PersistObj::Release()

     

    {

     

             returnm_pParent->Release();

     

    }

     

    HRESULTCoMath::PersistObj::QueryInterface(REFIIDriid,LPVOIDFAR* ppvObject)

     

    {

     

             returnm_pParent->QueryInterface(riid,ppvObject);

     

    }

     

    //Math

     

    ULONGCoMath::MathObj::AddRef()

     

    {

     

             returnm_pParent->AddRef();

     

    }

     

    ULONGCoMath::MathObj::Release()

     

    {

     

             returnm_pParent->Release();

     

    }

     

    HRESULTCoMath::MathObj::QueryInterface(REFIIDriid,LPVOIDFAR* ppvObject)

     

    {

     

             returnm_pParent->QueryInterface(riid,ppvObject);

     

    }

     

    HRESULTCoMath::PersistObj::GetClassID(LPCLSIDpclsid)

     

    {

     

             *pclsid=CLSID_CoMath;

     

             returnNOERROR;

     

    }

     

    HRESULTCoMath::MathObj::Add(INTn1,INTn2,LPLONGlpResult)

     

    {

     

             *lpResult=n1+n2;

     

             returnNOERROR;

     

    }

     

    HRESULTCoMath::MathObj::Subtract(INTn1,INTn2,LPLONGlpResult)

     

    {

     

             *lpResult=n1-n2;

     

             returnNOERROR;

     

    }

     

    ///

     

    //CoMathClassFactory

     

    staticDWORDdwServerCount=0;

     

    staticCoMathClassFactorycoMathCF;

     

     

     

    CoMathClassFactory::CoMathClassFactory():m_dwRefCount(0)

     

    {

     

    }

     

    CoMathClassFactory::~CoMathClassFactory()

     

    {

     

    }

     

    DWORDCoMathClassFactory::AddRef()

     

    {

     

             return ++m_dwRefCount;

     

    }

     

    DWORDCoMathClassFactory::Release()

     

    {

     

             DWORDdwResult=--m_dwRefCount;

     

             if(!dwResult)

     

                       deletethis;

     

             returndwResult;

     

    }

     

    HRESULTCoMathClassFactory::QueryInterface(REFIIDriid,LPVOIDFAR* ppv)

     

    {

     

             *ppv=0;

     

     

     

             if(riid==IID_IClassFactory)

     

                      *ppv=LPCLASSFACTORY(this);

     

             elseif(riid==IID_IUnknown)

     

                      *ppv=LPUNKNOWN(this);

     

            

     

             if(*ppv)

     

             {

     

                      LPUNKNOWN(*ppv)->AddRef();

     

                       returnNOERROR;

     

             }

     

     

     

             returnResultFromScode(E_NOINTERFACE);

     

    }

     

     

     

    HRESULTCoMathClassFactory::CreateInstance(IUnknown* pUnkOuter,REFIIDriid,VOID** ppvObject)

     

    {

     

             HRESULThr=ResultFromScode(E_OUTOFMEMORY);

     

             CoMath* pCoMath=NULL;

     

             pCoMath=newCoMath;

     

             if(pCoMath){

     

                      hr=pCoMath->QueryInterface(riid,ppvObject);

     

                      if(FAILED(hr))

     

                                deletepCoMath;

     

             }

     

             returnhr;

     

    }

     

    HRESULTCoMathClassFactory::LockServer(BOOLfLook)

     

    {

     

             if(fLook)

     

                      dwServerCount++;

     

             else

     

                      dwServerCount--;

     

             returnNOERROR;

     

    }

     

     

    DllGetClassObject

     

    STDAPIDllGetClassObject(REFCLSIDrclsid, REFIIDriid, LPVOIDFAR* ppv)

     

    {

     

             if((rclsid==CLSID_CoMath)&&(riid==IID_IClassFactory||riid==IID_IUnknown))

     

             {

     

                      

     

                       returncoMathCF.QueryInterface(riid,ppv);

     

             }

     

             returnCLASS_E_CLASSNOTAVAILABLE;

     

    }

     

    2.3 好,到此COM设计完成2.4 客户端

     

    接下来我们写个客户端程序对此COM进行测试。新建一个空的名为TestMathCOM win32 Console 工程,将它添加到 MathCOM workspace 中。在TestMathCOM 工程里添加一个名为 main.cpp 的文件,此文件的内容如下:

     

    #include "stdafx.h"

     

    intmain(intargc, char* argv[])

     

    {

     

             CoMathClassFactory *pCF=NULL;

     

             IMath *pIMath=NULL;

     

             HRESULThr=::CoInitialize(NULL);

     

     

     

             if(hr!=S_OK) return 0;

     

             hr=::CoGetClassObject(CLSID_CoMath,CLSCTX_ALL,NULL,IID_IClassFactory,(VOID**)&pCF);

     

             if(SUCCEEDED(hr))

               {

                      if(hr=pCF->CreateInstance(NULL,IID_IMath,(VOID**)&pIMath)!=NOERROR)

     

                                return 0;

     

                      longr;

     

                      if(hr=pIMath->Add(3,4,&r)!=NOERROR)

     

                                return 0;

     

             }

     

             else

     

             {

     

                      if(hr==CLASS_E_CLASSNOTAVAILABLE)

     

                                printf("%x",hr);

     

             }

     

     

     

             printf("Hello World!/n");

     

             return 0;

      }

    最新回复(0)