ActiveX に IObjectSafety を実装して 警告回避

0 件のコメント

今回は ActiveX に 安全であること を示す実装を行うことで、IEの 警告表示 を回避してみる。 ちなみに、実装は C# (自分が分かる範囲だからという軽い理由…)。

自分が知る限り、ActiveX の 警告回避 は以下のどれかでなかろうかと…思ってる。 そのうち、今回は「ActiveX に安全マークをつける」方法のうち、「コード上に実装する」方法。

  • ActiveXにデジタル署名する
    • 一般的な認証局で発行したデジタル署名を利用
    • オレオレ認証局で発行したデジタル署名を利用
  • ActiveXを登録時に安全マークをつける
    • コード上に実装する
    • レジストリに"事前承認済み"書き込む(→詳細
    • レジストリに"安全マーク"書き込む(→詳細

さて、前置きが長くなりましたが…これから実装を始めます。

実装はいたって単純で、 「IObjectSafety インターフェース」と「IObjectSafety 実装」をコピペして、「IObjectSafety 実装」を継承するだけ。
さて、その「IObjectSafety インターフェース」と「IObjectSafety 実装」についてを以下に載せます。

IObjectSafety.cs

namespace Sample.ActiveXPlugIn
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;

    [ComImport, Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
        [PreserveSig]
        uint GetInterfaceSafetyOptions(
                ref Guid riid,
                [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions,
                [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);

        [PreserveSig]
        uint SetInterfaceSafetyOptions(
                ref Guid riid,
                [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask,
                [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
    }
}

COM 関係が利用したいので、System.Runtime.InteropServices 名前空間を追加します。
属性をいくつか付けるのですが、COM の実装に合わせるため、GUID "CB5BDC81-93C1-11CF-8F20-00805F2CD064" も含めて、 まったく同じ属性をつけます。 …というか、"CB5BDC81-93C1-11CF-8F20-00805F2CD064" が安全マークを示すインターフェースの実態のようです。

IObjectSafetyTLB.cs

namespace Sample.ActiveXPlugIn
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    public class IObjectSafetyTLB : IObjectSafety
    {
        // ---------------------------------------------------
        // 定数
        // ---------------------------------------------------
        private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
        private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
        private const int INTERFACE_USES_DISPEX = 0x00000004;
        private const int INTERFACE_USES_SECURITY_MANAGER = 0x00000008;
        private const uint S_OK = 0x00000000;
        private const uint E_NOINTERFACE = 0x80004002;
        private const uint E_FAIL = 0x80004005;

        // ---------------------------------------------------
        // メンバ関数
        // ---------------------------------------------------
        public uint GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
        {
            return S_OK;
        }

        public uint SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
        {
            return S_OK;
        }
    }
}

IObjectSafety インターフェースを実装する実態クラスになります。
本来は、引き渡された参照データ(pdwSupportedOptions, pdwEnabledOptionsとか…)を参考にイロイロこねくり回して、 S_OK, E_NOINTERFACE, E_FAIL のどれかを返すようです。 が、面倒くさいのとよく分からないとを理由に無条件に S_OK として使わせてもらいます。
ちなみに、その他の定数周りはインターネットから拾ってきたので、怪しいです…。。

あとは、IObjectSafetyTLB クラス を plugin にしたいクラスに対して継承させてあげればOK。

IObjextSafetyTLB を継承した サンプルコード

namespace Sample.ActiveXPlugIn
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Windows.Forms;

    [Guid("YOURGUID-0000-0000-0000-000000000000")]
    [ComSourceInterfaces(typeof(IMyFormEvent))]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("Sample.ActiveXPlugIn.MyForm")]
    public class MyForm : IObjectSafetyTLB, IMyFormMethod
    {
        // IE プラグイン の実装。
    }
}

さすがにとは思いますが… プラグインのGUID"YOURGUID-0000-0000-0000-000000000000"や名前空間"Sample.ActiveXPlugIn"、 プラグイン実態クラス名"MyForm"、プラグインインターフェース名"IMyFormEvent", "IMyFormMethod" などは任意に読み替え、書き換えてください。

今回、参考にさせていただいた情報源は以下の通りです。