Khắc phục [QR-Code] sai do bộ gõ tiếng Việt ?

Liên hệ QC

Hoàng Nhật Phương

Thành viên gắn bó
Tham gia
5/11/15
Bài viết
1,894
Được thích
1,213
Xin chào các bạn.
Có thể sử dụng code để điều khiển ứng dụng Unikey được không ạ?
Ví dụ: Unikey đang ở chế độ gõ tiếng Việt, sau khi chạy code chuyển sang chế độ gõ tiếng Anh. Hoặc Unikey đang mở thì đóng lại ạ.
**********************************
Bài viết của tôi đã được giải quyết,hiện tôi đã đưa vào áp dụng kết quả đã OK đối với tôi.

Trong chủ đề có nhiều hướng giải quyết, nhưng tôi xin phép được trích dẫn link các bài viết tiêu biểu trong chủ đề để các bạn tiện theo dõi:
1.https://www.giaiphapexcel.com/diendan/threads/khắc-phục-qr-code-sai-do-bộ-gõ-tiếng-việt.140358/#post-902152
2.https://www.giaiphapexcel.com/diendan/threads/khắc-phục-qr-code-sai-do-bộ-gõ-tiếng-việt.140358/page-3#post-902364
3.https://www.giaiphapexcel.com/diendan/threads/khắc-phục-qr-code-sai-do-bộ-gõ-tiếng-việt.140358/page-7#post-902900

Xin trân trọng cảm ơn tất cả mọi người đã nhiệt tình giúp đỡ và đóng góp ý kiến, đặc biệt với sự giúp đỡ tận tình của các thành viên: Bác @batman1 (@siwtom ) , Anh @huuthang_bd , Anh @Nguyễn Duy Tuân và Bạn @HeSanbi

Xin trân trọng cảm ơn BQT đã tạo ra và đã mang đến cho tôi và mọi người một nơi thật tuyệt vời, một nơi để mọi người cùng nhau có thể trao đổi/học hỏi và cùng nhau thành công trong sự nghiệp.
 
Lần chỉnh sửa cuối:
Nếu đã nói đến việc can thiệp vào code nguồn của Unikey thì trước hết phải xét xem tác giả có cho phép không. Sau đó sửa code nguồn chỉ để cho OT dùng. Nếu chỉ phục vụ OT thì dễ rồi. Tổ hợp Ctrl + Shift thì vẫn giữ để chuyển qua lại giữa 2 chế độ. Thêm 1 tổ hợp phím nữa mà nếu Unikey nhận được thì luôn chuyển về chế độ Anh. Tức đang Anh thì không làm gì, ngược lại thì chuyển về Anh. Cái này thì cứ bắt chước code xử lý Ctrl + Shift, chỉ có điều không chuyển qua lại mà luôn chuyển về Anh. Thế thôi. Rồi compile lại code và trang bị cho công nhân của OT. Lúc này công nhân có thêm lựa chọn là nhấn tổ hợp mới thì luôn về Anh, Nếu click hoặc tổ hợp cũ thì luôn chuyển qua lại. Code cũng có 2 lựa chọn là chuyển qua lại - giả nhấn Ctrl + Shift, và chuyển về Anh - giả nhấn tổ hợp mới.
Sửa code nguồn và compile lại là chuyện nhỏ (thêm 1 tổ hợp phím mới) nhưng tôi cho là tác giả không đồng ý.
Unikey vốn là nguồn mở mà chú. Tác giả cũng phải cóp nhặn từ nhiều nguồn mới tạo nên nó điển hình nhất là ban đầu nó lấy dll của một người Tây. Thứ nữa là Ctrl + Shift nằm trong khá nhiều bộ phím tắt của nhiều ứng dụng nên có khi vô tình tắt/mở Unikey mà không hay. Cháu toàn cài Alt+Z thôi vì bộ phím này rất ít dùng trong ứng dụng khác. Nếu giải quyết triệt để theo ý cháu thì sẽ tránh được nhiều phát sinh tương tự .
 
Lần chỉnh sửa cuối:
Upvote 0
Cách của bác Batman1: Dùng hàm API để lấy Tips của Unikey và so sánh với chuỗi "Click to turn off Vietnamese mode" có vẻ vô phương với Windows 10. Nghe giang gồ nói không có API để lấy được Handle chứa danh sách Icon của các ứng dụng trên nó. Microsoft hình như không cung cấp API để chui vào đây. Tuy nhiên với Windows XP, Vista, 7 có thể Ok vì kiến trúc khu vực này Windows không thay đổi.

theo em thấy thì kiếm hàm API nào đó chụp màn hình lại , rồi viết đoạn code xử lý ảnh cái phần tray chứa các Icon , Icon của Unikey cũng dễ nhận dạng ảnh , nếu là màu thì có 2 màu xanh , đỏ đặc trưng , nét thì gồm 2 nét V E trong ô vuông , rồi cứ theo tự nhiên gửi 1 cú click chuột vào vị trí đó trên màn hình desktop để thay đổi giữa E và V ^^

