荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: michaelx (Silver Bullet), 信区: DotNET
标  题: C# 和内存指针
发信站: 荔园晨风BBS站 (Tue Mar  9 18:06:22 2004), 站内信件

虽然到了.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 及它的参数不必细加研


--

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.55.18]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店