如何调用C++;当C++;调用C#函数? 我想从C++调用一个C语言库。< /P>
C#library请求一项委托职能, 以便报告结果 也许我的目的是混淆的:概念是C++调用C++函数,C函数调用C++的回调函数。如何调用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++调用回调函数阻塞了,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可以。