VB6:我无法弄清楚为什么这段代码有效

时间:2014-06-01 12:31:49

标签: vb6

我为这个愚蠢的问题道歉。我维护旧的遗留VB6代码,我有一个实际工作的功能 - 但我只是无法弄清楚它为什么有用,或者为什么代码在没有它的情况下也无法工作。

基本上,此函数读取UTF-8文本文件并在DHTMLEdit组件中显示其内容。它的方式是,它将整个文件读入一个字符串,然后使用ANSI代码页将其从双字节转换为多字节字符串,然后将其转换回双字节。

使用这整个精心制作的机制可以使组件同时正确显示包含希伯来语,阿拉伯语,泰语和中文的页面。不使用此代码会使文本看起来像转换为ASCII,显示字母曾经的各种标点符号。

我不明白的是:

  1. 由于原始文件是UTF-8而VB6字符串是UTF-16,为什么还需要这个?为什么没有VB6正确地从文件中读取字符串而没有所有这些转换?
  2. 如果函数使用CodePage = 0(ANSI)从widebyte转换为multibyte,那么是否会消除当前代码页不支持的任何字符?我甚至没有在这个电台上安装中文,泰文和阿拉伯文。然而,这是我可以正确显示DHTMLEdit控件的唯一方法。
  3. [代码]

    Private Declare Function MultiByteToWideChar Lib "kernel32" (ByVal codePage As Long, ByVal dwFlags As Long, ByVal lpMultiByteStr As Long, ByVal cchMultiByte As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long) As Long
    Private Declare Function WideCharToMultiByte Lib "kernel32" (ByVal codePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, ByVal lpMultiByteStr As Long, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, lpUsedDefaultChar As Long) As Long
    Private Declare Function GetACP Lib "kernel32" () As Long
    
    
    ...
    Open filePath For Input As #lFilePtr
    Dim sInput    as String
    dim sResult   as string
    
    Do While Not EOF(lFilePtr)
        Line Input #lFilePtr, sInput
        sResult = sResult + sInput;
    Loop
    txtBody.DOM.Body.innerText = DecodeString(sResult, CP_UTF8);
    
    Public Function DecodeString(ByVal strSource As String, Optional FromCodePage As Long = -1) As String
        Dim strTemp As String
    
        If strSource = vbNullString Then Exit Function
        strTemp = UnicodeToAnsi(strSource, 0)
        DecodeString = AnsiToUnicode(strTemp, FromCodePage)
    End Function
    
    Public Function AnsiToUnicode(ByVal strSource As String, Optional ByVal codePage As Long = -1, Optional lFlags As Long = 0) As String
        Dim strBuffer As String
        Dim cwch As Long
        Dim pwz As Long
        Dim pwzBuffer As Long
    
        If codePage = -1 Then codePage = GetACP()
        pwz = StrPtr(strSource)
        cwch = MultiByteToWideChar(codePage, lFlags, pwz, -1, 0&, 0&)
        strBuffer = String$(cwch + 1, vbNullChar)
        pwzBuffer = StrPtr(strBuffer)
        cwch = MultiByteToWideChar(codePage, lFlags, pwz, -1, pwzBuffer, Len(strBuffer))
        AnsiToUnicode = Left(strBuffer, cwch - 1)
    End Function
    
    Public Function UnicodeToAnsi(ByVal strSource As String, Optional ByVal codePage As Long = -1, Optional lFlags As Long = 0) As String
        Dim strBuffer As String
        Dim cwch As Long
        Dim pwz As Long
        Dim pwzBuffer As Long
    
        If codePage = -1 Then codePage = GetACP()
        pwz = StrPtr(strSource)
        cwch = WideCharToMultiByte(codePage, lFlags, pwz, -1, 0&, 0&, ByVal 0&, ByVal 0&)
        strBuffer = String$(cwch + 1, vbNullChar)
        pwzBuffer = StrPtr(strBuffer)
        cwch = WideCharToMultiByte(codePage, lFlags, pwz, -1, pwzBuffer, Len(strBuffer), ByVal 0&, ByVal 0&)
        UnicodeToAnsi = Left(strBuffer, cwch - 1)
    End Function
    

    [代码]

1 个答案:

答案 0 :(得分:6)

当使用内置运算符读/写文件时,VB6 / A使用隐式双向UTF16-ASCII转换。

Line Input使用非Unicode程序的当前系统代码页将文件视为ASCII(一系列字节,每个字节代表一个字符)。读取的字符将转换为UTF-16。

当您以这种方式读取UTF-8文件时,您得到的是一个“无效”字符串 - 您不能直接在该语言中使用它(如果您尝试将看到垃圾),但它包含可用的二进制文件数据

然后将指向该可用二进制数据的指针传递给WideCharToMultiByte(在UnicodeToAnsi中),这导致另一个“无效”字符串被创建 - 这次它包含“ASCII”数据。实际上这会使用Line Input自动恢复VB的转换,并且因为原始文件是UTF-8,你现在有一个带有UTF-8数据的“无效”字符串,尽管转换函数认为它正在转换到ASCII。

指向第二个无效字符串的指针传递给MultiByteToWideChar(在AnsiToUnicode中),最终创建一个可在VB中使用的有效字符串。

关于此代码的令人困惑的部分是string用于包含“无效”数据。从逻辑上讲,所有这些都应该是字节数组。我将重构代码以二进制模式从文件中读取字节,并将数组直接传递给MultiByteToWideChar