如何调用C++;当C++;调用C#函数? 我想从C++调用一个C语言库。< /P>

如何调用C++;当C++;调用C#函数? 我想从C++调用一个C语言库。< /P>,c#,c++,com-interop,C#,C++,Com Interop,C#library请求一项委托职能, 以便报告结果 也许我的目的是混淆的:概念是C++调用C++函数,C函数调用C++的回调函数。 我已经被C++调用回调函数阻塞了,COM互操作对我来说晦涩难懂。 我的示例代码是: C#代码: < > C++代码: #include <windows.h> // Import the type library. #import "CSharpLibrary.tlb" raw_interfaces_only using namespace CShar

C#library请求一项委托职能, 以便报告结果

也许我的目的是混淆的:概念是C++调用C++函数,C函数调用C++的回调函数。

我已经被C++调用回调函数阻塞了,COM互操作对我来说晦涩难懂。 我的示例代码是:

C#代码:

< > C++代码:

#include <windows.h>
// Import the type library.

#import "CSharpLibrary.tlb" raw_interfaces_only
using namespace CSharpLibrary;

 typedef void (__stdcall * C_Callback)(int);

 __declspec(dllexport) int __stdcall theCallback(void)
{
    return 0;
}/*theCallback*/

 class CPPcallback :public _NativeDelegateType
 {
 public:
     CPPcallback(){};
            virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
            /* [out] */ UINT *pctinfo)
        {
            return E_NOTIMPL;
        }

        virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( 
            /* [in] */ UINT iTInfo,
            /* [in] */ LCID lcid,
            /* [out] */ ITypeInfo **ppTInfo)
        {

             if (ppTInfo == NULL)
                return E_INVALIDARG;
            *ppTInfo = NULL;

            if(iTInfo != 0)
                return DISP_E_BADINDEX;

            AddRef();      // AddRef and return pointer to cached
                               // typeinfo for this object.
            *ppTInfo = NULL;

            return NOERROR;
        }

        virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( 
        /* [in] */ REFIID riid,
        /* [size_is][in] */ LPOLESTR *rgszNames,
        /* [in] */ UINT cNames,
        /* [in] */ LCID lcid,
        /* [size_is][out] */ DISPID *rgDispId)
        {
            return E_NOTIMPL;
        }

        virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( 
        /* [in] */ DISPID dispIdMember,
        /* [in] */ REFIID riid,
        /* [in] */ LCID lcid,
        /* [in] */ WORD wFlags,
        /* [out][in] */ DISPPARAMS *pDispParams,
        /* [out] */ VARIANT *pVarResult,
        /* [out] */ EXCEPINFO *pExcepInfo,
        /* [out] */ UINT *puArgErr)
        {
            return 0;
        }

        virtual HRESULT STDMETHODCALLTYPE QueryInterface(/* [in] */ REFIID riid,
                /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
        {
            if (riid == IID_IUnknown) 
            {
                *ppvObject = static_cast<IUnknown*>(this); 
                AddRef();
                return S_OK;
            }

            if (riid == IID_IDispatch) {
                *ppvObject = static_cast<IDispatch*>(this); 
                AddRef();
                return S_OK;
            }

            //if (riid == IID_CPPcallback ) 
            {
                *ppvObject = static_cast<CPPcallback*>(this);
                AddRef();
                return S_OK;
            }

            *ppvObject = NULL;
            return E_NOINTERFACE;
        }

        virtual ULONG STDMETHODCALLTYPE AddRef( void)
        {
            return InterlockedIncrement(&_refCount);
        }

        virtual ULONG STDMETHODCALLTYPE Release( void)
        {
            return  InterlockedDecrement(&_refCount);
        }

 private:
        long _refCount;
 };

