Using Unicode in
Visual Basic 6.0
Updated 13-August-2018 03:22

Special thanks to our viewers.
Webalizer statistics averages 1043 visits per day.

"Welcome" in 28 languages

ARA: مـرحبــاً ETH: እንኳን ደህና መጣህ JPN: ようこそ PTB: Bem-vindo
ARM: ԱԲԳԴԵԶԷԸԹ GEO: სასურველი KAZ: Қош келдіңіз PUN: ਜੀ ਆਇਆਂ ਨੂੰ
BGR: Добре дошли GER: Willkommen KHM: សូម​ស្វាគមន៍ RUS: Добро пожаловать
CHS: 欢迎 GRK: Καλώς ήλθατε KOR: 여보세요 TAM: அங்கிகரி
CHT: 歡迎 HEB: ברוכים הבאים LAO: ຍິນດີຕ້ອນຮັບ THA: การต้อนรับ
ENG: Welcome HIN: रवागत MMR: ြကိုဆိုြခင်း။ URD: स्वागत
ERI: መርሓባ HUN: Üdvözlet PHL: Maligayang pagdating VIE: tính từ
  • Copyright © 2003 - 2018 Dana Seaman - www.CyberActivex.com www.toolboxw.com
    Unicode and the Unicode Logo are trademarks of Unicode, Inc.
    Microsoft and Visual Basic are trademarks of Microsoft Corporation

  • This is a work in progress so expect to see updates often.
  • Send comments, suggestions, corrections, or contribute Unicode Vb source code to:
  • Please note that we have moved to new host providers on 06-July-2018.
    Please contact us if you find any broken links at


Product Unicode Replacements for
Visual Basic 6.0 ANSI Controls
Please Visit Website www.ToolBoxW.com
3ª Geração (2018)
Migration Wizard
8 Windowless Controls.
Compatible with Windows Vista/7/8/10.
No time limits in IDE.
Lifetime License. Free upgrades (including Major).
No Distribution Royalties.
$149.85 (Single Developer).







01 Introduction 21 ClipBoard 41 SurrogatePairs 61 Where's the Beef (Unicode) 81 Version Info 101 Remove Diacritics 19-Jul-2018
02 Flowchart 22 Unicode Blocks 42 DateTime 62 DoubleUnicode 82 FileVersionInfo 102 Virtual List (Group) 09-Aug-2018
03 Character Sets 23 DrawText Align Flags 43 FileIO 63 UniMsgBox 83 Windows 10 103 DataBndingInkEdit 07-Aug-2018
04 SBCS-DBCS 24 RTL(RightToLeft, Mirroring) 44 VbAccelerator
64 VarPtr for API UDT 84 File Reader 104 DataBindingToolBoxW 13-Aug-2018
05 Test Strings(Unicode)
Updated 13-Aug-2018
25 Hints 45 Registry 65 INI File 85 Numeric TextBox 105  
06 Platforms 26 Why use a Type Library? 46 Win98 66 Crypto 86 FSO Replacement 106  
07 LocaleLCID 27 Chinese GB18030 Support 47 MapString 67 Crypto Enumerations 87 Keyboard Layouts 107  
08 Codepage 28 PropertyBag 19-Jun-2018 48 Byte Array 68 Cloud 88 Enumerate Locales 108  
09 Fonts 29 PropertyBag-UTF8 49 Vb Get/Put (UDTs) 69 Huge Files 89 DirW 109  
10 Uniscribe 30 Property Pages 50 IStream 70 Font Fallback/Linking 90 Wrapper RichTextbox 110  
11 Mlang 31 Input Methods 51 Calendars 71 UniToolKit 27-Mar-2018 91 IsAlpha, IsNumeric 111  
12 RichEdit 32 Resource Files 52 Sorting 72 vbRichClient 11-Jul-2018 92 Ocx Template 112  
13 MSLU 33 Satellite DLL 53 Subclassing 73 Crypto Unicode 25-Jul-2018 93 vbAccelerator Listview 113  
14 GDI+ 34 XP Themes 54 FileNames Drop/Paste 74 Capicom 94 vbAccelerator Treeview 114  
15 User Controls
Owner/Custom Draw
35 Menus 55 Printing 75 EditContextMenu 95 TitleCase(ProperCase)  04-Oct-2017  115  
16 Custom Control Example 36 Database 56 References 76 SlidingCompass 96 ucCalendar 04-Oct-2017 116  
17 Unicode Aware Controls 37 Grid Controls 57 Links 77 RegistrationFreeCom 15-Sep-2017 97 ucMDITabs 04-Oct-2017 117  
18 Convert Utf8 - Utf16 38 Misc Source Code 58 Troubleshooting 78 VbMenuUnicode 98 ucRichEdit  21-Jul-2018 118  
19 Export UTF-8 Example 39 IsUnicode 59 Vb6 on non-English Machines 79 CreatePopMenu 99 Get/Let UnicodeText  18-Apr-2018 119  
20 Export To File 40 IdeographicDescChar 60 FarEast on English Machine
NJSTAR Communicator)
80 OnScreenKeyboard 25-Sep-2017 100 Virtual Combo 24-Jul-2018 120  




Although Visual Basic 6.0 stores strings internally as Unicode(UTF-16) it has several limitations:

  1. Ships with ANSI only controls (Label, Textbox, etc.).
  2. Properties Window in IDE is ANSI only. Unicode strings are displayed as '????'
  3. PropertyBag automatically converts Unicode strings to ANSI.
  4. Clipboard functions are ANSI only.
  5. Menus are ANSI only.

The purpose of this tutorial is to resolve these issues and provide working VB code solutions. The level of difficulty of these solutions vary but in general require intimate knowledge of ActiveX Controls and Classes.
Subclassing and API programming are a must to gain functionality that Vb does not directly support.

The amount of information gathered during development of Unicode aware controls was so overwhelming that it made sense to organize it and this Tutorial proved to be an ideal place to bring eveything together under one roof.

Tutorial Development Tools
Microsoft® Frontpage® 2003  
Microsoft® Platform SDK
Feb 2007 Edition for Vista
Visual Basic 6.0 - Service Pack 6


Note: Dates in this tutorial are displayed as dd-mmm-yyyy (Example: 11-Mar-2004) to eliminate any ambiguities in other Locales.

*  These issues are resolved in Vb.Net although you will have to go through a learning curve to get up to speed with the language.
    Review these tables to determine the minimum system requirements:

  1. System Requirements Visual Basic .NET 2003 Standard.
  2. System Requirements Visual Studio .NET 2003.




This flowchart shows basic program flow of:

  1. Send ANSI/DBCS text to ANSI Controls or ANSI API.
  2. Send Unicode text to Unicode Controls
  3. Send Unicode text to ANSI/Unicode API using MSLU.
  4. Convert UTF8 to Unicode.
  5. Convert ANSI/DBCS to Unicode.
  6. Get Charset/Codepage from LCID.





Character Sets


Character Set Range Codepage Byte
OEM (DOS) 0..255 437 OEM - United States None
ANSI (Windows) 0..255 1252 ANSI - Latin I
etc. See SBCS-DBCS
EBCDIC (Mainframe) 0..255 1047 IBM EBCDIC - Latin 1/Open System  
Unicode Hex
Unicode Dec
0..7F 0..127 1
80..7FF 128..2047 2
800..FFFF 2048..65535 3


UTF-16LE (little endian, low byte first, x86 Processor and Microsoft Windows) 0..65535(FFFF) - 2 bytes 1200 FF FE
UTF-16BE (big endian, high byte first, PowerPC Processor and Mac OS) 0..65535(FFFF) - 2 bytes 1201 FE FF
UTF-32LE (little endian, low byte first) 0..10FFFF - 4 bytes 12000 FF FE 00 00
UTF-32BE (big endian, high byte first) 0..10FFFF - 4 bytes 12001 00 00 FE FF
DBCS - Double-Byte Character Set 0..65535(FFFF) - 2 bytes
Chars 0-127 are 1 byte
See DBCS  

Note: You should have a utility on your system called CharMap.Exe which will allow you to browse and select Unicode characters.




SBCS(Single-Byte) and DBCS(Double-Byte) Character Sets are different character sets from Unicode.


Character codes for "A" in ANSI, Unicode, and DBCS

ANSI Character "A" &H41


Unicode character "A" &H41 &H00 A
DBCS character that represents a Japanese wide-width "A" &H82 &H60  
Unicode wide-width "A" &H21 &HFF

CharSet from Platform SDK wingdi.h

Font Character Sets


Name Info
0 ANSI_CHARSET West, Occidental(United States, Western Europe)
2 SYMBOL_CHARSET Standard symbol charset
77 MAC_CHARSET Macintosh
128 * SHIFTJIS_CHARSET Shift-JIS (Japanese Industry Standard)
129 * HANGEUL_CHARSET Korea (Wansung)
129 * HANGUL_CHARSET Korea (Wansung)
130 *  JOHAB_CHARSET Korea (Johab)
134 * GB2312_CHARSET Simplified Chinese - Mainland China(PRC) and Singapore
136 * CHINESEBIG5_CHARSET Traditional Chinese - Taiwan and Hong Kong
204 RUSSIAN_CHARSET Cyrillic - Russia, Belarus, Ukraine and some other slavic countries.

* DBCS - Double-Byte Character Set

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:

Option Explicit

Private Sub Form_Load()
   Dim sUni As String
   Dim sMBCS As String
   Dim b() As Byte
   Dim i As Long

   sUni = "2006" & ChrW$(&H6B22) & "9" & ChrW$(&H8FCE) & "12" & ChrW$(&H6B22) & " 8:04"
   UniTextBoxEx1 = sUni
   b = StrConv(sUni, vbFromUnicode, 2052)
   sMBCS = StrConv(sUni, vbFromUnicode, 2052)
   Debug.Print sUni, sMBCS
   Text1 = sMBCS
   For i = 0 To UBound(b)
      Debug.Print b(i)
   sUni = StrConv(b, vbUnicode, 2052)
   UniTextBoxEx2 = sUni
End Sub
UniTextBox1, UniTextBox2:
2006欢9迎12欢 8:04
Debug Window:
50 ' 2
48 ' 0
48 ' 0
54 ' 6
187 '
182 ' 欢
57 ' 9
211 '
173 ' 迎
49 ' 1
50 ' 2
187 '
182 ' 欢
32 ' space
56 ' 8
58 ' :
48 ' 0
52 ' 4



The following demos shows how to display Chinese on an English-U.S. system without changing your Regional settings 

Example of VbTextBox using DBCS Charset 134, CHINESE_GB2312


Example of Vb ListView using DBCS Charset 134, CHINESE_GB2312


See MSDN for more information about DBCS:
Issues Specific to the Double-Byte Character Set (DBCS)
ANSI, DBCS, and Unicode: Definitions
Calling Windows API Functions
DBCS Sort Order and String Comparison
DBCS String Manipulation Functions
DBCS-Enabled KeyPress Event
Designing an International-Aware User Interface
Font, Display and Print Considerations in a DBCS Environment
Identifiers in a DBCS Environment
Processing Files That Use Double-Byte Characters

DBCS String Conversion

StrConv Function

The global options of the StrConv function are converting uppercase to lowercase, and vice versa. In addition to those options, the function has several DBCS-specific options. For example, you can convert narrow letters to wide letters by specifying vbWide in the second argument of this function. You can convert one character type to another, such as hiragana to katakana in Japanese. StrConv enables you to specify a LocaleID for the string, if different than the system's LocaleID.

You can also use the StrConv function to convert Unicode characters to ANSI/DBCS characters, and vice versa. Usually, a string in Visual Basic consists of Unicode characters. When you need to handle strings in ANSI/DBCS (for example, to calculate the number of bytes in a string before writing the string into a file), you can use this functionality of the StrConv function.



Test Strings(Unicode)

The easiest way to add Unicode test strings to your project is to make a resource file with a Unicode aware text editor and compile it with RC.exe.
That way you can test your controls using LoadResString(ResourceID).
Use Notepad + "SaveAs" and select Unicode. The file will be saved as UTF-16.




"Welcome" in 28 languages

Country Flag Resource
UTF-16 Unicode
UTF-8 Encoded
Saudi Arabia

90 ARA: مـرحبــاً 150 ARA: مـرحبــاً 121 Saudi Arabia|Riyadh|Arabic

91 ARM: ԱԲԳԴԵԶԷԸԹ 151 ARM: Ô±Ô²Ô³Ô´ÔµÔ¶Ô·Ô¸Ô¹ 122 Armenia|Yerevan|Armenian
Bulgaria 92 BGR: Добре дошли 152 BGR: Добре дошли 123 Bulgaria|Sofia|Bulgarian
China 93 CHS: 欢迎 153 CHS: 欢迎 124 China|Beijing|Chinese Simplified
Taiwan 94 CHT: 歡迎 154 CHT: æ­¡è¿Ž 125 Taiwan|Taipei|Chinese Traditional
United States 95 ENG: Welcome 155 ENG: Welcome 126 United States|Washington DC|English
Eritrea 96 ERI: መርሓባ 156 ERI: መርሓባ 127 Eritrea|Asmara|Tigrinya
Ethiopia 97 ETH: እንኳን ደህና መጣህ 157 ETH: እንኳን ደህና መጣህ 128 Ethiopia|Addis Ababa|Amharic
Georgia 98 GEO: სასურველი 158 GEO: სáƒ?სურველი 129 Georgia|Tbilisi|Georgian
Germany 99 GER: Umlaute ÄÏÖ 159 GER: Umlaute ÄÏÖ 130 Germany|Berlin|German
Greece 100 GRK: Καλώς ήλθατε 160 GRK: Καλώς ήλθατε 131 Greece|Athens|Greek
Israel 101 HEB: ברוכים הבאים 161 HEB: ברוכי×? הב×?×™×? 132 Israel|Jerusalem|Hebrew
India 102 HIN: रवागत 162 HIN: रवागत 133 India|New Delhi|Hindi
Hungary 103 HUN: Üdvözlet 163 HUN: Ãœdvözlet 134 Hungary|Budapest|Hungarian
Japan 104 JPN: ようこそ 164 JPN: よã?†ã?“ã?? 135 Japan|Tokyo|Japanese
Kazakhstan 105 KAZ: Қош келдіңіз 165 KAZ: Қош келдіңіз 136 Kazakhstan|Astana|Kazakh
Cambodia 106 KHM: សូម​ស្វាគមន៍ 166 KHM: សូម​ស្វាគមនáŸ? 137 Cambodia|Phnom Penh|Khmer
South Korea 107 KOR: 여보세요 167 KOR: 여보세요 138 South Korea|Seoul|Korean
Laos 108 LAO: ຍິນດີຕ້ອນຮັບ 168 LAO: àº?ິນດີຕ້ອນຮັບ 139 Laos|Vientianev|Lao
Myanmar 109 MMR: ြကိုဆိုြခင်း။ 169 MMR: ြကိုဆိုြá€?င်းá?‹ 140 Myanmar|Naypyidaw|Burmese
Philippines 110 PHL: Maligayang pagdating 170 PHL: Maligayang pagdating 141 Philippines|Manila|Filipino
Brazil 111 PTB: Bem-vindo 171 PTB: Bem-vindo 142 Brazil|Brasilia|Portuguese(BR)
Pakistan 112 PUN: ਜੀ ਆਇਆਂ ਨੂੰ 172 PUN: ਜੀ ਆਇਆਂ ਨੂੰ 143 Pakistan|Islamabad|Punjabi
Russian Federation 113 RUS: Добро пожаловать 173 RUS: Добро пожаловать 144 Russian Federation|Moscow|Russian
India 114 TAM: அங்கிகரி 174 TAM: à®…à®™à¯?கிகரி 145 India|New Delhi|Tamil
Thailand 115 THA: การต้อนรับ 175 THA: à¸?ารต้อนรับ 146 Thailand|Bangkok|Thai
Pakistan 116 URD: स्वागत 176 URD: सà¥?वागत 147 Pakistan|Islamabad|Urdu
Vietnam 117 VIE: tính từ 177 VIE: tính từ 148 Vietnam|Hanoi|Vietnamese


"Hello" in several languages

Language "Hello"
UTF-16 Unicode
UTF-8 Encoded
Arabic السلام عليكم السلام عليكم
Bengali (বাঙ্লা) ষাগতোম ষাগতোম
* Burmese မ္ရန္မာ (မ္ရန္မာ)
Cantonese (粵語,廣東話) 早晨, 你好  æ—©æ™¨, 你好
* Cherokee (á£áŽ³áŽ©)ᎣᏏᏲ ᎣᏏᏲ Ꭳáá²
Chinese (中文,普通话,汉语) 你好 你好
Czech (česky) Dobrý den Dobrý den
Danish (Dansk) Hej, Goddag Hej, Goddag
English Hello Hello
Esperanto Saluton Saluton
Estonian Tere, Tervist Tere, Tervist
Finnish (Suomi) Hei Hei
French (Français) Bonjour, Salut Bonjour, Salut
German (Deutsch Nord) Guten Tag Guten Tag
German (Deutsch Süd) Grüß Gott Grüß Gott
Georgian (ქართველი) გამარჯობა გáƒáƒ›áƒáƒ áƒ¯áƒáƒ‘áƒ
Gujarati (ગુજરાતિ) (ગà«àªœàª°àª¾àª¤àª¿)
Greek (Ελληνικά) Γειά σας Γειά σας
Hebrew שלום שלו×
Hindi नमस्ते, नमस्कार। नमसà¥à¤¤à¥‡, नमसà¥à¤•à¤¾à¤°à¥¤
Italiano Ciao, Buon giorno Ciao, Buon giorno
Japanese (日本語) こんにちは, コンニチハ ã“ã‚“ã«ã¡ã¯, コï¾ï¾†ï¾ï¾Š
Korean (한글) 안녕하세요, 안녕하십니까 안녕하세요, 안녕하십니까
Maltese Ċaw, Saħħa ÄŠaw, Saħħa
Nederlands (Vlaams) Hallo, Dag Hallo, Dag Hallo, Dag Hallo, Dag    
Norwegian (Norsk) Hei, God dag Hei, God dag
Punjabi (ਪੁਂਜਾਬਿ) (ਪà©à¨‚ਜਾਬਿ)
Polish Dzień dobry, Hej DzieÅ„ dobry, Hej
Russian (Русский) Здравствуйте! ЗдравÑтвуйте!
Slovak Dobrý deň Dobrý deň
Spanish (Español) ‎¡Hola!‎ ‎¡Hola!‎
Swedish (Svenska) Hej, Goddag Hej, Goddag
Thai (ภาษาไทย) สวัสดีครับ, สวัสดีค่ะ สวัสดีครับ, สวัสดีค่ะ
Tamil (தமிழ்) வணக்கம் வணகà¯à®•à®®à¯
Turkish (Türkçe) Merhaba Merhaba
Vietnamese (Tiếng Việt) Xin Chào Xin Chào
Yiddish â€(ײַדישע) דאָס הײַזעלע ד×ָס הײַזעלע

These Vb Strings can be pasted into the IDE to set Captions or Text:

Flag   Sample Output Vb String

  ARA: مـرحب "ARA: " & ChrW$(&H645) & ChrW$(&H640) & ChrW$(&H631) & ChrW$(&H62D) & ChrW$(&H628)

  ARM: ԱԲԳԴԵԶԷԸԹ "ARM: " & ChrW$(&H531) & ChrW$(&H532) & ChrW$(&H533) & ChrW$(&H534) & ChrW$(&H535) & ChrW$(&H536) & ChrW$(&H537) & ChrW$(&H538) & ChrW$(&H539)
  BGR: Добре дошли "BGR: " & ChrW$(&H414) & ChrW$(&H43E) & ChrW$(&H431) & ChrW$(&H440) & ChrW$(&H435) & " " & ChrW$(&H434) & ChrW$(&H43E) & ChrW$(&H448) & ChrW$(&H43B) & ChrW$(&H438)
  CHS: 欢迎 "CHS: " & ChrW$(&H6B22) & ChrW$(&H8FCE)
  CHT: 歡迎 "CHT: " & ChrW$(&H6B61) & ChrW$(&H8FCE)
  ENG: Welcome "ENG: Welcome"
  ERI: መርሓባ "ERI: " & ChrW$(&H1218) & ChrW$(&H122D) & ChrW$(&H1213) & ChrW$(&H1263)
  ETH: እንኳን ደህና መጣህ "ETH: " & ChrW$(&H12A5) & ChrW$(&H1295) & ChrW$(&H12B3) & ChrW$(&H1295) & " " & ChrW$(&H12F0) & ChrW$(&H1205) & ChrW$(&H1293) & " " & ChrW$(&H1218) & ChrW$(&H1323) & ChrW$(&H1205)
  GEO: სასურველი "GEO: " & ChrW$(&H10E1) & ChrW$(&H10D0) & ChrW$(&H10E1) & ChrW$(&H10E3) & ChrW$(&H10E0) & ChrW$(&H10D5) & ChrW$(&H10D4) & ChrW$(&H10DA) & ChrW$(&H10D8)
  GER: Willkommen "GER: Willkommen"
  GRK: Καλώς ήλθατε "GRK: " & ChrW$(&H39A) & ChrW$(&H3B1) & ChrW$(&H3BB) & ChrW$(&H3CE) & ChrW$(&H3C2) & " " & ChrW$(&H3AE) & ChrW$(&H3BB) & ChrW$(&H3B8) & ChrW$(&H3B1) & ChrW$(&H3C4) & ChrW$(&H3B5)
  HEB: ברוכים הבאים "HEB: " & ChrW$(&H5D1) & ChrW$(&H5E8) & ChrW$(&H5D5) & ChrW$(&H5DB) & ChrW$(&H5D9) & ChrW$(&H5DD) & " " & ChrW$(&H5D4) & ChrW$(&H5D1) & ChrW$(&H5D0) & ChrW$(&H5D9) & ChrW$(&H5DD)
  HIN: रवागत "HIN: " & ChrW$(&H930) & ChrW$(&H935) & ChrW$(&H93E) & ChrW$(&H917) & ChrW$(&H924)
  HUN: Üdvözlet "HUN: Üdvözlet"
  JPN: ようこそ "JPN: " & ChrW$(&H3088) & ChrW$(&H3046) & ChrW$(&H3053) & ChrW$(&H305D)
  KAZ: Қош келдіңіз "KAZ: " & ChrW$(&H49A) & ChrW$(&H43E) & ChrW$(&H448) & " " & ChrW$(&H43A) & ChrW$(&H435) & ChrW$(&H43B) & ChrW$(&H434) & ChrW$(&H456) & ChrW$(&H4A3) & ChrW$(&H456) & ChrW$(&H437)
  KHM: សូម​ស្វាគមន៍ "KHM: " & ChrW$(&H179F) & ChrW$(&H17BC) & ChrW$(&H1798) & ChrW$(&H200B) & ChrW$(&H179F) & ChrW$(&H17D2) & ChrW$(&H179C) & ChrW$(&H17B6) & ChrW$(&H1782) & ChrW$(&H1798) & ChrW$(&H1793) & ChrW$(&H17CD)
  KOR: 여보세요 "KOR: " & ChrW$(&HC5EC) & ChrW$(&HBCF4) & ChrW$(&HC138) & ChrW$(&HC694)
  LAO: ຍິນດີຕ້ອນຮັບ "LAO: " & ChrW$(&HE8D) & ChrW$(&HEB4) & ChrW$(&HE99) & ChrW$(&HE94) & ChrW$(&HEB5) & ChrW$(&HE95) & ChrW$(&HEC9) & ChrW$(&HEAD) & ChrW$(&HE99) & ChrW$(&HEAE) & ChrW$(&HEB1) & ChrW$(&HE9A)
  MMR: ြကိုဆိုြခင်း။ "MMR: " & ChrW$(&H103C) & ChrW$(&H1000) & ChrW$(&H102D) & ChrW$(&H102F) & ChrW$(&H1006) & ChrW$(&H102D) & ChrW$(&H102F) & ChrW$(&H103C) & ChrW$(&H1001) & ChrW$(&H1004) & ChrW$(&H103A) & ChrW$(&H1038) & ChrW$(&H104B)
  PHL: Maligayang pagdating "PHL: Maligayang pagdating"
  PTB: Bem-vindo "PTB: Bem-vindo"
  PUN: ਜੀ ਆਇਆਂ ਨੂੰ "PAN: " & ChrW$(&HA1C) & ChrW$(&HA40) & " " & ChrW$(&HA06) & ChrW$(&HA07) & ChrW$(&HA06) & ChrW$(&HA02) & " " & ChrW$(&HA28) & ChrW$(&HA42) & ChrW$(&HA70)
  RUS: Добро пожаловать "RUS: " & ChrW$(&H414) & ChrW$(&H43E) & ChrW$(&H431) & ChrW$(&H440) & ChrW$(&H43E) & " " & ChrW$(&H43F) & ChrW$(&H43E) & ChrW$(&H436) & ChrW$(&H430) & ChrW$(&H43B) & ChrW$(&H43E) & ChrW$(&H432) & ChrW$(&H430) & ChrW$(&H442) & ChrW$(&H44C)
  TAM: அங்கிகரி "TAM: " & ChrW$(&HB85) & ChrW$(&HB99) & ChrW$(&HBCD) & ChrW$(&HB95) & ChrW$(&HBBF) & ChrW$(&HB95) & ChrW$(&HBB0) & ChrW$(&HBBF)
  THA: การต้อนรับ "THA: " & ChrW$(&HE01) & ChrW$(&HE32) & ChrW$(&HE23) & ChrW$(&HE15) & ChrW$(&HE49) & ChrW$(&HE2D) & ChrW$(&HE19) & ChrW$(&HE23) & ChrW$(&HE31) & ChrW$(&HE1A)
  URD: स्वागत "URD: " & ChrW$(&H938) & ChrW$(&H94D) & ChrW$(&H935) & ChrW$(&H93E) & ChrW$(&H917) & ChrW$(&H924)
  VIE: tính từ "VIE: tính t" & ChrW$(&H1EEB)

