Dim xlApp As New Excel.Applicationでエラー

タグの編集
投稿者 ひでと  (社会人) 投稿日時 2024/4/4 14:17:04
お世話になります。
Visual Studio 2019 のvbでエクセル2019 のブックを使用したいと思い、
 Dim xlApp As New Excel.Application
としたのですが、サーバーの実行に失敗しましたとエラーがでます。
処理の初めの方のエラーなのですが、原因はなんでしょうか。

保存してあるマクロ付きのブックをコピーしてシートにデータを記載する処理をしようとしています。
冒頭部分は以下のとおりです。

   Private Sub Excelへ出力ToolStripMenuItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Excelへ出力ToolStripMenuItem.Click
        Dim i, j As Integer
        Dim xlApp As New Excel.Application
        Dim xlBooks As Excel.Workbooks = xlApp.Workbooks
        Dim xlFilePath = My.Computer.FileSystem.CurrentDirectory & "\重量計算1.xlsm"
        Dim xlBook As Excel.Workbook = xlBooks.Open(xlFilePath)
        Dim xlSheets As Excel.Sheets = xlBook.Worksheets
        Dim xlSheet As Excel.Worksheet

参照設定は 
Microsoft Office 16.0 Object Library
Microsoft Excel 16.0 Object Library
として Microsoft .Office.Core の名前をインポートしています。
投稿者 Dim xlApp As New Excel.Applicationでエラー  (社会人) 投稿日時 2024/4/4 15:07:48
補足
エラーは
"CLSID {00024500-0000-0000-C000-000000000046} を含むコンポーネントの COM クラス ファクトリを取得中に
とメッセージの一部にあります。
投稿者 KOZ  (社会人) 投稿日時 2024/4/4 15:32:47
エラーメッセージは省略せず書きましょう。

Office はデスクトップアプリ版でしょうか?それともストアアプリ版でしょうか?
ストアアプリ版の場合は、デスクトップアプリ版に差し替えてください。

「Microsoft Officeのストアアプリ版とデスクトップアプリ版について」
https://www.hom.co.jp/it/1573/
投稿者 ひでと  (社会人) 投稿日時 2024/4/5 08:53:22
ありがとうございます。
デスクトップ版です。
Microsoft Office Home and Business 2019-ja-jp
となっていました。

エラーは以下になっていました。

System.Runtime.InteropServices.COMException
  HResult=0x80080005
  Message=CLSID {00024500-0000-0000-C000-000000000046} を含むコンポーネントの COM クラス ファクトリを取得中に、次のエラーが発生しました: 80080005 サーバーの実行に失敗しました (HRESULT からの例外:0x80080005 (CO_E_SERVER_EXEC_FAILURE))。
  Source=mscorlib
  スタック トレース:
   at System.Runtime.Remoting.RemotingServices.AllocateUninitializedObject(RuntimeType objectType)
   at System.Runtime.Remoting.Activation.ActivationServices.CreateInstance(RuntimeType serverType) in f:\dd\ndp\clr\src\BCL\system\runtime\remoting\activationservices.cs:line 458
   at System.Runtime.Remoting.Activation.ActivationServices.IsCurrentContextOK(RuntimeType serverType, Object[] props, Boolean bNewObj) in f:\dd\ndp\clr\src\BCL\system\runtime\remoting\activationservices.cs:line 175
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) in f:\dd\ndp\clr\src\BCL\system\rttype.cs:line 5476
   at System.Activator.CreateInstance(Type type, Boolean nonPublic) in f:\dd\ndp\clr\src\BCL\system\activator.cs:line 193
   at System.Activator.CreateInstance(Type type) in f:\dd\ndp\clr\src\BCL\system\activator.cs:line 134
   at トレイ重量計算.メニュー.Excelへ出力ToolStripMenuItem_Click(Object sender, EventArgs e) in C:\Users\hidet\Documents\Visual Studio 2019\作成プログラムソース\トレイ重量計算\トレイ重量計算\メニュー.vb:line 1103
   at System.Windows.Forms.ToolStripItem.RaiseEvent(Object key, EventArgs e)
   at System.Windows.Forms.ToolStripMenuItem.OnClick(EventArgs e)
   at System.Windows.Forms.ToolStripItem.HandleClick(EventArgs e)
   at System.Windows.Forms.ToolStripItem.HandleMouseUp(MouseEventArgs e)
   at System.Windows.Forms.ToolStrip.OnMouseUp(MouseEventArgs mea)
   at System.Windows.Forms.ToolStripDropDown.OnMouseUp(MouseEventArgs mea)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ToolStrip.WndProc(Message& m)
   at System.Windows.Forms.ToolStripDropDown.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun() in f:\dd\vb\runtime\msvbalib\ApplicationServices\WindowsFormsApplicationBase.vb:line 779
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel() in f:\dd\vb\runtime\msvbalib\ApplicationServices\WindowsFormsApplicationBase.vb:line 1472
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine) in f:\dd\vb\runtime\msvbalib\ApplicationServices\WindowsFormsApplicationBase.vb:line 544
   at トレイ重量計算.My.MyApplication.Main(String[] Args) in :line 84