int main(int argc, char *argv[])
{
    // Initialize COM.
    HRESULT hr = CoInitialize(NULL);

    // Create the interface pointer.
    ManagedInterfacePtr CSharpDLLPtr(__uuidof(ManagedCSharpClass));

    long lResult = 0;

    // Call the Add method.
    CSharpDLLPtr->Add(5, 10, &lResult);
    long aa;
    aa = 3;
    CPPcallback cppcallback;


    CSharpDLLPtr->CalltheCallbackFun(&cppcallback, &aa);
    wprintf(L"The result is %d\n", lResult);


    // Uninitialize COM.
    CoUninitialize();
    return 0;
}
联系不到


<>我如何登记C++中的C++回调函数?< /P> < P>我不喜欢<代码> COM< /COD>方法(代码太多,注册太多),我建议您使用<代码> PInvoke < /C> >和<代码>托管CLI < /C> > 但是在您的情况下(假设您已经构建了大型
COM
基础设施),我可以建议您使用小型
PInvoke
特定的解决方法。 其想法是将<代码>指针<代码>传递给您的<代码>回调< /代码>函数,作为<代码> ItpTrt/Cube >(<代码> Value*/Cuffe+C++)。然后在C端用

COM
不会破坏
IntPtr
。我已经检查了
IntPtr
如何转换为
COM
接口。结果是,在
x64
上,它变为
LongLong
,而对于
x86
来说,它是
Long
。所以这种类型是保存指针的理想方式(顺便说一句,您可以在
回调中传递指向类的指针)。这意味着
AnyCPU
配置将毫无用处

下面是代码示例C#重写部分:

using System;
using System.Runtime.InteropServices;

namespace CSharpLibraryNameSpace
{    
    // Any delegate decorated as for PInoke
    public delegate int NativeDelegateType([MarshalAs(UnmanagedType.LPWStr)] string strMsg);

    // Interface declaration.
    [ComVisible(true)]
    public interface ManagedInterface
    {
        int Add(int Number1, int Number2);

        int CalltheCallbackFun(IntPtr callbackFnPtr);
    };


    // Interface implementation.
    [ComVisible(true)]
    public class ManagedCSharpClass : ManagedInterface
    {
        public int Add(int Number1, int Number2)
        {
            Console.Write("Inside MANAGED Add Num1={0} Num2={1}\n", Number1, Number2);
            return Number1 + Number2;
        }

        public int CalltheCallbackFun(IntPtr callbackFnPtr)
        {
            Console.Write("Inside MANAGED CalltheCallbackFun Before Call ptr={0}\n", callbackFnPtr);

            //Convert IntPtr to Delegate
            NativeDelegateType callback =
                Marshal.GetDelegateForFunctionPointer(callbackFnPtr,
                    typeof(NativeDelegateType)) as NativeDelegateType;

            int nRet = callback("Message from C# :)");

            Console.Write("Inside MANAGED CalltheCallbackFun After Call Result={0}\n", nRet);

            return nRet;
        }
    }
}
C++
客户端部分:

#import "CSharpLibrary.tlb" raw_interfaces_only
using namespace CSharpLibrary;

int SimpleCallbackFunction(const wchar_t* pszMsg)
{
    wprintf(L"Inside C++ UNMANAGED Callback Param=\"%s\"\n", pszMsg);
    return 77;
}

int main()
{
    wprintf(L"Inside C++ UNMANAGED Start\n");

    // Initialize COM.
    HRESULT hr = CoInitialize(NULL);

    // Create the interface pointer.
    ManagedInterfacePtr CSharpDLLPtr(__uuidof(ManagedCSharpClass));

    long lResult = 0;

    // Call the Add method.
    CSharpDLLPtr->Add(5, 10, &lResult); //lResult == 15

    //! For x64 you need to convert to LongLong
    CSharpDLLPtr->CalltheCallbackFun((long)SimpleCallbackFunction, &lResult);
    wprintf(L"Inside C++ UNMANAGED Main result is %d\n", lResult);

    // Uninitialize COM.
    CoUninitialize();
    return 0;
}
输出为:

