在VB6中显示Unicode文本(希伯来语等)的最佳选择是什么

时间:2022-05-05 22:42:13

I have some customers who want to use our speech therapy software in Hebrew.

我有一些客户希望使用希伯来语的语音治疗软件。

The programs are in VB6. The best option I'm aware of are:

这些程序是在VB6中。我所知道的最佳选择是:

  1. use the Forms 2.0 controls from MS Office, but you can't distribute them.
  2. 使用MS Office中的Forms 2.0控件,但您无法分发它们。

  3. http://www.hexagora.com/en_dw_unictrl.asp $899
  4. http://www.iconico.com/UniToolbox/ $499

Any other options?

还有其他选择吗?

6 个解决方案

#1


I found this tutorial very useful. Yes it is partially an ad for another Unicode Control Suite, but it has a lot of information about how to do it yourself and what issues are involved.

我发现本教程非常有用。是的,它部分是另一个Unicode控制套件的广告,但它有很多关于如何自己做以及涉及哪些问题的信息。

EDIT

I knew I had way more on this stored in my bookmarks.

我知道我在书签中存储了更多内容。

First of all there is an article from Chilkat (another component vendor) about how to use the Font's charset (assuming it is a unicode font) to set different font types (you have to manually change the .frm since charset isn't exposed in the gui). Then all you have to do is convert from AnsiToUTF8 and back to support different languages (that is what Chilkat's control does).

首先,有一篇来自Chilkat(另一个组件供应商)的文章,关于如何使用Font的字符集(假设它是一个unicode字体)来设置不同的字体类型(你必须手动更改.frm,因为charset没有暴露在gui)。然后你所要做的就是从AnsiToUTF8转换回来支持不同的语言(这就是Chilkat的控制所做的)。

Second, there are the Vesa Piittinen's free (Creative Commons, source included) VB6 controls for download here. They include Textbox, Label, Menu, List, Dialog, CommandButton, Caption (form's caption)). I haven't played with them much, but basically he is doing all the onPaint and the nice thing is that is all done in VB and you can look at the source.

其次,有Vesa Piittinen的免费(知识共享,包含源代码)VB6控件可供下载。它们包括Textbox,Label,Menu,List,Dialog,CommandButton,Caption(form的标题))。我没有和他们玩过多,但基本上他正在做所有的onPaint,而且好的是,这一切都是在VB中完成的,你可以查看源代码。

#2


Presumably your users don't have Hebrew selected as the system default code page, otherwise you could just use the native VB6 controls (bearing in mind that Hebrew is right-to-left, obviously!).

据推测,您的用户没有选择希伯来语作为系统默认代码页,否则您可以使用原生VB6控件(请记住,希伯来语是从右到左,显然!)。

Don't use Forms 2 - it will crash your VB6 program. Microsoft Knowledge Base article: "FM20.DLL is known to have many problems when used with Visual Basic and other developer products. Its use is neither recommended nor supported in any Visual Studio product."

不要使用表单2 - 它会使你的VB6程序崩溃。 Microsoft知识库文章:“与Visual Basic和其他开发人员产品一起使用时,FM20.DLL会出现许多问题。任何Visual Studio产品都不推荐使用它。”

I've no personal experience of the others, but your #3 option UniToolbox has been around for years and Google throws up some positive chatter about it on the newsgroups (EDIT - for instance VB6 internationalisation guru Michael Kaplan recommended it in a post in 2004 and a blog post in 2005).

我没有其他人的个人经验,但你的#3选项UniToolbox已经存在多年了,谷歌在新闻组上引发了一些积极的喋喋不休(编辑 - 例如VB6国际化大师Michael Kaplan在2004年的一篇文章中推荐它和2005年的博客文章)。

One whacky option is to use API calls with the native VB6 controls - some pointers in Michael Kaplan's excellent book on Internationalization with VB6 and some sample code on his website too. But it would be lots of work. Do buy the book anyway as it's a gold mine of information on international issues in VB6. For instance the sample chapter explains your problems with Hebrew. Look for it secondhand as it's out of print.

一个令人讨厌的选择是使用原生VB6控件的API调用 - 迈克尔卡普兰关于VB6国际化的优秀书籍以及他网站上的一些示例代码的一些指示。但这将是很多工作。无论如何都要购买这本书,因为它是VB6中有关国际问题的信息的金矿。例如,样本章节解释了希伯来语的问题。因为它已经绝版,所以请二手查找。

#3


According to KB224305 ("INFO: Usage and Redistribution of FM20.DLL"), you can install the free "Microsoft ActiveX Control Pad", which in turn installs the Forms 2.0 Library.

根据KB224305(“INFO:FM20.DLL的使用和重新分发”),您可以安装免费的“Microsoft ActiveX控制板”,然后安装Forms 2.0库。

Maybe this is an option for you.

也许这是你的选择。

#4


Here is all you should need:

以下是您应该需要的:

Option Explicit
'
Private Type GETTEXTEX
    cb As Long
    flags As Long
    codepage As Long
    lpDefaultChar As Long
    lpUsedDefChar As Long
End Type
'
Private Type GETTEXTLENGTHEX
    flags As Long
    codepage As Long
End Type
'
Private Type SETTEXTEX
    flags As Long
    codepage As Long
End Type
'
Private Declare Function DefWindowProcW Lib "user32" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Sub PutMem4 Lib "msvbvm60" (Destination As Any, Value As Any)
Private Declare Function SysAllocStringLen Lib "oleaut32" (ByVal OleStr As Long, ByVal bLen As Long) As Long
Private Declare Function OpenClipboard Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Declare Function EmptyClipboard Lib "user32.dll" () As Long
Private Declare Function CloseClipboard Lib "user32.dll" () As Long
Private Declare Function IsClipboardFormatAvailable Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function GetClipboardData Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function SetClipboardData Lib "user32.dll" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function GlobalAlloc Lib "kernel32.dll" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function lstrcpy Lib "kernel32.dll" Alias "lstrcpyW" (ByVal lpString1 As Long, ByVal lpString2 As Long) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
Private Declare Function SendMessageWLng Lib "user32" Alias "SendMessageW" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'
' The following is from MSDN help:
'
' UNICODE: International Standards Organization (ISO) character standard.
' Unicode uses a 16-bit (2-byte) coding scheme that allows for 65,536 distinct character spaces.
' Unicode includes representations for punctuation marks, mathematical symbols, and dingbats,
' with substantial room for future expansion.
'
' vbUnicode constant:     Converts the string toUnicode using the default code page of the system.
' vbFromUnicode constant: Converts the string from Unicode to the default code page of the system.
'
' LCID: The LocaleID, if different than the system LocaleID. (The system LocaleID is the default.)
'

Public Property Let UniCaption(ctrl As Object, sUniCaption As String)
    Const WM_SETTEXT As Long = &HC
    ' USAGE: UniCaption(SomeControl) = s
    '
    ' This is known to work on Form, MDIForm, Checkbox, CommandButton, Frame, & OptionButton.
    ' Other controls are not known.
    '
    ' As a tip, build your Unicode caption using ChrW.
    ' Also note the careful way we pass the string to the unicode API call to circumvent VB6's auto-ASCII-conversion.
    DefWindowProcW ctrl.hWnd, WM_SETTEXT, 0&, ByVal StrPtr(sUniCaption)
End Property

Public Property Get UniCaption(ctrl As Object) As String
    Const WM_GETTEXT As Long = &HD
    Const WM_GETTEXTLENGTH As Long = &HE
    ' USAGE: s = UniCaption(SomeControl)
    '
    ' This is known to work on Form, MDIForm, Checkbox, CommandButton, Frame, & OptionButton.
    ' Other controls are not known.
    Dim lLen As Long
    Dim lPtr As Long
    '
    lLen = DefWindowProcW(ctrl.hWnd, WM_GETTEXTLENGTH, 0&, ByVal 0&) ' Get length of caption.
    If lLen Then ' Must have length.
        lPtr = SysAllocStringLen(0&, lLen) ' Create a BSTR of that length.
        PutMem4 ByVal VarPtr(UniCaption), ByVal lPtr ' Make the property return the BSTR.
        DefWindowProcW ctrl.hWnd, WM_GETTEXT, lLen + 1&, ByVal lPtr ' Call the default Unicode window procedure to fill the BSTR.
    End If
End Property

Public Property Let UniClipboard(sUniText As String)
    ' Puts a VB string in the clipboard without converting it to ASCII.
    Dim iStrPtr As Long
    Dim iLen As Long
    Dim iLock As Long
    Const GMEM_MOVEABLE As Long = &H2
    Const GMEM_ZEROINIT As Long = &H40
    Const CF_UNICODETEXT As Long = &HD
    '
    OpenClipboard 0&
    EmptyClipboard
    iLen = LenB(sUniText) + 2&
    iStrPtr = GlobalAlloc(GMEM_MOVEABLE Or GMEM_ZEROINIT, iLen)
    iLock = GlobalLock(iStrPtr)
    lstrcpy iLock, StrPtr(sUniText)
    GlobalUnlock iStrPtr
    SetClipboardData CF_UNICODETEXT, iStrPtr
    CloseClipboard