Note: Under the hood StrConv inserts a BOM (FEFF) before the CJK Unified Ideographs.

More stuff to play with:

Sample Font.Name Font.Charset String
1 English Tahoma ANSI_CHARSET "English"
2 româneşte " EASTEUROPE_CHARSET ChrW$(114) & ChrW$(111) & ChrW$(109) & ChrW$(226) & ChrW$(110) & ChrW$(101) & ChrW$(351) & ChrW$(116) & ChrW$(101)
3 ภาษาไทย
" THAI_CHARSET ChrW$(3616) & ChrW$(3634) & ChrW$(3625) & ChrW$(3634) & ChrW$(3652) & ChrW$(3607) & ChrW$(3618)
4 Հայերեն Arial Unicode MS   ChrW$(1344) & ChrW$(1377) & ChrW$(1397) & ChrW$(1381) & ChrW$(1408) & ChrW$(1381) & ChrW$(1398)
5 Tiếng Việt


VIETNAMESE_CHARSET ChrW$(84) & ChrW$(105) & ChrW$(234) & ChrW$(769) & ChrW$(110) & ChrW$(103) & ChrW$(32) & ChrW$(86) & ChrW$(105) & ChrW$(234) & ChrW$(803) & ChrW$(116)
6 עברית


HEBREW_CHARSET ChrW$(1506) & ChrW$(1489) & ChrW$(1512) & ChrW$(1497) & ChrW$(1514)
7 मराठी Arial Unicode MS   ChrW$(2350) & ChrW$(2352) & ChrW$(2366) & ChrW$(2336) & ChrW$(2368)
8 中文 (台灣) PMingLiU CHINESEBIG5_CHARSET ChrW$(20013) & ChrW$(25991) & " (" & ChrW$(21488) & ChrW$(28771) & ")")
9 नेपाली Arial Unicode MS   ChrW$(2344) & ChrW$(2375) & ChrW$(2346) & ChrW$(2366) & ChrW$(2354) & ChrW$(2368)
10 Русский


RUSSIAN_CHARSET ChrW$(1056) & ChrW$(1091) & ChrW$(1089) & ChrW$(1089) & ChrW$(1082) & ChrW$(1080) & ChrW$(1081)
11 ირუკსაბ Arial Unicode MS   StrReverse(ChrW$(4305) & ChrW$(4304) & ChrW$(4321) & ChrW$(4313) & ChrW$(4323) & ChrW$(4320) & ChrW$(4312))
12 日本語 Arial Unicode MS SHIFTJIS_CHARSET ChrW$(26085) & ChrW$(26412) & ChrW$(-30050)
13 ଉଡିଯା Arial Unicode MS   ChrW$(2825) & ChrW$(2849) & ChrW$(2879) & ChrW$(2863) & ChrW$(2878)
14 Ελληνικά


GREEK_CHARSET ChrW$(917) & ChrW$(955) & ChrW$(955) & ChrW$(951) & ChrW$(957) & ChrW$(953) & ChrW$(954) & ChrW$(940)
15 हिन्दी
Arial Unicode MS   ChrW$(2361) & ChrW$(2367) & ChrW$(2344) & ChrW$(2381) & ChrW$(2342) & ChrW$(2368)
16 한국어 GulimChe HANGEUL_CHARSET ChrW$(-10916) & ChrW$(-21139) & ChrW$(-14924)
17 తెలుగు Arial Unicode MS   ChrW$(3108) & ChrW$(3142) & ChrW$(3122) & ChrW$(3137) & ChrW$(3095) & ChrW$(3137
18 Čeština


EASTEUROPE_CHARSET ChrW$(268) & ChrW$(101) & ChrW$(353) & ChrW$(116) & ChrW$(105) & ChrW$(110) & ChrW$(97)
19 ಕನ್ನಡ Arial Unicode MS   ChrW$(3221) & ChrW$(3240) & ChrW$(3277) & ChrW$(3240) & ChrW$(3233)
20 中文(中国) SimSun GB2312_CHARSET ChrW$(20013) & ChrW$(25991) & "(" & ChrW$(20013) & ChrW$(22269) & ")")
21 ગુજરાતી Arial Unicode MS   ChrW$(2711) & ChrW$(2753) & ChrW$(2716) & ChrW$(2736) & ChrW$(2750) & ChrW$(2724) & ChrW$(2752)
22 Türkçe


TURKISH_CHARSET ChrW$(84) & ChrW$(252) & ChrW$(114) & ChrW$(107) & ChrW$(231) & ChrW$(101)
23 தமிழ்
Arial Unicode MS   ChrW$(2980) & ChrW$(2990) & ChrW$(3007) & ChrW$(2996) & ChrW$(3021)









Additional Requirements

 Vb5/6 Yes. Uses Unicode to store and manipulate strings.     Instrinsic controls, Properties Window(IDE), Clipboard, and PropertyBag are ANSI only.
 NT/2000/XP/Vista/Win7/Win8/Win10 Yes. Uses Unicode to store and manipulate strings. Uses Unicode:
DrawTextW Lib "user32" - TextOutW Lib "gdi32"
Installed. You may need to enable Far East language support via Control Panel, Regional Options, Languages if it was not done so at install time. None

No. Uses ANSI or * DBCS to store and manipulate strings.

Uses ANSI:
DrawTextA Lib "user32" - TextOutA Lib "gdi32"or DrawTextW Lib "Unicows"
TextOutW Lib "Unicows"
You need to install at least one Unicode font. Arial MS Unicode used to be a free(23Mb) download from Microsoft. It is installed automatically with Office XP Pro or Frontpage 2003. Microsoft Layer for Unicode on Win9x Systems (MSLU). Unicows.DLL (269.7kb download) available free from Microsoft.
The current FileVersion is "1.0.4018.0" April 21, 2003.
Automation 95/98/ME & NT/2000/XP/Vista Yes. Uses Unicode to pass the strings back and forth.      

XP now supports a total of 136 locales, which includes the 126 locales supported by Windows 2000 and adds the following:

Other international features New to XP:

New Locales in Windows XP Service Pack 2

Windows XP Service Pack 2 introduces 25 additional locales and another 11 with Service Pack 2 Update:

Windows XP Service Pack 2 Locales

Bengali (India)

Quechua (Bolivia)

Sami, Northern (Sweden)

Bosnian (Latin, Bosnia and Herzegovina)

Quechua (Ecuador)

Sami, Skolt (Finland)

Croatian (Latin, Bosnia and Herzegovina)

Quechua (Peru)

Sami, Southern (Norway)

isiXhosa (South Africa) Sami

Sami, Inari (Finland)

Sami, Southern (Sweden)

isiZulu (South Africa)

Sami, Lule (Norway)

Serbian (Cyrillic, Bosnia and Herzegovina)

Malayalam (India)

Sami, Lule (Sweden)

Serbian (Latin, Bosnia and Herzegovina)

Maltese (Malta) Sami

Sami, Northern (Finland)

Sesotho sa Leboa (South Africa)

Maori (New Zealand)

Sami, Northern (Norway)

Setswana (South Africa)



Welsh (United Kingdom)

Windows XP Service Pack 2 Update Locales

Bosnian (Cyrillic, Bosnia and Herzegovina)

Irish (Ireland)

Nepali (Nepal)

Filipino (Philippines)

Luxembourgish (Luxembourg)

Pashto (Afghanistan)

Frisian (Netherlands)

Mapudungun (Chile)

Romansh (Switzerland)

Inuktitut (Latin, Canada)

Mohawk (Mohawk)


Windows Vista New locales

Alsatian (France) Hausa (Latin, Nigeria) Spanish (United States)
Amharic (Ethiopia) Igbo (Nigeria) Tajik (Cyrillic, Tajikistan)
Assamese (India) Inuktitut (Syllabics, Canada) Tamazight (Latin, Algeria)
Bashkir (Russia) Khmer (Cambodia) Tibetan (PRC)

Bengali (Bangladesh)

K'iche (Guatemala)

Turkmen (Turkmenistan)

Breton (France)

Kinyarwanda (Rwanda)

Uighur (PRC)

Corsican (France)

Lao (Lao P.D.R.)

Upper Sorbian (Germany)

Dari (Afghanistan)

Lower Sorbian (Germany)

Wolof (Senegal)

English (India)

Mongolian (Traditional Mongolian, PRC)

Yakut (Russia)

English (Malaysia)

Occitan (France)

Yi (PRC)

English (Singapore)

Oriya (India)

Yoruba (Nigeria)

Greenlandic (Greenland)

Sinhala (Sri Lanka)


These locales are automatically installed when you update Windows XP to SP2. You can select new locales in Regional and Language Options. They are not supported in Windows Server 2003.




International Locale Codes

Click Icon to your left to Load Table.
 Please Wait...

Win 10 v 180310.0.17134.165 28-Jul-2018  258 Locales Download utility to get a current list of installled locales here:
Enumerate Locales


Unicode Only LCIDs

Identifier Language Platform
0x042b  Armenian 2000/XP
0x0465  Divehi XP
0x0437  Georgian 2000/XP
0x0447  Gujarati XP
0x0439  Hindi 2000/XP
0x044b  Kannada XP
0x0457  Konkani 2000/XP
0x044e  Marathi 2000/XP
0x0446  Punjabi XP
0x044f  Sanskrit 2000/XP
0x045a  Syriac XP
0x0449  Tamil 2000/XP
0x044a  Telugu XP



Related resources




Also see Table above

Table of Known Code Pages

CP_ACP 0 WesternEuropean_Mac 10000 UserDefined 50000
CP_OEMCP 1 Japanese_Mac 10001 AutoSelect 50001
CP_MACCP 2 Arabic_Mac 10004 Japanese_JIS 50220
CP_THREAD_ACP 3 Greek_Mac 10006 Japanese_JIS_Allow1byteKana 50221
CP_SYMBOL 42 Cyrillic_Mac 10007 Japanese_JIS_Allow1byteKanaSOSI 50222
OEM_UnitedStates 437 Latin2_Mac 10029 Korean_ISO 50225
Arabic_ASMO708 708 Turkish_Mac 10081 Japanese_AutoSelect 50932


720 Chinese_Traditional_CNS 20000 Chinese_Simplified_AutoSelect 50936
Greek_DOS 737 Chinese_Traditional_Eten 20002 Korean_AutoSelect 50949
Baltic_DOS 775 WesternEuropean_IA5 20105 Chinese_Traditional_Auto_Select 50950
WesternEuropean_DOS 850 German_IA5 20106 Cyrillic_Auto_Select 51251
Central_European_DOS 852 Swedish_IA5 20107 Greek_AutoSelect 51253
Icelandic_DOS 861 Norwegian_IA5 20108 Arabic_AutoSelect 51256
Hebrew_DOS 862 US_ASCII 20127 Japanese_EUC 51932
Cyrillic_DOS 866 Cyrillic_KOI8R 20866 Chinese_Simplified_EUC 51936
Greek_DOS_Modern 869 Cyrillic_KOI8U 21866 Korean_EUC 51949
Thai_Windows 874 WesternEuropean_ISO 28591 Chinese_Simplified_HZ 52936
IBM_EBCDIC_GreekModern 875 Central_European_ISO 28592 CP_UTF7 65000 *
Japanese_ShiftJIS 932 * Baltic_ISO 28594 CP_UTF8 65001 *
Chinese_Simplified_GB2312 936 * Cyrillic_ISO 28595    
Korean 949 * Arabic_ISO 28596    
Chinese_Traditional_Big5 950 * Greek_ISO 28597    
Unicode 1200 Latin3_ISO 28593    
Unicode_BigEndian 1201 Hebrew_ISO_Visual 28598
Central_European_Windows 1250 Turkish_ISO 28599    
Cyrillic_Windows 1251 Latin9_ISO 28605    
WesternEuropean_Windows 1252 Europa 29001    
Greek_Windows 1253 Hebrew_ISO_Logical 38598    
Turkish_Windows 1254        
Hebrew_Windows 1255        
Arabic_Windows 1256        
Baltic_Windows 1257        
Vietnamese_Windows 1258        
Korean_Johab 1361        

* DBCS - Double-Byte Character Set
* This is a pseudo codepage. There is no corresponding NLS file. This code page ID can only be used with WideCharToMultiByte() and MultiByteToWideChar() API calls.




Fonts used on Windows XP-SP1:

Method API Parameter Font Name API Face Name
GetStockFont GetStockObject SYSTEM_FONT MS Sans Serif GetTextFace System
GetStockFont GetStockObject DEFAULT_GUI_FONT MS Sans Serif GetTextFace MS Shell Dlg
GetSysFontA SystemParametersInfo cf_Caption Arial    
GetSysFontA SystemParametersInfo cf_Menu Tahoma    
GetSysFontA SystemParametersInfo cf_Message Tahoma    
GetSysFontA SystemParametersInfo cf_SmallCaption Tahoma    
GetSysFontA SystemParametersInfo cf_Status Tahoma    

Win2000/XP/Office2000/Office2003 should already have Arial Unicode MS installed.
Win98 users will need a Unicode font to render Unicode glyphs.

Not redistributable.
Version Glyphs Size Comments
Arial Unicode MS 1.00 51,180 22.19 Mb Installed with Win2000/Office2000 or later.
Lucida Sans Unicode 2.00 1,776 316.4 kb  
Bitstream Cyberbit beta v2.0 29,934 13.04 Mb Complete - Download Font and DOC here.
Bitstream Cyberbase beta v2.0 1,249 302 kb No CJK - Download Font and DOC here.
Bitstream CyberCJK beta v2.0 28686 12.74 Mb CJK only - Download Font and DOC here.
Code2000 1.13 34,810 3.01 Mb Shareware. US$5.00. Download here.
TITUS Cyberbit Basic 2000; 3.0 9,568 1.82 Mb Non-Commercial use only.
UNICODE 4.0 compliant.
Download here.
Doulos SIL 4.010.2004   674 kb DoulosSIL4.0.10.zip.
Non-Commercial use only.
Ezra SIL
Hebrew Unicode
    3.20 Mb EzrSIL20.zip
Non-Commercial use only.

Also see Multilingual Unicode TrueType Fonts on the Internet.

Sample Font Support for several Languages
Test Platform WinXP-SP1

Sample Arial
Unicode MS
* Microsoft
Tahoma or Arial
* Microsoft
Sans Serif
ARA: مـرحبــاً
CHS: 欢迎
CHT: 歡迎
GEO: სასურველი
GRK: Καλώς ήλθατε
HEB: בִּרוּבִים חַבָּאִים
HIN: रवागत
JPN: よろてそ
KOR: 여보세요
PAN: ਜੀ ਆਇਆਂ ਨੂੰ
RUS: Добро пожаловать
TAM: 쏅얧주ø
THA: การต้อนรับ
URD: स्वागत
VIE: tính từ

Tahoma, Arial do not support all these languages but works due to Font Substitution.




Microsoft Layer for Unicode Technology(UNICOWS.DLL)

While you can make a separate programs for specific platforms it is often desirable to make one program that will work on all platforms. By using Microsoft Layer for Unicode Technology (Unicows.DLL, 240kb), a single executable can run on both NT-based and Win9x Platforms. In this case you can use DrawTextW or TextOutW Lib "Unicows" for all platforms.

  1. The Unicows.Dll forwards calls to the system API if you are running on NT, 2000, or XP platforms.

  2. MSLU does not support the display of characters that the system cannot display. Therefore do not expect to see Chinese under Win98 English even though you have installed a font that supports Chinese(Arial Unicode MS for example). For more info see Newsgroup microsoft.public.platformsdk.mslayerforunicode and http://trigeminal.com/usenet/usenet035.asp.

Use this conditional compilation directive to test your code with and without Unicows:

Under Project/Properties/Make set conditional compilation arguments to UNICOWS = -1 or UNICOWS = 0.


You may not need MSLU at all if your program uses only DrawText or TextOut. In this case you can simply wrap the ANSI and Wide versions into a Sub. Do not expect to see Unicode on Win9x platforms even if you are using a Unicode font such as Arial Unicode MS:

'Put this in your startup (Initialise,Sub Main, etc.)
   Dim m_bIsNt as Boolean
   ' Are we running NT?
   Dim lVer As Long
   lVer = GetVersion()
   m_bIsNt = ((lVer And &H80000000) = 0)

Public Sub pDrawText(ByVal hdc As Long, ByVal s As String, tR As RECT, ByVal lFlags As Long)
   Dim lPtr As Long
   If (m_bIsNt) Then
      lPtr = StrPtr(s)
      If Not (lPtr = 0) Then
         DrawTextW hdc, lPtr, -1, tR, lFlags
      End If
      DrawTextA hdc, s, -1, tR, lFlags
   End If
End Sub

Public Sub pTextOut(ByVal lhDC As Long, ByVal x As Long, ByVal y As Long, ByVal sText As String)
   Dim lPtr As Long
   If (m_bIsNt) Then
      lPtr = StrPtr(sText)
      If Not (lPtr = 0) Then
         TextOutW lhDC, x, y, lPtr, Len(sText)
      End If
      TextOutA lhDC, x, y, sText, Len(sText)
   End If
End Sub
Public Sub pGetTextExtentPoint32(ByVal hdc As Long, ByVal s As String, lpSize As SIZEAPI)
   Dim lPtr As Long
   If (m_bIsNt) Then
      lPtr = StrPtr(s)
      If Not (lPtr = 0) Then
         GetTextExtentPoint32W hdc, lPtr, Len(s), lpSize
      End If
      GetTextExtentPoint32A hdc, s, Len(s), lpSize
   End If
End Sub





Uniscribe Architecture


In 1999 Microsoft introduced Uniscribe, a Windows system-level component that could take advantage of OpenType fonts. Microsoft Windows 2000 and applications Internet Explorer 5 and Office 2000 were released with support for Uniscribe built in.

For Windows 2000 and later, supports the processing of complex scripts, that is, those scripts that need special processing to properly render them. It includes a subset of the features found in GDI+ in Windows 2000 and Windows XP. The rules governing the shaping and positioning of glyphs are specified and catalogued in The Unicode Standard: Worldwide Character Encoding, Version 2.0, Addison-Wesley Publishing Company.

A complex script has at least one of the following attributes:

You may wonder how WinXP displays Unicode correctly even when you haven't selected a Font which supports all the required characters.
"Font fallback: this mechanism, made available through Uniscribe (see section on Complex Scripts Support), provides a fallback font (or a default font) when dealing with complex scripts. If the selected font face does not include any glyphs for the complex script that is about to be displayed, Uniscribe selects a default hardcoded font for the given script. For example, if you have Hindi text and the font is Courier, then Uniscribe will use the Mangal font. This technique is internal to Uniscribe and developers can not add additional fonts to the list of fallback fonts."
Note: Set flags to SSA_FALLBACK

Uniscribe is installed with Internet Explorer 5.0 or later, MS Office, Win2000, WinXP. Here are some versions of Uniscribe I found (including one found on Win98SE):

