You've probably heard many times that VB6 native controls don't support Unicode. For the most part this is true, there simply is no way to make a label or textbox to truly show Unicode.
There is however a possibility with forms and some of the controls for Unicode. Namely the controls are CheckBox, CommandButton, Frame and OptionButton. All four of these are based on the same internal Windows Button control, even if VB6 separates them. The actual trick is simple: use Unicode version of the default window procedure instead of VB's own methods.
The following code lets you pass in any form or control, paste into a module:The usage is simple, UniCaption(Form1) = ChrW$(&H3042) will display a single Japanese character as the caption of Form1 (important! you need Far East Character Support installed via Control Panel to see Japanese!). The end result is Unicode instead of the infamous question mark in Windows XP and Windows Vista. However, this trick does not unfortunatenaly work in Windows 2000. Windows 2000 does display the Unicode character in the taskbar, but fails to draw the actual window caption correctly. There is no easy workaround for this.Code:' UniCaption Private Declare Function DefWindowProcW Lib "user32" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Declare Sub PutMem4 Lib "msvbvm60" (Destination As Any, Value As Any) Private Declare Function SysAllocStringLen Lib "oleaut32" (ByVal OleStr As Long, ByVal bLen As Long) As Long Private Const WM_GETTEXT = &HD Private Const WM_GETTEXTLENGTH = &HE Private Const WM_SETTEXT = &HC Public Property Get UniCaption(ByRef Control As Object) As String Dim lngLen As Long, lngPtr As Long ' validate supported control If Not Control Is Nothing Then If _ (TypeOf Control Is CheckBox) _ Or _ (TypeOf Control Is CommandButton) _ Or _ (TypeOf Control Is Form) _ Or _ (TypeOf Control Is Frame) _ Or _ (TypeOf Control Is MDIForm) _ Or _ (TypeOf Control Is OptionButton) _ Then ' get length of text lngLen = DefWindowProcW(Control.hWnd, WM_GETTEXTLENGTH, 0, ByVal 0) ' must have length If lngLen Then ' create a BSTR of that length lngPtr = SysAllocStringLen(0, lngLen) ' make the property return the BSTR PutMem4 ByVal VarPtr(UniCaption), ByVal lngPtr ' call the default Unicode window procedure to fill the BSTR DefWindowProcW Control.hWnd, WM_GETTEXT, lngLen + 1, ByVal lngPtr End If Else ' go ahead and try the default property On Error Resume Next UniCaption = Control End If End If End Property Public Property Let UniCaption(ByRef Control As Object, ByRef NewValue As String) ' validate supported control If Not Control Is Nothing Then If _ (TypeOf Control Is CheckBox) _ Or _ (TypeOf Control Is CommandButton) _ Or _ (TypeOf Control Is Form) _ Or _ (TypeOf Control Is Frame) _ Or _ (TypeOf Control Is MDIForm) _ Or _ (TypeOf Control Is OptionButton) _ Then ' call the default Unicode window procedure and pass the BSTR pointer DefWindowProcW Control.hWnd, WM_SETTEXT, 0, ByVal StrPtr(NewValue) Else ' go ahead and try the default property On Error Resume Next Control = NewValue End If End If End Property
When working with MDI forms things get a bit more complicated if you happen to support maximized child forms: VB updates the MDI form's caption automatically when a child form is maximized or a maximized state of a child is removed. Thus you need to do a custom function that updates the MDI caption whenever you want it to be updated.
The code looks for the current active child form, gets it's actual caption and then shows it alongside the MDI form's own caption that is being stored in the Tag property of the MDI form. If the child form is not maximized, the MDI caption will not contain the child form's caption.Code:' MDI form sample Option Explicit Public Sub CaptionW(Optional ByRef NewCaption As String) ' update to new caption if a non vbNullString was passed If StrPtr(NewCaption) Then Me.Tag = NewCaption ' must have active form If Not Me.ActiveForm Is Nothing Then ' see if window state is maximized If Me.ActiveForm.WindowState = vbMaximized Then ' show both child caption and MDI caption UniCaption(Me) = UniCaption(Me.ActiveForm) & " - " & Me.Tag Else ' show only MDI caption UniCaption(Me) = Me.Tag End If Else ' show only MDI caption UniCaption(Me) = Me.Tag End If End Sub Private Sub MDIForm_Load() ' set initial caption Me.CaptionW "MDI: " & ChrW$(&H3042) End Sub
In MDI child form we need to do a bit of coding as well:Basically the code attempts to change the caption of all controls, detects for window state changes to know when to change MDI parent caption and fixes a maximized child window unload behavior with the MDI parent window so that a correct caption is shown when the child is unloaded.Code:' MDI child form sample Option Explicit Private Sub Form_Load() Dim Ctrl As Control ' attempt to change caption of all controls For Each Ctrl In Me.Controls UniCaption(Ctrl) = ChrW$(&H3042) & ChrW$(&H3052) & ChrW$(&H3062) Next Ctrl ' change the form's caption UniCaption(Me) = "Child: " & ChrW$(&H3042) End Sub Private Sub Form_Resize() Static WindowState As FormWindowStateConstants ' see if window state has changed If WindowState <> Me.WindowState Then ' use custom caption updating in MDI form MDIForm1.CaptionW ' remember current window state WindowState = Me.WindowState End If End Sub Private Sub Form_Unload(Cancel As Integer) ' important if you allow maximized MDI child style! ' otherwise the ANSI caption appears and there is no easy way to detect when that happens Me.Visible = False End Sub
A full sample project is attached. It has a bit more meat into it and should get anyone started with Unicode in VB6. The project includes Unicode versions of Command$ and MsgBox functions, so you can also easily get the Unicode filenames upon application startup and show true Unicode message boxes.
Included functions/properties/subs:
UniInteraction.bas: Command, IIf and MsgBox
UniStrings.bas: QuickSplit, QuickSplitB, SplitToVar and UniCaption


Reply With Quote