Inside C++ UNMANAGED Start
Inside MANAGED Add Num1=5 Num2=10
Inside MANAGED CalltheCallbackFun Before Call ptr=2625906
Inside C++ UNMANAGED Callback Param="Message from C# :)"
Inside MANAGED CalltheCallbackFun After Call Result=77
Inside C++ UNMANAGED Main result is 77
Inside C++ UNMANAGED Start
Inside MANAGED Add Num1=5 Num2=10
Inside MANAGED CalltheCallbackFun Before Call
Inside C++ UNMANAGED Callback Param="Message from C# :)"
Inside MANAGED CalltheCallbackFun After Call Result=77
Inside C++ UNMANAGED Main result is 77

我不喜欢
COM
方法(代码和注册太多),我建议您改用
PInvoke
Managed CLI

但是在您的情况下(假设您已经构建了大型
COM
基础设施),我可以建议您使用小型
PInvoke
特定的解决方法。 其想法是将<代码>指针<代码>传递给您的<代码>回调< /代码>函数,作为<代码> ItpTrt/Cube >(<代码> Value*/Cuffe+C++)。然后在C端用

COM
不会破坏
IntPtr
。我已经检查了
IntPtr
如何转换为
COM
接口。结果是,在
x64
上,它变为
LongLong
,而对于
x86
来说,它是
Long
。所以这种类型是保存指针的理想方式(顺便说一句,您可以在
回调中传递指向类的指针)。这意味着
AnyCPU
配置将毫无用处

下面是代码示例C#重写部分:

using System;
using System.Runtime.InteropServices;

namespace CSharpLibraryNameSpace
{    
    // Any delegate decorated as for PInoke
    public delegate int NativeDelegateType([MarshalAs(UnmanagedType.LPWStr)] string strMsg);

    // Interface declaration.
    [ComVisible(true)]
    public interface ManagedInterface
    {
        int Add(int Number1, int Number2);

        int CalltheCallbackFun(IntPtr callbackFnPtr);
    };


    // Interface implementation.
    [ComVisible(true)]
    public class ManagedCSharpClass : ManagedInterface
    {
        public int Add(int Number1, int Number2)
        {
            Console.Write("Inside MANAGED Add Num1={0} Num2={1}\n", Number1, Number2);
            return Number1 + Number2;
        }

        public int CalltheCallbackFun(IntPtr callbackFnPtr)
        {
            Console.Write("Inside MANAGED CalltheCallbackFun Before Call ptr={0}\n", callbackFnPtr);

            //Convert IntPtr to Delegate
            NativeDelegateType callback =
                Marshal.GetDelegateForFunctionPointer(callbackFnPtr,
                    typeof(NativeDelegateType)) as NativeDelegateType;

            int nRet = callback("Message from C# :)");

            Console.Write("Inside MANAGED CalltheCallbackFun After Call Result={0}\n", nRet);

            return nRet;
        }
    }
}
C++
客户端部分:

#import "CSharpLibrary.tlb" raw_interfaces_only
using namespace CSharpLibrary;

int SimpleCallbackFunction(const wchar_t* pszMsg)
{
    wprintf(L"Inside C++ UNMANAGED Callback Param=\"%s\"\n", pszMsg);
    return 77;
}

int main()
{
    wprintf(L"Inside C++ UNMANAGED Start\n");

    // Initialize COM.
    HRESULT hr = CoInitialize(NULL);

    // Create the interface pointer.
    ManagedInterfacePtr CSharpDLLPtr(__uuidof(ManagedCSharpClass));

    long lResult = 0;

    // Call the Add method.
    CSharpDLLPtr->Add(5, 10, &lResult); //lResult == 15

    //! For x64 you need to convert to LongLong
    CSharpDLLPtr->CalltheCallbackFun((long)SimpleCallbackFunction, &lResult);
    wprintf(L"Inside C++ UNMANAGED Main result is %d\n", lResult);

    // Uninitialize COM.
    CoUninitialize();
    return 0;
}
输出为:

Inside C++ UNMANAGED Start
Inside MANAGED Add Num1=5 Num2=10
Inside MANAGED CalltheCallbackFun Before Call ptr=2625906
Inside C++ UNMANAGED Callback Param="Message from C# :)"
Inside MANAGED CalltheCallbackFun After Call Result=77
Inside C++ UNMANAGED Main result is 77
Inside C++ UNMANAGED Start
Inside MANAGED Add Num1=5 Num2=10
Inside MANAGED CalltheCallbackFun Before Call
Inside C++ UNMANAGED Callback Param="Message from C# :)"
Inside MANAGED CalltheCallbackFun After Call Result=77
Inside C++ UNMANAGED Main result is 77

尽管我仍然建议使用
PInvoke
Managed CLI
或至少使用我以前的
answer
方法,但我想添加
COM
方法答案

代理使用
COM包装器
不是一个好主意。下面的代码将
回调
声明为来自
C
接口
,并获取实现此
接口
的对象

using System;
using System.Runtime.InteropServices;

namespace CSharpLibraryNameSpace
{   
    //Callback Interface declaration
    [ComVisible(true)]
    public interface CallbackInterface1
    {
        int InvokeUnmanaged(string strMsg);
    }

    [ComVisible(true)]
    public interface ManagedInterface
    {
        int Add(int Number1, int Number2);
        int CalltheCallbackFun(CallbackInterface1 callback);
    };


    // Interface implementation.
    [ComVisible(true)]
    public class ManagedCSharpClass : ManagedInterface
    {
        public int Add(int Number1, int Number2)
        {
            Console.Write("Inside MANAGED Add Num1={0} Num2={1}\n", Number1, Number2);
            return Number1 + Number2;
        }

        public int CalltheCallbackFun(CallbackInterface1 callback)
        {
            Console.Write("Inside MANAGED CalltheCallbackFun Before Call\n");

            int nRet = callback.InvokeUnmanaged("Message from C# :)");

            Console.Write("Inside MANAGED CalltheCallbackFun After Call Result={0}\n", nRet);

            return nRet;
        }
    }
}
为了从
C++
使用此
回调
,您需要创建特殊对象。以下是整个程序代码:

#import "CSharpLibrary.tlb" raw_interfaces_only
using namespace CSharpLibrary;

