首页 > 解决方案 > 从 DLL res 文件中将希伯来语字符串读入 VB6

问题描述

我在 Visual Studio 2019 中创建了一个字符串资源 .RES 文件,其中包含多种语言的各种字符串表,然后我将 .RES 编译成一个 VB6 DLL(没有代码,VB6 项目只是一个编译后的 VB6 DLL)。这是创建 DLL 的无代码 VB6 项目:

在此处输入图像描述

然后我将这个 DLL 中的字符串读入一个 VB6 程序,并输出到一个支持 Unicode 的标签控件。

从英语和阿拉伯语中读取/输出的字符串很好,但对于希伯来语,它只显示相同的字符。

Option Explicit

Private Declare Function LoadString Lib "user32" Alias "LoadStringA" (ByVal hInstance As Long, ByVal wID As Long, ByVal lpBuffer As String, ByVal nBufferMax As Long) As Long
Private Declare Function LoadStringW Lib "user32" (ByVal hInstance As Long, ByVal wID As Long, ByVal lpBuffer As String, ByVal nBufferMax As Long) As Long '   Works Arabic
Private Declare Function SetThreadUILanguage Lib "kernel32" (ByVal dwLCID As Long) As Long
Private Declare Function SetThreadLocale Lib "kernel32" (ByVal dwLCID As Long) As Long

Private Sub Form_Load()
    Dim hInst As Long, lResult As Long
    Dim resstring As String
    Dim icc As Long
    
    Const STRLENGTH As Long = 1000
    Const HEBREW As Long = 1037
    Const ARABIC As Long = 3073
    Const ENGLISH As Long = 1033

    icc = ENGLISH   ' convenience, set it once here
    
    SetThreadUILanguage icc
    SetThreadLocale icc
    
    hInst = LoadLibrary("c:\temp\resstr.dll")
    If hInst Then
        resstring = String(STRLENGTH, Chr(0))
        If icc = ENGLISH Then
            lResult = LoadString(hInst, 101, resstring, STRLENGTH)
            Label1.Caption = Left$(resstring, lResult)
        Else
            lResult = LoadStringW(hInst, 101, resstring, STRLENGTH)
            Label1.Caption = StrConv(Left(resstring, lResult * 2), vbFromUnicode, icc)
        End If
        lResult = FreeLibrary(hInst)
    End If
End Sub

这是输出以及编译成 DLL 的 .RES 文件中的内容

如您所见,阿拉伯语输出很好(英语也很好,只是没有截屏)。但是...希伯来语打印出相同的字符?!

标签: vb6localehebrewunicode-stringresource-files

解决方案


您不能Declare作为函数族的参数As String。 VB6 会在调用 d 函数时自动将a转换为非 Unicode 程序的当前系统代码页,并在调用返回时转换回 Unicode。该机制旨在与处理 ANSI 的函数族交互。*W
StringDeclare*A

以这种方式调用*W函数时,不仅Unicode数据会在你有机会执行之前被破坏StrConv(vbFromUnicode)(你几乎不应该这样做,在这里它只会进一步破坏数据),而且你还有一个缓冲区溢出,您向函数承诺您提供了 1000 个字符的空间,而您只提供了 1000 个字节,这是一半。

为了调用*W函数,您必须声明字符串缓冲区As Long并传递StrPtr()字符串变量。

你也不需要回退到LoadStringA,因为它只不过是一个包装器LoadStringW
您的声明 forSetThreadUILanguage也是错误的(LANGIDis a Integer,而不是LCIDwhich is a Long)。

Option Explicit

Private Declare Function LoadStringW Lib "user32" (ByVal hInstance As Long, ByVal wID As Long, ByVal lpBuffer As Long, ByVal nBufferMax As Long) As Long
Private Declare Function SetThreadUILanguage Lib "kernel32" (ByVal LangId As Integer) As Integer
Private Declare Function SetThreadLocale Lib "kernel32" (ByVal dwLCID As Long) As Long

Private Sub Form_Load()
    Dim hInst As Long, lResult As Long
    Dim resstring As String
    Dim icc As Long
    
    Const STRLENGTH As Long = 1000
    Const HEBREW As Long = 1037
    Const ARABIC As Long = 3073
    Const ENGLISH As Long = 1033

    icc = ENGLISH   ' convenience, set it once here
    
    SetThreadUILanguage icc
    SetThreadLocale icc
    
    hInst = LoadLibrary("c:\temp\resstr.dll")
    If hInst Then
        resstring = String(STRLENGTH, vbNullChar)
        lResult = LoadStringW(hInst, 101, StrPtr(resstring), STRLENGTH)
        Label1.Caption = Left$(resstring, lResult)

        lResult = FreeLibrary(hInst)
    End If
End Sub

推荐阅读