Asp.NET Tutorials
Home > C#语言 > 如何在C#中使用Win32和其他库(四)

Hot archives

如何在C#中使用Win32和其他库(四)
如何在C#中使用 Win32和其他库(四)
字符串缓冲区

  .NET  中的字符串类型是不可改变的类型,这意味着它的值将永远保持不变。对于要将字符串值复制到字符串缓冲区的函数,字符串将无效。这样做至少会破坏由封送拆收器在转换字符串时创建的临时缓冲区;严重时会破坏托管堆,而这通常会导致错误的发生。无论哪种情况都不可能获得正确的返回值。  

  要解决此问题,我们需要使用其他类型。StringBuilder  类型就是被设计为用作缓冲区的,我们将使用它来代替字符串。下面是一个示例:  

[dllimport("kernel32.dll",  charset  =  charset.auto)]
public  static  extern  int  GetShortPathName(
   [MarshalAs(UnmanagedType.LPTStr)]
   string  path,
   [MarshalAs(UnmanagedType.LPTStr)]
   StringBuilder  shortPath,
   int  shortPathLength);    

  使用此函数很简单:  

stringbuilder  shortpath  =  new  stringbuilder(80);
int  result  =  GetShortPathName(
@"d:\test.jpg",  shortPath,  shortPath.Capacity);
string  s  =  shortPath.ToString();    

  请注意,StringBuilder  的  Capacity  传递的是缓冲区大小。  

  具有内嵌字符数组的结构

  某些函数接受具有内嵌字符数组的结构。例如,GetTimeZoneInformation()  函数接受指向以下结构的指针:  

typedef  struct  _time_zone_information  {  
  LONG     Bias;  
  WCHAR   StandardName[  32  ];  
  SYSTEMTIME  StandardDate;  
  LONG     StandardBias;  
  WCHAR   DaylightName[  32  ];  
  SYSTEMTIME  DaylightDate;  
  LONG     DaylightBias;  
}  TIME_ZONE_INFORMATION,  *PTIME_ZONE_INFORMATION;    

  在  C#  中使用它需要有两种结构。一种是  SYSTEMTIME,它的设置很简单:  

   struct  SystemTime
   {
   public  short  wYear;
   public  short  wMonth;
   public  short  wDayOfWeek;
   public  short  wDay;
   public  short  wHour;
   public  short  wMinute;
   public  short  wSecond;
   public  short  wMilliseconds;
   }    

  这里没有什么特别之处;另一种是  TimeZoneInformation,它的定义要复杂一些:  

[structlayout(layoutkind.sequential,  charset  =  charset.unicode)]
struct  TimeZoneInformation
{  
   public  int  bias;
   [MarshalAs(UnmanagedType.ByValTStr,  SizeConst  =  32)]
   public  string  standardName;
   SystemTime  standardDate;
   public  int  standardBias;
   [MarshalAs(UnmanagedType.ByValTStr,  SizeConst  =  32)]
   public  string  daylightName;
   SystemTime  daylightDate;
   public  int  daylightBias;
}    

  此定义有两个重要的细节。第一个是  MarshalAs  属性:  

   [MarshalAs(UnmanagedType.ByValTStr,  SizeConst  =  32)]  

  查看  ByValTStr  的文档,我们发现该属性用于内嵌的字符数组;另一个是  SizeConst,它用于设置数组的大小。  

  我在第一次编写这段代码时,遇到了执行引擎错误。通常这意味着部分互操作覆盖了某些内存,表明结构的大小存在错误。我使用  Marshal.SizeOf()  来获取所使用的封送拆收器的大小,结果是  108  字节。我进一步进行了调查,很快回忆起用于互操作的默认字符类型是  Ansi  或单字节。而函数定义中的字符类型为  WCHAR,是双字节,因此导致了这一问题。  

  我通过添加  StructLayout  属性进行了更正。结构在默认情况下按顺序布局,这意味着所有字段都将以它们列出的顺序排列。CharSet  的值被设置为  Unicode,以便始终使用正确的字符类型。  

  经过这样处理后,该函数一切正常。您可能想知道我为什么不在此函数中使用  CharSet.Auto。这是因为,它也没有  A  和  W  变体,而始终使用  Unicode  字符串,因此我采用了上述方法编码。  

Add by : Huobazi (2005-11-16:07:38)