投稿者 KOZ  (社会人) 投稿日時 2024/4/5 16:19:05
Windows アプリケーションのようですが、タスクスケジューラで動かしていませんか?
投稿者 ひでと  (社会人) 投稿日時 2024/4/5 17:11:46
お世話になります。
タスクスケジューラーは分からないですが、セキュリティーソフトが関係している可能性もあるのでしょうか?
普通にexcelを起動するときに、「Microsoft Office Home and Business 2019-ja-jpが・・・再開しました」とメッセージが出るときがあります。
このメッセージは、1度出ると次は出ないようになっている気もします。
Dim xlApp As New Excel.Application
この部分では、プログラムょ変更する以前は出なかったエラーなのですが、変更しようとして急にエラーになってしまいました。
セキュリティーソフトに問題があると、セキュリティーソフトを停止する他、方法が思いつかず、難しいです。
タスクスケジューラーに問題があるとすると、どのようにすれば良いのかアドバイスいただけませんでしょうか。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2024/4/5 19:40:20
インストール後に Office の起動経験が無かった場合に外部から起動しようとすると、
初回起動時にオートメーション エラーになることがありますが、今回はそれとは違いそうですね。
(この問題は、追加認証が必要とされたり、あるいはアドバタイズ インストール要求が発生するといった理由によるもの)


> エラーは以下になっていました。
Office の再インストールでも回復しない状況でしょうか?


> CLSID {00024500-0000-0000-C000-000000000046} を含むコンポーネントの COM クラス ファクトリ
このクラス識別子は Excel.Application のことを示しています。
MsgBox(Type.GetTypeFromProgID("Excel.Application").GUID.ToString())

なのでそのメッセージから読み取れる情報とは、Excel.Application のクラスファクトリ絡みであるという点、
すなわち「New Excel.Application を呼び出そうとして失敗した」という事柄だけです。

それゆえ調査においては、そのあとの「次のエラーが発生しました」の方のメッセージも重要になりえます。
まぁ、それでも断片的な情報しか得られないことは多いのですが。


> 「Microsoft Office Home and Business 2019-ja-jpが・・・再開しました」
さて、何でしょうね。
「再開」ということは、何らかの予期せぬエラーもしくはセキュリティによるブロックによって
起動直後に意図せず終了されてしまう事象が起こり、その後、自動再起動で復帰されている可能性、とか。
その場合、VB 側からのオートメーションで通信が切れてしまうことになり、
0x80080005 (CO_E_SERVER_EXEC_FAILURE) に繋がってしまう…という状況を想像してみました。


> セキュリティーソフトが関係している可能性もあるのでしょうか?
無いとは言えないですね。

本件の事象とは異なるものの、セキュリティソフトの監視の停止だけでは改善せず、
セキュリティソフト自体をアンインストールしないと正しく起動しない問題があることは
私自身が経験したことはあります。もちろん、今回の事象が該当するかどうかは分からないですが。
(私の時は、セキュリティソフト側のメジャーバージョン更新が必要でした)

