2

約 40 人のエンド ユーザーに配布されている PPT アドインのエラーの原因を特定するのに苦労しています。

問題:リボンの状態が失われるか、ribbonUI オブジェクトが失われます。

一部のユーザーにとって、最終的にRibオブジェクトは になりNothingます。

ユーザーは、実行時エラーやスクリプト エラー (このアドインを介して呼び出す COM オブジェクトから) が発生していないことを保証します。Endユーザーのヒットによって状態が失われることが予想される場合は、未処理のエラー。

観測された障害の原因となったシナリオを確実に再現できたユーザーはいません。これが、トラブルシューティングを非常に困難にしている原因です。私が見逃している、または予期していなかった明らかな何かがあるという希望に逆らって望んでいます。

現在の損失またはRibbonUIの処理方法

これに対抗するために、リボンへのオブジェクト ポインターを 3 つの場所に保存しますこれはやり過ぎのように思えますが、まだ十分ではないようです。

  • 呼び出されたクラス オブジェクトには、割り当てられcbRibbonたプロパティがあります。リボンのコールバック手順中。したがって、オブジェクト自体のコピーがあります。リボンが何もない場合、理論的には可能であり、オブジェクトも範囲外でない限り、これは機能します。.RibbonUISet cbRibbon.RibbonUI = RibonLoadbyRefSet rib = cbRibbon.RibbonUIcbRibbon
  • 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

ここに画像の説明を入力

それで、私は何が欠けていますか?

4

2 に答える 2