End Property

Public Property Get UniClipboard() As String
    ' Gets a UNICODE string from the clipboard and puts it in a standard VB string (which is UNICODE).
    Dim iStrPtr As Long
    Dim iLen As Long
    Dim iLock As Long
    Dim sUniText As String
    Const CF_UNICODETEXT As Long = 13&
    '
    OpenClipboard 0&
    If IsClipboardFormatAvailable(CF_UNICODETEXT) Then
        iStrPtr = GetClipboardData(CF_UNICODETEXT)
        If iStrPtr Then
            iLock = GlobalLock(iStrPtr)
            iLen = GlobalSize(iStrPtr)
            sUniText = String$(iLen \ 2& - 1&, vbNullChar)
            lstrcpy StrPtr(sUniText), iLock
            GlobalUnlock iStrPtr
        End If
        UniClipboard = sUniText
    End If
    CloseClipboard
End Property

Public Sub SetupRichTextboxForUnicode(rtb As RichTextBox)
    ' Call this so that the rtb doesn't try to do any RTF interpretation.  We will just be using it for Unicode display.
    ' Once this is called, the following two procedures will work with the rtb.
    Const TM_PLAINTEXT As Long = 1&
    Const EM_SETTEXTMODE As Long = &H459
    SendMessage rtb.hWnd, EM_SETTEXTMODE, TM_PLAINTEXT, 0& ' Set the control to use "plain text" mode so RTF isn't interpreted.
End Sub

Public Property Let RichTextboxUniText(rtb As RichTextBox, sUniText As String)
    ' Usage: Just assign any VB6 string to the rtb.
    '        If the string contains Unicode (which VB6 strings are capable of), it will be correctly handled.
    Dim stUnicode As SETTEXTEX
    Const EM_SETTEXTEX As Long = &H461
    Const RTBC_DEFAULT As Long = 0&
    Const CP_UNICODE As Long = 1200&
    '
    stUnicode.flags = RTBC_DEFAULT ' This could be otherwise.
    stUnicode.codepage = CP_UNICODE
    SendMessageWLng rtb.hWnd, EM_SETTEXTEX, VarPtr(stUnicode), StrPtr(sUniText)
End Property

Public Property Get RichTextboxUniText(rtb As RichTextBox) As String
    Dim uGTL As GETTEXTLENGTHEX
    Dim uGT As GETTEXTEX
    Dim iChars As Long
    Const EM_GETTEXTEX As Long = &H45E
    Const EM_GETTEXTLENGTHEX As Long = &H45F
    Const CP_UNICODE As Long = 1200&
    Const GTL_USECRLF As Long = 1&
    Const GTL_PRECISE As Long = 2&
    Const GTL_NUMCHARS As Long = 8&
    Const GT_USECRLF As Long = 1&
    '
    uGTL.flags = GTL_USECRLF Or GTL_PRECISE Or GTL_NUMCHARS
    uGTL.codepage = CP_UNICODE
    iChars = SendMessageWLng(rtb.hWnd, EM_GETTEXTLENGTHEX, VarPtr(uGTL), 0&)
    '
    uGT.cb = (iChars + 1) * 2
    uGT.flags = GT_USECRLF
    uGT.codepage = CP_UNICODE
    RichTextboxUniText = String$(iChars, 0&)
    SendMessageWLng rtb.hWnd, EM_GETTEXTEX, VarPtr(uGT), StrPtr(RichTextboxUniText)
End Property

Public Sub SaveStringToUnicodeFile(sData As String, sFileSpec As String)
    ' These are typically .TXT files.  They can be read with notepad.
    Dim iFle As Long
    '
    iFle = FreeFile
    Open sFileSpec For Binary As iFle
    Put iFle, , &HFEFF ' This is the Unicode header to a text file.  First byte = FF, second byte = FE.
    Put iFle, , UnicodeByteArrayFromString(sData)
    Close iFle
End Sub

