.NET 8 DLLをVBAから型付きで呼び出す方法

· · C#, .NET 8, VBA, COM, Office, dscom

まず結論

.NET 8 の DLL を VBA から型付き(早期バインディング)で使う流れはこうです。

  1. .NET 8 のクラスライブラリを EnableComHosting=true でビルド
  2. COM 向けの明示的なインターフェイスとクラスを作成
  3. クラスは ClassInterfaceType.None、インターフェイスは InterfaceIsDual
  4. ビルド後、dscom tlbexport で TLB を生成
  5. regsvr32*.comhost.dll を登録
  6. dscom tlbregister で TLB を登録
  7. VBA で参照設定を追加し、型付きで利用

COM の入口は *.comhost.dll、型情報は *.tlb、VBA はその TLB を見て早期バインディングする という構成です。

全体像

ファイル 役割
VbaTypedComSample.dll .NET 8 の実装本体
VbaTypedComSample.comhost.dll COM から呼ばれる入口
VbaTypedComSample.tlb VBA が見る型情報
VbaTypedComSample.deps.json 依存関係の解決情報
VbaTypedComSample.runtimeconfig.json .NET ランタイム起動情報

最初に決めること: 32bit / 64bit を揃える

Office/VBA と COM サーバーの bitness を揃えないと「ActiveX コンポーネントはオブジェクトを作成できません」系のエラーが出ます。

利用側 .NET 側 TLB 生成 登録コマンド
64bit Office x64 / win-x64 dscom C:\Windows\System32\regsvr32.exe
32bit Office x86 / win-x86 dscom32.exe C:\Windows\SysWOW64\regsvr32.exe

.NET 8 側の作り方

.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <EnableComHosting>true</EnableComHosting>
    <PlatformTarget>x64</PlatformTarget>
    <NETCoreSdkRuntimeIdentifier>win-x64</NETCoreSdkRuntimeIdentifier>
  </PropertyGroup>
</Project>

ポイントは EnableComHosting=true。これを付けるとビルド時に *.comhost.dll が生成される。

アセンブリ全体は COM 非公開に

using System.Runtime.InteropServices;
[assembly: ComVisible(false)]

公開するインターフェイスとクラス

namespace VbaTypedComSample;

[ComVisible(true)]
[Guid("2A1BBEDE-DE6E-4C34-AD60-2E9E0E33E999")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ICalculator
{
    [DispId(1)] int Add(int x, int y);
    [DispId(2)] double Divide(double x, double y);
    [DispId(3)] string Hello(string name);
}

[ComVisible(true)]
[Guid("FAD1C752-0BB6-4DDD-889F-FE446350847A")]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ICalculator))]
public class Calculator : ICalculator
{
    public int Add(int x, int y) => checked(x + y);
    public double Divide(double x, double y) { /* 0除算チェック付き */ }
    public string Hello(string name) { /* 空文字対応 */ }
}

押さえるポイント

  • Guid はインターフェイスとクラスに別々に振る
  • ClassInterfaceType.None にして AutoDual に頼らない
  • VBA 向けインターフェイスは InterfaceIsDual
  • DispId を振っておくとメソッド順変更時の事故を減らせる
  • public な引数なしコンストラクターが必要(COM から New されるため)

ビルドと TLB 生成

dotnet build -c Release
dotnet tool install --global dscom
dscom tlbexport .\bin\Release\net8.0-windows\VbaTypedComSample.dll --out .\bin\Release\net8.0-windows\VbaTypedComSample.tlb

32bit Office 向けの場合は dscom32.exe を使用する。

COM host と TLB の登録(管理者権限で実行)

# 64bit Office の場合
$out = Resolve-Path .\bin\Release\net8.0-windows
C:\Windows\System32\regsvr32.exe "$out\VbaTypedComSample.comhost.dll"
dscom tlbregister "$out\VbaTypedComSample.tlb"

VBA から使う

  1. Excel/Access を開く → VBA エディタ
  2. ツール参照設定VbaTypedComSample.tlb を選択
  3. コードを記述:
Option Explicit

Public Sub UseCalculator()
    Dim calc As VbaTypedComSample.ICalculator
    Set calc = New VbaTypedComSample.Calculator

    Debug.Print calc.Add(10, 20)
    Debug.Print calc.Divide(10, 4)
    Debug.Print calc.Hello("VBA")
End Sub

IntelliSense が効き、メソッド名の typo が実行前に見つけやすくなる。

例外は VBA 側では COM エラーになる

Public Sub UseWithErrorHandling()
    On Error GoTo EH
    Dim calc As VbaTypedComSample.ICalculator
    Set calc = New VbaTypedComSample.Calculator
    Debug.Print calc.Divide(10, 0)
    Exit Sub
EH:
    Debug.Print Err.Number, Err.Description
End Sub

配布時に必要なファイル

VbaTypedComSample.dll
VbaTypedComSample.comhost.dll
VbaTypedComSample.deps.json
VbaTypedComSample.runtimeconfig.json
VbaTypedComSample.tlb

さらに、クライアント PC には対応する .NET 8 ランタイム が必要。

はまりどころ

  1. AnyCPU のまま放置しない: 64bit Office なら x64、32bit Office なら x86
  2. ClassInterfaceType.AutoDual を使わない: 公開後のメンバー順変更で壊れやすい
  3. GUID を軽率に再生成しない: COM では GUID が契約そのもの。変更すると既存参照が壊れる
  4. 公開済みインターフェイスを壊さない: 変更が大きいなら ICalculator2 を新設する
  5. 型は地味に寄せる: VBA 境界では intdoubleboolstringDateTimedecimalenum が安全
  6. Office を開いたまま更新しない: DLL が掴まれたままになりビルドや再登録でトラブルに

まとめ

.NET 8 × VBA 連携は COM host と TLB を分けて考える のがコツ。

  • 起動入口: *.comhost.dll
  • 型情報: *.tlb
  • 実装本体: *.dll

この構成で EnableComHosting=truedscom tlbexportregsvr32 + dscom tlbregister → VBA 参照設定の流れを押さえれば、型付きで安全に連携できる。

参考資料

関連する記事

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

VBScript非推奨化に備える移行ガイド

Windows の VBScript 段階廃止に向け、VBA や Excel マクロ、社内ツールの依存を棚卸しし、静的検出と実行ログで隠れた呼び出しを洗い出す手順、PowerShell や Office Scripts などへの代替選定、署名運用と段階展開までを実務目線で整...

記事を読む

VBAの現在地と移行戦略

VBA の役割と制約、将来の見通しを整理し、デスクトップに残す部分とクラウドや .NET へ出す部分を責務ごとに切り分け、段階移行を進める実務的な判断軸を示します。

記事を読む

Excel帳票出力の方式選定ガイド

Excel 帳票出力を Windows アプリやサーバー処理にどう組み込むかを、COM 自動化、Open XML 直接生成、テンプレート差し込み、既存 VBA 活用の四方式で比較し、要件別の選び方や設計時のハマりどころまでまとめた判断表です。

記事を読む

関連トピック

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

このテーマがつながるサービス

この記事は次のサービスページにつながります。近い入口からご覧ください。

ブログ一覧に戻る