nhân tiện mã nguồn Unikey có thể down trên mạng đó , có lần hỏi 1 tiền bối mình mới biết ^^
https://www.unikey.org/download.html
 
Lần chỉnh sửa cuối:
Upvote 0
Nhân tiện Python:
- có thể tạo 'docstrings' cho UDF;
- tạo Dynamic array (gõ hàm ở một cell và kết quả trả về cả mảng xuống bảng tính) với 1 dòng lệnh (có sẵn thư viện rồi).
Hihi cái này trong delphi khong tinh code phụ trợ minh gõ dung 1 dòng code trong udf là dua arr, datashet, list grip xuống excel hết
 
Upvote 0
Con đã tải file kèm của Bác về và chạy sub VietnameseOff nhưng không thấy hiện tượng gì sảy ra,cũng không thông báo lỗi gì ạ.

Trước khi chạy code Unikey để chế độ tiếng Việt ạ, và khi con "trỏ chuột vào biểu tượng thì cũng có lời gợi ý: Click to turn off Vietnamese mode".
Con đang sử dụng Win10/Office2016 32bit ạ.
Có sự khác nhau giữa các system.

1. Trong XP thì các icon (button) nằm trong ToolbarWindow32, mà ToolbarWindow32 là con của SysPager (Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> ToolbarWindow32)

Ngoài ta cấu trúc TBBUTTON có 20 bai
Mã:
Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 1) As Byte
    dwData As Long
    iString As Long
End Type
Tức bReserved có 2 bai. Và iString là 4 bai tính từ bai 16 (tính từ 0).

2. Trong Windows 10 64 bit của người quen thì SysPager có con là ToolbarWindow32, nhưng trên nó, nếu tôi đoán đúng thì chỉ có những icon luôn luôn hiển thị. Các icon bị giấu đi thì phải click vào chỗ đỏ trong hình mới nhìn thấy. Và cái bảng đỏ cũng chính là ToolbarWindow32. Nhưng ToolbarWindow32 này là con của NotifyIconOverflowWindow (xem hình 1). Code trước tìm con của SysPager :D

tray.JPG

Ngoài ta cấu trúc TBBUTTON trên Windows 10 của hàng xóm chắc phải có 28 bai (tuy trong hình tôi đếm thấy có 24 bai).
Xem hình 2 hoặc địa chỉ
https://docs.microsoft.com/pl-pl/windows/desktop/api/commctrl/ns-commctrl-_tbbutton

TBBUTTON.JPG

Tức bReserved có 6 bai. Và iString là 4 bai tính từ bai 24 (tính từ 0).

Như vậy là có 2 thay đổi căn bản: Trên Windows 10 64 bit phải tìm cha của ToolbarWindow32 là
NotifyIconOverflowWindow. Và địa chỉ để đọc ra Tip không phải lấy từ bai 16 của cấu trúc TBButton mà phải lấy từ bai 24.

Với Windows 10 64 bit của hàng xóm thì tôi thử thấy TBBUTTON phải có 28 bai và địa chỉ để đọc ra tip phải lấy từ bai 24.

Tôi không rõ trên Windows 10 32 bit thì thế nào. Tôi đoán mò là sẽ giống XP. Tức vẫn phải tìm cha NotifyIconOverflowWindow nhưng TBBUTTON 20 bai và địa chỉ để đọc ra tip phải lấy từ bai 16.

Để kiểm nghiệm thì tôi soạn 2 phiên bản, chỉ chạy trên Windows 10 và XP. Tuy tôi đặt tên cho 32 bit và 64 bit (Windows) nhưng nếu ai test hộ thì trên mỗi system hãy chạy cả 2 phiên bản. Và ghi rõ đã chạy trên system Windows nào. Chỉ dùng với Office 32 bit vì tôi không khai báo cho 64 bit.

Về phần mình tôi mong đơi VietnameseOff_1032_xp sẽ chạy trên Windows 10 32 bit và XP, còn VietnameseOff_1064 sẽ chạy trên Windows 10 64 bit.

Hai code y hệt nhau chỉ khác khai báo là
Mã:
Dim tb As TBButton, tray As TRAYDATA
hoặc là
Mã:
Dim tb As TBButtonXP, tray As TRAYDATAXP
-----------
Mã:
Option Explicit

Private Const WM_USER As Long = &H400
Private Const TB_BUTTONCOUNT As Long = (WM_USER + 24)
Private Const TB_GETBUTTON As Long = (WM_USER + 23)
Private Const MEM_COMMIT As Long = &H1000
Private Const MEM_RELEASE As Long = &H8000
Private Const PAGE_READWRITE As Long = &H4
Private Const WM_LBUTTONDOWN As Long = &H201
Private Const WM_LBUTTONUP As Long = &H202
Private Const PROCESS_QUERY_INFORMATION As Long = (&H400)
Private Const PROCESS_ALL_ACCESS As Long = &H1F0FFF

Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 5) As Byte
    dwData As Long
    dummy(0 To 3) As Byte
    iString As Long
End Type

Private Type TBButtonXP
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 1) As Byte
    dwData As Long
    iString As Long
