[.net] COM interop 어셈블리로드 시퀀스


Answers

Microsoft의 기본 Interop 어셈블리 입문서에서 문제에 대한 해결책을 발견했다고 생각합니다. PIA는 Visual Studio에서 다르게 처리됩니다.

사용자가 등록 된 PIA가있는 형식 라이브러리에 대한 참조를 추가하려고하면 Visual Studio는 Tlbimp를 사용하여 형식 라이브러리를 다시 가져 오는 대신 등록 된 PIA를 자동으로 사용합니다. 이렇게하면 가능할 때마다 PIA가 사용됩니다.

즉, 자신의 IA에 대한 참조를 프로젝트에 추가하면 Visual Studio는이 COM 개체에 대해 PIA가 등록되어 있는지 여부를 확인합니다. Outlook PIA는 다음 키 아래에 등록됩니다.

HKEY_CLASSES_ROOT\CLSID\{0006F023-0000-0000-C000-000000000046}\InprocServer32\12.0.0.0
    Assembly="Microsoft.Office.Interop.Outlook, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71E9BCE111E9429C"

regasm 도구를 사용하여 PIA 등록을 취소하는 것이 핵심을 제거하고 자신의 IA에 대한 참조를 다시 추가하면 예상 결과를 제공해야한다는 것을 이해합니다.

그러나 PIA를 사용할 수있는 경우 사용자 지정 IA를 사용하지 않는 것이 좋습니다. 나는 정확한 이유를 이해하지 못한다. 그러나 이것은 마샬링 최적화와 고유 한 타입 정의와 관련 있다고 생각한다.

Question

아주 이상한 어셈블리 참조 문제 및 내 Outlook 추가 기능에서 발생하는 로딩 문제가 있습니다. 세부 사항은 다음과 같습니다 (긴 이야기 :)).

나는 오래된 Outlook addin을 가지고 있고 닷넷 1.1을 사용하여 작성하고 작성했다. 추가 기능은 자체 응용 프로그램 도메인에서 관리되지 않는 심을 사용하여로드됩니다. 1.1이 사용자 컴퓨터에 없더라도 .Net 2.0에서는 정상적으로 작동합니다.

추가 기능은 Outlook 2003에 대해 VS 2003에서 만든 사용자 지정 Outlook interop 어셈블리를 사용하고 그 후 다시 작성하여 강력한 추가 기능을 제공합니다 (내 추가 기능과 동일).

addin 프로젝트에서이 사용자 지정 interop 어셈블리 만 참조하며 공식 MS interop 어셈블리는 참조하지 않습니다.

이 addin이 Outlook 2007 및 공식 MS interop 어셈블리가 GAC에 설치된 .Net 2.0이있는 환경에서 사용되는 경우, 추가 기능이로드되어 사용되는 것을 볼 수 있습니다.

Connect 클래스의 코드에는 using 지시문이 있습니다.

using Outlook;

내 사용자 지정 interop 어셈블리의 네임 스페이스입니다.

Connect ctor에는 다음과 같은 코드 행이 있습니다 (테스트 목적으로 추가됨).

Assembly.LoadFrom(PATHTOMYASSEMBLY + "Interop.Outlook.dll");
Type type = typeof(Outlook.ApplicationClass);
logger.Debug("Outlook.Application full type is: {0}", type.AssemblyQualifiedName);

이 결과는 다음과 같습니다.

Outlook.Application 전체 형식 : Outlook.ApplicationClass, Interop.Outlook, 버전 = 9.0.0.0, 문화 = 중립, PublicKeyToken = 4cfbdc5349cf59d8

정확히 내가 기대했던 것입니다.

문제는 OnConnection (개체 응용 프로그램, Extensibility.ext_ConnectMode connectMode, 개체 addInInst, ref System.Array 사용자 지정) 호출 될 때, 나는 (현재 도메인의 AssemblyLoad 이벤트에 대한 후크가있는) 로그에서 MS interop 어셈블리도로드됩니다.

private void app_domain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{
    Assembly loadedAssembly = args.LoadedAssembly;
    logger.Debug("Assembly {0} is loaded from: {1}", loadedAssembly.FullName, loadedAssembly.GlobalAssemblyCache ? "GAC" : loadedAssembly.Location);
}

산출:

어셈블리 Microsoft.Office.Interop.Outlook, 버전 = 12.0.0.0, Culture = neutral, PublicKeyToken = 71e9bce111e9429c는에서로드했습니다 : GAC

내 OnConnection 메서드는 다음과 같이 시작됩니다.

public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
{
    Type type = application.GetType();
    logger.Debug("OnConnection application object's full type is: {0}", type.AssemblyQualifiedName);

    Outlook.Application applicationObject = (Outlook.Application)application;

이 결과는 다음과 같습니다.

OnConnection 응용 프로그램 개체의 전체 형식은 Microsoft.Office.Interop.Outlook.ApplicationClass, Microsoft.Office.Interop.Outlook, Version = 12.0.0.0, Culture = neutral, PublicKeyToken = 71e9bce111e9429c입니다.

이것은 정말 이상합니다. 다음 번에 성공적으로 Outlook으로 캐스팅 할 수 있음을 알 수 있습니다. 아무 문제없이 응용 프로그램을 사용할 수 있습니다.

리플렉터를 확인해 본 결과 어셈블리는 Microsoft의 interop 어셈블리를 참조하지 않습니다. 내 Interop.Outlook.dll과 동일합니다.

그래서, 어떤 일이 벌어지고 있는지 아는 사람이 있습니까? 이 질문에 대한 답은 무엇입니까?

  1. Microsoft 어셈블리를 전혀로드하지 않는 이유는 무엇입니까?

  2. 서로 다른 어셈블리에 정의 된 관련없는 클래스 / 인터페이스간에 어떻게 캐스팅 할 수 있습니까?

NOTE : 새로운 addin을 만들었습니다. 아주 간단한 것입니다. 문제를 재현 할 수 있기 때문에 CLR이 어떻게 interop을로드할지, 어디에서 결정 할지를 아는 사람이 누구인지 알 수 있습니다. GAC 외에 COM 개체와 interop간에 필요한 링크가있는 곳 (레지스트리 ???)이 있습니까?