6
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

C#でCOM In-Process Server

Posted at

概要

COM(Component Object Model)を使うと、プログラムをExcelやVBScriptなどから呼び出すことができる。
呼び出される側をCOMサーバ
、呼び出す側をCOMクライアントと呼ぶ。
COMサーバにはIn-Process ServerOut-Of-Process Serverの2種類に分けられる。

  • In-Process Server: 実体はDLL。単体では動作せず、クライアントから呼ばれた際に、クライアント下にインスタンスが生成される。
  • Out-Of-Process Server: 実体はEXE。単体で動作し、クライアントからアクセスできるインタフェースを提供。クライアントから呼ばれた際に、独立した別プロセスが立ち上がる。

Component Object Model

ここでは、In-Process ServerをC#で実装する方法を紹介する。

環境

  • Windows 10 Pro (Ver.1709)
  • Visual Studio 2017
  • .NET Framework 4.6.1

手順

ソリューション・プロジェクト作成

まずソリューションを作り、その下にC#プロジェクトを作る。
プロジェクト種別は**クラス ライブラリ(.NET Framework)**を選択する。

インタフェース作成

COMサーバのインタフェースを定義する。
外部からはこのインタフェース下のメソッドやプロパティを介してアクセスする事となる。

using System;
using System.Runtime.InteropServices;

namespace Sample
{
    [ComVisible(true)]
    [Guid("502262A7-19EB-4EC5-984C-8F010665A586")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface ITest
    {
        string ToUpper(string str);
    }
}
  • ComVisible属性は、指定したクラスやインタフェースをCOMから見えるようにするもの。
  • Guid属性は、唯一のIDを振るためのもの。この後の処理でGUIDがレジストリに登録されるので、必要。
  • Guidの生成は、Visual Studioの「ツール」->「GUIDの作成」から可能。
  • InterfaceType属性は、アクセス方法をIDispatchに限るかIUnknownに限るか、両方可能かを設定する。
  • 公開するため、アクセス指定子はpublicにする。

備考: IDispatchとIUnknown

  • IDispatch: 遅延バインディングを示す。クライアントはサーバーのインタフェースの情報を持たず、ProgId名とメソッド名を指定して呼び出して動的に解決する。CreateObjectを使う場合はこのケース。
  • IUnknown: 事前バインディングを示す。クライアントはサーバーのインタフェースの情報を持ち、それを使って呼び出す。
    サーバーのDLLを参照設定に入れる場合はこのケース。

クラス作成

COMサーバのクラスを作成する。

using System;
using System.Runtime.InteropServices;

namespace Sample
{
    [ComVisible(true)]
    [Guid("A2666F42-F50D-4F42-9CC7-D7F55300FD95")]
    [ProgId("Sample.Test")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Test : ITest
    {
        public string ToUpper(string str)
        {
            return str.ToUpper();
        }
    }
}
  • インタフェース同様、ComVisibleで公開する。
  • Guidは、インタフェースとは別のIDを新たに生成すること。
  • ProgId属性は、クライアントが呼び出す際に指定する名前の文字列を定義する。
  • ClassInterface属性は、インタフェースが明示的に指定されていない場合のデフォルトのアクセス方法を決める属性。今回はITestインタフェースを実装しているので、Noneを指定する。
  • 公開するため、アクセス指定子はpublicにする。

参考

In-process C# COM server (CSDllCOMServer)

アセンブリに署名

Properties -> 「署名」 を開き、「アセンブリに署名する」にチェックを入れ、キーファイルを作成する
(※これをしておかないと、後のRegAsm処理に失敗する)

ビルド

構成マネージャで、x86またはx64を選択した後、
プロジェクトをビルドし、dllファイルを生成する

RegAsm.exeでレジストリに登録する

作成したCOMサーバを利用可能にするには、レジストリに登録する必要がある。
その為の登録処理を行うプログラム「RegAsm.exe」が用意されている。

パスは以下の通り

