2017-02-03 4 views
-1

COM 인터페이스를 노출하는 비 관리 C++로 작성된 COM Dll이 있습니다. idl의 간단한 샘플은 다음과 같습니다.COM 인터페이스 포인터에 대한 포인터를 관리되는 C++에서 .NET C#

import "oaidl.idl"; 
import "ocidl.idl"; 

[ 
    object, 
    uuid(A806FAED-FCE2-4F1B-AE67-4B36D398508E), 
    dual, 
    nonextensible, 
    pointer_default(unique) 
] 
interface IObjectToPass : IDispatch{ 
    [propget, id(1)] HRESULT Name([out, retval] BSTR* pVal); 
    [propput, id(1)] HRESULT Name([in] BSTR newVal); 
}; 
[ 
    uuid(B99537C0-BEBC-4670-A77E-06AB5350DC23), 
    version(1.0), 
] 
library  { 
    importlib("stdole2.tlb"); 
    [ 
     uuid(FB7C7D08-0E38-40D2-A160-0FC8AE76C3CF)  
    ] 
    coclass ObjectToPass 
    { 
    [default] interface IObjectToPass; 
    }; 
}; 

IObjectToPass 인터페이스는 노출 된 인터페이스입니다. 이제 IObjectToPass 인터페이스를 사용할 수 있도록이 COM 개체를 tlbimp로 만든 Interop를 통해 가져 오는 C# .NET 라이브러리 (ObjectConsumer)를 구현했습니다. 다음은이 라이브러리의 샘플 코드 아래 :

using Interop.ComTest; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text;ComTestLib 

using System.Threading.Tasks; 

namespace ObjectConsumer 
{ 
    public class Consumer 
    { 
     public void PassObject(IObjectToPass passobj) 
     { 
      string str = passobj.Name; 
     } 
    } 
} 

모두 C++와 C#을 모듈 문제없이 수입 과를 통해 모두 ComTestLib을 가져

지금은 C에서 간단한 콘솔 응용 프로그램을 만든 ++ 느릅 나무 지원 CLR을 컴파일 소비자가 콘솔 응용 프로그램 프로젝트에 대한 참조를 추가합니다. 내 목표는 내 콘솔 응용 프로그램 내에서 ObjectToPass의 인스턴스를 얻을

#include "stdafx.h" 
#import "..\Debug\ComTest.tlb" no_namespace, raw_interfaces_only 

int main() 
{ 
    CoInitialize(NULL); 
    IObjectToPassPtr obj; 

    HRESULT hr = obj.CreateInstance(__uuidof(IObjectToPass)); 
    ObjectConsumer::Consumer^ consumer = gcnew ObjectConsumer::Consumer(); 
    obj->put_Name(_T("MyName")); 
    consumer->PassObject(obj); 

    CoUninitialize(); 
     return 0; 
} 

아래에 컴파일되지 않습니다이 코드를 쇼와 공공 방법을 PassObject 호출 소비자에게 전달하는 것입니다. 컴파일러는 인수 1을 'IObjectToPassPtr'에서 'Interop :: ComTest :: IObjectToPass ^'로 변환 할 수 없습니다. 다른 시도를했지만 IObjectToPass *를 'Interop :: ComTest :: IObjectToPass ^'로 캐스팅 할 수 없습니다. 그것을 할 수있는 방법이 있습니까?

+0

blech! 당신은 정말로 무엇을하려고합니까? 스트레이트 C++/CLI (COM 없음)가 더 쉬울까요? –

+0

[Marshal.GetUniqueObjectForIUnknown] (https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getuniqueobjectforiunknown (v = vs.110) .aspx)이 필요할 수도 있습니다. 그것은 당신에게 관리되지 않는'obj' 인터페이스를위한 관리되는'Object :: Consumer' 인스턴스를주기 위해서 나타납니다. –

+0

저는 움직여야 할 시나리오를 시뮬레이트했습니다. 여기서 설명하기에는 너무 복잡합니다. 난 주 응용 프로그램에서 com unmanaged dll 전달해야합니다 .NET 개체를이 unmanged dll 바꾸려면 세 번째 부분 com 개체를 전달하고 세 번째 부분을 com 개체를 사용했습니다했습니다. –

답변

0

COM 인터페이스를 건너 뛰고 C++에서 팩토리 함수를 내 보냅니다. C#에서

이제
#define MY_API __declspec(dllexport) 
#ifdef __cplusplus 
# define EXTERNC extern "C" 
#else 
# define EXTERNC 
#endif 

EXTERNC MY_API IObjectToPass* APIENTRY MyFactory(void); 
EXTERNC MY_API void APIENTRY SomeFunction(IObjectToPass* handle); 

// Implementation: 

MY_API IObjectToPass* APIENTRY MyFactory(void) 
{ 
    return new ObjectToPass(); 
} 
MY_API void APIENTRY SomeFunction(IObjectToPass* handle) 
{ 
    handle->DoFunction(); 
} 

// And then export any needed functions too. 

:

public class MyWrapper{ 
IntPtr myReference; 
public ObjectWrapper() 
    { 
     try 
     { 

      this.myReference = MyFactory(); 
      if (myReference == IntPtr.Zero) 
      { 

       throw "Error or something"; 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
      throw e; 
     } 

    } 

    //Path to dll 
    [DllImport(lib_path)] 
    private static extern IntPtr MyFactory(); 

    [DllImport(lib_path)] 
    private static extern void SomeFunction(IntPtr toTrigger); 
} 

고려는 설계를 단순화 C의 세 가지 형태 중 적어도 하나의 치우는 그렇지 않으면 나는 작업을 수행 무엇을 제안하고 내가 전에 그것을 사용하고 있습니다!