簡體   English   中英

將指向 COM 接口指針的指針從托管 C++ 傳遞到 .NET C#

[英]Passing a pointer to COM interface pointer from managed c++ to .NET C#

我有一個用非托管 C++ 編寫的 COM Dll,它公開了一個 com 接口。 idl 的簡單示例如下所示:

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 接口是暴露的接口。 現在我已經在 C# 中實現了一個 .NET 庫(ObjectConsumer),它通過一個由 tlbimp 這個 COM 對象創建的互操作導入,所以我可以使用 IObjectToPass 接口。 下面是這個庫的示例代碼:

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# 模塊編譯都沒有問題

現在我已經在 C++ 中創建了一個簡單的控制台應用程序,它支持 CLR,它通過 import 和 Consumer 添加對控制台應用程序項目的引用來導入 ComTestLib。 我的目標是在我的控制台應用程序中獲取 ObjectToPass 的一個實例,並傳遞給調用公共方法 PassObject 的消費者,如下所示

#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;
 }

這段代碼不會編譯。 編譯器無法將參數 1 從“IObjectToPassPtr”轉換為“Interop::ComTest::IObjectToPass ^”。 我進行了不同的嘗試,但似乎 IObjectToPass* 無法轉換為“Interop::ComTest::IObjectToPass^”。 有沒有辦法做到這一點?

跳過 COM 接口,只需在 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. 

現在在 C# 中:

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 的三種形式中的至少一種以簡化設計,否則我建議的方法確實有效並且我以前使用過它!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM