Groups | Blog | Home
all groups > dotnet interop > april 2006 >

dotnet interop : Memory allocation in C# callback


mortb
4/27/2006 10:41:43 AM
Hi!

I'm writing a C# program that uses a dll-library called libmng.
The library relies heavily on callback fucntions.
To use it you have to provide callbacks for memory allocation ammongst other
things.
Using Marshal.AllocHGlobal memroy allocation seems to work ok, but I get
wierd errors that my memory free delegate gets called without actually
beeing called in the library. I've written some C# and C code to test my
callbacks:

C#:
--------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace liteTest
{
public unsafe class MyTest
{
private const string DLLPATH = @"..\..\..\testDll\Debug\testDll";

[DllImport(DLLPATH)]
private static extern IntPtr initialize(IntPtr userData,
memoryAllocDelegate memoryAllocationCallback, memoryFreeDelegate
memoryDeAllocationCallback);

private delegate IntPtr memoryAllocDelegate(int size);

private memoryAllocDelegate _memoryAllocationCallback;

private delegate void memoryFreeDelegate([In, Out] IntPtr
memoryToFree, uint size);

private memoryFreeDelegate _memoryFreeCallback;

public MyTest()
{
}

public void init()
{
_memoryAllocationCallback = new memoryAllocDelegate(myAlloc);
_memoryFreeCallback = new memoryFreeDelegate(myFree);

initialize(IntPtr.Zero, _memoryAllocationCallback,
_memoryFreeCallback);
}

private int _numberOfCallsToAlloc = 0;

private IntPtr myAlloc(int size)
{
IntPtr chunkOfMemory = Marshal.AllocHGlobal(size);
Console.WriteLine("{0} C# Alloc:{1},{2}",
++_numberOfCallsToAlloc, chunkOfMemory, size);
return chunkOfMemory;
}

private void myFree(IntPtr ptrToMemory, int size)
{
Console.WriteLine("C# Free:{0}", ptrToMemory);
Marshal.FreeHGlobal(ptrToMemory);
}
}

class console
{
static void Main(string[] args)
{
MyTest test = new MyTest();
test.init();
Console.ReadKey();
}
}
}

--------------------------------------------------------

C:
--------------------------------------------------------
#include <stdio.h>
#include <windows.h>

extern "C" __declspec(dllexport)
void * initialize
(void * userData,
void * (*memoryAllocationCallback)(int size),
void (*memoryDeAllocationCallback)(void * ptr, int size))
{
int i, j;
int sizeToAlloc = 8;
void * tmp_ptr;
printf("Hello from DLL!\n");

for(i = 0; i < 10; i++)
{
tmp_ptr = memoryAllocationCallback(sizeToAlloc );
printf("C++ pointer adress: %d\n", tmp_ptr);
}
return NULL;
}
----------------------------------------------------------
This is the output when runniig the DLL in the debugger:

Hello from DLL!
1 C# Alloc:1830872,8
C++ pointer adress: 1830872
2 C# Alloc:1830888,8
C++ pointer adress: 1830888
3 C# Alloc:1844336,8
C++ pointer adress: 1844336
4 C# Alloc:1847112,8
C++ pointer adress: 1847112
5 C# Alloc:1848584,8
C++ pointer adress: 1848584
6 C# Alloc:1848600,8
C++ pointer adress: 1848600
7 C# Alloc:1848616,8
C++ pointer adress: 1848616
8 C# Alloc:1848632,8
C++ pointer adress: 1848632
9 C# Alloc:1848648,8
C++ pointer adress: 1848648
10 C# Alloc:1848664,8
C++ pointer adress: 1848664
C# Free:2045708296

The memory allocation seems to work -- the pointers seem to be the same in
C# and C.
However, last in the output is a weird call to my memory free callback,
which I haven't put in my code with some adress that has never been
allocated. My questions are: Why is the free callback called when not
programmed to do so? This is the first time I do anything like this and I'm
not that good at C or interop, am I doing something totally wrong here?

*Any* help appreciated!
cheers,
mortb

Christian_Fröschlin
4/27/2006 12:18:46 PM
[quoted text, click to view]

The code looks reasonable to me. Try setting a breakpoint
mortb
4/27/2006 1:33:27 PM
According to the stack trace the call to myFree was from the initialize
method which is defined in my C dll.
But the callback myFree is never called, it is just passed as a parameter
into the initialize C method.

