繁体   English   中英

将本机非托管 C++ DLL 加载到托管 C# 应用程序会导致 DLL 输出垃圾

[英]Loading a native unmanaged C++ DLL into a managed C# app causes the DLL to output garbage

我有一个本地的、非托管的 C++ DLL (symulator.dll),我必须加载它并从托管的 C# 应用程序调用。

DLL 利用 C++ 类和动态内存分配(通过new运算符)。

它导出了一个名为Init的函数,其定义如下:

extern "C" __declspec( dllexport ) int Init( void )
{
    sym = new CSymulator();
    sym->Init();
    return 0;
}

DLL 中包含的CSymulator类有一个相当简单的构造函数:

CSymulator::CSymulator( void )
{
    memset( mem, 0, sizeof( mem ) );
    memset( &rmr, 0, sizeof( rmr ) );
    md = 0;
    ma = 0;
    tacts = 0;
}

DLL导出的Init()函数调用的CSymulator::Init()方法定义如下:

int CSymulator::Init( void )
{
    int *a = new int;

    *a = 1;

    FILE *f = fopen( "tmp.log", "wb" );
    fprintf( f, "%i", *a );
    fclose( f );

    delete a;
    return 0;
}

我正在使用以下代码将本机 C++ DLL 加载到托管 C# 应用程序中:

public partial class Form1 : Form
{
    public IntPtr SimHandle;

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr LoadLibrary(string libname);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    private static extern bool FreeLibrary(IntPtr hModule);

    [DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

    delegate int SimInit();

    SimInit DLL_Init;

    public void InicjujDLL()
    {
        IntPtr adres;

        adres = GetProcAddress(SimHandle, "Init");
        DLL_Init = (SimInit)Marshal.GetDelegateForFunctionPointer(adres, typeof(SimInit));

        int rc = DLL_Init();
    }

    private void WczytajDLL()
    {
        String fileName = "D:\\prg\\kompilator\\Debug DLL\\symulator.dll";

        SimHandle = LoadLibrary(fileName);
        if (SimHandle == IntPtr.Zero)
        {
            int errorCode = Marshal.GetLastWin32Error();
            throw new Exception(string.Format("Blad przy wczytywaniu biblioteki ({0})", errorCode));
        }
        else
        {
            InicjujDLL();
        }
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        WczytajDLL();
    }
}

此代码应生成一个名为tmp.log的文件,其中包含1的内容。 但是由于某种原因, tmp.log包含垃圾数据(一个随机的 32 位整数值而不是 1;例如2550276 )。

它不是产生垃圾输出的唯一函数。 任何试图动态分配内存的 DLL 函数在这样做之后都无法使用它。

就好像原生 C++ DLL 以某种方式让 C# 垃圾收集器清除了它的内存。

如何防止这种行为?

等一下:看下面的参考:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int MultiplyByTen(int numberToMultiply);

我没有注意到您的代表没有相同的属性。

作为参考,我没有看到您执行 LoadLibrary 的方式有什么异常: 动态加载本机库

我自己使用准确的参考资料完成了这项工作,没有任何问题。 我建议暂时删除在 DLL 中执行的所有代码,只做一个简单的传递值。 现在 Init() 总是返回 0。尝试其他方法,因为您之前已将内存清零,返回零可能只是 mem-zero 操作的副作用。 返回 1974 年什么的。

确保您启用了允许不安全代码并使用内存查看器查看堆栈(您正在获取一个指针,因此您有一个起点)。 如果您在 IL 旁边执行此操作,您可能会发现您的记忆被破坏的地方。

高温高压

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM