我正在重写我公司的库代码中的一个过度设计且无法维护的块,该库代码是 C# 和 C++ 之间的接口。我已经开始研究 P/Invoke,但似乎没有太多可访问的帮助。
我们将包含各种参数和设置的结构传递给非托管代码,因此我们定义了相同的结构。我们不需要在 C++ 端更改任何这些参数,但我们确实需要在 P/Invoked 函数返回后访问它们。
我的问题是:
- 传递字符串的最佳方法是什么?有些很短(可以由我们设置的设备 ID),有些是文件路径(可能包含亚洲字符)
- 我应该将 IntPtr 传递给 C# 结构,还是应该让 Marshaller 通过将结构类型放入函数签名中来处理它?
- 我是否应该担心任何非指针数据类型,如 bool 或 enums(在其他相关结构中)?我们在 C++ 中设置了将警告视为错误标志,因此我们不能使用枚举的 Microsoft 扩展来强制数据类型。
- P / Invoke实际上是要走的路吗?有一些关于隐式 P/Invoke 的 Microsoft 文档说它更加类型安全和高性能。
作为参考,这是我迄今为止编写的一对结构体:
C++
/**
Struct used for marshalling Scan parameters from managed to unmanaged code.
*/
struct ScanParameters
{
LPSTR deviceID;
LPSTR spdClock;
LPSTR spdStartTrigger;
double spinRpm;
double startRadius;
double endRadius;
double trackSpacing;
UINT64 numTracks;
UINT32 nominalSampleCount;
double gainLimit;
double sampleRate;
double scanHeight;
LPWSTR qmoPath; //includes filename
LPWSTR qzpPath; //includes filename
};
C#
/// <summary>
/// Struct used for marshalling scan parameters between managed and unmanaged code.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ScanParameters
{
[MarshalAs(UnmanagedType.LPStr)]
public string deviceID;
[MarshalAs(UnmanagedType.LPStr)]
public string spdClock;
[MarshalAs(UnmanagedType.LPStr)]
public string spdStartTrigger;
public Double spinRpm;
public Double startRadius;
public Double endRadius;
public Double trackSpacing;
public UInt64 numTracks;
public UInt32 nominalSampleCount;
public Double gainLimit;
public Double sampleRate;
public Double scanHeight;
[MarshalAs(UnmanagedType.LPWStr)]
public string qmoPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string qzpPath;
}