Search code examples
c#c++dllnativeunmanaged

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


I have a native, unmanaged C++ DLL (symulator.dll) which I have to load in and call from a managed C# application.

The DLL utilizes C++ classes and dynamic memory allocation (via the new operator).

It exports a function called Init and its definition is as follows:

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

The CSymulator class contained within the DLL has a rather simple constructor:

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

The CSymulator::Init() method, called by the Init() function exported by the DLL, is defined as follows:

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

I am loading the native C++ DLL into the managed C# application using this code:

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();
    }
}

This code should produce a file named tmp.log with the content of 1 in it. But for some reason, tmp.log contains garbage data (a random 32-bit integer value instead of 1; for example, 2550276).

It's not the only function that produces garbage output. Any DLL function that tries to allocate memory dynamically is unable to use it after doing so.

It's as if the native C++ DLL is somehow getting its memory purged by the C# garbage collector.

How to prevent this behavior?


Solution

  • Wait a sec: Look at the reference below:

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

    I didn't notice that your delegate doesn't have the same attribute.

    For reference, I don't see anything unusual in how you are doing the LoadLibrary: Dynamically Loading a Native Library

    I have done this myself using the exact reference without a problem. I would suggest removing ALL code temporarily that executes inside the DLL and just do a simple pass-through value. Right now Init() is always returning 0. Try something else since you have zeroed out memory before, getting a zero back may just be a side-effect of the mem-zero op. Return 1974 or something.

    Ensure you have allow unsafe code enabled and use the memory viewer to look at the stack (you are getting a pointer back so you have a starting point). If you do this beside the IL, you might spot where your memory is getting trashed.

    HTH