Classic VB - How to use Unicode with forms and standard controls?
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:
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
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.
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.
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
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.
In MDI child form we need to do a bit of coding as well:
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
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.
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
Re: Classic VB - How to use Unicode with forms and standard controls?
Hi, there is some problem
when I replaced "ChrW$(&H3042) & ChrW$(&H3052) & ChrW$(&H3062)" to "ChrW$(&H2632) & ChrW$(&H2633) & ChrW$(&H2634)" the contrl's caption didn't work correct, it just shows "???".