usp10.dll FileVersion
Note: Not redistributable.
1.0163.1890.1   268,288 22-Sep-1998 23:04:38 Microsoft Systems Journal Nov 98
Download code here
1.0325.2180.1   315.152 30-Nov-1999 09:34:40 Found on Win98SE \Windows\System
Download from DLL World
1.0400.2411.1         Installed with Internet Explorer 6
1.0405.2415.1 (lab06_N.010104-1344) 325,120 06-Jan-2001 05:14:26 MS Office 10 common archives
1.0409.2600.1106 (xpsp1.020828-1920) 339,456 09-Sep-2002 21:05:43 XP-SP1 \Windows\System32
1.0420.2600.2180 (xpsp_sp2_rtm.040803-2158) 406,528 07-Dec-2005 14:38 XP-SP2 \Windows\System32
1.0453.3665.0 (private/Lab06_dev(paulnel).
397,312 06-Aug-2002 23:14:38 Microsoft VOLT users community
1.0471.4030.0 (main.030626-1414) 413,184 27-Jun-2003 10:24:14 Microsoft Office 2003


Best results in tests run on Win98SE has been with Uniscribe version 1.0405.2415.1. Microsoft Office 2003 version has not been tested yet.

A Vb wrapper for this library can be found in Internationalization with Visual Basic by Michael S. Kaplan. It comes with a CD containing sample sourcecode. The sample includes a Uniscribe-aware version of ExtTextOutW. More info here.

A more complex C++ example can be found at "Supporting Multilanguage Text Layout and Complex Scripts with Windows NT 5.0". Dont be mislead by 'Windows NT 5.0' in the title because this demo also works on Win98. More info here.

Logical characters: Display Plain Text and handle caret placement: Display Formatted Text and handle caret placement:

ARA: العربية

 العربية :ARA

  • ScriptGetCmap
  • ScriptStringAnalyse - Calls ScriptItemise, Shape, Place etc.
  • ScriptStringGetLogicalWidths - Returns logical widths for the entire line
  • ScriptStringXtoCP - Pixel position to character index
  • ScriptStringCPtoX - Character index to pixel position
  • ScriptString_pSize - Gets points to SIZE structure for the line
  • ScriptStringOut - Render line to device
  • ScriptStringFree - All analyses must be freed
  • ScriptItemize - Break string on script and direction boundaries
  • ScriptLayout - Bidi embedding level interpreter
  • ScriptShape - Unicode to glyph translation
  • ScriptPlace - Width and position generation
  • ScriptTextOut - Render to device
  • ScriptXtoCP - Pixel position to character index
  • ScriptCPtoX - Character index to pixel position
  • ScriptGetLogicalWidths - Generate widths in character order
  • ScriptBreak - Get line breaking flags

This sample has been update and can be found on the Microsoft® Platform SDK(August 2002 Edition, Windows XP SP1) if you have it installed under C:\Program Files\Microsoft SDK\Samples\winui\globaldev\CSSamp. You may encounter problems compiling this due to missing or outdated files.

File Copy From Copy To
60,270 bytes
Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include Microsoft Visual Studio\VC98\Include
6,622 bytes
Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include Microsoft Visual Studio\VC98\Include
81,839 bytes
Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include Microsoft SDK\Samples\winui\globaldev\CSSamp


To build an application that supports Unicode on all Platforms AND uses Uniscribe you could use something similar to this:

Public Sub pDrawText(ByVal hdc As Long, ByVal s As String, tR As RECT, ByVal lFlags As Long)
   Dim lPtr As Long
   If (IsNt) Then
      lPtr = StrPtr(s)
      If Not (lPtr = 0) Then
         DrawTextW hdc, lPtr, -1, tR, lFlags
      End If
      If (IsUnicode(s)) Then
         If (HasUniscribe) Then
            DrawTextU hdc, s, tR, lFlags 'Uniscribe Wrapper
            DrawTextM hdc, s, tR, lFlags 'MultiByte Wrapper
         End If
         DrawTextA hdc, s, -1, tR, lFlags
      End If
   End If
End Sub




Provides services for applications on international issues, including conversion between code pages, font linking, code page "guessing", line breaking, and more. Installed with Internet Explorer 5.5 or later.

The only Vb wrapper for this library I can find is here.



Provides a programming interface(control) for formatting text. This can be used in lieu of Fm20.Dll Unicode TextBox. No distribution issues and comes with source code.

Rich Edit
Unicode New DLL Win10 Xp - Sp1
Xp Me 2000 NT 98 95



2.0 Supports Unicode Riched20.dll   May be installed
3.0 Expanded support for complex scripts, partly due to Uniscribe. Riched20.dll  

Hyphenation, page rotation, and Text Services Framework (TSF) support. Msftedit.dll  
7.5   Msftedit.dll              

About Rich Edit Controls
Tutorial 33: RichEdit Control: Basics


Rich Edit Controls

Control Price Unicode Aware



vbAccelerator RichEdit control (164kb) Free http://www.vbaccelerator.com/codelib/richedit/richedit.htm Source code included
ctl_riched.msi (330Kb) Free


Source code included






GDI+ ships with Windows XP and 2000(SP3). You can also install it on other windows platforms(98 or later). It is a free download from Microsoft at gdiplus_dnld.exe. It is Unicode aware on all platforms and allows you to draw high quality Unicode antialiased text. There is also support for rotation, skewing, and text outlining(Logo style).


To use Unicode in Win98 you must install a Unicode font such as Arial Unicode MS.Complex glyphs such as Chinese will render in Win98SE English version even though the operating system doesn't support this via DrawTextW or TextOutW! How does it do this? GDI+ uses Uniscribe under the hood to render Unicode.

You can find more information on using GDI+ in Visual Basic here

Sample Vb source code, declares, and class wrapper. PlanetSourceCode Enter GDI+ in the search window at top of page.
Sample Vb source code and class wrapper. www.vbaccelerator.com  
GDI+ Type Library (GDIPlus.TLB) version 1.30
Updated Thursday, 02 Aug 2003 06:51:14 UTC
GDI+ Type Library This Type Library provides everything you need to start working with GDI+ in Visual Basic giving you direct access to the native GDI+ functions. The TLB only exposes the Native(Flat) exports from the GDI+ DLL and not the C++ class methods.

Note: Most examples you will find on the WEB use class wrappers which are geared to C++/.Net users. The Vb equivalent wrappers on PSC and VbAccelerator are not complete so you may want to stick with local GDIplus Declares or use a Type Library.

See advantage of using the TLB here.



User Controls - Owner/Custom Draw

Windows TextOut() APIs

From antiquity, the routines DrawText(), TextOut() and (more recently) ExtTextOut() have been the work-horse APIs used to draw text. Except on OS editions localized for regions of the world where complex scripts were needed, these routines did not do any complex script handling. And in fact they still do not, except on Windows 2000 and XP or later. On those operating systems, which come with Uniscribe as a standard system component, these standard APIs now do complex script shaping even for programs that have not been designed for it or are not expecting it.

If you are coding a User Control or subclassing a control to take advantage of Owner Draw or Custom Draw features then use API DrawTextW or TextOutW as follows:

Note: lFlags values can be found here: DrawText Align Flags.


Custom Control Example



Updated 13-August-2018 03:22 -0300



  • Unicode is a trademark of Unicode, Inc.
  • Microsoft, Visual Basic, VB.NET, and C#.NET are trademarks of Microsoft Corporation.





Unicode Aware Controls

The intrinsic controls that ship with Vb6 are not Unicode aware so you have several options.


Convert UTF16-UTF8-UTF16

UTF8 is a lossless method of encoding UTF16 Unicode in 1-3 bytes.

Unicode Hex
Unicode Dec
0..7F 0..127 1
80..7FF 128..2047 2
800..FFFF 2048..65535 3

According to HTML standard, HTML files should be transmitted in Big-Endian format and using Byte-Order Mark (BOM) is recommended. Since Windows Native format is Little-Endian, to avoid the Endian conversion problem, it is recommended to use UTF-8 encoding in HTML files. In addition to converting your strings to UTF-8 add the following MetaTag to indicate your content as being UTF-8:

"<HEAD><meta http-equiv='Content-Type' content='text/html; charset=utf-8'></HEAD>"

Platforms Function Comments
All WideCharToMultiByte Lib "kernel32"
MultiByteToWideChar Lib "kernel32"
Codepage CP_UTF8 = 65001
This is a pseudo codepage. There is no corresponding NLS file. This code page ID can only be used with WideCharToMultiByte() and MultiByteToWideChar() API calls.
All ConvertINetMultiByteToUnicode Lib "mlang"
ConvertINetUnicodeToMultiByteLib "mlang"
Minimum availability Internet Explorer 5.5


API UTF8 Conversions




Export UTF-8 Example


Sample Grid saved as HTML(UTF-8 encoded). Supports Header, Filter Bar, Icons, Pictures, Backgrounds, Alignment, Unicode text, Cell ForeColor/BackColor, and Hyperlinks

DemoHeader - ExportHTML

Name Multiline Headers
CHS: 欢迎
JPN: よろてそ
Type Modified GEO: სასურველი Col 6 Col 7 Col 8 Col 9 Col 10
  Insira o texto aqui   Insira o texto aqui Insira o texto aqui Insira o texto aqui Insira o texto aqui Insira o texto aqui Insira o texto aqui Insira o texto aqui
  0,707107 Type 1,Col3 2007-190 ARA: مـرحبــاً Arabic United Arab Emirates   Abu Dhabi Row1,Col10
  316.615 Type 2,Col3 2008-359 CHS: 欢迎 Chinese Simplified China   Beijing Row2,Col10
  316.615 Type 3,Col3 2009-013 CHT: 歡迎 Chinese Traditional Taiwan   Taipei Row3,Col10
  www.unisuite.com Type 4,Col3 2009-120 ENG: Welcome English United States   Washington, DC Row4,Col10

HTML Table

Language Unicode
Chinese CHS: 欢迎
Japanese JPN: よろてそ
Korean KOR: 여보세요
Portuguese PTB: Bem-vindo


Visit www.unisuite.com

Type 5,Col3   Georgian Georgia   Tbilisi Row5,Col10

HTML Markers


  1. sChinese
    • CHS: 欢迎
  2. sJapanese
    • JPN: よろてそ
  3. sKorean
    • KOR: 여보세요

Arabic, Roman, Alpha, Circle, Disc, Square, Upper/Lower Case.

Type 6,Col3 Greek Greece   Athens Row6,Col10
  491.467 Type 7,Col3 2005-201 HEB: בִּרוּבִים חַבָּאִים Hebrew Israel   Jerusalem Row7,Col10
  276.606 Type 8,Col3 2005-299 HIN: रवागत Hindi India   New Delhi Row8,Col10
  617.782 Type 9,Col3 2011-311 JPN: よろてそ Japanese Japan   Tokyo Row9,Col10
  728.881 Type 10,Col3 2011-076 KOR: 여보세요 Korean Korea   Seoul Row10,Col10
  111.536 Type 11,Col3 2011-212 PAN: ਜੀ ਆਇਆਂ ਨੂੰ Punjabi Pakistan   Islamabad Row11,Col10
  603.123 Type 12,Col3 2004-025 PTB: Bem-vindo Portuguese(BR) Brazil   Brasilia Row12,Col10
  298.299 Type 13,Col3 2003-102 RUS: Добро пожаловать Russian Russian Federation   Moscow Row13,Col10
  315.590 Type 14,Col3 2011-346 TAM: 쏅얧주ø Tamil India   New Delhi Row14,Col10
  291.797 Type 15,Col3 2004-051 THA: การต้อนรับ Thai Thailand   Bangkok Row15,Col10
  429.992 Type 16,Col3 2006-253 URD: स्वागत Urdu Pakistan   Islamabad Row16,Col10
  663.936 Type 17,Col3 2005-049 VIE: tính từ Vietnamese Vietnam   Hanoi Row17,Col10
  84.635 Type 18,Col3 2007-312 ARA: مـرحبــاً Arabic United Arab Emirates   Abu Dhabi Row18,Col10
  823.354 Type 19,Col3 2006-088 CHS: 欢迎 Chinese Simplified China   Beijing Row19,Col10
  662.429 Type 20,Col3 2008-124 CHT: 歡迎 Chinese Traditional Taiwan   Taipei Row20,Col10
  588.293 Type 21,Col3 2009-330 ENG: Welcome English United States   Washington, DC Row21,Col10
  23.728 Type 22,Col3 2007-317 GEO: სასურველი Georgian Georgia   Tbilisi Row22,Col10
  710.879 Type 23,Col3 2007-165 GRK: Καλώς ήλθατε Greek Greece   Athens Row23,Col10
  370.642 Type 24,Col3 2006-061 HEB: בִּרוּבִים חַבָּאִים Hebrew Israel   Jerusalem Row24,Col10
  255.690 Type 25,Col3 2011-012 HIN: रवागत Hindi India   New Delhi Row25,Col10

DemoFooter - ExportHTML



Export To File


Exporting Unicode to a file usually involves prefixing the text with a BOM (Byte Order Mark). See the table above to see what prefix is required depending on the Unicode format. Using UTF-8 although it takes more space than UTF-16 is recommended since it is easier to transport to other platforms and easier to use in HTML.

See FileIO for methods on how to Read/Write Unicode files.




The VB Clipboard functions are ANSI only. If you need to access the Clipboard 'Unicode string' you must use format 'CF_UNICODETEXT = 13'. Code to do this can be found at http://www.vbaccelerator.com/home/VB/Code/Libraries/Clipboard/Customising_Clipboard_Use/article.asp

Standard Clipboard Formats


Windows Message Clipboard Constants

WM_PASTE = &H302
WM_CLEAR = &H303
WM_COPY = &H301
WM_CUT = &H300
WM_UNDO = &H304

Windows Clipboard API's

Declare Function CloseClipboard Lib "user32" () As Long
Declare Function CloseClipboard Lib "user32" () As Long
Declare Function EmptyClipboard Lib "user32" () As Long
Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
Declare Function IsClipboardFormatAvailable Lib "user32" (ByVal wFormat As Long) As Long
Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Declare Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As Long) As Long




Unicode Blocks

Chart Updated 18-Jul-2007

Block Name From To # Codepoints


Basic Latin U+0000 U+007F (128) Tahoma
Latin-1 Supplement U+0080 U+00FF (128) Tahoma
Latin Extended-A U+0100 U+017F (128) Tahoma
Latin Extended-B U+0180 U+024F (208) Tahoma
IPA Extensions U+0250 U+02AF (96) Arial Unicode MS
Spacing Modifier Letters U+02B0 U+02FF (80) Tahoma
Combining Diacritical Marks U+0300 U+036F (112) Tahoma
Greek and Coptic U+0370 U+03FF (127) Tahoma
Cyrillic U+0400 U+04FF (255) Tahoma
Cyrillic Supplement U+0500 U+052F (20) Tahoma
Armenian U+0530 U+058F (86) Sylfaen
Hebrew U+0590 U+05FF (87) David
Arabic U+0600 U+06FF (235) Arial Unicode MS
Syriac U+0700 U+074F (77) Estrangelo Edessa
Arabic Supplement U+0750 U+077F (30) Arial Unicode MS
Thaana U+0780 U+07BF (50) MV Boli
NKo U+07C0 U+07FF (59) Arial Unicode MS
Devanagari U+0900 U+097F (110) Mangal
Bengali U+0980 U+09FF (91) Vrinda
Gurmukhi U+0A00 U+0A7F (77) Raavi
Gujarati U+0A80 U+0AFF (83) Shruti
Oriya U+0B00 U+0B7F (81) Arial Unicode MS
Tamil U+0B80 U+0BFF (71) Latha
Telugu U+0C00 U+0C7F (80) Guatami
Kannada U+0C80 U+0CFF (86) Tunga
Malayalam U+0D00 U+0D7F (78) Kartika
Sinhala U+0D80 U+0DFF (80) Arial Unicode MS
Thai U+0E00 U+0E7F (87) Angsana New
Lao U+0E80 U+0EFF (65) Arial Unicode MS
Tibetan U+0F00 U+0FFF (195) Arial Unicode MS
Myanmar U+1000 U+109F (78) Arial Unicode MS
Georgian U+10A0 U+10FF (83) Sylfang
Hangul Jamo U+1100 U+11FF (240) Batang
Ethiopic U+1200 U+137F (356) Arial Unicode MS
Ethiopic Supplement U+1380 U+139F (26) Arial Unicode MS
Cherokee U+13A0 U+13FF (85) Arial Unicode MS
Unified Canadian Aboriginal Syllabics U+1400 U+167F (630) Arial Unicode MS
Ogham U+1680 U+169F (29) Arial Unicode MS
Runic U+16A0 U+16FF (81) Arial Unicode MS
Tagalog U+1700 U+171F (20) Arial Unicode MS
Hanunoo U+1720 U+173F (23) Arial Unicode MS
Buhid U+1740 U+175F (20) Arial Unicode MS
agbanwa U+1760 U+177F (18) Arial Unicode MS
Khmer U+1780 U+17FF (114) Arial Unicode MS
Mongolian U+1800 U+18AF (155) Arial Unicode MS
Limbu U+1900 U+194F (66) Arial Unicode MS
Tai Le U+1950 U+197F (35) Arial Unicode MS
New Tai Lue U+1980 U+19DF (80) Arial Unicode MS
Khmer Symbols U+19E0 U+19FF (32) Arial Unicode MS
Buginese U+1A00 U+1A1F (30) Arial Unicode MS
Balinese U+1B00 U+1B7F (121) Arial Unicode MS
Phonetic Extensions U+1D00 U+1D7F (128) Arial Unicode MS
Phonetic Extensions Supplement U+1D80 U+1DBF (64) Arial Unicode MS
Combining Diacritical Marks Supplement U+1DC0 U+1DFF (13) Arial Unicode MS
Latin Extended Additional U+1E00 U+1EFF (246) Tahoma
Greek Extended U+1F00 U+1FFF (233) Tahoma
General Punctuation U+2000 U+206F (106) Tahoma
Superscripts and Subscripts U+2070 U+209F (34) Tahoma
Currency Symbols U+20A0 U+20CF (22) Tahoma
Combining Diacritical Marks for Symbols U+20D0 U+20FF (32) Tahoma
Letterlike Symbols U+2100 U+214F (79) Tahoma
Number Forms U+2150 U+218F (50) Tahoma
Arrows U+2190 U+21FF (112) Arial Unicode MS
Mathematical Operators U+2200 U+22FF (256) Arial Unicode MS
Miscellaneous Technical U+2300 U+23FF (232) Tahoma
Control Pictures U+2400 U+243F (39) Tahoma
Optical Character Recognition U+2440 U+245F (11) Tahoma
Enclosed Alphanumerics U+2460 U+24FF (160) Tahoma
Box Drawing U+2500 U+257F (128) Tahoma
Block Elements U+2580 U+259F (32) Tahoma
Geometric Shapes U+25A0 U+25FF (96) Tahoma
Miscellaneous Symbols U+2600 U+26FF (176) Tahoma
Dingbats U+2700 U+27BF (174) Tahoma
Miscellaneous Mathematical Symbols-A U+27C0 U+27EF (39) Arial Unicode MS
Supplemental Arrows-A U+27F0 U+27FF (16) Arial Unicode MS
Braille Patterns U+2800 U+28FF (256) Arial Unicode MS
Supplemental Arrows-B U+2900 U+297F (128) Arial Unicode MS
Miscellaneous Mathematical Symbols-B U+2980 U+29FF (128) Arial Unicode MS
Supplemental Mathematical Operators U+2A00 U+2AFF (256) Arial Unicode MS
Miscellaneous Symbols and Arrows U+2B00 U+2BFF (31) Arial Unicode MS
Glagolitic U+2C00 U+2C5F (94) Arial Unicode MS
Latin Extended-C U+2C60 U+2C7F (17) Arial Unicode MS
Coptic U+2C80 U+2CFF (114) Arial Unicode MS
Georgian Supplement U+2D00 U+2D2F (38) Sylfaen
Tifinagh U+2D30 U+2D7F (55) Arial Unicode MS
Ethiopic Extended U+2D80 U+2DDF (79) Arial Unicode MS
Supplemental Punctuation U+2E00 U+2E7F (26) Tahoma
CJK Radicals Supplement U+2E80 U+2EFF (115) MingLiU
Kangxi Radicals U+2F00 U+2FDF (214) MingLiU
Ideographic Description Characters U+2FF0 U+2FFF (12) MingLiU
CJK Symbols and Punctuation U+3000 U+303F (64) MingLiU
Hiragana U+3040 U+309F (93) MS Gothic
Katakana U+30A0 U+30FF (96) MS Gothic
Bopomofo U+3100 U+312F (40) MingLiU
Hangul Compatibility Jamo U+3130 U+318F (94) Batang
Kanbun U+3190 U+319F (16) MingLiU
Bopomofo Extended U+31A0 U+31BF (24) MingLiU
CJK Strokes U+31C0 U+31EF (16) MingLiU
Katakana Phonetic Extensions U+31F0 U+31FF (16) MS Gothic
Enclosed CJK Letters and Months U+3200 U+32FF (242) MingLiU
CJK Compatibility U+3300 U+33FF (256) MingLiU
CJK Unified Ideographs Extension A U+3400 U+4DBF (6582) MingLiU
Yijing Hexagram Symbols U+4DC0 U+4DFF (64) MingLiU
CJK Unified Ideographs U+4E00 U+9FFF (20924) MingLiU
Yi Syllables U+A000 U+A48F (1165) Arial Unicode MS
Yi Radicals U+A490 U+A4CF (55) Arial Unicode MS
Modifier Tone Letters U+A700 U+A71F (27) MingLiU
Latin Extended-D U+A720 U+A7FF (2) Arial Unicode MS
Syloti Nagri U+A800 U+A82F (44) Arial Unicode MS
Phags-pa U+A840 U+A87F (56) Tahoma
Hangul Syllables U+AC00 U+D7AF (2) Batang
High Surrogates U+D800 U+DB7F (2) Arial Unicode MS
High Private Use Surrogates U+DB80 U+DBFF (2) ??
Low Surrogates U+DC00 U+DFFF (2) Arial Unicode MS
Private Use Area U+E000 U+F8FF (2) Arial Unicode MS
CJK Compatibility Ideographs U+F900 U+FAFF (467) MingLiU
Alphabetic Presentation Forms U+FB00 U+FB4F (58) Tahoma
Arabic Presentation Forms-A U+FB50 U+FDFF (595) Arial Unicode MS
Variation Selectors U+FE00 U+FE0F (16) Tahoma
Vertical Forms U+FE10 U+FE1F (10) MingLiU
Combining Half Marks U+FE20 U+FE2F (4) Tahoma
CJK Compatibility Forms U+FE30 U+FE4F (32) MingLiU
Small Form Variants U+FE50 U+FE6F (26) MingLiU
Arabic Presentation Forms-B U+FE70 U+FEFF (141) Arial Unicode MS
Halfwidth and Fullwidth Forms U+FF00 U+FFEF (225) MingLiU
Specials U+FFF0 U+FFFF (5) Tahoma
Linear B Syllabary U+10000 U+1007F (88) Tahoma
Linear B Ideograms U+10080 U+100FF (123) Tahoma
Aegean Numbers U+10100 U+1013F (57) Tahoma
Ancient Greek Numbers U+10140 U+1018F (75) Tahoma
Old Italic U+10300 U+1032F (35) Tahoma
Gothic U+10330 U+1034F (27) Tahoma
Ugaritic U+10380 U+1039F (31) Tahoma
Old Persian U+103A0 U+103DF (50) Tahoma
Deseret U+10400 U+1044F (80) Tahoma
Shavian U+10450 U+1047F (48) Tahoma
Osmanya U+10480 U+104AF (40) Tahoma
Cypriot Syllabary U+10800 U+1083F (55) Tahoma
Phoenician U+10900 U+1091F (27) Tahoma
Kharoshthi U+10A00 U+10A5F (65) Tahoma
Cuneiform U+12000 U+123FF (879) Tahoma
Cuneiform Numbers and Punctuation U+12400 U+1247F (103) Tahoma
Byzantine Musical Symbols U+1D000 U+1D0FF (246) Tahoma
Musical Symbols U+1D100 U+1D1FF (219) Tahoma
Ancient Greek Musical Notation U+1D200 U+1D24F (70) Tahoma
Tai Xuan Jing Symbols U+1D300 U+1D35F (87) Tahoma
Counting Rod Numerals U+1D360 U+1D37F (18) Tahoma
Mathematical Alphanumeric Symbols U+1D400 U+1D7FF (996) Tahoma
CJK Unified Ideographs Extension B U+20000 U+2A6DF (42711) Tahoma
CJK Compatibility Ideographs Supplement U+2F800 U+2FA1F (542) Tahoma
Tags U+E0000 U+E007F (97) Tahoma
Variation Selectors Supplement U+E0100 U+E01EF (240) Tahoma
Supplementary Private Use Area-A U+F0000 U+FFFFF (2) Arial Unicode MS
Supplementary Private Use Area-B U+100000 U+10FFFF (2) Arial Unicode MS



