2016-11-30 2 views
7

몇 달 동안 끌고있는 COM 추가 기능에 문제가 있습니다. 그 이유를 알 수 없습니다.CommandBar 단추 정리

IDTExtensibility2 구현은 이미 Carlos Quintero (MZ-Tools의 뒤편에있는 사람)에 의해 검토되었으며 올바른 것으로 간주되었습니다. 자신의 권장 사항에 따라

OnBeginShutdown 구현 한 번만 실행 ShutdownAddIn을 보장하기 위해, OnDisconnection 체크 것 플래그를 설정 (일부 VBE 호스트 응용 프로그램 OnBeginShutdown를 호출하지 않는, 그 이유) :

public void OnBeginShutdown(ref Array custom) 
{ 
    _isBeginShutdownExecuted = true; 
    ShutdownAddIn(); 
} 

내 추가 DI/IoC에 대한 Ninject에를 사용하고, 내 ShutdownAddIn 방법은 Marshal.ReleaseComObject 모든 COM 객체를 Ninject에 IKernel 인스턴스에서 Dispose를 호출 한 다음 방출로 귀결 :

private void ShutdownAddIn() 
{ 
    if (_kernel != null) 
    { 
     _kernel.Dispose(); 
     _kernel = null; 
    } 
    _ide.Release(); 
    _isInitialized = false; 
} 

이 코드를 실행하는 데 이전 시간을 생각할 수 없습니다. 그러나, 명령 모음이/메뉴가 컨트롤을 해체 할 때 내 명령 모음 및 메뉴 래퍼에 Dispose 실행은, 내가 InvalidCastExceptionStopEvents에 받고 있어요 때

public void HandleEvents() 
{ 
    // register the unmanaged click events 
    ((Microsoft.Office.Core.CommandBarButton)Target).Click += Target_Click; 
} 

public void StopEvents() 
{ 
    // unregister the unmanaged click events 
    ((Microsoft.Office.Core.CommandBarButton)Target).Click -= Target_Click; 
} 

public event EventHandler<CommandBarButtonClickEventArgs> Click; 
private void Target_Click(Microsoft.Office.Core.CommandBarButton ctrl, ref bool cancelDefault) 
{ 
    // handle the unmanaged click events and fire a managed event for managed code to handle 
    var handler = Click; 
    if (handler == null) 
    { 
     return; 
    } 
    var args = new CommandBarButtonClickEventArgs(new CommandBarButton(ctrl)); 
    handler.Invoke(this, args); 
    cancelDefault = args.Cancel; 
} 

InvalidCastException 그것이 IConnectionPoint로 캐스팅 할 수 없습니다 이렇게 말한다 - 그리고 내가 찾은 것은이 코드가 실행될 때 내 Target (랩 된 __ComObject)이 이미 없어 졌기 때문에 잘못된 포인터와 느린 참조가 더 이상 COM 개체에 남아 있지 않기 때문입니다. 존재합니다.

티어 다운 과정에서 던져지는 모든 예외를 잡아 내면 (동일한 루트 문제로 인해 예외가 발생합니다. Delete 버튼과 메뉴를 시도 할 때) 호스트 응용 프로그램이 닫히지 만 호스트 프로세스는 남아 있습니다. 에서 작업 관리자을 죽여야합니다. 이 동작은 내가 생각한 제거되지 않은 클릭 핸들러로 인해 발생하는 메모리 누수와 일치합니다.


내가/추가, Microsoft.Office.Core.CommandBarButton 래퍼에 대한 이벤트 핸들러를 제거 해결할 수있는보다 강력한 방법이 있나요? OnBeginShutdown이 실행될 때 내 래핑 된 COM 객체가 아직 사라 졌을 때, 아직 풀어 놓지 않은 이유는 무엇입니까?

답변

5

내가 틀릴 수도 있지만 InvalidCastException은 일부 COM 개체가 없어 졌기 때문에 "기본 RCW에서 분리 된 COM 개체를 사용할 수 없습니다"라는 메시지가 나타날 것이라고 생각하지 않습니다. InvalidCastException은 유형이 다른 유형으로 변환 될 수 없으며 전체 이름 유형이 다르다는 명백한 경우뿐만 아니라 예를 들어 가장자리 사례에서도 볼 수 있습니다.

1) 형식의 전체 이름은 동일하지만 다른 어셈블리에서 가져온 것이거나 어떻게 든 다른 위치에서 두 번로드 한 동일한 어셈블리에서 가져온 것입니다. 예 : Isolating .NET-based add-ins for the VBA editor with COM Shims에 언급 된 사례 1

2) 동일한 유형의 전체 이름은 동일하지만 동일한 프로세스에서 다른 CLR (2.0/4.0)에로드되었습니다. 예 : The strange case of System.InvalidCastException (“Unable to cast COM object of type ‘System.__ComObject’ to class type System.Windows.Forms.UserControl”) showing toolwindow

캐스팅되는 유형의 전체 유형 이름/어셈블리 이름/CLR을 얻으려고 제안합니다. Microsoft.VisualBasic 참조에 대한 임시 참조를 추가하면 Microsoft.VisualBasic.Information.TypeName (object)을 사용하여 __ComObject 뒤에 실제 유형을 가져올 수 있습니다.

+0

다른 위치에서로드 된 어셈블리 ... 'Rubberduck.VBEditor.dll'이 문제를 일으킬 수 있습니다 ... 가장자리 케이스 1이 실제 가능성처럼 보입니다. –

+0

그것은 이상하게 들릴지 모르지만, 이것은 우리 자신의 @ Mat'sMug를 생성하는 대신에 Microsoft의 interop PIA 라이브러리를 사용하여 우리에게 줄 수 있습니까? 어둠 속에서 쐈어. https://www.mztools.com/articles/2012/MZ2012011.aspx – RubberDuck

+1

어제 밤에 그것을 보지 못했지만 지금은 handler.Invoke를 호출 한 후이를 볼 수 있습니다. marshal.ReleaseComObject on ctrl을 호출하지 않습니다. .NET- Target_Click 이벤트 처리기의 COM 쪽에서받는 RCW 쪽 RCW. 그건 누출이야. 또는이를 매개 변수로받는 CommandBarButton 래퍼가 Dispose 메서드에서 호출하는 경우에는 다음 가비지 수집 때까지 부동 상태로두기보다는 이벤트 처리기에서 Dispose 메서드를 호출해야합니다. –