的NullReferenceException℃持续++回调到C#功能 [英] NullReferenceException during C++ callback to C# function

查看:291
本文介绍了的NullReferenceException℃持续++回调到C#功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

开发商!结果
我有很奇怪的问题。我的项目在C DLL writen ++和C#writen的GUI。我已经实现的回调一些互操作性。我刨了C ++ DLL将调用C#代码在某些情况下。它的工作原理......但没多久,我无法理解这是为什么。



C ++ DLL:


$标志着在C#中的部分结果
这里简化样品的完整代码注释的问题b $ b

 的#include< SDKDDKVer.h> 
#定义WIN32_LEAN_AND_MEAN
&#包括LT; WINDOWS.H>

BOOL APIENTRY的DllMain(HMODULE HMODULE,
DWORD ul_reason_for_call,
LPVOID lpReserved

{
开关(ul_reason_for_call)
{
情况下DLL_PROCESS_ATTACH:
情况下DLL_THREAD_ATTACH:
情况下DLL_THREAD_DETACH:
情况下DLL_PROCESS_DETACH:
中断;
}
返回TRUE;
}

的externC
{
无效的typedef(* WriteSymbolCallback)(CHAR符号);
WriteSymbolCallback测试;

_declspec(dllexport)的无效InitializeLib()
{
测试= NULL;
}

_declspec(dllexport)的无效SetDelegate(WriteSymbolCallback回调)
{
测试=回拨;
}

_declspec(dllexport)的无效TESTCALL(为const char *文本,诠释长度)
{
如果(测试!= NULL)
{
。对于(INT I = 0; I<长度;我+ +)
{
测试(文[I]);
}
}
}
};



C#部分:

 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;使用System.Runtime.InteropServices
;

命名空间CallBackClient
{
类节目
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
私人委托无效WriteToConsoleCallback(字符符号) ;

函数[DllImport(CallbackSketch.dll,字符集= CharSet.Ansi,CallingConvention = CallingConvention.Cdecl)]
私人静态外部无效InitializeLib();

函数[DllImport(CallbackSketch.dll,字符集= CharSet.Ansi,CallingConvention = CallingConvention.Cdecl)]
私人静态外部无效SetDelegate(WriteToConsoleCallback回调);

函数[DllImport(CallbackSketch.dll,字符集= CharSet.Ansi,CallingConvention = CallingConvention.Cdecl)]
私人静态外部无效TESTCALL(字符串文本,INT长度);

私有静态无效PrintSymbol(字符符号)
{
Console.Write(Symbol.ToString());
}

静态无效的主要(字串[] args)
{
InitializeLib();
SetDelegate(新WriteToConsoleCallback(PrintSymbol));

字符串测试=世界,你好!


的for(int i = 0; I< 15000;我++)
{
TESTCALL(测试,test.Length); //它崩溃时,我== 6860 !!!!调试器告诉我关于System.NullReferenceException
}
}
}
}

的问题是,它崩溃在第六千八百六十零迭代!我认为这个问题是我没有在这个问题knowlege的。 ?sombody能不能帮我。


解决方案

  SetDelegate(新WriteToConsoleCallback(PrintSymbol)); 



是的,这不能正常工作。本机代码存储的函数指针,委托对象,但垃圾收集器无法看到此引用。至于它而言,还有的没有的对象引用。而接下来的收集毁坏它。 KABOOM。



您必须存储到自己的对象的引用。添加一个字段中的类来存储它:

 私有静态WriteToConsoleCallback回调; 

静态无效的主要(字串[] args)
{
InitializeLib();
回调=新WriteToConsoleCallback(PrintSymbol);
SetDelegate(回调);
//等等......
}



该规则是类存储至少长对象必须有一个终生为本地代码的机会,使回调。它必须是静态的在这种特殊情况下,这是坚实的。


developers!
I have very strange problem. My project has DLL writen in C++ and a GUI writen in C#. And I have implemented callback for some interoperability. I planed that C++ dll will call C# code in some circumstances. It works... but not long and I cant understand why. The problem marked in comment in C# part
Here the complete code of simplified sample:

C++ DLL:

#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

BOOL APIENTRY DllMain( HMODULE hModule,
                    DWORD  ul_reason_for_call,
                    LPVOID lpReserved
                                    )
    {
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

extern "C" 
{    
    typedef void  (*WriteSymbolCallback) (char Symbol); 
    WriteSymbolCallback Test;

    _declspec(dllexport) void InitializeLib()
    {
        Test = NULL;
    }

    _declspec(dllexport) void SetDelegate(WriteSymbolCallback Callback)
    {
        Test = Callback;
    }

    _declspec(dllexport) void TestCall(const char* Text,int Length)
    {
        if(Test != NULL)
        {
            for(int i=0;i<Length;i++)
            {
                Test(Text[i]);
            }
        }
    }
};

C# part:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace CallBackClient
{
    class Program
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        private delegate void WriteToConsoleCallback(char Symbol);

        [DllImport("CallbackSketch.dll",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
        private static extern void InitializeLib();

        [DllImport("CallbackSketch.dll",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
        private static extern void SetDelegate(WriteToConsoleCallback Callback);

        [DllImport("CallbackSketch.dll",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
        private static extern void TestCall(string Text,int Length);

        private static void PrintSymbol(char Symbol)
        {
            Console.Write(Symbol.ToString());
        }

        static void Main(string[] args)
        {
            InitializeLib();
            SetDelegate(new WriteToConsoleCallback(PrintSymbol));

            string test = "Hello world!";


            for (int i = 0; i < 15000; i++)
            {
                TestCall(test, test.Length);// It crashes when i == 6860!!!! Debugger told me about System.NullReferenceException
            }            
        }
    }
}

The problem is that it crashes in 6860th iteration! I believe that the problem is lack of my knowlege in the subject. Could sombody help me?

解决方案

       SetDelegate(new WriteToConsoleCallback(PrintSymbol));

Yes, this cannot work properly. The native code is storing a function pointer for the delegate object but the garbage collector cannot see this reference. As far as it is concerned, there are no references to the object. And the next collection destroys it. Kaboom.

You have to store a reference to the object yourself. Add a field in the class to store it:

    private static WriteToConsoleCallback callback;

    static void Main(string[] args)
    {
        InitializeLib();
        callback = new WriteToConsoleCallback(PrintSymbol);
        SetDelegate(callback);
        // etc...
    }

The rule is that the class that stores the object must have a lifetime at least as long as native code's opportunity to make the callback. It must be static in this particular case, that's solid.

这篇关于的NullReferenceException℃持续++回调到C#功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