Public Function LoadStringFromUnicodeFile(sFileSpec As String) As String
    ' These are typically .TXT files.  They can be read with notepad.
    Dim iFle As Long
    Dim bb() As Byte
    Dim i As Integer
    '
    iFle = FreeFile
    Open sFileSpec For Binary As iFle
    Get iFle, , i
    If i <> &HFEFF Then ' Unicode file header.  First byte = FF, second byte = FE.
        Close iFle
        Exit Function ' It's not a valid Unicode file.
    End If
    ReDim bb(1 To LOF(iFle) - 2&)
    Get iFle, , bb
    Close iFle
    LoadStringFromUnicodeFile = bb ' This directly copies the byte array to the Unicode string (no conversion).
    ' Note: If you try to directly read the file as a string, VB6 will attempt to convert the string from ASCII to Unicode.
End Function

Public Function AsciiByteArrayFromString(s As String) As Byte()
   ' This converts the "s" string to an ASCII string before placing in the byte array.
   AsciiByteArrayFromString = StrConv(s, vbFromUnicode)
End Function

Public Function StringFromAsciiByteArray(bb() As Byte) As String
    ' This assumes that the "bb" array uses only one byte per character and expands it to UNICODE before placing in string.
    StringFromAsciiByteArray = StrConv(bb, vbUnicode)
End Function

Public Function UnicodeByteArrayFromString(s As String) As Byte()
    ' This directly copies the Unicode string into the byte array, using two bytes per character (i.e., Unicode).
    UnicodeByteArrayFromString = s
End Function

Public Function StringFromUnicodeByteArray(bb() As Byte) As String
    ' This directly copies the byte array into the Unicode string, using two bytes per character.
    '
    ' Interestingly, you can assign an odd number of bytes to a string.
    ' The Len(s) function will not count the last (odd) byte, but the LenB(s) function will correctly report it.
    ' However, it is advisable to keep the byte array an even number of bytes.
    StringFromUnicodeByteArray = bb
End Function

#5


Charset table from this link

来自此链接的字符集表

在VB6中显示Unicode文本(希伯来语等)的最佳选择是什么

  • DBCS - Double-Byte Character Set
  • DBCS - 双字节字符集

DBCS is actually not the correct terminology for what Windows uses. It is actually MBCS where a character can be 1 or 2 bytes. To illustrate this consider the following code which will take a Unicode string of English and Chinese characters, convert to a byte array of MBCS Chinese, dump the byte array to the immediate window, and finally convert it back to a Unicode string to display in a Unicode aware textbox. The byte array when converted using Chinese(PRC) LCID = 2052 contains single bytes for the english characters and double bytes for the Unicode characters. This proves that it is MBCS and not DBCS:

DBCS实际上不是Windows使用的正确术语。它实际上是MBCS,其中一个字符可以是1或2个字节。为了说明这一点,请考虑以下代码,它将采用英文和中文字符的Unicode字符串,转换为MBCS中文字节数组,将字节数组转储到即时窗口,最后将其转换回Unicode字符串以显示在Unicode感知文本框。使用中文(PRC)LCID = 2052转换时的字节数组包含英文字符的单个字节和Unicode字符的双字节。这证明它是MBCS而不是DBCS:

#6


Here are some comments about displaying Unicode characters in Microsoft Visual Basic forms using resource (.RES) files:

以下是使用资源(.RES)文件在Microsoft Visual Basic窗体中显示Unicode字符的一些注释:

When I pasted Russian or Japanese characters to Microsoft Visual Basic 6 Resource Editor when creating a resource (.RES) file, the characters would appear as question marks (?) both in MSVB6 Resource Editor and in MSVB6 forms displayed on a computer with Russian or Japanese locale, respectively, using the resource DLL that I built from the RES file through MSVB6.

当我在创建资源(.RES)文件时将俄语或日语字符粘贴到Microsoft Visual Basic 6资源编辑器时,字符在MSVB6资源编辑器和显示在俄语或俄语的计算机上的MSVB6表单中都显示为问号(?)日语语言环境分别使用我通过MSVB6从RES文件构建的资源DLL。

However, if I added the characters to the resource file by pasting them into Resource Hacker http://www.angusj.com/resourcehacker, the characters still would display as question marks in MSVB6 Resource Editor, but would display correctly on a computer with appropriate locale after I built the resource DLLs through MSVB6.

但是,如果我通过将字符粘贴到资源黑客http://www.angusj.com/resourcehacker中将字符添加到资源文件中,字符仍会在MSVB6资源编辑器中显示为问号,但会在具有问题的计算机上正确显示我通过MSVB6构建资源DLL后适当的语言环境。

