C# Free IntPtr from C malloc - c#

I have an unmanaged DLL on C with func:
char* My_Func(char* data, int input_length, int output_length);
In this func i have
result = (char*)malloc(output_lenght);
strcpy(result,test_char);
return(result);
In C# i import it
[DllImport(#"libsmev.DLL", CharSet = CharSet.Ansi)]
public static extern IntPtr My_Func([MarshalAs(UnmanagedType.LPStr)]string data, int input_length, out int output_length);
And call it
IntPtr result = My_Func (n1, n1.Lenght,n2);
How to free char* or IntPtr?
Marshal.FreeHGlobal(IntPtr) and Marshal.FreeCoTaskMem(IntPtr) doesn`t work.

You need to export a function that can free the pointer using free. As you have noticed Marshal.FreeHGlobal and Marshal.FreeCoTaskMem doesn't work because these functions expect pointer that have allocated using a different allocation function.
If you create an API that allocates memory and returns a pointer to this memory you have to also add a function in the API to free the memory. Otherwise your API will not be available outside the library that was used to allocate the memory (in this case the C standard library).

In C, something like this:
void Free_Obj(char* obj) {
free(obj);
}
In C#, something like this:
[DllImport("libsmev.DLL")]
public static extern void Free_Obj(IntPtr obj);
And call it:
IntPtr result = My_Func (n1, n1.Lenght,n2);
Free_Obj(result);

Instread of creating a custom free function in your DLL, you could also use CoTaskMemAlloc instead of malloc to allocate the memory.
You can then use Marshal.FreeCoTaskMem to free it.

Related

How to get IntPtr of c# unsafe struct to free its memory initialized in c++ dll

Please, advise me on how to free memory from the created unsafe C# struct(s) using some standard C# toolset or how get I get the IntPtr of those objects to use the default provided custom C++ library?
The problem details (UPD):
I create the C# unsafe struct and pass it to C++ dll that I can't change TH_ExtractBimTemplate(ref createdStruct). The dll updates its content. And in addition to that, the dll saves the reference to the struct object inside of it in an internal list. Here is the struct definition:
public unsafe struct BIM_Template
{
public ushort ImageSizeX;
public ushort ImageSizeY;
public fixed uint Mint[MAX_MINUTIAE_SIZE];
public uint Reserve;
}
After the API call returns, I use the data in the struct populated by the C++ dll in my C# code.
I need to free the memory used by the struct and C++. The dll has an API to do this, TH_FreeMemory.
For step #3 I need to pass the object reference (I presume IntPtr) to C++ library or I need to Free the memory it was occupying with some C# instrument.
The Garbage Collection doesn't work even if there are no reference in my C# code to the object, I assume, because of the struct object reference is stored in the list in the dll that I don't control. When TH_FreeMemory on the struct object is called, it removes it from the list and release the memory with delete, but I can't generate the C# IntPtr to pass it to the TH_FreeMemory for that...
How can I do that - release the memory with just C# tools, ignoring the list dll or generate the IntPtr for this struct?
The implementation details:
This is how I create and initialize it:
BIM_Template template = default;
var template = TH_ExtractBimTemplate(ref template)
Where TH_ExtractBimTemplate(...) is the method that is pulled from the C++ dll in this way:
[DllImport("TemplateHelper.dll")]
private static extern int TH_ExtractBimTemplate(
ref BIM_Template out_template);
The TemplateHelper.dll provides me a C++ method to release the memory - TH_FreeMemory:
int WINAPI TH_FreeMemory( void *memblock, BIM_MemBlockType memblock_type )
This is how I plug it into C#
[DllImport("TemplateHelper.dll")]
private static extern int TH_FreeMemory(
IntPtr memblock, BIM_MemBlockType memblock_type
);
Current solutions I tried:
I need IntPtr of the created unsafe struct (the template variable) but I don't know how to get it, to free allocated memory with TH_FreeMemory dll method
I have tried to create a bunch of these unsafe struct type templates in the method that create them and return void, leaving no references to the created templates, but the garbage collector doesn't free memory. I assume that is, because of the object type is unsafe struct. At least, I've waited for 40 minutes and memory wasn't released.
I have tried the approach below to release the memory with Marshal.FreeHGlobal(IntPtr ptr) but that doesn't reduce the amount of unmanaged memory used by the app as well here is the code:
[Fact]
public void TestDisposalIsCalledOnOutOfContext()
{
// Create templates
var templates = LoadTemplates(m, Output);
// Release the allocated memory using Marshal
templates.ForEach( t => MarshaFreeMemory(ref t));
// Wait
Thread.Sleep(new TimeSpan(hours: 1, 0, 0));
}
private static IntPtr MarshaFreeMemory(ref BIM_Template? template)
{
IntPtr ptr;
ptr = Marshal.AllocHGlobal(Marshal.SizeOf<BIM_Template>());
Marshal.StructureToPtr(template, ptr, true);
Marshal.FreeHGlobal(ptr);
return ptr;
}
private static List<BIM_Template?> LoadTemplates()
{
var templates = new List<BIM_Template?>();
for (int j = 0; j < 1000; j++) templates.Add(LoadTemplate());
return templates;
}
public static BIM_Template LoadTemplate()
{
BIM_Template template = default;
var template = TH_ExtractBimTemplate(ref template);
return template;
}
So, the question is how can I prevent these memory leaks and free memory from the created templates using some standard C# toolset or how get I get the IntPtr of the template object to use the library?
You don’t need to call TH_FreeMemory. Your structure doesn’t have any pointers inside. In C++, the Mint field should be std::array<uint32_t, MAX_MINUTIAE_SIZE> or an equivalent.
Your template local variable is on the stack, it does not use any heap memory, and the stack memory will be freed automatically just before the LoadTemplate() method returns.
if you wanna free the memory used by the list in TestDisposalIsCalledOnOutOfContext, do this:
templates = null;
// Collect all generations of memory
GC.Collect();

Is it necessary to free the memory of strings in C++ received from C#?

I have the following exposed DLL functions in C++.
// center_of_rotation_api.h
// CENTER_OF_ROTATION_API is a macro like __cdecl(dllexport) on Windows
CENTER_OF_ROTATION_API void SerializeMesh(Mesh * mesh, const char * path);
CENTER_OF_ROTATION_API const char * SerializationError(Mesh * mesh);
From C#, I use the following.
// dll is the name of the compiled dll
[DllImport(dll)]
public static extern void SerializeMesh(IntPtr mesh, string path);
[DllImport(dll)]
public static extern IntPtr SerializationError(IntPtr mesh);
The IntPtr returned by SerializationError is allocated using new in C++. So I have another DLL exported function that frees the pointer when called by C#.
My question is, do I need to free the memory of the const char * path in the argument of SerializeMesh in C++?
No, the C# marshaler will take care of this for you. The char* will be valid during the lifetime of the PInvoke call. If your C++ code expects to own the char*, you should make a copy in SerializeMesh.
Here is a primer on string marshaling. If you really need to use a const char*, you might need to set the MarshalAsAttribute to UnmanagedType.LPStr. See here for more information on string marshaling behavior.
Here is another useful reference if you want to dig even deeper.

Marshalling arrays of VARIANT using P/Invoke

Situation:
I have a managed (C#, .NET 2.0) application which uses an unmanaged (C++) DLL using P/Invoke. Along with the "simple" methods (POD arguments/return value) there's a requirement to pass a boost::variant value arrays to the code. The reason for it is that these methods pass report data (similar to Excel cells, which can be of any type). C# code accepts them as boxed "object"'s.
The previous implementation called for use of SafeArray of COM VARIANT's. However, due to poor coding/not testing it, the marshalling turned out to be leaking memory. Now I have to find another option for marshalling the data.
Previous implementation looked like this:
C++:
extern "C" __declspec(dllexport) void GetReport(VARIANT& output) {
// ... here a SafeArray of VARIANT values was created
output.vt = VT_VARIANT | VT_ARRAY;
output.parray = safeArray;
}
C#
[DllImport("CppLibrary.dll")]
private static extern void GetReport(out object output);
//....
object data;
GetReport(data);
object rows = data as object[];
This specific implementation leaks memory by not freeing up the interop structures.
I've tried to change the prototypes by including SafeArray marshalling directives:
C++
extern "C" __declspec(dllexport) void GetReport(SAFEARRAY output) { // Also tried SAFEARRAY*, SAFEARRAY&, VARIANT, VARIANT&, VARIANT*
// Internal stuff
}
C#
private static extern void GetReport([Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]ref object[] output);
However, the only things I've achieved were either an empty resulting object(s), or crash due to memory corruption/stack overflow.
Problem:
How to correctly marshal such data type (array of VARIANT-typed structures) to C#?
I can make the C++ DLL a COM one, but this will require rewriting quite a handful of code. Is there any simpler way out of the situation? Maybe I'm missing something.
There is this example: http://limbioliong.wordpress.com/2011/03/20/c-interop-how-to-return-a-variant-from-an-unmanaged-function/
In the end they use directly an IntPtr (they use it as a return value, you would have to use it as a out IntPtr), then Marshal.GetObjectForNativeVariant(), VariantClear() and Marshal.FreeCoTaskMem() from the C# side, while on the C/C++ side the VARIANT was allocated with CoTaskMemAlloc().
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.StdCall)]
static extern void MyFunction(out IntPtr ptr);
[DllImport("oleaut32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern Int32 VariantClear(IntPtr pvarg);
IntPtr pVariant;
MyFunction(out pVariant);
object objRet = Marshal.GetObjectForNativeVariant(pVariant);
VariantClear(pVariant);
Marshal.FreeCoTaskMem(pVariant);
pVariant = IntPtr.Zero;
Clearly you could expose another C function in your dll that frees the VARIANT (it's always correct to expose Free methods in your library, so that caller can use them and not ask himself "how should I free this memory?")

Receiving char* from C++ method, converting to managed string, then deallocating memory

I have a third party unmanaged C++ dll that I need to call from C#. The C++ function returns a char*. I've figured out how to convert that to a managed string in C#. But I don't know if I need to deallocate the memory. The following code works except that Marshal.FreeHGlobal(p) throws "The handle is invalid.". So do I need to deallocate the memory, and if so, how?
[DllImport("abc.dll", EntryPoint = "?GetVersion#ABC##QEAAPEADXZ", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern unsafe char* GetVersionRaw();
public static unsafe string GetVersion()
{
char* x = Abc.GetVersionRaw(); // call the function in the unmanaged DLL
IntPtr p = new IntPtr(x);
string s = Marshal.PtrToStringAnsi(p);
Marshal.FreeHGlobal(p);
return s;
}
It is impossible to say in general how to free an arbitrary pointer returned from a C++ function. There are many ways the pointer could have been produced (new, malloc, VirtualAlloc when you're on Windows, etc). There is no way to determine by inspection which one the pointer came from, and using the wrong deallocation function is an error (which may crash your process). Also, even if you know which function to call, your code may be linked against a different version of the language runtime library - so you might be correctly calling free or delete, but an incompatible version.
Normal procedure is for libraries that perform allocation to provide a corresponding deallocation function that frees the allocated memory appropriately. If the library you're using doesn't have this, you'll just have to try what they've told you and follow up if it doesn't work.

Using C++ native dll in .Net External component has thrown an exception

I'm trying to use a native C++ dll in C# and am getting the "External component has thrown an exception" with an error code of -2147467259.
C#:
[DllImport(#"MyDLL.dll", CharSet = CharSet.Auto)]
public static extern string MyFunction([MarshalAs(UnmanagedType.LPStr)] StringBuilder input);
C++:
__declspec(dllexport) char * __stdcall MyFunction(const char* inputPtr);
The function works just fine in C++. How can I track this error down?
I have tried using string and string builder for the parameter.
Update
I found this article http://tom-shelton.net/index.php/2008/12/11/creating-a-managed-wrapper-for-a-lib-file/
It details a way to use managed C++ to wrap an unmanaged static library in C++ which can then be used in a managed language. Would this be a good way of going about tackling this problem? Can the lib be an unmanaged dll?
try the technique from http://blog.rednael.com/2008/08/29/MarshallingUsingNativeDLLsInNET.aspx - this has saved the day several times :-)
If the parameter is in-only (and not out), stringbuilder is not required. If it's an out parameter (or ref) you should use stringbuilder and pre-allocate the buffer using stringbuilder constructor.
I can guess the problem is that you are returning an Ansi string instead of the expected unicode string. This cause the default pinvoke marshaler to read too much memory.
Try this:
[DllImport(#"MyDLL.dll", CharSet = CharSet.Auto)]
[return : MarshalAs(UnmanagedType.LPStr)]
public static extern string MyFunction([MarshalAs(UnmanagedType.LPStr)] string input);
In any case, in the vast majority of times, it does not make any sense to write Ansi C++ code. I would suggest to convert the C++ code to unicode only (not tchar but wchar_t).
CharSet = CharSet.Auto?? use CharSet.Ansi
You cannot use a char array as return, a block of memory allocated with c++ cannot be used by C#! In your case you probably need to copy it into C# managed memory.
Use StringBuilder for that or MarshalAs attribute that will copy for you the buffer into C# managed memory.
You have to change your C++ function, your C++ function must write into the destination buffer that must be allocate so it contains at least the number of characters you need plus one (for null termination character).
[DllImport(#"MyDLL.dll", CharSet = CharSet.Ansi)]
private static extern void MyFunction([MarshalAs(UnmanagedType.LPStr)] string input, StringBuilder result);
public static string MyFunctionPublic(string input)
{
StringBuilder sb = new StringBuilder(input.Length + 1);
MyFunction(input, sb);
return sb.ToString();
}
And i expect your C function to do something like this:
void __stdcall MyFunction(const char* input, char* result)
{
strcpy(result, input); // this is a dummy stupid code to show how it works.
}
Probably you will need a function that gives you idea of how much bytes you have to allocate in C#. This function can be something like this:
int __stdcall ComputeMyFunctionBytes(const char* input)
{
return strlen(input); // this is a dummy stupid code to show how it works.
}
Never return a piece of allocated memory to C#, it cannot do anything with that, nor deallocating, nor reading and nor writing, until you use unsafe code, but this is not what you are trying to do.
A good article seems to be here: http://www.devx.com/dotnet/Article/6990/1954
Also note that C# uses unicode, 16 bit per character, so it will be converted from ansi to unicode.

Categories

Resources