Reputation: 4453
I have a c++ dll with 2 functions
const char* getVersionText1(void);
void getVersionText2(const char** res);
Both function return a string describing the version of the product. First function returns it as const char* (which means it allocates and deal locates it internally) and the second one gets a pointer to char* and just sets it to point to a char* describing the version.
I want to call those functions from C# and display the text. I cant use [dllimport ...] style since the order of the calling of functions is important. I first call constructor than getVersion and finally the destructor. So dll must be loaded to memory first.
Can you please post the few lines of codes that print the text for both functions. I am new to C#, so sorry if you find my code problematic I tried
static class NativeMethods{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
class Program{
// Define function pointers to entires in DLL
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr getVersionText1();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void getVersionText2(IntPtr );
static void Main(string[] args){
// Pointers to functions of DLL.
getVersionText1 f1;
getVersionText2 f2;
IntPtr pDll = NativeMethods.LoadLibrary("p:\\my.dll");
IntPtr pAddressOfFunctionToCall;
pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "getVersionText1 ");
f1 = (getVersionText1)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(getVersionText1));
pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "getVersionText2 ");
f2 = (getVersionText2)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(getVersionText2));
// Here I don't know what to do. It doesn't work ????
IntPtr verText = f1();
String s = Marshal.PtrToStringAuto(verText);
Console.WriteLine(s); // Doesnt work
// And how to use the second function. How do I sent a pointer to char* ???
}
}
Upvotes: 8
Views: 19691
Reputation: 7287
If you need more speed, you also can do an unsafe read:
unsafe string GetString(IntPtr ptr) => new string((char*)ptr); // local function
IntPtr charPtr = f1();
var s = GetString(charPtr);
When you add the unsafe
method, VS will ask you if you want to allow unsafe code in the project: answer yes. Or manually "project properties/build/allow unsafe code".
Upvotes: 1
Reputation: 42165
Here's a way of making your calls. There may be shorter alternatives that perform the utf8/string conversions automatically.
[DllImport("mydll.dll")]
public static extern IntPtr getVersionText1(void);
public string getVersionTextConst()
{
IntPtr ptr = getVersionText1();
// assume returned string is utf-8 encoded
return PtrToStringUtf8(ptr);
}
[DllImport("mydll.dll")]
public static extern void getVersionText2(out IntPtr res);
public string getVersionTextConst()
{
IntPtr ptr;
getVersionText2(ptr);
// assume returned string is utf-8 encoded
String str = PtrToStringUtf8(ptr);
// call native DLL function to free ptr
// if no function exists, pinvoke C runtime's free()
return str;
}
private static string PtrToStringUtf8(IntPtr ptr) // aPtr is nul-terminated
{
if (ptr == IntPtr.Zero)
return "";
int len = 0;
while (System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0)
len++;
if (len == 0)
return "";
byte[] array = new byte[len];
System.Runtime.InteropServices.Marshal.Copy(ptr, array, 0, len);
return System.Text.Encoding.UTF8.GetString(array);
}
Upvotes: 8
Reputation: 1539
If the C++ library function returns char*
, C# code will treat it as IntPtr
and Marshal.PtrToStringAnsi()
will convert it into C# string
.
IntPtr verText = f1();
string s = Marshal.PtrToStringAnsi(verText);
Console.WriteLine(s);
Upvotes: 14