One can make resource DLLs for each of several languages and use Microsoft's GetUserDefaultLCID or GetUserDefaultLocaleName to decide which to load.

可以为多种语言中的每种语言创建资源DLL,并使用Microsoft的GetUserDefaultLCID或GetUserDefaultLocaleName来决定加载哪些语言。

#1


I found this tutorial very useful. Yes it is partially an ad for another Unicode Control Suite, but it has a lot of information about how to do it yourself and what issues are involved.

我发现本教程非常有用。是的,它部分是另一个Unicode控制套件的广告,但它有很多关于如何自己做以及涉及哪些问题的信息。

EDIT

I knew I had way more on this stored in my bookmarks.

我知道我在书签中存储了更多内容。

First of all there is an article from Chilkat (another component vendor) about how to use the Font's charset (assuming it is a unicode font) to set different font types (you have to manually change the .frm since charset isn't exposed in the gui). Then all you have to do is convert from AnsiToUTF8 and back to support different languages (that is what Chilkat's control does).

首先,有一篇来自Chilkat(另一个组件供应商)的文章,关于如何使用Font的字符集(假设它是一个unicode字体)来设置不同的字体类型(你必须手动更改.frm,因为charset没有暴露在gui)。然后你所要做的就是从AnsiToUTF8转换回来支持不同的语言(这就是Chilkat的控制所做的)。

Second, there are the Vesa Piittinen's free (Creative Commons, source included) VB6 controls for download here. They include Textbox, Label, Menu, List, Dialog, CommandButton, Caption (form's caption)). I haven't played with them much, but basically he is doing all the onPaint and the nice thing is that is all done in VB and you can look at the source.

其次,有Vesa Piittinen的免费(知识共享,包含源代码)VB6控件可供下载。它们包括Textbox,Label,Menu,List,Dialog,CommandButton,Caption(form的标题))。我没有和他们玩过多,但基本上他正在做所有的onPaint,而且好的是,这一切都是在VB中完成的,你可以查看源代码。

#2


Presumably your users don't have Hebrew selected as the system default code page, otherwise you could just use the native VB6 controls (bearing in mind that Hebrew is right-to-left, obviously!).

据推测,您的用户没有选择希伯来语作为系统默认代码页,否则您可以使用原生VB6控件(请记住,希伯来语是从右到左,显然!)。

Don't use Forms 2 - it will crash your VB6 program. Microsoft Knowledge Base article: "FM20.DLL is known to have many problems when used with Visual Basic and other developer products. Its use is neither recommended nor supported in any Visual Studio product."

不要使用表单2 - 它会使你的VB6程序崩溃。 Microsoft知识库文章:“与Visual Basic和其他开发人员产品一起使用时,FM20.DLL会出现许多问题。任何Visual Studio产品都不推荐使用它。”

I've no personal experience of the others, but your #3 option UniToolbox has been around for years and Google throws up some positive chatter about it on the newsgroups (EDIT - for instance VB6 internationalisation guru Michael Kaplan recommended it in a post in 2004 and a blog post in 2005).

我没有其他人的个人经验,但你的#3选项UniToolbox已经存在多年了,谷歌在新闻组上引发了一些积极的喋喋不休(编辑 - 例如VB6国际化大师Michael Kaplan在2004年的一篇文章中推荐它和2005年的博客文章)。

One whacky option is to use API calls with the native VB6 controls - some pointers in Michael Kaplan's excellent book on Internationalization with VB6 and some sample code on his website too. But it would be lots of work. Do buy the book anyway as it's a gold mine of information on international issues in VB6. For instance the sample chapter explains your problems with Hebrew. Look for it secondhand as it's out of print.

一个令人讨厌的选择是使用原生VB6控件的API调用 - 迈克尔卡普兰关于VB6国际化的优秀书籍以及他网站上的一些示例代码的一些指示。但这将是很多工作。无论如何都要购买这本书,因为它是VB6中有关国际问题的信息的金矿。例如,样本章节解释了希伯来语的问题。因为它已经绝版,所以请二手查找。

#3


According to KB224305 ("INFO: Usage and Redistribution of FM20.DLL"), you can install the free "Microsoft ActiveX Control Pad", which in turn installs the Forms 2.0 Library.

根据KB224305(“INFO:FM20.DLL的使用和重新分发”),您可以安装免费的“Microsoft ActiveX控制板”,然后安装Forms 2.0库。

