`
weizhai12
  • 浏览: 145024 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

如何在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 传递的是缓冲区大小。


简单字符串

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

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 传递的是缓冲区大小。

分享到:
评论

相关推荐

    如何在c#中使用win32和其他库_c#应用

    如何在c#中使用win32和其他库_c#应用

    C#封装好的Win32API.rar

    这是一个c# 调用win32api封装好的库代码,几乎封装了常用win32api。

    C#调用vlc播放器所用到的库(libvlc)

    win-x86 C#调用vlc播放器所用到的库(libvlc) C#调用vlc播放器所用到的库(libvlc) C#调用vlc播放器所用到的库(libvlc) C#调用vlc播放器所用到的库(libvlc) C#调用vlc播放器所用到的库(libvlc) C#...

    . net c# USB库用于WinUSB, LibUsb-Win32和libusb-1.0

    . net c# USB库用于WinUSB, LibUsb-Win32和libusb-1.0。通过使用通用设备类,应用程序可以在所有操作系统和驱动程序中工作,无需修改。大量示例代码。

    在Windows中用C#开发USB的接口库

    完全的通用USB开发库,不需要要任何的驱动(Windows自带),本人开发USB上位机软件包时,发现都是非托管的C++调用库,C#调用库非常少。所以收集了这个,供用.NET方式开发USB的朋友使用。(也包含VC++调用案例)

    C#调用PC主板蜂鸣器小喇叭speaker发声beep(Win7_64位亲测可用)

    不是拷贝XP的beep.sys实现,使用的是InpOut库,32位及64位均可使用。 我自己加了音符频率表,内附一首生日歌,类似于20年前DOS开发一样,使用蜂鸣器播放音乐,其它歌曲请自己编写。 另附InpOut32的调用源代码,不...

    [精]C#实现Win8窗体(SkinForm Demo)

    2.直角边框和阴影。 3.扁平化系统按钮。 4.多系统支持,不需要win8系统。 5.自定义控件的美化使用。 小编:下载不要分,DEMO教你如何熟练使用SkinForm界面库美化自己的窗体。 友情链接:...

    C#开发opcserver含源码

    经常使用的函数在工程中已经定义并使用.WTOPCSVRDLL使用说明中文.doc中,介绍的是VB中WtOPCSvr的使用方法.大家可以把VB的转变成C#的.我的工程中,已经给大家做了示例. 所有的文件:源码,dll文件,说明文件,都包含在...

    支持win10的C#可用以太网收发库文件,可代替Sharppcap

    在C#下实现MAC层以太网收发功能,互联网上多使用sharppcap,但这个库在win10下用不了(win7正常),至少在我电脑上不行,找了好久,发现了pcapdotnet,和sharppcap差不多,但能支持win10,而且功能还要更强大些,给...

    WinIO3.0库(Win32)

    WinIo库允许32位和64位Windows应用程序直接访问I/O端口和物理内存。 3.0版本提供了以下特性: 支持32位和64位平台(不包括Itanium)。 WinIo现在可以被多个应用程序同时使用。 新的c#样本。 这个版本中的Bug修复: 修正...

    C#与C++之间DLL文件的创建与调用DEMO演示

    C#与C++之间DLL文件的创建与调用用VC创建DLL动态连接库 用C#跨语言DLL调用

    USB 通讯 libusb-win32

    USB读写采集vc源码, 数字界面,VC++ 6.0 MFC,libusb-win32应用

    Api精灵 for c#

    欢迎使用精灵 FOR c#>这是我用C#写的第一个 程序,希望大家能够喜欢!(需要.NET环境支持) 主要功能: 简单快速对C#中使用的API函数进行查询,包括 1。提供在C#中能够直接运行的代码。 2。该函数的中文注释。 ...

    C#版DLL远程线程注入源代码

    C#没有自动调用WIN32的一些API函数,我们可以手动添加内核库到我们自己的代码中,从而实现调用win32API函数。 此方法不仅仅用于远程线程注入,还可以用于从MFC转C#过程中不知道如何用C#实现功能,但有知道如何用MFC...

    C#如何在后台捕捉按键

    C#如何在后台捕捉按键 [此问题的推荐答案] API别忘了 using System.Runtime.InteropServices; [DllImport("user32.dll")] public static extern UInt32 RegisterHotKey(IntPtr hWnd, UInt32 id, UInt32 ...

    C#全局钩子屏蔽键盘按键Demo

    C#全局钩子屏蔽键盘按键Demo 可屏蔽键盘按键,组合键,Alt+F4等,亲测可用

    C#版SVN客户端动态库 SharpSvn v1.8

    C#版SVN客户端动态库 SharpSvn v1.8. 包含.Net2.0和.Net4.0的发布版本。 SharpSvn is a binding of the Subversion Client API for .Net 2.0-4.0+ applications contained within a set of xcopy-deployable dll's.

    c#开发opcserver例子(内附源代码)

    经常使用的函数在工程中已经定义并使用.WTOPCSVRDLL使用说明中文.doc中,介绍的是VB中WtOPCSvr的使用方法.大家可以把VB的转变成C#的.我的工程中,已经给大家做了示例. 所有的文件:源码,dll文件,说明文件,都包含在...

    C# 使用管道Pipe在进程间通信

    进程间通信的一种方式,Pipes:管道,分为无名管道:在父子进程间交换数据;有名管道:可在不同主机间交换数据,分为服务器方和客户方,在Win9X下只支持有名管道客户。 1、进程间通信 2、管道Pipe通信

Global site tag (gtag.js) - Google Analytics