Declare C function with char* parameter in c# - c#

Using C#.net, how I declare and use this function inside a .dll file:
DEMO_API Boolean DEMO_CALL GetVersion(Char* versionBuffer,
UInt16* versionLengthBuffer);
Thanks in advance!

C# doesn't have the notion of string pointers as such, you can just use a string / int.
Basically to define your own you'd have to do somethign slightly different, but it wouldn't be compatible.
public bool GetVersion (string versionBuffer, int versionLengthBuffer)
If your using an existing item have a look at pInvoke for a list of possible signatures.

This is the solution I found:
[DllImport("DEMO.dll",
SetLastError = true,
CallingConvention = CallingConvention.Cdecl)]
public extern static byte GetVersion(
[MarshalAs(UnmanagedType.LPStr)] StringBuilder versionBuffer,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder versionLengthBuffer);

Related

Ref string parameter is empty?

I want to call in C# a function from unmanaged library with following signature:
DLL_EXPORT int xli_open(char *, int , struct t_info *);
In legacy code on Windows 7 the function is improrted as:
[DllImport(DRIVER_FILENAME, EntryPoint = "xli_open", CallingConvention = CallingConvention.Cdecl)]
public static extern int xli_open(string device, int hndl, ref t_info tInfo);
On Windows 10 I get an AccessViolationException for calling the function and I import the function as:
[DllImport(DRIVER_FILENAME, EntryPoint = "xli_open", CallingConvention = CallingConvention.Cdecl)]
public static extern int xli_open(ref string device, int hndl, ref t_info tInfo);
I don't get AccessViolationException anymore, but it seems that the function gets an empty string. Is the declaration right? And why does the pass of the ref parameter work (would string not be passed by reference anyway?)?
Assuming that you are passing the text to the function, then plain by value string is correct. The access violation is likely because of some other error. Perhaps the structure definition does not match, perhaps the calling convention is wrong. Or perhaps some other mistake, but the string argument appears to be correct.

DLLimport returns gobbledygook

I have this define in C++ header file
extern "C" __declspec(dllexport) const char* __stdcall GetId(const My_Polyhedron *obj);
and has this in C#
[DllImport("polyhedra.dll", CallingConvention = CallingConvention.Cdecl)]
static private extern string GetId(IntPtr obj);
It returns me gobbledygook
îþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþ2§{€ûW#_‹p
in .net 4.0, but it works well in .net 3.5.
Note:
I have tried charset=...(all possible settings, e.g. Charset.Unicode) in DllImport.
I have tried to let it returns IntPtr instead of string, then use Marshal.PtrToStringAnsi convert it back to string.
I have tried StringBuilder instead of string.
All the solutions above do not work.
If you are the owner of the C++ code, you can modify the function so that it returns the string as a out parameter:
extern "C" __declspec(dllexport) void __stdcall GetId(
const My_Polyhedron *obj, char* result);
Then use this import in C#:
[DllImport("polyhedra.dll", CallingConvention = CallingConvention.Cdecl)]
static private extern void GetId(IntPtr obj, StringBuilder result);
Please note that result is a StringBuilder instead of a string.
You have to allocate enough space first by making the StringBuilder big enough.
Call it like this:
StringBuilder result = new StringBuilder(1000);
GetId(obj, result);
Use result.ToString() to get the string.
There's the return attribute (it isn't really a attribute) that specifies how marshal the returned value:
[return: MarshalAs(UnmanagedType.Bool)]
But I didn't tried it on your code.
Maybe this helps...

Passing strings to c dll from C#

