调用从c#返回char*的c++dll函数.无法使用DllImport()
本文关键字:DllImport 函数 c++dll 返回 char 调用 | 更新日期: 2023-09-27 17:59:57
我有一个带有两个函数的c++dll
const char* getVersionText1(void);
void getVersionText2(const char** res);
这两个函数都返回一个描述产品版本的字符串。第一个函数将其返回为const char*(这意味着它在内部分配和处理定位它),第二个函数获取一个指向char*的指针,并将其设置为指向描述版本的char*。
我想从C#调用这些函数并显示文本。我不能使用[dlllimport…]样式,因为函数调用的顺序很重要。我首先调用构造函数,而不是getVersion,最后调用析构函数。所以dll必须先加载到内存中。
你能发布几行代码来打印这两个函数的文本吗。我是C#的新手,如果你发现我的代码有问题,我很抱歉我试过
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* ???
}
}
如果C++库函数返回char*
,C#代码将其视为IntPtr
,Marshal.PtrToStringAnsi()
将其转换为C#string
。
IntPtr verText = f1();
string s = Marshal.PtrToStringAnsi(verText);
Console.WriteLine(s);
这里有一种拨打电话的方法。可能有较短的替代方案可以自动执行utf8/string转换。
[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);
}
如果您需要更高的速度,您也可以执行不安全的读取:
unsafe string GetString(IntPtr ptr) => new string((char*)ptr); // local function
IntPtr charPtr = f1();
var s = GetString(charPtr);
当您添加unsafe
方法时,VS将询问您是否希望在项目中允许不安全的代码:回答是。或者手动"项目属性/构建/允许不安全代码"。