以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 Dot NET,C#,ASP,VB 』  (http://bbs.xml.org.cn/list.asp?boardid=43)
----  C# 和内存指针(转载)  (http://bbs.xml.org.cn/dispbbs.asp?boardid=43&rootid=&id=11769)


--  作者:admin
--  发布时间:11/9/2004 2:25:00 AM

--  C# 和内存指针(转载)


发信人: Nineteen (-_-#!), 信区: DotNET
标  题: C# 和内存指针(转载)
发信站: BBS 水木清华站 (Fri Dec  5 09:28:30 2003), 转信

C# 和内存指针  
其它位置:  
Key: C#,point,IntPtr,Marshal,PtrToStructure,typeof. Author: ArLi @ http://www.zpcity.com/arli/
虽然到了.net 的runtime 时代,C 仍然是不可磨灭的主要支柱,包括在MSDN 里见到的API 大部都是有指针类型存在,那么在以C 冠首的C# 里应当如何去使用指针呢?  
其实,C# 里可以直接使用结构型的变量引用进API,但是毕竟它不是指针在对一些涉及以结构数组存放的内存区操作可能就力有不及了,我举一个例子要使用到结构数组的一个API(对这个API 不必加以了解,我们不是主说API):

NET_API_STATUS NetShareEnum(
LPWSTR servername,
DWORD level,
LPBYTE* bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);

及它要用到的结构 (设 level 为1):

typedef struct _SHARE_INFO_1 {
LPWSTR shi1_netname;
DWORD shi1_type;
LPWSTR shi1_remark;
} SHARE_INFO_1, *PSHARE_INFO_1, *LPSHARE_INFO_1;


在第三个参数 LPBYTE* bufptr 它就是一个指针,而非C 型传统语言的数组的做法,就可以直接声明成 ref SHARE_INFO_1[] bufptr,但我不推荐这么做,原因之一在C# 似乎还不支持结构数组块,而且它并没有存在数组型结构参数的重载。暂且不说如何去实现它,我希望以 C 的操作方式-指针去实现,所以我转成 C# 声明如下:

[StructLayout(LayoutKind.Sequential)]
protected struct SHARE_INFO_1 {
[MarshalAs(UnmanagedType.LPWStr)] public string shi1_netname;
[MarshalAs(UnmanagedType.U4)] public uint shi1_type;
[MarshalAs(UnmanagedType.LPWStr)] public string shi1_remark;
}

[DllImport("Netapi32.dll", EntryPoint="NetShareEnum")]
protected static extern int NetShareEnum(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.U4)] uint level,
ref IntPtr bufptr,
[MarshalAs(UnmanagedType.U4)] uint prefmaxlen,
[MarshalAs(UnmanagedType.U4)] ref uint entriesread,
[MarshalAs(UnmanagedType.U4)] ref uint totalentries,
[MarshalAs(UnmanagedType.U4)] ref uint resume_handle
);

在上面的函数执行完成后,会在指针 bufptr 所指的位置存在一个数据块,此内存块的数据格式是以 SHARE_INFO_1 结构排列的(假设level为1),并且在 entriesread 中指示该块的结构个数,那么我们要如何将它转成真正可用的类型到 SHARE_INFO_1[] shareInfo; 变量中去呢,其实 C# 提供了一种 Marshal.PtrToStructure 的方法,它就是专门将指针所指的非托管内存块搬到托管内存中的指定的结构中去,可它不支持结构数组(目前.net 1.1 还没有该重载实现过),所以只好也最好一个一个的搬(而且一个一个搬更形象些),例子如下:

Int32 ptr = bufptr.ToInt32();
for (int i=0; i<entriesread; i++) {
//开始将ptr 所指的内存块中搬一个SHARE_INFO_1 结构大小并按SHARE_INFO_1 格式排列的数据到 SHARE_INFO_1 型变量 shareInfo 中去
SHARE_INFO_1 shareInfo = (SHARE_INFO_1)Marshal.PtrToStructure(new IntPtr(ptr), typeof(SHARE_INFO_1));  
ptr += Marshal.SizeOf(shareInfo); // 这是将指针向后移一个结构位,因为已经移完一个结构了

//TODO: 操作当前的 shareInfo
}

上面的例子很明显了,bufptr 就是指针,该例子就是将内存中的指针所指的内存块(非托管内存)以一个指定结构的大小和排列格式移动.net 内存(托管内存)中的一个变量去,然后将指针向后移一个位置(ptr += Marshal.SizeOf(shareInfo)),此位置由指针当前位置加上 Marshal.SizeOf(shareInfo) 也就是已经移完的大小获得,它的意思其实就是将指针移到已经搬完的数据的后面去准备搬一下结构块

这个例子只是说明指针的用法,并不是主要说API 对该API 及它的参数不必细加研究
  
2003.10.9  

--
——长夜漫漫,无心睡眠……难道狼妹妹也睡不着吗?


※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.206.3.3]
上一篇
返回上一页
回到目录
回到页首
下一篇



W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
4,644.531ms