找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 10067|回复: 4

[开源] 【分享】API返回字符串的方式

[复制链接]

275

主题

3017

回帖

1

精华

管理员

嗷嗷叫的老马

积分
17064

论坛牛人贡献奖关注奖最佳版主进步奖人气王疯狂作品奖精英奖赞助论坛勋章乐于助人勋章

QQ
发表于 2009-3-1 03:11:32 | 显示全部楼层 |阅读模式
使用API的过程中,会遇到一些需要返回字符串的API,比如GetClassName,GetWindowText,GetComputerName等.
这类API的共同特点是需要传入一个初始化为一定长度的字符串以及这个字符串的长度,并且在返回值(或某参数)里面返回复制到字符串内的字符的长度.
下面以GetComputerName为例,说明一下这类API使用这种方式的原理.
GetComputerName原型如下:
BOOL GetComputerName(
  LPTSTR lpBuffer,          // 缓冲区地址
  LPDWORD nSize          // 输入时,缓冲区长度;输出时,复制到缓冲区里的字符数
);
返回值为标志着是否成功复制的布尔变量.
那么在VB里面使用,就需要在lpBuffer参数处传入一个初始化为一定长度的字符串,并在nSize参数处以ByRef方式传入这个字符串的长度:
Option Explicit
Private Declare Function GetComputerName Lib "kernel32.dll" Alias "GetComputerNameA" ( _
     ByVal lpBuffer As String, _
     ByRef nSize As Long) As Long
Private Sub Form_Load()
    Dim lpBuffer As String, nSize As Long, lRet As Long
    nSize = 256
    lpBuffer = Space(nSize)      '分配256个长度
    lRet = GetComputerName(lpBuffer, nSize)
                        'nSize参数的声明为ByRef,因为要用于返回"复制到缓冲区内字符的数量"
    If lRet = 1 Then
            'C里面True = 1,False = 0,而VB里True = -1,False = 0,所以API不能声明为Boolean返回值.
        lpBuffer = Mid(lpBuffer, 1, nSize)      '利用nSize的值来去掉多余的字符
        Debug.Print """" & lpBuffer & """"
    End If
End Sub
字符串缓冲区lpBuffer参数为什么要声明为ByVal,是因为BSTR的特殊性.实际传入到API里面的值,是一个指向lpBuffer字符串地址的指针.
因此把lpBuffer参数声明为ByVal lpBuffer As Long后再在调用时用StrPtr(lpBuffer)也是一样的效果,只是没必要......
由于这是一个缓冲区,所以事先需要初始化,就好象一张能写入XX个字的白纸一样,然后再拿给API,并告诉它,这张纸最多可以写XX个字.
当API得到所需要的字符串内容后,会检查这些内容的长度是否小于给出的缓冲区长度.如果缓冲区小了,那么就会在返回值(或某参数)里给出所需要的长度.
此时就需要再次分配足够的缓冲区并再次调用API来完成操作.
当然,这种情况很少碰到,因为我们完全可以一次性分配足够的缓冲区:)
对于如GetClassName,GetWindowText等API而言,复制到缓冲区内的字符数量是由API返回值来给出的.
具体一个API如何使用,请查看MSDN(本论坛总置顶帖"常用下载大全"里面有)
所以要记得使用这些值,不要再用判断NULL啊之类的非标准代码了~~~(话说,见到很多代码就是找NULL,晕倒.)
我就是嗷嗷叫的老马了......

275

主题

3017

回帖

1

精华

管理员

嗷嗷叫的老马

积分
17064

论坛牛人贡献奖关注奖最佳版主进步奖人气王疯狂作品奖精英奖赞助论坛勋章乐于助人勋章

QQ
 楼主| 发表于 2009-3-1 03:12:25 | 显示全部楼层
<p>J8动网,格式全乱了.</p>
<p>&nbsp;</p>
<p>要想办法整一下.</p>
我就是嗷嗷叫的老马了......

275

主题

3017

回帖

1

精华

管理员

嗷嗷叫的老马

积分
17064

论坛牛人贡献奖关注奖最佳版主进步奖人气王疯狂作品奖精英奖赞助论坛勋章乐于助人勋章

QQ
 楼主| 发表于 2009-7-29 23:59:43 | 显示全部楼层
<div class="msgheader">QUOTE:</div><div class="msgborder"><b>以下是引用<i>tonycasablanca</i>在2009-3-7 14:53:30的发言:</b><br/>
<p>好帖!!!学习了!</p>
<p>&nbsp;</p>
<p>关于“所以要记得使用这些值,不要再用判断NULL啊之类的非标准代码了”这句,</p>
<p>我不同意你的看法:</p>
<p>我认为在大多数情况下,都<font color="#ff0000">不应该</font>使用这些返回值。</p>
<p>&nbsp;</p>
<p>因为,API 返回的长度是按<font color="#ff0000">字节</font>计算的,而不是按<font color="#ff0000">字符</font>,如“老马”会返回4 ,</p>
<p>如果用 myStr = &nbsp;Left (Buff, 4) 的话,结果可想而知了,多了2个NULL。</p>
<p>所以,我认为还是要用获得 NULL 位置的方法好!</p>
<p>myStr = Left(Buff, InStr(Buff, vbNullChar) -1)</p>
<p>&nbsp;</p>
<p>当然,像类似 GetComputerName 这种不可能返回双字节字符的 API 就另当别论了。</p>
<div align="right"><font color="#000066">[此贴子已经被作者于2009-3-7 14:57:53编辑过]</font></div></div>
<p>这个倒是,我没考虑到这些情况.....</p>
<p>&nbsp;</p>
<p>但是这种情况主要的问题不在于我上面的思路,而是由于VB自动进行了ANSI---&gt;UNICODE的转换貌似.....所以再使用LEFT,MID之类针对UNICODE的函数去处理,就确实会出错.</p>
<p>&nbsp;</p>
<p>如果是自己进行这种转换,即遇到ByVal XX as string,换成ByVal XX as long后再传一个字节数组的地址进去,返回后再StrConv,则我上面的方法就差不多是通用的了.</p>
我就是嗷嗷叫的老马了......

30

主题

693

回帖

0

精华

钻石会员

积分
2815
发表于 2015-8-30 11:08:47 | 显示全部楼层
不错的文章 支持马总

857

主题

2632

回帖

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

积分
36130
发表于 2015-8-30 12:31:24 | 显示全部楼层
没记错的话,VB6的定长字符串是:dim xx as string*长度
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表