|
■No103858 (いとこんにゃく さん) に返信 > OutlookApp = new Outlook.Application(); > OutookNameSpace = (Outlook._NameSpace)OutlookApp.GetNamespace("MAPI"); <=ここで以下のエラーが出ます。
手元に "Outlook (new)" を動かせる環境が無いうえに、 普段ブラウザ版 Outlook を使っているため、デスクトップアプリ版の Outlook のオートメーション操作については詳しくありませんが、状況からすると
・NameSpace の dual interface の vtable 側に不整合が起きている ・あるいは TypeLib の参照が正しく解決されていない
といった可能性が考えられます。 Outlook の TypeLib は後方互換性を重視しているため、 実際にインターフェイスが変更されたとは考えにくいのですが、 vtable 側と TypeLib の整合性が崩れたなら「変更されたように見える」挙動になりえます。
原因が Office 側の更新か、Windows 側の更新かは判断が難しいところです。
> ' Outlookアプリのイベント(NewMailEx)に接続 > Dim olApp: Set olApp = WScript.CreateObject("Outlook.Application", "OutApp_") > Dim olNS : Set olNS = olApp.GetNamespace("MAPI") > で実行した場合は問題ありません。
VBScript が動くということは、IDispatch (遅延バインディング) 側は正常ということになります。 一方で C# の事前バインディングは vtable (IUnknown) 側を使うため、 dual interface の vtable 側だけが壊れていると、型変換に失敗する可能性があります。
そのため、C# でも dynamic を使った遅延バインディングにした場合は動作するかもしれません。
まず、事前バインディングで取得した Application オブジェクトが 本当に従来 Outlook の CLSID を返しているか確認してみてください。
var app = new Outlook.Application(); // 通常であれば「0006f03a-0000-0000-c000-000000000046」が返される Console.WriteLine(app.GetType().GUID);
念のため、Marshal.IsComObject(app) が true を返すかも確認しておきましょう。
ちなみに PowerShell の COM 呼び出しは、VBScript 同様、常に IDispatch(遅延バインディング)なので、 C# からの事前バインディング(参照設定で呼び出した場合)とは結果が異なる可能性があります。
$o = New-Object -COM "Outlook.Application" $o.GetType().Guid # → 0006f03a-0000-0000-c000-000000000046
$n = $o.GetNamespace("MAPI") $n.GetType().Guid # → 0006308b-0000-0000-c000-000000000046
# 一応、解放処理も書いておく # # $objs = @($mail, $items, $folder, $n, $o) $objs = @($n, $o)
foreach ($obj in $objs) { if ($obj -ne $null -and [System.Runtime.InteropServices.Marshal]::IsComObject($obj)) { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($obj) | Out-Null } }
# $mail = $items = $folder = $n = $o = $null $n = $o = $null
比較のため、C# でも遅延バインディングを試してみてください。特に星印の部分です。 (イベント処理も遅延バインドでやろうとすると大変なので、あくまで検証目的ですが)
OutlookApp = new Outlook.Application(); // early-bind dynamic outlookDynApp = OutlookApp; dynamic outookDynNameSpace = outlookDynApp.GetNamespace("MAPI"); //★ late-bind OutookNameSpace = outookDynNameSpace; // ☆
または最初から遅延バインディングで起動する方法:
// OutlookApp = new Outlook.Application(); dynamic outlookDynApp = Activator.CreateInstance(Type.GetTypeFromProgID("Outlook.Application")); // late-bind dynamic outookDynNameSpace = outlookDynApp.GetNamespace("MAPI"); //★ late-bind OutookNameSpace = outookDynNameSpace; // ☆
さらに、実際に返ってきた COM オブジェクトの CLSID を確認するには: IntPtr unk = Marshal.GetIUnknownForObject(outlookDynApp); object real = Marshal.GetObjectForIUnknown(unk); Console.WriteLine(real.GetType().GUID);
サポートされる IID を調べる場合は、スタートメニューから [Visual Studio] > [Developer Command Prompt] を起動(あるいは管理者起動)し、左ペインから [Type Libraries] > [Microsoft Outlook 16.0 Object Library] をダブルクリックすることで確認できます。
・interface ⇒ C# の参照設定で使われる事前バインディング用 (vtable / IUnknown ベース)
・dipinterface ⇒ PowerShell や VBScript 、あるいは C# で dynamic + Activator.CreateInstance で 使われる遅延バインディング用 (IDispatch.Invoke ベース)
※dual interface の場合、事前バインディング では vtable 側が使われます。
> メニューに > Outlookの他に > Outlook(new)が出現したことも関係するのかもしれません。
"Outlook (new)" の実体は WebView2 ベースと聞いていますが、 COM オートメーションをどこまでサポートし続けているかは不明です。
試しに "Outlook (new)" を無効化して従来版を強制起動して 挙動が変わるかどうかを確認すると、原因の切り分けに役立つかもしれません。
HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Options\General DisableNewOutlook = 1 (DWORD)
365 導入企業の場合はこちらも参考になるかもしれません。 https://www.prins.co.jp/knowledge/column/20250523-5234/
|