DrawText Align Flags


These are the flags you can set when using API DrawTextW. Combine using the OR operator. Example: DT_CENTER OR DT_WORDBREAK

Name Value Description
DT_TOP &H0& Justifies the text to the top of the rectangle.
DT_LEFT &H0& Aligns text to the left.
DT_CENTER &H1& Centers text horizontally in the rectangle.
DT_RIGHT &H2& Aligns text to the right.
DT_VCENTER &H4& Centers text vertically. This value is used only with the DT_SINGLELINE value.
DT_BOTTOM &H8& Justifies the text to the bottom of the rectangle. This value is used only with the DT_SINGLELINE value.
DT_WORDBREAK &H10& Breaks words. Lines are automatically broken between words if a word would extend past the edge of the rectangle specified by the lpRect parameter. A carriage return-line feed sequence also breaks the line.

If this is not specified, output is on one line.

DT_SINGLELINE &H20& Displays text on a single line only. Carriage returns and line feeds do not break the line.
DT_EXPANDTABS &H40& Expands tab characters. The default number of characters per tab is eight. The DT_WORD_ELLIPSIS, DT_PATH_ELLIPSIS, and DT_END_ELLIPSIS values cannot be used with the DT_EXPANDTABS value.
DT_TABSTOP &H80& Sets tab stops. Bits 158 (high-order byte of the low-order word) of the uFormat parameter specify the number of characters for each tab. The default number of characters per tab is eight. The DT_CALCRECT, DT_EXTERNALLEADING, DT_INTERNAL, DT_NOCLIP, and DT_NOPREFIX values cannot be used with the DT_TABSTOP value.
DT_NOCLIP &H100& Draws without clipping. DrawText is somewhat faster when DT_NOCLIP is used.
DT_EXTERNALLEADING &H200& Includes the font external leading in line height. Normally, external leading is not included in the height of a line of text.
DT_CALCRECT &H400& Determines the width and height of the rectangle. If there are multiple lines of text, DrawText uses the width of the rectangle pointed to by the lpRect parameter and extends the base of the rectangle to bound the last line of text. If the largest word is wider than the rectangle, the width is expanded. If the text is less than the width of the rectangle, the width is reduced. If there is only one line of text, DrawText modifies the right side of the rectangle so that it bounds the last character in the line. In either case, DrawText returns the height of the formatted text but does not draw the text. Thus it should never be used as a CellTextFormat parameter.
DT_NOPREFIX &H800& Turns off processing of prefix characters. Normally, DrawText interprets the mnemonic-prefix character & as a directive to underscore the character that follows, and the mnemonic-prefix characters && as a directive to print a single &. By specifying DT_NOPREFIX, this processing is turned off. For example,

input string:   "A&bc&&d"
normal:         "Abc&d"
DT_NOPREFIX:    "A&bc&&d"


DT_INTERNAL &H1000& Uses the system font to calculate text metrics.
DT_EDITCONTROL &H2000& Duplicates the text-displaying characteristics of a multiline edit control. Specifically, the average character width is calculated in the same manner as for an edit control, and the function does not display a partially visible last line.
DT_PATH_ELLIPSIS &H4000& For displayed text, replaces characters in the middle of the string with ellipses so that the result fits in the specified rectangle. If the string contains backslash (\) characters, DT_PATH_ELLIPSIS preserves as much as possible of the text after the last backslash.

The string is not modified unless the DT_MODIFYSTRING flag is specified.


DT_END_ELLIPSIS &H8000& For displayed text, if the end of a string does not fit in the rectangle, it is truncated and ellipses are added. If a word that is not at the end of the string goes beyond the limits of the rectangle, it is truncated without ellipses.

The string is not modified unless the DT_MODIFYSTRING flag is specified.


DT_MODIFYSTRING &H10000& Modifies the specified string to match the displayed text. This value has no effect unless DT_END_ELLIPSIS or DT_PATH_ELLIPSIS is specified.
DT_RTLREADING &H20000& Layout in right-to-left reading order for bi-directional text when the font selected into the hdc is a Hebrew or Arabic font. The default reading order for all text is left-to-right.
DT_WORD_ELLIPSIS &H40000& Truncates any word that does not fit in the rectangle and adds ellipses.


DT_NOFULLWIDTHCHARBREAK &H80000& Windows 98/Me, Windows 2000/XP: Prevents a line break at a DBCS (double-wide character string), so that the line breaking rule is equivalent to SBCS strings. For example, this can be used in Korean windows, for more readability of icon labels. This value has no effect unless DT_WORDBREAK is specified.
DT_HIDEPREFIX  &H100000& Windows 2000/XP: Ignores the ampersand (&) prefix character in the text. The letter that follows will not be underlined, but other mnemonic-prefix characters are still processed. For example:

input string:    "A&bc&&d"
normal:          "Abc&d"


DT_PREFIXONLY &H200000& Windows 2000/XP: Draws only an underline at the position of the character following the ampersand (&) prefix character. Does not draw any other characters in the string. For example,

input string:    "A&bc&&d"

normal:          "Abc&d"

DT_PREFIXONLY:   " _   "





RTL(RightToLeft) provides support for languages such as Arabic, Hebrew, Urdu.

Activation Method Activate Deactivate
Process SetProcessDefaultLayout (LAYOUT_RTL) SetProcessDefaultLayout (0)
Window lExStyles = lExStyles Or WS_EX_LAYOUTRTL lExStyles = lExStyles And Not WS_EX_LAYOUTRTL
Device Context SetLayout(hdc, LAYOUT_RTL) SetLayout (hdc, 0)

There are several Extended Style Constants used to enable Window Activation:

LTR (Default)
ENG: Welcome ]
 العربية :ARA]
WS_EX_LEFT = &H0 WS_EX_RIGHT = &H1000 Alignment
WS_EX_RIGHTSCROLLBAR = &H0 WS_EX_LEFTSCROLLBAR = &H4000 Vertical Scrollbar Alignment
  WS_EX_LAYOUTRTL = &H400000 Right to left mirroring
  WS_EX_NOINHERITLAYOUT = &H100000 Disable inheritence of mirroring by children

To test various Styles or Extended Styles put this code in a module:




Suggested reading MSDN:

Control Should not allow layout inheritance
Listview No
Panel Yes
Statusbar Yes
Tabcontrol Yes
TabPage Yes
Toolbar No
TreeView No
Form Yes
Splitter Yes


Activating Mirroring per Device Context

GetLayout(hdc) will return the current layout state.

SetLayout(hdc, 0) If the device context is not mirrored
SetLayout(hdc, LAYOUT_RTL) If the device context is mirrored
SetLayout(hdc, LAYOUT_RTL Or LAYOUT_BITMAP) If the device context is mirrored and if the programmer does not want the device context to have mirrored bitmaps
SetLayout(hdc, LAYOUT_RTL Or  LAYOUT_BITMAPORIENTATIONPRESERVED) If the device context is mirrored and if the programmer wants the device context to have mirrored bitmaps


Constant Value Description
LAYOUT_RTL 1 Right to left
LAYOUT_BTT 2 Bottom to top
LAYOUT_VBH 4 Vertical before horizontal


Visual Basic Bi-directional Features:

Visual Basic is bi-directional (also known as "BIDI")-enabled. Bi-directional is a generic term used to describe software products that support Arabic and other languages, which are written right-to-left. More specifically, bi-directional refers to the product ability to manipulate and display text for both left-to-right and right-to-left languages. For example, displaying a sentence containing words written in both English and Arabic requires bi-directional capability.

Microsoft Visual Basic includes standard features to create and run Windows applications with full bi-directional language functionality. However, these features are operational only when Microsoft Visual Basic is installed in a bi-directional 32-bit Microsoft Windows environment, such as Arabic Microsoft Windows 95. Other bi-directional 32-bit Microsoft Windows environments are available as well.

The Right-To-Left property has been added to forms, controls, and other Visual Basic objects to provide an easy mechanism for creating objects with bi-directional characteristics.
Although Right-To-Left is a part of every Microsoft Visual Basic installation, it is operational only when Microsoft Visual Basic is installed in a bi-directional 32-bit Microsoft Windows environment.

This is frustrating since we may be developing on a non-BIDI environment but yet want to support BIDI.
Using WS_EX_LAYOUTRTL would seem the logical answer here but when you try to manipulate a UserControl using this Flag it does not work correctly on a non-BIDI OS.
The trick is to not bind the RightToLeft Property to the UserControl and owner-draw the control  to replicate both BIDI and normal modes.
Thus LTR would use something like "DT_LEFT" and RTL would use "DT_RIGHT Or DT_RTLREADING".
DT_SINGLELINE or DT_WORDBREAK and other options would be added to both alignments.

Here is what Microsoft has to say about "MiddleEast - Frequently Asked Questions"


The part about installing Arabic Support to Win2000/XP/Vista is True.

You can take with a grain of salt these statements:

Microsoft CyberActiveX
Although Right-To-Left is a part of every Microsoft Visual Basic installation, it is operational only when Microsoft Visual Basic is installed in a bi-directional 32-bit Microsoft Windows environment. While you can't set this Property in a UserControl unless you are in a BIDI environment you can Owner-Draw to emulate RTL or set style to include WS_EX_LAYOUTRTL.
On Windows XP: "Regional and Language Options" go to the "Advanced" tab and change the "Language for non Unicode programs" to an Arabic language. This is not always necessary and makes development a pain on U.S. systems. This might be true for SBCS but not for Unicode or when you are developing you own controls.




Just so you do not have to reinvent the wheel check out these hints:

  1. If you pass a string to an API as 'String', VB will convert the Unicode string to ANSI first. Always use a pointer such as StrPtr(sText) to pass a Unicode string. You usually need to change the API Declare to a Long for this to work. This is not necessary if your Function is Declared in a TLB.
  2. Advanced source code for OwnerDraw Controls can be found at http://www.vbaccelerator.com. Highly recommended. This is a gold mine.
  3. Use COMMCTRL.Tlb from www.domaindlx.com/e_morcillo/. It has 95% of what you need to deal with owner draw and custom draw controls. It nicely wraps the Comctl32.Dll.
  4. Owner Draw requires you to create the entire control from scratch in code including drawing and event handling.
  5. Custom Draw allows you to override a specific portion of a control drawing cycle to modify its behaviour. Note that only certain controls allow this. The header control in Comctl32.Dll is one example(used in conjunction with Listview but can also be attached to a Grid control). Search MSDN for more info.
  6. Beware of accents in your strings. If you are using ANSI then you can freely use characters 128..255 and they will appear correctly using DrawTextA or DrawTextW. However, if you intend your string to represent UTF-8 you must encode the characters 128..255. For example the sample string sPortuguese in ANSI is "português(BR)" & vbCrLf & "Ação já". The same string in Utf-8 is "português(BR)" & vbCrLf & "Ação já". It is then up to code that receives the Utf-8 to convert to Unicode(Utf-16) and then send it to DrawTextW.
  7. Vb code support for Uniscribe and Mlang can be found here.
  8. You may need to store your Unicode string caption locally if it is being converted to ANSI via a structure. Using OwnerDraw or CustomDraw you can then render the string using DrawTextW or TextOutW.
    Another situation can occur in classes where the string is passed ByRef via a Method(Sub) can be corrupted. The solution here is to create a Property in the class to hold the Unicode string.
    Note: This is very important. Make sure your string is not being converted to ANSI somewhere before it arrives at DrawTextW.
    This is easy to troublsehoot as long as you have the source code. Follow your string and substitute with ChrW$(-27073) until you find out where the string gets corrupted.
  9. In general create controls with CreateWindowExW.
    This is not always necessary though. For example you can for example create a Balloon Tooltip with CreateWindowExA and use the Wide version of ToolInfo to successfully set a Unicode caption. SendMessage in this case uses TTM_ADDTOOLW, TTM_UPDATETIPTEXTW, and TTM_SETTITLEW for the wMsg parameter. You must also use StrPtr(sCaption) to supply the long pointer to the string.
  10. Use Wide versions of UDTs. Note that they are usually identical to the ANSI version with exception of the strings which use a long string pointer in lieu of a string variable.
  11. Use Wide versions of message constants. The values are often different for Unicode.
    Constants can be found in file "Microsoft SDK\include\CommCtrl.h" from the Platform SDK.
  12. Some controls require sending a message to specifically set Unicode mode. The header control in Comctl32.Dll is one example(used in conjunction with Listview but can also be attached to a Grid control).



Why use a Type Library (TLB)?


  1. Eliminates cut and paste in your projects.
  2. Eliminates typographical errors.
  3. No Bloat. The final EXE uses only the Constants, Types, and Declares that are used by your project.
  4. There is a common misconception that you need to ship the TLB. You never need to include the TLB in your deployment package unless there are implement interfaces. All relevant data is embedded in the EXE, DLL, or OCX.
  5. Unicode strings are not corrupted when passed to functions since they are passed as a pointer without the explicit need of using StrPtr(sText) in your code.




GB18030 Support Package

GB18030–2000 is a new Chinese character encoding standard. The standard contains many characters and has some tough new conformance requirements. GB18030-2000 encodes characters in sequences of one, two, or four bytes. These sequences are defined as follows:

The government has said that it will enforce the standard first for platforms, and later for tools and applications.

Which Microsoft Platforms have
been approved for use in China?

Product GB-18030
Approval Status
Windows XP Yes (with add-on) Approved by the Chinese testing agency.
Windows 2000 Yes (with add-on) Approved by the Chinese testing agency.
Windows NT4 No Exempt from the law because released before the standard was published.
Windows 98 No Exempt from the law because released before the standard was published.
Windows 95 No Exempt from the law because released before the standard was published.
Windows Millennium No Does not conform and may no longer be sold in China.
Internet Explorer 6.0 Yes ??
Internet Explore 5.5 and earlier No ??

GB18030 Support Package (English)

File Name:


Download Size: 7,015,936 bytes

Date Published:

11-oct-2003 19:00

Version: 1.0
Download Link: Download
  • * SimSun18030.ttc: A font file for GB18030
  • C_g18030.dll: A system library that extends the MultiByteToWideChar and WideCharToMultiByte prgram interfaces to support GB18030. It is only installed on Windows 2000 systems.
  • GBunicnv.exe: An end-user application that converts GB18030 plain text and HTML files to Unicode and vice versa.
  • Ms4bsp.dll: A system library that provides program interfaces for the GB18030 character type.

* According to Dr. International: http://www.microsoft.com/globaldev/drintl/columns/015/default.mspx#Q13
The SimSun18030 font (simsun18030.ttc) in the GB18030 support package does not have the complete GB18030 repertoire. It is missing the entire CJK Extension B set, as well as other characters. It does have, however, CJK Extension A.
A font that contains Simplified Chinese glyphs from both CJK Extension A and B sets is "SimSun (Founder Extended)" (SurSong.ttf in the system), or 宋体–方正超大字符集 (in Chinese). It is currently available in the Simplified Chinese (CHS) version of Office XP, or the Microsoft Office Proofing Tools. Click the link for more information and how to buy.

Also see Surrogate pairs.




When you save strings to the PropertyBag in User Controls they are automatically converted to ANSI. You can however save Unicode as a string of Hex values of the wide characters(AscW) and reconstruct the string upon retrieval.

A better(easier/faster) method to prevent ANSI conversion is to convert the string to a byte array and then to a variant before writing to the PropertyBag. The reverse process is used to read from the PropertyBag. Note that it is not necessary to dimension the byte array.

PropertyBag Wrapper Functions


These methods have been updated with code by Krool:

Function UniToVar(ByVal Text As String) As Variant
  If Len(Text) = 0 Then 'Handles both vbNullString and ""
    UniToVar = Empty 'Added by Krool (2016)
    Dim b() As Byte 'Original by Dana Seaman (2006)
    b = Text
    UniToVar = b
  End If
End Function

Function VarToUni(ByVal vVar As Variant) As String
  If IsEmpty(vVar) Then
    VarToUni = vbNullString 'Added by Krool (2016)
    Dim b() As Byte 'Original by Dana Seaman (2006)
    b = vVar
    VarToUni = b
  End If
End Function

An example of how to use these functions:

Operation Sample code
Property Variable Dim mCaption As String
Property Get Public Property Get Caption() As String
   Caption = mCaption
End Property
Property Let Public Property Let Caption(ByVal RHS As String)
   mCaption = RHS
   PropertyChanged "Caption"
End Property
UserControl_ReadProperties mCaption = VarToUni(PropBag.ReadProperty("Caption", vbNullString))
UserControl_WriteProperties PropBag.WriteProperty "Caption", UniToVar(mCaption), vbNullString

This preserves the Unicode in string m_Caption. In an OwnerDraw label control you would then do something like this:

DrawTextW hdc, StrPtr(m_Caption), -1, rct, m_Alignment

Note2: To input the Unicode Caption/Text in the IDE will require you to create a Propery Page that has a Unicode aware TextBox or InkEdit.


Property Bag - UTF-8

This is a method that allows you to input and store Unicode string captions/text without the need for a PropertyPage for Caption/Text or the need for saving the caption as a ByteArray in the PropertyBag.

Using UniConverter.Zip(10Kb) convert your strings to UTF8 and simply paste the UTF8 string into the IDE Properties Window Caption/Text Property. You could also set them at runtime via code, resource file, database, or text file:

Unicode String Desired UTF-8 Equivalent
CHS: 欢迎 CHS: 欢迎

In your UserControl convert the UTF8 to Unicode and render with DrawTextW or TextOutExW. The code to perform the conversion can be found here or at UniConverter.Zip(10Kb)


Property Pages

This applies to User Control Unicode Strings:

  1. You cannot set Unicode strings from the IDE Properties Window since it only displays ANSI.
  2. You can set them at runtime from code, a resource file, or a satellite DLL.
  3. Make a Custom Property Page for your User Control. You can use the Property Page wizard to do this. Then replace the Vb TextBox with one that is Unicode aware. You may need to change the names created by the Wizard or just change the name of your Unicode control to Text1.
    Note: So you don't print '????' for strings in the Vb6 IDE Properties window you may also want to change your control code to this:
  4. You will also need to modify the Property Bag so that it doesn't mangle your Unicode string.
  5. Another option is to use UTF-8 which you can easily display in the properties window AND persist to the PropertyBag as an ANSI string. You will however have to convert the UTF-8 to Unicode UTF-16 at runtime to display the text.



Input Methods

Several methods are available to populate a Control or String variable with Unicode.



  1. Input Unicode as Alt-+-#### where #### is the hexadecimal value of the desired character.
  2. IME (Input Method Editor). Add optional IMEs via the Control Panel, Regional Configurations, Languages, Details.

    Most newer Brazilian Portuguese keyboard layouts however look more like this:

Pickers Use Unicode picker available in Office(WinWord). Select the Unicode text, copy to clipboard(Ctrl-C) and paste(Ctrl-V) into your textbox at the desired position.
  1. Use a stand-alone Unicode picker. Put the desired character(s) into the clipboard and then paste(Ctrl-V) into your textbox at the desired position.
  1. Use any Unicode editor such as Notepad, UltraEdit, or Office(WinWord). Select text, copy to clipboard(Ctrl-C) and paste(Ctrl-V) into your textbox at the desired position.
  1. DesignTime - See Property Pages
  2. RunTime - See Sample Strings

Keyboard Input Methods for WinXP

Application Method Result
Notepad Type Alt + then a Unicode hex value such as C866. Do not release the Alt key until you type the final hex value. The character will appear when you release the Alt key.
Microsoft Word
RichEdit controls
Office edit boxes
Type a Unicode hex value such as C866 then Alt-x. If you made an error type Alt-x and the hex value will reappear. Correct the value and convert again.

For more information see http://www.microsoft.com/globaldev/handson/dev/Unicode-KbdsonWindows.pdf



Resource Files

Using a Resource file is yet another method of storing your Unicode strings. A sample can be found on MSDN: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcsample/html/vcconUniresSampleDemonstratesUseOfUnicodeResourceFiles.asp.

Make sure you use a Unicode aware editor. In NT/2000/XP Notepad is OK. In Win98 you will need to use WordPad or UltraEdit32.

If you create a new resource file in Notepad the first time you save the file use "Save As" and specify the coding as Unicode. If your file has Unicode content and you attempt to save the file as ANSI you will receive a warning that you have Unicode content and must save as Unicode.
Compile this new file using resource compiler Rc.Exe. You may want to make a simple batch file to do this (make sure Rc.Exe is in an available path):

RC UnicodeStrings.rc

Vb6 has no problem reading a Resource file that was saved in ANSI or Unicode format and LoadResString will read Unicode from the resource correctly.


Satellite DLL

The recommended approach for dealing with multilingual resources is the use of Satellite Resource Dlls. Information can be found at Satellite resource DLLs,




XP Themes

The Good, the Bad, and the Ugly

ForeverBlue2 Theme Luna Theme(Silver) Vb Button

As you can see from the above Screenshot XP Themes give a nice appearance to controls but they may have undesirable side effects when it comes to Unicode.

UxTheme.Dll Patch for WinXP

Ordinarily I would never recommend patching an Operating System DLL. However Microsoft does not allow 3rd party themes like the one shown above(ForeverBlue2). There are lots of free themes available for download. You can use a commercial program to apply these themes or you can apply a patch to UxTheme.Dll. Patches are supplied for both XP or XP-SP1. I have been using both these patches for over a year with no problems. If you are tired of the Micosoft Luna Theme then try this. You are on your own so make backups and follow the instructions carefully.
Now for the Link: http://www.belchfire.net/article205.html





Vb menus are ANSI only.

The quick fix is to ignore Vb menus and create Unicode Owner-Draw menus at run-time. Almost all the menu source code you will find on the WEB are ANSI only but you can easily modify them to accomodate Unicode.

There are two basic types of Owner-Draw menus available:

  1. Modifies standard Vb menus to add icons, styles, etc. These are more difficult to adapt to Unicode.

  2. Create menus from scratch at run-time. Here you can easily assign Unicode captions and then handle the strings appropriately when you render them.

  3. You are also responsible for responding to WM_MEASUREITEM messages to set the menu width.


