.NET Forum / .NET Framework / Interop / May 2006
Memory allocation in C# callback
|
|
Thread rating:  |
mortb - 27 Apr 2006 09:41 GMT 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 - 27 Apr 2006 11:18 GMT > 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? The code looks reasonable to me. Try setting a breakpoint in the free delegate and have a look at the call stack.
mortb - 27 Apr 2006 12:33 GMT 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
>> 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 [quoted text clipped - 3 lines] > The code looks reasonable to me. Try setting a breakpoint > in the free delegate and have a look at the call stack. Christian Fröschlin - 27 Apr 2006 13:01 GMT > 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. 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)
really correct? Maybe it should be "void * (something)".
mortb - 27 Apr 2006 13:29 GMT 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
>> According to the stack trace the call to myFree was from the initialize >> method which is defined in my C dll. [quoted text clipped - 10 lines] > > really correct? Maybe it should be "void * (something)". "Peter Huang" [MSFT] - 28 Apr 2006 09:11 GMT 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 - 02 May 2006 12:00 GMT Thank you!
The stdcall bit seems to have solved the issue!
cheers, mortb
> Hi Mortb, > [quoted text clipped - 104 lines] > This posting is provided "AS IS" with no warranties, and confers no > rights. "Peter Huang" [MSFT] - 03 May 2006 04:02 GMT 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.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|