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


168

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


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) 에 대해 컴파일러가 추가 한 다른 속성 은 트릭을 수행하지 않는 것 같습니다. 매직 소스는 무엇입니까?


11
선택적 매개 변수가 좋지 않습니까? IMO, 아니요 그들은 좋지 않습니다. Microsoft는 C #에 부풀림을 추가하여 Office COM 인터페이스의 결함을 수정하려고합니다.
Mehrdad Afshari

18
@Mehrdad : 물론 선택적 매개 변수는 COM 이상으로 유용합니다. 기본값에주의해야하지만, 값과 명명 된 인수 사이에서 사용 가능한 불변 유형을 작성하는 것이 훨씬 쉽습니다.
Jon Skeet

1
진실. 특히 일부 동적 환경과의 상호 운용을 위해서는 실제로 명명 된 매개 변수가 필요할 수 있습니다 . 의심의 여지없이 유용한 기능이지만 무료로 제공되는 것은 아닙니다. 단순성 (명시 적으로 명시된 설계 목표)이 필요합니다. 개인적으로 C #은 팀이 중단 한 기능에 놀랍습니다 (그렇지 않으면 C ++ 클론 일 수 있음). C # 팀은 훌륭하지만 회사 환경에는 정치가 거의 없습니다. 나는 생각 그의 PDC'08 이야기에 명시된대로 자신이 이것에 대해 매우 행복하지 않았다 앤더스를 : "우리가 있었던 곳으로 돌아가는 데 10 년이 걸렸다."
Mehrdad Afshari

7
팀이 복잡성을 면밀히 관찰해야한다는 데 동의합니다. 동적 요소는 대부분의 개발자 에게는 가치가 거의 없지만 일부 개발자 에게는 가치가 높기 때문에 많은 복잡성을 추가합니다 .
Jon Skeet

1
프레임 워크 개발자가 여러 곳에서 그 사용법을 논의하기 시작했습니다. IMO 그것은 우리가 잘 사용하기 전까지의 시간입니다 dynamic... 우리는 정적 / 강력한 타이핑에 너무 익숙하여 COM 외부에서 중요한 이유를 알 수 있습니다.
chakrit

답변:


145

결코 이것에 대한 전문가는 아니지만 최근에 내가 원하는 것, 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 { }

2
매우 흥미로운-나중에 시도합니다. 연결된 PIA 유형에는 CoClass가 없습니다. 어쩌면 그것은 연결 과정과 관련이있을 수 있습니다
Jon Skeet

64
Eric Lippert와 Jon Skeet도 답변했을 때 허용되는 답변을 작성하여 굉장한 +1 :) 아니요, 실제로 CoClass에 대해 +1했습니다.
OregonGhost

61

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

만약:

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

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

만약:

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

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

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


36

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

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 인터페이스를 위조하려고 시도하고 컴파일러가 링크하도록 할 수 있는지 확인하십시오 ...


27

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!


고마워, 시도했지만 ComImport 속성 이 누락 되었지만 소스 코드로 이동하면 F12를 사용하여 작업하고 CoClassGuid 만 표시됩니다 . 왜 그렇 습니까?
Ehsan Sajjad
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.