End Type

Private Type TRAYDATA
    hwnd As Long
    dummy(0 To 3) As Byte
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
End Type

Private Type TRAYDATAXP
    hwnd As Long
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
End Type

Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As Long, ByRef lpdwProcessId As Long) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function VirtualAllocEx Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpAddress As Any, ByRef dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As Long, ByRef lpNumberOfBytesWritten As Long) As Long
Private Declare Function VirtualFreeEx Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpAddress As Any, ByRef dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long

Private Function TrayToolbarWnd() As Long
Dim hTB As Long
    hTB = FindWindow("NotifyIconOverflowWindow", vbNullString)
    If hTB <> 0 Then
        hTB = FindWindowEx(hTB, 0, "ToolbarWindow32", vbNullString)
    Else
        hTB = FindWindow("Shell_TrayWnd", vbNullString)
        If hTB <> 0 Then
            hTB = FindWindowEx(hTB, 0, "TrayNotifyWnd", vbNullString)
            If hTB <> 0 Then
                hTB = FindWindowEx(hTB, 0, "SysPager", vbNullString)
                If hTB <> 0 Then hTB = FindWindowEx(hTB, 0, "ToolbarWindow32", vbNullString)
            End If
        End If
    End If
    TrayToolbarWnd = hTB
End Function

Sub VietnameseOff_1064()
Dim nCount As Long, k As Long, sTip As String
Dim tb As TBButton, tray As TRAYDATA
Dim pid As Long, pMemory As Long, hTB As Long, hProcess As Long, BytesRead As Long
    hTB = TrayToolbarWnd
    If hTB = 0 Then Exit Sub
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then Exit Sub
    nCount = SendMessage(hTB, TB_BUTTONCOUNT, 0, 0)
    pMemory = VirtualAllocEx(hProcess, ByVal 0, ByVal 1024, MEM_COMMIT, PAGE_READWRITE)
    For k = 0 To nCount - 1
        SendMessage hTB, TB_GETBUTTON, k, pMemory
        ReadProcessMemory hProcess, ByVal pMemory, tb, LenB(tb), BytesRead
        ReadProcessMemory hProcess, ByVal tb.dwData, tray, LenB(tray), BytesRead
        sTip = String(256, Chr(0))
        ReadProcessMemory hProcess, ByVal tb.iString, ByVal StrPtr(sTip), 256, BytesRead
        sTip = Left(sTip, InStr(1, sTip, Chr(0)) - 1)
        If sTip = "Click to turn off Vietnamese mode" Then
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONDOWN
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONUP
        End If
    Next k
    VirtualFreeEx hProcess, pMemory, 0, MEM_RELEASE
    CloseHandle hProcess
End Sub

Sub VietnameseOff_1032_xp()
Dim nCount As Long, k As Long, sTip As String
Dim tb As TBButtonXP, tray As TRAYDATAXP
Dim pid As Long, pMemory As Long, hTB As Long, hProcess As Long, BytesRead As Long
    hTB = TrayToolbarWnd
    If hTB = 0 Then Exit Sub
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then Exit Sub
    nCount = SendMessage(hTB, TB_BUTTONCOUNT, 0, 0)
    pMemory = VirtualAllocEx(hProcess, ByVal 0, ByVal 1024, MEM_COMMIT, PAGE_READWRITE)
    For k = 0 To nCount - 1
        SendMessage hTB, TB_GETBUTTON, k, pMemory
        ReadProcessMemory hProcess, ByVal pMemory, tb, LenB(tb), BytesRead
        ReadProcessMemory hProcess, ByVal tb.dwData, tray, LenB(tray), BytesRead
        sTip = String(256, Chr(0))
        ReadProcessMemory hProcess, ByVal tb.iString, ByVal StrPtr(sTip), 256, BytesRead
        sTip = Left(sTip, InStr(1, sTip, Chr(0)) - 1)
        If sTip = "Click to turn off Vietnamese mode" Then
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONDOWN
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONUP
        End If
    Next k
    VirtualFreeEx hProcess, pMemory, 0, MEM_RELEASE
    CloseHandle hProcess
End Sub
 

File đính kèm

  • VietnameseOff_10_xp.xlsm
    16.6 KB · Đọc: 15
Lần chỉnh sửa cuối:
Upvote 0
Hihi cái này trong delphi khong tinh code phụ trợ minh gõ dung 1 dòng code trong udf là dua arr, datashet, list grip xuống excel hết
Vậy à. Nhưng khác nhau nhiều lắm đó.

Bạn làm với Delphi thì cỡ vài tháng từ khi bắt đầu tới lúc tự làm được (chưa kể các trợ giúp từ người khác).

Nhưng với cách kia thì chỉ mở CMD gõ vài dòng 'pip install...' cài thư viện, rồi đọc docs mấy chục phút là làm được luôn (vì mọi thứ có sẵn rồi). :)
 
Upvote 0
Vậy à. Nhưng khác nhau nhiều lắm đó.