Maybe this is an option for you.

也许这是你的选择。

#4


Here is all you should need:

以下是您应该需要的:

Option Explicit
'
Private Type GETTEXTEX
    cb As Long
    flags As Long
    codepage As Long
    lpDefaultChar As Long
    lpUsedDefChar As Long
End Type
'
Private Type GETTEXTLENGTHEX
    flags As Long
    codepage As Long
End Type
'
Private Type SETTEXTEX
    flags As Long
    codepage As Long
End Type
'
Private Declare Function DefWindowProcW Lib "user32" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Sub PutMem4 Lib "msvbvm60" (Destination As Any, Value As Any)
Private Declare Function SysAllocStringLen Lib "oleaut32" (ByVal OleStr As Long, ByVal bLen As Long) As Long
Private Declare Function OpenClipboard Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Declare Function EmptyClipboard Lib "user32.dll" () As Long
Private Declare Function CloseClipboard Lib "user32.dll" () As Long
Private Declare Function IsClipboardFormatAvailable Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function GetClipboardData Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function SetClipboardData Lib "user32.dll" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function GlobalAlloc Lib "kernel32.dll" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function lstrcpy Lib "kernel32.dll" Alias "lstrcpyW" (ByVal lpString1 As Long, ByVal lpString2 As Long) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
Private Declare Function SendMessageWLng Lib "user32" Alias "SendMessageW" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'
' The following is from MSDN help:
'
' UNICODE: International Standards Organization (ISO) character standard.
' Unicode uses a 16-bit (2-byte) coding scheme that allows for 65,536 distinct character spaces.
' Unicode includes representations for punctuation marks, mathematical symbols, and dingbats,
' with substantial room for future expansion.
'
' vbUnicode constant:     Converts the string toUnicode using the default code page of the system.
' vbFromUnicode constant: Converts the string from Unicode to the default code page of the system.
'
' LCID: The LocaleID, if different than the system LocaleID. (The system LocaleID is the default.)
'

Public Property Let UniCaption(ctrl As Object, sUniCaption As String)
    Const WM_SETTEXT As Long = &HC
    ' USAGE: UniCaption(SomeControl) = s
    '
    ' This is known to work on Form, MDIForm, Checkbox, CommandButton, Frame, & OptionButton.
    ' Other controls are not known.
    '
    ' As a tip, build your Unicode caption using ChrW.
    ' Also note the careful way we pass the string to the unicode API call to circumvent VB6's auto-ASCII-conversion.
    DefWindowProcW ctrl.hWnd, WM_SETTEXT, 0&, ByVal StrPtr(sUniCaption)
End Property

Public Property Get UniCaption(ctrl As Object) As String
    Const WM_GETTEXT As Long = &HD
    Const WM_GETTEXTLENGTH As Long = &HE
    ' USAGE: s = UniCaption(SomeControl)
    '
    ' This is known to work on Form, MDIForm, Checkbox, CommandButton, Frame, & OptionButton.
    ' Other controls are not known.
    Dim lLen As Long
    Dim lPtr As Long
    '
    lLen = DefWindowProcW(ctrl.hWnd, WM_GETTEXTLENGTH, 0&, ByVal 0&) ' Get length of caption.
    If lLen Then ' Must have length.
        lPtr = SysAllocStringLen(0&, lLen) ' Create a BSTR of that length.
        PutMem4 ByVal VarPtr(UniCaption), ByVal lPtr ' Make the property return the BSTR.
        DefWindowProcW ctrl.hWnd, WM_GETTEXT, lLen + 1&, ByVal lPtr ' Call the default Unicode window procedure to fill the BSTR.
    End If
End Property

Public Property Let UniClipboard(sUniText As String)
    ' Puts a VB string in the clipboard without converting it to ASCII.
    Dim iStrPtr As Long
    Dim iLen As Long
    Dim iLock As Long
    Const GMEM_MOVEABLE As Long = &H2
    Const GMEM_ZEROINIT As Long = &H40
    Const CF_UNICODETEXT As Long = &HD
    '
    OpenClipboard 0&
    EmptyClipboard
    iLen = LenB(sUniText) + 2&
    iStrPtr = GlobalAlloc(GMEM_MOVEABLE Or GMEM_ZEROINIT, iLen)
    iLock = GlobalLock(iStrPtr)
    lstrcpy iLock, StrPtr(sUniText)
    GlobalUnlock iStrPtr
    SetClipboardData CF_UNICODETEXT, iStrPtr
    CloseClipboard
