从 C++ 代码向 C# 代码发送回调时访问冲突读取位置 0x00000004

Access violation read location 0x00000004 when sending calllback from C++ code to C# code

我正在开发一个 windows 8 phone 应用程序,我需要在其中将回调事件消息从 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";
            }
        }
}

Below is the C++ code which will send event messages to 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 个回调后,我的应用程序给出了访问冲突异常,此后没有任何效果。我怀疑我将函数指针从 C# 传递到 C++ 但无法解析它的方式。

你的问题是,callback_delegate 被垃圾回收了。

MSDN

You must manually keep the delegate from being collected by the garbage collector from managed code. The garbage collector does not track reference to unmanaged code.

试试这个

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