在MFC中使用純COM方式來(lái)操縱Flash OCX (IShockwaveFlash)
2008-12-15
5130
小小貝,小小貝,小小貝,小小貝,小小貝,小小貝,小小貝,小小貝,小小貝,小小貝,小小貝,小小貝,小小貝,小小貝

1. MFC中的控件(jiàn)(OCX)包裝類

在VC++環境中,使用OCX會變得(de)比較簡單和快(kuài)捷。

在Dialog中插入ActiveX,如(rú):Shockwave Flash Object。

在建立了Dialog的類之後,爲剛才插入的Flash 控件(jiàn)添加變量,

MFC會自(zì)動幫我們生(shēng)成兩個文件(jiàn):CShockwaveFlash1.h和CShockwaveFlash1.cpp有了這兩個文件(jiàn),就(jiù)可(kě)以很容易控制Flash了。

2. 通過MIDL生(shēng)成TLB文件(jiàn)

MFC包裝類固然簡單,但(dàn)很明顯缺乏一些高級的功能,此時就(jiù)需要采用純COM的方式了。

首先使用OLE/COM Object Viewer來(lái)找到Shockwave Flash Object,

點擊右鍵“View Type Information”,在彈出的界面中,點擊“save as”将信息保存爲 SWF.IDL文件(jiàn),然後在打開VS提供的工(gōng)具:“Visual Studio 2008 命令提示”,進入DOS界面,切換到SWF.IDL所在的目錄,執行如(rú)下命令:

MIDL SWF.IDL /tlb SWF.tlb,即可(kě)生(shēng)成tlb文件(jiàn)。

如(rú)果生(shēng)成過程有錯,提示“error MIDL2110 : end of file found in string”,可(kě)以這樣做:将前面打開的界面中(“View Type Information”)的内容拷貝,然後手動新建一個SWF.IDL的文件(jiàn),将拷貝的内容粘貼入,再次執行MIDL命令。

接下來(lái)在你(nǐ)的VC++項目中:#import  "SWF.tlb",編譯之,即會在debug或者release。

目錄下面生(shēng)成tlh(頭文件(jiàn),header)和tli文件(jiàn)(實現文件(jiàn),implementation)。

注意,在tlh文件(jiàn)的末尾處已經包含了tli文件(jiàn)。

當然也可(kě)以采用下面叙述的方式生(shēng)成。

3. 相(xiàng)關概念

多數情況下,生(shēng)成的com組件(jiàn)DLL/EXE/OCX已經包含了類型庫信息(type information),但(dàn)當你(nǐ)的com程序足夠大(dà),可(kě)能需要分(fēn)離(lí)類型庫信息,此時考慮生(shēng)成tlb[/B]文件(jiàn),單獨存放(fàng)類型庫。

此時使用:#import "XXX.tlb",然後編譯之,也會在debug或者release下面産生(shēng) XXX.tli和XXX.tlh文件(jiàn)。

tlh和tli文件(jiàn)實際上是對com接口及其屬性方法的封裝類,其中tlh[/B]相(xiàng)當于類型申明(頭文件(jiàn)),tli相(xiàng)當于定義實現(CPP文件(jiàn)),這裡(lǐ)的實現完全是封裝方法的實現,而不是com接口方法的實現。

如(rú)下例:

