大家都只ActiveX在web中可以通過object 標籤來聲明,並通過javascript等指令碼代碼來進行操作,但有些時候我們希望在服務端在操作ActiveX,特別是包含一些複雜的商務邏輯的或要對大資料量進行操作的。
通常某些控制項是可以通過添加引用=》COM,使用Visual Studio來產生封裝類來進行調用,但有些則不行,封裝類可以進行初始化,但訪問屬性或方法時都會運行報錯,錯誤資訊為“災難性故障 (異常來自 HRESULT:0x8000FFFF (E_UNEXPECTED))”。此時若在Winform中使用採用拖控制項的形式則可以啟動並執行,當然不在Form中拖控制項直接後台寫代碼new一個對象肯定也是同樣報錯的。網路上提問的也很多,許多說控制項未註冊,還有人說Win7的原因,有人說的著邊一點就是可能控制項需要一個容器,但問題是怎麼建立一個容器和銷毀容器呢?Winform中可以通過一個隱藏的Form來繞道解決,在Web中就不行了。
在Winform中,拖一個COM控制項到介面上的時候會添加2個引用,以Spread COM控制項為例,為添加FPSpreadADO和AxFPSpreadADO兩個Dll引用(新產生在Debug的obj檔案夾下),其中FPSpreadADO是產生的封裝類,AxFpSpreadADO是派生與AxHost的類,AxHost的作用就是封裝 ActiveX 控制項,並將其作為功能完全的 Windows 表單控制項進行公開。
在Web裡首先要做的也是產生這個Dll引用,可以通過上述在Winform拖控制項利用Visual Studio來產生DLL也可以使用Windows 表單 ActiveX 控制項匯入程式 (Aximp.exe)來產生,然後Web裡添加引用。
然後,AxFPSpreadADO.AxfpSpread cell = new AxFPSpreadADO.AxfpSpread(),此時會報錯,錯誤資訊為“當前線程不在單一執行緒 Apartment中,因此無法執行個體化 ActiveX 控制項的解決方案”,解決方案1為Main函數設定STAThread屬性(預設就是STAThread的),方法2為設定線程的ApartmentState,剛開始使用System.Threading.Thread.CurrentThread.SetApartmentState(System.Threading.ApartmentState.STA)來設定,但提示無法更改狀態,因為主線程此時早就已經啟動,運行中是無法改變STA、MTA的。所以我採取建立線程的來進行處理 <!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> System.Threading.Thread th = new System.Threading.Thread( new System.Threading.ParameterizedThreadStart(WorkMethod));
th.SetApartmentState(System.Threading.ApartmentState.STA);
th.Start();
最後,因為控制項操作完可能還要利用控制項操作後的狀態和資訊,因此我進行了線程的同步,示意如下: <!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> System.Threading.AutoResetEvent autoEvent = new System.Threading.AutoResetEvent( false );
System.Threading.Thread th = new System.Threading.Thread( new System.Threading.ParameterizedThreadStart(WorkMethod);
th.SetApartmentState(System.Threading.ApartmentState.STA);
th.Start(autoEvent);
autoEvent.WaitOne();
我所擔心的是,由於Web本身是多人並發訪問的,這樣阻塞線程會不會有問題,還有就是在服務端調用ActiveX會不會對伺服器造成很大的壓力。