[C#] C # 컴파일러는 COM 유형을 어떻게 감지합니까?

편집 : 나는 블로그 게시물 로 결과를 작성 했습니다 .


C # 컴파일러는 COM 유형을 다소 마술처럼 처리합니다. 예를 들어,이 문장은 정상적으로 보입니다 …

Word.Application app = new Word.Application();

Application인터페이스 임을 알 때까지 . 인터페이스에서 생성자를 호출 하시겠습니까? 요 익스! 이것은 실제로에 대한 호출 Type.GetTypeFromCLSID()및 로의 다른 호출로 변환됩니다 Activator.CreateInstance.

또한 C # 4에서는 ref매개 변수에 비 참조 인수를 사용할 수 있으며 컴파일러는 로컬 변수를 참조로 전달하여 결과를 무시합니다.

// FileName parameter is *really* a ref parameter
app.ActiveDocument.SaveAs(FileName: "test.doc");

(예, 많은 인수가 누락되었습니다. 선택적 매개 변수가 좋지 않습니까? 🙂

컴파일러 동작을 조사하려고하는데 첫 번째 부분을 위조하지 못했습니다. 나는 문제없이 두 번째 부분을 할 수 있습니다.

using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

[ComImport, GuidAttribute("00012345-0000-0000-0000-000000000011")]
public interface Dummy
{
    void Foo(ref int x);
}

class Test
{
    static void Main()
    {
        Dummy dummy = null;
        dummy.Foo(10);
    }
}

다음과 같이 쓸 수 있기를 원합니다.

Dummy dummy = new Dummy();

그러나. 분명히 그것은 실행 시간에 쾅 할 것이지만 괜찮습니다. 방금 실험 중입니다.

연결된 COM PIA ( CompilerGeneratedTypeIdentifier) 에 대해 컴파일러가 추가 한 다른 속성 은 트릭을 수행하지 않는 것 같습니다. 매직 소스는 무엇입니까?



답변

결코 이것에 대한 전문가는 아니지만 최근에 내가 원하는 것, CoClass 속성 클래스 에 대해 우연히 발견했습니다 .

[System.Runtime.InteropServices.CoClass(typeof(Test))]
public interface Dummy { }

코 클래스는 하나 이상의 인터페이스의 구체적인 구현을 제공합니다. COM에서 이러한 구체적인 구현은 COM 구성 요소 개발을 지원하는 모든 프로그래밍 언어 (예 : Delphi, C ++, Visual Basic 등)로 작성 될 수 있습니다.

인터페이스를 “인스턴스화”할 수 있는 Microsoft Speech API에 대한 비슷한 질문에 대한 나의 답변을 참조하십시오 SpVoice(실제로 인스턴스화하고 있습니다 SPVoiceClass).

[CoClass(typeof(SpVoiceClass))]
public interface SpVoice : ISpeechVoice, _ISpeechVoiceEvents_Event { }


답변

당신과 마이클 사이에 조각들이 거의 다 갖추어졌습니다. 이것이 작동하는 방식이라고 생각합니다. (코드를 작성하지 않았으므로 약간 잘못 설명했을 수도 있지만 이것이 어떻게 진행되는지는 확실합니다.)

만약:

  • 인터페이스 유형을 “새로 작성”하고
  • 인터페이스 유형에는 알려진 코 클래스가 있으며
  • 이 인터페이스에 “피아 없음”기능을 사용하고 있습니다

그런 다음 코드는 (IPIAINTERFACE) Activator.CreateInstance (Type.GetTypeFromClsid (GUID OF COCLASSTYPE))로 생성됩니다.

만약:

  • 인터페이스 유형을 “새로 작성”하고
  • 인터페이스 유형에는 알려진 코 클래스가 있으며
  • 이 인터페이스에 “피아 없음”기능을 사용하지 않습니다

“new COCLASSTYPE ()”이라고 말한 것처럼 코드가 생성됩니다.

존,이 문제에 대해 궁금한 점이 있으면 언제든지 저나 샘에게 직접 버그를 보내십시오. 참고로 Sam은이 기능의 전문가입니다.


답변

자, 이것은 마이클의 대답에 약간의 육체를 넣는 것입니다 (그가 원한다면 그것을 추가하는 것을 환영합니다.이 경우 나는 이것을 제거 할 것입니다).

Word.Application의 원본 PIA를 살펴보면 세 가지 유형이 있습니다 (이벤트 무시).

[ComImport, TypeLibType(...), Guid("..."), DefaultMember("Name")]
public interface _Application
{
     ...
}

[ComImport, Guid("..."), CoClass(typeof(ApplicationClass))]
public interface Application : _Application
{
}

[ComImport, ClassInterface(...), ComSourceInterfaces("..."), Guid("..."),
 TypeLibType((short) 2), DefaultMember("Name")]
public class ApplicationClass : _Application, Application
{
}

Eric Lippert가 다른 답변 에서 말하는 이유에는 두 가지 인터페이스가 있습니다 . 그리고 당신이 말했듯이, CoClass클래스 자체와 Application인터페이스 의 속성 측면 에서 – 입니다.

이제 C # 4에서 PIA 링크를 사용하면 이 중 일부 가 결과 바이너리에 포함되지만 전부는 아닙니다. 응용 프로그램 단지 의 인스턴스 생성 Application이러한 종류의 최대 끝을 :

[ComImport, TypeIdentifier, Guid("..."), CompilerGenerated]
public interface _Application

[ComImport, Guid("..."), CompilerGenerated, TypeIdentifier]
public interface Application : _Application

아니요 ApplicationClass-아마도 실행 시간에 실제 COM 유형에서 동적으로로드되기 때문입니다 .

또 다른 흥미로운 점은 링크 된 버전과 링크되지 않은 버전 간의 코드 차이입니다. 라인을 디 컴파일하면

Word.Application application = new Word.Application();

에서 참조 된 버전이로 끝난다 :

Application application = new ApplicationClass();

반면 링크 된 버전에서는

Application application = (Application)
    Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("...")));

“진짜”PIA가 필요 것 같습니다 그래서 CoClass속성을하지만,이 때문에 링크 된 버전은하지 않습니다 하지CoClass 컴파일러 수 실제로 참조. 동적으로 수행해야합니다.

이 정보를 사용하여 COM 인터페이스를 위조하려고 시도하고 컴파일러가 링크하도록 할 수 있는지 확인하십시오 …


답변

Michael의 답변에 약간의 확인을 추가하려면 다음을 수행하십시오.

다음 코드는 컴파일 및 실행됩니다.

public class Program
{
    public class Foo : IFoo
    {
    }

    [Guid("00000000-0000-0000-0000-000000000000")]
    [CoClass(typeof(Foo))]
    [ComImport]
    public interface IFoo
    {
    }

    static void Main(string[] args)
    {
        IFoo foo = new IFoo();
    }
}

당신은 모두가 필요 ComImportAttribute하고 GuidAttribute작업에 대한합니다.

또한 마우스를 마우스로 가리키면 정보가 나타납니다 new IFoo(). Intellisense가 정보를 올바르게 선택합니다. Nice!


답변