问题:调用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 ;
}
相关文章
- JNI在C和C++中的调用区别
- Release模式和Debug模式下调用dll的结果完全不一样?
- v-if和v-show的区别?使用场景?v-if状态改变调用钩子函数的示例
- 使用Visual Studio安装项目自动注册和GAC一个COM互操作DLL
- Delphi 中的DLL 封装和调用对象技术(刘艺,有截图)
- 在Vuex使用 以及 dispatch和commit来调用mutations的区别
- com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver的区别 serverTimezone设定
- MSVC和MinGW组件dll相互调用
- C++ 普通函数和虚函数调用的区别
- Python的扩展接口[2] -> 动态链接库DLL[1] -> 组件对象模型 COM 的 Python 调用