I have a lib that returns a CFString, and I'm trying to get that string value in C#..
The problem is that I don't know how to do this in C#..
Making the external function return a CFString won't work as it throws an exception "Type MonoMac.CoreFoundation.CFString which is passed to unmanaged code must have a StructLayout attribute."
Then I thought that I could get the string as a byte array and then convert it to a string in C#, but then, I have another problem, I don't know how to convert in C the CFString to a byte array :/
C# Dll Import stuff
[DllImport("lib")]
public static extern MonoMac.CoreFoundation.CFString test();
[DllImport("lib")]
public static extern byte[] test();
C Library sample
CFStringRef test()
{
return CFSTR("test string");
}
If anyone knows a way to do this please help me out ;)
Thanks
Try:
[DllImport("lib")]
public static extern IntPtr test();
Then use:
new CFString (test ()).ToString ();
using UnixMarshal.StringToHeap to convert string to IntPtr.
using UnixMarshal.PtrToString to convert IntPtr to string.
Related
i am not sure what the problem is. i have a c++ function returning a string as follows
extern "C++" __declspec(dllexport) std::string D()
{
return "say hello";
}
and on my c#
[DllImport("MyMSG.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern string D();
when i run the wpf, i get an
'Unable to find an entry point named 'D' in DLL 'MyMSG.dll'.'
error. it seems to me that c++ and c# have a type mismatch on strings? i tried with other types like int and bool and i didnt get any problem. can someone explain please? thank you
EDIT
first i would like to thank dxiv and andy for the response. i did more research and found that changing
public static extern string D();
to
public static extern System.IntPtr D();
then calling
string x = Marshal.PtrToStringAnsi(D());
seems to give me the right value.
I have written a DLL in C++. One of the functions writes to a character array.
C++ Function
EXPORT int xmain(int argc, char argv[], char argv2[])
{
char pTypeName[4096];
...
//Other pTypeName ends up populated with "Portable Network Graphics"
//This code verifies that pTypeName is populated with what I think it is:
char szBuff[64];
sprintf(szBuff, pTypeName, 0);
MessageBoxA(NULL, szBuff, szBuff, MB_OK);
//The caption and title are "Portable Network Graphics"
...
//Here, I attempt to copy the value in pTypeName to parameter 3.
sprintf(argv2, szBuff, 0);
return ret;
}
C# Import
//I believe I have to use CharSet.Ansi because by the C++ code uses char[],
[DllImport("FirstDll.dll", CharSet=CharSet.Ansi)]
public static extern int xmain(int argc, string argv, ref string zzz);
C# Function
private void button2_Click(object sender, EventArgs e)
{
string zzz = "";
int xxx = xmain(2, #"C:\hhh.bmp", ref zzz);
MessageBox.Show(zzz);
//The message box displays
//MessageBox.Show displays "IstuÈst¼ÓstÄstlÄstwÄstiÑstõÖstwÍst\
// aÖst[ÖstÃÏst¯ÄstÐstòÄstŽÐstÅstpÅstOleMainThreadWndClass"
}
I have attempted to pass a parameter from C# by reference and have the C++ DLL populate the parameter. Even though I have verified that the value is correct in the DLL, gibberish gets passed to the C# application.
What can I do to write the correct string value to the C# string?
Use a StringBuilder to pass a character array that native code can fill in (see Fixed-Length String Buffers).
Declare the function:
[DllImport("FirstDll.dll", CharSet=CharSet.Ansi)]
public static extern int xmain(int argc, string argv, StringBuilder argv2);
Use it:
// allocate a StringBuilder with enough space; if it is too small,
// the native code will corrupt memory
StringBuilder sb = new StringBuilder(4096);
xmain(2, #"C:\hhh.bmp", sb);
string argv2 = sb.ToString();
Give some other information to the DLLImport call. Look at the following example of my own:
[DllImport("tcpipNexIbnk.dll", EntryPoint = "SendData", CallingConvention = CallingConvention.Cdecl)]
public static extern int Send([MarshalAs(UnmanagedType.LPWStr)]string message);
Notice two things, the CallingConvention parameter:
CallingConvention = CallingConvention.Cdecl)
Use that as it is.
And then just behind the c# string type, you can play with the different Unmanaged types using the MarshalAS instruction, that will cast your C# string parameter to the native string type you have in your c++ program:
public static extern int Send([MarshalAs(UnmanagedType.LPWStr)]string message);
Hope it helps.
I have a C++ MFC regular DLL I am calling with the following:
public static class Access3rdPartyDLL
{
public static string FilePath;
[DllImport("3rdparty.dll")]
// I have also tried LPWStr
public static extern long Download([MarshalAs(UnmanagedType.LPStr)]string sDownloadFile,
int iDeviceNum
...);
public static long DownloadToDevice()
{
long result;
string FilePath = "C:\\myfile.txt"
result = Download(FilePath, 1, ...);
// check if success or error
if(result > 0)
...
}
}
I get an error back from the DLL saying "File: 'C:\myfile.txt' not found. But its there...
I have also tried using StringBuilder but this also fails.
Could this be a problem with the DLL or am I doing something wrong?
I found this current code here: SO: equivalent char* in C#
EDIT: I have done this in C++ before and this code works:
extern "C" __declspec(dllimport) HRESULT __stdcall Download(char* sDownloadFile, int ...
which I call with:
HRESULT result = Download(file_for_download, 1, .. // where file_for_download is a char*
The only thing wrong with the P/invoke is that you are using C# long which is 64 bits, but an HRESULT is only 32 bits.
You have matching calling conventions, default marshalling for managed string is char* on the unmanaged side.
Mismatching return value size would not explain why your C# code receives a string message File: 'C:\myfile.txt' not found so your main problem most likely lies in the code that you haven't shown us.
I don't see any reason why the following wouldn't work in this simple scenario:
[DllImport( "3rdparty.dll", CharSet = CharSet.Ansi )]
static extern long Download(string sDownloadFile, int iDeviceNum, ...)
long result = Download("C:\\myfile.txt", 1, ...);
I have a C function with prototype,
void* VoidPointer(void*);
Now I need to marshal it in C#(using DllImport). But I do not know how to mention the parameters in C# code.
static public extern WHAT_RETURN_TYPE VoidPointer( WHAT_PARAMETER_TYPE );
How to make a call with the proper parameters in the C# code (SAMPLE USE)
I am new to C# and need to solve this asap ( in several attempts have got errors like this cannot convert from 'int' to 'System.IntPtr')
Thanks.
c# supports void pointers. Just declare the function as
[DllImport("test.dll")]
public static extern unsafe void* VoidPointer(void* AValue);
public unsafe void Test()
{
int* a;
int b = 0;
a = (int*)VoidPointer(&b);
}
(this only works if the void pointers are referencing integers ofcourse)
This question already has answers here:
Closed 13 years ago.
Duplicate of 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(string str);
public void func2(string str)
{
func1(str);
}
The C++ side:
void func1(wchar_t *path)
{
//...
}
What I get in the C++ side is an empty string, every time, no matter what I send. Help?
I already asked it here before, but I didn't get an answer that worked.
Thanks.
You need
[DllImport(#"Native3DHandler.dll", EntryPoint = "#22", CharSet = CharSet.Unicode)]
private static extern void func1 ([MarshalAs (UnmanagedType.LPWSTR)] string str) ;
in this case (wchar_t*). And pay attention to the calling convention, as #danbystrom suggests.
have you read this ?
Default Marshaling for Strings
http://msdn.microsoft.com/en-us/library/s9ts558h(VS.71).aspx
Try to put
MarshalAs(UnmanagedType.BStr)
for string type that you are passing to method.
You should declare your C++ func like this:
extern "C" void __stdcall func1(wchar_t *path)
If that doesn't help, try passing a StringBuilder instead of a string.
(Disclaimer: I've never actually passed Unicode code strings, so if neither of the above suggestions work, then just a a test, you could try with "Ansi" instead just to see what happens.)