End Property

Public Property Get UniClipboard() As String
    ' Gets a UNICODE string from the clipboard and puts it in a standard VB string (which is UNICODE).
    Dim iStrPtr As Long
    Dim iLen As Long
    Dim iLock As Long
    Dim sUniText As String
    Const CF_UNICODETEXT As Long = 13&
    '
    OpenClipboard 0&
    If IsClipboardFormatAvailable(CF_UNICODETEXT) Then
        iStrPtr = GetClipboardData(CF_UNICODETEXT)
        If iStrPtr Then
            iLock = GlobalLock(iStrPtr)
            iLen = GlobalSize(iStrPtr)
            sUniText = String$(iLen \ 2& - 1&, vbNullChar)
            lstrcpy StrPtr(sUniText), iLock
            GlobalUnlock iStrPtr
        End If
        UniClipboard = sUniText
    End If
    CloseClipboard
End Property

Public Sub SetupRichTextboxForUnicode(rtb As RichTextBox)
    ' Call this so that the rtb doesn't try to do any RTF interpretation.  We will just be using it for Unicode display.
    ' Once this is called, the following two procedures will work with the rtb.
    Const TM_PLAINTEXT As Long = 1&
    Const EM_SETTEXTMODE As Long = &H459
    SendMessage rtb.hWnd, EM_SETTEXTMODE, TM_PLAINTEXT, 0& ' Set the control to use "plain text" mode so RTF isn't interpreted.
End Sub

Public Property Let RichTextboxUniText(rtb As RichTextBox, sUniText As String)
    ' Usage: Just assign any VB6 string to the rtb.
    '        If the string contains Unicode (which VB6 strings are capable of), it will be correctly handled.
    Dim stUnicode As SETTEXTEX
    Const EM_SETTEXTEX As Long = &H461
    Const RTBC_DEFAULT As Long = 0&
    Const CP_UNICODE As Long = 1200&
    '
    stUnicode.flags = RTBC_DEFAULT ' This could be otherwise.
    stUnicode.codepage = CP_UNICODE
    SendMessageWLng rtb.hWnd, EM_SETTEXTEX, VarPtr(stUnicode), StrPtr(sUniText)
End Property

Public Property Get RichTextboxUniText(rtb As RichTextBox) As String
    Dim uGTL As GETTEXTLENGTHEX
    Dim uGT As GETTEXTEX
    Dim iChars As Long
    Const EM_GETTEXTEX As Long = &H45E
    Const EM_GETTEXTLENGTHEX As Long = &H45F
    Const CP_UNICODE As Long = 1200&
    Const GTL_USECRLF As Long = 1&
    Const GTL_PRECISE As Long = 2&
    Const GTL_NUMCHARS As Long = 8&
    Const GT_USECRLF As Long = 1&
    '
    uGTL.flags = GTL_USECRLF Or GTL_PRECISE Or GTL_NUMCHARS
    uGTL.codepage = CP_UNICODE
    iChars = SendMessageWLng(rtb.hWnd, EM_GETTEXTLENGTHEX, VarPtr(uGTL), 0&)
    '
    uGT.cb = (iChars + 1) * 2
    uGT.flags = GT_USECRLF
    uGT.codepage = CP_UNICODE
    RichTextboxUniText = String$(iChars, 0&)
    SendMessageWLng rtb.hWnd, EM_GETTEXTEX, VarPtr(uGT), StrPtr(RichTextboxUniText)
End Property

Public Sub SaveStringToUnicodeFile(sData As String, sFileSpec As String)
    ' These are typically .TXT files.  They can be read with notepad.
    Dim iFle As Long
    '
    iFle = FreeFile
    Open sFileSpec For Binary As iFle
    Put iFle, , &HFEFF ' This is the Unicode header to a text file.  First byte = FF, second byte = FE.
    Put iFle, , UnicodeByteArrayFromString(sData)
    Close iFle
End Sub

Public Function LoadStringFromUnicodeFile(sFileSpec As String) As String
    ' These are typically .TXT files.  They can be read with notepad.
    Dim iFle As Long
    Dim bb() As Byte
    Dim i As Integer
    '
    iFle = FreeFile
    Open sFileSpec For Binary As iFle
    Get iFle, , i
    If i <> &HFEFF Then ' Unicode file header.  First byte = FF, second byte = FE.
        Close iFle
        Exit Function ' It's not a valid Unicode file.
    End If
    ReDim bb(1 To LOF(iFle) - 2&)
    Get iFle, , bb
    Close iFle
    LoadStringFromUnicodeFile = bb ' This directly copies the byte array to the Unicode string (no conversion).
    ' Note: If you try to directly read the file as a string, VB6 will attempt to convert the string from ASCII to Unicode.
