Marshalling char * to StringBuilder in C# - c#

I know this has already been discussed but after 3days I haven't figured out why I keep getting a blank string after calling a C function wrapped in a DLL in C# :
[DllImport(DllName, CharSet = CharSet.Ansi)]
public static extern int QA_FormatExample(int viHandle, int viExample [MarshalAs(UnmanagedType.LPStr)]StringBuilder rsComment)
In Main :
StringBuilder rsComment = new StringBuilder(256);
apiWrap.QA_FormatExample(currentInstance, viExample, rsComment);
System.Diagnostics.Debug.WriteLine(rsComment);
Function's signature :
int __stdcall QA_FormatExample(int, int, char*);
The function QA_FormatExample initializes rsComment once called but I keep getting rsComment blank. Any suggestion would be really appreciated, thank you.

In order to match the C++ the function should be declared like this:
[DllImport(DllName)]
public static extern int QA_FormatExample(
int viHandle,
int viExample,
StringBuilder rsComment
);
And you call it like this:
StringBuilder comment = new StringBuilder(256);
int res = QA_FormatExample(handle, example, comment);
Which is very close to what you present in the question. So, if your calls to the function do not work, then your problems lie in the code that we cannot see. What I show above is the correct way to marshal text from native to managed via char*.
I would point out that it is a little unusual that you do not pass the length of buffer to the function. Without that information, the maximum length must be hardcoded.

Related

PInvoking function with output parameter