Bạn làm với Delphi thì cỡ vài tháng từ khi bắt đầu tới lúc tự làm được (chưa kể các trợ giúp từ người khác).

Nhưng với cách kia thì chỉ mở CMD gõ vài dòng 'pip install...' cài thư viện, rồi đọc docs mấy chục phút là làm được luôn (vì mọi thứ có sẵn rồi). :)
Hhihi mỗi cái đều có cái mạnh riêng, cái đó cũng chẳng qua có người viết sẵn dua vào sử dụng, mà cũng tiện thật
mà tùy ý thích của mọi người, theo mình cái gì tu mình mò ra mới thích hứng thú
 
Upvote 0
Vậy à. Nhưng khác nhau nhiều lắm đó.

Bạn làm với Delphi thì cỡ vài tháng từ khi bắt đầu tới lúc tự làm được (chưa kể các trợ giúp từ người khác).

Nhưng với cách kia thì chỉ mở CMD gõ vài dòng 'pip install...' cài thư viện, rồi đọc docs mấy chục phút là làm được luôn (vì mọi thứ có sẵn rồi). :)

Thành công rồi đó bác :) . Khác nhau lớn nhất chính ở "NotifyIconOverflowWindow" và "Shell_TrayWnd"và cấu trúc Button trên "ToolbarWindow32". Vấn đề còn lại làm làm cho tự động hóa khi chạy Win gì thì chạy Sub tương ứng tự động, cho cả 32, 64-bit. Vấn đề này thì không khó nữa.
 
Upvote 0
Vậy à. Nhưng khác nhau nhiều lắm đó.

Bạn làm với Delphi thì cỡ vài tháng từ khi bắt đầu tới lúc tự làm được (chưa kể các trợ giúp từ người khác).

Nhưng với cách kia thì chỉ mở CMD gõ vài dòng 'pip install...' cài thư viện, rồi đọc docs mấy chục phút là làm được luôn (vì mọi thứ có sẵn rồi). :)

Cậu em làm công ty mình học Delphi được 2 ngày đã viết được phần mềm hiển thị HTML trên Form. Hóa ra cậu ra tìm được mã nguồn trên Github. :). Như vậy yếu tố nhanh hay không nhanh để có một kết quả với người với bắt đầu là copy hay ứng dụng mã nguồn có sẵn. Python vốn dĩ là Open nên càng nhiều người tham gia thì càng có nhiều. Delphi hay .NET cũng có nhiều dự án Open. Tuy nhiên cái mà có thể thương mại hóa, định vị sản phẩm, hay bí kíp kung phu người ta vẫn phải dùng cái biên dịch để bảo vệ bí kíp. TeamViewer, RemoteDesktop, App Grap Mobile mà open source là điều khó xảy ra. Vậy mình nghĩ trong lập trình không nên chọn ngôn ngữ lập trình vì có nhiều mã nguồn mở, phải tự mình học các loại kiến thức rồi đến một kinh nghiệm sẽ ghép nối lại được thôi. Ai học chuyên ngôn ngữ nào thì sẽ thích thú nó cả.
 
Lần chỉnh sửa cuối:
Upvote 0
Có sự khác nhau giữa các system.

1. Trong XP thì các icon (button) nằm trong ToolbarWindow32, mà ToolbarWindow32 là con của SysPager (Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> ToolbarWindow32)

Ngoài ta cấu trúc TBBUTTON có 20 bai
Mã:
Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 1) As Byte
    dwData As Long
    iString As Long
End Type
Tức bReserved có 2 bai. Và iString là 4 bai tính từ bai 16 (tính từ 0).

2. Trong Windows 10 64 bit của người quen thì SysPager có con là ToolbarWindow32, nhưng trên nó, nếu tôi đoán đúng thì chỉ có những icon luôn luôn hiển thị. Các icon bị giấu đi thì phải click vào chỗ đỏ trong hình mới nhìn thấy. Và cái bảng đỏ cũng chính là ToolbarWindow32. Nhưng ToolbarWindow32 này là con của NotifyIconOverflowWindow (xem hình 1). Code trước tìm con của SysPager :D

View attachment 211463

Ngoài ta cấu trúc TBBUTTON trên Windows 10 của hàng xóm chắc phải có 28 bai (tuy trong hình tôi đếm thấy có 24 bai).
Xem hình 2 hoặc địa chỉ
https://docs.microsoft.com/pl-pl/windows/desktop/api/commctrl/ns-commctrl-_tbbutton

View attachment 211464

Tức bReserved có 6 bai. Và iString là 4 bai tính từ bai 24 (tính từ 0).

Như vậy là có 2 thay đổi căn bản: Trên Windows 10 64 bit phải tìm cha của ToolbarWindow32 là
NotifyIconOverflowWindow. Và địa chỉ để đọc ra Tip không phải lấy từ bai 16 của cấu trúc TBButton mà phải lấy từ bai 24.

Với Windows 10 64 bit của hàng xóm thì tôi thử thấy TBBUTTON phải có 28 bai và địa chỉ để đọc ra tip phải lấy từ bai 24.

