2010年06月 存档

用VBS读写二进制文件

2010年06月18日,星期五

网上关于VBS读写二进制文件和二进制数据的文章很少,估计是高手们都很忙,那就由我这个菜鸟来写吧。不知道会不会被很多人复制粘贴然后还不注明出处,应该是会的。恩,我要好好学习知识产权法。

查了很多资料,很多不明真相的同学都叫嚣说用adodb.stream对象就可以实现。不错,是通过adodb.stream实现读写二进制文件的功能,问题是如何实现,你有自己测试过吗?给出的代码都是先用adodb.stream对象读取,然后又写入,这样做有什么意义,还不如直接复制。我想实现的是用adodb.stream直接写我保存在代码中的数据。我试过使用adodb.stream对象的write方法,但是每次都弹出"ADODB.Stream: Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another."错误。想到Linux之父Torvalds Linus的一句话:“Talk is cheap. Show me the code.”光说有什么用,把代码给出来啊。没有代码,就不要说话。

下面是读写二进制文件的两个函数(过程),并不是我写的,我没有那么高的水平,也没有那么厚的脸皮说是我写的,而是国外一位VBS高人写的,膜拜之。ReadBinary函数从文件读取二进制数据并返回数组,WriteBinary将数组中的数据以二进制的形式写到文件中。

Function ReadBinary(FileName)
  Dim Buf(), I
  With CreateObject("ADODB.Stream")
    .Mode = 3: .Type = 1: .Open: .LoadFromFile FileName
    ReDim Buf(.Size - 1)
    For I = 0 To .Size - 1: Buf(I) = AscB(.Read(1)): Next
    .Close
  End With
  ReadBinary = Buf
End Function

Sub WriteBinary(FileName, Buf)
  Dim I, aBuf, Size, bStream
  Size = UBound(Buf): ReDim aBuf(Size \ 2)
  For I = 0 To Size - 1 Step 2
      aBuf(I \ 2) = ChrW(Buf(I + 1) * 256 + Buf(I))
  Next
  If I = Size Then aBuf(I \ 2) = ChrW(Buf(I))
  aBuf=Join(aBuf, "")
  Set bStream = CreateObject("ADODB.Stream")
  bStream.Type = 1: bStream.Open
  With CreateObject("ADODB.Stream")
    .Type = 2 : .Open: .WriteText aBuf
    .Position = 2: .CopyTo bStream: .Close
  End With
  bStream.SaveToFile FileName, 2: bStream.Close
  Set bStream = Nothing
End Sub

非常的强大,我写了一个示例程序,用WriteBinary过程写了一张图片,感兴趣的可以下载来测试一下。

[download id=13]

用VBS下载文件

2010年06月17日,星期四

Google一下关键词“VBS 下载文件”出来也是一堆一样的,你复制我的,我复制你的,复制来复制去最后不知道是谁的。不过基本都是对的了,原理都一样,使用msxml2.xmlhttp和adodb.stream对象。至于他们所说的第二种方法,使用internet.application对象下载文件,我没有测试过,不知道效果怎么样。

Sub download(url,target)
	Const adTypeBinary = 1
	Const adSaveCreateOverWrite = 2
	Dim http,ado
	Set http = CreateObject("Msxml2.XMLHTTP")
	http.open "GET",url,False
	http.send
	Set ado = createobject("Adodb.Stream")
	ado.Type = adTypeBinary
	ado.Open
	ado.Write http.responseBody
	ado.SaveToFile target
	ado.Close
End Sub

download "https://demon.tw/foo.gif","foo.gif"

代码很简单,我就不多说什么了。我好奇的是他们说这段代码杀毒软件会报毒,我没有测试过不知道会不会报毒,但是这句话表明了他们的不良企图。呵呵,原来大家都喜欢编病毒啊。

Asc/AscB/AscW和Chr/ChrB/ChrW函数之间的区别

2010年06月15日,星期二

翻译自微软帮助和支持,感谢公子的大力协助。http://support.microsoft.com/kb/145745/en-us/

概要:多年来,BASIC程序员一直使用Asc和Chr函数来访问和操作ASCII字符集。随着Unicode被主流操作系统和应用程序所接受,需要改进版本的Asc和Chr函数已经开发了。为了满足这种需求,针对Windows系统的Microsoft Visual Basic(4.0以及更高版本)包括了AscB、ChrB和AscW、ChrW函数。

更多信息:Unicode是一种为代替ANSI标准而设计的,把字符编码成数值形式的标准。因为ANSI标准只使用单个字节来代表每个字符,它受最大256个字符的限制。虽然这对于英语受众来说已经足够,但当考虑到全球软件市场时,它无法满足。使用Unicode标准,每个字符由两个字节表示,因此整个的Unicode字符集包括了65536个可能的位置。

微软的Windows NT, Windows 2000, and Microsoft OLE 2.0完全基于Unicode设计,而且Visual Basic(4.0以及更高版本)在内部使用Unicode格式来表示所有的字符串。AscW和ChrW函数允许对Unicode字符的全范围访问。这些函数和原始的Asc、Chr函数运行方式相同,唯一的区别在于新函数支持0到65536的参数,而原来的只能是0到255。许多Visual Basic对象(例如调试窗口、标签、文本框),当它们不知道怎样显示一个Unicode字符时,会返回一个“?”。

