一、基础知识――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<――这是函数序号 PRIVATE DllRegisterServer() 函数的作用是将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 const char * g_RegTable[][3]={ {"CLSID\\{00000000-0000-0003-0000-000000000000}",0,"MathCOM"}, {"CLSID\\{00000000-0000-0003-0000-000000000000}\\InprocServer32", 0, (const char * )-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、实现IMath、IPersist接口和DllGetClassObject() 2.1 声明IMath和IPersist接口 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} static const GUID IID_IMath={0,0,2,{0,0,0,0,0,0,0,0}}; //CLSID_CoMath //{00000000-0000-0011-0000-000000000000} static const CLSID CLSID_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)(REFIID riid,LPVOID FAR* ppvObject) PURE; //IMath method STDMETHOD(Add) (THIS_ INT,INT,LPLONG) PURE; STDMETHOD(Subtract)(THIS_ INT,INT,LPLONG) PURE; }; /////////////////// ////com of CoMath class CoMath:public IUnknown { private: DWORD m_dwRefCount; public: CoMath(); virtual ~CoMath(); //IUnknown methods STDMETHODIMP_(DWORD) AddRef(VOID); STDMETHODIMP_(DWORD) Release(VOID); STDMETHODIMP QueryInterface(REFIID riid,LPVOID FAR* ppvObject); class PersistObj:public IPersist { public: CoMath* m_pParent; STDMETHODIMP_(DWORD) AddRef(VOID); STDMETHODIMP_(DWORD) Release(VOID); STDMETHODIMP QueryInterface(REFIID riid,LPVOID FAR* ppvObject); STDMETHODIMP GetClassID(LPCLSID pclsid); }m_persistObj; class MathObj:public IMath { public: CoMath* m_pParent; STDMETHODIMP_(DWORD) AddRef(VOID); STDMETHODIMP_(DWORD) Release(VOID); STDMETHODIMP QueryInterface(REFIID riid,LPVOID FAR* ppvObject); STDMETHODIMP Add(INT,INT,LPLONG); STDMETHODIMP Subtract(INT,INT,LPLONG); }m_mathObj; }; /////////////////// ////class factory of CoMath class CoMathClassFactory:public IClassFactory { public: CoMathClassFactory(); ~CoMathClassFactory(); STDMETHODIMP_(DWORD) AddRef(VOID); STDMETHODIMP_(DWORD) Release(VOID); STDMETHODIMP QueryInterface(REFIID riid,LPVOID FAR* ppv); STDMETHODIMP CreateInstance(IUnknown* pUnkOuter,REFIID riid,VOID** ppvObject); STDMETHODIMP LockServer(BOOL fLook); private: DWORD m_dwRefCount; }; //////////////////////// ////funtion STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv); STDAPI DllRegisterServer(void); STDAPI DllUnregisterServer(void); STDAPI DllCanUnloadNow(void); DLLCOM_API int ComAdd(int x,int y);// ComAdd @5 PRIVATE #endif //#if !defined(DLLCOM_H) 2.2 定义IMath和IPersist接口 ///////////////////////////////////////////////// ////CoMath CoMath::CoMath() { m_dwRefCount=0; m_persistObj.m_pParent=this; m_mathObj.m_pParent=this; } CoMath::~CoMath() { } DWORD CoMath::AddRef() { return ++m_dwRefCount; } DWORD CoMath::Release() |