Add COM and ActiveX Support in .NET Compact Framework Using Odyssey Software CFCOM(中文)
Andy Sjöström
businessanyplace.net
September 2003
Applies to:
Microsoft® .NET Compact Framework 1.0
Microsoft Visual Studio® .NET 2003
Odyssey Software CFCOM 1.0
Microsoft Windows Mobile™–based Pocket PC
aawolf 的話:本月給大家帶來的是一篇上了MSDN首頁的文章,讀者評價為7。原文發于2003年9月8日,而且話題也是大家比較關心的在CF下如何調用COM和ActiveX元件。是以,老狼抽出一個下午的時間翻譯過來,希望的是大家能了解目前最新的技術,并與之保持同步。但老狼畢竟是個程式員而不是專業譯者,水準粗糙不說,也沒有很多時間翻譯文章,是以還是希望大家能多讀寫英文資料,老狼的翻譯僅做參考。原文的連接配接如下:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnppc2k3/html/cfcom.asp
摘要:學習在Visual C#中如果将COM和ActiveX支援添加到.NET Compact Framework應用程式中來。還有,如何在.NET Compact Framework應用程式中如何使用Macromedia Flash Player 6 for a Microsoft Windows Mobile–based Pocket PC。
背景:COM和ActiveX的互用性在full .NET Framework中是可用的。受管.NET Compact Framework代碼可以使用Platform Invoke (P/Invoke)調用DLL中的非受管代碼,但是在.NET Compact Framework中對COM和ActiveX的支援是不可用的。Odyssey Software的 CFCOM作為介入層将COM對象和ActiveX控件作為.NET equivalences暴露給.NET Compact Framework應用程式,使用一個大約隻有30K的memory foot print。
Odyssey Software CFCOM能夠透明地通路控件(比如Windows Media Player)和對象(比如Pocket Outlook Object Model 和 ADOCE),和實際上任何第三方的COM或者ActiveX元件。CFCOM可以通過Odyssey Software得到許可,盡管文章中的代碼示例可以通過license key被建立在代碼中。
Download cfcom.exe from the Microsoft Download Center.
Contents
Introduction
Odyssey Software CFCOM
Code Walk-through
Macromedia Flash 6 Player for Pocket PC
Flash Anyplace
Flash Anyplace Code Walk-through
Conclusion
Introduction
姑且不論大小,.NET Compact Framework的命名空間和類的結構層次和完整的.NET framework是十分相似的。當然,因為體積和執行效率的問題,去掉了.NET Framework的一些特性。其中之一就是COM互用性。Microsoft® Windows® CE和Pocket PC的許多核心子產品都是作為COM對象和ActiveX控件實作的,比如連通性、消息、通訊、圖形、媒體、對象存儲和個人資訊管理(PIM)。也有許多第三方COM和ActiveX控件被用在移動裝置上,例如GPS、圖表、安全和連通性。Platform Invoke (P/Invoke)存在于System.Runtime.InteropServices命名空間中,可以用來調用簡單的非受管代碼函數。第三方有效提供者的一個執行個體是Sapphire Solutions Ltd (http://www.sapphire-solutions.co.uk/),使用存在的.NET Compact Framework服務是足夠的。Sapphire Solutions通過元件和源代碼遠端通路服務、編密碼等等。Sapphire Solutions元件是通過Platform Invoke加載到.NET Compact Framework代碼示例中的,使之更早地開始使用這些代碼。
調用更複雜的非受管代碼函數需要需要一個大量的複雜編碼,包括更多有挑戰性的領域,比如marshalling。開發COM封裝往往是需要單一的基于函數的接口。使COM和ActiveX融合到受管代碼中是充滿挑戰的。
Odyssey Software CFCOM
Odyssey Software對于Windows CE開發者社群來說并不陌生。他們從1996年開始就已經在推動企業級移動應用程式開發方面扮演重要的角色了,他們的産品有CEfusion 和 ViaXML。公司連續為移動應用開發社群提供工具,這次他們帶來的是一個介于COM和Compact Framework中間的轉換層,可以使COM暴露等價于.NET的接口。CFCOM為COM和ActiveX轉換到Compact Framework應用程式提供廣泛的互用性。
CFCOM可以被看作一個使COM和.NET對象能夠運作在同一個應用程式中的封裝。一個Compact Framework對象被Common Language Runtime (CLR)限制在受管記憶體中,當一個COM對象儲存在非受管記憶體中。CFCOM實作了一個透明的轉換層,使受管和非受管元件可以互相作用:設定或取得屬性值,調用方法,捕捉COM事件,處理進階類型轉換函數(a k a marshalling)并從非受管代碼的異常事件中産生本地.NET異常。
對于開發者來說,CFCOM由三個檔案組成:
·
Odyssey.CFCOM.dll包含CFCOM運作時。
·
Odyssey.CFCOM.Design.dll提供Visual Studio的設計期支援。該檔案被安裝在C:/Program Files/Microsoft Visual Studio .NET 2003/CompactFrameworkSDK/ v1.0.5000/Windows CE/Designer目錄中。
·
Odyssey.CFCOM.1248.dll是本地(裝置支援)運作時元件。
圖一顯示ComObject和ComControl工具被添加到toolbox中。
Figure 1. ComObject and ComControl tools added to the toolboxOdyssey Software也包括一個示例Windows Media Player Wrapper Designer,開發者可以添加到toolbox中并在設計期設定屬性值。使用Windows Media Player 的Compact Framework應用程式可以被快速建立。
對于eMbedded Visual Basic開發者來說,CFCOM意味着他們能夠使用熟悉的COM對象和ActiveX元件,而不需要學習C/C++和P/Invoke。eMbedded Visual C++開發者可以繼續使用C++來寫他們應用程式的性能臨界(performance-critical)部分,而不用建立本地封裝并使用custom marshalling處理
Odyssey Software CFCOM的更多資訊,您可以讀Microsoft Case Study, COM Interop Library Gives Compact Framework Applications Easy Access to COM Components and ActiveX Controls.
Code Walk-through
CFCOM的設計思想就是近可能實作透明轉換。在使用ActvieX控件或COM對象前隻需要做兩件事。
· ActiveX控件或者COM對象的ProgID 或者 CLSID。
· 從Odyssey Software獲得的CFCOM 的license key。
在這之後,可以開始使用CFCOM的調用方法來使用元件了。下面的代碼顯示如何在一個Compact Framework應用程式中使用Windows Media Player。
License key在應用程式的主函數入口處被設定。
ComObject.AddLicense(CFCOM_LICENSEKEY);
單窗體(one-form)應用程式可以開始使用Windows Media Player。
public class frmMain : System.Windows.Forms.Form
{
private const string CFCOM_LICENSEKEY = " XXXXXXXXXXXXXXXXXXXXXXXXXX ";
public frmMain()
{
InitializeComponent();
mpc.ProgID = "WMPCEOCX.WMP";
mpc.Invoke("ShowControls", InvokeFlags.SetProperty, false);
mpc.Invoke("ShowAudioControls", InvokeFlags.SetProperty, false);
mpc.Invoke("ShowPositionControls", InvokeFlags.SetProperty, false);
mpc.Invoke("ShowTracker", InvokeFlags.SetProperty, false);
mpc.Invoke("ShowStatusBar", InvokeFlags.SetProperty, true);
mpc.Invoke("Autostart", InvokeFlags.SetProperty, true);
mpc.Invoke("Filename", InvokeFlags.SetProperty, "http://news.com.com/1604-2-966406-1.asx?msft_awe+win");
mpc.Invoke("SendMouseClickEvents", InvokeFlags.SetProperty, true);
mpc.ComObject.ComEvent += new ComEventHandler(mpc_COMEvent);
}
請注意如何設定ProgID,然後如何通過Invoke方法設定屬性。InvokeFlags enumeration包括SetProperty, GetProperty, 和 CallMethod。
更多關于這些代碼和如何在Compact Framework應用程式中添加多媒體的資訊請看,"Play Media with .NET CF using CFCOM" http://www.businessanyplace.net/?p=cfcommedia.
圖二顯示使用Windows Media Player ActiveX的應用程式。
Figure 2. Windows Media Player Active X controlMacromedia Flash 6 Player for Pocket PC
Macromedia已經退出了播放Macromedia Flash内容的免費Pocket PC播放器。Flash是一個流行的平台,用來釋出high profile content, movies,甚至可以用于移動應用程式。Flash開發團體是活躍的并在增長。基于Visual Studio .NET and the Compact Framework,開發者在移動應用程式使用Flash 容易得創造出奇異的内容和應用程式。Pocket PC player的個人免費版本可以在Macromedia Web伺服器上找到:http://www.macromedia.com/software/flashplayer/pocketpc/2002.html.
該播放器是一個ActiveX控件,大部分是用在Pocket Internet Explorer中,實體上作為flash.dll被安裝在/Windows/Macromedia目錄中。一旦播放器被安裝,使用者可以通過Pocket Internet Explorer觀看Macromedia Flash 内容。一種做法是将一個Flash内容檔案(.swf)和HTML檔案放在同一個目錄下,并打開HTML檔案。該HTML檔案顯示ActiveX控件如何被調用。下列片段來自HTML檔案:
<HTML>
<HEAD>
<TITLE>book</TITLE>
</HEAD>
<BODY bgcolor="#53695C">
<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=6,0,0,0"
ID=rapier4 WIDTH=230 HEIGHT=255>
<PARAM NAME=movie VALUE="book.swf">
<PARAM NAME=menu VALUE=false>
<PARAM NAME=quality VALUE=high>
<PARAM NAME=bgcolor VALUE=#53695C>
</OBJECT>
</BODY>
</HTML>
在
"PARAM"屬性後,
ActiveX控件被使用參數引用調用。叫做“book.swf”的電影被播放,Flash内容菜單被關閉,播放品質為高,背景色被設為
#53695C。
圖三顯示Pocket Internet Explorer中的效果。
Figure 3. Pocket PC Flash player in action這個例子中的Macromedia Flash content由來自flashenabled.com (http://www.flashenabled.com/)的Flash開發者Phillip Torrone設計。更多相似的例子和關于Pocket PC 和Macromedia Flash相關資訊可以檢視Pocket PC Flash (http://www.pocketpcflash.net/home.htm).
更多關于Falsh播放器參數的資訊,請看"Scripting with Flash Player and ActiveX" 來自Macromedia Web 伺服器: http://www.macromedia.com/support/flash/ts/documents/activex_script.htm.
下面讓我們來看如何在一個Compact Framework應用程式中使用Flash player.
Flash Anyplace
Flash Anyplace是一個使用CFCOM使用Flash ActiveX控件的應用程式。Flash Anyplace可以播放内容并使使用者控制如何播放内容。圖4顯示第一個窗體。
Figure 4. Flash player settings在這個窗體中,使用者可以設定播放哪個Flash檔案,并控制Flash 檔案播放的行為。第二個窗體(圖5)顯示實際的Flash檔案被播放。
Figure 5. Viewing the fileFlash Anyplace Code Walk-through
這個工程包含兩個窗體。當使用者在第一個窗體中點選“Play”按鈕時下列代碼被執行:
private void btnPlay_Click(object sender, System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
frmFlashAnyplacePlayer flashAnyplacePlayer = new frmFlashAnyplacePlayer(this, this.txtFlashFile.Text, this.cmbQuality.SelectedIndex, this.cmbScale.SelectedIndex, this.chkLoop.Checked, this.chkMenu.Checked, this.txtBackgroundColor.Text);
flashAnyplacePlayer.ShowDialog();
}
參數被傳遞給第二個窗體,一個CFCOM ComControl在這個窗體中。Macromedia Flash Player的ProgID是ShockwaveFlash.ShockwaveFlash。下面是這個窗體的初始化InitializeComponent部分:
this.flashPlayer = new Odyssey.CFCOM.ComControl();
this.flashPlayer.ProgID = "ShockwaveFlash.ShockwaveFlash";
像在Pocket Internet Explorer中播放Flash内容的HTML檔案中那樣使用CLSID建立也是可以的。這行将這麼寫:
this.flashPlayer.ProgID = "{D27CDB6E-AE6D-11cf-96B8-444553540000}";
注意license key在ComControl起作用前已經被設定。首先,在聲明中設定license key字元串。
private const string CFCOM_LICENSEKEY = "XUHXRATLAUVKL96EFVBH9BEUV7";
這個license key是CFCOM隻能使用Flash player(使用ProgID)并隻能用在這個工程中。AddLicense方法應該被優先放置在Application.Run中啟動窗體之前的位置。CFCOM将在每一個過程中查找這個許可。
static void Main()
{
// Set license key
ComControl.AddLicense(CFCOM_LICENSEKEY);
Application.Run(new frmFlashAnyplace());
}
如果Flash檔案在Internet上,使用URL作為電影位址。例如http://www.businessanyplace.net/files/FlashAnyplace.swf.如果Flash檔案定位在Pocket PC上,使用下面的格式:
file:///My%20Documents/mymovie.swf
Flash Anyplace工程将一個Flash檔案作為一個Content item,被安裝在應用程式目錄中。得到目前應用程式目錄并将這個Flash檔案作為預設值,下面的代碼會執行:
// Get application directory
string currentDir = new FileInfo(Assembly.GetExecutingAssembly().GetName().CodeBase).DirectoryName;
// Set default values
txtFlashFile.Text = @"file://" + currentDir + @"/book.swf";
第二個窗體的load事件通過CFCOM得到傳遞給Flash player的參數:
try
{
flashPlayer.Invoke("quality", InvokeFlags.SetProperty, quality);
flashPlayer.Invoke("bgcolor", InvokeFlags.SetProperty, backgroundColor);
flashPlayer.Invoke("scale", InvokeFlags.SetProperty, scale);
flashPlayer.Invoke("loop", InvokeFlags.SetProperty, loop);
flashPlayer.Invoke("menu", InvokeFlags.SetProperty, menu);
flashPlayer.Invoke("movie", InvokeFlags.SetProperty, flashFile);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
parentForm.Hide();
Cursor.Current = Cursors.Default;
}
如果我們嘗試将一個無效的參數名傳遞給Macromedia Flash Player,異常處理将傳回一個适當的異常。例如,當傳遞“movie1”作為一個屬性替代“movie”,CFCOM将抛出一個異常"0x80020006: DISP_E_UNKNOWNNAME."
最後,當使用者離開這個帶有Flash player的窗體,CFCOM ComControl需要被釋放:
private void frmFlashAnyplacePlayer_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
flashPlayer.Dispose();
parentForm.Show();
}
來自CFCOM的幫助檔案:“也許像CFCOM一樣簡單,有一個非常重要的問題需要被了解,即垃圾回收的不确定性,經常手工回收COM資源是必須的。ComObject.Dispose 和 ComControl.Dispose方法是成熟的。某些ActiveX控件,比如Windows Media Player,當他們在被垃圾回收釋放之前會出現一些未知的行為。”
Conclusion
Odyssey Software CFCOM 緻力于 Compact Framework 開發中一些非常有挑戰性的領域: ActiveX 和 COM 互用性。通過執行一個受管代碼和非受管代碼之間的轉換層,開發者可以緻力于向核心挑戰,進而給他們的客戶帶來正常的價值。