web-dev-qa-db-ja.com

単純なC#DLLをCOM相互運用コンポーネントに変える

C#DLLをVB6アプリケーションで使用できるCOM相互運用機能DLLにするにはどうすればよいですか?

65
Elena Lawrence

これは私がStackOverflowで見つけたいと思ったが、見つけることができなかった答えです。単純なC#dllをCOM dllに変換するのはかなり簡単であることがわかりました。

C#dllを作成するには

C#クラスプロジェクトでソリューションを作成します。クラスには、プロパティ/メソッドのインターフェイスとイベントのインターフェイスが必要です。 MSDN-COMクラスの例(C#プログラミングガイド) で説明されているように、GUID属性をクラスとインターフェイスに割り当てます。参照: MSDN-方法:COMシンクによって処理されるイベントを発生させる

[プロジェクトのプロパティ]> [アプリケーション]タブ> [アセンブリ情報]ボタン> [アセンブリCOMを表示]をオンにします。これにより、クラスCOMのすべてのパブリックメソッドが表示されます。

[プロジェクトのプロパティ]> [ビルド]タブ> [プラットフォームターゲット]をx86に設定します。

DLLを作成するために必要なことはそれだけです。 DLLを呼び出すには、登録する必要があります。

開発マシンでDLLを登録する

次のいずれかの方法でDLLを登録できます。

  • [プロジェクトのプロパティ]> [ビルド]タブ> [COM相互運用機能に登録]を確認します。これにより、ビルド時にDLLが自動的に登録されます。
  • RegAsmでDLLを手動で登録します。これにより、ビルドディレクトリではなく、選択したディレクトリにDLLを登録できます。これがメソッドです。使った。

    • しない[プロジェクトのプロパティ]> [ビルド]タブ> [COM相互運用機能に登録]をチェックします
    • DLLを登録するディレクトリにコピーします
    • 管理者権限とタイプでコマンドシェルを開きます

      RegAsm.exe -tlb -codebase mydll.dll
      

      RegAsm.exeは「C:\ Windows\Microsoft.NET\Framework\v2.0.50727」にありますが、「mydll.dll」はDLLの名前です。 tlbは「タイプライブラリの作成」を意味します。 codebaseは、「ディレクトリの場所をGACに配置されていないと仮定して、レジストリに書き込む」ことを意味します。

      RegAsmは、アセンブリに厳密な名前を付ける必要があるという警告を表示します。無視しても構いません。

      この時点で、VB6のCOM DLLへの参照を追加し、Intellisenseで参照して、通常のCOM DLLと同じように実行できるようになります。

InstallShieldでDLLをインストールする

InstallShieldを使用して、アプリケーションの他の部分と一緒にDLLをインストールする場合は、以下を実行します。

InstallShieldで、コンポーネントリストに新しいコンポーネントを追加します。コンポーネントを機能に関連付けることを忘れないでください。コンポーネントプロパティ「.NET COM Interop」をYesに設定します。

コンポーネントの[ファイル]セクションに.dllファイルを追加します。 「自己登録」プロパティをチェックしないでください。 .dllファイルを右クリックし、「キーファイルの設定」を選択します。

コンポーネントの[ファイル]セクションに.tlbファイルを追加します。 「自己登録」プロパティを確認します。

.Net Frameworkの正しいバージョンがターゲットPCに存在する必要があります。

それでおしまい。

86

@ Kieren Johnstone's answer の拡張として、クラスの変更に関する実用的なコード例が必要です:

から:

public class ApiCaller 
{

    public DellAsset GetDellAsset(string serviceTag, string apiKey)
    {
     ....
    }
}

public class DellAsset
{
    public string CountryLookupCode { get; set; }
    public string CustomerNumber { get; set; }
    public bool IsDuplicate { get; set; }
    public string ItemClassCode { get; set; }
    public string LocalChannel { get; set; }
    public string MachineDescription { get; set; }
    public string OrderNumber { get; set; }
    public string ParentServiceTag { get; set; }
    public string ServiceTag { get; set; }
    public string ShipDate { get; set; }

}

に:

