トップ回答者
[Excel VBA] 新しいインスタンス (New Application) で起動した Excel でウィンドウが非表示のマクロブックを開いてそのマクロブックの中でシート保護をした非表示のブックを開くと落ちる

質問
-
説明が難しいのですが、例えば同じフォルダ内に test.xlsx、test.xlsm、test2.xlsm の
1 つのブックと 2 つのマクロブックを作ってマクロブックはそれぞれ以下のような
マクロを書いておきます。test.xlsm (Module1)
Sub test() ChDir ThisWorkbook.Path With New Application .Visible = True .Workbooks.Open ThisWorkbook.Path & "\test2.xlsm", , True End With End Sub
test2.xlsm (ThisWorkbook)
Private Sub Workbook_Open() ChDir ThisWorkbook.Path With Workbooks.Open("test.xlsx", , True) .Unprotect .Windows(1).Visible = True End With End Sub
test2.xlsm はウィンドウを非表示にして保存します。
test.xlsx はシートの保護を設定してウィンドウの非表示をして保存します。test.xlsm の test メソッドを実行すると test2.xlsm の
.Windows(1).Visible = True
のところで Excel が落ちて test.xlsm 側で
オートメーションエラーが発生してしまうようです。
なお、test2.xlsm か test.xlsx のどちらかを表示状態にしていたり
test.xlsx のシート保護を解除している状態では発生しませんでした。この件に関する情報などはありませんか。
- 編集済み infade 2022年10月11日 5:33 タイトルの追記
回答
-
提示された AppCrash ログでは、excel.exe プロセス内のオフセット 0x00000000005cc575 で、STATUS_ACCESS_VIOLATION エラーが発生したことを示しています。
Excel で追加しているアドインがある場合、それらを全て削除した状態でもクラッシュするのか、検証されることをお勧めします。
アドインを削除しても改善され無い場合は、さらにクリーン ブート設定を行い検証されることをお勧めします。
---------------------------------------------
Windows でクリーン ブートを実行する方法
https://support.microsoft.com/ja-jp/help/929135/how-to-perform-a-clean-boot-in-windows
---------------------------------------------
それでも改善しないのであれば先に示した Blog でも説明されている様に、WER (Windows Error Reporting) のレジストリ設定を行い AppCrash 時のクラッシュ ダンプを採取し、それを解析すればよいかと。- 回答としてマーク infade 2022年10月17日 6:35
すべての返信
-
FYI
-----------------------
イベント ID 1000 で記録される Application Error のイベント ログについて
https://jpdscore.github.io/blog/debugging/application-error-eventlog/
-----------------------
すみません。
該当するログは以下です。
障害が発生しているアプリケーション名: EXCEL.EXE、バージョン: 16.0.5356.1000、タイム スタンプ: 0x62ce4588 障害が発生しているモジュール名: EXCEL.EXE、バージョン: 16.0.5356.1000、タイム スタンプ: 0x62ce4588 例外コード: 0xc0000005 障害オフセット: 0x00000000005cc575 障害が発生しているプロセス ID: 0x25ac 障害が発生しているアプリケーションの開始時刻: 0x01d8e1dfd4655698 障害が発生しているアプリケーション パス: C:\Program Files\Microsoft Office\Office16\EXCEL.EXE 障害が発生しているモジュール パス: C:\Program Files\Microsoft Office\Office16\EXCEL.EXE レポート ID: a135f1ec-a46f-41cb-9919-ae454949fb74 障害が発生しているパッケージの完全な名前: 障害が発生しているパッケージに関連するアプリケーション ID:
障害バケット 1415413911155373052、種類 4 イベント名: APPCRASH 応答: 使用不可 Cab ID: 0 問題の署名: P1: EXCEL.EXE P2: 16.0.5356.1000 P3: 62ce4588 P4: EXCEL.EXE P5: 16.0.5356.1000 P6: 62ce4588 P7: c0000005 P8: 00000000005cc575 P9: P10: 添付ファイル: \\?\C:\xxxx\test2.xlsm \\?\C:\xxxx\test.xlsx \\?\C:\Users\xxxx\AppData\Local\Temp\{52860324-F978-42A1-AC0E-0363DD5EA1CA} - OProcSessId.dat \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER44D5.tmp.WERInternalMetadata.xml \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER44F5.tmp.xml \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER44F4.tmp.csv \\?\C:\ProgramData\Microsoft\Windows\WER\Temp\WER4534.tmp.txt これらのファイルは次の場所にある可能性があります: \\?\C:\ProgramData\Microsoft\Windows\WER\ReportArchive\AppCrash_EXCEL.EXE_4c9b9a393caa138a10a5efeb6147d7d3810bb39_00000000_a49ef868-3d72-4a89-9680-e8a773e0cd8f 分析記号: 解決策を再確認中: 0 レポート ID: a135f1ec-a46f-41cb-9919-ae454949fb74 レポートの状態: 268435456 ハッシュされたバケット: f326fe8ca517f9bb33a48f73f88ff3fc Cab GUID: 0
-
提示された AppCrash ログでは、excel.exe プロセス内のオフセット 0x00000000005cc575 で、STATUS_ACCESS_VIOLATION エラーが発生したことを示しています。
Excel で追加しているアドインがある場合、それらを全て削除した状態でもクラッシュするのか、検証されることをお勧めします。
アドインを削除しても改善され無い場合は、さらにクリーン ブート設定を行い検証されることをお勧めします。
---------------------------------------------
Windows でクリーン ブートを実行する方法
https://support.microsoft.com/ja-jp/help/929135/how-to-perform-a-clean-boot-in-windows
---------------------------------------------
それでも改善しないのであれば先に示した Blog でも説明されている様に、WER (Windows Error Reporting) のレジストリ設定を行い AppCrash 時のクラッシュ ダンプを採取し、それを解析すればよいかと。- 回答としてマーク infade 2022年10月17日 6:35
-
提示された AppCrash ログでは、excel.exe プロセス内のオフセット 0x00000000005cc575 で、STATUS_ACCESS_VIOLATION エラーが発生したことを示しています。
Excel で追加しているアドインがある場合、それらを全て削除した状態でもクラッシュするのか、検証されることをお勧めします。
アドインを削除しても改善され無い場合は、さらにクリーン ブート設定を行い検証されることをお勧めします。
---------------------------------------------
Windows でクリーン ブートを実行する方法
https://support.microsoft.com/ja-jp/help/929135/how-to-perform-a-clean-boot-in-windows
---------------------------------------------
それでも改善しないのであれば先に示した Blog でも説明されている様に、WER (Windows Error Reporting) のレジストリ設定を行い AppCrash 時のクラッシュ ダンプを採取し、それを解析すればよいかと。
以下のようにもっと簡単にウィンドウを非表示にした test1.xlsx と
test.xlsm (Module1)
シートの保護とウィンドウの非表示をした test2.xlsx を作っても
同様です。
(前述のコードではシートの保護解除ではなく、ブックの
保護解除していました)Sub test() ChDir ThisWorkbook.Path ' test1.xlsx を作成 With Workbooks.Add ' ウィンドウの非表示 .Windows(1).Visible = False ' 保存 .SaveAs "test1.xlsx", xlOpenXMLWorkbook ' 閉じる .Close End With ' test2.xlsx を作成 With Workbooks.Add ' シートの保護 (保護する項目は 1 つ以上ならなんでもいい模様) .ActiveSheet.Protect , True ' ウィンドウの非表示 .Windows(1).Visible = False ' 保存 .SaveAs "test2.xlsx", xlOpenXMLWorkbook ' 閉じる .Close End With ' 新しい Excel インスタンスを起動する With New Application ' 新しいインスタンスのウィンドウを表示する .Visible = True ' test1.xlsx を読み取り専用で開く .Workbooks.Open ThisWorkbook.Path & "\test1.xlsx", , True ' test2.xlsx を読み取り専用で開く With .Workbooks.Open(ThisWorkbook.Path & "\test2.xlsx", , True) ' .ActiveSheet.Unprotect ' シートの保護解除をすると正常動作する ' 以下の部分で落ちる .Windows(1).Visible = True ' .Windows(1).Activate でも同様 End With End With End Sub
- 編集済み infade 2022年10月17日 6:31 少しコードのコメントを修正
-
以下のようにもっと簡単にウィンドウを非表示にした test1.xlsx と
test.xlsm (Module1)
シートの保護とウィンドウの非表示をした test2.xlsx を作っても
同様です。
(前述のコードではシートの保護解除ではなく、ブックの
保護解除していました)Sub test() ChDir ThisWorkbook.Path ' test1.xlsx を作成 With Workbooks.Add ' ウィンドウの非表示 .Windows(1).Visible = False ' 保存 .SaveAs "test1.xlsx", xlOpenXMLWorkbook ' 閉じる .Close End With ' test2.xlsx を作成 With Workbooks.Add ' シートの保護 (保護する項目は 1 つ以上ならなんでもいい模様) .ActiveSheet.Protect , True ' ウィンドウの非表示 .Windows(1).Visible = False ' 保存 .SaveAs "test2.xlsx", xlOpenXMLWorkbook ' 閉じる .Close End With ' 新しい Excel インスタンスを起動する With New Application ' 新しいインスタンスのウィンドウを表示する .Visible = True ' test1.xlsx を読み取り専用で開く .Workbooks.Open ThisWorkbook.Path & "\test1.xlsx", , True ' test2.xlsx を読み取り専用で開く With .Workbooks.Open(ThisWorkbook.Path & "\test2.xlsx", , True) ' .ActiveSheet.Unprotect ' シートの保護解除をすると正常動作する ' 以下の部分で落ちる .Windows(1).Visible = True ' .Windows(1).Activate でも同様 End With End With End Sub
もう少しいろいろ調べてたら
Window.Visible = True
をする前に以下のように
ShowWindow で表示してやるとなぜか落ちないよいうです。With .Workbooks.Open(ThisWorkbook.Path & "\test2.xlsx", , True) ShowWindow .Windows(1).hWnd, SW_SHOW ' 追加 .Windows(1).Visible = True End With
-
いろいろ試してみたところ、New Application で作ったものだけではなく
Shell 関数で起動してプロセス ID からウィンドウハンドルを取得、
ウィンドウハンドルを Excel オブジェクトに変換した場合も同様の症状でした。Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As LongPtr, lpdwProcessId As Long) As Long Private Declare PtrSafe Function GetWindow Lib "user32" (ByVal hWnd As LongPtr, ByVal wCmd As Long) As LongPtr Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long Private Declare PtrSafe Sub AccessibleObjectFromWindow Lib "OLEACC.DLL" (ByVal hWnd As LongPtr, ByVal dwId As Long, riid As GUID, ppvObject As Any) ' 次のウィンドウ Const GW_HWNDNEXT As Long = 2 ' GUID を定義 Private Type GUID lData1 As Long iData2 As Integer iData3 As Integer aBData4(0 To 7) As Byte End Type Private Const OBJID_NATIVEOM = &HFFFFFFF0 ' IDispatch を設定 Private Sub SetIDispatch(ByRef ID As GUID) With ID .lData1 = &H20400 .iData2 = &H0 .iData3 = &H0 .aBData4(0) = &HC0 .aBData4(1) = &H0 .aBData4(2) = &H0 .aBData4(3) = &H0 .aBData4(4) = &H0 .aBData4(5) = &H0 .aBData4(6) = &H0 .aBData4(7) = &H46 End With End Sub ' ウィンドウハンドルから Excel オブジェクトを取得する Function GetXLApp(hWnd As LongPtr) As Application Dim hXlWnd As LongPtr Dim IDispatch As GUID Dim oWnd As Object ' Excel のウィンドウハンドルから Excel ワークブックのウィンドウを取得し ' Excel オブジェクトに変換する hXlWnd = FindWindowEx(FindWindowEx(hWnd, 0, "XLDESK", vbNullString), 0, "EXCEL7", vbNullString) If hXlWnd <> 0 Then SetIDispatch IDispatch ' Excel オブジェクトの取得 AccessibleObjectFromWindow hXlWnd, OBJID_NATIVEOM, IDispatch, oWnd ' オブジェクトの型が Window の場合は成功 If TypeName(oWnd) = "Window" Then Set GetXLApp = oWnd.Application End If End If End Function Sub test() Dim p As Long Dim hWnd As LongPtr Dim pID As Double Dim cname As String, cpt As String Dim xlApp As Application Dim d As String ' 自分のワークブックパスを取得 d = ThisWorkbook.Path ' Excel を別のインスタンスで起動してプロセス ID を取得 pID = Shell("excel.exe /x /r """ & d & "\test1.xlsx""") ' 約 2 秒待機 Application.Wait DateAdd("s", 2, Now) ' 起動中の Excel のウィンドウを取得する (取得されるウィンドウは不定) hWnd = FindWindowEx(0, 0, "xlmain", vbNullString) ' 自分のウィンドウを取得するまでループ Do Until ThisWorkbook.Windows(1).hWnd = hWnd ' クレス名を取得する変数を初期化 cname = String(100, vbNullChar) ' クラス名を取得 GetClassName hWnd, cname, 99 ' クラス名の後ろのゴミを除去 For i = 1 To Len(cname) If Asc(Mid(cname, i, 1)) = 0 Then Exit For End If Next cname = LCase$(Left$(cname, i - 1)) ' Excel のウィンドウの場合に処理 If cname = "xlmain" Then ' ウィンドウからプロセス ID を取得 GetWindowThreadProcessId hWnd, p ' 起動した Excel のプロセス ID と同じだったらループを抜ける If pID = p Then Exit Do End If End If ' 次のウィンドウを取得してループ hWnd = GetWindow(hWnd, GW_HWNDNEXT) DoEvents Loop ' ウィンドウハンドルから Excel オブジェクトを取得 Set xlApp = GetXLApp(hWnd) If Not xlApp Is Nothing Then ' ファイルをオープンしてウィンドウ表示 (落ちる) xlApp.Workbooks.Open(d & "\test2.xlsx", , True).Windows(1).Visible = True End If End Sub
-
その後もいろいろ調べてみるとこの現象は以下の条件がそろった時に
再現するようです。
(なお、以下ではウィンドウを非表示にしているだけのブックを test1.xlsx、
シートの保護とウィンドウの非表示をしているブックを test2.xlsx と
仮定します)- New Application や CreateObject("Excel.Application")、
excel.exe /e などのように初期表示ウィンドウが空の Excel を起動する - 上記の Excel 上にほかのウィンドウが表示されていない状態で
test1.xlsx と test2.xlsx を開く - test2.xlsx のウィンドウを VBA で表示 (.Visible = True) しようとする
1. で起動した Excel 上に表示されているウィンドウがひとつもない状態で
VBA で test2.xlsx のウィンドウを表示しようとすることが原因のようです。通常の起動をした場合は再現しないこと、手動でウィンドウ表示したときは
再現せず VBA から操作したときのみ再現すること、表示されているウィンドウが
ひとつでもあれば再現しないこと、1. の条件で起動した Excel 上であれば
ほかのウィンドウを一度表示したとしてもその後に条件さえそろえば再現すること
などがわかりました。test2.xlsx のウィンドウを手動で表示した後に非表示に戻しても再現しないようで
非表示状態で保存されているブックを開き直すと再現するようになります。挙動的に Excel 側の不具合だと思うのですが。
- 編集済み infade 2022年12月7日 1:55 行間調整してみた
- New Application や CreateObject("Excel.Application")、