Unicode tiếng Việt trong VBA Excel

Liên hệ QC

phamduylong

-
Thành viên đã mất
Tham gia
30/12/06
Bài viết
918
Được thích
2,368
Nghề nghiệp
Giáo viên
Unicode bây giờ phải xác định là font chính khi nhập dữ liệu. Khổ nổi có một số ứng dụng chưa hỗ trợ tốt font này, trong đó có VBA Excel. Muốn VBA gởi vào ô B1 chuỗi "Lập trình với Excel" không đơn giản chút nào vì khi nhập Cells(1,2)="Lập trình với Excel" nó lại trở thành Cells(1,2)="L?p trình v?i Excel". Những dấu ? đó là những ký tự mà mã của nó vượt ngưỡng 255.
Vấn đề này nhiều bạn đã đưa lên diễn đàn nhưng ở nhiều bài khác nhau, tôi mở chuyên mục này để chúng ta cùng tham gia để có thể sử dụng Unicode đễ dàng hơn.
Qua học hỏi từ diễn đàn và vận dụng vào lập trình VBA Excel, tôi viết Unicode tiếng Việt bằng 3 cách. Xin nêu lên và các bạn bổ sung thêm:
1. Nhập chuỗi vào 1 ô trên vào bảng tính, viết lệnh truy xuất nó. Ví dụ nhập vào ô A1 của sheet2 câu trên. Câu lệnh viết:
Cells(1, 2) = Sheets("Sheet2").Cells(1,1)
Cách này đơn giản, nhưng bảng tính phải có 1 sheet chứa các chuỗi này. Nếu có ai đó chỉnh, xóa dữ liệu thì hỏng.
2. Dùng phép nối chuỗi và hàm ChrW để viết:
Câu trên viết thành:
Cells(1,2)= L" & ChrW(7853) & "p trình v" & ChrW(7899) & "i Excel"
Cách này rắc rối vì phải biết mã ậ=7953, ớ=7899, nhưng nó được viết ngay trong module, người sử dụng khó thay đổi được (bạn tham khảo bảng mã trong tập tin CodeUnicode.xls).
3. Dùng 1 hàm tự viết để hỗ trợ cách 2 (hàm UniVba). Cách sử dụng như sau:
- Nhập chuỗi cần viết vào 1 ô trong bàng tính. Ví dụ nhập vào ô A1 chuỗi “Xử lý tiếng Việt”.
- Ô B1 nhập công thức =univba(A1), hàm sẽ cho kết quả:
"X" & ChrW(7917) & " lý ti" & ChrW(7871) & "ng Vi" & ChrW(7879) & "t"
Hàm UniVba dò tìm từng ký tự trong chuỗi, nếu ký tự nào có mã > 255 sẽ chuyển thành ChrW(mã) và ghép chúng bằng phép &.
Bạn copy ô B1 và dán vào module, rất nhanh và chính xác.
Mã:
‘===========
Function UniVba(TxtUni As String) As String
If TxtUni = "" Then
UniVba = """"""
Else
TxtUni = TxtUni & " "
If AscW(Left(TxtUni, 1)) < 256 Then UniVba = """"
For n = 1 To Len(TxtUni) - 1
uni1 = Mid(TxtUni, n, 1)
uni2 = AscW(Mid(TxtUni, n + 1, 1))
If AscW(uni1) > 255 And uni2 > 255 Then
UniVba = UniVba & "ChrW(" & AscW(uni1) & ") & "
ElseIf AscW(uni1) > 255 And uni2 < 256 Then
UniVba = UniVba & "ChrW(" & AscW(uni1) & ") & """
ElseIf AscW(uni1) < 256 And uni2 > 255 Then
UniVba = UniVba & uni1 & """ & "
Else
UniVba = UniVba & uni1
End If
Next
If Right(UniVba, 4) = " & """ Then
UniVba = Mid(UniVba, 1, Len(UniVba) - 4)
Else
UniVba = UniVba & """"
End If
End If
End Function
‘========
Các bạn tải tập tin CodeUnicode và UniVba về tham khảo.
 

File đính kèm

  • CodeUnicode.zip
    7.8 KB · Đọc: 3,999
  • UniVba.zip
    7.7 KB · Đọc: 3,275
Hì hì, tìm ra lý do rồi, do Theme API của Windows. Để desktop về theme Windows Classis thì sẽ không được, do Windows dùng Ansi API để xử lý các non Unicode Window. Còn có theme thì Windows dùng Theme API Unicode cho tất cả các Window.
PS: Ủa, admin xem lại giúp cu anh tui cái, tui có 4 cái sao mà sao giờ đâu biến mất tiêu hết rầu :)
 

File đính kèm

  • 1.png
    1.png
    77.8 KB · Đọc: 59
  • 2.png
    2.png
    63.3 KB · Đọc: 58
Lần chỉnh sửa cuối:
Upvote 0
Hì hì, thank befaint, em thấy sao lại rồi :)
File Caption Unicode up lần sau của bác giaiphap, các bác test giùm cu anh em đoạn code sau cái.
Mã:
Option Explicit

Private Sub UserForm_Initialize()
    Dim strUniCaption As String
    
    strUniCaption = "L" & ChrW(7863) & "p l" & ChrW(7841) & "i tiêu " & ChrW(273) & ChrW(7873) & " cho dòng d" & ChrW(7919) & " li" & ChrW(7879) & "u"
    SetUniText Me, strUniCaption
    
    MsgBox Me.Caption
    MsgBox StrComp(Me.Caption, strUniCaption, vbTextCompare)
    MsgBox StrComp(Me.Caption, strUniCaption, vbBinaryCompare)
End Sub
Nghi là do ông ClearType font của Quýnh đâu can thiệp nữa.
Cái vụ Caption UserForm này còn dài dài, nhiều chuyện để moi đây.
 
Lần chỉnh sửa cuối:
Upvote 0
Up cái mới sữa :)
 
Upvote 0
Cảm ơn befaint, giống máy tôi, -1 hết. Ông nội nào đã change cái text Caption đây ?
 
Upvote 0
Mã:
Option Explicit

Private Sub UserForm_Initialize()
    Dim strUniCaption As String
  
    strUniCaption = "L" & ChrW(7863) & "p l" & ChrW(7841) & "i tiêu " & ChrW(273) & ChrW(7873) & " cho dòng d" & ChrW(7919) & " li" & ChrW(7879) & "u"
    SetUniText Me, strUniCaption
  
    MsgBox Me.Caption
    MsgBox StrComp(Me.Caption, strUniCaption, vbTextCompare)
    MsgBox StrComp(Me.Caption, strUniCaption, vbBinaryCompare)
End Sub
Nghi là do ông ClearType font của Quýnh đâu can thiệp nữa.
Cái vụ Caption UserForm này còn dài dài, nhiều chuyện để moi đây.

[/CODE]
Nghi là do ông ClearType font của Quýnh đâu can thiệp nữa.
Cái vụ Caption UserForm này còn dài dài, nhiều chuyện để moi đây.

Me.Caption luôn trả vể AnsiString. Kể cả dùng các hàm API GetWindowTextW (unicode) để lấy text cũng chỉ ra AnsiString. Mặc dù vậy, trong handle của userform này luôn lưu chuỗi unicode cho Caption từ lúc chạy DefWindowProcW. Bạn luôn coi Caption của userform chính là chuối strUniCaption mà đã nhồi vào bởi DefWindowProcW trước đó.

Vụ này mình làm nhiều năm trước và chỉ dừng lại ở việc tạo unicode trên title của userform. Việc Theme Windows là classic sẽ không thể hiển thị unicode thì chưa tìm được cách nào khác đơn giản. Lập trình kỳ công hơn thì vẫn có thể viết được unicode trên Title của userform nhưng chắc là không đáng để lao công khổ tứ, vì dù hiển thị được thì còn phải làm quá nhiều thứ nữa khi người dùng đổi Theme hoặc vào "Advance Appearance" chỉnh sửa tùm lum để đảm bảo việc hiển thị nó luôn cân đối.
 
Upvote 0
Làm cách nào bác Tuân biết UserForm Caption get property trả về Ansi string vậy bác ? Bác đã từng debug vào đó chưa ?
 
Upvote 0
Làm cách nào bác Tuân biết UserForm Caption get property trả về Ansi string vậy bác ? Bác đã từng debug vào đó chưa ?

Userform tạo ra từ hàm CreateWindowA nên handle của nó không phải unicode (dùng hàm IsUnicodeWindow là thấy). Khi handle không phải unicode thì các hàm API đi theo nó trong thủ tục chính WndProc làm theo Ansi - Người lập trình có thể dùng phương pháp Subclass để hack vào trong này để thay đổi... Theo chuẩn gọi API thì Userform.Caption thì bên trong mấy anh lập trình sẽ dùng hàm GetWindowTextA (vì handle không phải unicode) để trả về cho property_get gọi nó. Các cách lấy text của handle hệ thống làm bên trong là SendMessage(,.. ,WM_GETTEXT,...), khi đó thằng WndProc nhận thông điệp WM_GETTEXT để trả về,....
 
Upvote 0
Lý thuyết lập trình là vậy, nhưng internal của UserForm (FM20.dll) làm sao thì phải "rờ em" nó mới biết chứ, đâu nói không vậy được.
 
Upvote 0
Upvote 0
em mới tìm hiểu VBA đọc từ trên xuống mà vẫn không biết làm sao để đưa tiếng việt vào msgbox trong uhm, mong các anh chị chỉ bảo dễ hiểu để em làm theo với ạ. xin cảm ơn anh chị đã chia sẻ?
 
Upvote 0
em mới tìm hiểu VBA đọc từ trên xuống mà vẫn không biết làm sao để đưa tiếng việt vào msgbox trong uhm, mong các anh chị chỉ bảo dễ hiểu để em làm theo với ạ. xin cảm ơn anh chị đã chia sẻ?
Bạn tìm hiểu bài của anh @Hoàng Trọng Nghĩa ở đây.
 
Upvote 0
...................................................
PS: Ủa, admin xem lại giúp cu anh tui cái, tui có 4 cái sao mà sao giờ đâu biến mất tiêu hết rầu.
Vào Thông tin tài khoản > Tiêu đề riêng xóa dòng Mới học Ét xeo thì nó hiện 4 cái sao trở lại.
 
Upvote 0
Hì hì, tìm ra lý do rồi, do Theme API của Windows. Để desktop về theme Windows Classis thì sẽ không được, do Windows dùng Ansi API để xử lý các non Unicode Window. Còn có theme thì Windows dùng Theme API Unicode cho tất cả các Window.
PS: Ủa, admin xem lại giúp cu anh tui cái, tui có 4 cái sao mà sao giờ đâu biến mất tiêu hết rầu :)
Bác cho em hỏi cái này thì vào chỗ nào để sửa ?
 
Upvote 0
Tôi đang tạo một UserForm chạy trên VBA7 và Win64 với chức năng hiển thị form Min, Max, Resize, và tôi cho nó thêm caption tiếng Việt.
Tất cả đều OK, tuy nhiên một vấn đề khác mà tôi không khắc phục được đó là nếu thủ tục tạo Caption tiếng Việt được kích hoạt thì nó không show form Max khi load lên, ngược lại, bỏ câu lệnh đó thì nó show được form Max! Nhờ các anh chị hướng dẫn khắc phục giúp.

Thủ tục tạo UserForm có 3 nút Close, Max, Min & Normal:
Mã:
Sub CreateMaxMinResizeForm(ByVal lngFrmWndHdl)
    Dim lngStyle
    lngStyle = GetWindowLongPtr(lngFrmWndHdl, GWL_STYLE)
    lngStyle = lngStyle Or WS_SYSMENU       'Add SystemMenu
    lngStyle = lngStyle Or WS_MINIMIZEBOX   'Add MinimizeBox
    lngStyle = lngStyle Or WS_MAXIMIZEBOX   'Add MaximizeBox
    lngStyle = lngStyle + (WS_THICKFRAME)
    SetWindowLongPtr lngFrmWndHdl, GWL_STYLE, lngStyle
    DrawMenuBar lngFrmWndHdl
End Sub

Thủ tục Unicode trên Caption của UserForm:
Mã:
Sub SetUniCaption(ByVal usfHwnd, ByVal UnicodeString As String)
    DefWindowProc usfHwnd, WM_SETTEXT, 0, StrPtr(UnicodeString)
End Sub

Các sự kiện trong UserForm:
Mã:
Private hwnd

''Thủ tục show form Max:
Private Sub UserForm_Activate()
    ShowWindow FindWindowA(vbNullString, Me.Caption), Show_MAXIMIZE
End Sub

Private Sub UserForm_Initialize()
    hwnd = FindWindow("ThunderDFrame", Me.Caption)
    ''The same:
    'hwnd = FindWindowA(vbNullString, Me.Caption)
   
    Dim strFormCaption As String
    strFormCaption = "  HOÀNG TR" & ChrW(7884) & "NG NGH" & ChrW(296) & "A, Phone: 0938.520.520, Mail: NghiaCSG@gmail.com"
    CreateMaxMinResizeForm hwnd

    ''Tai sao co dong duoi day thi khi load form khong the show max form duoc?

    SetUniCaption hwnd, strFormCaption
End Sub
 

File đính kèm

  • formmaxmin2.xlsm
    21.1 KB · Đọc: 40
Upvote 0
Tôi đang tạo một UserForm chạy trên VBA7 và Win64 với chức năng hiển thị form Min, Max, Resize, và tôi cho nó thêm caption tiếng Việt.
Tất cả đều OK, tuy nhiên một vấn đề khác mà tôi không khắc phục được đó là nếu thủ tục tạo Caption tiếng Việt được kích hoạt thì nó không show form Max khi load lên, ngược lại, bỏ câu lệnh đó thì nó show được form Max! Nhờ các anh chị hướng dẫn khắc phục giúp
Tôi đã nói không biết bao nhiêu lần rồi. Đã dịch thì dịch đến cùng, không dịch nửa vời. Vì trên máy khác có thể không hiển thị chuẩn.
Trên máy tôi

userform.JPG

do không dịch HOÀNG.
-------------
Sửa
Mã:
ShowWindow FindWindowA(vbNullString, Me.Caption), Show_MAXIMIZE

thành
Mã:
ShowWindow hwnd, Show_MAXIMIZE
 
Upvote 0
Tôi đang tạo một UserForm chạy trên VBA7 và Win64 với chức năng hiển thị form Min, Max, Resize, và tôi cho nó thêm caption tiếng Việt.
Tất cả đều OK, tuy nhiên một vấn đề khác mà tôi không khắc phục được đó là nếu thủ tục tạo Caption tiếng Việt được kích hoạt thì nó không show form Max khi load lên, ngược lại, bỏ câu lệnh đó thì nó show được form Max! Nhờ các anh chị hướng dẫn khắc phục giúp.

Thủ tục tạo UserForm có 3 nút Close, Max, Min & Normal:
Mã:
Sub CreateMaxMinResizeForm(ByVal lngFrmWndHdl)
    Dim lngStyle
    lngStyle = GetWindowLongPtr(lngFrmWndHdl, GWL_STYLE)
    lngStyle = lngStyle Or WS_SYSMENU       'Add SystemMenu
    lngStyle = lngStyle Or WS_MINIMIZEBOX   'Add MinimizeBox
    lngStyle = lngStyle Or WS_MAXIMIZEBOX   'Add MaximizeBox
    lngStyle = lngStyle + (WS_THICKFRAME)
    SetWindowLongPtr lngFrmWndHdl, GWL_STYLE, lngStyle
    DrawMenuBar lngFrmWndHdl
End Sub

Thủ tục Unicode trên Caption của UserForm:
Mã:
Sub SetUniCaption(ByVal usfHwnd, ByVal UnicodeString As String)
    DefWindowProc usfHwnd, WM_SETTEXT, 0, StrPtr(UnicodeString)
End Sub

Các sự kiện trong UserForm:
Mã:
Private hwnd

''Thủ tục show form Max:
Private Sub UserForm_Activate()
    ShowWindow FindWindowA(vbNullString, Me.Caption), Show_MAXIMIZE
End Sub

Private Sub UserForm_Initialize()
    hwnd = FindWindow("ThunderDFrame", Me.Caption)
    ''The same:
    'hwnd = FindWindowA(vbNullString, Me.Caption)
  
    Dim strFormCaption As String
    strFormCaption = "  HOÀNG TR" & ChrW(7884) & "NG NGH" & ChrW(296) & "A, Phone: 0938.520.520, Mail: NghiaCSG@gmail.com"
    CreateMaxMinResizeForm hwnd

    ''Tai sao co dong duoi day thi khi load form khong the show max form duoc?

    SetUniCaption hwnd, strFormCaption
End Sub
----------------
Rất dễ hiểu là vì Form đã nhận Handle khi chưa chuyển tiếng Việt
sau khi chuyển tiếng Việt Hàm FindWindow không đủ khả năng tìm ký tự ngoài UTF-8.

Cách giải quyết, có thể là Lưu lại Handle của Form trước khi chuyển tiếng Việt.
Hoặc dùng hàm FindWindowW
----------------
PHP:
Khai báo FindWindowW hoặc Alias "FindWindowW"
hWnd = FindWindow("ThunderDFrame" , VBA.StrConv(Form.Caption, vbUnicode))
 
Upvote 0
Trên OfficeX32 thì chạy tốt mà cái #If VBA7 And Win64 Then Nhìn vào trong code rất đẹp
Còn trên Officex64 thì nó báo API màu đỏ .... tất nhiên là nó cũng chạy rất tốt .... Nhưng nhìn vào VBA thấy đỏ code nó ko đẹp tí nào
Sao Bill vẻ ra rắc rối thế nhỉ

Tiện có thớt này hỏi ké chút
Có cách nào xử lý đỏ code như mô tả đó khi xài #If VBA7 And Win64 Then trên Officex64 hay không ???!!! ... hay ta xoá nó đi là xong khỏi nhiều chuyện he ???!!! :D -0-0-0-
Capture.PNG
 
Upvote 0
Trên OfficeX32 thì chạy tốt mà cái #If VBA7 And Win64 Then Nhìn vào trong code rất đẹp
Còn trên Officex64 thì nó báo API màu đỏ .... tất nhiên là nó cũng chạy rất tốt .... Nhưng nhìn vào VBA thấy đỏ code nó ko đẹp tí nào
Sao Bill vẻ ra rắc rối thế nhỉ

Tiện có thớt này hỏi ké chút
Có cách nào xử lý đỏ code như mô tả đó khi xài #If VBA7 And Win64 Then trên Officex64 hay không ???!!! ... hay ta xoá nó đi là xong khỏi nhiều chuyện he ???!!! :D -0-0-0-
View attachment 231360
Thì nếu chỉ dành riêng cho Win 64bit và Office 64 bit thì xóa cha nó cho rồi, khỏi IF éc gì cả.
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom