【问题标题】:Access violation read location 0x00000004 when sending calllback from C++ code to C# code从 C++ 代码向 C# 代码发送回调时访问冲突读取位置 0x00000004
【发布时间】:2016-06-29 12:07:02
【问题描述】:

我正在开发一个 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 个回调后,我的应用程序给出了访问冲突异常,之后没有任何效果。我怀疑我将函数指针从 C# 传递到 C++ 但无法解决它的方式。

【问题讨论】:

    标签: c# c++ visual-studio windows-ce


    【解决方案1】:

    你的问题是,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";
            }
        }
    }
    

    【讨论】:

    • 当我这样做时,我必须将 CallbackFunction 设为静态。否则通过“new CallBack(CallBackFunction);”初始化CallBackDelegate将返回错误,因为“字段初始化程序无法引用非静态字段/方法”。如果我将 CallbackFunction 设为静态,那么我将无法访问 CallbackFunction 中的 Dispatcher 对象,它会给出错误,因为“非静态字段/方法需要对象引用”。它看起来像僵局。谢谢。
    • @SanjeevKumar 对不起,我不是 C# 程序员,所以我弄错了。您只需在构造函数或void DemonstrateCallback() 方法中初始化此变量,以便它保留在类中并且不是静态的。我已经编辑了我的答案并修复了它
    • 向 V. Kravchenko 致敬,你解决了我的问题。它工作正常。非常感谢你。
    猜你喜欢
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-28
    • 2020-03-17
    • 1970-01-01
    相关资源
    最近更新 更多