在VC++中使用Flash界面

最近的一個項目,想通過在VC中嵌入Flash的方式實現程序界面。以前曾經做過Flex的B/S項目,知道一些Flash和IE瀏覽器之間的工作方式。可是接觸了以ActiveX方式實現的Flash編程時,自然而然想當然的走了很多的彎路。很多貌似很複雜的問題,在繞了很多的圈子之後才發現,原來實現起來往往只需要一行代碼。項目還需進行,特意在此把心得記錄下來。
 
一、Flash同VC之間的數據通訊。
同大多數的ActiveX控件一樣,VC爲Flash實現了一個CWnd的包裝:CShockwaveFlash,該類實現了Flash ActiveX控件的所有功能。在AS3問世之前,Flash同宿主之間的通訊只有FSCommand一種方式,而且是異步的,更沒有返回值可言。因爲項目中需要VC爲Flash提供大量的數據庫查詢,返回結果通過XML進行傳遞。因此,FSCommand無疑是不方便的。
 
AS3推出的外部API調用方式:ExternalInterface,極大的簡化了編程方式。ExternaleInterface是同步的調用,並可以返回調用結果。需要說明的是,同步調用是以犧牲性能爲代價的,因爲這涉及到大量的CPU週期佔用)。我曾經在Flex項目中,利用ExternalInterface實現了IFrame在Flash的嵌入調用,從而達到在Flash中顯示HTML的問題。
 
CShockwaveFlash爲ExternalInterface提供了一個事件接收器(event sink):FlashCall。FlashCall事件只有一個參數:request,而且我們會發現,在Flash中通過ExternalInterface的調用,是通過XML的方式進行封裝,然後傳遞到request中的。爲了獲得調用的方法名和參數,你必須解析request封裝的XML包。
 
不過奇怪的是,處理FlashCall事件的是一個void方法。要返回數據,你需要調用SetReturnValue方法。返回的數據也必須是XML格式,且必須符合Flash的規範。如果要返回XML結果集,把XML封裝到<string></string>中,然後在Flash中通過new XML(str)的方式動態生成。
 
二、屏蔽Flash的右鍵菜單
這是個惱人的問題,我不希望用戶在軟件界面中彈出Flash右鍵菜單。在VC中,雖然Flash控件提供了SetMenu方法,通過傳入FALSE屏蔽大部分的菜單項,但遺憾的是,“關於”和“設置”菜單無法去掉。
 
爲了實現這個功能,我查閱了大量的資料。按照一般的想法,右鍵菜單的生成應該經過某種消息處理的流程。我先是重載了CShockwaveFlash類的WndProc方法,並在其中跟蹤消息流,結果造成IDE死機。我做出了一個錯誤的決定,我認爲這個消息一定可以在其它地方截獲,於是我又費了很大的周折,特意實現了自己的CControlSite類,結果依然讓人失望。
 
後來下載了一個Delphi下的TShockwaveFlashEx組件,才發現該組件是通過截獲組件的WM_RBUTTONDOWN消息實現的菜單屏蔽。這就是說,讓用戶的右鍵消息乾脆不傳到Flash控件中去。簡單而直接的方法。
 
在VC中實現起來更簡單些。直接從CShockwaveFlash派生自己的類(不建議直接修改CShowwaveFlash類),然後捕獲WM_RBUTTONDOWN消息,直接在消息處理函數中註釋掉父類的方法調用。然後修改Flash對象的類型爲你的派生類即可。
 
甚至可以更簡單些。直接在對話框中響應WM_MOUSEACTIVATE消息,然後在處理函數中判斷message參數的值,如果是WM_RBUTTONDOWN,則返回MA_ACTIVATEANDEAT(激活控件,吃掉消息。http://msdn2.microsoft.com/en-us/library/ms645612.aspx)。
 
三、調整窗口大小時防止Flash控件閃爍
在Dialog的WM_SIZE響應中,把Flash控件佈滿整個窗口。可是這個簡單的實現卻造成了Flash界面的頻繁閃爍。在Delphi的TShockwaveFlashEx組件中,作者是通過覆蓋組件的CreateWnd方法實現的,在對話框Resize事件中,調用這個重載的CreateWnd方法。
 
可是,在VC中如何實現呢?爲此,我在google上苦苦搜索了好幾天。關於ActiveX控件閃爍的問題,網上有很多的解決方案。很多方案都是建議同時重載控件和對話框擦除背景事件,然後寫一些代碼防止控件重繪自身。也有一些方法是通過GDI的思路,在內存中通過bitblt的方式避免閃爍。看到最後很傷心,怎麼會這麼麻煩呢。
 
今天在網上找到一篇文章:解決Windows 程序界面閃爍問題的一些經驗,文中講到造成界面閃爍的第二個原因:

複雜的界面有多層窗口組成,當windows在窗口改變大小的時候是先重畫父窗口,然後重畫子窗口,子父窗口重畫的過程一般無法在一個刷新週期內完成,所以會呈現閃爍。我們知道父窗口上被子窗口擋住的部分其實沒必要重畫的。

解決方法:給窗口加個風格 WS_CLIPCHILDREN ,這樣父窗口上被子窗口擋住的部分就不會重畫了。如果同級窗口之間有重疊,那麼需要再加上 WS_CLIPSIBLINGS 風格

 

我趕緊到項目中把Flash對話框的窗口風格加上WS_CLIPCHILDREN,編譯後運行,成功了!感謝作者,讓我終於睡了一個安穩覺。
 
四、DEBUG狀態是總是報Assertion失敗。
這個問題困擾了我一整天。我的系統上安裝了Flex SDK,因此,註冊的Flash控件是調試版。不知什麼原因,在每次關閉對話框之後,系統總是報cmdtarget.cpp文件中的控件引用值不爲1錯誤,從而造成斷言失敗。
 
我以爲是代碼的問題,重建了一個項目,什麼代碼都沒寫。運行,關閉,斷言錯誤。因爲之前的VC出現了一個奇怪的問題:打開對話框命令總是出現非法操作。反覆重裝VC都不能解決,最後在網上看到可能是安裝的visio 2003衝突,卸載visio 2003後問題解決。我開始懷疑是不是我之前的折騰把系統搞亂掉了。我又重裝了一次VC,再次編譯運行,問題再次出現。我都快瘋了。
 
在沒瘋之前,我決定到同事的電腦上試一下。生成的程序運行沒有問題。把我生成的代碼拷貝過去運行,沒有問題。我突然意識到,是不是Flash控件的問題。卸載重裝後,問題解決。我的天!
 
(待續。。。)
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章