VB6:我能';我不明白这段代码为什么有效

VB6:我能';我不明白这段代码为什么有效,vb6,Vb6,我为这个愚蠢的问题道歉。我正在维护旧的遗留VB6代码,我有一个实际工作的函数,但我无法理解为什么它可以工作,或者为什么没有它代码就不能工作 基本上,此函数读取UTF-8文本文件并在DHTMLEdit组件中显示其内容。它的工作方式是,将整个文件读入字符串,然后使用ANSI代码页将其从双字节转换为多字节字符串,然后将其转换回双字节 使用这个复杂的机制可以使组件同时正确显示包含希伯来语、阿拉伯语、泰语和汉语的页面。不使用此代码会使文本看起来像是向下转换为ASCII码,显示字母所在的各种标点符号 我不明

我为这个愚蠢的问题道歉。我正在维护旧的遗留VB6代码,我有一个实际工作的函数,但我无法理解为什么它可以工作,或者为什么没有它代码就不能工作

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

使用这个复杂的机制可以使组件同时正确显示包含希伯来语、阿拉伯语、泰语和汉语的页面。不使用此代码会使文本看起来像是向下转换为ASCII码,显示字母所在的各种标点符号

我不明白的是:

  • 既然原始文件是UTF-8,VB6字符串是UTF-16,为什么还要这样做?为什么VB6在没有所有这些转换的情况下不能从文件中正确读取字符串
  • 如果函数使用CodePage=0(ANSI)从宽字节转换为多字节,这不会消除当前代码页不支持的任何字符吗?我甚至没有在这个电台上安装中文、泰语和阿拉伯语。然而,这是使DHTMLEdit控件正确显示的唯一方法
  • [守则]

    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
    

    [code]

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

    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
    
    行输入
    使用非Unicode程序的当前系统代码页,将文件视为ASCII格式(一系列字节,每个字节代表一个字符)。读取的字符转换为UTF-16

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

    然后,指向该可用二进制数据的指针被传递到
    WideCharToMultiByte
    (在
    UnicodeToAnsi
    中),这将导致创建另一个“无效”字符串-这次它包含“ASCII”数据。这有效地恢复了VB使用
    行输入自动进行的转换,因为原始文件是UTF-8格式的,所以现在有一个包含UTF-8数据的“无效”字符串,尽管转换函数认为它正在转换为ASCII

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


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

    GSerg-你真是个天才。我有一种感觉,这是一种倒退的转变,但这对我来说毫无意义。以ASCII格式读取文件并将其转换为UTF-16?哇!关于重构,您完全正确,不幸的是,这是一个更大的类的一部分,用于读取和解析电子邮件,而Line Input命令是这个类的核心。使用字节数组重新编写所有内容将非常麻烦,效率也不高,我必须不断地来回转换。非常感谢你帮了我的忙!我相信这些信息对其他人也很有用。@user884248在该类中,您真的将无效字符串存储为一级数据吗?即,在您显示的代码中,它们仅用于创建和存储解码字符串,并且它是有效字符串,应存储为字符串。看起来你不需要来回转换。不幸的是,是的。代码读取一行,然后开始检查其内容。即使我不必来回转换,这也意味着重新编写整个类,而且我没有单元测试。到目前为止,它已经工作了,所以我宁愿保持原样。+1您已经正确地说过VB6文件编码取决于Windows代码页。在Windows文档中,这种编码通常被称为“ANSI”——这是一个误导性的术语,但它是常用的。它可能比ASCII更好。小诡辩-你说过每个字节代表一个字符,但在某些代码页上,一个字符有多个字节,例如简体中文。这让我注意到OP描述的原始代码还有另一个问题——它可能会在某些代码页中失败。在某些代码页上,UTF8字节流可能不是有效的“ANSI”字节流。