Tôi không rõ trên Windows 10 32 bit thì thế nào. Tôi đoán mò là sẽ giống XP. Tức vẫn phải tìm cha NotifyIconOverflowWindow nhưng TBBUTTON 20 bai và địa chỉ để đọc ra tip phải lấy từ bai 16.

Để kiểm nghiệm thì tôi soạn 2 phiên bản, chỉ chạy trên Windows 10 và XP. Tuy tôi đặt tên cho 32 bit và 64 bit (Windows) nhưng nếu ai test hộ thì trên mỗi system hãy chạy cả 2 phiên bản. Và ghi rõ đã chạy trên system Windows nào. Chỉ dùng với Office 32 bit vì tôi không khai báo cho 64 bit.

Về phần mình tôi mong đơi VietnameseOff_1032_xp sẽ chạy trên Windows 10 32 bit và XP, còn VietnameseOff_1064 sẽ chạy trên Windows 10 64 bit.

Hai code y hệt nhau chỉ khác khai báo là
Mã:
Dim tb As TBButton, tray As TRAYDATA
hoặc là
Mã:
Dim tb As TBButtonXP, tray As TRAYDATAXP
-----------
Mã:
Option Explicit

Private Const WM_USER As Long = &H400
Private Const TB_BUTTONCOUNT As Long = (WM_USER + 24)
Private Const TB_GETBUTTON As Long = (WM_USER + 23)
Private Const MEM_COMMIT As Long = &H1000
Private Const MEM_RELEASE As Long = &H8000
Private Const PAGE_READWRITE As Long = &H4
Private Const WM_LBUTTONDOWN As Long = &H201
Private Const WM_LBUTTONUP As Long = &H202
Private Const PROCESS_QUERY_INFORMATION As Long = (&H400)
Private Const PROCESS_ALL_ACCESS As Long = &H1F0FFF

Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 5) As Byte
    dwData As Long
    dummy(0 To 3) As Byte
    iString As Long
End Type

Private Type TBButtonXP
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 1) As Byte
    dwData As Long
    iString As Long
End Type

Private Type TRAYDATA
    hwnd As Long
    dummy(0 To 3) As Byte
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
End Type

Private Type TRAYDATAXP
    hwnd As Long
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
End Type

Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As Long, ByRef lpdwProcessId As Long) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function VirtualAllocEx Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpAddress As Any, ByRef dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As Long, ByRef lpNumberOfBytesWritten As Long) As Long
Private Declare Function VirtualFreeEx Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpAddress As Any, ByRef dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long

Private Function TrayToolbarWnd() As Long
Dim hTB As Long
    hTB = FindWindow("NotifyIconOverflowWindow", vbNullString)
    If hTB <> 0 Then
        hTB = FindWindowEx(hTB, 0, "ToolbarWindow32", vbNullString)
    Else
        hTB = FindWindow("Shell_TrayWnd", vbNullString)
        If hTB <> 0 Then
            hTB = FindWindowEx(hTB, 0, "TrayNotifyWnd", vbNullString)
            If hTB <> 0 Then
                hTB = FindWindowEx(hTB, 0, "SysPager", vbNullString)
                If hTB <> 0 Then hTB = FindWindowEx(hTB, 0, "ToolbarWindow32", vbNullString)
            End If
        End If
    End If
    TrayToolbarWnd = hTB
End Function

Sub VietnameseOff_1064()
Dim nCount As Long, k As Long, sTip As String
Dim tb As TBButton, tray As TRAYDATA
Dim pid As Long, pMemory As Long, hTB As Long, hProcess As Long, BytesRead As Long
    hTB = TrayToolbarWnd
    If hTB = 0 Then Exit Sub
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then Exit Sub
    nCount = SendMessage(hTB, TB_BUTTONCOUNT, 0, 0)
    pMemory = VirtualAllocEx(hProcess, ByVal 0, ByVal 1024, MEM_COMMIT, PAGE_READWRITE)
    For k = 0 To nCount - 1
        SendMessage hTB, TB_GETBUTTON, k, pMemory
        ReadProcessMemory hProcess, ByVal pMemory, tb, LenB(tb), BytesRead
        ReadProcessMemory hProcess, ByVal tb.dwData, tray, LenB(tray), BytesRead
        sTip = String(256, Chr(0))
        ReadProcessMemory hProcess, ByVal tb.iString, ByVal StrPtr(sTip), 256, BytesRead
        sTip = Left(sTip, InStr(1, sTip, Chr(0)) - 1)
        If sTip = "Click to turn off Vietnamese mode" Then
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONDOWN
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONUP
        End If
    Next k
    VirtualFreeEx hProcess, pMemory, 0, MEM_RELEASE
    CloseHandle hProcess
End Sub