I have the following C++ function:
int my_func(char* error) {
// Have access here to an Exception object called `ex`
strcpy(error, ex.what());
return 0;
}
I am PInvoking it like this in C#:
[DllImport("pHash.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int my_func(
[MarshalAs(UnmanagedType.LPStr)]
StringBuilder error);
And using like this in the code (always C# of course):
StringBuilder error = new StringBuilder();
int returnValue = my_func(error);
If I run this, the program crashes terribly (meaning that is crashes with no exception. Just closes, that's it). What am I doing wrong?
The question here is: How does your code know how large the string buffer should be?
Normally you'd have some way of finding out. In the absence of this information, the only thing you can do is to initialise the StringBuilder to be as large as the largest string you expect, before calling the function.
For example:
StringBuilder error = new StringBuilder(1024); // Assumes 1024 chars max.
Your code is passing a StringBuilder with a default capacity, which is (I think) 16, so any string larger than that will cause a crash.

Calling C++ code from C# error using references in c++

In my C++ dll named "scandll.dll" I have the following function
extern "C" __declspec(dllexport) void scanfile(char * returnstring)
{
strcpy(returnstring, "return string");
}
in my C# code I'm doing this
[DllImport("scandll.dll", CharSet = CharSet.Ansi, SetLastError = true )]
public static extern int scanfile(ref IntPtr strReturn);
and this is the method that I'm using to get the value from the dll
public void Scan()
{
string filename = "";
IntPtr ptr = new IntPtr();
scanfile(ref ptr);//Here i get the error
filename = Marshal.PtrToStringAnsi(ptr);
}
I get an exception thrown as "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
I'm following this link
Calling C++ code from C# error using references in c++ ref in c#
Any help would be appreciated.
Thanks
Your C++ code is wrong - all it's doing is changing the value of the pointer which has been passed to it to point to a constant string. The caller knows nothing about that change.
It's the same as if you'd done this:
void MyCfunction(int number)
{
number = 3;
}
and then hoped that a caller of that function would somehow see the number '3' anywhere.
You could do something like this in C++:
void MyCFunction(char* pReturnString)
{
strcpy(pReturnString, "Hello, world");
}
but you also need to make sure on the C# side that you had provided a buffer with pReturnString pointing to it. One way to do this by using a StringBuilder, and then having your C# declaration of the C function take a parameter like this:
[MarshalAs(UnmanagedType.LPStr)] StringBuilder returnString
You need to reserve space in the StringBuilder before calling into the C++ function.
In real life, C/C++ functions like this pretty much always take an additional length parameter, which allows the caller to tell the callee the maximum length of string it's allowed to copy into the buffer. There is no consistency of convention about whether the length includes the terminating \0 or not, so people are often careful about running right up to the end of the buffer.
memcpy ( destination, * source, size_t num );
Try this to assign the value to returnstring = "rturn name";

how to call a C function from C# with a WCHAR* out parameter?

I'm having a bit of problem with marshaling and I just can't figure it out by myself. I've searched for this topic, but hadn't have any luck yet, so basically I'm trying to call an unmanaged C function from my managed C# application. The signature of the C function looks like this:
long MyFunction(WCHAR* upn, long upnSize, WCHAR* guid, long* guidSize);
I don't access to the .dll file, I just know that the function is being exposed for usage and I know what the function is supposed to do, but I don't know what happening inside, so the function receives a WCHAR* upn holding a UserPricipalName and a long with the length of the supplied UPN. Also a WCHAR pointer is passed along, where the function writes back a corresponding GUID which is associated with the passed UPN. The guidSize pointer supplies the size of the pointer, if it's too small the written GUID is not fully written. If everything goes fine the function should return 0 (it never happened yet, when called from c#)
Now my efforts to invoke and call this function look like this:
[DllImport(#"MyDll.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern long MyFunction(IntPtr upnPtr, long upnSize, [Out, MarshalAsAttribute(UnmanagedType.LPWStr) ] StringBuilder guidPtr, IntPtr guidSizePtr);
//my attempt to call the Dll's exposed function
string upn = foo#bar.com;
long upnSize = upn.Length;
IntPtr upnPtr = Marshal.StringToHGlobalUni(upn);
IntPtr guidSizePtr = Marshal.AllocHGlobal(sizeof(long));
Marshal.WriteInt32(GuidSizePtr, 128);
var guidSB = new StringBuilder(128);
result = MyFunction(upnPtr, upnSize, guidSB, guidSizePtr);
as a result I receive an AccessViolationException. I've played around with many variations to call the function, but I never managed to receive a 0 as return value and I was never able to read out the GUID as I'm supposed to do.
Any help with this would be appreciated.
Declare the function as:
[DllImport(#"MyDll.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern int MyFunction([MarshalAsAttribute(UnmanagedType.LPWStr)] string upnPtr, int upnSize, [MarshalAsAttribute(UnmanagedType.LPWStr)] StringBuilder guidPtr, ref int guidSizePtr);
Call it as follows:
string upn = "foo#bar.com";
var guidSB = new StringBuilder(128);
int guidSizePtr =guidSB.Capacity;
MyFunction(upn, upn.Length, guidSB, ref guidSizePtr);
Note that long in C++ is 32-bit, so you should define all such instances as int in your C# code.

Marshalling string from c# to c++

I am new in microsoft world.
I have lot of problem trying to pass a simple string from c# to dll/c++
I have read a lot of post and documentation about but the problem is the same.
C++ code
extern "C" __declspec(dllexport) int Init( long l , char* url );
C# code
[DllImport("MCRenderer.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = false)]
public static extern int Init(long a, StringBuilder url);
Init(hndl.ToInt64(), str );
what haeppen is that long value is passed correctly while string parameter is
0x00000000 <Bad Ptr>
can you help me ... Iam really confused
thanks!!
AG
You should pass a string, url should be of type string and not StringBuilder.
It's because you're marshalling incorrectly: long and int in C++ are both (usually) int in C#.
From MSDN, you need to:
The only caveat is that the StringBuilder must be allocated enough space for the return value, or the text will overflow, causing an exception to be thrown by P/Invoke
Also from Marshaling between Managed and Unmanaged Code
Don't pass StringBuilder by reference (using out or ref). Otherwise, the CLR will expect the signature of this argument to be wchar_t ** instead of wchar_t *, and it won't be able to pin StringBuilder's internal buffer. Performance will be significantly degraded.
Use StringBuilder when the unmanaged code is using Unicode. Otherwise, the CLR will have to make a copy of the string and convert it between Unicode and ANSI, thus degrading performance. Usually you should marshal StringBuilder as LPARRAY of Unicode characters or as LPWSTR.
Always specify the capacity of StringBuilder in advance and make sure the capacity is big enough to hold the buffer. The best practice on the unmanaged code side is to accept the size of the string buffer as an argument to avoid buffer overruns. In COM, you can also use size_is in IDL to specify the size.
So in your example, you need to specify the native size as the parameter of the StringBuilder like this StringBuilder str = new StringBuilder(SIZE_OF_NATIVE_STRING);
Try using LPCSTR in the dll function parameter
extern "C" __declspec(dllexport) int Init( long l , **LPCTSTR** url );
Here is a good example that I found on how to do this.
C++:
extern "C" __declspec(dllexport) void doSomething(LPCTSTR asString)
{
std::cout << "here" << (wchar_t)asString << endl;
system ("pause");
}
C#:
class Program
{
static void Main(string[] args)
{
String myString = "String in C#";
doSomething(myString);
}
private const String path = #"C:\testdll2.dll"; //Make sure that the DLL is in this location
[DllImport(path)]
private static extern void doSomething(string asString);
}

Calling DLL function with char* param from C#?

I have a C++ dll that I need to call from C#. One of the functions in the dll requires a char* for an input parameter, and another function uses a char* as an output parameter.
What is the proper way to call these from C#?
string should work if the parameter is read-only, if the method modifies the string you should use StringBuilder instead.
Example from reference below:
[DllImport ("libc.so")]
private static extern void strncpy (StringBuilder dest,
string src, uint n);
private static void UseStrncpy ()
{
StringBuilder sb = new StringBuilder (256);
strncpy (sb, "this is the source string", sb.Capacity);
Console.WriteLine (sb.ToString());
}
If you don't know how p/invoke marshaling works you could read http://www.mono-project.com/Interop_with_Native_Libraries
If you are only conserning with strings, read only the section: http://www.mono-project.com/Interop_with_Native_Libraries#Strings
Just using strings will work fine for input parameters, though you can control details about the string with the MarshalAs attribute. E.g.
[DllImport("somedll.dll", CharSet = CharSet.Unicode)]
static extern void Func([MarshalAs(UnmanagedType.LPWStr)] string wideString);
As for returning char* parameters, that's a little more complex since object ownership is involved. If you can change the C++ DLL you can use CoTaskMemAllocate, with something like:
void OutputString(char*& output)
{
char* toCopy = "hello...";
size_t bufferSize = strlen(toCopy);
LPVOID mem = CoTaskMemAlloc(bufferSize);
memcpy(mem, toCopy, bufferSize);
output = static_cast<char*>(mem);
}
The C# side then just uses an 'out string' parameter, and the garbage collector can pick up the ownership of the string.
Another way of doing it would be to use a StringBuilder, but then you need to know how big the string will be before you actually call the function.
Not sure this works, but have you tried with
StringObject.ToCharArray();
Not sure about initialising the String from char * tho. Mybe just assign to a string object, its worth a try.
Have you tried StringBuilder? I found this in a Google search:
[DllImport("advapi32.dll")]
public static extern bool GetUserName(StringBuilder lpBuffer, ref int nSize);
If you post the call you're making we can help you assemble it.
If the DLL function is expecting an allocated buffer of char* (not a wide/multibyte buffer) then the following will work:
[DllImport("somedll.dll", CharSet = CharSet.Ansi)]
static extern void TheFunc(byte[] someBuffer, int someSize);
Here a buffer allocated in c# is passed to TheFunc which fills it with a string of characters (of type char). Bytes aren't "interpreted" by C# they are treated like 8 bit integers, so are perfect for holding 8 bit characters.
An example code snipped would therefore be:
byte[] mybuffer;
int bufSize;
bufSize = 2048;
mybuffer = new byte[bufSize];
TheFunc(mybuffer, bufSize);
string value;
for(value = "", int ix = 0; (mybuffer[ix] != 0) && (ix < bufSize); ix++)
value += (char) mybuffer[ix];
DoSomethingWithTheReturnedString(value);

Categories