一、基础知识――DLL的调试
方法①:对DLL的工程DEBUG,
在DLL工程的ProjectSetting->Debug->Executablefordebug
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/librarymodules中加入:../hook/debug/hook.lib
4。为了找到DLL,需要在工程设置->Debug->Workingdirectory中加入:e:/hook/debug/
5。通过工程->InsertProjectintoWorkspace将hook.dsp工程加入Test项目中。
6。设置hook工程为活动工程,在工程>Debug>ExecutableforDebugsession中加入:
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创建一个类型为win32dll工程
创建一个名为MathCOM的win32dll工程。在向导的第二步选择"Asmipledll
project"选项。当然如果你选择一个空的工程,那你自己定义DllMain。
1.2增加注册功能
作为COM必须要注册与注销的功能。
增加一个MathCOM.def文件:DEF文件是模块定义文件(ModuleDefinitionFile)。它允许引出符号被化名为不同的引入符号。
//MathCOM.def文件
;MathCOM.def:Declaresthemoduleparameters.
LIBRARY"MathCOM.DLL"
EXPORTS
DllUnregisterServer 这是函数名称@4<――这是函数序号PRIVATE
DllRegisterServer()函数的作用是将COM服务器注册到本机上。
DllUnregisterServer()函数的作用是将COM服务器从本机注销。
1.3MathCOM.cpp文件
现在请将MathCOM.cpp文件修改成如下:
//MATHCOM.cpp:DefinestheentrypointfortheDLLapplication.
//#include"stdafx.h"
#include<objbase.h>
#include<initguid.h>
#include"MathCOM.h"
//standardself-registrationtable
const char *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}"},
};
HINSTANCEg_hinstDll;
BOOLAPIENTRYDllMain(HANDLEhModule,DWORDul_reason_for_call,LPVOIDlpReserved)
{
g_hinstDll=(HINSTANCE)hModule;
returnTRUE;
}
/*********************************************************************
FunctionDeclare:DllRegisterServer*Explain:selfRegistrationroutine
********************************************************************/
STDAPIDllRegisterServer(void){HRESULThr=S_OK;
charszFileName[MAX_PATH];::GetModuleFileName(g_hinstDll,szFileName,MAX_PATH);
intnEntries=sizeof(g_RegTable)/sizeof(*g_RegTable);
for(inti=0;SUCCEEDED(hr)&&i<nEntries;i++){constchar*pszKeyName=g_RegTable[i][0];
constchar*pszValueName=g_RegTable[i][1];
constchar*pszValue=g_RegTable[i][2];
if(pszValue==(constchar*)-1){pszValue=szFileName;
}
HKEYhkey;
longerr=::RegCreateKey(HKEY_CLASSES_ROOT,pszKeyName,&hkey);
if(err==ERROR_SUCCESS)
{
err=::RegSetValueEx(hkey,pszValueName,0,REG_SZ,(constBYTE*)pszValue,(strlen(pszValue)+1));
::RegCloseKey(hkey);
}
if(err!=ERROR_SUCCESS)
{
::DllUnregisterServer();
hr=E_FAIL;
}
}
returnhr;
}/*********************************************************************
FunctionDeclare:DllUnregisterServer*Explain:selfunregistrationroutine
********************************************************************/
STDAPIDllUnregisterServer(void){HRESULThr=S_OK;charszFileName[MAX_PATH];
::GetModuleFileName(g_hinstDll,szFileName,MAX_PATH);
intnEntries=sizeof(g_RegTable)/sizeof(*g_RegTable);
for(inti=0;SUCCEEDED(hr)&&i<nEntries;i++)
[i][0];longerr=::RegDeleteKey(HKEY_CLASSES_ROOT,pszKeyName);
if(err!=ERROR_SUCCESS)hr=S_FALSE;
}
returnhr;
}
STDAPIDllGetClassObject(REFCLSIDrclsid,REFIIDriid,void**ppv)
{
returnCLASS_E_CLASSNOTAVAILABLE;
}
STDAPIDllCanUnloadNow(void){
returnE_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)
#defineDLLCOM_H
#ifdefDLLCOM_EXPORTS
#defineDLLCOM_API_declspec(dllexport)
#else
#defineDLLCOM_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}};
///
//comofIMath
DECLARE_INTERFACE_(IMath,IUnknown)
{
//IUnknownmethod
STDMETHOD_(ULONG,AddRef)(THIS)PURE;
STDMETHOD_(ULONG,Release)(THIS)PURE;
STDMETHOD(QueryInterface)(REFIIDriid,LPVOIDFAR*ppvObject)PURE;
//IMathmethod
STDMETHOD(Add)(THIS_INT,INT,LPLONG)PURE;
STDMETHOD(Subtract)(THIS_INT,INT,LPLONG)PURE;
};
///
comofCoMath
classCoMath:publicIUnknown
{
private:
DWORDm_dwRefCount;
public:
CoMath();
virtual~CoMath();
//IUnknownmethods
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;
};
///
classfactoryofCoMath
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@5PRIVATE
#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()
{
}
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,REFIID
riid,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的win32Console工程,将它添加到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)return0;
hr=::CoGetClassObject(CLSID_CoMath,CLSCTX_ALL,NULL,IID_IClassFactory,(VOID**)&pCF);
if(SUCCEEDED(hr))
{
if(hr=pCF->CreateInstance(NULL,IID_IMath,(VOID**)&pIMath)!=NOERROR)
return0;
longr;
if(hr=pIMath->Add(3,4,&r)!=NOERROR)
return0;
}
else
{
if(hr==CLASS_E_CLASSNOTAVAILABLE)
printf("%x",hr);
}
printf("HelloWorld!/n");
return0;
}
说明:文章参考了部分网络帖子和《深入解析MFC》的内容,希望能给大家一个入门的借鉴。