Sub VietnameseOff_1032_xp()
Dim nCount As Long, k As Long, sTip As String
Dim tb As TBButtonXP, tray As TRAYDATAXP
Dim pid As Long, pMemory As Long, hTB As Long, hProcess As Long, BytesRead As Long
    hTB = TrayToolbarWnd
    If hTB = 0 Then Exit Sub
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then Exit Sub
    nCount = SendMessage(hTB, TB_BUTTONCOUNT, 0, 0)
    pMemory = VirtualAllocEx(hProcess, ByVal 0, ByVal 1024, MEM_COMMIT, PAGE_READWRITE)
    For k = 0 To nCount - 1
        SendMessage hTB, TB_GETBUTTON, k, pMemory
        ReadProcessMemory hProcess, ByVal pMemory, tb, LenB(tb), BytesRead
        ReadProcessMemory hProcess, ByVal tb.dwData, tray, LenB(tray), BytesRead
        sTip = String(256, Chr(0))
        ReadProcessMemory hProcess, ByVal tb.iString, ByVal StrPtr(sTip), 256, BytesRead
        sTip = Left(sTip, InStr(1, sTip, Chr(0)) - 1)
        If sTip = "Click to turn off Vietnamese mode" Then
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONDOWN
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONUP
        End If
    Next k
    VirtualFreeEx hProcess, pMemory, 0, MEM_RELEASE
    CloseHandle hProcess
End Sub
Em mới Thử Windows10_x64 chạy tốt đó Anh
Anh viết chung nó hết vào WindowsXP, Windows7, Windows10 ............ x32 hay x64 chạy Off , ON chung 1 cái thì tốt :p:D
 
Upvote 0
Kéo Unikey từ Toolbar ra Taskbar chắc phải viết thêm rồi anh.
Unikey chỉ người sử dụng "Lơ tơ mơ" mới để trong Toolbar.
"Không hiểu sao có cái Ngôn ngữ Ba lan"

MÌnh là công ty chuyên triển khai các giải pháp cho các nhà máy (có nhiều công nhân) tới các chuyên viên văn phòng thì không có cái như bạn nói đâu. Việc Unikey ở Traybar là hiển nhiên rồi.
Bài đã được tự động gộp:

To Batman1: nếu bác có thời gian thì gom code để chạy tự động hóa trên mọi Windows với các nền tảng Office 32, 64 bit. Việc này những người đã lập trình Windows API tốt rồi thì nó không còn khó nữa. Nếu bác bận hay lý do nào đó chưa làm được ngay thì em có thể hỗ trợ một tay :) .
 
Lần chỉnh sửa cuối:
Upvote 0
MÌnh là công ty chuyên triển khai các giải pháp cho các nhà máy (có nhiều công nhân) tới các chuyên viên văn phòng thì không có cái như bạn nói đâu. Việc Unikey ở Traybar là hiển nhiên rồi.
Em nghĩ là anh @batman1 nên thực hiện thêm một công việc nữa là kéo Unikey ra khỏi Toolbar hoặc làm ngược lại. Để ứng dụng muôn màu muôn vẽ.
 
Upvote 0
Có sự khác nhau giữa các system.

1. Trong XP thì các icon (button) nằm trong ToolbarWindow32, mà ToolbarWindow32 là con của SysPager (Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> ToolbarWindow32)

Ngoài ta cấu trúc TBBUTTON có 20 bai
Mã:
Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 1) As Byte
    dwData As Long
    iString As Long
End Type
Tức bReserved có 2 bai. Và iString là 4 bai tính từ bai 16 (tính từ 0).

2. Trong Windows 10 64 bit của người quen thì SysPager có con là ToolbarWindow32, nhưng trên nó, nếu tôi đoán đúng thì chỉ có những icon luôn luôn hiển thị. Các icon bị giấu đi thì phải click vào chỗ đỏ trong hình mới nhìn thấy. Và cái bảng đỏ cũng chính là ToolbarWindow32. Nhưng ToolbarWindow32 này là con của NotifyIconOverflowWindow (xem hình 1). Code trước tìm con của SysPager :D

View attachment 211463

Ngoài ta cấu trúc TBBUTTON trên Windows 10 của hàng xóm chắc phải có 28 bai (tuy trong hình tôi đếm thấy có 24 bai).
Xem hình 2 hoặc địa chỉ
https://docs.microsoft.com/pl-pl/windows/desktop/api/commctrl/ns-commctrl-_tbbutton

View attachment 211464

Tức bReserved có 6 bai. Và iString là 4 bai tính từ bai 24 (tính từ 0).

Như vậy là có 2 thay đổi căn bản: Trên Windows 10 64 bit phải tìm cha của ToolbarWindow32 là
NotifyIconOverflowWindow. Và địa chỉ để đọc ra Tip không phải lấy từ bai 16 của cấu trúc TBButton mà phải lấy từ bai 24.

Với Windows 10 64 bit của hàng xóm thì tôi thử thấy TBBUTTON phải có 28 bai và địa chỉ để đọc ra tip phải lấy từ bai 24.

Tôi không rõ trên Windows 10 32 bit thì thế nào. Tôi đoán mò là sẽ giống XP. Tức vẫn phải tìm cha NotifyIconOverflowWindow nhưng TBBUTTON 20 bai và địa chỉ để đọc ra tip phải lấy từ bai 16.