inline int IShockwaveFlash::GetQuality ( ) {
int _result = 0;
HRESULT _hr = get_Quality(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}


其中get_Quality的真正實現實際上在XXX.ocx或者XXX.dll中。

4. 開始創建IShockwaveFlash 

爲了簡單起見(jiàn),就(jiù)不使用那麽麻煩的方法了,直接這樣:

#import "C:WINDOWSsystem32MacromedFlashFlDbg9f.ocx"  
raw_interfaces_only, /* Don't add raw_ to method names */
raw_native_types, /* Don't map to DTC smart types */  
named_guids, /* Named guids and declspecs */  
no_namespace /* Don't wrap with C++ name space */ 


如(rú)前述會自(zì)動在debug目錄下面生(shēng)成tlh和tli文件(jiàn),不需要在工(gōng)程屬性裡(lǐ)面加入lib,也不要include什麽,很方便。

接下來(lái),構造、析構:


其中isf和ivo是成員(yuán)變量(在.h中聲明):

IShockwaveFlash * isf;
IViewObject2 * ivo;


再初始化接口:

HRESULT CFlashHelper::Init(BSTR fileName)
{
HRESULT hr;
JIF(CoCreateInstance(__uuidof(ShockwaveFlash),
NULL,CLSCTX_INPROC_SERVER,
__uuidof(IShockwaveFlash),(void **)&isf));
JIF(isf->QueryInterface(__uuidof(IViewObject2),(void **)&ivo));
AtlAxAttachControl(isf,theApp.m_pFlashPlayerDlg->m_hWnd,NULL);
isf->put_Movie(fileName);
return S_OK;
}


其中JIF是一個宏:

#define JIF(x) if (FAILED(hr=(x)))
{TRACE(TEXT("FAILED(hr=0x%x) in ") TEXT(#x) TEXT(" "), hr); return hr;}


這裡(lǐ)還(hái)要使用一點點ATL,ATL做COM這方面的工(gōng)作(zuò)在行些。

故,要在工(gōng)程屬性中,設置“動态使用ATL”,在這個cpp文件(jiàn)中,包含如(rú)下頭文件(jiàn):

#include <atlbase.h>
#include <atlcom.h>
#include <atlctl.h>


上面的代碼中還(hái)采用了一種比較簡單的方法,即:

AtlAxAttachControl(isf,theApp.m_pFlashPlayerDlg->m_hWnd,NULL);


傳統的做法是先用CAxWindow創建窗(chuāng)口,然後采用其QueryControl方法得(de)到IUnknown接口,

再采用其QueryInterface,得(de)到IShockwaveFlash,代碼大(dà)概如(rú)下:

HRESULT CFlash::Create(LPRECT lpRect) {
HRESULT hr = S_OK;
AtlAxWinInit();
m_pAxWin = new CAxWindow();
m_hwnd = m_pAxWin->Create(NULL, lpRect, g_szCLSID_ShockwaveFlash, 0);
if (!m_hwnd)
{
return E_FAIL;
}
IUnknown *pUk = NULL;
hr = m_pAxWin->QueryControl(&pUk);
if (FAILED(hr))
{
return hr;
}
m_lWidth = lpRect->right-lpRect->left;
m_lHeight = lpRect->bottom - lpRect->top;
hr = pUk->QueryInterface(IID_IShockwaveFlash,(void**)&m_pShockwaveFlash);
pUk->Release();
return hr;
}


但(dàn)這個工(gōng)程既然是MFC的工(gōng)程,就(jiù)不想使用CAxWindow來(lái)創建窗(chuāng)口,所以采用MFC來(lái)建立的Dialog,

然後AtlAxAttachControl(isf,theApp.m_pFlashPlayerDlg->m_hWnd,NULL);就(jiù)可(kě)以了。

通過上面的方法就(jiù)得(de)到了IShockwaveFlash和IViewObject2了,接下來(lái)怎麽做就(jiù)随你(nǐ)了。

5. 其他(tā)要注意

如(rú)果你(nǐ)同時在使用GDI+,那麽可(kě)能會要加入如(rú)下代碼:

// for GDI+
#include <comdef.h>
#ifndef ULONG_PTR
#define ULONG_PTR unsigned long *
#include "GdiPlus.h"
using namespace Gdiplus;
// end for GDI+
#endif


這樣編譯的時候就(jiù)會出現如(rú)下的錯誤:

錯誤 8 error C2440: “初始化”: 無法從(cóng)“int”轉換爲“unsigned long *” c:program filesmicrosoft visual studio 9.0vcatlmfcincludeatlwin.h 523 LEDEngine

錯誤 9 error C2664: “GlobalAlloc”: 不能将參數 2 從(cóng)“unsigned long *”轉換爲“SIZE_T” c:program filesmicrosoft visual studio

9.0vcatlmfcincludeatlwin.h 570 LEDEngine

其實是因爲ULONG_PTR這個數據類型,這個東西在ATL中也有定義,而且在altwin.h中使用了,但(dàn)是其實在ATL中:

ULONG_PTR是這樣定義的:typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;

在GDI+中式這樣定義的:#define ULONG_PTR unsigned long *

這樣就(jiù)有沖突了,故如(rú)要同時使用GDI+和ATL,一定要這樣聲明:

// for GDI+
#include <comdef.h>
#include "GdiPlus.h"
using namespace Gdiplus;
// end for GDI+


好了,這個話(huà)題就(jiù)說(shuō)到這裡(lǐ)。

 

關鍵字:MFC中使用純COM方式來(lái)操縱Flash,OCX,貝一科(kē)技知識庫