약 40 명의 최종 사용자에게 배포되는 PPT 추가 기능에서 오류의 원인을 확인하는 데 어려움을 겪고 있습니다.PowerPoint 추가 기능 RibbonUI의 손실
문제점 : 리본 상태의 손실/리본 UI 객체의 손실.
일부 사용자의 경우 결국 Rib
개체는 Nothing
이됩니다.
사용자는 런타임 오류 나 스크립트 오류 (이 추가 기능을 통해 호출하는 COM 개체에서)가 발생하지 않는다고 확신합니다. 사용자가 End
에 도달하면 처리되지 않은 오류로 인해 상태 손실이 예상됩니다.
관찰 된 오류를 일으키는 시나리오를 안정적으로 재현 할 수있는 사용자가 없습니다. 이것이 문제 해결을 어렵게 만드는 이유입니다. 내가 누락 된 부분이나 예상하지 못한 부분이 있다는 희망에 반대하기를 희망합니다.
나는 현재 손실 또는 RibbonUI이, 나는 세 장소에서 리본에 개체 포인터를 저장 대처하기 위해 시도에서
, 이것은 나에게 잔인한 것 같아를 처리하지만 분명히 아직 충분하지 않다 방법 :
cbRibbon
이라는 클래스 개체는 할당 된.RibbonUI
속성을가집니다. 리본onLoad
콜백 절차 중에Set cbRibbon.RibbonUI = Rib
. 그래서 우리는 객체 자체의byRef
사본을 가지고 있습니다. 리본이 없으면 이론적으로Set rib = cbRibbon.RibbonUI
을 사용할 수 있으며cbRibbon
개체도 범위를 벗어나지 않으면이 작업이 가능합니다.cbRibbon
개체의 속성은.Pointer
이며cbRibbon.Pointer = ObjPtr(Rib)
입니다.- "RibbonPointer"라고하는
CustomDocumentProperty
도 개체 포인터에 대한 참조를 저장하는 데 사용됩니다. (참고 :이도 상태 손실 이상 지속)
그래서 내가 하나가 숨겨진 워크 시트에 저장 할 수이 포인터에게 길을 저장하는 방법을 복제 시도이 몇 가지 생각을 준 볼 수 있습니다/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
이 절차에서 가장 먼저해야 할 일은 Nothing
-ness 인 Rib
개체를 테스트하는 것입니다. 이 값이 True
으로 평가되면 RibbonUI 객체가 손실 된 것입니다. 다음 cbRibbon.Pointer
에서 cbRibbon.RibbonUI
에서제 이들 모두 다음 CustomDocumentProperties("RibbonPointer")
값에서 실패했을 경우는
에러 함수는 리본 재 인스턴스화. 이 두 가지가 모두 성공하지 못하면 치명적인 오류가 표시되고 PowerPoint 응용 프로그램을 닫으라는 메시지가 나타납니다. 이 중 하나라도 성공하면 리본이 프로그래밍 방식으로 다시로드되고 모든 것이 계속 작동합니다.
다음은이 절차의 코드입니다. 코드를 포함하지 않은 몇 가지 다른 프로 시저를 호출합니다. 이것들은 도우미 함수 또는 로거 함수입니다. .GetPointer
메서드는 실제로 포인터 값에서 개체를 다시로드하기 위해 WinAPI CopyMemory
함수를 호출합니다.
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
문을 호출 또는으로) 실행 시간을 죽이고 예상대로 이러한 절차가 리본을 다시 설정합니다. 그래서
Access 2010에서 내 자신의 리본 처리 방법을 살펴보면 리본 개체를 설정하기 위해'CopyMemory' API 호출을 사용하고있는 것을 볼 수 있습니다. 개인 함수 GetRibbon (lngRibPtr As Long) 객체 : 희미한 objRibbon 객체 : CopyMemory objRibbon, lngRibPtr, 4 : GetRibbon = objRibbon : Set objRibbon = Nothing : End Function' 아마도 당신을 도울 수 있습니까? – Bobort
@Bobort 예, 실제로이 WinAPI 호출을 내부적으로 사용하고 있습니다 (이 호출의 GetRibbon 메서드에서 : Set Rib = cbRibbon.GetRibbon (cbRibbon.Pointer)). 여기서 문제는 "포인터를 리본에서 복원하는 방법"이 아니라 A) 리본 상태가 손실되는 원인과 B) 어디에서 PowerPoint에서 포인터 값을 안정적으로 저장할 수 있는지 (디스크에 쓰거나 레지스트리를 변경하는 것이 바람직 함) 둘 다 할 수는 있지만 가능하면하지 않는 편이 더 좋습니다.) –