如何处理 null 或可选的 DLL 结构参数
- 作者: 你的亲爹临死前居然
- 来源: 51数据库
- 2022-10-20
问题描述
如何处理使用 pinvoke 从 C# 调用的 dll 方法中的可选 struct 参数?例如,lpSecurityAttributes 此处的参数 不存在时应传递null.
How do I deal with optional struct arguments in dll methods called from C# using pinvoke? For example, the lpSecurityAttributes parameter here should be passed null when absent.
struct 的正确传递方式似乎是使用ref,但它不能有可选参数,或者一般取null.
The correct way of passing struct's seems to be using ref, but it cannot have optional parameters, or take null in general.
有哪些方法可以实现这一目标?
What ways are there to achieve this?
推荐答案
你有几个选择
1) 使用 class 而不是 struct
我认为这个方法是最简单的.只需将 struct 声明为 class:
You have a few options
1) Use a class instead of a struct
I think this method is the easiest. Simply declare the struct as a class:
[StructLayout(LayoutKind.Sequential)]
public class CStruct
{
//member-list
}
然后声明你的方法:
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static extern int DLLFunction(CStruct cStruct, ...);
如果您的可选参数恰好是最后一个,您可以使用 CStruct cStruct = null 作为参数.这允许您排除它而不是显式传递 null.您还可以编写一个使用此方法并确保可选参数放在最后的包装方法.
If your optional parameter happens to be the last one, you can instead use CStruct cStruct = null as the parameter. This allows you to exclude it instead of passing null explicitly. You can also write a wrapper method that uses this and ensures the optional parameters come last.
使用struct:
[StructLayout(LayoutKind.Sequential)]
public struct CStruct
{
//member-list
}
并将您的方法声明为:
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static extern int DLLFunction(IntPtr cStruct, ...);
在非null 的情况下,编组struct 指向一个指针并调用该方法:
In the non-null case, marshal the struct to a pointer and call the method:
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CStruct)));
try{
Marshal.StructureToPtr(myCStruct, ptr, false);
DLLFunction(ptr, ...);
} finally {
Marshal.FreeHGlobal(ptr);
}
在null的情况下,调用带有IntPtr.Zero的方法:
In the null case, call the method with IntPtr.Zero:
DLLFunction(IntPtr.Zero, ...);
同样,如果这恰好是列表中的最后一个(或者您使用包装器使其成为可选参数),您可以将此参数设为可选.通过使用 IntPtr cStruct = default(IntPtr) 作为参数来执行此操作.(作为 default(IntPtr) 创建一个 IntPtr.Zero.)
Again, you can make this parameter optional if this happens to be the last in the list (or you use a wrapper to make it so). Do this by using IntPtr cStruct = default(IntPtr) as the parameter. (As default(IntPtr) creates a IntPtr.Zero.)
使用 struct,如 2).
简单地为非null情况声明一个选项:
Simply declare one option for the non-null case:
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static extern int DLLFunction(ref cStruct, ...);
另一个用于 null 的情况:
and another for the null case:
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static extern int DLLFunction(IntPtr cStruct, ...);
第一个方法会在传递struct 时自动调用,第二个方法会在传递IntPtr.Zero 时自动调用.如果使用可选参数声明IntPtr 版本(如上面2)底部所示),它会在您排除cStruct时自动调用它代码>参数.
The first method will automatically get called when passing a struct, and the second when passing IntPtr.Zero. If declaring the IntPtr version with an optional parameter (as shown at the bottom of 2) above), it will automatically call it when you exclude the cStruct parameter.
使用 2) 中的结构并声明您的方法(注意 unsafe 关键字):
Use a struct as in 2) and declare your method (note the unsafe keyword):
[DllImport("mydll.dll", OptionName = optionValue, ...)]
static unsafe extern int DLLFunction(CStruct* cStruct, ...);
在非null 的情况下,您传递&myCStruct,并在null 中简单地传递null案件.和1)一样,如果这个可选参数在最后,你可以把参数声明为CStruct* cStruct = null,当<时自动传nullcode>cStruct 被排除在外.
In the non-null case, you pass &myCStruct, and simply null in the null case. As in 1), if this optional parameter is last, you can declare the parameter as CStruct* cStruct = null to automatically pass null when cStruct is excluded.
感谢@dialer 提出这种方法.
- C#通过fleck实现wss协议的WebSocket多人Web实时聊天(附源码)
- 团队城市未满足要求:MSBuildTools12.0_x86_Path 存在
- 使用 MSBuild.exe 在发布模式下构建 C# 解决方案
- 当我发布 Web 应用程序时,AfterPublish 脚本不运行
- 构建时 T4 转换的产品仅在下一个构建中使用
- ASP.NET Core Application (.NET Framework) for Windows x64 only error in project.assets.json
- 新的 .csproj 格式 - 如何将整个目录指定为“链接文件"到子目录?
- 如何将条件编译符号(DefineConstants)传递给 msbuild
- MSBuild 支持 Visual Studio 2017 RTM 中的 T4 模板
- NuGet 包还原找不到包,没有源
