zoukankan      html  css  js  c++  java
  • 如何在C#中使用Win32和其他库之二

    简单字符串

    下面是一个接受字符串参数的函数的简单示例:

    BOOL GetDiskFreeSpace(  LPCTSTR lpRootPathName,          // 根路径  LPDWORD lpSectorsPerCluster,     // 每个簇的扇区数  LPDWORD lpBytesPerSector,        // 每个扇区的字节数  LPDWORD lpNumberOfFreeClusters,  // 可用的扇区数  LPDWORD lpTotalNumberOfClusters  // 扇区总数);

    根路径定义为 LPCTSTR。这是独立于平台的字符串指针。

    由于不存在名为 GetDiskFreeSpace() 的函数,封送拆收器将自动查找“A”或“W”变体,并调用相应的函数。我们使用一个属性来告诉封送拆收器,API 所要求的字符串类型。

    以下是该函数的完整定义,就象我开始定义的那样:

    [DllImport("kernel32.dll")]static extern bool GetDiskFreeSpace(   [MarshalAs(UnmanagedType.LPTStr)]   string rootPathName,   ref int sectorsPerCluster,   ref int bytesPerSector,   ref int numberOfFreeClusters,   ref int totalNumberOfClusters);

    不幸的是,当我试图运行时,该函数不能执行。问题在于,无论我们在哪个平台上,封送拆收器在默认情况下都试图查找 API 的 Ansi 版本,由于 LPTStr 意味着在 Windows NT 平台上会使用 Unicode 字符串,因此试图用 Unicode 字符串来调用 Ansi 函数就会失败。

    有两种方法可以解决这个问题:一种简单的方法是删除 MarshalAs 属性。如果这样做,将始终调用该函数的 A 版本,如果在您所涉及的所有平台上都有这种版本,这是个很好的方法。但是,这会降低代码的执行速度,因为封送拆收器要将 .NET 字符串从 Unicode 转换为多字节,然后调用函数的 A 版本(将字符串转换回 Unicode),最后调用函数的 W 版本。

    要避免出现这种情况,您需要告诉封送拆收器,要它在 Win9x 平台上时查找 A 版本,而在 NT 平台上时查找 W 版本。要实现这一目的,可以将 CharSet 设置为 DllImport 属性的一部分:

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

    在我的非正式计时测试中,我发现这一做法比前一种方法快了大约百分之五。

    对于大多数 Win32 API,都可以对字符串类型设置 CharSet 属性并使用 LPTStr。但是,还有一些不采用 A/W 机制的函数,对于这些函数必须采取不同的方法。

    字符串缓冲区

    .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:	est.jpg", shortPath, shortPath.Capacity);string s = shortPath.ToString();

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


  • 相关阅读:
    DoNet:浅淡对delegate的理解
    纹理学习总结
    Vue引发的getter和setter
    JS——判断一个对象是否为空
    使用vue-axios请求geoJson数据报错的问题
    在vue-cli项目中使用echarts
    Vue中的$set的使用
    史上最全的开发和设计资源大全(转--------来源:伯乐在线)
    IOS safari浏览器登陆时Cookie无法保存的问题
    JS中const、var 和let的区别
  • 原文地址:https://www.cnblogs.com/kevinGao/p/2243453.html
Copyright © 2011-2022 走看看