セキュリティソフトが関係しているかどうかは、そのソフトを一時的に止めてみるなり
アンインストールしてみることで確認してみてください。


> プログラムょ変更する以前は出なかったエラーなのですが、変更しようとして急にエラーになってしまいました。
(1) 開発環境の Office のメジャーバージョンが更新された
(2) 開発環境または実行環境で、異なるバージョンの Office が並行インストールされた
(3) Office の再インストールで 32bit版/64bit 版の入れ替えが行われたが、以前のレジストリ情報の断片が残留していた
などによって、インターフェイスの互換性に問題が生じることで、一部のメソッド呼び出しが失敗することがあります。

とはいえ (1) については、エラーが出るなら New Excel.Application よりも、そのあとのタイミングになりそうです。


> タスクスケジューラーに問題があるとすると
これは Office という製品が、デスクトップ ユーザーとの対話(attended)を前提とした設計になっており、
サービス等からの無人実行で呼ばれること(unattended)が考慮されてはいないという事から、、
タスクスケジューラーからの実行には向いていない……という話かと思います。

今回は、デスクトップ アプリ上の ToolStripMenu をユーザー操作して Excel.Application を
起動する形のようですし、タスクスケジューラーから実行する予定が無いのであれば、
この点については気にしなくても良いと思いますよ。

無人実行を保証していないという点に関する参考資料としてはこのあたり。
https://support.microsoft.com/ja-jp/topic/48bcfe93-8a89-47f1-0bce-017433ad79e2
https://learn.microsoft.com/ja-jp/office/client-developer/integration/considerations-unattended-automation-office-microsoft-365-for-unattended-rpa
投稿者 とくま  (社会人) 投稿日時 2024/4/8 11:06:27
>Message=CLSID {00024500-0000-0000-C000-000000000046} を含むコンポーネントの COM クラス ファクトリを取得中に、次のエラー
>Dim xlApp As New Excel.Application
Excelの起動で失敗なので、ライセンスかDLL参照か、環境依存のことも多いから、他人がズバリの回答は難しい問題ですね。
色々試して、動けば良いけど、Microsoftのサポート受けたほうが早いのでは?まである。

>この部分では、プログラムょ変更する以前は出なかったエラーなのですが、変更しようとして急にエラーになってしまいました。
変更前の動いていたプログラムの作成者は別の方ですか?特殊な設定とかしていませんでしたか?

>サーバーの実行に失敗しました
>Runtime.Remoting.Activation.ActivationServices.CreateInstance
> f:\dd\ndp\clr\src\BCL\system\runtime
Fドライブはネットワークドライブですか?
ネットワーク越しのアプリケーション実行は制限が多いので、ネットワーク越しの処理があるならローカルで試しては?

>セキュリティーソフトに問題があると、セキュリティーソフトを停止する他、方法が思いつかず、難しいです。
当たり前の話だけど、セキュリティーソフトによって仕様は違いますが、一時的に停止できたり、
安全なサイトやアプリを対象外として登録できるアプリも多いと思いますが。
思い付くどうこう以前に、セキュリティソフトの仕様を確認しては?
現状で原因が全く絞れていません。一時的に停止して動いたなら、そこで原因が特定できます。
最終的に停止して業務するかとは別の話です。試すだけならできるのでは?

>Office の再インストール
過去、別バージョンのOfficeをインストールしていた場合、レジストリにゴミ情報が残っていて、プログラムから
うまく参照できない場合があります。大抵は再インストールすれば上手くいきますが、専用のツールで
クリーンな環境にしたり、手動でレジストリを修正しないと上手くいかない場合もあります。

>参照設定
Office の再インストールなどを試した後、参照設定は一度解除して、参照しなおした方が良いかも?
これも古い情報が残る場合があります。プロジェクトフォルダ配下の bin、obj フォルダも削除して
作り直すほうが良いです。