End Function

Public Function AsciiByteArrayFromString(s As String) As Byte()
   ' This converts the "s" string to an ASCII string before placing in the byte array.
   AsciiByteArrayFromString = StrConv(s, vbFromUnicode)
End Function

Public Function StringFromAsciiByteArray(bb() As Byte) As String
    ' This assumes that the "bb" array uses only one byte per character and expands it to UNICODE before placing in string.
    StringFromAsciiByteArray = StrConv(bb, vbUnicode)
End Function

Public Function UnicodeByteArrayFromString(s As String) As Byte()
    ' This directly copies the Unicode string into the byte array, using two bytes per character (i.e., Unicode).
    UnicodeByteArrayFromString = s
End Function

Public Function StringFromUnicodeByteArray(bb() As Byte) As String
    ' This directly copies the byte array into the Unicode string, using two bytes per character.
    '
    ' Interestingly, you can assign an odd number of bytes to a string.
    ' The Len(s) function will not count the last (odd) byte, but the LenB(s) function will correctly report it.
    ' However, it is advisable to keep the byte array an even number of bytes.
    StringFromUnicodeByteArray = bb
End Function

#5


Charset table from this link

来自此链接的字符集表

在VB6中显示Unicode文本(希伯来语等)的最佳选择是什么

  • DBCS - Double-Byte Character Set
  • DBCS - 双字节字符集

DBCS is actually not the correct terminology for what Windows uses. It is actually MBCS where a character can be 1 or 2 bytes. To illustrate this consider the following code which will take a Unicode string of English and Chinese characters, convert to a byte array of MBCS Chinese, dump the byte array to the immediate window, and finally convert it back to a Unicode string to display in a Unicode aware textbox. The byte array when converted using Chinese(PRC) LCID = 2052 contains single bytes for the english characters and double bytes for the Unicode characters. This proves that it is MBCS and not DBCS:

DBCS实际上不是Windows使用的正确术语。它实际上是MBCS,其中一个字符可以是1或2个字节。为了说明这一点,请考虑以下代码,它将采用英文和中文字符的Unicode字符串,转换为MBCS中文字节数组,将字节数组转储到即时窗口,最后将其转换回Unicode字符串以显示在Unicode感知文本框。使用中文(PRC)LCID = 2052转换时的字节数组包含英文字符的单个字节和Unicode字符的双字节。这证明它是MBCS而不是DBCS:

#6


Here are some comments about displaying Unicode characters in Microsoft Visual Basic forms using resource (.RES) files:

以下是使用资源(.RES)文件在Microsoft Visual Basic窗体中显示Unicode字符的一些注释:

When I pasted Russian or Japanese characters to Microsoft Visual Basic 6 Resource Editor when creating a resource (.RES) file, the characters would appear as question marks (?) both in MSVB6 Resource Editor and in MSVB6 forms displayed on a computer with Russian or Japanese locale, respectively, using the resource DLL that I built from the RES file through MSVB6.

当我在创建资源(.RES)文件时将俄语或日语字符粘贴到Microsoft Visual Basic 6资源编辑器时,字符在MSVB6资源编辑器和显示在俄语或俄语的计算机上的MSVB6表单中都显示为问号(?)日语语言环境分别使用我通过MSVB6从RES文件构建的资源DLL。

However, if I added the characters to the resource file by pasting them into Resource Hacker http://www.angusj.com/resourcehacker, the characters still would display as question marks in MSVB6 Resource Editor, but would display correctly on a computer with appropriate locale after I built the resource DLLs through MSVB6.

但是,如果我通过将字符粘贴到资源黑客http://www.angusj.com/resourcehacker中将字符添加到资源文件中,字符仍会在MSVB6资源编辑器中显示为问号,但会在具有问题的计算机上正确显示我通过MSVB6构建资源DLL后适当的语言环境。

One can make resource DLLs for each of several languages and use Microsoft's GetUserDefaultLCID or GetUserDefaultLocaleName to decide which to load.

可以为多种语言中的每种语言创建资源DLL,并使用Microsoft的GetUserDefaultLCID或GetUserDefaultLocaleName来决定加载哪些语言。