class CPPcallback :public CallbackInterface1
{
public:
    CPPcallback(){};
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
        /* [out] */ UINT *pctinfo)
    {
        *pctinfo = 1;
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( 
        /* [in] */ UINT iTInfo,
        /* [in] */ LCID lcid,
        /* [out] */ ITypeInfo **ppTInfo)
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( 
        /* [in] */ REFIID riid,
        /* [size_is][in] */ LPOLESTR *rgszNames,
        /* [in] */ UINT cNames,
        /* [in] */ LCID lcid,
        /* [size_is][out] */ DISPID *rgDispId)
    {
        return E_NOTIMPL;
    }

    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( 
        /* [in] */ DISPID dispIdMember,
        /* [in] */ REFIID riid,
        /* [in] */ LCID lcid,
        /* [in] */ WORD wFlags,
        /* [out][in] */ DISPPARAMS *pDispParams,
        /* [out] */ VARIANT *pVarResult,
        /* [out] */ EXCEPINFO *pExcepInfo,
        /* [out] */ UINT *puArgErr)
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE QueryInterface(/* [in] */ REFIID riid,
        /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
    {
        if (riid == IID_IUnknown) 
        {
            *ppvObject = static_cast<IUnknown*>(this); 
            AddRef();
            return S_OK;
        }

        if (riid == IID_IDispatch) {
            *ppvObject = static_cast<IDispatch*>(this); 
            AddRef();
            return S_OK;
        }

        if (riid == __uuidof(CallbackInterface1)) 
        {
            *ppvObject = static_cast<CallbackInterface1*>(this);
            AddRef();
            return S_OK;
        }

        *ppvObject = NULL;
        return E_NOINTERFACE;
    }

    virtual ULONG STDMETHODCALLTYPE AddRef( void)
    {
        return InterlockedIncrement(&_refCount);
    }

    virtual ULONG STDMETHODCALLTYPE Release( void)
    {
        return  InterlockedDecrement(&_refCount);
    }

    virtual HRESULT __stdcall InvokeUnmanaged (
        /*[in]*/ BSTR strMsg,
        /*[out,retval]*/ long * pRetVal ) override
    {
        wprintf(L"Inside C++ UNMANAGED Callback Param=\"%s\"\n", strMsg);
        *pRetVal = 77;
        return S_OK;
    }

private:
    long _refCount;
};

int main()
{
    wprintf(L"Inside C++ UNMANAGED Start\n");

    // Initialize COM.
    HRESULT hr = CoInitialize(NULL);

    // Create the interface pointer.
    ManagedInterfacePtr CSharpDLLPtr(__uuidof(ManagedCSharpClass));

    long nRes = 0;

    // Call the Add method.
    CSharpDLLPtr->Add(5, 10, &nRes);

    //Callback holder instance
    CPPcallback cppcallback;

    //Call COM Managed method which calls our Callback
    CSharpDLLPtr->CalltheCallbackFun(&cppcallback, &nRes);
    wprintf(L"Inside C++ UNMANAGED Main result is %d\n", nRes);

    // Uninitialize COM.
    CoUninitialize();
    return 0;
}

如果您将
IDispatch
实现隐藏在场景后面,代码将几乎与前面答案中的代码一样短,但您将面临所有
COM
特定对象(如
BSTR
SAFEARRAY
)虽然我仍然建议使用
PInvoke
managedcli
或者至少从我以前的
answer
中添加
COM
approach-answer,但它确实比
PInvoke

工作得慢

代理使用
COM包装器
不是一个好主意。下面的代码将
回调
声明为来自
C
接口
,并获取实现此
接口
的对象

using System;
using System.Runtime.InteropServices;

namespace CSharpLibraryNameSpace
{   
    //Callback Interface declaration
    [ComVisible(true)]
    public interface CallbackInterface1
    {
        int InvokeUnmanaged(string strMsg);
    }

    [ComVisible(true)]
    public interface ManagedInterface
    {
        int Add(int Number1, int Number2);
        int CalltheCallbackFun(CallbackInterface1 callback);
    };


    // Interface implementation.
    [ComVisible(true)]
    public class ManagedCSharpClass : ManagedInterface
    {
        public int Add(int Number1, int Number2)
        {
            Console.Write("Inside MANAGED Add Num1={0} Num2={1}\n", Number1, Number2);
            return Number1 + Number2;
        }

        public int CalltheCallbackFun(CallbackInterface1 callback)
        {
            Console.Write("Inside MANAGED CalltheCallbackFun Before Call\n");

            int nRet = callback.InvokeUnmanaged("Message from C# :)");

            Console.Write("Inside MANAGED CalltheCallbackFun After Call Result={0}\n", nRet);

            return nRet;
        }
    }
}
为了从
C++
使用此
回调
,您需要创建特殊对象。以下是整个程序代码:

#import "CSharpLibrary.tlb" raw_interfaces_only
using namespace CSharpLibrary;

class CPPcallback :public CallbackInterface1
{
public:
    CPPcallback(){};
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
        /* [out] */ UINT *pctinfo)
    {
        *pctinfo = 1;
        return S_OK;
    }

    virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( 
        /* [in] */ UINT iTInfo,
        /* [in] */ LCID lcid,
        /* [out] */ ITypeInfo **ppTInfo)
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( 
        /* [in] */ REFIID riid,
        /* [size_is][in] */ LPOLESTR *rgszNames,
        /* [in] */ UINT cNames,
        /* [in] */ LCID lcid,
        /* [size_is][out] */ DISPID *rgDispId)
    {
        return E_NOTIMPL;
    }

    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( 
        /* [in] */ DISPID dispIdMember,
        /* [in] */ REFIID riid,
        /* [in] */ LCID lcid,
        /* [in] */ WORD wFlags,
        /* [out][in] */ DISPPARAMS *pDispParams,
        /* [out] */ VARIANT *pVarResult,
        /* [out] */ EXCEPINFO *pExcepInfo,
        /* [out] */ UINT *puArgErr)
    {
        return E_NOTIMPL;
    }

    virtual HRESULT STDMETHODCALLTYPE QueryInterface(/* [in] */ REFIID riid,
        /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
    {
        if (riid == IID_IUnknown) 
        {
            *ppvObject = static_cast<IUnknown*>(this); 
            AddRef();
            return S_OK;
        }

        if (riid == IID_IDispatch) {
            *ppvObject = static_cast<IDispatch*>(this); 
            AddRef();
            return S_OK;
        }

        if (riid == __uuidof(CallbackInterface1)) 
        {
            *ppvObject = static_cast<CallbackInterface1*>(this);
            AddRef();
            return S_OK;
        }

        *ppvObject = NULL;
        return E_NOINTERFACE;
    }

    virtual ULONG STDMETHODCALLTYPE AddRef( void)
    {
        return InterlockedIncrement(&_refCount);
    }

    virtual ULONG STDMETHODCALLTYPE Release( void)
    {
        return  InterlockedDecrement(&_refCount);
    }

    virtual HRESULT __stdcall InvokeUnmanaged (
        /*[in]*/ BSTR strMsg,
        /*[out,retval]*/ long * pRetVal ) override
    {
        wprintf(L"Inside C++ UNMANAGED Callback Param=\"%s\"\n", strMsg);
        *pRetVal = 77;
        return S_OK;
    }

private:
    long _refCount;
};

int main()
{
    wprintf(L"Inside C++ UNMANAGED Start\n");

    // Initialize COM.
    HRESULT hr = CoInitialize(NULL);

    // Create the interface pointer.
    ManagedInterfacePtr CSharpDLLPtr(__uuidof(ManagedCSharpClass));

    long nRes = 0;

    // Call the Add method.
    CSharpDLLPtr->Add(5, 10, &nRes);

    //Callback holder instance
    CPPcallback cppcallback;

    //Call COM Managed method which calls our Callback
    CSharpDLLPtr->CalltheCallbackFun(&cppcallback, &nRes);
    wprintf(L"Inside C++ UNMANAGED Main result is %d\n", nRes);

    // Uninitialize COM.
    CoUninitialize();
    return 0;
}

如果您将
IDispatch
实现隐藏在幕后,代码将几乎与前面答案中的代码一样短,但您将面对所有
COM
特定对象(如
BSTR
SAFEARRAY
),它的工作速度肯定比
PInvoke
慢,谢谢,但我应该在这里作出评论:将type:var替换为NativeDelegateType更好compatibility@GaigerChen我不明白如何替换
var
type?关于主题,我想补充一点,使用
PInvoke
有很多优点:您不必编写包装器,您可以传递
C++数组
LPCTSTR
Structs
,而无需显式转换,速度更快等等。在我的环境:VS2005中,编译器无法传递var的使用,但是NativeDeleteGateType可以。谢谢,但我应该在这里发表评论:将type:var替换为NativeDeleteGateType更好compatibility@GaigerChen我不明白如何替换
var
type?关于主题,我想补充一点,使用
PInvoke
有很多优点:您不必编写包装器,您可以传递
C++数组
LPCTSTR
Structs
,而无需显式转换,速度更快等等。在我的环境:VS2005中,编译器无法传递var的使用,但是NativeDelegateType可以。