>その他
新規プロジェクトで参照設定せず、遅延バインディングのコードで、ローカルのExcel起動のみ実行してみるとか。
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim xlApp As Object = CreateObject("Excel.Application")
        Dim xlBooks As Object = xlApp.Workbooks
        Dim xlBook As Object = xlBooks.Add()
        Try
            xlApp.Visible = True
        Finally
            MRComObject(xlBook)
            MRComObject(xlBooks)
            MRComObject(xlApp)
        End Try
    End Sub

    'https://hanatyan.sakura.ne.jp/dotnet/index.html 
    'VB2005/VB2008/VB2010 用 
    ''' <summary> 
    ''' COMオブジェクトの参照カウントをデクリメントします。 
    ''' </summary> 
    ''' <typeparam name="T">(省略可能)</typeparam> 
    ''' <param name="objCom"> 
    ''' COM オブジェクト持った変数を指定します。 
    ''' このメソッドの呼出し後、この引数の内容は Nothing となります。 
    ''' </param> 
    ''' <param name="force"> 
    ''' すべての参照を強制解放する場合はTrue、現在の参照のみを減ずる場合はFalse。 
    ''' </param> 
    Public Shared Sub MRComObject(Of T As Class)(ByRef objCom As T,
     Optional ByVal force As Boolean = False)
        If objCom Is Nothing Then
            Return
        End If
        Try
            If System.Runtime.InteropServices.Marshal.IsComObject(objCom) Then
                If force Then
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(objCom)
                Else
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(objCom)
                End If
            End If
        Finally
            objCom = Nothing
        End Try
    End Sub


Excel保存ファイルの編集だけなら、サードパーティ製のXMLファイル編集ライブラリを使って
回避する手もありますね。Excelを実行しないプログラムにします。
マクロ実行したそうなプログラムだから無理かもだけど。

>タスクスケジューラーは分からないですが、
>セキュリティーソフトを停止する他、方法が思いつかず
技術者なら知っていそうな、メジャーな知識が足りてないと感じる言葉です。
しかし、直面している問題は、セキュリティ面やライセンスまで波及する可能性があります。
技術者を雇ったり、外注できないのですか?
投稿者 (削除されました)  () 投稿日時 2024/4/8 14:39:14
(削除されました)
投稿者 (削除されました)  () 投稿日時 2024/4/8 14:41:05
(削除されました)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2024/4/8 14:42:27
とくまさんの回答に補足:

>> at System.Runtime.Remoting.Activation.ActivationServices.CreateInstance(RuntimeType serverType)
>> in f:\dd\ndp\clr\src\BCL\system\runtime\remoting\activationservices.cs:line 458
> Fドライブはネットワークドライブですか?

このパスは関係ないでしょうね。
そもそも、元質問者であるひでとさんのコードは、.cs (C#) でなく .vb (Visual Basic) ですし。

これらのパスはひでとさんのソースコードの場所を示しているわけではなく、
.NET Framework そのものがコンパイルされたマシン上のソースコードの場所かと。

すなわち『Common Language Runtime の Base Class Library のソースコード』において、
"activationservices.cs ファイルの 458 行目”に「System.Runtime.Remoting.Activation 名前空間」の
「ActivationServices クラス の CreateInstance メソッド」が定義された、ということを示しています。

Reference Source Code のサイトなどによりますと、このメソッドの定義は
.NET Framework 4.6.1 や 4.8 の場合は 446 行目にあるようです。
.NET Framework 4.5.1 (2013/12/19 時点)では 448 行目でした。
https://referencesource.microsoft.com/#mscorlib/system/runtime/remoting/activationservices.cs,443
https://github.com/microsoft/referencesource/blob/master/mscorlib/system/runtime/remoting/activationservices.cs#L443-L521
投稿者 (削除されました)  () 投稿日時 2024/4/8 16:25:59
(削除されました)
投稿者 とくま  (社会人) 投稿日時 2024/4/8 16:35:47
>>> at System.Runtime.Remoting.Activation.ActivationServices.CreateInstance(RuntimeType serverType)
>>> in f:\dd\ndp\clr\src\BCL\system\runtime\remoting\activationservices.cs:line 458
>> Fドライブはネットワークドライブですか?
>このパスは関係ないでしょうね。
>そもそも、元質問者であるひでとさんのコードは、.cs (C#) でなく .vb (Visual Basic) ですし。

補足ありがとうございます。
メニューボタンを押して Excel を起動するプログラムのスタックトレースに、
上記の関数呼び出しが出てくる意味が分からなくて、質問者から何か情報が出て
くることを期待して書きました。
魔界の仮面弁士さんに、恥を忍んでお伺いしたいのですが、この関数はどこから
呼び出されているのでしょうか?

Activator.CreateInstance メソッド
https://learn.microsoft.com/ja-jp/dotnet/api/system.activator.createinstance?view=net-8.0
Excelのインスタンス生成ですか?Excelが拒否した時点で無視して良いログですか?
投稿者 (削除されました)  () 投稿日時 2024/4/9 11:03:33
(削除されました)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2024/4/9 11:21:33
> Activator.CreateInstance メソッド
> https://learn.microsoft.com/ja-jp/dotnet/api/system.activator.createinstance?view=net-8.0
それは .NET 8.0 版のリンクですね。
.NET Framework 版のアセンブリは mscorlib.dll で、
.NET (.NET Core) 版のアセンブリは System.Runtime.dll です。

おそらくひでとさんは .NET Framework 版の WinForms プロジェクトをお使いなのでしょう。
.NET Framework のバージョンまでは読み解けませんでしたが、VB2019 をお使いである以上、
.NET 8.0 どころか、.NET 6.0 が使われていることさえ考えにくいです。
https://learn.microsoft.com/en-us/answers/questions/620284/how-to-target-net-6-0-with-visual-studio-2019

> 魔界の仮面弁士さんに、恥を忍んでお伺いしたいのですが、この関数はどこから
> 呼び出されているのでしょうか?
とくまさんもご存知の通り、エラーの起点は、
ひでとさんの「トレイ重量計算\トレイ重量計算\メニュー.vb」1103行目です。

Private Sub Excelへ出力ToolStripMenuItem_Click(ByVal sender As ObjectByVal e As System.EventArgs) Handles Excelへ出力ToolStripMenuItem.Click
        Dim i, j As Integer
        Dim xlApp As New Excel.Application
        Dim xlBooks As Excel.Workbooks = xlApp.Workbooks
        Dim xlFilePath = My.Computer.FileSystem.CurrentDirectory & "\重量計算1.xlsm"
        Dim xlBook As Excel.Workbook = xlBooks.Open(xlFilePath)
        Dim xlSheets As Excel.Sheets = xlBook.Worksheets
        Dim xlSheet As Excel.Worksheet


COM クラス ファクトリの取得中に、CO_E_SERVER_EXEC_FAILURE が発生した…という点から想像するに、
1103行目というのは恐らく、『Dim xlApp As New Excel.Application』であろうと推察しています。
.xlsm の Open 時という可能性も無くはないですが、多分、New Excel.Application の方でしょう。
(恐らくはプライマリ相互運用機能アセンブリが COM 参照されていると推察します)

この場合、As New Excel.Application() というコードは、
= DirectCast( System.Activator.CreateInstance( [Excel.Applicationを表すSytem.Type型] ) , Excel.Application)
に相当する呼び出しとなります。

Type の取得は
 Type.GetTypeFromProgID("Excel.Application")
あるいは
 Marshal.GetTypeFromCLSID(New Guid("00024500-0000-0000-C000-000000000046"))
などで得られているものと推察(たぶん後者)。


そしてこの部分が、エラーのスタックトレースにあった
> at System.Activator.CreateInstance(Type type) in f:\dd\ndp\clr\src\BCL\system\activator.cs:line 134
に相当します。一応、Reference Sourc も貼っておきますが、.NET Framework バージョンの違いなどで、行番号は一致しないかもしれません。
https://referencesource.microsoft.com/#mscorlib/system/activator.cs,132

さらにスタックを追ってみると…
> at System.Activator.CreateInstance(Type type, Boolean nonPublic) in f:\dd\ndp\clr\src\BCL\system\activator.cs:line 193
https://referencesource.microsoft.com/#mscorlib/system/activator.cs,180

> at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) in f:\dd\ndp\clr\src\BCL\system\rttype.cs:line 5476
https://referencesource.microsoft.com/#mscorlib/system/rttype.cs,5446

> at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
https://referencesource.microsoft.com/#mscorlib/system/runtimehandles.cs,239

> at System.Runtime.Remoting.Activation.ActivationServices.IsCurrentContextOK(RuntimeType serverType, Object[] props, Boolean bNewObj) in f:\dd\ndp\clr\src\BCL\system\runtime\remoting\activationservices.cs:line 175
https://referencesource.microsoft.com/#mscorlib/system/runtime/remoting/activationservices.cs,155

> at System.Runtime.Remoting.Activation.ActivationServices.CreateInstance(RuntimeType serverType) in f:\dd\ndp\clr\src\BCL\system\runtime\remoting\activationservices.cs:line 458
https://referencesource.microsoft.com/#mscorlib/system/runtime/remoting/activationservices.cs,443

> at System.Runtime.Remoting.RemotingServices.AllocateUninitializedObject(RuntimeType objectType)
https://referencesource.microsoft.com/#mscorlib/system/runtime/remoting/remotingservices.cs,230
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2024/4/9 12:08:06
> Excelのインスタンス生成ですか?Excelが拒否した時点で無視して良いログですか?

自分ならば、今回のケースではライブラリ内部のスタックトレースまでは気にしないですね。
「VB 側のどの行でエラーになったのか」と「HRESULT 値」までしか普段は見ないです。

開発環境では動作するというのであれば、どちらかというと、
主に「実行環境」に関する調査を行っていくと思います。

Windows のイベントログに追加情報が記録されていないか、とか、
Windows に新しいローカルユーザーを作ってログインしたら結果が変化しないか、とか、
Office の修復や再インストールで解決しないか、とか、
セキュリティソフトを止めてみたら改善しないか、とか、
32bit/64bit の確認やデスクトップ版/ストアアプリ版の確認を行うとか、
タスクスケジューラー等のサービスからの起動を行っていないか、とか、
オブジェクト参照の解放漏れで二回目以降のアクセスに障害が起きているのではないか、とか、
特定バージョンの Excel 更新が要因の可能性を疑ってみる(マイナーバージョンを確認)とか、
複数の Office が共存インストールされていることで実行環境が「汚れている」のではないか、とか、
他の PC で試してみたらどうなるか、とか…。

他の PC で再現しないなら、原因を特定するよりも、OS から入れなおした方が手っ取り早いこともありますし。
投稿者 ひでと  (社会人) 投稿日時 2024/4/9 15:14:28
遅くなりまして申し訳ありません。
ご教示いただいた皆様、高度で貴重なアドバイス大変ありがとうございます。
セキュリティーソフトもしくは、オフィス自体、その他の影響が大きいことが、なんとなくですが理解できました。

以下試したことと結果です。

1.Excelを手動で起動しようとすると、セキュリティーソフトによる表示が、
「Microsoft Office Home and Business 2019-ja-jpが動作を再開しました」
と表示が現れ、Excelを手動で、すぐに閉じ、再び起動するとメッセージが現れませんでした。

2.私のプログラムを起動中、「Excelへ出力ToolStripMenuItem_Click」を呼び出す前に、
Excelを手動で起動しておくと、エラーにならず処理が進みました。

3.2を確認したので、
    Private Sub Excelへ出力ToolStripMenuItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Excelへ出力ToolStripMenuItem.Click
        Dim i, j As Integer
        Dim xlApp As Excel.Application
        Try
            xlApp = New Excel.Application
        Catch ex As Exception
            MsgBox("Excelを手動で起動しておいてください")
            Exit Sub
        End Try
と書き換えて置き、Excelを閉じた状態で処理を呼び出すと、メッセージボックスが現れるようになりました。
手動でExcelを起動して、再び「Excelへ出力ToolStripMenuItem」を呼び出すと、正常に処理が進みました。

以上でエラーを回避することはできたのですが、
できれば、Excelが(手動で)起動されているかをプログラムから知ることができないか?
を課題と考えます。
Tryの分で処理すると時間がかかるような気がするのです。

投稿者 とくま  (社会人) 投稿日時 2024/4/9 16:36:14
まだ原因が明確になっていない気もしますが、(※注1)
セキュリティソフトがブロックしてるのが原因として、
2回連続起動っぽいことをすれば、
なぜかセキュリティソフトが通しちゃうらしいって
ことであれば、それいわゆるセキュリティホールと
言えるわけで、後日セキュリティソフトのアップデート
とかで完全に動かなくなったとか、ありえそうな未来
なんですけど、そんなんで大丈夫ですか?

普通の対応は、手動で起動してもセキュリティソフトの
メッセージが出ないようにする。。。だと思いますが。


(※注1)
ブロックしたなら、それなりのメッセージが出そうなものなのに
「動作を再開しました」だと起動を許してて辻褄が合わない。
エラーを出した時のプロセスが裏に残っててとか?一次的な
原因がまだ裏に隠れていて、二次的なメッセージが出てきた
ようにも見えるから。
そもそも、アプリからのExcelマクロファイルの起動とか
一番セキュリティソフトが警戒しなきゃいけない組み合わせ
なんだから、ブロックされて当然、このファイルやアプリは
チェック対象外ってセキュリティソフトに登録すべき場面で、
なんでプログラムで押し通そうとするん?
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2024/4/9 21:36:29
> Excelを手動で起動しておくと、エラーにならず処理が進みました。
ひとまず起動済みであれば通るということは、状況的に、
ROT (Running Object Table) への登録遅延が発生しているのかな…。

こんな記事が見つかりました。
https://learn.microsoft.com/en-us/archive/blogs/adioltean/when-cocreateinstance-returns-0x80080005-co_e_server_exec_failure?WT.mc_id=DT-MVP-8907

> Most of the time, this error says that the COM server process failed to start in time and register the proper class factory for this specific COM class. 
『ほとんどの場合、このエラーは、COM サーバー プロセスの開始が間に合わず、
この特定の COM クラスに適切なクラス ファクトリを登録できなかったことを示しています。』

> We will see in a second what can cause this, but the idea is that under heavy CPU load the machine can be pretty slow, and some out-of-process COM servers will fail to initialize properly. That said, there is a limited number of cases when this error is caused by bad configuration or even a bug in the server code.
『この原因については後ほど説明しますが、CPU 負荷が高いとマシンの動作が非常に遅くなり、一部のアウトプロセス COM サーバーが適切に初期化されなくなる可能性があるということです。ただし、このエラーが不適切な構成やサーバー コードのバグによって発生するケースは限られています。』


> Excelが(手動で)起動されているかをプログラムから知ることができないか?
起動済み判定された直後に、終了されてしまうというパターンも無いとは言えないですが、
ひとまず起動の有無だけなら、Process クラスで得られます。
この場合、非表示で起動されている Excel.exe も含まれます。

Dim p = Process.GetProcessesByName("Excel")


ただ、起動シーケンス中であったり、その逆に終了処理の最中という可能性もあるでしょうから、
起動していたからといっても、それが COM として使える状態になっているかは別問題ですけれどね。


> できれば、Excelが(手動で)起動されているかをプログラムから知ることができないか?
> を課題と考えます。
COM として取得することを目的とする場合は、GetObject を使うという手もあります。
この場合、取得できなければ例外として取得されます。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim xls As Object = Nothing
    Try
        xls = GetObject(, "Excel.Application")
    Catch 'ex As Exception 
        '起動済みでない場合、例外となる 
    End Try
    If xls Is Nothing Then
        MessageBox.Show(Me"Excel は起動されていません。""起動判定", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Return
    End If

    Dim xlApp = DirectCast(xls, Excel.Application)
    xlApp.Visible = True
    
    '中略 
    
    If Marshal.IsComObject(xlApp) Then
        Marshal.ReleaseComObject(xlApp)
        xlApp = Nothing
    End If
End Sub


また、GetObject(, "Excel.Application") の代わりに
GetObject(excelDocumentFilePath) とする方法もあります。

ファイルパスを指定した場合は、Excel が起動していなかった場合、自動的に Excel を起動してくれます。
(New Excel.Application が失敗する可能性がある環境なので、常時成功するのかどうかは未知数ですが)

ただしパスを指定する方式の場合、得られるインスタンスは Excel.Application 型ではなく
Excel.Workbook 型になる点に注意が必要です。なお、その Workbook インスタンスの
Application プロパティをたどれば、Excel.Application のインスタンスを得ることができます。


一方、GetObject(, "Excel.Application") を使う方法だと、Excel.Application のインスタンスが
複数存在していた場合、どれを拾うことになるのか確証が持てなくなるという欠点があります。
(CreateObject や New で起動した場合は、自身が起動したものであることが明確なのですが)

もし、起動済みの複数のインスタンスを列挙したいなら、GetRunningObjectTable API を使って取得する方法もあり。
https://hanatyan.sakura.ne.jp/vbnetbbs/wforum.cgi?mode=allread&no=10322
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2024/4/10 13:55:23
> xls = GetObject(, "Excel.Application")
これは、
 xls =  Marshal.GetActiveObject("Excel.Application")
と書いても良いですね。

機能的には同じもので、ROT(Running Object Table) から、
指定した COM オブジェクトの実行中のインスタンスを返します。

COM サーバーとの通信が確立できなければ例外になるので、
Try~Catch する必要があるのも同じ。


ちなみにこれは、Win32 API の GetActiveObject 関数 (oleaut32.dll) を呼び出しているだけです。
https://learn.microsoft.com/ja-jp/windows/win32/api/oleauto/nf-oleauto-getactiveobject?WT.mc_id=DT-MVP-8907

> Tryの分で処理すると時間がかかるような気がするのです。
元の API 自体が、取得失敗時に HRESULT エラー コードを返す実装なので、
例外処理が必要なのは仕方ないです…。

どうしても Try ~ Catch したくないのであれば、.NET の Managed ライブラリではなく、
同等機能の Win32 API を直接 DllImport (あるいは Declare) して呼び出すようにすることで、
HRESULT を例外としてではなく、32bit整数値として直接受け取ることができます。
投稿者 ひでと  (社会人) 投稿日時 2024/4/10 15:29:08
魔界の仮面弁士様ありがとうございます。

> Tryの分で処理すると時間がかかるような気がするのです。
元の API 自体が、取得失敗時に HRESULT エラー コードを返す実装なので、
例外処理が必要なのは仕方ないです…。

上記のこと分かりました。
現状の処理でいくことにします。

今回は使用しているセキュリティーソフトによるExcelの起動の遅延を疑うようになりましたが、
別のセキュリティーソフトの場合はエラーが出ない場合も有ると思います。
場当たり的ではありますが、処理は残しておこうと思います。

とくま様ご指摘ありがとうございます。

使用しているセキュリティーソフトがチェックしているのは、Excelの起動時であり、
Bookを開くときにチェックされているのかは、現状では分からないのだと考えています。
これは、Excelのふりをした別の悪意あるプログラムをチェックする処理だと思っています。
2重起動でスルーされているのが、セキュリティーホールだとは分からないです。
なんとなくですが、セキュリティーソフトのバージョンアップで、今作っているプログラム内で処理が出来なくなるのは、
考えなくても良いのではないかと思います。
その場合は、セキュリティーソフトを変更すれば良いと思いますし。

セキュリティーソフトのチェックを外すには、Excelへのチェック自体を外すことになりそうで怖いです。
(Bookを開くときのチェックでは無くExcelの起動時のチェックだと思いますので)
その為、マイルドな処理として、Excelを手動で別に起動してほしいというメッセージを出すことにしたつもりです。



投稿者 ひでと  (社会人) 投稿日時 2024/4/10 15:29:55
チェック忘れてました。
ありがとうございました。