从 C# GUI 将 char * 参数传递给 C++ dll 函数

Passing char * parameter to C++ dll function from C# GUI

我有一个 cpp 函数作为 DLL 文件,用于从特定文件路径读取文件,如果成功则返回“0”,如果失败则返回其他数字:

short __stdcall ReadPx(char *filePath, MAP *map, int *num);

此函数在我的 C# 中定义为:

[DllImport("lib.dll", EntryPoint = "ReadPx", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern System.Int16 ReadPx([MarshalAs(UnmanagedType.LPStr)] string filePath, ref MAP Map, ref Int32 numE);

在主函数中调用为:

var pix = new MAP();
int num = 1;
string path = "C:/Users/Visual Studio 2015/Projects/testWrapper2/Map[=12=]";
System.Int16 Output = ReadPx(path, ref pix, ref num);
Console.WriteLine(Output);

函数运行正常,但给出无效文件路径错误。我认为问题可能是在 C# 代码中将“String filePath”定义为 Unicode(每个字符 2 个字节),而 ReadPx 需要一个指向简单 ASCII 字符串的指针。这就是为什么我尝试了如下所示的一些修改,但文件路径错误仍然存​​在。

[DllImport("lib.dll", EntryPoint = "ReadPx", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern System.Int16 ScReadPixMap(IntPtr filePath, ref PIXMAPENTRY pixMap, ref Int32 numEntries);

IntPtr ptrCString = (IntPtr)Marshal.StringToHGlobalAnsi(path);
System.Int16 output = ReadPx(ptrCString, ref pix, ref num);
Marshal.FreeHGlobal(ptrCString);

一些想法和建议表示赞赏。谢谢。

C++ 声明是:

short __stdcall ReadPx(char *filePath, MAP *map, int *num);

您的 C# 声明是:

[DllImport("lib.dll", EntryPoint = "ReadPx", 
    CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern System.Int16 ReadPx(
    [MarshalAs(UnmanagedType.LPStr)] string filePath, 
    ref MAP Map, 
    ref Int32 numE
);

鉴于我们掌握的信息,这方面没有错误。但是请注意,我们不知道 MAP 是如何声明的,并且那里可能存在错误。我想,第二个和第三个参数可能是数组。这些细节只有你自己知道。

p/invoke 声明过于冗长。如果是我我会这样写:

[DllImport("lib.dll")]
public static extern short ReadPx(string filePath, ref MAP Map, ref int numE);

在您的问题中,您继续声明您是这样调用该函数的:

string path = "C:/Users/Visual Studio 2015/Projects/testWrapper2/Map[=13=]";
System.Int16 Output = ReadPx(ref path, ref pix, ref num);

您添加的显式空终止符毫无意义。该框架确保编组的字符串具有空终止符。明确添加一个并没有什么坏处,但它没有任何用处。删除它。

更大的问题是如何传递字符串参数。代码说:

ref path

嗯,这不会编译,因为您的 p/invoke 将第一个参数声明为值参数,这确实应该如此。

很明显,问题中提供的信息是错误的。也许您的 p/invoke 声明错误地将第一个参数声明为 ref 参数,这与您的问题中所述相矛盾。

总而言之,根据我们掌握的信息,您在问题中提供的 p/invoke 声明是准确的。您的实际代码没有使用该声明,而是使用了错误的声明。