I have a function in C++ that returns pointer values:
fPosFirst( int &aId, char *aNname, char *aDirectory );
My syntax in c# is:
fPosFirst(ref int aId, String aNname, String aDirectory);
the function returns the id but not the string parameters that anyone knows?
If you want the parameters to be used for returning values then mark them as ref or out.
E.g.
fPosFirst(ref int aId, out string aNname, out string aDirectory);
Assuming that the native function does not "return pointers" but writes characters to the memory locations specified by aNname and aDirectory, you should be able to pass a StringBuilder with a proper capacity to the native function:
void fPosFirst(ref int aId, StringBuilder aNname, StringBuilder aDirectory);
Usage:
var aId = 0;
var aNname = new StringBuilder(260);
var aDirectory = new StringBuilder(260);
fPosFirst(ref aId, aNname, aDirectory);
You need to make the string parameters ref or out if you want to assign to them within the method and have those values available outside the method.
You need to use out keyword before parameters names (example). But actually this is not good practice in C#
Related
This question already exists:
How to marshal an out string from native code [closed]
Closed 6 years ago.
Having a native function that returns a string (as char *) by parameter, what would be the best option between pre-allocating the char * via managed code and passing it by parameter and allocating the char * from inside the native code and then release it from c#?
could you kindly explain to me why should I use one over the other? Please answer only if there is a specific reason to prefer a solution over the other. If instead either solutions are ok, my question can be considered answered as well.
As bonus, I would like to know how I should allocate the char * variable from c# in the first case(using the Marshal class or with a simple new or with a StringBuilder like I often see in other answers?) and how I should delete the pointer if instead I create the char * variable from inside the native code in the second case.
It is usually not good practice to return a char* from a C function and expect it to be de-allocated by the caller. The caller may not do this (correctly or at all) and thus will leak memory. One common way to avoid this (as used by OpenGL, OpenCL and other libraries I've seen) is to declare the prototype as:
int GetString(char* str, int* len);
with an implementation like so:
int GetString(char* str, int* len)
{
if (str == NULL)
{
len = internal_get_string_length();
return 0; // No errors
}
else
{
if (len <= internal_get_string_length())
return -1; // not enough space in str
char* internal_str = internal_get_string_ptr();
strcpy(str, internal_str);
return 0;
}
}
The documentation will then state that if str is NULL, the length of the string to be returned is returned in len. Otherwise, the pointer str is expected to contain as many characters as required. In order to use it, the user calls the function twice, once with NULL for str and an int for len, then again with an allocated char array as long as len. A possibly prototype for P/Invoking this sort of function is:
// Declaration
[DllImport("myDll.dll")]
int GetString(StringBuilder sb, ref int len);
// Usage
int length;
GetString(null, length);
var sb = new StringBuilder(length); // Set capacity
GetString(sb, length);
Console.WriteLine(sb.ToString()); // Do stuff with C# string
Hope that helps!
I have the following test function set up in a C project:
__declspec(dllexport) int test(char *str, int strlen){
char* h = "Hello";
int length = 5;
for(int i = 0; i < length; i++){
str[0] = h[0];
}
return strlen;
}
And in my C# project I declare the method as follows:
[DllImport("solver.dll", CharSet = CharSet.Unicode ,CallingConvention = CallingConvention.Cdecl)]
public static extern int test(StringBuilder sol, int len);
And I try to use it in my project like so:
StringBuilder sol = new StringBuilder(15);
int t = test(sol, sol.Capacity);
string str = sol.ToString();
I'd like to pass "Hello" back to the C# code as a test, but when I run the code the StringBuilder stays empty, and even though 15 is passed to the C function as the length, when the C function returns the length it returns a 'random' large number like 125822695. What am I missing?
A number of problems:
You state CharSet.Unicode in the C#, but use ANSI in the unmanaged code.
You only write to the first character.
You ignore the value of strlen passed to the function.
You don't attempt to write a null-terminator.
As for the value returned from the function, that cannot be explained by the code that you present. There is something missing from your question that we need to see in order to explain that.
It is quite common when we see these questions, that the unmanaged code is clearly broken. It's hard enough to write correct p/invokes to correct unmanaged code. Trying to debug the p/invoke and the unmanaged code at the same time is so much harder. Test your unmanaged code in an unmanaged setting first. Only when you are confident it is correct should you move to write your p/invoke.
I have a c# library with this function:
public static int myGetStrings(String sOne, out String sTemp1, out String sTemp2)
{
sTemp1 = sOne+"1";
sTemp2 = sOne+"2";
return 0;
}
My c++ wrapper call c# library:
char sOneCall[256],sTemp1Call[256],sTemp2Call[256];
sprintf(sOneCall,"this is a test");
int iReturnData = myLibraryClass-> myGetStrings(
Marshal::PtrToStringAnsi((IntPtr) (char *)sOneCall),
Marshal::PtrToStringAnsi((IntPtr) (char *)sTemp1Call),
Marshal::PtrToStringAnsi((IntPtr) (char *)sTemp2Call) );
But when I execute my code the variables "sTemp1Call" and "sTemp1Call" are void.
Why? What is my problem? Where i wrong?
Thank you
I am assuming you are using c++/cli. if so there is no need to use marshal you can just pass a string directly.
String ^sOneCall = "this is a test";
String ^sTemp1Call = "";
String ^sTemp2Call = ""
int iReturnData = myLibraryClass-> myGetStrings(sOneCall,sTemp1Call,sTemp2Call);
Your function has out parameters if you want to get the values after the call you will need to keep around the .net object a PtrToStringAnsi copies the strings to a new String^ object so you will need to copy it back to your native ptr.
The function in C DLL looks like this:
int my_Funct(char* input, char* output);
I must call this from C# app. I do this in the following way:
...DllImport stuff...
public static extern int my_Funct(string input, string output);
The input string is perfectly transmitted to the DLL (I have visible proof of that). The output that the function fills out although is wrong. I have hexa data in it, like:
3F-D9-00-01
But unfortunately everything that is after the two zeros is cut, and only the first two bytes come to my C# app. It happens, because (I guess) it treats as null character and takes it as the end of the string.
Any idea how could I get rid of it? I tried to specifiy it as out IntPtr instead of a string, but I don't know what to do with it afterwards.
I tried to do after:
byte[] b1 = new byte[2];
Marshal.Copy(output,b1,0,2);
2 should be normally the length of the byte array. But I get all kind of errors: like "Requested range extends past the end of the array." or "Attempted to read or write protected memory..."
I appreciate any help.
Your marshalling of the output string is incorrect. Using string in the p/invoke declaration is appropriate when passing data from managed to native. But you cannot use that when the data flows in the other direction. Instead you need to use StringBuilder. Like this:
[DllImport(...)]
public static extern int my_Funct(string input, StringBuilder output);
Then allocate the memory for output:
StringBuilder output = new StringBuilder(256);
//256 is the capacity in characters - only you know how large a buffer is needed
And then you can call the function.
int retval = my_Funct(inputStr, output);
string outputStr = output.ToString();
On the other hand, if these parameters have null characters in them then you cannot marshal as string. That's because the marshaller won't marshal anything past the null. Instead you need to marshal it as a byte array.
public static extern int my_Funct(
[In] byte[] input,
[Out] byte[] output
);
That matches your C declaration.
Then assuming the ANSI encoding you convert the input string to a byte array like this:
byte[] input = Encoding.Default.GetBytes(inputString);
If you want to use a different encoding, it's obvious how to do so.
And for the output you do need to allocate the array. Assuming it's the same length as the input you would do this:
byte[] output = new byte[input.Length];
And somehow your C function has got to know the length of the arrays. I'll leave that bit to you!
Then you can call the function
int retval = my_Funct(input, output);
And then to convert the output array back to a C# string you use the Encoding class again.
string outputString = Encoding.Default.GetString(output);
In objectiveC given an NSArray fred containing strings I can say:
NSString *s = [fred ObjectAtIndex:5];
What is the c# equivalent? Rosetta stone says to use the method ValueAt but that returns an IntPtr.
var i = fred.ValueAt(5);
But then you are left with how to convert an IntPtr to NSString pointer.
Going via IntPtr feels like a bad idea. Instead, as long as you know the type of the item you want to get, you can just use the following:
int index = 0;
NSString str = myNsArr.GetItem<NSString>(index);
I've came to the same situation.
You can convert that IntPtr to an NSString with new NSString(), like:
string strValue = new NSString(nsArr.ValueAt(1));
It's probably too late for you, but maybe it will help other people.
string strValue = NSString.FromHandle(nsArr.ValueAt(1));