C#面对“重载”的Win 32 函数
在Win32 Api中有很多添加/设置函数在参数上支持多种不同类型的结构体。这些参数定义为LPVOID* 或者LPBYTE,LPVOID*一般由Win32 分配内存空间,在C#从通过System.IntPtr进行遍历[1]。LPBYTE空间在函数调用的外部进行分配,之所以定义为LPBYTE,是因为这些结构体可能并不相同——属性、大小不同。那么在C#中如何处理这种LPBYTE接收多种结构体引用的Win32 Api?
先看一个Win 32 API的定义:
//The NetUserSetInfo function sets the parameters of a user account. //Syntax [2] NET_API_STATUS NetUserSetInfo(
_In_ LPCWSTR servername,
_In_ LPCWSTR username,
_In_ DWORD level,
_In_ LPBYTE buf,
_Out_ LPDWORD parm_err
); //LPBYTE支持的结构体有二十多种
/**buf部分类型说明
0
Specifies the user account name. The buf parameter points to a USER_INFO_0 structure. Use this structure to specify a new group name. For more information, see the following Remarks section. 1
Specifies detailed information about the user account. The buf parameter points to a USER_INFO_1 structure.
....
1005
Specifies a user privilege level. The buf parameter points to a USER_INFO_1005 structure.
.....
**/
LPBYTE buf支持的类型多达二十多个,面对这种情况,一般可以有两种解决办法。LPBYTE是一个字节数组(栈或者堆)指针,在C#中对应的类型为System.UInt[]。但在此函数中,LPBYTE buf是指向结构体首地址的地址指针。所以第一种方法是直接传入IntPtr。IntPtr是一个神奇的类型,MSDN是这样介绍的[3]:
A platform-specific type that is used to represent a pointer or a handle.
用于表示指针或句柄的平台特定类型。 在Remark是这样说的: The IntPtr type can be used by languages that support pointers, and as a common means of referring to data between languages that do and do not support pointers. MSDN机器翻译: IntPtr 语言中所支持的指针,并作为一种常见的方式来指代语言,并不支持指针之间的数据,则可以使用类型。
MSDN机器翻译我个人认为是错误的,我个人翻译为:
IntPtr可以被支持指针,或者那些不支持指针,而使用通常意义上的数据的引用做指针所做的事的各种(编程)语言使用。(.NET支持多种语言,有些语言支持指针。)
基于以上,第一种方法这是使用System.IntPtr来类型替换LPBYTE,支持多种变化的结构体Buf。那么该函数在C#中的定义即为:
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode)]
internal static extern uint NetUserSetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string username,
uint level,
IntPtr buf,
uint parm_err);
第二种方法基于Win32 Api函数的“重载”——类似于通过参数实现的重载。如果在使用某一个函数时,不考虑其通用性而考虑具体性,可以直接将函数定义为具体的结构体类型。比如如下定义:
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode)]
internal static extern uint NetUserSetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string username,
uint level,
ref USER_INFO_1003 buf,
uint parm_err);
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode)]
internal static extern uint NetUserSetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string username,
uint level,
ref USER_INFO_1017 buf,
uint parm_err);
这两个函数在C#中属于重载函数,支持USER_INFO_1003 和 USER_INFO_1017两个类型。当需要较多的重载函数时,这种方法稍显冗余,使用IntPtr更加有弹性。
毕竟,Win32 只是想得到结构体的地址指针。使用具体类型的引用(ref)或者IntPtr都可以做到。
参考:
[1] 遍历LPVOID*, http://www.cnblogs.com/jjseen/p/win32_api.html
[2] NetSetUserInfo, https://msdn.microsoft.com/zh-cn/data/aa370659(v=vs.100)
[3] IntPtr结构, https://msdn.microsoft.com/zh-cn/library/system.intptr(v=vs.110).aspx
C#面对“重载”的Win 32 函数的更多相关文章
- (转)C#调用非托管Win 32 DLL
转载学习收藏,原文地址http://www.cnblogs.com/mywebname/articles/2291876.html 背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使 ...
- C#访问Win 32的一些尝试
使用C#调用Win 32 Api大部分情况下基本只涉及到参数类型的转变,但在遇到Win 32 Api返回LPVOID *lpBuff 时会遇到一些解析遍历难题.lpBuff为二维指针,*lpBuff是 ...
- 【Windows编程】入门篇——win 32窗口的hello word!
✍ Windows编程基础 1.Win 32应用程序基本类型 1) 控制台程序 不需要完善的windows窗口,可以使用DOS窗口方式显示 2) Win 32窗口程序 包含窗口的程序,可以通过窗 ...
- VCL控件组件大都应该重载TWinControl的虚函数WndProc来进行处理窗口消息的工作
TWinControl的构造函数中会调用MakeObjectInstance并且传递MainWndProc作为窗口消息处理函数,而MainWndProc则会调用虚函数WndProc来处理窗口消息.留个 ...
- 重载operator new delete函数
可以重载global的operator new delete 函数,细节如下: MyNewDelete.h #pragma once #include <stdlib.h> #includ ...
- [原创] Delphi Win API函数 操作帮助文件 HtmlHelpA函数介绍
Delphi Win API函数 操作帮助文件 HtmlHelpA函数介绍 函数原型:HWND HtmlHelpA( HWND hwndCaller, LPCSTR pszFile, UINT uCo ...
- Delphi Win API 函数 MulDiv
Delphi Win API 函数 MulDiv 原型:function MulDiv(nNumber, nNumerator, nDenominator: Integer): Integer; st ...
- 虚函数的使用 以及虚函数与重载的关系, 空虚函数的作用,纯虚函数->抽象类,基类虚析构函数使释放对象更彻底
为了访问公有派生类的特定成员,可以通过讲基类指针显示转换为派生类指针. 也可以将基类的非静态成员函数定义为虚函数(在函数前加上virtual) #include<iostream> usi ...
- Delphi Win API 函数 [ ShellAPI ] ShellExecute 函数
引用单元:uses ShellAPI; 函数原型:function ShellExecute(hWnd: HWND; Operation, FileName, Parameters,Directory ...
随机推荐
- tensorflow的数据输入
tensorflow有两种数据输入方法,比较简单的一种是使用feed_dict,这种方法在画graph的时候使用placeholder来站位,在真正run的时候通过feed字典把真实的输入传进去.比较 ...
- Huawei-R&S-网络工程师实验笔记20190524-VRP的系统、接口视图下基本操作
>Huawei-R&S-网络工程师实验笔记20190524-VRP的系统.接口视图下基本操作(重命名.配置IP.VLAN接口.双工模式.console口) >>实验开始,先上 ...
- 从NLP任务中文本向量的降维问题,引出LSH(Locality Sensitive Hash 局部敏感哈希)算法及其思想的讨论
1. 引言 - 近似近邻搜索被提出所在的时代背景和挑战 0x1:从NN(Neighbor Search)说起 ANN的前身技术是NN(Neighbor Search),简单地说,最近邻检索就是根据数据 ...
- Spring Boot学习总结(4)——使用Springloaded进行热部署
我在开发的时候,总是会及时对自己的程序进行测试,总是频繁的重启web server,容器不烦我们都觉得烦了. dependencys目录下增加: <dependency> <grou ...
- Android第三方开源图片裁剪截取:cropper
Android第三方开源图片裁剪截取:cropper 很多app都需要裁剪截取图片作为头像.logo之类,而cropper是github上的一个针对Android平台的.第三方开源图片裁剪截取项 ...
- python编码小记
Python编码小记 标签(空格分隔): 编程 python 1.list类型remove()操作 列表对象执行remove()函数后,会自动退出循环,所以如果想利用一个单独的for循环删除列表中多个 ...
- nyoj_8_一种排序_201311251238
一种排序 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 现在有很多长方形,每一个长方形都有一个编号,这个编号可以重复:还知道这个长方形的宽和长,编 ...
- [bzoj4385][POI2015]Wilcze doły_单调队列
Wilcze doły bzoj-4385 POI-2015 题目大意:给定一个n个数的序列,可以将连续的长度不超过d的区间内所有数变成0,求最长的一段区间,使得区间和不超过p. 注释:$1\le n ...
- 树剖LCA讲解
LCA的类型多种多样,只说我知道的,就有倍增求LCA,tarjin求LCA和树链剖分求LCA,当然,也还有很多其他的方法. 其中最常用,速度最快的莫过于树链剖分的LCA了. 树链剖分,首先字面理解一下 ...
- Zend_Form 创建、校验和解析表单的基础--(手冊)
1. 创建表单对象 创建表单对象很easy:仅仅要实现 Zend_Form: <?php $form = newZend_Form; ? > 对于高级用例.须要创建 Zend_Form ...