  • 32bitの場合: C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe
  • 64bitの場合: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe

(なお、v4.0.30319の部分は.NET Frameworkのバージョンにより異なる)

管理者権限でPowerShell(またはコマンドプロンプト)を起動し、/codebaseオプションを付けてRegAsm.exeを実行する
(Sample.dllは対象のdll名)

> C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe /codebase Sample.dll
Microsoft .NET Framework Assembly Registration Utility 4.7.2556.0
for Microsoft .NET Framework Version 4.7.2556.0
Copyright (C) Microsoft Corporation.  All rights reserved.

型は正常に登録されました。

これで、登録が完了した

呼び出し

例えば、ExcelマクロやVBScriptでは、以下のように呼び出すことができる。

Sub TestCall()
  Dim ret As String
  Dim obj As Object
  Set obj = CreateObject("Sample.Test")
  
  ret = obj.ToUpper("abc")
  MsgBox (ret)
  
  Set obj = Nothing
End Sub

なお、COM In-Procサーバーは、呼び出し元のプラットフォーム(x86/x64)と呼び出し先が一致している必要がある?模様。
Excelからの呼び出しでは、x64のIn-Procサーバーを呼び出せず、
VBScriptからの呼び出しでは、x86のIn-Procサーバーを呼び出せなかった。

備考: RegAsmでレジストリに何が登録されるのか?

RegAsmを実行した後、regeditでレジストリを確認したところ、以下の項目が登録されていた。
なお、RegAsmを使わずに直接レジストリに同様の設定を行うこともできる。

キー 名前 データ 備考
HKEY_CLASSES_ROOT\作成したクラスのProgId (規定) 作成したクラスのProgId
HKEY_CLASSES_ROOT\作成したクラスのProgId\CLSID (規定) 作成したクラスのGUID
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\作成したクラスのGUID (規定) 作成したクラスのProgId x86のみ
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\作成したクラスのGUID\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29} (規定) (無し) x86のみ
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\作成したクラスのGUID\InProcServer32 (規定) mscoree.dll x86のみ
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\作成したクラスのGUID\InprocServer32 Assembly アセンブリ名、Culture, Version, PublicKeyToken x86のみ
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\作成したクラスのGUID\InprocServer32 Class 作成したクラスのProgId x86のみ
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\作成したクラスのGUID\InprocServer32 CodeBase dllのパス x86のみ
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\作成したクラスのGUID\InprocServer32 RuntimeVersion v4.0.30319 x86のみ
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\作成したクラスのGUID\InprocServer32 ThreadingModel Both x86のみ
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\作成したクラスのGUID\ProgId (規定) 作成したクラスのProgId x86のみ
HKEY_CLASSES_ROOT\CLSID\作成したクラスのGUID (規定) 作成したクラスのProgId x64のみ
HKEY_CLASSES_ROOT\CLSID\作成したクラスのGUID\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29} (規定) (無し) x64のみ
HKEY_CLASSES_ROOT\CLSID\作成したクラスのGUID\InProcServer32 (規定) mscoree.dll x64のみ
HKEY_CLASSES_ROOT\CLSID\作成したクラスのGUID\InprocServer32 Assembly アセンブリ名、Culture, Version, PublicKeyToken x64のみ
HKEY_CLASSES_ROOT\CLSID\作成したクラスのGUID\InprocServer32 Class 作成したクラスのProgId x64のみ
HKEY_CLASSES_ROOT\CLSID\作成したクラスのGUID\InprocServer32 CodeBase dllのパス x64のみ
HKEY_CLASSES_ROOT\CLSID\作成したクラスのGUID\InprocServer32 RuntimeVersion v4.0.30319 x64のみ
HKEY_CLASSES_ROOT\CLSID\作成したクラスのGUID\InprocServer32 ThreadingModel Both x64のみ
HKEY_CLASSES_ROOT\CLSID\作成したクラスのGUID\ProgId (規定) 作成したクラスのProgId x64のみ
6
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?