【发布时间】:2012-07-10 15:13:02
【问题描述】:
我正在重写我公司的 C# 和 C++ 之间接口的库代码的过度设计和不可维护的部分。我已经开始研究 P/Invoke,但似乎没有太多可访问的帮助。
我们将包含各种参数和设置的结构传递给非托管代码,因此我们定义了相同的结构。我们不需要在 C++ 端更改任何这些参数,但我们确实需要在 P/Invoked 函数返回后访问它们。
我的问题是:
- 传递字符串的最佳方式是什么?有些很短(可以由我们设置的设备 ID),有些是文件路径(可能包含亚洲字符)
- 我应该将 IntPtr 传递给 C# 结构,还是应该让 Marshaller 通过将结构类型放入函数签名中来处理它?
- 我是否应该担心任何非指针数据类型,如布尔值或枚举(在其他相关结构中)?我们在 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;
}
【问题讨论】:
-
究竟是什么不起作用。使用 non-bittable 术语很奇怪,因为您列出的结构肯定会变成字节数组。我会定义结构中每个字段的长度。
-
我更多的是寻找使用 P/Invoke 的正确设计模式。我认为任何带有指针的东西都是不可 blittable 的?
标签: c# c++ string pinvoke marshalling