問題:調用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 ;
}