[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
[ComVisible(true)]
public interface IComClassApiCaller
{
    IComClassDellAsset GetDellAsset(string serviceTag, string apiKey);

}

[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface IComClassApiCallerEvents
{
}

[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
    ClassInterface(ClassInterfaceType.None),
    ComSourceInterfaces(typeof(IComClassApiCallerEvents))]
[ComVisible(true)]
[ProgId("ProgId.ApiCaller")]
public class ApiCaller : IComClassApiCaller {

    public IComClassDellAsset GetDellAsset(string serviceTag, string apiKey)
    {
        .....
    }
}


[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83E")]
[ComVisible(true)]
public interface IComClassDellAsset
{
     string CountryLookupCode { get; set; }
     string CustomerNumber { get; set; }
     bool IsDuplicate { get; set; }
     string ItemClassCode { get; set; }
     string LocalChannel { get; set; }
     string MachineDescription { get; set; }
     string OrderNumber { get; set; }
     string ParentServiceTag { get; set; }
     string ServiceTag { get; set; }
     string ShipDate { get; set; }

}

[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA70"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface IComClassDellAssetEvents
{
}

[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F937"),
    ClassInterface(ClassInterfaceType.None),
    ComSourceInterfaces(typeof(IComClassDellAssetEvents))]
[ComVisible(true)]
[ProgId("ProgId.DellAsset")]
public class DellAsset : IComClassDellAsset
{
    public string CountryLookupCode { get; set; }
    public string CustomerNumber { get; set; }
    public bool IsDuplicate { get; set; }
    public string ItemClassCode { get; set; }
    public string LocalChannel { get; set; }
    public string MachineDescription { get; set; }
    public string OrderNumber { get; set; }
    public string ParentServiceTag { get; set; }
    public string ServiceTag { get; set; }
    public string ShipDate { get; set; }

}

これで時間を節約できることを願っています

4

Kieren Johnstoneの回答を使用して、マネージCOM DLLを作成しました。

  1. C#クラスライブラリのソリューションを作成し、SOExampleNewなどの名前を付けます。 VS 2017では、クラスライブラリ(.Net Standard)ではなくクラスライブラリ(.Net Framework)を選択します。

  2. 生成されたコードを削除し、次のコードを挿入します。

    using System.Runtime.InteropServices;
    
    namespace SOExampleNew
    {
      [ComVisible(true)]  // This is mandatory.
      [InterfaceType(ComInterfaceType.InterfaceIsDual)]
      public interface ITestCls
      {
        int Add(int a, int b);      // A method
        string TheName { get; set;} // A property
      }
    
      [ComVisible(true)]  // This is mandatory.
      [ClassInterface(ClassInterfaceType.None)]
      [ProgId("SOExampleNew.TestCls")]
      public class TestCls : ITestCls
      {
        private string mName = "Bert";
    
        // A default public constructor is also mandatory.
        public TestCls() { }
    
        public int Add(int a, int b){ return a + b; }
    
        public string TheName { get { return mName; } set { mName = value; } }
      }
    }
    
  3. 構成Release/Any CPUを使用してプロジェクトをビルドします。出力は、\ bin\releaseフォルダーにあるマネージドDLL SOExampleNew.dllです。

  4. 次に、マネージCOM DLLを登録する必要があります。 regsvr32を試さないでください。マネージドCOM DLLにはregasmという特別なプログラムがあります。 Regasmには、32ビットおよび64ビットアプリ用のバージョンがあります。管理者としてコマンドプロンプトを開き、C:\ Windows\Microsoft.NET\Framework\v4.0.30319に変更します。このフォルダーには、管理されたCOM DLLがネイティブ32ビットCOM DLLであるかのように登録するためのregasm.exeアプリが含まれています。

  5. タイプRegAsm.exe /tlb /codebase path_to_your_bin_release_folder\SOExampleNew.dllこの方法で任意のコンピューターにDLL)を登録する必要があります。タイプライブラリを作成する/ tlbスイッチを忘れないでください。コンパイラーは/ codebaseスイッチにコメントしますDLLはレジストリのWoW64部分に登録されており、ネイティブ(管理されていない)32ビットアプリで使用できます。

  6. ここで、64ビットアプリによるマネージCOM DLLを使用するための登録を繰り返します。C:\ Windows\Microsoft.NET\Framework 64\v4.0.30319に変更します。前と同じコマンドを入力します。

  7. 登録を高速化するには、自分のPCで管理者権限でVisual Studioを実行し、次のビルド後イベントを追加します。

    %SystemRoot%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe /tlb /codebase "$(TargetPath)"
    %SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe /tlb /codebase "$(TargetPath)"
    

ネイティブのアンマネージCOM DLLのようにDLLを使用できます。VBAでDLLをテストします。ツール/リファレンスでSOExampleNewを確認します。登録に問題があります。簡単なテストサブ:

Sub TestSOExampleNew()
  Dim so As New SOExampleNew.TestCls
  MsgBox so.Add(2, 3) & ", " & so.TheName
End Sub

C++でマネージCOM DLLをテストするには、新しいコンソールアプリケーションを作成し、次のコードを挿入してRelease/x64またはRelease/x86としてビルドします。

#include "stdafx.h"
#import   D:\Aktuell\CSharpProjects\SOExampleNew\SOExampleNew\bin\Release\SOExampleNew.tlb"
//this is the path to my bin\Release folder
int main()
{
  SOExampleNew::ITestClsPtr TestClsPtr = nullptr;

  if (SUCCEEDED(CoInitialize(0)))
  {
    if (SUCCEEDED(TestClsPtr.CreateInstance("SOExampleNew.TestCls")))
    {
        wprintf(L"out: %ld, %s\n", TestClsPtr->Add(2, 3), (LPCWSTR)TestClsPtr->TheName);
    }
  }

  CoUninitialize();// Uninitialize COM
  return 0;
}
2

Microsoftには here の簡単な方法があります。ただし、dllを登録する必要があります。 C#dllを単純なC dll(C#Unmanaged Exports)のようにするには、 this メソッドを使用します。詳細は here で説明します。

1
pcunite

COM相互運用機能は、.NET Framework共通言語ランタイム(CLR)に含まれるテクノロジで、コンポーネントオブジェクトモデル(COM)オブジェクトと.NETオブジェクトとの相互作用を可能にします。 COM Interopは、元のコンポーネントを変更したり、その逆を行うことなく、既存のCOMコンポーネントへのアクセスを提供することを目的としています。詳細: http://www.writeulearn.com/com-interop-using-csharp/

0
bhupesh