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?")
Related
I am using DLL runtime which is made with C language into C#.
I came across below statement.
typedef void *JCCP_PROPERTY_HANDLE;
In function it is being used as:
JCCP_RESULT __JCCP_FUNCTION__ jccpGetProperty(
JCCP_HANDLE hjccp,
const char *name,
JCCP_PROPERTY_HANDLE *phproperty);
Now I want to call jccpGetProperty() method in my C# code.
Can anybody tell how can I pass third parameter(JCCP_PROPERTY_HANDLE *phproperty) to function from C#.
I tried with below code but not working.
Extern Method:
[DllImport(DLL_NAME, EntryPoint = "_jccpGetProperty", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jccpGetProperty(IntPtr hjccp, string name, ref IntPtr JCCP_PROPERTY_HANDLE);
Usage
IntPtr handle = IntPtr.Zero;
string tag = "server.version";
var result = jccpGetProperty(hjccp, tag, ref handle);
Can anybody help me in this?
IntPtr is the correct type mapping for void*. The native type void* is generally used for an opaque pointer, and that is mapped to IntPtr in C#.
Those parts of the p/invoke declaration that we can verify are correct. The unverifible parts are:
The calling convention. You believe that it is cdecl, but we can't check.
The return type. You believe it to be pointer sized. Again we cannot check. My guess is that a 32 bit integer, int or uint is more likely. That would make a difference in a 64 bit process.
The values passed to the function. It's perfectly possible that the function is declared correctly, but you are passing invalid values.
Because you only showed partial code and details, it's hard to say much more. You will have to verify all the parts of the program that we cannot.
I suggest that you start with working C or C++ code and translate that, looking for the first point of deviation in behaviour between that code and your C# translation.
For different purposes I need to provide an interface that implementents the following functions in C#
malloc
calloc
realloc
free
But I would prefer to not to code it myself (why reinvent the wheel).
A better solution would be when my alloc-functions was called, I would simplely call the alloc-functions in stdlib.h, the interface is made so I "just" need to call those functions.
The question is, how do I access the functions in the stdlib.h from C#?
I know about platform invoke, and I am getting better at it. But for platform invoke to work, I need a .dll
And I don't know which .dll implements the stdlib.h
I don't think this sounds like the best solution for your problem. But to answer the question you first need to decide which C runtime to use. One possibility is the system component in msvcrt.dll. Access the functions like this:
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr malloc(IntPtr size);
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void free(IntPtr ptr);
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr calloc(IntPtr num, IntPtr size);
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr realloc(IntPtr ptr, IntPtr size);
However, the official position from MS is that msvcrt.dll is private and not for use by third party applications. So you might prefer to link to a C++ runtime associated with a specific version of MSVC. For example, to link to the VS2013 runtime specify msvcr120.dll. This of course would require you to distribute that runtime.
I have some C code which I have converted into a DLL. I need to call the DLL from a C# program. I'm getting the error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
So, I believe that I haven't converted my function prototype right which is leading to memory leaks.
The function prototype in C is
int __stdcall karacell_bridge( int argumentCount, char **argContent)
Is this a correct conversion of the function prototype in C# DLL call?
[DllImport("KaracellLib.dll", EntryPoint = "karacell_bridge#8", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern int karacell_bridge(int argumentCount, [In, Out]string[] argContent);
No. You'd need to marshal the second argument. I'm not sure if there's a safe PInvoke way to marshal modifiable arrays of strings; It seems like there would be many failure modes here. Perhaps you could try converting the array of strings to an array of char *.
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.
I'm using a DLL written in c++ in my C# project. I have been able to call functions within the DLL using this code:
[DllImport("hidfuncs", EntryPoint = "vm_hid_scan", ExactSpelling = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr VmHidScan();
Now I need to call a function that requres a custom type pointer. The Docs for the DLL layout the function like this:
hid_get_info(int n,PDEV_INFO *pdi)
I don't know how to use this custom pointer. Is this defined in the DLL? If so how can use it from C# project? If not do I need to include the header file in c#? Thanks in advance for your help.
Given the "P" prefix, it looks like the real declaration is
hid_get_info(int n, DEV_INFO **pdi)
where DEV_INFO is a structure. You'll need to find the declaration of this structure and add it to your C# code with the [StructLayout] attribute. You'd then declare the function like this in your C# code:
[DllImport("blah.dll")]
private static extern something hid_get_info(int n, out IntPtr pdi);
and use Marshal.PtrToStructure() to obtain the structure value. Hopefully you don't have to free the structure, you'd be screwed.
A second interpretation is that "pid" returns an array of pointers to DEV_INFO structures. Somewhat likely given the "n" argument, which could well mean the number of elements in the array you pass to be filled by the function. In that case, pass an IntPtr[] and set "n" to its Length.
You need to create a struct in C# that mirrors the C++ PDEV_INFO struct in C++.
You should apply [StructLayout(LayoutKind.Sequential)] to the struct and then copy the fields from the C++ struct (look at the header file) in order.
You can then write an extern method that takes the struct as a ref parameter.
I'll safely assume PDEV_INFO* is a DEV_INFO**.
Use this in C#:
class DEV_INFO
{
// fields go here
}
static class NativeMethods
{
[DllImport...]
public static extern int hid_get_info(int n, ref DEV_INFO pdi);
}