ActiveX コントロールを Web サーバーで動かす
諸般の事情により、急遽 ActiveX コントロールを Web サーバーで動かす要件が発生しました。
本記事はその備忘録になります。そのためかなり読みづらい個所があると思いますが、ご了承ください。
リソースファイルの作成
ActiveX コントロールを使う場合、アプリケーションリソースを使うため、リソースファイルを用意する必要がある。
ちなみに ActiveX コントロールはシリアライズ用のインターフェースの実装が義務付けられているため、シリアライズされたデータがリソースファイルに格納される。これがないと ActiveX コントロールのインスタンスを生成できない。
まず Form を用意し、アプリケーションで必要な ActiveX を Form に貼りつける。
次に ActiveX を使用するクラスと同じ名前のリソースファイルを作成する。
Form のリソースファイルを XML エディタで開くと以下のようなデータが存在する筈である。
<data name="HogeHoge.OcxState" mimetype="application/x-microsoft.net.object.binary.base64"> <value> AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACFTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5BeEhvc3QrU3RhdGUBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAtwAAAAIB AAAAAQAAAAAAAAAAAAAAAKIAAAAAAwAACAAAAAAABQAAAAAAAADwPwMAAAAAAAUAAAAAAAAAAAAIAAIA AAAAAAMAAQAAAAsA//8DAAAAAAALAP//CAACAAAAAAADADIAAAALAAAACAAKAAAAZgB1AGwAbAAAAAsA AAALAAAACwD//wsA//8LAAAACAACAAAAAAAIAAIAAAAAAAgAAgAAAAAACAACAAAAAAALAAAAwAcAAGEC AAAL </value> </data>
「○○.OcxState」の部分をコピーし、クラス名.resx を開いて
ComponentResourceManager によるリソースの取得
次に ActiveX コントロールのインスタンス生成であるが、ComponentResourceManager を使ってリソースを取得する。
Dim resources As New ComponentResourceManager(GetType(HogeHoge)) _hogeObj = New AxHogeHogeLib.AxObject() CType(_hogeObj, ISupportInitialize).BeginInit() _hogeObj.OcxState = CType(_resources.GetObject("HogeHoge.OcxState"), AxHost.State) _hogeObj.CreateControl() ' 以下、プロパティの初期設定を行う ' ・・・・・・・ CType(_hogeObj, ISupportInitialize).EndInit()
AspCompat属性の設定によるページのシングルスレッド化
ActiveX の生成はシングルスレッドアパートメント(STA) でしか生成できないため、、@Pageディレクティブの AspCompat 属性に True を設定し、Web ページ自体を STA で動作するように変更する。
<%@ Page Language="vb" AspCompat="true"・・・・・・ %>
これで、以下のような感じで ASP.NET でActiveX コントロールが利用できる。
sample.aspx
<%@ Page Language="vb" AutoEventWireup="false" AspCompat="true" CodeBehind="result.aspx.vb" Inherits="WebApplication1.sample" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <asp:Label ID="lblTallCharge" runat="server" Text="0" /> </form> </body> </html>
sample.aspx.vb
Partial Public Class sample Inherits System.Web.UI.Page #Region "イベント" ''' <summary> ''' ページロード時のイベントハンドラ ''' </summary> Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load If (Page.PreviousPage IsNot Nothing) Then ' 他ページからのポストバック If (Page.PreviousPage.IsCrossPagePostBack) Then _start = CType(Page.PreviousPage.FindControl("txtStart"), TextBox).Text _goal = CType(Page.PreviousPage.FindControl("txtGoal"), TextBox).Text Try Using hogehoge As New HogeClass() Dim toll As Integer = hogehoge.GetTallCharge(_start, _goal) lblTallCharge.Text = String.Format("{0:#,##0}", toll) End Using Catch ex As Exception lblTallCharge.Text = _ ex.Message + vbCrLf + _ "サーバーで障害が発生しました。しばらくお待ちください。" End Try End If End If End Sub #End Region End Class
以下は Page クラスで呼び出す ActiveX コントロールをラップしたクラス。リソースファイル「HogeClass.resx」を同じフォルダに作成し、ActiveX コントロールで使うリソースを用意しておく。
HogeClass.vb
Imports System.ComponentModel Imports System.Windows.Forms Imports AxHogeHogeLib ''' <summary> ''' 高速料金算出クラス ''' </summary> ''' <remarks>高速料金を算出します。</remarks> Public Class HogeClass Implements IDisposable #Region "フィールド" ''' <summary>経路検索用 ActiveX オブジェクト</summary> Private WithEvents _hogeObj As AxHogeHogeLib.AxObject ''' <summary>重複する呼び出しを検出するには</summary> Private _disposedValue As Boolean = False #End Region #Region "コンストラクタ・デストラクタ" ''' <summary> ''' コンストラクタ ''' </summary> Public Sub New() Try Me.InitializeComponent() Catch ex As Exception Throw End Try End Sub ''' <summary> ''' リソースを解放します。 ''' </summary> Protected Overridable Sub Dispose(ByVal disposing As Boolean) If (_disposedValue = False) Then If (disposing) Then ' TODO: 他の状態を解放します (マネージ オブジェクト)。 End If If (_hogeObj IsNot Nothing) Then _hogeObj.Dispose() End If End If _disposedValue = True End Sub ''' <summary> ''' リソースを解放します。 ''' </summary> Public Sub Dispose() Implements IDisposable.Dispose Me.Dispose(True) GC.SuppressFinalize(Me) End Sub #End Region #Region "メソッド" ''' <summary> ''' 経路検索用コントロールを初期化します。 ''' </summary> Private Sub InitializeComponent() Try Dim resources As New ComponentResourceManager(GetType(HogeClass)) _hogeObj = New AxHogeHogeLib.AxObject() CType(_hogeObj, ISupportInitialize).BeginInit() _hogeObj.OcxState = CType(_resources.GetObject("HogeHoge.OcxState"), AxHost.State) _hogeObj.CreateControl() ' 以下、プロパティの初期設定を行う ' ・・・・・・・ CType(_hogeObj, ISupportInitialize).EndInit() Catch ex As Exception Throw End Try End Sub ''' <summary> ''' 高速料金を検出します。 ''' </summary> ''' <param name="start">出発地</param> ''' <param name="goal">目的地</param> ''' <returns>算出された高速料金</returns> Public Function GetTallCharge(ByVal start As String, ByVal goal As String) As Integer Dim ret As Integer = 0 Try ret = _hogeObj.GetTollWayCharge(start, goal) Catch ex As Exception Throw End Try Return ret End Function #End Region End Class