I have some trouble using a c dll in a c# application. The function which gives me an error is defined in the header file of the dll like this:
int __stdcall DDC_CreateFilePropertyString (DDCFileHandle file,
const char *property,
const char *value);
I added the following code in my class where I access the dll.
[DllImport("nilibddc.dll", CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
private static extern int DDC_CreateFilePropertyString(IntPtr file,
[MarshalAs(UnmanagedType.LPStr)]string property,
[MarshalAs(UnmanagedType.LPStr)]string value);
The Type DDCFileHandle is defined in the header file like this:
typedef struct _DDCFile DDCFile;
typedef DDCFile* DDCFileHandle;
There is are no additional information about the _DDCFile struct in the header file (i don't have any other files from the library im using).
Before I'm calling the function DDC_CreateFilePropertyString() I call the following function to create a file and get the file handle.
[DllImport("nilibddc.dll", CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.Ansi]
private static extern int DDC_CreateFile(char[] filePath,
char[] fileType,
char[] name,
char[] description,
char[] title,
char[] author,
ref IntPtr file);
The definition in the header file looks like this.
int __stdcall DDC_CreateFile (const char *filePath,
const char *fileType,
const char *name,
const char *description,
const char *title,
const char *author,
DDCFileHandle *file);
Now always when i call the function DDC_CreateFilePropertyString it returns me an error telling me that i have some wrong parameters passed. What am i doing wrong? The library I'm using is the TDMS C API from National instruments.
Thanks for your help.
Your p/invokes are a little off. You need to use CallingConvention.Stdcall, which is the default. And for the const char* parameters you should simply declare them to be string at the C# end.
The correct C# p/invoke for DDC_CreateFile is:
[DllImport("nilibddc.dll", CharSet=CharSet.Ansi]
private static extern int DDC_CreateFile(
string filePath,
string fileType,
string name,
string description,
string title,
string author,
ref IntPtr file
);
And for DDC_CreateFilePropertyString you need this:
[DllImport("nilibddc.dll", CharSet=CharSet.Ansi)]
private static extern int DDC_CreateFilePropertyString(
IntPtr file,
string property,
string value
);
If, after fixing your code, you still receive errors when calling these functions, then you are clearly using the library incorrectly. And that's beyond the scope of this question. Consult the documentation, and/or seek support from the library vendor.

How to call from a C# applicaiton a C++ function taking a pointer to void?

I have a dynamic library (.dll) written in C++ exporting a function I'd like to use in my C# applicaiton:
int SendText(void* pControl, char* sText);
How can I, given it takes a pointer to void?
for void* you can just use IntPtr ,
strings will work with the MarshalAs attribute:
[DllImport("MyDll.dll", CharSet = CharSet.Ansi)]
public static extern int SendText(IntPtr pControl, [MarshalAs(UnmanagedType.LPStr)] string sText);

Interop sending string from C# to C++

I want to send a string from C# to a function in a native C++ DLL.
Here is my code:
The C# side:
[DllImport(#"Native3DHandler.dll", EntryPoint = "#22",
CharSet = CharSet.Unicode)]
private static extern void func1(byte[] path);
public void func2(string path)
{
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] arr = encoding.GetBytes(path);
func1(this.something, arr);
}
The C++ side:
void func1(char *path)
{
//...
}
What I get in the C++ side is an empty string, every time, no matter what I send.
Help?
Thanks.
It looks like you have 2 issues. The first is your native C++ uses an ANSI string but you are specifying unicode. Secondly, it's easiest to just marshal a string as a string.
Try changing the DllImport to the following
[DllImport(
#"Native3DHandler.dll",
EntryPoint = "#22",
CharSet = CharSet.Ansi)]
private static extern void func1(void* something, [In] string path);
Works fine for me with no extra marshalling instructions in VS2008:
C# side:
[DllImport("Test.dll")]
public static extern void getString(StringBuilder theString, int bufferSize);
func()
{
StringBuilder tstStr = new StringBuilder(BufSize);
getString(tstStr, BufSize);
}
C++ side:
extern "C" __declspec(dllexport) void getString(char* str, int bufferSize)
{
strcpy_s(str, bufferSize, "FOOBAR");
}
Your declaration is wrong. The parameter should be of type string, and you should set the character set encoding to Ansi, like so:
[DllImport(#"Native3DHandler.dll", EntryPoint = "#22",
CharSet = CharSet.Ansi)]
private static extern void func1(string path);
This assumes that you are not modifying the contents of the path variable in your C++ code. Then, you pass the string parameter directly (no need for the wrapper).
If you just want to send a string, just declare func1's parameter as a string. If you want to receive a string, declare it as a StringBuilder and allocate enough buffer space for what you want to receive.
Default Marshaling for Strings
http://msdn.microsoft.com/en-us/library/s9ts558h.aspx

Categories

Resources