2014-05-19 1 views
1

COM에서 호출 코드로의 콜백을 허용하는 COM 인터페이스를 만들려고합니다. C#에서 이에 대한 적절한 설명을 찾을 수없는 것 같습니다.COM 콜백을 구현하고 등록하는 방법

정상적인 COM 인터페이스가 작동하지만 콜백 파트를 올바르게 등록하고 설정하는 방법을 모르겠습니다.

"com"은 .com 사이트로 연결되며 실제 com 인터페이스는 포함하지 않는 대부분의 Google 검색어로 C#에서이를 올바르게 수행하는 방법에 대한 정보를 찾을 수 없습니다. 콜백 및 이벤트에 대해 이야기 할 때, 그들은 기본 non-com 것들만 포함합니다. 더 나은 정보를 얻을 수있는 출처를 지적한 경우에도 도움이 될 것입니다.

내 콜백 인터페이스는 다음과 같습니다

using System; 
using System.Runtime.InteropServices; 

namespace ComAdapter 
{ 
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
    [Guid("7f176b75-7b66-463a-94ab-493943792f88")] 
    public interface INet40Callback 
    { 
     [PreserveSig] 
     void Callback(string data); 
    } 
} 

I는 다음과 같이 노력 콜백 클래스 :

호출 응용 프로그램은 지금까지 다음과 같습니다
using net40lib; 
using System; 
using System.Runtime.InteropServices; 

namespace ComAdapter 
{ 
    [ClassInterface(ClassInterfaceType.None)] 
    [ComSourceInterfaces(typeof(INet40Callback))] 
    [Guid("023e4ad9-77d1-461e-af89-4cfc2b53959c")] 
    public class Net40Callback : INet40CallbackRegistration 
    { 
     [ComVisible(false)] 
     public delegate void MyCallbackDelegate(string data); 

     public event MyCallbackDelegate Callback; 

     public INet40Callback callbackObject; 

     public Net40Callback() 
     { 
      Net40Class.Instance.VersionSent += Instance_VersionSent; 
     } 

     void Instance_VersionSent(object sender, EventArgs e) 
     { 
      if (callbackObject != null) 
      { 
       callbackObject.Callback("blah"); 
      } 

      if (Callback != null) 
      { 
       Console.WriteLine("Instance_VersionSent Sending Callback"); 
       Callback("blah"); 
      } 
     } 

     public void RegisterCallback(INet40Callback reg) 
     { 
      if (reg is INet40Callback) 
      { 
       callbackObject = reg as INet40Callback; 
      } 
     } 
    } 
} 

:

using ComAdapter; 
using System; 
using System.Runtime.InteropServices; 

namespace net20lib 
{ 
    class Net40Callback : INet40Callback 
    { 
     [PreserveSig] 
     public void Callback(string data) 
     { 
      Console.WriteLine("Callback Called with data {0}", data); 
     } 
    } 
} 

등록 :

using System; 
using System.Runtime.InteropServices; 

namespace ComAdapter 
{ 
    [ComVisible(true)] 
    [Guid("3b2ab267-9e9a-47be-ab0a-f55db10a971e")] 
    public interface INet40CallbackRegistration 
    { 
     void RegisterCallback(INet40Callback callback); 
    } 
} 

테스트 클래스에서 호출 : 다음은 인터페이스의 구현 : C에서 #

INet40Callback callback = new Net40Callback(); 

Type myCallbackType = Type.GetTypeFromProgID("ComAdapter.Net40Callback"); 
object myCallbackInstance = Activator.CreateInstance(myCallbackType); 
INet40CallbackRegistration registration = (INet40CallbackRegistration)myCallbackInstance; 
registration.RegisterCallback(callback); 
+0

정확히 작동하지 않는 것은 무엇입니까? 귀하의 클라이언트 COM 테스트 애플 리케이션은'RegisterCallback'을 전혀 호출합니까? 목록에있는 C# 코드에는이 코드가 표시되지 않습니다. COMSourceInterfaces는 Interop Runtime이 암시 적으로 구현하는 IConnectionPointContainer 인터페이스를 통해 COM에 C# 클래스 이벤트를 노출하고자 할 때 사용됩니다. – Noseratio

+0