Owner-Draw Menus with Source Code

Link Uses Vb
Unicode Notes
Menu System 4.1  
CoolMenu (real icon menus)  
vbAccelerator - PopupMenu - Transparent Menu Demonstration  
vbAccelerator - Using the cNewMenu DLL to Create Start Menu/ICQ ...  
vbAccelerator - PopupMenu - Context Menu Demonstration  
Using the cNewMenu DLL to Create Start Menu/ICQ Style Pop-up ...  
CoolMenu 1.3.2  
CoolMenu (real icon menus)  
SuperCode XP  
Office XP Menus (No OCX)  
LaVolpe Submenus v2  
Update 11-Aug-2001 Enhanced VbAccelerator popup menus  
First VB Menu Ownerdraw Engine  
HookMenu 1.4 Subclassing Thunk
HookMenu 1.5 Subclassing Thunk
UniHookMenu UniSuitePlus
vbRichEdit Menus and Toolbar vbRichEdit





Download a simple demo of an MS Access database with Unicode here.
Also search MSDN or http://www.trigeminal.com for more info.

MS Access database supports Unicode and you can use:

Note that your control must be Unicode aware such as MSHFlexGrid or Forms 2.0 Object Library Controls.

Question Marks and Garbage characters instead of Arabic text:

  • As a SQL developer, you should use Unicode data types in applications. The Unicode data types are nchar, nvarchar, and ntext. These data types use Unicode character representation. Code pages do not apply to these data types. Using Unicode data types gives you the ability to deal with Arabic data even the system collation is not Arabic.
    When using Unicode data types, the best way to save your Arabic data from corruption when inserting, and updating is to add capital N before your Arabic string otherwise if the default database collation is not Arabic your data will be corrupted. When using N prefix with Unicode data types you save your Arabic data regardless the default database collation is Arabic or not. This is the golden key to deal with Unicode data types in the applications like VB, or ASP, even inside SQL server like stored procedures.

    UPDATE TableName SET ColumnName = N'Unicode Text' WHERE id = 1000
    INSERT INTO TableName (ColumnName) values(N’Unicode Text’)

  • You may want to look into SQLite3 database which uses similar syntax to Microsoft ADO.
    It is free and you can find an excellent DLL class wrapper with vbRichClient at www.vbRichClient.com

    Unicode is supported and the default is that V6 strings (already Unicode UF16-LE) are stored as UTF-8.
    Upon retrieval they are converted back to Vb6 UTF16-LE.
    This is all tranparent to the user so it "just works".

    Be sure to download and install compoents first before running and demos.

    A large SQLite3 Demo (about 1MB) using NWind database is downloadable here:



    Grid Controls

    Table of Grid Controls

    As you can see from the table below there are very few Grid Controls that are Unicode aware. This table was prepared by searching for keyword 'unicode' on Features page for each control.

    Control Unicode Aware



    sGrid2 VbAccelerator sGrid2.

    Source code provided

    VSFlexGrid Pro VSFlexGrid Pro 8.0

    A version that supports
    Unicode is also included.

    InaGrid InaGrid Supports Unicode on
    Win9x Platforms
    Exontrol ExGrid Exontrol ExGrid ANSI and UNICODE
    versions available
    Objective Grid 9.02 Rogue Wave Objective Grid for ActiveX  
    CyberActiveGrid www.cyberactivex.com


    ListView Visual Studio  
    ListView www.cyberactivex.com

    Unicode aware ListView

    MSFlexGrid Visual Studio  
    MSHFlexGrid Visual Studio  
    SCGrid SCgrid  
    Janus GridEX Janus Janus GridEx  
    True DBGrid Pro True DBGrid Pro  
    UltraGrid UltraGrid  
    Protoview Data Table(Infragistics) DataTable  
    XpressQuantumGrid and Spread XpressQuantumGrid  
    sGrid www.VbAccelerator.com

    Source code provided. Modify for Unicode

    iGrid www.10Tec.com  
    DevGrid DevGrid  
    FarPoint Spread 6 FarPoint Spread 6  
    Data Dynamics SharpGrid(#Grid) SharpGrid(#Grid)  
    CTGrid CTGrid  
    ActiveGrid ActiveGrid  
    ContourCube ContourCube  
    Data Widgets Data Widgets  
    FlyTreeX FlyTreeX  
    Gridwiz Gridwiz  
    itGrid www.it-partners.com  
    Mabry Grid/X Control www.mabry.com/gridx/  
    Rich Text Grid Control RichText Grid Control  
    TList Pro TList Pro  
    YDFGrid YDFGrid  



    Misc Source Code

    In addition to the examples already provided here are some other useful source codes:




    • UTF16 ð UTF8

    • UTF8  ð UTF16

    • UTF16 ð VB6

    • UTF8  ð VB6

    • Requires Office FM20.DLL Unicode TextBox.


    • UTF16 ð  "CHS: 欢迎"

    • UTF8  ð  "CHS: 欢迎"

    • VB6   ð  "CHS: " & ChrW$(&H6B22) & ChrW$(&H8FCE)


    • Enumerates LCID, CodePage, Months, Days, Numeric, Currency.
    • Modified for Unicode.
    • Requires Office FM20.DLL Unicode controls.
      Must have FM20ENU.DLL installed.
    • Updated 9-Dec-2003 19:03 UTC. Added Today Icon,
    • 130 Locales on WinXP-SP1 with Far East, Complex
      Scripts, and RightToLeft languages installed.


    • Enumerates all supported locales and associated timezone information including daylight savings entry and exit dates. 27 reusable Date/Time functions.
    • NOT Unicode aware. Uses Vb ANSI controls.
    • Updated 13-Nov-2003 03:10 UTC.


    • Class to create ANSI or Unicode aware Tooltip.
    • Unicode on Win98
    • RTL for Arabic, Hebrew, Urdu
    • Updated 16-Mar-2004.


    • Extract a Unicode string from resource.
    • Unlike LoadString you can specify a language.
    • Requires Office FM20.DLL Unicode controls.
      Must have FM20ENU.DLL installed.
    • Released 24-Feb-2004.


    Function to determine if RTL languages are installed courtesy of Keith LaVolpe..


    Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Long, ByVal lpProcName As String) As Long
    Private Declare Function GetModuleHandleA Lib "kernel32" (ByVal lpModuleName As String) As Long
    Private Declare Function IsValidLanguageGroup Lib "kernel32.dll" (ByVal LanguageGroup As Long, ByVal dwFlags As Long) As Long

    Public Function IsRTLCapable() As Boolean
       Const LGRPID_ARABIC As Long = &HD
       Const LGRPID_HEBREW As Long = &HC
       Const LGRPID_INSTALLED As Long = &H1

       If GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsValidLanguageGroup") Then
          If IsValidLanguageGroup(LGRPID_ARABIC, LGRPID_INSTALLED) Then
             IsRTLCapable = True
             IsRTLCapable = IsValidLanguageGroup(LGRPID_HEBREW, LGRPID_INSTALLED)
          End If
       End If
    End Function
    Function to determine if Far East languages are installed (adapted from code by Keith LaVolpe). Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Long, ByVal lpProcName As String) As Long
    Private Declare Function GetModuleHandleA Lib "kernel32" (ByVal lpModuleName As String) As Long
    Private Declare Function IsValidLanguageGroup Lib "kernel32.dll" (ByVal LanguageGroup As Long, ByVal dwFlags As Long) As Long

    Public Function IsFarEastCapable() As Boolean
       Const LGRPID_JAPANESE As Long = &H7
       Const LGRPID_KOREAN As Long = &H8
       Const LGRPID_INSTALLED As Long = &H1
       Dim i As Long

       If GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsValidLanguageGroup") Then
          For i = 7 To 10 'JPN - CHS
             If IsValidLanguageGroup(i, LGRPID_INSTALLED) Then
                IsFarEastCapable = True
                Exit For
             End If
       End If
    End Function





    You can find various functions on the WEB that attempt to identify a string as Unicode:

    Function Author Comments
    Function IsUnicode(ByVal s As String) As Boolean
       IsUnicode = Len(s) = LenB(s)
    End Function
    MSDN ?? This is useless since it always returns True. Vb5/Vb6 always stores strings internally as Unicode. This is not analyzing the string.

    Public Function IsUnicodeStr(s As String) As Boolean
       'Returns True if s evaluates to a Unicode string
       Dim dwRtnFlags As Long
       IsUnicodeStr = IsTextUnicode(ByVal s, Len(s), dwRtnFlags)
    End Function

    MSDN ?? Returns False on 17 test strings, 2 of which are ANSI and the remaining Unicode. This function is only available on WinNT or later. Also available if MSLU if installed on Win9x.

    This should work so there is probably something wrong with the implementation.

    Public Function IsUtf16(ByVal s As String) As Boolean
       Dim i As Long
       Dim lLen As Long
       Dim lAscW As Long

       lLen = Len(s)
       For i = 1 To lLen
          lAscW = AscW(Mid$(s, i))
          If lAscW < 0 Then
             lAscW = lAscW + 65536
          End If
          If (lAscW > 255) Then
             IsUtf16 = True
             Exit Function
          End If

    End Function
    CyberActiveX Returns correct status for all 17 test strings. Note that this would also return True for a MBCS string so perhaps this function should be called NOT_ANSI. Nevertheless it was written using the assumption that the client is using Unicode/ANSI.
    'Purpose:Returns True if string has a Unicode char.
    Public Function IsUnicode(s As String) As Boolean
       Dim i As Long
       Dim bLen As Long
       Dim Map() As Byte

       If LenB(s) Then
          Map = s
          bLen = UBound(Map)
          For i = 1 To bLen Step 2
             If (Map(i) > 0) Then
                IsUnicode = True
                Exit Function
             End If
       End If
    End Function
    CyberActiveX Same functionality as above but much faster.
    No Mid$ or AscW.



    Ideographic Description Characters

    These are visibly displayed graphic characters, not invisible composition controls.

    We are in the process of replacing the bitmaps with the actual characters if we can find them(Example of IDS, IDS Example Represents Char). We would appreciate any help from native Chinese speakers.


    Hex Char Font


    Example of IDS Example of IDS
    IDS Example
    IDS Example




    3 从从日 OK  




    2 凵 土 OK  


    2 广  




    2FFB OVERLAID 2 从工 OK OK 巫



    Surrogate Pairs

    Supplementary Characters (Surrogate pairs)

    There are two terms that describe the concept of surrogates more accurately:

    Surrogates or surrogate characters are misnomers because encoded characters cannot have a surrogate code point.

    For more information, visit the Unicode Consortium's website, http://www.unicode.org.


    Char Vb String Codepoint Unicode Block Font
    𠁎 ChrW$(&HD840) & ChrW$(&HDC4E) 2004E CJK Unified Ideographs Extension B DFSongStd

    In order to see Surrogate Pairs you must have a font which contains the characters you desire to render:

    'An example of a surrogate character from CJK extension B is (U+20001, or U+D840 U+DC01 in surrogate code point format).
    According to Dr. International:http://www.microsoft.com/globaldev/drintl/columns/015/default.mspx#Q13
    The SimSun18030 font (simsun18030.ttc) in the GB18030 support package does not have the complete GB18030 repertoire. It is missing the entire CJK Extension B set, as well as other characters. It does have, however, CJK Extension A.
    A font that contains Simplified Chinese glyphs from both CJK Extension A and B sets is "SimSun (Founder Extended)" (SurSong.ttf in the system), or 宋体–方正超大字符集 (in Chinese). It is currently available in the Simplified Chinese (CHS) version of Office XP, or the Microsoft Office Proofing Tools. Click the link for more information and how to buy.

    Here are several Functions for working with Surrogate Pairs::

    Download modSurrogate:

    Public Function CodepointToSurrogatePair(ByVal lChar As Long) As String
    Public Function ShowHexW(ByVal s As String) As String
    Public Function SurrogatePairToCodepoint(HiSurrogate As Integer, LoSurrogate As Integer) As Long
    Public Function IsHiSurrogate(ch As Integer) As Boolean
    Public Function IsLoSurrogate(ch As Integer) As Boolean
    Public Function UnsignedToInteger(Value As Long) As Integer
    Public Function IntegerToUnsigned(Value As Integer) As Long


    72 8 Aug 03 The Unicode Standard 4.0

    3.8 Surrogates

    D25 High-surrogate code point: A Unicode code point in the range U+D800 to U+DBFF.
    D25a High-surrogate code unit: A 16-bit code unit in the range D80016 to DBFF16, used in UTF-16 as the leading code unit of a surrogate pair.
    D26 Low-surrogate code point: A Unicode code point in the range U+DC00 to U+DFFF.
    D26a Low-surrogate code unit: A 16-bit code unit in the range DC0016 to DFFF16, used in UTF-16 as the trailing code unit of a surrogate pair.

    • High-surrogate and low-surrogate code points are designated only for that use.

    Conformance 3.9 Unicode Encoding Forms

    • High-surrogate and low-surrogate code units are used only in the context of the UTF-16 character encoding form.

    D27 Surrogate pair: A representation for a single abstract character that consists of a sequence of two 16-bit code units, where the first value of the pair is a high-surrogate code unit, and the second is a low-surrogate code unit.

    • Surrogate pairs are used only in UTF-16. (See Section 3.9, Unicode Encoding Forms.)

    • Isolated surrogate code units have no interpretation on their own. Certain other isolated code units in other encoding forms also have no interpretation on their own. For example, the isolated byte 8016 has no interpretation in UTF-8; it can only be used as part of a multibyte sequence. (See Table 3-6.)

    • Sometimes high-surrogate code units are referred to as leading surrogates. Low-surrogate code units are then referred to as trailing surrogates. This is analogous to usage in UTF-8, which has leading bytes and trailing bytes.

    • For more information, see Section 15.5, Surrogates Area, and Section 5.4, Handling Surrogate Pairs in UTF-16.




    There is a common misconception that VbDate is a string. This is probably due to the fact that when you hover over a VbDate in the IDE you will see a formatted date(short date format). It is actually a double in disguise where the integer portion represents the date and the fractional(decimal) portion is the time of day. If a VbDate is applied to a label caption or textbox it will display the date as short date as defined in your regional configurations.

    You can coerce a VbDate into a double by using code such as "Cdbl(Now)"

    With all the Vb hacks needed to make things work in Unicode it is a pleasant surprise that Format$ with a date argument and FormatDateTime$ are Unicode aware. The problem lies in displaying these string values so you must use a Unicode aware control. If you don't have a Unicode control handy and you are using NT or later then you can simply use a Vb PictureBox and DrawTextW to display the results.

    Sample code:

    m_Text= "Hello World"

    Private Sub picCanvas_Paint()
    End Sub

    Private Sub UpdateCanvas()
       Const DT_WORDBREAK As Long = &H10&
       Dim rct as RECT
       SetRect rct, 3, 3, picCanvas.ScaleWidth - 3, picCanvas.ScaleWidth - 3
       DrawTextW picCanvas.hDC, StrPtr(m_Text), -1, rct, DT_WORDBREAK
    End Sub

    MSDN: Visual Basic 6.0

    Date variables are stored as IEEE 64-bit (8-byte) floating-point numbers that represent dates ranging from 1 January 100 to 31 December 9999 and times from 0:00:00 to 23:59:59. Any recognizable literal date values can be assigned to Date variables. Date literals must be enclosed within number signs (#), for example, #January 1, 1993# or #1 Jan 93#.

    Date variables display dates according to the short date format recognized by your computer. Times display according to the time format (either 12-hour or 24-hour) recognized by your computer.

    When other numeric types are converted to Date, values to the left of the decimal represent date information while values to the right of the decimal represent time. Midnight is 0 and midday is 0.5. Negative whole numbers represent dates before 30 December 1899.




    Here are several methods of Reading and Writing Unicode Files:
    This code has been superseeded by FileReader.

    Download modUnicodeRW:

    Method Operation Function
    VB Read Public Function UnicodeFile_Read_VB(ByVal sFileName As String, Optional ByVal bRemoveBOM As Boolean) As String
    Write Public Sub UnicodeFile_Write_VB(ByVal sFileName As String, ByVal sText As String, Optional ByVal bInsertBOM As Boolean)
    FSO(Scripting) Read Public Function UnicodeFile_Read_FSO( ByVal sFileName As String, Optional ByVal TriState As TristateEnum = TristateTrue) As StringPublic Function UnicodeFile_Read_API(ByVal sFileName As String) As String
    Write Public Sub UnicodeFile_Write_FSO( ByVal sFileName As String, ByVal sText As String, Optional ByVal ForWrite As ForWriteEnum = ForWriting, Optional ByVal TriState As TristateEnum = TristateTrue)
    API Read Public Function UnicodeFile_Read_API(ByVal sFileName As String) As String
    Write Public Function UnicodeFile_Write_API(ByVal sFileName As String, ByVal sText As String) As Boolean

    Sometimes your file is saved in the old DOS 8.3 covention, aka shortname. This is frustrating and you certainly wouldn't want to display a short filename to a user. The solution is API which can convert to and from short/long pathnames.

    Download modPathName:

    Method Function
    API Public Function GetShortName(ByVal sLongFileName As String) As String
    Public Function GetLongName(ByVal sShortFileName As String) As String



    VbAccelerator ListView/TreeView

    Due to several requests on various Forums here are some basic instructions on how to enable Unicode in VbAccelerator ListView/TreeView controls. Note that this is just the basics to enable Unicode in LV cells and TV items. It does not include the extra support for LV Header, Column Sorting, or RightToLeft.



    Set Conditional compile to "UNICODE = -1"

    Line Old New
    529 .pszText = sText .pszText = StrPtr(sText)
    547 .sText = sText .sText = StrPtr(sText)
    1379 m_tLV.pszText = sBuf m_tLV.pszText = StrPtr(sBuf)
    1422 m_tLV.pszText = sBuf m_tLV.pszText = StrPtr(sBuf)
    1425 LSet m_tLV.pszText = sText & Chr$(0) m_tLV.pszText = StrPtr(sText)
    1785 tLV.pszText = sText & vbNullChar tLV.pszText = StrPtr(sText)
    1937 tLBI.pszImage = sURL & Chr$(0) tLBI.pszImage = StrPtr(sURL)



    CHANGE DrawTextA to DrawTextW. Use StrPtr() in DrawTextW calls.
    ADD Private Const TVM_INSERTITEMW = (TV_FIRST + 50)
    ADD Private Type TVITEMEXW
       mask As Long
       hItem As Long
       State As Long
       stateMask As Long
       pszText As Long
       cchTextMax As Long
       iImage As Long
       iSelectedImage As Long
       cChildren As Long
       lParam As Long
       iIntegral As Long
    End Type
       hParent As Long
       hInsertAfter As Long
       Item As TVITEMEXW
    End Type
    CHANGE TVIN.Item.pszText = StrPtr(sText)
    CHANGE in pInitialize use StrPtr() for strings.




    You can save registry files either in text or Unicode format, but versions of Windows earlier than Win2K can't recognize Unicode files, so for those OS versions, you need to save the files in text format. In XP and Win2K, the registry editor is version 5, which you'll find specified in the first line of the exported registry file, which reads "Windows Registry Editor Version 5.00." Changing this header line (you can use a text editor such as notepad.exe to do so) to read REGEDIT4 will make the file compatible with earlier Windows OSs.

    Since registry entries(Keys, Values) under Windows Registry 5.0 format can be Unicode you need to use the Wide versions of AdvApi32.DLL to manipulate keys and values. If you want to make a RegEdit clone you will also need Unicode aware versions of TreeView/ListView to render Unicode keys and values.

    This snippet shows how one would implement registry functions that can run on all Platforms. We create a "Public Function RegOpenKeyEx" and then call the ANSI or Wide API versions as appropriate.

    Private Declare Function RegOpenKeyExA Lib "advapi32" (ByVal hkey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, ByVal samDesired As Long, phkResult As Long) As Long
    Private Declare Function RegOpenKeyExW Lib "advapi32" (ByVal hkey As Long, ByVal lpSubKey As Long, ByVal ulOptions As Long, ByVal samDesired As Long, phkResult As Long) As Long

    'Purpose: ANSI/Unicode wrapper.
    Public Function RegOpenKeyEx(ByVal hkey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, ByVal samDesired As Long, phkResult As Long) As Long
       If Is2000 Then
          RegOpenKeyEx = RegOpenKeyExW(hkey, StrPtr(lpSubKey), ulOptions, samDesired, phkResult)
          RegOpenKeyEx = RegOpenKeyExA(hkey, lpSubKey, ulOptions, samDesired, phkResult)
       End If
    End Function


    If you plan on writing you own Registry class here is a wish list of features available in RegEdit and some commercial Registry Editors:




    "According to Microsoft" Windows 95 and 98 were built upon 3.1, and they don't support Unicode. All applications written for Windows 98 should be ANSI applications.

    Actually Windows 98 has a handful of Unicode APIs, which are listed in the below table. Other than these functions, the system DLLs for Windows 98 have export symbols for wide character functions as well, but they all return FALSE, and GetLastError would return ERROR_CALL_NOT_IMPLEMENTED which is defined as 120.

    Unicode functions implemented on Windows 98

    EnumResourceLanguagesW GetTextExtentPoint32W
    EnumResourceNamesW GetTextExtentPointW
    EnumResourceTypesW lstrlenW
    ExtTextOutW MessageBoxExW
    FindResourceW MessageBoxW
    FindResourceExW TextOutW
    GetCharWidthW WideCharToMultiByte
    GetCommandLineW MultiByteToWideChar

    What is really missing in Win98 and necessary for serious work is the DrawTextW API:
    Private Declare Function DrawTextW Lib "user32" (ByVal hdc As Long, ByVal lpStr As Long, ByVal nCount As Long, lpRect As rect, ByVal wFormat As Long) As Long

    To get this in Win98 you will need to write a Uniscribe Wrapper that will emulate this function. This is not an easy task since there are 24 DrawText Alignment Flags that can be combined to specify how the text is to be formatted within the bounding rectangle.

    Example of how to integrate the wrapper:

    Public Sub DrawTextU(ByVal sText As String, ByRef rct as Rect, ByVal lFlags As Long)
       Dim lPtr As Long

       If (LenB(sText) = 0) Then Exit Sub

       If (IsNT) Then
          lPtr = StrPtr(sText)
          If Not (lPtr = 0) Then
             DrawTextW hdc, lPtr, -1, rct, lFlags
          End If
       Else 'Win9x
          If IsUnicode(sText) Then
             'Call Uniscribe Wrapper here
             DrawTextA hdc, sText, -1, rct, lFlags
          End If
       End If
    End Sub




    Vb6 strings are stored internally as Unicode ((Integer 0-65535)) with 2 bytes per character. While there is internal code to cast from string to byte array there is no function to cast a string to a integer array.
    Here is code that does this.


    "Hello" (ANSI) "JPN: ようこそ" (ANSI + Unicode)



    Byte Array

    A Byte Array is an array of bytes that starts at LBound(usually 0 unless you change Option Base) and ends at UBound. Here are some examples:

    String Conversion


    Hello b = StrConv(s, vbFromUnicode) H 72
    e 101
    l 108
    l 108
    0 111
    ANSI byte array of an ANSI string.
    Hello b = s H 72
    e 101
    l 108
    l 108
    o 111
    Unicode byte array of an ANSI string.
    CHS: 欢迎 b = s C  67
    H  72
    S  83
    :  58
    欢 34
    迎 206
    Unicode byte array of an Unicode string.
    CHS: 欢迎 b = StrConv(s, vbFromUnicode) C 67
    H 72
    S 83
    : 58
    ? 63
    ? 63
    ANSI byte array of an Unicode string. Note that the 2 Unicode characters are now replaced by "?"

    An important note is that a Vb string ends with a null byte which is Chr$(0). A byte array ends with the last character of the string and has no null byte.

    OK so Byte Arrays can also be used to load raw data such as WAV, GIF, JPG from resources. The Byte Array is then written to a temp file and then loaded back using LoadPicture(). In the case of WAV you can use the following Declare to pass a byte array:
    Private Declare Function PlaySoundData Lib "winmm.dll" Alias "PlaySoundA" (lpData As Any, ByVal hModule As Long, ByVal dwFlags As Long) As Long

    A better way to eliminate the temp file is to use IStream which is addressed in the next topic.



    Vb Get/Put

    If you try to use Get/Put to write Unicode strings they are changed to ANSI via the Put method.

    Put appears to use a proprietary format to write UDT data which is then readable by Get.
    If you would like to study more about how this works in Vb6 see the link:

    It is also interesting that VB's Put and Get command were built to be pretty smart. We know that complex UDTs(such as "s As String" or "b() As Byte") aren't stored in memory as a continuous block, however the VB Put command is kind enough to pack the whole structure and data into a new format for us so that it is complete when dumping it to disk.



    Public Type MyType
       s As String
       i As Integer
       L as Long
    End Type

    Public Function UnicodeFile_Write_Vb_UDT(ByVal sFileName As String, _
    vArray() As MyType) As Boolean

       Dim FF As Integer
       Dim ArraySize As Long

       On Error Resume Next

       If Dir$(sFileName) Then
          Kill sFileName
       End If

       ArraySize = UBound(vArray) - LBound(vArray)

       FF = FreeFile
       Open sFileName For Binary As #FF
       Put #FF, , ArraySize
       Put #FF, , vArray
       Close #FF

    End Function

    Public Function UnicodeFile_Read_Vb_UDT(ByVal sFileName As String) As MyType()

       Dim FF As Integer
       Dim ArraySize As Long
       Dim MyArray() As MyType

       FF = FreeFile
       Open sFileName For Binary As #FF
       Get #FF, , ArraySize
       ReDim MyArray(ArraySize)
       Get #FF, , MyArray
       Close #FF
       UnicodeFile_Read_Vb_UDT = MyArray

    End Function

    The solution for Unicode is simple. Just change the UDT to:

       b() As Byte
       i As Integer
       L as Long
    End Type

    Example (Write): MyArray(0).b = "CHS: " & ChrW$(&H6B22) & ChrW$(&H8FCE)
    Example (Read): MyString =  MyArray(0).b

    Now that strings are stored as a byte array they will not be corrupted and you can use Get/Put for Unicode strings in UDTs.



    Many people shy away from IStream because they think it is too complex to implement or requires a Type Library. Neither is true. That is of course assuming you do not require the full repetoire of IStream Read/Seek, etc.

    Where would you use IStream? A good example would be reading a Byte Array from a CUSTOM resource such as Jpg or Gif. Normally you would write the Byte Array to a temp file and then read it back in via LoadPicture().
    This is very ineffiecient for the following reasons:

    Another place to use IStream is in conjunction with BLOBs from a Database. They could be strings or pictures. In any case you read the data into a Byte Array, convert to IStream, and finally pass it to a function that accepts Istream.

    In the example here we are loading data from a Byte Array. This could be for example LoadResData from a CUSTOM resource such as Jpg or Gif. Almost all examples on the Web use a TLB but here we will define IStream here as IUnknown. Also note that the Declares use "As Any". Note that this sample code is used where IStream is required for input as in GDI+ CreateBitmapFromIStream. You also need to tweak the GDI+ Declares that use IStream to type IUnknown.

    Sample Code

    Public Declare Function GdipLoadImageFromStream Lib "GDIPlus" (ByVal stream As IUnknown, Image As Long) As GpStatus
    Public Declare Function GdipSaveImageToStream Lib "GDIPlus" (ByVal Image As Long, ByVal stream As IUnknown, clsidEncoder As CLSID, encoderParams As Any) As GpStatus
    Private Declare Function CreateStreamOnHGlobal Lib "ole32.dll" (ByRef hGlobal As Any, ByVal
    fDeleteOnResume As Long, ByRef ppstr As Any) As Long

    Public Function ByteArrayToStream(ByRef b() As Byte) As IUnknown
       On Error GoTo EH
       CreateStreamOnHGlobal b(0), True, ByteArrayToStream
       Exit Function
       Debug.Print "Could not convert ByteArray to Stream!"
    End Function

    OK. This works where you require a stream but what about StdPicture objects. Not that much more complicated in that you need to prefix a picture header to the byte array and call OleCreatePictureIndirect. CopyMemory API is used to put this together.

    Sample Code

    NOTE: This uses an IStream TLB.

    Public Function Array2Picture(aBytes() As Byte) As StdPicture
       Dim oIPS As IPersistStream
       Dim oStream As IStream
       Dim hGlobal As Long
       Dim lPtr As Long
       Dim lSize As Long
       Dim Hdr As PictureHeader

       Set Array2Picture = New StdPicture ' Create a new empty picture object
       Set oIPS = Array2Picture ' Get the IPersistStream interface
       lSize = UBound(aBytes) - LBound(aBytes) + 1 ' Calculate the array size
       hGlobal = GlobalAlloc(GHND, lSize + Len(Hdr)) ' Allocate global memory
       If hGlobal Then
          lPtr = GlobalLock(hGlobal) ' Get a pointer to the memory
          Hdr.Magic = PictureID ' Initialize the header
          Hdr.Size = lSize
          CopyMemory ByVal lPtr, Hdr, Len(Hdr) ' Write the header
          CopyMemory ByVal lPtr + Len(Hdr), aBytes(0), lSize ' Copy the byte array to the global memory
          GlobalUnlock hGlobal ' Release the pointer
          Set oStream = CreateStreamOnHGlobal(hGlobal, True) ' Create a IStream object with the global memory
          oIPS.Load oStream ' Load the picture from the stream
          Set oStream = Nothing ' Release the IStream object
       End If
    End Function

    Public Sub Picture2Array(ByVal oObj As StdPicture, aBytes() As Byte)
       Dim oIPS As IPersistStream
       Dim oStream As IStream
       Dim hGlobal As Long
       Dim lPtr As Long
       Dim lSize As Long
       Dim Hdr As PictureHeader

       Set oIPS = oObj ' Get the IPersistStream interface
       Set oStream = CreateStreamOnHGlobal(0, True) ' Create a IStream object on global memory
       oIPS.Save oStream, True ' Save the picture in the stream
       hGlobal = GetHGlobalFromStream(oStream) ' Get the global memory handle from the stream
       lSize = GlobalSize(hGlobal) ' Get the memory size
       lPtr = GlobalLock(hGlobal) ' Get a pointer to the memory
       If lPtr Then
          lSize = lSize - Len(Hdr)
          ReDim aBytes(0 To lSize - 1)
          CopyMemory aBytes(0), ByVal lPtr + Len(Hdr), lSize ' Copy the data to the array
       End If
       GlobalUnlock hGlobal ' Release the pointer
       Set oStream = Nothing ' Release the IStream object
    End Sub




    These are the basics of how to make a Unicode aware calendar control. You can use the ComCtl32.Dll derived DTPicker or MonthCal but this will only display a calendar for the current LCID set in Control Panel/ Regional Settings.

    To make a calendar that will work for any LCID:

    Note that Vb supports both Gregorian and Hijri Calendars via VBA.Calendar = vbCalGreg or VBA.Calendar = vbCalHijri





    http://www.unicode.org/ describes the "Unicode Collation Algorithm" at UTS #10- Unicode Collation Algorithm, and this link provides further information http://www.answers.com/topic/unicode-collation-algorithm, however Microsoft does not use the "Unicode Collation Algorithm" as indicated at  http://blogs.msdn.com/michkap/archive/2004/11/28/271121.aspx.

    In Visual Basic many sort algorithms are implemented using comparisons like "If String1 < String2 Then"(it is unclear what this actually does, Unicode or at worse just the low byte of Unicode character).

    StrComp Mode Usage
    StrComp(S1,S2,vbBinaryCompare) Compares string S1 and S2 based on their Unicode values.
    StrComp(S1,S2,vbTextCompare) Compares string S1 and S2 in a locale-dependent, case-insensitive way.

    As it turns out Japanese for example will be sorted correctly (http://blogs.msdn.com/michkap/archive/2004/12/27/332618.aspx) using StringCompareW even if you do not pass the Japanese LCID, 1041. "The world is in the proper アアあイイいウウうエエえオオお order (in the traditional AIUEO order, Halfwidth Katakana followed by Fullwidth Katakana followed by Hiragana). "

    'Valid dwCmpFlags
    Const NORM_IGNORECASE As Long = &H1 'Ignore case.
    Const NORM_IGNOREKANATYPE As Long = &H40 'Do not differentiate between Hiragana and Katakana characters. Corresponding Hiragana and Katakana characters compare as equal.
    Const NORM_IGNORENONSPACE As Long = &H2 'Ignore nonspacing characters.
    Const NORM_IGNORESYMBOLS As Long = &H4 'Ignore symbols.
    Const NORM_IGNOREWIDTH As Long = &H8 'Do not differentiate between a single-byte character and the same character as a double-byte character.
    Const SORT_STRINGSORT As Long = &H1000 'Treat punctuation the same as symbols.

    'Default Locale
    Const LOCALE_SYSTEM_DEFAULT As Long = &H800
    Const LOCALE_USER_DEFAULT As Long = &H400


    Declare Function CompareStringA Lib "kernel32.dll" ( _
        ByVal Locale As Long, _
        ByVal dwCmpFlags As Long, _
        ByVal lpString1 As String, _
        ByVal cchCount1 As Long, _
        ByVal lpString2 As String, _
        ByVal cchCount2 As Long) As Long
    Declare Function CompareStringW Lib "kernel32.dll" ( _
        ByVal Locale As Long, _
        ByVal dwCmpFlags As Long, _
        ByVal lpString1 As Long, _
        ByVal cchCount1 As Long, _
        ByVal lpString2 As Long, _
        ByVal cchCount2 As Long) As Long




    Several subclassers are available ranging from the classic SSubTmr6 by VbAccelerator.com to several available on Planet Source Code such as SelfSub, SelfHook, SelfCallback by Paul Caton.

    For the most part they work fine except when the hWnd you are subclassing is a Unicode window. You can detect this automatically in your subclassing code using API IsWindowUnicode(hWnd). If the result is True then you must use the Wide API calls or else your window will be changed to ANSI.

    It may not be necessary to wrap all of the API calls (GetPropW, SetPropW, RemovePropW, GetWindowLongW, SetWindowLongW, CallWindowProcW), however the SetWindowLongW is mandatory since your window will revert to ANSI if you use SetWindowLongA.

    Private Declare Function IsWindowUnicode Lib "user32" (ByVal hwnd As Long) As Long

    Demonstrates native Windows subclassing method with no risk of improper teardown. Very flexible!


    FileNames via DragDrop or Paste


       Keith LaVolpe

    Keith LaVolpe was kind enough to provide this code to Get Unicode Filenames via DragDrop or Paste(Clipboard).
    Here is the code.




    If you have already tried to print Unicode using the Vb Printer Object you already know that it is ANSI only.

    Here are several options:









    Chilkat Software http://www.example-code.com/vb/unicode.asp

    Unicode Visual Basic Examples

    Unicows.DLL Download http://www.microsoft.com/data. Microsoft Layer for Unicode Technology (Unicows.DLL)
    GDIplus.DLL Download



    • XP and Win2000(SP3) platforms already have this Dll pre-installed. Users of other platforms can install it free from Microsoft®.
    • Release Date: 19-September-2001
    • Version: 3097
    • Size: 1073 Kb
    General Unicode http://www.unicode.org  
    * Unicode Conversions in Vb6 http://www.vovisoft.com/unicode/UniFunctions.htm Unicode Conversion
    * Zip Download http://www.vovisoft.com/unicode/UniTextInOut.zip Vb6 Unicode Conversion source code
    Owner/Custom Draw Unicode ActiveX Grid http://www.unisuite.com Screenshots, Docs, Features.
    COMMCTRL.TLB www.domaindlx.com/e_morcillo/ comctl32.dll 5.8 Type Library
    UTF http://czyborra.com/utf/ Unicode Transformation Formats
    MSLU Newsgroup microsoft.public.platformsdk.mslayerforunicode Info about MS Layer for Unicode
    MSLU: reported bugs and known issues http://trigeminal.com/usenet/usenet035.asp Maintained by an employee of Microsoft who is the principal developer for MSLU
    Sample code and other info http://www.trigeminal.com "Internationalization with Visual Basic" by Michael S. Kaplan
    DrInternational Columns http://www.microsoft.com/globaldev/DrIntl/columns/default.mspx
    World-Ready Software Example http://www.microsoft.com/globaldev/tools/wrapp.mspx C++

    * UTF16 to UTF8 works(although not optimized) and UTF8 to UTF16 is not 100% correct so I suggest using the modified versions here.

    Related resources





    The most common problem with Unicode controls is the infamous display of "??" or boxes "▯▯" . It can usually be traced to one or more of the following areas:


    Vb6 on non-English Machines

    This has come up several times in various Forums. Running Vb6 on non-English machines may seem confusing to U.S. English users.
    Is it Unicode? No, it is MBCS in a Vb6 ANSI code window.

    On Chinese machine you see: CHS: 欢迎 in Vb6 ANSI code window.
    On U.S. machine you see: CHS: »¶Ó­ in Vb6 ANSI code window. This looks like junk but it is MBCS equivalent of CHS: 欢迎 using codepage 936.

    On Greek machine you see Clipboard.SetText "αβγ" in Vb6 ANSI code window.
    On U.S. machine you see Clipboard.SetText "áâã" in Vb6 ANSI code window. This looks like junk but it is MBCS equivalent of "αβγ" using codepage 1253.

    How is that a Chinsese or Greek machine display and set strings in the Vb IDE window in their language? The Vb IDE is ANSI but setting the Font.charset to Chinese allows Chinese users to type in Chinese. This is not Unicode though, it is MBCS. If you download a Vb project from a Chinese site and run it on a U.S. machine you will see comments and strings as unreadable bytes. These bytes though are perfectly good MBCS. If you were to reboot you machine in Chinese(non-Unicode program language default) you can now see readable Chinese.
    What happens to data sent to the clipboard using Vb clipboard object when using a Chinsese or Greek machine? It appears as though the MBCS strings in program  are sent to the clipboard as follows:
    Format Data Comments
    CF_TEXT CHS: »¶Ó­ MBCS using current Code Page.
    CF_UNICODETEXT CHS: 欢迎 It appears that the MBCS is converted to Unicode and placed on the clipboard

    Here are several links that explain this somewhat confusing issue:

    Title Link
    Display Unicode Strings in Visual Basic 6.0 http://www.example-code.com/vb/vbUnicode1.asp
    Display Japanese in VB6 on Any Computer Regardless of Locale http://www.example-code.com/vb/vbUnicode1.asp
    VB, VBLM & Unicode http://www.whippleware.com/VBLM/webhelp/vblm/vb__vblm___unicode.htm



    FarEast on English Machine

    The easiesr way to get FarEast support is to set Regional Config - Language for non-Unicode programs) to your desired language,

    Here is one way to get Far East support in Vb6 IDE without rebooting into another language .

    NJStar Communicator will allow all ANSI programs (not just Vb6) to support Chinese and other Far East languages.
    The second Debug.Print "CHS: 欢迎" statement below was actually pasted from a Unicode string in a Notepad file.
    Also note Caption Property in Proprties Window as "NJSTAR CHS: 欢迎"
    Priced as US$ 99 this might be useful for using a single Far East language in conjunction with English application.
    Note that this is NOT Unicode since the Vb Wndows are ANSI.




    Where's the Beef (Unicode)

    Your running XP but your control looks like this when displaying Unicode:
    This is no longer an issue for Vista or later where full Unicode support is installed by default.


    Windows XP Windows 7

    Solution. You need to install the Optional Far East and RightToLeft languages.
    On XP go to Control Panel, Regional and Language Settings, Language Tab.
    Check both boxes for Suplemental Language Support.

    You wil be prompted to insert your XP installation CD to update your system to include this support.




    APIs are usually defined something like this:
       Private Declare Function DrawTextA Lib "user32.dll" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, ByRef lpRect As RECT, ByVal wFormat As Long) As Long
       Private Declare Function DrawTextW Lib "user32.dll" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, ByRef lpRect As RECT, ByVal wFormat As Long) As Long

    When calling the above DrawTextW the string is converted to ANSI.

    Knowing that Vb will convert the Unicode string when calling the API we convert the already Vb Unicode string to "DoubleUnicode" via StrConv.
    When the API is called the "DoubleUnicode" is converted to "Unicode".
    While this method works it is inefficient since it involves 2 conversions and should probably be considered as a unnecessary hack.
       sUni = "CHS: " & ChrW$(&H6B22) & ChrW$(&H8FCE)
       DrawTextW Me.hdc, StrConv(sUni, vbUnicode), -1, rct, lFlags

    If API DrawTextW was declared inside a Type Library(TLB) then we could call it directly like this:
       DrawTextW Me.hdc, sUni,, -1, rct, lFlags

    The best way to do this in Vb6 when the API is declared in your application is the just change the Wide API String to Long and use StrPtr:
       Private Declare Function DrawTextW Lib "user32.dll" (ByVal hdc As Long, ByVal lpStr As Long, ByVal nCount As Long, ByRef lpRect As RECT, ByVal wFormat As Long) As Long
       DrawTextW Me.hdc, StrPtr(sUni),, -1, rct, lFlags

    To make matters worse, wide API with a String parameter and usage of StrConv will return garbage in lieu of correct Unicode on a Japanese OS.. You can reproduce this error by setting your U.S. English OS to Japanese for non-Unicode programs via Regional Configurations and restarting your computer.

    Run this sample code to see the error with GetLocaleInfoW:

    This will work:
       Private Declare Function GetLocaleInfoW Lib "kernel32" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpData As Long, ByVal cchData As Long) As Long
    This will not:
       Private Declare Function GetLocaleInfoW Lib "kernel32" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpData As String, ByVal cchData As Long) As Long




    Often we need a quick solution for displaying a Unicode string without using a Unicode aware control.
    Vb MsgBox or Debug.Print will not display Unicode but this ShellMsgBox will.
    Placing this function is a Module will allow it to override the Vb6 ANSI MsgBox.

    If for some reason you don't see Unicode using ShellMsgBox you may be missing FarEast, complex script, or RTL support.
    See Where's the Beef.

    For a version that uses Windows API MessageBoxIndirectW see sample code in UniToolKit.


    VarPtr for API UDT

    The old method for adapting fixed-length string in UDT for use with API was to use byte arrays.


    Fixed-length string Byte Array
    Private Type WIN32_FIND_DATA
       dwFileAttributes As Long
       ftCreationTime   As Currency
       ftLastAccessTime As Currency
       ftLastWriteTime  As Currency
       nFileSizeBig     As Currency
       dwReserved0      As Long
       dwReserved1      As Long
       cFileName        As String * MAX_PATH '260
       cShortFileName   As String * 14
    End Type
    Private Type WIN32_FIND_DATA
       dwFileAttributes   As Long
       ftCreationTime     As Currency
       ftLastAccessTime   As Currency
       ftLastWriteTime    As Currency
       nFileSizeBig       As Currency
       dwReserved0        As Long
       dwReserved1        As Long
       cFileName(519)     As Byte
       cShortFileName(27) As Byte
    End Type

    Newer method to prevent ANSI conversion of Unicode strings:

    Fixed-length string
    Private Type WIN32_FIND_DATA
       dwFileAttributes As Long
       ftCreationTime   As Currency
       ftLastAccessTime As Currency
       ftLastWriteTime  As Currency
       nFileSizeBig     As Currency
       dwReserved0      As Long
       dwReserved1      As Long
       cFileName        As String * MAX_PATH '260
       cShortFileName   As String * 14
    End Type

    API that use this UDT must be modified to Byval Long as in this example:

    Old Private Declare Function FindFirstFileW Lib "kernel32" (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) As Long
    Private Declare Function FindNextFileW Lib "kernel32" (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) As Long
    New Private Declare Function FindFirstFileW Lib "kernel32" (ByVal lpFileName As Long, ByVal lpFindFileData As Long) As Long
    Private Declare Function FindNextFileW Lib "kernel32" (ByVal lpFileName As Long, ByVal lpFindFileData As Long) As Long

    Example call for this API:

    Dim wFD As WIN32_FIND_DATA
    Dim lPtr As Long
    lPtr = VarPtr(wFD)
    lHandle = FindFirstFileW(StrPtr(sPath & sPattern), lPtr)
    Loop While FindNextFileW(lHandle, lPtr) > 0



    Ini File

    For Unicode aware INI files you need to create an empty file with a Unicode BOM marker before writing keys.

    This wrapper code will automatically create an empty Unicode file and allow read/write of keys.
    Also includes functions DeleteKey, DeleteSection and ReadSections.




    Support Unicode in Crypto Utilities:

    Most Vb6 crypto utilities were written with ANSI only support. After all the Vb6 TextBox and standard file I/O are ANSI only.
    Typical code will use StrConv which  removes the upper byte:

    Dim b() As Byte
    b = StrConv("Hello World", vbFromUnicode)

    Now let's try to support Unicode by preserving all bytes:

    Dim b() As Byte
    b = "Hello World")

    The above code is OK when the string is Unicode but not efficient if there are many characters within the range 0-255.

    Here comes UTF-8 to the rescue. ANSI Characters 0-127 are 1 byte, characters with diacritics (accents) and Unicode characters are 2 to 4 bytes.
    UTF-8 is pretty much the standard when it comes to Web Pages and Cloud storage.

    In summary we will convert Vb6 strings to a UTF-8 byte array before passing it to Hash/Hmac/Encrypt functions.

    When working with files though we don't know the content so we must treat them all as binary (byte arrays).

    To automate crypto functions to handle both UTF-8 and byte arrays we can use a Variant.
    If the Variant is a string then we convert it to a UTF-8 byte array.
    If the Variant is already a byte array then use as is. Any other Variant format raises an error.

    Option Explicit
    Const vbByteArray As Long = vbByte Or vbArray
    Const CP_UTF8     As Long = 65001
    Private Declare Function MultiByteToWideChar Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpMultiByteStr As Long, ByVal cbMultiByte 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, ByVal lpUsedDefaultChar As Long) As Long
    Private Function VarToByte(ByRef vData As Variant) As Byte()
       On Error GoTo ErrHandler
       Select Case VarType(vData)
          Case vbString
             If Len(vData) Then
                VarToByte = ToUTF8(vData)
                Err.Raise Err.LastDllError, "VarToByte", "vData String is empty"
             End If
          Case vbByteArray
             If IsInitialized(vData) Then
                VarToByte = vData
                Err.Raise Err.LastDllError, "VarToByte", "Array not dimensioned "
             End If
          Case Else
             Err.Raise Err.LastDllError, "VarToByte", "vData must be a byte array or string "
       End Select
       Exit Function
       Err.Raise Err.LastDllError, "VarToByte", "Array Error"
    End Function
    Private Function IsInitialized(aArray As Variant) As Boolean
       On Error GoTo Uninitialized
       IsInitialized = UBound(aArray) >= 0
    End Function
    Public Function FromUTF8(ByRef Utf8() As Byte) As String
       Dim lngOutLen        As Long
       Dim strWide          As String
       lngOutLen = MultiByteToWideChar(CP_UTF8, 0, VarPtr(Utf8(LBound(Utf8))), UBound(Utf8) - LBound(Utf8) + 1, 0, 0)
       If lngOutLen = 0 Then
          Err.Raise Err.LastDllError, "FromUTF8", "MultiByteToWideChar"
          strWide = String$(lngOutLen, 0)
          lngOutLen = MultiByteToWideChar(CP_UTF8, 0, VarPtr(Utf8(LBound(Utf8))), UBound(Utf8) - LBound(Utf8) + 1, StrPtr(strWide), lngOutLen)
          If lngOutLen = 0 Then
             Err.Raise Err.LastDllError, "FromUTF8", "MultiByteToWideChar"
             FromUTF8 = strWide
          End If
       End If
    End Function
    Public Function ToUTF8(ByVal Text As String) As Byte()
       Dim lngOutLen        As Long
       Dim Utf8()           As Byte
       lngOutLen = WideCharToMultiByte(CP_UTF8, 0, StrPtr(Text), Len(Text), 0, 0, 0, 0)
       If lngOutLen = 0 Then
          Err.Raise Err.LastDllError, "ToUTF8", "WideCharToMultiByte"
          ReDim Utf8(lngOutLen - 1)
          WideCharToMultiByte CP_UTF8, 0, StrPtr(Text), Len(Text), VarPtr(Utf8(0)), lngOutLen, 0, 0
          ToUTF8 = Utf8
       End If
    End Function
    Screenshot of Unicode aware Crypto Demo See #Crypto_Unicode for Source Code and Demo.:



    Crypto Enumerations

    Crypto Enumerations:


    Add this code to a Class:

    Option Explicit
    Private Const CRYPT_FIRST                 As Long = 1
    Private Const CRYPT_VERIFYCONTEXT         As Long = &HF0000000
    Private Const MS_DEFAULT_PROVIDER         As String = "Microsoft Base Cryptographic Provider v1.0"
    Private Const PP_ENUMALGS_EX              As Long = 22
    Private Const PP_ENUMCONTAINERS           As Long = 2
    Private Type PROV_ENUMALGS_EX
       ALG_ID               As Long
       dwDefaultLen         As Long
       dwMinLen             As Long
       dwMaxLen             As Long
       dwProtocols          As Long
       dwNameLen            As Long
       bytName(19)          As Byte
       dwLongNameLen        As Long
       bytLongName(39)      As Byte
    End Type
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
       ByVal Destination As Long, _
       ByVal Source As Long, _
       ByVal Length As Long)
    Private Declare Function CryptAcquireContext Lib "Advapi32" Alias "CryptAcquireContextW" ( _
       ByRef phProv As Long, _
       ByVal pszContainer As Long, _
       ByVal pszProvider As Long, _
       ByVal dwProvType As Long, _
       ByVal dwFlags As Long) As Long
    Private Declare Function CryptReleaseContext Lib "Advapi32" ( _
       ByVal hProv As Long, _
       ByVal dwFlags As Long) As Long
    Private Declare Function CryptEnumProvidersW Lib "advapi32.dll" ( _
       ByVal dwIndex As Long, _
       ByVal pdwReserved As Long, _
       ByVal dwFlags As Long, _
       pdwProvType As Long, _
       ByVal pszProvName As Long, _
       pcbProvName As Long) As Long
    Private Declare Function CryptGetProvParam Lib "advapi32.dll" ( _
       ByVal hProv As Long, _
       ByVal dwParam As Long, _
       pbData As Any, _
       pdwDataLen As Long, _
       ByVal dwFlags As Long) As Long
    Private Declare Function CryptEnumProviderTypesW Lib "advapi32.dll" ( _
       ByVal dwIndex As Long, _
       ByVal pdwReserved As Long, _
       ByVal dwFlags As Long, _
       ByRef pdwProvType As Long, _
       ByVal pszTypeName As Long, _
       ByRef pcbTypeName As Long) As Long
    Private Declare Function GetLastError Lib "kernel32" () As Long
    Private Declare Function FormatMessageW Lib "kernel32" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As Long, _
       ByVal nSize As Long, Arguments As Long) As Long
    Public Event Algo(ByVal AlgID As Long, ByVal Alg As String, ByVal Desc As String, ByVal Min As Long, ByVal Max As Long, ByVal Default As Long)
    Public Event CSP(ByVal lProvType As Long, ByVal strProvName As String)
    Public Event Container(ByVal strContainerName As String)
    Public Event ProviderType(ByVal lProvType As Long, ByVal strProvTypeName As String)
    Public Sub EnumALG(ByVal Provider As String, ByVal ProvType As Long)
       Dim hProv            As Long
       Dim AlgsEx           As PROV_ENUMALGS_EX
       Dim strAlg           As String
       Dim strDesc          As String
       Dim dwFlags          As Long
       CryptAcquireContext hProv, 0, StrPtr(Provider), ProvType, CRYPT_VERIFYCONTEXT
       dwFlags = CRYPT_FIRST
       While CryptGetProvParam(hProv, PP_ENUMALGS_EX, ByVal VarPtr(AlgsEx), Len(AlgsEx), dwFlags)
          dwFlags = 0
          With AlgsEx
             strAlg = Left$(StrConv(.bytName, vbUnicode), .dwNameLen - 1)
             strDesc = Left$(StrConv(.bytLongName, vbUnicode), .dwLongNameLen - 1)
          End With
          RaiseEvent Algo(AlgsEx.ALG_ID, strAlg, strDesc, AlgsEx.dwMinLen, AlgsEx.dwMaxLen, AlgsEx.dwDefaultLen)
       CryptReleaseContext hProv, 0
    End Sub
    Public Function GetProviderTypeName(ByVal lProvideType As Long) As String
       Dim lIndex           As Long
       Dim sNameBuffer      As String
       Dim lNameLength      As Long
       Dim lProvType        As Long
       CryptEnumProviderTypesW lIndex, 0, 0, lProvType, 0, lNameLength
       sNameBuffer = String(lNameLength, vbNullChar)
       While CryptEnumProviderTypesW(lIndex, 0, 0, lProvType, StrPtr(sNameBuffer), lNameLength)
          If lProvideType = lProvType Then
             GetProviderTypeName = Left$(sNameBuffer, lNameLength - 1)
             Exit Function
          End If
          lIndex = lIndex + 1
          CryptEnumProviderTypesW lIndex, 0, 0, lProvType, 0, lNameLength
          sNameBuffer = String(lNameLength, vbNullChar)
       GetProviderTypeName = "(Unknown)"
    End Function
    Public Sub EnumProviderTypes()
       Dim lIndex           As Long
       Dim sNameBuffer      As String
       Dim lNameLength      As Long
       Dim lProvType        As Long
       CryptEnumProviderTypesW lIndex, 0, 0, lProvType, 0, lNameLength
       sNameBuffer = String(lNameLength, vbNullChar)
       While CryptEnumProviderTypesW(lIndex, 0, 0, lProvType, StrPtr(sNameBuffer), lNameLength)
          RaiseEvent ProviderType(lProvType, Left$(sNameBuffer, lNameLength - 1))
          lIndex = lIndex + 1
          CryptEnumProviderTypesW lIndex, 0, 0, lProvType, 0, lNameLength
          sNameBuffer = String(lNameLength, vbNullChar)
    End Sub
    Public Sub EnumCSP()
       Dim lIndex           As Long
       Dim sNameBuffer      As String
       Dim lNameLength      As Long
       Dim lProvType        As Long
       CryptEnumProvidersW lIndex, 0, 0, lProvType, 0, lNameLength
       sNameBuffer = String(lNameLength, vbNullChar)
       While CryptEnumProvidersW(lIndex, 0, 0, lProvType, StrPtr(sNameBuffer), lNameLength)
          RaiseEvent CSP(lProvType, Left$(sNameBuffer, lNameLength - 1))
          lIndex = lIndex + 1
          CryptEnumProvidersW lIndex, 0, 0, lProvType, 0, lNameLength
          sNameBuffer = String(lNameLength, vbNullChar)
    End Sub
    Public Sub EnumContainers()
       Dim hProv            As Long
       Dim bytArray()       As Byte
       Dim strContainer     As String
       Dim dwFlags          As Long
       CryptAcquireContext hProv, 0, StrPtr(MS_DEFAULT_PROVIDER), 1, CRYPT_VERIFYCONTEXT
       dwFlags = CRYPT_FIRST
       ReDim bytArray(260)
       While CryptGetProvParam(hProv, PP_ENUMCONTAINERS, bytArray(0), 261, dwFlags)
          dwFlags = 0
          strContainer = StrConv(bytArray, vbUnicode)
          RaiseEvent Container(StripNull(strContainer))
       CryptReleaseContext hProv, 0
    End Sub
    Private Function StripNull(StrIn As String) As String
       Dim nul              As Long
       nul = InStr(StrIn, vbNullChar)
       If (nul) Then
          StripNull = Left$(StrIn, nul - 1)
          StripNull = Trim$(StrIn)
       End If
    End Function
    Private Function GetLastSystemError() As String
       Dim sError           As String * 500 '\\ Preinitilise a string buffer to put any error message into
       Dim lErrNum          As Long
       lErrNum = Err.LastDllError
       If FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, ByVal 0&, lErrNum, 0, StrPtr(sError), Len(sError), 0) = 0 Then
          GetLastSystemError = "Unknown Error"
          GetLastSystemError = StripNull(sError)
       End If
    End Function
    Private Sub RaiseError(ByVal Source As String, Optional ByVal Description As String)
       If Len(Description) Then
          Description = Description & vbCrLf & "-----" & vbCrLf
       End If
       Err.Raise Err.LastDllError, Source, "Crypto." & Description & GetLastSystemError
    End Sub





    Support Unicode in Cloud Utilities:

    Use UTF-8 encoding for filenames, followed by URLEncode.

    Files are uploaded/downloaded as binary so it doesn't matter what the file content is.

    Use following Hmac generators:

    Excellent Hmac SHA1, SHA256, UTF8, Encode, and Decode functions can be found at:

    The biggest problem you will probably run into when coding Cloud storage is the authentication.
    Documentation, while helpful, is often incomplete and sometimes misleading.
    Your best friend is installing Fiddler which is a Web Debugging Proxy. http://www.fiddler2.com/ 
    Monitor the HTML request  for a working Cloud Service and then try to replicate it with Vb6. Keep going until your authentication string is the same as the working Cloud Service.

    There are some working Amazon S3 samples here although you will need to replace the commercial components with your own or purchase their suite:

  • Amazon S3 - List Buckets
  • Amazon S3 - Create Bucket with PUT Request
  • Amazon S3 - Create Bucket with Constraint
  • Amazon S3 - Delete Bucket (REST API)
  • Amazon S3 - Add Text Object to Bucket
  • Amazon S3 - Add Image (GIF) to Bucket
  • Note that you can use Hmac, Utf8, Encode/Decode from the above link (http://www.vbforums.com/showpost.php?p=3996113&postcount=4) so all you really need is to make your own http class using XMLHTTP60 of Microsoft XML, v6.0 (msxml6.dll).


    Huge Files

    Huge File Support (Chunking):

    While processing huge files (>2Gb) you need to process the file in chunks. A side benefit of this is that you can easily implement a Progress Event.

    An excellent example (HugeBinaryFile.cls) can be found at:

    We made a couple minor modifications to this code so that the final chunk is truncated to the correct length.

    Public Function ReadBytes(ByRef Buffer() As Byte) As Long
       Dim bytCount As Long
       bytCount = UBound(Buffer) - LBound(Buffer) + 1
       If ReadFile(hFile, _
          Buffer(LBound(Buffer)), _
          bytCount, _
          ReadBytes, _
          0) Then
          If ReadBytes = 0 Then
             fEOF = True
          ElseIf ReadBytes < bytCount Then 'Resize return array
             ReDim Preserve Buffer(ReadBytes - 1)
          End If
          RaiseError HBF_READ_FAILURE
       End If
    End Function

    In addition we need the output file to be opened with CREATE_ALWAYS flag

    Public Sub OpenFile(ByVal OPENFILENAME As String, ByVal bRead As Boolean)
       Dim dwDesiredAccess        As Long
       Dim dwCreationDisposition  As Long
       If bRead Then
          dwDesiredAccess = GENERIC_READ
          dwCreationDisposition = OPEN_ALWAYS
          dwDesiredAccess = GENERIC_WRITE
          dwCreationDisposition = CREATE_ALWAYS
       End If
       If hFile <> INVALID_HANDLE_VALUE Then
          RaiseError HBF_FILE_ALREADY_OPEN
       End If
       hFile = CreateFileW(StrPtr(OPENFILENAME), dwDesiredAccess, 0, _
          0, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0)
       If hFile = INVALID_HANDLE_VALUE Then
          RaiseError HBF_OPEN_FAILURE
       End If
       sFName = OPENFILENAME
    End Sub

    Now you can step through the file as follows:

       BytesRead = cIN.ReadBytes(bytBlock)
       Do While BytesRead > 0
          UpdateProgress BytesRead
          retBlock = EncryptDecrypt(bytBlock, bEncrypt)
          cOUT.WriteBytes retBlock
          BytesRead = cIN.ReadBytes(bytBlock)


    Font Fallback/Linking

    Microsoft InkEdit (a RichEdit control) appears to be using Font Fallback which would account for differences in appearance and line spacing.
    A Unicode aware TextBox appears to be using Font Linking where the base Font uses info from Linked Font and renders using the base Font.
    See http://msdn.microsoft.com/en-us/goglobal/bb688134.aspx

    There are also IME issues with Vb6 RichTextBox, InkEdit, and MS Forms 2.0 TextBox.
    Try typing "asdf890" with Kazakh IME and you get "???????".
    With correct implementation a Unicode TextBox will show "фываүұқ".

    Most applications (Notepad, Wordpad, Office WinWord) do handle this corrctly.

    Kazakh keyboard example:

    You can see the difference in the screenshot below:
    Also note the last line where we type "asdf 890" using Kazakh IME. Only UniTextBox (CyberActiveX) correctly handles this IME.

    If you look at the RTF code generated by InkEdit you get the following:

    [CODE]{\rtf1\fbidis\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 Tahoma;}{\f1\fnil\fcharset178 Tahoma;}{\f2\fmodern\fprq6\fcharset134 SimSun;}{\f3\fswiss\fcharset1 Sylfaen;}{\f4\fswiss\fcharset161 Sylfaen;}{\f5\fswiss\fcharset177 Arial;}{\f6\fswiss\fcharset0 Arial;}{\f7\fswiss\fcharset1 Mangal;}{\f8\fswiss\fcharset0 Mangal;}{\f9\froman\fprq1\fcharset128 MS PGothic;}{\f10\fmodern\fprq1\fcharset129 Gulim;}{\f11\fswiss\fcharset1 Raavi;}{\f12\fswiss\fcharset0 Raavi;}{\f13\fswiss\fcharset204{\*\fname Arial;}Arial CYR;}{\f14\fswiss\fcharset1 Latha;}{\f15\fswiss\fcharset0 Latha;}{\f16\fswiss\fcharset222 Cordia New;}{\f17\fswiss\fcharset1 Sylfaen;}}
    {\*\generator Msftedit;}\viewkind4\uc1\pard\ltrpar\f0\fs20 ARA: \lang1025\f1\rtlch\'e3\'dc\'d1\'cd\'c8\'dc\'dc\'c7\'f0\lang1046\f0\ltrch \par
    CHS: \lang2052\f2\'bb\'b6\'d3\'ad \par
    CHT: \'9a\'67\'d3\'ad \par
    ENG: Welcome \par
    GEO: \f3\u4321?\u4304?\u4321?\u4323?\u4320?\u4309?\u4308?\u4314?\u4312? \par
    GRK: \f4\'ca\'e1\'eb\'fe\'f2 \'de\'eb\'e8\'e1\'f4\'e5 \par
    HEB: \lang1037\f5\rtlch\'e1\'f8\'e5\'eb\'e9\'ed \'e4\'e1\'e0\'e9\'ed\lang1046\f6\ltrch \par
    HIN: \lang1037\f7\u2352?\u2357?\u2366?\u2327?\u2340? \par
    \lang1046\f8 JPN: \lang1041\f9\'82\'e6\'82\'a4\'82\'b1\'82\'bb \par
    KOR: \lang1042\f10\'bf\'a9\'ba\'b8\'bc\'bc\'bf\'e4 \par
    PTB: Bem-vindo \par
    PUN: \f11\u2588?\u2624? \u2566?\u2567?\u2566?\u2562? \u2600?\u2626?\u2672? \par
    \lang1046\f12 RUS: \lang1087\f13\'c4\'ee\'e1\'f0\'ee \'ef\'ee\'e6\'e0\'eb\'ee\'e2\'e0\'f2\'fc \par
    TAM: \f14\u2949?\u2969?\u3021?\u2965?\u3007?\u2965?\u2992?\u3007? \par
    \lang1046\f15 THA: \f16\fs27\'a1\'d2\'c3\'b5\'e9\'cd\'b9\'c3\'d1\'ba \par
    URD: \f7\fs20\u2360?\u2381?\u2357?\u2366?\u2327?\u2340? \par
    \f8 VIE: t\'ednh t\u7915? \par
    ARM: \f17\u1329?\u1330?\u1331?\u1332?\u1333?\u1334?\u1335?\u1336?\u1337? \par
    GER: Umlaute A\u776?I\u776?O\u776? \par
    } [/CODE]



    UniSuitePlus_BDC0849A now includes UniToolKit in the same installer.
    Since UniToolKit is composed of Unicode aware Methods and Classes we need to use Unicode aware controls to properly display Unicode in the Demos.
    UniSuitePlus controls work in the IDE without licensing and without time limits.
    UniToolKit is organized by Folders so you can unpack it anywhere and it will preserve the folder structure.

    UniToolKit - Updated 27-Mar-2018
    113612 lines of reusable Unicode aware source code

      Functions Subs Properties Modules Classes
    Private 2295 192 28    
    Public 1290 319 680 158 80
    Total 3585 511 708 158 80
    • Free to licensed users.
    • UniToolKit (aka BonusSourceCode) provides code that you can cut/paste into your projects.
      Unicode support for Clipboard, Common Dialogs, File I/O, Array sorting, PropertyBag, Registry, INI files, and many other tasks.




    vbRichClient (a modern framework for VB-Classic) by Olaf Schmidt http://vbrichclient.com is a DLL (3.59 Mb) that is Unicode aware.
    See http://vbrichclient.com/#/en/About/ for a summary of features.
    First install the DLLs, from the link below, preferably in a new folder C:\RC5 and register with RegisterRC5inPlace.vbs,

    Note that in lieu of UniSuitePlus controls these demos use vbRichEdit Widgets.


    vbRichClient DLLs
    Required for demos below.
    Recommend instlaling to C:\RC5
    Register only vbRichClient5.Dll

    vbRichClient CHM Documents
    Document Version Date
    vbRichClient5.chm 5.00.0067 11-Jul-2018 18:27:10
    vbWidgets.chm 1.00 23-Jun-2018 21:00:12

    There are many Demos available at http://vbrichclient.com/#/en/Demos/GUI/ . Also search http://www.vbforums.com/forumdisplay.php?1-Visual-Basic-6-and-Earlier for additional demos.

    Here are some Demos that we have written:

    1. Modern DriveList utility that refreshes when it detects a USB device insertion or removal:


    10-Oct-2013 Initial release. Detects a USB device insertion or removal
    09-Dec-2014 Added cDrive Class w/more info.
    10-Dec-2014 Added cwVList, cwDriveChart.
    10-Dec-2014 Added Properties via Right-Click.
    11-Dec-2014 Added cDrives() As cDrive.
    12-Dec-2014 Refactored code.
    24-Dec-2014 Switched to Shell Enumeration to add Network and Portable Devices.
    24-Dec-2014 Removed cDrives() As cDrive.
    24-Dec-2014 Added In-Memory SQLite DB to hold data.
    24-Dec-2014 Sort DB by Group, added Group as Column 1.
    24-Dec-2014 Fixed bug calling Properties.
    24-Dec-2014 Added ClipExplicit to OwnerDrawItem column rendering.
    26-Dec-2014 Fixed bug where some Network items were not cleared
    19-Jan-2015 Removed WinAPIForVB.TLB dependency.
    1. Olaf Schmidt
    2. Emmet Gray
    3. Dilettante

    Note: Windows 8/10 includes Desktop, Music, Pictures, Videos, Documents, Downloads under "CSIDL_DRIVES" so expect them to show up in this list. 

    2. cwPieChart Widget:


    14-Dec-2014 Added Clear Function .


    vbRichClient sample code

    3. cwTree Widget (MultiColumn).



    vbRichClient sample code

    Updated 08-Aug-2018 Horizontal ScrollBar.

    4. cwProgressCircle:




    Crypto Unicode

    Many Crypto libraries are ANSI only.
    This set of classes and functions demonstrate Unicode functionality by using byte arrays.
    When encrypting a string, it automatically converts it to a UTF-8 byte array before encryption.
    Demo also Enumerates Containers, Providers, Certificates and has sample code to encrypt/decrypt huge files.

    Updated 25-Jul-2018. Switched to Capicom v for extraction of Certificate Info.
    49 info items for each Certificate.
    Added InitKeyPair to Demo.
    Switched to InkEdit (Vista or later) in lieu of UniSuitePlus controls.


    • Dilettante
    • Doug Guede
    • Salvo Cortesiano

    Testing shows that Capicom does not appeat to support SHA-512 and perhaps other algorithms or options.
    Therefore, Crypto API is used in these classes (with exception of  Certificates)

    Screenshot of Demo.

    Note that Capicom is currently only used in the above Demo for Certficate Info (adapted from code by Salvo Cortesiano).




    CAPICOM is a discontinued ActiveX DLL created by Microsoft to help expose a select set of Microsoft Cryptographic Application Programming Interface (CryptoAPI) functions through Microsoft Component Object Model (COM).

    The latest version is

    helpstring("CAPICOM v2.1 Type Library")

    Testing shows that Capicom does not appear to support SHA-384/SHA-512 and perhaps other algorithms or options present in Win7 Crypto API.
    The SDK (SoftwareDevelopers Kit) can be downloaded here.

    Original Demo by Salvo Cortesiano can be found here:
    A slightly modified version using Unicode controls can be downloaded here. This version also fixes the Visual Styles issue with Frames in the original demo.
    Note that by replacing the Demo ANSI TextBox with Unicode TextBox you can Encrypt/Decrypt Unicode strings as long as we limit ourselves to SHA-256. Also don't see an option to encrypt byte arrays which we need for processing large binary files in chunks.
    What CAPICOM does well is Enumerating Certficates and providing extensive info for each Certificate.




    This was inspired by a recent post at vbForums http://www.vbforums.com/showthread.php?776385-RESOLVED-Modify-right-click-context-menu-in-standard-controls .
    Sample Unicode TextEdit control from PlanetSourceCode http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=73063&lngWId=1

    While implementing this in a Unicode TextBox that was already subclassed we found the following:

    1. Menu is not yet created when WM_CONTEXTMENU is fired. However we are getting multiple WM_ENTERIDLE messages as soon as it is popped so you can find hMenu handle and call AppendMenuW there.
    We locked this with m_Busy flag upon first entry. m_Busy flag is reset in WM_CONTEXTMENU awaiting the next popup.

    2. Some items in SubMenu "Insert Unicode control character" already include WM_APP so we have to exclude these from firing during WM_APP.
    Also, we need to find highest menu ID value so we really know what is available to use with our new menu items.

    3. We can query menu item ID and text during WM_MENUSELECT but we found that GetMenuStringW requires a positive value so replaced LoWord(wParam) with LoWordUnsigned(wParam).
    Once (uMsg And WM_APP) = WM_APP is fired the menu is already gone so if you need the menu caption you should grab it during WM_MENUSELECT.



    • LaVolpe
    • AndRAY





    Sliding Compass control uses gradients to give the illusion that an illuminated cylinder with compass markings is rotating behind the control window.




    Registration-free COM is a mechanism available on the Microsoft Windows XP (SP2 for .NET-based components) and Microsoft Windows Server 2003 platforms.
    As the name suggests, the mechanism enables easy (for example, using XCOPY) deployment of COM components to a machine without the need to register them.

    In a nutshell, you build your application against a set of Ocx/Dll and create a Manifest of com elements that is embedded into the final Exe.
    Your Exe is then installed (copied without registration) with the Ocx/Dll in the same folder as the Exe.
    Your Exe will then use the Ocx/Dll in that folder, even if  newer versions of these Com components are installed and registered on  your machine.
    This elimnates "DLL hell" where newer installed components may break exisiting applications.

    Where can you get this for Vb6?

    MakeMyManifest Unattended  MakeMyManifest Registration Free Com
    This above link is currently dead.
    Command line application
    Hosted on SourceForge
    CybeActiveX version with Vb6 source code.

    Updated 19-Jul-2017 to support gdiScaling for
    Windows 10 Version 1703 Creators Update




    This is a class to change Vb6 Menu captions to Unicode using API SetMenuItemInfoW.
    Tested on Windows 7 (Note that you do not need to fiddle with Fonts or Charset.).


    1. 11-Oct-2014 Icon support using MS Vb6 ImageList.


    Vb6 menus Unicode.





    Create a new Unicode PopMenu on the fly using this class.
    Uses TrackPopupMenuEx to retrieve Selected ID and/or Selected Caption.


    1. 11-Oct-2014 Icon support using MS Vb6 ImageList.
    2. 20-Oct-2014 Support for loading Bitmap from resource file.
    3. 22-Oct-2014 Support for 32bpp Bitmap from resource file using "Custom" resource, byte array, and ArrayToPicture.
          Note that you need a Manifest enabling Themes in app exe. You can add Manifest to Vb6.exe to make development easier.


    UniPopMenu on Windows 10
    Must have Manifest for 32bpp to work
    Selected ID + Caption





    On Screen Keyboard (OSK.,exe) does not work when calling via ShellExecute on x64 systems.
    This is due to WOW 64 redirection.

    The following code will allow you to run Osk.exe on both x86 and x64 OS.
    Updated  25-Sep-2017 to reflect bWow64Process As Long insted of incorrect bWow64Process As Boolean.


    Option Explicit
    Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpszOp As String, ByVal lpszFile As String, ByVal lpszParams As String, ByVal LpszDir As String, ByVal FsShowCmd As Long) As Long
    Private Declare Function Wow64EnableWow64FsRedirection Lib "kernel32.dll" (ByVal Enable As Boolean) As Boolean
    Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
    Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
    Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
    Private Declare Function IsWow64Process Lib "kernel32" (ByVal hProc As Long, bWow64Process As Long) As Long
    Private Sub Command1_Click()
    If Is64bit Then
    Wow64EnableWow64FsRedirection False
    ShellExecute 0, "open", "osk.exe", "", "", vbNormalFocus
    Wow64EnableWow64FsRedirection True
    ShellExecute 0, "open", "osk.exe", "", "", vbNormalFocus
    End If
    End Sub
    Public Function Is64bit() As Long
    If GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process") > 0 Then
    IsWow64Process GetCurrentProcess(), Is64bit
    End If
    End Function

    Keyboard example (ABNT2 Portuguese Brazil):





    VersionInfo This demo Loads HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion and decodes
    "InstallDate" and REG_QWORD "InstallTime"

    VersionInfo retrieves OS version data using multiple methods.
    The traditional method is calling GetVersionEx with Enum OSVERSIONINFOEX
    But now there is an issue that this doesn't work correctly for Windows 8.1 (which reports itself as Windows 8.0).
    The solution is to apply a Manifest to the application so that it can report as 8.1.

    Another method is to get info from the registry under:
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
    However on a 64bit OS we get redirected to the 32bit section of the registry which is:
    HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion

    So how do we get the 64-bit registry info?
    You add the KEY_WOW64_64KEY Flag in RegOpenKeyEx,
    Private Const KEY_WOW64_64KEY As Long = &H100 'Access a 64-bit key from either a 32-bit or 64-bit application.
    Example: e = RegOpenKeyEx(m_hClassKey, m_sSectionKey, 0, KEY_QUERY_VALUE Or KEY_WOW64_64KEY, hKey)

    Windows 10 is just out and looking at the 64bit registry we have a 2 subKeys to convert:
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion

    "InstallDate" is REG_DWORD which is a 32bit integer which ranges between -2,147,483,648 and 2,147,483,647 which is a Unix date
    as the number of seconds since #1/1/1970#

    "InstallTime" is a REG_QWORD which is a 64bit which ranges between -9,223,372,036,854,775,808 and 9,223,372,036,854,775,807
    which is the number of 100ns intervals since #1/1/1601#

    We decode both of these in the following function (make sure you supply a Variant and not a string):

    Public Function Unix2Date(ByVal vUnixDate As Variant) As Date
       Dim dblCurr As Double
       Dim tim As Double
       Select Case VarType(vUnixDate)
       Case vbLong 'REG_DWORD
          Unix2Date = DateAdd("s", vUnixDate, #1/1/1970#)
       Case vbCurrency 'REG_QWORD
          'scale to days to avoid overflow in DateAdd
          'Note that vbCurrency is already scaled by 10000 from registry QWORD

          dblCurr = vUnixDate / 86400000
          'get time (fraction of day)
          tim = dblCurr - Int(dblCurr)
          Unix2Date = DateAdd("d", dblCurr, #1/1/1601#) + tim
       End Select
    End Function

    Windows 7 Ultimate - x64 Windows 10 Pro - x64



    VersionInfo2 For Windoiws 2000 or later we also have APÌ RtlGetVersion Lib "ntdll.dll" which gets the correct version info without requiring a Manifest.
    This has been wrapped into a class for convenience.


    Major                        10 
    Minor                        0 
    BuidNumber                   17134 
    PlatformID                   2 
    ServicePackMajor             0 
    ServicePackMinor             0 
    SuiteMask                    256          VER_SUITE_SINGLEUSERTS
    ProductType                  1            VER_NT_WORKSTATION
    Reserved                     0 
    IsWindows10                 True 






    You can also get the correct OS version without requiring a Manifest or using WMI by calling GetFileVersionInfo with "kernel32".
    Sample code (Unicode aware) can be downloaded at link above.

    Win 7 Ultimate6.1.7601.18869
    Win 10 Technical Preview6.4.9841.0
    Win 10 RTM10.0.10586
    Win 10 v 170310.0.15063.296
    Win 10 v 170910.0.16299.402
    Win 10 v 180310.0.17134.191 24-Jul-2018 



    Windows 10

    We installed Windows 10 (Technical Preview) on 01-Oct-2014 to VmWare Desktop.
    Vb6 + SP6 installed easier than Win7/Win8 with no tricks necessary other than "Run As Administrator".
    Initial testing shows that Vb6 runs OK without any problems.

    This is the supportedOS Id to be used in Manifest for Windows 10:
    <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"></supportedOS>

    Update: Now that we have Windows 10 Pro Build 10240 installed on our development machine on 15-Aug-2015 everything seems to be working OK.

    Win 10 Pro Version 1803 10.0.17134.191 24-Jul-2018





    14-Oct-2014 Detect UTF-8 without BOM
    28-Oct-2014 Added lPos to Functon FromUTF8 so we can easily strip BOM
    30-Oct-2014 Use CreateFileW in lieu of Vb6 I/O
    02-Nov-2014 Additional Error checking, code refactoring.

    When a file has a BOM (Byte Order Mark) we can decode the file OK.

    Encoding BOM
    UTF-16LE (Little Endian, Vb6 Unicode) FF FE
    UTF-16BE (Big endian) FE FF
    UTF-8 EF BB BF

    Many UTF-8 files do not have a BOM and it is not mandatory.
    We found that Notepad, Notepad++, UltraEdit, and many other apps were able to detect a UTF-8 file without a BOM.
    The sample code above detects UTF-8 in the file content when there is no BOM.

    UTF-8 BOM


    "Use of a BOM is neither required nor recommended for UTF-8, but may be encountered in contexts where UTF-8 data is converted from other encoding forms that use a BOM or where the BOM is used as a UTF-8 signature". http://en.wikipedia.org/wiki/Byte-order_mark#cite_note-2
    According to the "Unicode standard" the BOM for UTF-8 files is not recommended. http://www.unicode.org/versions/Unicode5.0.0/ch02.pdf
    In fact using a BOM in UTF-8 is discouraged by the Unicode consortium!  
    UTF-8 is the default encoding for XML and since 2010 has become the dominant character set on the Web. www.utf-8.com
    UTF-8 From Wikipedia, the free encyclopedia http://en.wikipedia.org/wiki/UTF-8


    UTF-16LE (Little Endian, Vb6) UTF-16BE (Big Endian) UTF-8 with BOM UTF-8 without BOM ANSI with Accents




    Numeric TextBox

    Make a Vb6 TextBox Numeric only.
    Also prohibits clipboard paste of alpha characters.


    Numeric TextBox



    FSO Replacement


    Still under development.
    Unicode aware and fast API implementation.
    Note that we are using UniListView from UniSuitePlus since it has Grouping feature.

    Download Classes (19) Modules





    cDrive class raises Event DeviceChange when it detects a USB device arrival or removal.

    24-Nov-2014 Added Bus, Model, HardSerial
    01-Dec-2014 Function IsUSB = Me.BusType = BusTypeUsb.
    13-Dec-2014 Added code to skip shares.
    13-Dec-2014 Updated screenshot (new ProgressBar rendering in UniSuitePlus UniListView)
    16-Dec-2014 Consolidated as single Vbp.
    21-Dec-2014 Switched to Pidls to enumerate all Drives + Portable Devices + Network Shares.
    21-Dec-2014 Merged cIDListData.cls into cDrive.cls.
    21-Dec-2014 Added "System" Group since Windows 10 now includes Pictures/Videos/Music folders under CSIDL_DRIVES.
    27-Sep-2015 Minor speed enhancements to class cEnumW32FD.cls
    03-Oct-2015 Added Filters similar to Opus Directory. Minor bug fixes
    11-Oct-2015 Updated cEnumW32.cls, cVBALSysImageList.cls.

    Fast enumeration of Files and Folders. Returns items via Event ItemDetails.
    Formatting of WIN32_FIND_DATA is only done when you retrieve it. That way you only format the information that you need.



    Keyboard Layouts

    This class will enumerate the installed keyboards (IME) and show which one is currently active (*).



    Kazakh OnScreenKeyboard:




    Enumerate Locales

    This class will enumerate the installed Locales and show which one is currently the default (active).
    Also shows some basic information (Unicode aware) for each Locale

    Enumerate Locales


    Win 10 v 180310.0.17134.165 28-Jul-2018  258 Locales




    Unicode aware replacement for the Vb6 DIR function.

    DirW Based on Original by Elroy:

    05-Nov-2014 Added Size, Type, Modified Date, Attr.
    24-Nov-2014 Added FileCreationDate, FileLastAccessed
    24-Nov-2014 Added System ImageList.



    Wrapper RichTextBox



    16-Nov-2014 Unicode aware OpenFile
    16-Nov-2014 PNG support for InsertPicture

    The Vb6 Microsoft Rich Textbox Control 6.0 (SP6), RichTx32.Ocx, is an ANSI control.
    We can make most functions handle Unicode by exposing the TOM (Text Object Model) without having to resort to complicated API hacks.
    The TOM opens up a whole range of features that would be difficult to implement otherwise.

    Info and demo on the class that gets the TOM can be found here:

    But... it does not handle:

    1. Clipboard Paste of Unicode from Notepad (format CF_UNICODETEXT).
    2. Keyboard IMEs like Kazakh (Kazakhstan).
          Try typing "asdf 890" with Kazakh IME and you get "???? ???".
          With correct implementation a Unicode TextBox will show "фыва үұқ".




     IsAlpha, IsNumeric

    With Unicode characters, checking for IsAlpha, IsAlphaNumeric, IsNumeric is not as sinmple as checking "a-z" and "A-Z".
    Fortunately there are Unicode APIs that can solve this.


    1. Can analyze single character of string using index 0 to Len(String) - 1.
    2. If Index = -1 then will analyze entire string and return True if condition is True for all characters.



    Added Function
    05-Jan-2015 IsAlpha
    05-Jan-2015 IsAlphaNumeric
    05-Jan-2015 IsNumeric
    05-Jan-2015 IsStringAlpha
    05-Jan-2015 IsStringAlphaNumeric
    05-Jan-2015 IsStringNumeric
    05-Jan-2015 IsLowerCase
    05-Jan-2015 IsUpperrCase
    05-Jan-2015 IsWhiteSpace (Credit Kelly Ethridge)
    06-Jan-2015 IsControl
    07-Jan-2015 Added clsGetStringType
    Wraps GetStringTypeExW
    Supports 27 Boolean Properties of Single character
    13-Jan-2015 Specifying Index = -1 will anlyze entire string
    IsAlpha IsArabicNumber IsDiacritic
    IsBlank IsBlockSeparator IsNonSpacing
    IsCntrl IsCommonSeparator IsSymbol
    IsDigit IsEuropeNumber IsVowelMark
    IsHexDigit IsEuropeSeparator IsNotApplicableProcessing
    IsLower IsEuropeTerminator  
    IsUpper IsLeftToRight  
    IsPunct sNotApplicableLayout  
    IsSpace IsOtherNeutral  
    IsOther IsRightToLeft  



    Ocx Template



    18-Oct-2015 Released

    Things can become very messy early on if you throw all the control/classes/modules,forms, etc. files in the same folder, especially for the more complicated controls like Listview.

    For OCX development, we have a template that we have been using for many years that separates the Demo and Source.

    Early on in the development we make a copy of the Ocx and place it in the Source\Compatibility folder. The we rename it with a "cmp" extension and then point to this new file as our binary compatibility file.
    By doing this you will eliminate the annoying error that occasionally locks you from compiling the Ocx.

    You can take a vbAccelerator project and paste the files to their appropriate folders, but you will have to update the Vbp/Vbg files to reflect the  new location.
    We do this manually by modifying the Vbp files and just adding "Modules\" in front of "bas" files, "Classes\" in front of "Cls" files, etc.
    Don't forget to add "..\Demo\" prefix to the demo Vbp in the Vbg file.
    Once this is done, and it doesn't take more than a few minutes, you will never go back to putting all files in the same folder.


     vbAccelerator Listview



    A recent thread on VbForums discussed Listview "multifile ghosted drag image"

    Directory Opus v 11.16 VbAccelerator Listview
     (out of the box)
    VbAccelerator Listview (modified for multi-file ghost drag image) Windows 10 Explorer (Build 10240)
    The blue background is for individual items so it has jagged look. It shows a label with a prefix "+ Move" or "+ Copy", with the appended drop target name. Shows a single drag image even when multiple files are selected. Uses m_hImlDrag = SendMessage(m_hWnd, LVM_CREATEDRAGIMAGE, m_lDragItem, tP) Blue background without the jagged look. The Label Overlay currently only shows Copy/Move and the # of Item(s).
    Uses m_hImlDrag = CreateDragImageEx
    Shows a Large Icon with an overlay showing number of File(s) and  "+ Copy" + Drop Target when Ctrl key is down. For Move it just shows the Drop Target.


    Modified VbAccelerator Listview to use CreateDragImageEx which renders a multifile ghosted drag image.
    While we were at it, also updated the code for Unicode.
    The subclasser SsubTmr6.Dll has been embedded into the control so that you do not need the extra dependency.
    The downside of SsubTmr6 embedded is that it is prone to crashing during development. Do not use the "End" key.

    I expect several since this was thown together rather quickly.
    Let me know when you find any so that I can fix them (time permitting).
    One known bug is that DragDrop ghost image does not work when RightToLeft property = True.



     vbAccelerator Treeview



    Modified VbAccelerator Treeview updated for Unicode.
    The subclasser SsubTmr6.Dll has been embedded into the control so that you do not need the extra dependency.
    The downside of SsubTmr6 embedded is that it is prone to crashing during development. Do not use the "End" key.



    TitleCase(ProperCase), SentenceCase

    This code uses LCMAP_TITLECASE (Windows7 and later) and modified code by cssriraman at vbForums for SentenceCase http://www.vbforums.com/showthread.php?403900-RESOLVED-vbProperCase&p=2461462&viewfull=1#post2461462
    It also attempts to preserve ProperNames in TitleCase(ProperCase) and SentenceCase, although it is far from foolproof.

    'Retain mixed case names like DaSilva, McConnell, and O'Reilly
    'If word has exactly 2 UpperCase chars AND at least 2 LowerCase chars then Preserve original.
    'If first leter is UpperCase and there is at least 2 LowerCase chars then Preserve original.
    'Note that this method is not foolproof but it does pick up many ProperNames and Places.
    'It falsely flags words that have a leading UpperCase and 2 or more LowerCase characters and is not a ProperName or Place.







       Stefaan Casier
       Ben Vonk


    Unlike DTPicker and MonthCal which shows only the current default UserLcid, ucCalendar can swtich LCID on the fly.

    Some ToolTip Text, like Seasons, Moon Phase and Zodiac are not fully localized, however the date portions of them are Unicode.

    This is what it looks like on Windows 10:







      Leandro Ascierto

    Note: Updated 05-Oct-2017 at 17:41 UTC. (Previous upload had wrong Zip)





    Updated 21-Jul-2018

       Dana Seaman
       Dilettante (Context Menu

    InkEdit is available on Windows Vista or later. Under the hood it is a RichEdit control.
    This wrapper disables the Ink feature and wraps the RichEdit portion of the control.


    1. Wraps InkEdit Control.
    2. Exposes TOM (Text Object Model) Interface.
    3. Exposes Range As ITextRange.
    4. Context Menu w/Insert Picture.
    5. Supports Tables As RTF (Paste from Word).
    6. Supports Left, Right,Top Margins.
    7. Does not support Kazakh IME.
    8. Added several Selection Properties.
    9. Renamed control to ucRichEdit 06-Oct-2017
    10. Added Justifiy to SelAlignment. 19-Oct-2017 See 1st Paragraph of Screenshot
    11. Added PrintRange. 19-Oct-2017
    12. Fixed bug in ReadProperties that was corrupting Unicode Text. 29-Apr-2018
    13. Fixed issue when appending via SelText. Now scroll updates without requiring control focus. 07-Jul-2018
    14. Added RightTLeft 19-Jul-2018
    15. Fixed bug in Demo 21-Jul-2018






    Updated 18-Apr-2018


    Get/Let UnicodeText with Unicode aware MsgBox.
    Used to Get/Let Form TitleBar Captions.




    Virtual Combo

    Updated 24-Jul-2018

    VirtualCombo Credits:
    Olaf Schmidt



    Fixed record count. Add a record on the fly in DropDown-Event.
    Delete Checked records in RollUp-Event




    Remove Diacritics

    Updated 19-Jul-2018

    Remove Diacritics Credits:
    Olaf Schmidt

    Function RemoveDiacritics that is fully Unicode aware (of course it works for ANSI too).
    Demo attached uses Unicode aware InkEdit control.
    Note: Requires Vista or later.




    Virtual List (Group)

    Updated 09-Aug-2018

    VirtualList(Group) Credits:
    Olaf Schmidt
    The Trick (Krivous Anatolii Anatolevich)






    Updated  07-Aug-2018

    DataBindingInkEdit Dependencies:
    File Description
    MSBind.dll Microsoft Data Binding Collection VB 6.0 (SP4)
    mstdmft.dll Microsoft Data Formatting Object Library VB 6.0 (SP6)
    msdatsrc.tlb Microsoft Data Source Interfaces for ActiveX Data Binding Type Library
    msado28.tlb Microsoft ActiveX Data Objects 2.8 Library
    Microsoft InkEdit Control 1.0

    While Adodc control supports Unicode, it is not as flexible as implementing the code behind Adodc.

    A nice feature is that this code works well with InkEdit (Unicode aware RichEdit, Vista or later)
    as can be seen in the screenshot below.




    Updated  13-Aug-2018

    DataBindingToolBoxW Dependencies:
    File Description
    MSBind.dll Microsoft Data Binding Collection VB 6.0 (SP4)
    mstdmft.dll Microsoft Data Formatting Object Library VB 6.0 (SP6)
    msdatsrc.tlb Microsoft Data Source Interfaces for ActiveX Data Binding Type Library
    msado28.tlb Microsoft ActiveX Data Objects 2.8 Library
    Microsoft InkEdit Control 1.0

    This demo binds several Unicode controls downloadable at ToolBoxW to ADO DataBase.
    Bindings can be for any String Property such as Caption or Text.
    Images are updated via an Event triggered by change in AbsolutePosition.