Để kiểm nghiệm thì tôi soạn 2 phiên bản, chỉ chạy trên Windows 10 và XP. Tuy tôi đặt tên cho 32 bit và 64 bit (Windows) nhưng nếu ai test hộ thì trên mỗi system hãy chạy cả 2 phiên bản. Và ghi rõ đã chạy trên system Windows nào. Chỉ dùng với Office 32 bit vì tôi không khai báo cho 64 bit.

Về phần mình tôi mong đơi VietnameseOff_1032_xp sẽ chạy trên Windows 10 32 bit và XP, còn VietnameseOff_1064 sẽ chạy trên Windows 10 64 bit.

Hai code y hệt nhau chỉ khác khai báo là
Mã:
Dim tb As TBButton, tray As TRAYDATA
hoặc là
Mã:
Dim tb As TBButtonXP, tray As TRAYDATAXP
-----------
Mã:
Option Explicit

Private Const WM_USER As Long = &H400
Private Const TB_BUTTONCOUNT As Long = (WM_USER + 24)
Private Const TB_GETBUTTON As Long = (WM_USER + 23)
Private Const MEM_COMMIT As Long = &H1000
Private Const MEM_RELEASE As Long = &H8000
Private Const PAGE_READWRITE As Long = &H4
Private Const WM_LBUTTONDOWN As Long = &H201
Private Const WM_LBUTTONUP As Long = &H202
Private Const PROCESS_QUERY_INFORMATION As Long = (&H400)
Private Const PROCESS_ALL_ACCESS As Long = &H1F0FFF

Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 5) As Byte
    dwData As Long
    dummy(0 To 3) As Byte
    iString As Long
End Type

Private Type TBButtonXP
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 1) As Byte
    dwData As Long
    iString As Long
End Type

Private Type TRAYDATA
    hwnd As Long
    dummy(0 To 3) As Byte
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
End Type

Private Type TRAYDATAXP
    hwnd As Long
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
End Type

Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As Long, ByRef lpdwProcessId As Long) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function VirtualAllocEx Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpAddress As Any, ByRef dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As Long, ByRef lpNumberOfBytesWritten As Long) As Long
Private Declare Function VirtualFreeEx Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpAddress As Any, ByRef dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long

Private Function TrayToolbarWnd() As Long
Dim hTB As Long
    hTB = FindWindow("NotifyIconOverflowWindow", vbNullString)
    If hTB <> 0 Then
        hTB = FindWindowEx(hTB, 0, "ToolbarWindow32", vbNullString)
    Else
        hTB = FindWindow("Shell_TrayWnd", vbNullString)
        If hTB <> 0 Then
            hTB = FindWindowEx(hTB, 0, "TrayNotifyWnd", vbNullString)
            If hTB <> 0 Then
                hTB = FindWindowEx(hTB, 0, "SysPager", vbNullString)
                If hTB <> 0 Then hTB = FindWindowEx(hTB, 0, "ToolbarWindow32", vbNullString)
            End If
        End If
    End If
    TrayToolbarWnd = hTB
End Function

Sub VietnameseOff_1064()
Dim nCount As Long, k As Long, sTip As String
Dim tb As TBButton, tray As TRAYDATA
Dim pid As Long, pMemory As Long, hTB As Long, hProcess As Long, BytesRead As Long
    hTB = TrayToolbarWnd
    If hTB = 0 Then Exit Sub
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then Exit Sub
    nCount = SendMessage(hTB, TB_BUTTONCOUNT, 0, 0)
    pMemory = VirtualAllocEx(hProcess, ByVal 0, ByVal 1024, MEM_COMMIT, PAGE_READWRITE)
    For k = 0 To nCount - 1
        SendMessage hTB, TB_GETBUTTON, k, pMemory
        ReadProcessMemory hProcess, ByVal pMemory, tb, LenB(tb), BytesRead
        ReadProcessMemory hProcess, ByVal tb.dwData, tray, LenB(tray), BytesRead
        sTip = String(256, Chr(0))
        ReadProcessMemory hProcess, ByVal tb.iString, ByVal StrPtr(sTip), 256, BytesRead
        sTip = Left(sTip, InStr(1, sTip, Chr(0)) - 1)
        If sTip = "Click to turn off Vietnamese mode" Then
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONDOWN
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONUP
        End If
    Next k
    VirtualFreeEx hProcess, pMemory, 0, MEM_RELEASE
    CloseHandle hProcess
End Sub

