.NET 8 DLLをVBAから型付きで呼び出す方法
まず結論
.NET 8 の DLL を VBA から型付き(早期バインディング)で使う流れはこうです。
- .NET 8 のクラスライブラリを
EnableComHosting=trueでビルド - COM 向けの明示的なインターフェイスとクラスを作成
- クラスは
ClassInterfaceType.None、インターフェイスはInterfaceIsDual - ビルド後、
dscom tlbexportで TLB を生成 regsvr32で*.comhost.dllを登録dscom tlbregisterで TLB を登録- 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 から使う
- Excel/Access を開く → VBA エディタ
ツール→参照設定→VbaTypedComSample.tlbを選択- コードを記述:
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 ランタイム が必要。
はまりどころ
- AnyCPU のまま放置しない: 64bit Office なら x64、32bit Office なら x86
- ClassInterfaceType.AutoDual を使わない: 公開後のメンバー順変更で壊れやすい
- GUID を軽率に再生成しない: COM では GUID が契約そのもの。変更すると既存参照が壊れる
- 公開済みインターフェイスを壊さない: 変更が大きいなら
ICalculator2を新設する - 型は地味に寄せる: VBA 境界では
int、double、bool、string、DateTime、decimal、enumが安全 - Office を開いたまま更新しない: DLL が掴まれたままになりビルドや再登録でトラブルに
まとめ
.NET 8 × VBA 連携は COM host と TLB を分けて考える のがコツ。
- 起動入口:
*.comhost.dll - 型情報:
*.tlb - 実装本体:
*.dll
この構成で EnableComHosting=true → dscom tlbexport → regsvr32 + dscom tlbregister → VBA 参照設定の流れを押さえれば、型付きで安全に連携できる。
参考資料
- Expose .NET components to COM - Microsoft Learn
- COM 相互運用のために .NET 型を修飾する - Microsoft Learn
- ComInterfaceType 列挙型 - Microsoft Learn
- ClassInterfaceType 列挙型 - Microsoft Learn
- COM 呼び出し可能ラッパー - Microsoft Learn
- DispIdAttribute クラス - Microsoft Learn
- dscom - NuGet Gallery
- How to use the Regsvr32 tool and troubleshoot Regsvr32 error messages - Microsoft Support
- .NET 8 downloads
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
Office 2024 / Microsoft 365 で ActiveX が動かないときの対処ガイド
Office 2024 と Microsoft 365 で ActiveX が動かない原因を、設定既定値、bitness、COM 登録、依存ランタイム、IE モードの順で切り分ける実務手順をまとめた現場向けガイドです。
VBScript非推奨化に備える移行ガイド
Windows の VBScript 段階廃止に向け、VBA や Excel マクロ、社内ツールの依存を棚卸しし、静的検出と実行ログで隠れた呼び出しを洗い出す手順、PowerShell や Office Scripts などへの代替選定、署名運用と段階展開までを実務目線で整...
VBAの現在地と移行戦略
VBA の役割と制約、将来の見通しを整理し、デスクトップに残す部分とクラウドや .NET へ出す部分を責務ごとに切り分け、段階移行を進める実務的な判断軸を示します。
Excel帳票出力の方式選定ガイド
Excel 帳票出力を Windows アプリやサーバー処理にどう組み込むかを、COM 自動化、Open XML 直接生成、テンプレート差し込み、既存 VBA 活用の四方式で比較し、要件別の選び方や設計時のハマりどころまでまとめた判断表です。
開発者の異常な愛情、または私は如何にして心配するのをやめてWindowsを愛するようになったか
Windowsは面倒くさい。けれど、その面倒くささは、現実の業務を背負ってきたOSだからこその面倒くささでもある。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
ActiveX / 移行テーマ
COM / ActiveX / OCX を残すか、包むか、置き換えるかを整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
既存資産活用・移行支援
COM / ActiveX / OCX、32bit / 64bit 制約を抱える既存資産の活用と移行を支援します。