2017年にVB6から.NetFrameworkのDLLを呼び出す

一体俺は何をやっているんだ...

# 1. 環境

## 1.1. .Net Framework

* Visual Studio 2017
* C#
* Windows 10 (summer) Creators Update (bootcamp)

## 1.2. VB6
* VB6 Enterprise (SP6, SP6B適用)
* Windows 10 (summer) Creators Update (bootcamp)

[VB6をWin10にインストールする方法](https://social.msdn.microsoft.com/Forums/ja-JP/db66e64d-ad01-429e-8635-659df56e0a37/vb60windows10?forum=vbgeneralja)

VB6はMSDNから入手できます。
[![https://gyazo.com/2c2cbd0f1a2d74ed4a2bdeb09b14cf07](https://i.gyazo.com/2c2cbd0f1a2d74ed4a2bdeb09b14cf07.png)](https://gyazo.com/2c2cbd0f1a2d74ed4a2bdeb09b14cf07)

# 2. DLL側の準備
[MSのドキュメント](https://msdn.microsoft.com/ja-jp/library/c3fd4a20(v=vs.80).aspx)を参照すると、DLL側でCOM相互参照機能から利用できるようにするために以下のような準備が必要。

> * クラスはパブリックであること。
> * プロパティ、メソッド、およびイベントがパブリックであること。
> * プロパティとメソッドがクラス インターフェイスで宣言されていること。
> * イベントがイベント インターフェイスで宣言されていること。

パブリックであることはCOM相互参照機能でなくても必要なので、インターフェイスの宣言が必要になる。
その際には、`System.Runtime.InteropServices` 名前空間のCOM参照用の属性を宣言する必要がある。

簡単な `MyMath` クラスを作成してCOM相互参照可能に修正してみる。
次のようなクラスだ。

``` csharp
namespace MyClassLibrary
{
    public class MyMath {
        public int Add(int a, int b) {
            return a + b;
        }
    }
}
```

これを次のように修正する。

``` csharp
using System.Runtime.InteropServices;

namespace MyClassLibrary
{
    public interface IMyMath
    {
        int Add(int a, int b);
    }

    [ClassInterface(ClassInterfaceType.None)]
    public class MyMath : IMyMath
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
    }
}
```

~~参考のドキュメントでは `Guid` アトリビュートを利用しているが、明示指定する必要はなさそうだ。~~

---

2017/10/10 追記
GuidアトリビュートはCOMに登録する際のIDになるらしく、Guidアトリビュートを指定しないと、DLLを更新して[COMへのアセンブリ登録](https://msdn.microsoft.com/ja-jp/library/h627s4zy.aspx)を再度行った際に、前回登録したアセンブリが特定できずに更新できないエラーとなる模様。

その際のエラーメッセージは次のようなもの

```
COM 相互運用機能に対して登録解除できる型を含んでいません。
```

---

ソースの他にVisual Studioのソリューションエクスプローラからプロジェクトの `Property` ファイルを編集する。

[![https://gyazo.com/4b267ac6f8a6d1ccad3c0a4d9c9f3026](https://i.gyazo.com/4b267ac6f8a6d1ccad3c0a4d9c9f3026.png)](https://gyazo.com/4b267ac6f8a6d1ccad3c0a4d9c9f3026)

* [アプリケーション]タブ > [アセンブリ情報] > [アセンブリをCOM参照可能にする] に チェック
* [ビルド]タブ > [COM相互運用機能の登録] に チェック

管理者権限で Visual Studio 2017 を起動し Release ビルドすると、プロジェクトフォルダの `bin/Release` に3つのファイルが確認できる。

* MyClassLibrary.dll
* MyClassLibrary.tlb
* MyClassLibrary.pdb

また、Visual Studio がビルドの過程で [COMへのアセンブリ登録](https://msdn.microsoft.com/ja-jp/library/h627s4zy.aspx) を済ませてくれている模様。

これで、DLL側の準備は完了。

# 3. 呼び出し側VB6の作業

DLLでビルドしたPCと別PCでおこなう場合には [COMへのアセンブリ登録](https://msdn.microsoft.com/ja-jp/library/h627s4zy.aspx) が必要になる。

Visual Basic を起動し、空プロジェクトを作成したあと、メニューから [プロジェクト] > [参照設定] を選択する。

[![https://gyazo.com/f70a2c696ac667b2c546066259617f5b](https://i.gyazo.com/f70a2c696ac667b2c546066259617f5b.png)](https://gyazo.com/f70a2c696ac667b2c546066259617f5b)

参照可能なライブラリファイルの中に登録した `dll` があるのでチェックを付けて[OK]を選択する。
ない場合は、[参照]ボタンを選択して `MyClassLibrary.tlb` を選択して追加し、チェックを付ける。

[![https://gyazo.com/d89a4ec676b19b0c83643db0a77cf6da](https://i.gyazo.com/d89a4ec676b19b0c83643db0a77cf6da.png)](https://gyazo.com/d89a4ec676b19b0c83643db0a77cf6da)

これで呼び出し側の設定も完了。

# 4. VB6で呼び出し実装

次のようなコードを書いて、DLLを利用してみる。

``` vb
Private Sub Form_Load()
    Dim MyMath As MyClassLibrary.MyMath
    Set MyMath = New MyClassLibrary.MyMath
    Label1.Caption = MyMath.Add(1, 2)
End Sub
```

参照設定に登録してあると補完機能が利用できる。

[![https://gyazo.com/24dd1167330b78433cec4a0b9d2e0c1c](https://i.gyazo.com/24dd1167330b78433cec4a0b9d2e0c1c.png)](https://gyazo.com/24dd1167330b78433cec4a0b9d2e0c1c)

引数の型も変換されている。

.Net Frameworkのintは32bitなのでVB6ではlongになる。

[![https://gyazo.com/2682a42813f75f460ba13b13547db41b](https://i.gyazo.com/2682a42813f75f460ba13b13547db41b.png)](https://gyazo.com/2682a42813f75f460ba13b13547db41b)

実行結果は以下のようになる。

[![https://gyazo.com/eca310f86788c65c29c8eec3fba1206b](https://i.gyazo.com/eca310f86788c65c29c8eec3fba1206b.png)](https://gyazo.com/eca310f86788c65c29c8eec3fba1206b)