감사. 정보를 업데이트하고 지금 당장 시도한 코드를 업데이트했습니다. 내 코드가 현재 어떻게 보이는지 나타낼 수 있습니다 (작동에 더 가까워 야하지만 여전히 그렇지는 않습니다.) 콜백 클래스를 만들고 인터페이스로 등록하십시오.내 문제가 바로 지금 것 같다는 인터페이스가 올바르지 않다는 것을 알려주는, "HRESULT : 0x80004002 (E_NOINTERFACE)"InvalidCastException 얻을. 예외 텍스트는 독일어로되어 있으므로별로 도움이되지 않습니다. –

+0

영어로 예외를 찾아 보았습니다. 'System .__ ComObject'유형의 COM 개체를 인터페이스 유형 'ComAdapter.INet40Callback'으로 캐스팅 할 수 없습니다. 다음 오류로 인해 IID '{XXXXXXXX-XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}'인터페이스의 COM 구성 요소에서 QueryInterface 호출이 실패했기 때문에이 작업이 실패했습니다. 해당 인터페이스가 지원되지 않습니다 (HRESULT 예외 : 0x80004002 (E_NOINTERFACE)). . –

답변

1

당신은 정말 테스트해서는 안 C#을 COM 서버 : 등록

internal class Net40Callback : INet40Callback 
{ 
    [PreserveSig] 
    public void Callback(string data) 
    { 
     Console.WriteLine("Callback Called with data {0}", data); 
    } 
} 

강령 COM 클라이언트, 비 관리 코드에서 호출 할 때 작동하는 방식이 아닙니다. 그런 다음 INet40Callback에 대한 참조를 유지할 필요가없는 경우 event 선언은 COM 클라이언트가 IConnectionPointContainer (RegAsm에서 생성 한 형식 라이브러리 사용)을 통해 이벤트를 연결하기에 충분해야합니다. 두 옵션을 모두 지원하고 싶지 않은 경우

[ComImport] 
[ComVisible(true)] 
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 
[Guid("7f176b75-7b66-463a-94ab-493943792f88")] 
public interface INet40Callback 
{ 
    // .. 
} 

[ComVisible(true)] 
[ClassInterface(ClassInterfaceType.None)]] 
[ComDefaultInterface(typeof(INet40Callback))] 
internal class Net40Callback : INet40Callback 
{ 
    // ... 
} 

업데이트, 당신은 제거 외에도, C#을 측면에 많은 변경할 필요가 없습니다 : 어쨌든

는 현재 코드가 작동을 만들기 위해, [ComVisible(true)] Net40Callback에와 [ComImport] INet40Callback에 추가 시도 public INet40Callback callbackObject 참고. 그러나 이벤트를 테스트하려면 관리되지 않는 COM 클라이언트가 필요합니다. 일반 C++ COM 응용 프로그램, ATL/MFC C++ 응용 프로그램, VB6 응용 프로그램 또는 심지어 HTML 응용 프로그램 ( <object> 태그가있는 .HTA 파일) 일 수 있습니다. 후자 (테스트되지 않음)의 예가 있습니다. test.hta으로 복사하십시오. Windows 탐색기에서이 파일을 실행하십시오.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" ""> 
<html> 
<head> 
    <title>Managed COM Object Test</title> 

    <object id="managedObject" 
     classid="clsid:023e4ad9-77d1-461e-af89-4cfc2b53959c" 
     codebase="#version=0,0,0,0"> 
    </object> 

    <script for="managedObject" event="Callback(data)" type="text/javascript"> 
     output.innerText = "Callback(" + data + ") fired"; 
    </script> 
</head> 

<body> 
    <div id="output">&nbsp;</div> 
</body> 
</html> 
+0

클라이언트에있는 interal Net40Callback에 ComVisible을 추가해도 동일한 예외가 발생합니다. 다른 정보를 보려면 어떻게해야하는지 살펴 봐야 할 것입니다. –

+0

@private_meta, 그건'registration.RegisterCallback' 무엇입니까? 방금 코드를 수정하고 그런 식으로 시도해보십시오. – Noseratio

+1

본인의 정보로 귀하의 정보를 업데이트했으며 올바르게 작동하는 것 같습니다. 콜백 메서드는 COM 인터페이스에 의해 호출됩니다. 고마워. 나는 당신의 대답의 첫 부분을 작동 시키려고 노력할 것이지만, 나는 그것을 이해하지 못합니다. 어떻게해야합니까? 분명히 나는 ​​COM과 많이 일하지 않았다. –

관련 문제