約 40 人のエンド ユーザーに配布されている PPT アドインのエラーの原因を特定するのに苦労しています。
問題:リボンの状態が失われるか、ribbonUI オブジェクトが失われます。
一部のユーザーにとって、最終的にRib
オブジェクトは になりNothing
ます。
ユーザーは、実行時エラーやスクリプト エラー (このアドインを介して呼び出す COM オブジェクトから) が発生していないことを保証します。End
ユーザーのヒットによって状態が失われることが予想される場合は、未処理のエラー。
観測された障害の原因となったシナリオを確実に再現できたユーザーはいません。これが、トラブルシューティングを非常に困難にしている原因です。私が見逃している、または予期していなかった明らかな何かがあるという希望に逆らって望んでいます。
現在の損失またはRibbonUIの処理方法
これに対抗するために、リボンへのオブジェクト ポインターを 3 つの場所に保存します。これはやり過ぎのように思えますが、まだ十分ではないようです。
- 呼び出されたクラス オブジェクトには、割り当てられ
cbRibbon
たプロパティがあります。リボンのコールバック手順中。したがって、オブジェクト自体のコピーがあります。リボンが何もない場合、理論的には可能であり、オブジェクトも範囲外でない限り、これは機能します。.RibbonUI
Set cbRibbon.RibbonUI = Rib
onLoad
byRef
Set rib = cbRibbon.RibbonUI
cbRibbon
cbRibbon
オブジェクトには次のプロパティ.Pointer
が割り当てられています:cbRibbon.Pointer = ObjPtr(Rib)
。CustomDocumentProperty
「RibbonPointer」という名前も、オブジェクト ポインターへの参照を格納するために使用されます。(注: これは、状態が失われた後も持続します)
したがって、Excel の非表示のワークシート/範囲に格納する方法と同じように、このポインターを格納する方法を複製しようとして、これについて考えてみたことがわかります。
追加情報
堅牢なクライアント側のログから、このエラーは通常発生するように見えますが、リボンとそのコントロールを更新/無効化するために使用される以下の手順中に常に発生するとは限りません。
このプロシージャは、リボンまたはそのコントロールの一部を動的に更新する必要があるたびに呼び出されます。
Call RefreshRibbon(id)
エラーは、次のように呼び出される完全な更新中に発生するようです (時々、これを十分に強調することはできません: エラーはオンデマンドで複製できません)。
Call RefreshRibbon("")
これは、無効化を行う手順です。
Sub RefreshRibbon(id As String)
If Rib Is Nothing Then
If RibbonError(id) Then GoTo ErrorExit
End If
Select Case id
Case vbNullString, "", "RibbonUI"
Call Logger.LogEvent("RefreshRibbon: Rib.Invalidate", Array("RibbonUI", _
"Ribbon:" & CStr(Not Rib Is Nothing), _
"Pointer:" & ObjPtr(Rib)))
Rib.Invalidate
Case Else
Call Logger.LogEvent("RefreshRibbon: Rib.InvalidateControl", Array(id, _
"Ribbon:" & CStr(Not Rib Is Nothing), _
"Pointer:" & ObjPtr(Rib)))
Rib.InvalidateControl id
End Select
Exit Sub
ErrorExit:
End Sub
ご覧のとおり、この手順で最初に行うことは、Rib
オブジェクトのNothing
-ness をテストすることです。これが と評価される場合True
、RibbonUI オブジェクトは何らかの理由で失われています。
次に、エラー関数はリボンの再インスタンス化を試みます。最初に からcbRibbon.RibbonUI
、次に から、cbRibbon.Pointer
両方が失敗した場合はCustomDocumentProperties("RibbonPointer")
値から。どちらも成功しない場合は、致命的なエラーが表示され、ユーザーは PowerPoint アプリケーションを閉じるように求められます。これらのいずれかが成功した場合、リボンはプログラムによって再読み込みされ、すべてが引き続き機能します。
その手順のコードは次のとおりです。コードを含めていない他のいくつかのプロシージャを呼び出すことに注意してください。これらはヘルパー関数またはロガー関数です。この.GetPointer
メソッドは実際に WinAPICopyMemory
関数を呼び出して、ポインター値からオブジェクトをリロードします。
Function RibbonError(id As String) As Boolean
'Checks for state loss of the ribbon
Dim ret As Boolean
If id = vbNullString Then id = "RibbonUI"
Call Logger.LogEvent("RibbonError", Array("Checking for Error with Ribbon" & vbCrLf & _
"id: " & id, _
"Pointer: " & ObjPtr(Rib), _
"cbPointer: " & cbRibbon.Pointer))
If Not Rib Is Nothing Then
GoTo EarlyExit
End If
On Error Resume Next
'Attempt to restore from class object:
Set Rib = cbRibbon.ribbonUI
'Attempt to restore from Pointer reference if that fails:
If Rib Is Nothing Then
'Call Logger.LogEvent("Attempt to Restore from cbRibbon", Array(cbRibbon.Pointer))
If Not CLng(cbRibbon.Pointer) = 0 Then
Set Rib = cbRibbon.GetRibbon(cbRibbon.Pointer)
End If
End If
'Attempt to restore from CDP
If Rib Is Nothing Then
'Call Logger.LogEvent("Attempt to Restore from CDP", Array(MyDoc.CustomDocumentProperties("RibbonPointer")))
If HasCustomProperty("RibbonPointer") Then
cbRibbon.Pointer = CLng(MyDoc.CustomDocumentProperties("RibbonPointer"))
Set Rib = cbRibbon.GetRibbon(cbRibbon.Pointer)
End If
End If
On Error GoTo 0
If Rib Is Nothing Then
Debug.Print "Pointer value was: " & cbRibbon.Pointer
'Since we can't restore from an invalid pointer, erase this in the CDP
' a value of "0" will set Rib = Nothing, anything else will crash the appliation
Call SetCustomProperty("RibbonPointer", "0")
Else
'Reload the restored ribbon:
Call RibbonOnLoad(Rib)
Call SetCustomProperty("RibbonPointer", ObjPtr(Rib))
cbRibbon.Pointer = ObjPtr(Rib)
End If
'Make sure the ribbon exists or was able to be restored
ret = (Rib Is Nothing)
If ret Then
'Inform the user
MsgBox "A fatal error has been encountered. Please save & restart the presentation", vbCritical, Application.Name
'Log the event to file
Call Logger.LogEvent("RibbonError", Array("FATAL ERROR"))
Call ReleaseTrap
End If
EarlyExit:
RibbonError = ret
End Function
これらはすべて理論上は完全にうまく機能し、実際には(ステートメントを呼び出すなどして) ランタイムを直接強制終了することができ、これらの手順によって期待どおりにリボンがリセットされます。End
それで、私は何が欠けていますか?