我正在开发一个Windows 8手机应用程序,我需要将C ++代码中的回调事件消息发送到C#中的UI代码。下面是C#代码,我在其中创建回调函数并发送它指向C ++代码的指针。 C ++代码可以使用此函数指针向UI发送异步事件消息。
C#代码
public partial class MainPage
{
public MainPage()
{
InitializeComponent();
}
public delegate void CallBack([In][MarshalAs(UnmanagedType.LPStr)] string strParam);
[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void PerformActionWithCallBack(int x);
void DemonstrateCallBack()
{
int x;
CallBack callback_delegate = new CallBack(CallBackFunction);
// Converting callback_delegate into a function pointer that can be
// used in unmanaged code.
IntPtr intptr_delegate = Marshal.GetFunctionPointerForDelegate(callback_delegate);
//Getting the pointer into integer value and sending it to C++
x = (int)intptr_delegate;
testApp.PerformActionWithCallBack(x);
}
//CallBack function in which event messages will be received
void CallBackFunction([In][MarshalAs(UnmanagedType.LPStr)] string strParam)
{
if (Dispatcher.CheckAccess() == false)
{
//Updating the text block with the received message
Dispatcher.BeginInvoke(() => MyTextBlock.Text = strParam);
}
else
{
MyTextBlock.Text = "Update directly";
}
}
}
下面是C ++代码,它将事件消息发送到C#
//Callback function prototype
typedef void(__stdcall *PCallBack)(LPSTR s);
LPSTR cbMsg = NULL;
//Global instance callback function
PCallBack gUICallback;
void TestApp::PerformActionWithCallBack(int x)
{
//Assigning the received calllback function pointer from C# to global function pointer
gUICallback = (PCallBack)x;
}
//This function will send event messages to C#
void SendCallbackMsg()
{
while(1)
{
cbMsg = "Hello";
Sleep(100);
gUICallback(cbMsg);
cbMsg = "Hi";
Sleep(100);
gUICallback(cbMsg);
}
}
使用此代码,我能够在C#中成功获取事件消息,但在发送650-700 calllbacks后,我的应用程序提供了访问冲突异常,之后无效。我怀疑我将函数指针从C#传递给C ++但无法解决它的方式。
答案 0 :(得分:3)
你的问题是,callback_delegate被垃圾收集。
MSDN说
您必须手动防止垃圾收集器从托管代码收集委托。垃圾收集器不跟踪对非托管代码的引用。
试试这个
public partial class MainPage
{
private CallBack _callBackDelegate = null;
public MainPage()
{
InitializeComponent();
}
public delegate void CallBack([In][MarshalAs(UnmanagedType.LPStr)] string strParam);
[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void PerformActionWithCallBack(int x);
void DemonstrateCallBack()
{
_callBackDelegate = new CallBack(CallBackFunction);
int x;
// Converting _callBackDelegate into a function pointer that can be
// used in unmanaged code.
IntPtr intptr_delegate = Marshal.GetFunctionPointerForDelegate(_callBackDelegate );
//Getting the pointer into integer value and sending it to C++
x = (int)intptr_delegate;
testApp.PerformActionWithCallBack(x);
}
//CallBack function in which event messages will be received
void CallBackFunction([In][MarshalAs(UnmanagedType.LPStr)] string strParam)
{
if (Dispatcher.CheckAccess() == false)
{
//Updating the text block with the received message
Dispatcher.BeginInvoke(() => MyTextBlock.Text = strParam);
}
else
{
MyTextBlock.Text = "Update directly";
}
}
}