有時候,我們需要在一個容器中插入各種不同的對象,比如,QQ聊天對話框裏可以插入各種靜態和動態的圖片,甚至還可以插入flash文件,這些都是通過OLE技術來實現的。OLE技術是基於COM的,而COM又是非常複雜的東西,想要學習COM得花很多的時間,《COM技術內幕》,《COM原理和應用》,《INSIDE OLE 2》都是非常好的學習COM和OLE的書,但要把這些書啃完,弄懂,幾個月甚至半年都過去了。學習COM是一個鬱悶、漫長的過程,雖然進步很慢,但堅持下去會很有意思。如果我們僅僅是使用別人的組件,並將別人的組件插入到自己的容器中,也不是很複雜,下面就是一個例子。
我們以MSDN的ATL Tutorial中創建的組件做爲我們要插入的對象(該組件的創建請看MSDN)。
1、創建一個COM客戶端基於對話框的工程,命名爲Client,按默認選項設置工程。
2、在主對話框中加入一個RichEdit控件,用ClassWizard爲添加一個表示該控件的變量,爲m_re,記住類型設爲control。爲主對話框加入一個按鈕,ID設爲IDC_INSERTPOLYGON,Caption設置爲InsertPolygon。
3、在CClientApp::InitInstance()函數中,在創建對話框的代碼前加入如下代碼:
if (AfxInitRichEdit() == FALSE)
{
return FALSE;
}
如果不加入上面的代碼,應用程序將無法運行。
4、在Client.cpp中添加頭文件
#include "..//Polygon.h" //DLL模塊頭文件
#include "..//Polygon_i.c" //接口定義
#include "Richole.h"
5、爲對話框類加入私有成員函數BOOL InsertPolygon(IRichEditOle* lpRichEditOle);將該函數定義如下:
BOOL CClientDlg::InsertPolygon(IRichEditOle* lpRichEditOle)
{
IStorage* lpStorage = NULL;//存儲接口
IOleObject* lpOleObject = NULL;//OLE對象
LPLOCKBYTES lpLockBytes = NULL;//LOCKBYTE
IOleClientSite* lpOleClientSite = NULL;
IPolyCtl* lpPolyCtl = NULL; //控件
CLSID clsid;
REOBJECT reobject;
HRESULT hr;
if(lpRichEditOle == NULL)
return FALSE;
//創建PolyCtl對象並獲取接口
hr = ::CoCreateInstance(CLSID_PolyCtl,NULL,CLSCTX_INPROC,IID_IPolyCtl,(LPVOID*)&lpPolyCtl);
if( lpPolyCtl == NULL )
{
return FALSE;
}
// USES_CONVERSION;
BOOL bRet = TRUE;
try{
hr = lpPolyCtl->QueryInterface(&lpOleObject);//獲得數據對象接口
if( hr != S_OK )
AfxThrowOleException(hr);
hr = lpOleObject->GetUserClassID(&clsid);
if ( hr != S_OK)
AfxThrowOleException(hr);
hr = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);//創建LOCKBYTE對象
if (hr != S_OK)
AfxThrowOleException(hr);
ASSERT(lpLockBytes != NULL);
hr = ::StgCreateDocfileOnILockBytes(lpLockBytes,//創建複合文檔
STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &lpStorage);
if (hr != S_OK)
{
VERIFY(lpLockBytes->Release() == 0);
lpLockBytes = NULL;
AfxThrowOleException(hr);
}
lpRichEditOle->GetClientSite(&lpOleClientSite);
ZeroMemory(&reobject, sizeof(REOBJECT));//初始化一個對象
reobject.cbStruct = sizeof(REOBJECT);
reobject.clsid = clsid;
reobject.cp = REO_CP_SELECTION;
reobject.dvaspect = DVASPECT_CONTENT;
reobject.dwFlags = REO_BELOWBASELINE;
reobject.poleobj = lpOleObject;
reobject.polesite = lpOleClientSite;
reobject.pstg = lpStorage;
hr = lpRichEditOle->InsertObject( &reobject );
if (hr != S_OK)
AfxThrowOleException(hr);
OleSetContainedObject(lpOleObject,TRUE);
}
catch( COleException* e )
{
TRACE(_T("OleException code:%d"),e->m_sc);
e->Delete();
bRet = FALSE;
}
// release the interface
if( lpPolyCtl != NULL ) lpPolyCtl->Release();
if( lpOleObject != NULL ) lpOleObject->Release();
if( lpOleClientSite != NULL ) lpOleClientSite->Release();
if( lpStorage != NULL ) lpStorage->Release();
return bRet;
}
6、爲InsertPolygon按鈕添加響應函數,定義如下:
void CClientDlg::OnInsertpolygon()
{
IRichEditOle* lpRichEditOle = NULL;
lpRichEditOle = m_re.GetIRichEditOle();
if (lpRichEditOle != NULL)
{
InsertPolygon(lpRichEditOle);
lpRichEditOle->Release();
}
}
7、運行效果圖如下:
如果你有自己的控件,可以按上述的方法插入。