Sub VietnameseOff_1032_xp()
Dim nCount As Long, k As Long, sTip As String
Dim tb As TBButtonXP, tray As TRAYDATAXP
Dim pid As Long, pMemory As Long, hTB As Long, hProcess As Long, BytesRead As Long
    hTB = TrayToolbarWnd
    If hTB = 0 Then Exit Sub
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then Exit Sub
    nCount = SendMessage(hTB, TB_BUTTONCOUNT, 0, 0)
    pMemory = VirtualAllocEx(hProcess, ByVal 0, ByVal 1024, MEM_COMMIT, PAGE_READWRITE)
    For k = 0 To nCount - 1
        SendMessage hTB, TB_GETBUTTON, k, pMemory
        ReadProcessMemory hProcess, ByVal pMemory, tb, LenB(tb), BytesRead
        ReadProcessMemory hProcess, ByVal tb.dwData, tray, LenB(tray), BytesRead
        sTip = String(256, Chr(0))
        ReadProcessMemory hProcess, ByVal tb.iString, ByVal StrPtr(sTip), 256, BytesRead
        sTip = Left(sTip, InStr(1, sTip, Chr(0)) - 1)
        If sTip = "Click to turn off Vietnamese mode" Then
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONDOWN
            PostMessage tray.hwnd, tray.uCallbackMessage, tray.uID, WM_LBUTTONUP
        End If
    Next k
    VirtualFreeEx hProcess, pMemory, 0, MEM_RELEASE
    CloseHandle hProcess
End Sub

Cảm ơn bác Siwtom,con đã thử code trong file kèm trên 2 phiên bản win7-32bit / win10-64bit.
Kết quả đúng là đã có tác dụng Unikey đang ở chế độ tiếng Việt thì chuyển về tiếng Anh, còn đang ở tiếng Anh thì giữ nguyên.
Thật vi diệu, cảm ơn Bác Siwtom nhiều ạ.
 
Upvote 0
Cảm ơn bác Siwtom,con đã thử code trong file kèm trên 2 phiên bản win7-32bit / win10-64bit.
Kết quả đúng là đã có tác dụng Unikey đang ở chế độ tiếng Việt thì chuyển về tiếng Anh, còn đang ở tiếng Anh thì giữ nguyên.
Thật vi diệu, cảm ơn Bác Siwtom nhiều ạ.

"Trời" - Bác ấy đã giúp phải giúp đến tất tần tật mới chịu sao
Mã:
If sTip = "Click to turn off Vietnamese mode" Or sTip = "Click to turn on Vietnamese mode" Then
OT muốn click bao nhiêu lần cũng được.
Hoặc sửa Sub thêm 1 biến Boolean để xác nhận mở và tắt
"Bác ấy muốn làm Người Dơi không phải Siwtom"
 
Upvote 0
Em nghĩ là anh @batman1 nên thực hiện thêm một công việc nữa là kéo Unikey ra khỏi Toolbar hoặc làm ngược lại. Để ứng dụng muôn màu muôn vẽ.

Xin chào HeSanbi, có phải Toolbar là cái khung màu đỏ này:

Khung1.png Khung2.png

OT test thử nếu biểu tượng unikey nằm trong khung màu đỏ trên thì Code của bác Siwtom OK.


Còn biểu tượng nằm ngoài khung này,code không có hiện tượng gì ạ.
Ngoai1.png Ngoai2.png
 
Upvote 0
Hiển nhiên rồi.
Bác ấy chưa viết code Click trên Taskbar.

Vì bạn nói là Taskbar nên mình lại nghĩ nó nằm gần khu vực nút Start (do tên gọi nhầm khu vực của icon). Nếu như hình của bạn OT thì đúng là cần phải xử lý. Từ Win7 về trước thì nó nằm ngoài, Win10 lúc thì nằm ở Float Window lúc thì nằm trên SysTray nên phải làm nhiều hơn nữa.
 
Upvote 0
Mình có ý tưởng như sau: Nếu mở file excel (này) hoặc file excel bất kỳ thì cho vòng lặp close unikeynt.exe là được.
Code quá đơn giản nếu làm bằng 1 phần mềm khác rồi cho chạy ẩn.
 
Upvote 0
Vì bạn nói là Taskbar nên mình lại nghĩ nó nằm gần khu vực nút Start (do tên gọi nhầm khu vực của icon). Nếu như hình của bạn OT thì đúng là cần phải xử lý. Từ Win7 về trước thì nó nằm ngoài, Win10 lúc thì nằm ở Float Window lúc thì nằm trên SysTray nên phải làm nhiều hơn nữa.

Taskbar - Định nghĩa thanh tác vụ của windows xưa nay mà anh.

Không biết anh @batman1 có đọc bài trong này không. Sao Code API của ảnh nó ít khác.
buttons-in-your-taskbar , button-on-toolbar
 
Lần chỉnh sửa cuối:
Upvote 0
Mình có ý tưởng như sau: Nếu mở file excel (này) hoặc file excel bất kỳ thì cho vòng lặp close unikeynt.exe là được.
Code quá đơn giản nếu làm bằng 1 phần mềm khác rồi cho chạy ẩn.

Nếu không còn cách nào mới làm như thế. Vì đây là tìm cách tốt nhất có thể và nó đang là làm được mà.
Bài đã được tự động gộp:

Taskbar - Định nghĩa thanh tác vụ của windows xưa nay mà anh.

Không biết anh @batman1 có đọc bài trong này không. Sao Code API của ảnh nó ít khác.
buttons-in-your-taskbar

Lập trình thì mình phân rõ khu vực để tương tác tập trung. Khái niện Taskbar là chung rồi.
 
Upvote 0
Web KT
Back
Top Bottom