调用dll和com的区别

时间:2022-08-29 22:53:31
问题:调用COM与调用DLL的区别和联系

调用DLL必须这样:
HMODULE hDll=::LoadLibrary("..//Debug//wdll.dll");
if(hDll==NULL)
{
MessageBox("加载动态链接库失败","Warning",MB_OK|MB_ICONWARNING);
return;
}
typedef int (*Yadd)(int,int);
Yadd yadd=(Yadd)::GetProcAddress(hDll,"add");

而调用COM可以这样:
#import "../debug/com.dll"
AfxOleInit();
IKeyComPtr keyCom;
HRESULT hr=keyCom.CreateInstance("DeviceCom.KeyMgr");
if( FAILED( hr)) ....

是不是这两种DLL的调用的方法是固定的??有联系或统一的方法吗?什么时候用COM什么时候用传统的DLL?

回复:
不要把Dll和COM联系起来,更不要把COM看成是DLL,DLL只是用来装载COM的,但是COM不一定要用DLL作载体,也可以用exe或者其他的,至于调用方法,这是specification规定的了。楼主先看看COM的基础知识。

回复:
你说对了,他们的调用方法基本是固定的。

但是你要分清COM与DLL的概念。

回复:
两种DLL可不可以都用传统的调用方法来调用?不可以?为什么?

回复:
com可以实现互操作,DLL不行

回复:
>>两种DLL可不可以都用传统的调用方法来调用?不可以?为什么?
不可以!传统的调用,是通过函数;
而COM组件的调用是通过接口.只有通过CreateInstance获得接口指针,才可以使用该接口.所有的一切调用都是通过接口实现.

回复:
COM是更好的DLL,所以COM是可以通过传统的DLL调用方法来实现的。
COM里有一全局导出函数
DllGetClassObject.
COM库在加载COM组件时也是
LoadLibrary
GetProcAddress("DllGetClassObject")
开始的。
只不过COM把Dll所在路径等等信息把他注册到注册表里了而已。



回复:
看看以下COM库是怎样帮我们把COM对象跑起来的吧。
  IUnknown *pUnk=NULL;
  IObject *pObject=NULL;
  CoInitialize(NULL);
  CoCreateInstance(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IUnknown, (void**)&pUnk);
  pUnk->QueryInterface(IID_IOjbect, (void**)&pObject);
  pUnk->Release();
  pObject->Func();
  pObject->Release();
  CoUninitialize();

  这就是一个典型的创建COM组件的框架,不过我的兴趣在CoCreateInstance身上,让我们来看看它内部做了一些什么事情。以下是它内部实现的一个伪代码:

  CoCreateInstance(....)
  {
  .......
  IClassFactory *pClassFactory=NULL;
  CoGetClassObject(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&pClassFactory);
  pClassFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pUnk);
  pClassFactory->Release();
  ........
  }

  这段话的意思就是先得到类厂对象,再通过类厂创建组件从而得到IUnknown指针。继续深入一步,看看CoGetClassObject的内部伪码:

 CoGetClassObject(.....)
 {
  //通过查注册表CLSID_Object,得知组件DLL的位置、文件名
  //装入DLL库
LoadLibrary
  //使用函数GetProcAddress( "DllGetClassObject" )得到DLL库中函数DllGetClassObject的函数指针。
  //调用DllGetClassObject
 }
  DllGetClassObject是干什么的,它是用来获得类厂对象的。只有先得到类厂才能去创建组件.
  下面是DllGetClassObject的伪码:
  DllGetClassObject(...)
  {
  ......
  CFactory* pFactory= new CFactory; //类厂对象
  pFactory->QueryInterface(IID_IClassFactory, (void**)&pClassFactory);
  //查询IClassFactory指针
  pFactory->Release();
 ......
  }
  CoGetClassObject的流程已经到此为止,现在返回CoCreateInstance,看看CreateInstance的伪码:
  CFactory::CreateInstance(.....)
  {
  ...........
  CObject *pObject = new CObject; //组件对象
  pObject->QueryInterface(IID_IUnknown, (void**)&pUnk);
  pObject->Release();
  ...........
  }

所以,我们完全可以不注册COM组件,而自己用以上相同的流程按照普通DLl的调用方式:
LoadLibary 和 GetProcAddress的方式 和对应的COM接口头文件,在加上COM dll生成的lib文件把一个COM成功的调用起来的。



回复:
好,够详细的,慢慢消化一下,结:)

回复:/**
* DllGetClassObject函数原型声明
*/
typedef int (CALLBACK *DllGetClassObjectPtr)(REFCLSID,REFIID,LPVOID *);
/**
* 从COM里返回一接口对象,成功则返回true,否则返回false
*@param lpDll[in] : dll路径
*@param strrclsid[in] : 类对象字符串助记符
*@param strriid[in] : 接口对象字符串助记符
*@param ppv [out] : 返回的接口对象
*/
int _stdcall GetComInterface( LPCSTR lpDll,LPCSTR strrclsid,LPCSTR strriid,LPVOID * ppv )
{
/**
* 加载DLL
*/
HINSTANCE hInstance = NULL ;
DllGetClassObjectPtr ProcFunc = NULL ;
bool bSucces = false;
hInstance = LoadLibrary(lpDll);

if ( hInstance )
{
/**
* 得到DllGetClassObject函数地址
*/
ProcFunc =(DllGetClassObjectPtr)GetProcAddress( hInstance, "DllGetClassObject");
if( ProcFunc )
{
/**
* 得到类GUID和接口的GUID
*/
CLSID rclsid;
IID riid;
CLSIDFromString((LPOLESTR )strrclsid,&rclsid);
if( strriid!= NULL )
{
CLSIDFromString((LPOLESTR )strriid,&riid);
}
else
{
riid=IID_IUnknown;
}

/***
* 得到类厂并创建接口对象
*/
IClassFactory *pIf = NULL;
if( ProcFunc(rclsid,IID_IClassFactory,(void **)&pIf)==S_OK )
{
bSucces = ( pIf->CreateInstance(NULL,riid,ppv)==S_OK );
pIf->Release();
pIf = NULL;
}
}

/**
* 如果创建借口对象失败,释放Dll
*/
if( !bSucces )
{
FreeLibrary( hInstance );
}
}

return bSucces ;