at
System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32
errorCode, IntPtr errorInfo)
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32
errorCode)
at System.Runtime.InteropServices.Marshal.FreeHGlobal(IntPtr hglobal)
at liteTest.MyTest.myFree(IntPtr ptrToMemory, Int32 size) in
C:\\Projects\\liteTest\\Program.cs:line 57
at liteTest.MyTest.initialize(IntPtr userData, memoryAllocDelegate
memoryAllocationCallback, memoryFreeDelegate memoryDeAllocationCallback)
at liteTest.MyTest.init() in C:\\Projects\\liteTest\\Program.cs:line 34
at liteTest.console.Main(String[] args) in
C:\\Projects\\liteTest\\Program.cs:line 66

cheers,ortb


[quoted text, click to view]

Christian_Fröschlin
4/27/2006 2:01:15 PM
[quoted text, click to view]

There may be some problem on the stack, so that the return statement
of "initialize" actually jumps to the free method (the address of
which has been conveniently pushed on the stack neighborhood).

I'm a bit hazy on old C's pointerisms, but is

void (*memoryDeAllocationCallback)(void * ptr, int size)

mortb
4/27/2006 2:29:26 PM
Well I am way beyond my skills in C/C++, so I corrected my method signature
according to your suggestions.
But that does not help the error, unforturnately.

/Mortb


[quoted text, click to view]

v-phuang NO[at]SPAM online.microsoft.com (
4/28/2006 12:00:00 AM
Hi Mortb,

Based on my test, I can not reproduce the problem.
Also I will get many CallingConvention error.
Here is my revised version which works OK at my side, it will not call the
dealloc callback.

["C#"]
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace TestCPPDllCallBackFunc
{
public unsafe class MyTest
{
private const string DLLPATH = @"DLLPath";

[DllImport(DLLPATH,CallingConvention=CallingConvention.StdCall)]
private static extern IntPtr initialize(IntPtr
userData,memoryAllocDelegate memoryAllocationCallback, memoryFreeDelegate
memoryDeAllocationCallback);

private delegate IntPtr memoryAllocDelegate(int size);

private memoryAllocDelegate _memoryAllocationCallback;

private delegate void memoryFreeDelegate([In, Out] IntPtr
memoryToFree, int size);

private memoryFreeDelegate _memoryFreeCallback;

public MyTest()
{
}

public void init()
{
_memoryAllocationCallback = new memoryAllocDelegate(myAlloc);
_memoryFreeCallback = new memoryFreeDelegate(myFree);

initialize(IntPtr.Zero,
_memoryAllocationCallback,_memoryFreeCallback);
}

private int _numberOfCallsToAlloc = 0;

private IntPtr myAlloc(int size)
{
IntPtr chunkOfMemory = Marshal.AllocHGlobal(size);
Console.WriteLine("{0} C#
Alloc:{1},{2}",++_numberOfCallsToAlloc, chunkOfMemory, size);
return chunkOfMemory;
}

private void myFree(IntPtr ptrToMemory, int size)
{
Console.WriteLine("C# Free:{0}", ptrToMemory);
Marshal.FreeHGlobal(ptrToMemory);
}
}

class Program
{
static void Main(string[] args)
{
MyTest test = new MyTest();
test.init();
Console.ReadKey();
}
}
}

[C++]
extern "C" __declspec(dllexport)
void * initialize
(void * userData,
void * (__stdcall * memoryAllocationCallback)(int size),
void (__stdcall * memoryDeAllocationCallback)(void * ptr, int size))
{
int i, j;
int sizeToAlloc = 8;
void * tmp_ptr;
printf("Hello from DLL!\n");

for(i = 0; i < 10; i++)
{
tmp_ptr = memoryAllocationCallback(sizeToAlloc );
printf("C++ pointer adress: %d\n", tmp_ptr);
}
return NULL;
}

You may have a try and let me know the result.


Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
mortb
5/2/2006 12:00:00 AM
Thank you!

The stdcall bit seems to have solved the issue!

cheers,
mortb

[quoted text, click to view]

v-phuang NO[at]SPAM online.microsoft.com (
5/3/2006 3:02:56 AM
Hi

You are welcomed!

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
AddThis Social Bookmark Button