现在的位置: 首页 > 综合 > 正文

C#和内存指针

2017年11月06日 ⁄ 综合 ⁄ 共 2248字 ⁄ 字号 评论关闭

 关 键 词: serverword.net
 
虽然到了.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  及它的参数不必细加研究

 

抱歉!评论已关闭.