因为所有的字符串现在在内部由Unicode格式表示,它不像以前表示一个字符串里的二进制数据那样简单。使用Chr函数来分配数据给一个字符串的结果不再向以前一样。例如:

stringvar = Chr(65)

结果是一个两字节长的字符串,其中第一字节的值为65,第二字节的值为0(这是Unicode表示的字母“A”)。需要记住的是,从ANSI转换至Unicode并不总是意味着像这个例子里做的那样,仅仅添加一个值为0的第二字节。例如,大多数在130~159范围内的ANSI字符码拥有完全不同的Unicode值。尝试运行’Debug.Print AscW(Chr(130))’,然后一个8218的值会显示出来。

(更多…)

用VBS实现PHP的urlencode函数

2010年06月13日,星期日

昨天是JavaScript的,今天换成VBScript版的urlencode函数了,好吧,我承认我很无聊。我写代码之前Google过关键词“VBS urlencode函数”,结果出来的前三个链接(你搜索的结果可能和我不一样)是:。(原谅我不喜欢直接贴链接)好家伙,代码一模一样,一模一样不要紧,还都是错的。贴出来围观一下(注意这是错的)。

Function URLEncode(strURL)
    Dim I
    Dim tempStr
    For I = 1 To Len(strURL)
        If Asc(Mid(strURL, I, 1)) < 0 Then
            tempStr = "%" & Right(CStr(Hex(Asc(Mid(strURL, I, 1)))), 2)
            tempStr = "%" & Left(CStr(Hex(Asc(Mid(strURL, I, 1)))), Len(CStr(Hex(Asc(Mid(strURL, I, 1))))) - 2) & tempStr
            URLEncode = URLEncode & tempStr
        ElseIf (Asc(Mid(strURL, I, 1)) >= 65 And Asc(Mid(strURL, I, 1)) <= 90) Or (Asc(Mid(strURL, I, 1)) >= 97 And Asc(Mid(strURL, I, 1)) <= 122) Or (Asc(Mid(strURL, I, 1)) >= 48 And Asc(Mid(strURL, I, 1)) <= 57) Then
            URLEncode = URLEncode & Mid(strURL, I, 1)
        Else
            URLEncode = URLEncode & "%" & Hex(Asc(Mid(strURL, I, 1)))
        End If
    Next
End Function

连“-_.”这几个符号都一起encode,忽悠广大的人民群众么。退一步讲,假设代码是正确的吧,这代码的效率不敢恭维。我觉得我写代码已经够不讲究效率了,原来还有比我更强的人。每循环一次都要计算一次Len(strURL),然后是出现无数次的Asc(Mid(strURL, I, 1)) 。现在的人到底在想什么,难道看都不看就Ctrl+C,Ctrl+V吗?

由于不同编码的中文字符urlencode的结果是不一样的,我写了两个版本的urlencode函数,一个是ANSI版的,一个是UTF-8版的。这里的ANSI和UTF-8指的不是VBS文件保存的编码,而是指对应的PHP编码,即ANSI版的对应以gb2312编码的PHP字符串的urlencode,UTF-8版的对应以UTF-8编码的PHP字符串的urlencode。以“恶魔”为例,使用ANSI版的urlencode后输出%B6%F1%C4%A7,而UTF-8版的输出%E6%81%B6%E9%AD%94。

代码懒得贴出来了,直接下载吧,有什么问题请留言指正,目前我测试的样本都没有问题,也许是样本不够多吧。

ANSI版的urlencode

[download id=11]

UTF-8版的urlencode

[download id=12]

用JavaScript实现PHP的urlencode函数

2010年06月11日,星期五

在写JavaScript(严格的说是JScript)版的六维空间作弊工具时(怎么又是这句话。。。其实我早就写完了。。。)需要用到PHP的urlencode函数,于是Google之,发现有几种说法。

有的说用JavaScript自带的encodeURIComponent函数即可实现,真是睁着眼睛说瞎话。不解释,自己测试一下就知道JavaScript的encodeURIComponent的PHP的urlencode是不一样的。有的给出了由VBScript和JavaScript混合编写的urlencode,对不对我没有测试,即使对,也只有IE兼容VBScript。还有的贴出一段不知道是自己写的还是哪里转来的代码,都不测试一下对不对就公布出来。

根据我的经验,中文一般是搜不出什么好代码的,用英文的Google搜索,找到三个不同的版本实现,phpjs.orgwebtoolkit.infocass-hacks.com。第一个给出的函数可以直接使用,第二个给出的Url变量也可以直接使用,第三个给出的函数也是对的,但是要保证输入的参数是UTF-8编码。传说JavaScript的内部采用的是UTF-16编码(是不是我也不知道,传说而已),所以要使用第三个函数需要先把字符串转成UTF-8。幸好这个牛人提供了这样一个函数,把两个结合起来就完成了JavaScript版的urlencode函数。代码太长久不贴出来了,直接下载把,下面是在线演示(注意在博客首页无法演示)


注:不同编码下中文的urlencode是不同的,例如“恶魔”在UTF-8编码下urlencode后为%E6%81%B6%E9%AD%94,而在gb2312编码下urlencode后为%B6%F1%C4%A7。鉴于UTF-8比较普遍,本代码仅实现了UTF-8编码的PHP urlencode函数

下载程序代码[download id=9]