Khắc phục [QR-Code] sai do bộ gõ tiếng Việt ? (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Hoàng Nhật Phương

Thành viên gắn bó
Tham gia
5/11/15
Bài viết
1,895
Được thích
1,219
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:
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

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
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.
À ý anh là nói chuyện trong cái Code của anh batman . Thì mình phải nói SySpager hoặc ToolbarWindows32...
Nhưng nói với người không biết nó là gì thì "Taskbar"
Toolbar thì Systems Tray.
 
Upvote 0
@Nguyễn Duy Tuân
Bổng dưng đọc lại đoạn Code thấy có Shell_TrayWnd và NotifyIconOverflowWindow , thành ra anh @batman1 đã dựng sẵn tất cả
Tức là sẽ click được lên cả Toolbar và Taskbar.

@Nguyễn Hoàng Oanh Thơ
Nếu bài viết đã nhận được kết quả và không có thêm ai đóng góp nữa thì lời khuyên của tôi:
1. OT sửa lại bài viết tổng hợp lại bài và thêm: "Bài viết đã hoàn thành:" có thể sao chép code dưới của tôi để vào bài viết.
2. Tải lên file đã được anh @batman1 hỗ trợ tốt nhất.
3. Tag @tên người đã hỗ trợ đóng góp cho bạn. và để tên người đóng góp chính là anh @batman1
(Sự đền đáp dễ nhất)

Mọi người xem Code dưới đây cải tiến lại từ Code của anh @batman1
Và mượn thêm một số Code trên Internet để mọi người tiện việc phát triển
PHP:
Option Explicit
Option Compare Text

#If VBA7 Then
  Private Declare PtrSafe Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
  Private Declare PtrSafe Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
  Private Declare PtrSafe Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
  Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As LongPtr, ByRef lpdwProcessId As Long) As Long
  Private Declare PtrSafe Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Private Declare PtrSafe Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Private Declare PtrSafe 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 PtrSafe 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 PtrSafe 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 PtrSafe Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long


  Private Declare PtrSafe Function EnumWindows Lib "user32" (ByVal lpEnumFunc As LongPtr, lParam As Any) As Long

  Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, _
                                                                      ByVal lpString As String, _
                                                                      ByVal cch As Long) As Long
  Private Declare PtrSafe Function GetParent Lib "user32" (ByVal hwnd As LongPtr) As Long
  Private Declare PtrSafe Function EnumChildWindows Lib "user32" (ByVal hWndParent _
                                                  As Long, ByVal lpEnumFunc As LongPtr, ByVal lParam As Long) As Long
  Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, _
                                                                    ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

  Private Declare PtrSafe Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, _
                                                                   ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
  Private Declare PtrSafe Function FindWindowX Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, _
                                                                   ByVal hWnd2 As LongPtr, ByVal lpsz1 As Long, ByVal lpsz2 As Long) As Long




  Private Declare PtrSafe Function CreateFileMapping Lib "KERNEL32" Alias "CreateFileMappingA" (ByVal hFile As Long, ByVal lpFileMappigAttributes As Long, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long


  Private Declare PtrSafe Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (ByVal lpDest As Long, ByVal lpSource As Long, ByVal cBytes As Long)
  Private Declare PtrSafe Function MapViewOfFile Lib "KERNEL32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
  Private Declare PtrSafe Function GetVersionEx Lib "KERNEL32" Alias "GetVersionExA" (LpVersionInformation As OSVERSIONINFO) As Long


#Else

  Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, lParam As Any) As Long

  Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, _
                                                                      ByVal lpString As String, _
                                                                      ByVal cch As Long) As Long
  Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
  Private Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent _
                                                  As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
  Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, _
                                                                    ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

  Private Declare Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
                                                                   ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
  Private Declare Function FindWindowX Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, _
                                                                   ByVal hWnd2 As Long, ByVal lpsz1 As Long, ByVal lpsz2 As Long) As Long
  Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
                                       (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
  Private Declare Function ReadProcessMemory Lib "KERNEL32" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByVal lpBuffer As Long, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
  Private Declare Function OpenProcess Lib "KERNEL32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
  Private Declare Function VirtualAllocEx Lib "KERNEL32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
  Private Declare Function CreateFileMapping Lib "KERNEL32" Alias "CreateFileMappingA" (ByVal hFile As Long, ByVal lpFileMappigAttributes As Long, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long

  Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
  Private Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (ByVal lpDest As Long, ByVal lpSource As Long, ByVal cBytes As Long)
  Private Declare Function MapViewOfFile Lib "KERNEL32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
  Private Declare Function GetVersionEx Lib "KERNEL32" Alias "GetVersionExA" (LpVersionInformation As OSVERSIONINFO) As Long
  Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) 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 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
#End If

Public Const WM_GETTEXT = &HD
Const PROCESS_VM_OPERATION = &H8
Const PROCESS_VM_READ = &H10
Const PROCESS_VM_WRITE = &H20
Const MEM_RESERVE = &H2000&
Const MEM_COMMIT = &H1000&
Const PAGE_READWRITE = &H4
Const STANDARD_RIGHTS_REQUIRED = &HF0000
Const SECTION_QUERY = &H1
Const SECTION_MAP_WRITE = &H2
Const SECTION_MAP_READ = &H4
Const SECTION_MAP_EXECUTE = &H8
Const SECTION_EXTEND_SIZE = &H10
Const SECTION_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE

Const FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS
Public Type OSVERSIONINFO
    dwOSVersionInfoSize As Long
    dwMajorVersion As Long
    dwMinorVersion As Long
    dwBuildNumber As Long
    dwPlatformId As Long
    szCSDVersion As String * 128
End Type
Public WIN As OSVERSIONINFO
Global MyButton As TBButton, lResult As Long
Private Const WM_COMMAND As Long = &H111
Private Const WM_USER& = &H400
Public Const TB_COMMANDTOINDEX As Integer = (WM_USER + 25)
Public Const TB_GETBUTTONTEXTA As Integer = (WM_USER + 45)
Public Const TB_GETBUTTONTEXTW As Long = (WM_USER + 75)
Public Const TB_GETBUTTONINFO As Long = (WM_USER + 65)
Private PlatformKnown As Boolean  ' have we identified the platform?
Private NTflag As Boolean    ' if so, are we NT family (NT, 2K,XP) or non-NT (9x)?
Public myBTNCnt As Integer
Public myBTNtoPress As Integer
Private Const TBSTATE_HIDDEN As Long = &H8

Private Const TB_BUTTONCOUNT& = (WM_USER + 24)
Private Const TB_GETBUTTON& = (WM_USER + 23)
Private Const MEM_RELEASE& = &H8000
Private Const WM_LBUTTONDOWN& = &H201
Private Const WM_LBUTTONUP& = &H202
Private Const PROCESS_QUERY_INFORMATION& = (&H400)
Private Const PROCESS_ALL_ACCESS& = &H1F0FFF
Private Type TrayMore
    SyshWnd As Long
    SysIconId As Long
End Type

'Private Type TBButton
    'iBitmap As Long
    'idCommand As Long
    'fsState As Byte
    'fsStyle As Byte
    'bReserved1 As Byte
    'bReserved2 As Byte
    'dwData As Long
    'iString As Long
'End Type

Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
  #If Win64 Then
    bReserved(0 To 5) As Byte
    dwData As Long
    dummy(0 To 3) As Byte
  #Else
    bReserved(0 To 1) As Byte
    dwData As Long
  #End If
    iString As Long
End Type
Private Type TRAYDATA
    hwnd As Long
  #If Win64 Then
    dummy(0 To 3) As Byte
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
  #Else
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
  #End If
    hIcon As Long
End Type



Private fpHandle As Long    ' the foreign-process instance handle. When we want
' memory on NT platforms, this is returned to us by
' OpenProcess, and we pass it in to VirtualAllocEx.
Private TitleToFind As String
Sub test_GetTBAppInTaskbarOn()
  Dim Where$
  TurnAppInTaskbar True, Where
  MsgBox Where
End Sub
Sub test_GetTBAppInTaskbarOff()
  Dim Where$
  TurnAppInTaskbar False, Where
  MsgBox Where
End Sub
Private Function TurnAppInTaskbar(Optional Byval TurnOnSysTray As Boolean = True, Optional Where$) As Boolean
  Dim hTB&
    hTB = FindWindow("NotifyIconOverflowWindow", vbNullString)
    If hTB <> 0 Then
        hTB = FindWindowEx(hTB, 0, "ToolbarWindow32", vbNullString)
        If AppInSystemTray(hTB, TurnOnSysTray) Then
          Where$ = "Toolbar": TurnAppInTaskbar = True: Exit Function
        End If
    End If
    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)
              If AppInSystemTray(hTB, TurnOnSysTray) Then
                Where$ = "Taskbar": TurnAppInTaskbar = True
              End If
            End If
        End If
    End If
End Function
Private Function AppInSystemTray(ByVal hTB&, Optional Byval TurnOnSysTray As Boolean = True) As Boolean
  Dim nCount&, k&, sTip$, tb As TBButton, tray As TRAYDATA, _
  pid&, pMemory&, hProcess&, BytesRead&
    If hTB = 0 Then GoTo Ends
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then GoTo Ends
    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" And Not TurnOnSysTray) Or _
               (sTip = "Click to turn on Vietnamese mode" And TurnOnSysTray) Then
            AppInSystemTray = True
            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
    Exit Function
Ends:
  AppInSystemTray = False
End Function
Sub testTB()
    Dim mytitle&
    Dim hparent&
    mytitle = "Unikey MainWnd"
    myBTNCnt = 200 'Bao nhieu Nút tren Toolbar
    myBTNtoPress = 201

    MsgBox FindWindowByTitle(mytitle)
    hparent = FindWindowByTitle(mytitle)
    EnumChildWindow hparent, 0   ' one call directly to list parent
    EnumChildWindows hparent, AddressOf EnumChildWindow, 0

End Sub

  Function FindWindowByTitle&(winTitle&)
  'returns the handle of the top window
  'with the title "winTitle"

      Dim t&

      'set public titletofind to wintitle
      TitleToFind = winTitle
      EnumWindows AddressOf FindWindowByTitlePROC, t
      'reset public titletofind
      TitleToFind = ""

      FindWindowByTitle = t

  End Function


  Function EnumChildWindow&(ByVal hChild&, ByVal lParam&)

      Dim wClass&, wText&, j%, TBhWnd&, xpBuffer&, z1 As Variant, tbcount&
      Dim i&, TBBUTT As TBButton, hProcess&, pMemory&
      wClass = Space(64)
      j = GetClassName(hChild, wClass, 63)
      wClass = Left(wClass, j)
      wText = Space(256)
      j = SendMessageS(hChild, WM_GETTEXT, 255, wText)
      wText = Left(wText, j)

      Debug.Print "Enum " & hChild; ", "; wClass;
      If Len(wText) Then Debug.Print ", """; wText; """";
      Debug.Print
      If wClass = "ToolbarWindow32" Then
          tbcount = SendMessageS(hChild, TB_BUTTONCOUNT, 0, 0)
          MsgBox "Button Count:" & tbcount
          pMemory = VirtualAllocEx(hProcess, ByVal 0, ByVal 1024, MEM_COMMIT, PAGE_READWRITE)
          If tbcount = myBTNCnt Then  'This will select the correct toolbar - Need to find buttoncount
              For i = 0 To tbcount - 1
                  TBhWnd = hChild
                  MsgBox i
                  If i = myBTNtoPress Then
                      '*********************************************************************
                      'This is the part that I am failing on...
                      xpBuffer = drMemoryAlloc(hChild, 1024)

                      ' lResult = SendMessage(TBhWnd, TB_GETBUTTON, i, xpBuffer)
                      lResult = SendMessage(TBhWnd, TB_GETBUTTONINFO, i, xpBuffer)
                      MsgBox "lResult =" & lResult
                      '  drMemoryRead xpBuffer, VarPtr(i), Len(i)
                      '*********************************************************************
                  End If



              Next

          End If
      End If
      EnumChildWindow = 1  ' Continue enumeration
  End Function

  Function FindWindowByTitlePROC(ByVal hwnd&, lParam&) As Boolean
  'this is the callback function procedure..do not change order
  ' or type of parameters in the procedure definition

      If hwnd = 0 Then
          lParam = 0
          'stop enumerating
          FindWindowByTitlePROC = False
      End If

      'see if the Hwnd is the one with the title
      If UCase(GetCaption(hwnd)) Like UCase(TitleToFind) & "*" Then
          'set return value
          lParam = CLng(hwnd)
          'stop enumerating
          FindWindowByTitlePROC = False
      Else
          'continue enumerating (not found)
          FindWindowByTitlePROC = True
      End If

  End Function
  Function GetCaption&(ByVal hwnd&)
  'returns the caption of the window with handle "hwnd"

      Dim sTemp&, c%
      sTemp = String$(255, 0)
      c = GetWindowText(hwnd, sTemp, 256)

      GetCaption = Left$(sTemp, c)

  End Function
  Public Function drMemoryAlloc&(ByVal xpWindow&, ByVal nBytes&)
  '
  ' Returns pointer to a share-able buffer (size nBytes) in target process
  '   that owns xpWindow
  '
      Dim xpThread&    ' target control's thread id
      Dim xpID&        '                  process id
      If WindowsNT Then
          xpThread = GetWindowThreadProcessId(xpWindow, xpID)
          drMemoryAlloc = VirtualAllocNT(xpID, nBytes)
      Else
          drMemoryAlloc = VirtualAlloc9X(nBytes)
      End If
  End Function
  Public Sub drMemoryRead(ByVal xpBuffer&, ByVal myBuffer&, ByVal nBytes&)
      If WindowsNT Then
          ReadProcessMemory fpHandle, xpBuffer, myBuffer, nBytes, 0
      Else
          CopyMemory myBuffer, xpBuffer, nBytes
      End If
  End Sub
Sub test_WindowsNT()
  MsgBox WindowsNT
End Sub
  Public Function WindowsNT() As Boolean
  ' return TRUE if NT-like platform (NT, 2000, XP, etc)
      If Not PlatformKnown Then GetWindowsVersion
      WindowsNT = NTflag
  End Function
  Private Function VirtualAllocNT&(ByVal fpID&, ByVal memSize&)
      fpHandle = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, fpID)
      VirtualAllocNT = VirtualAllocEx(fpHandle, ByVal 0&, ByVal memSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE)
  End Function
  Private Function VirtualAlloc9X&(ByVal memSize&)
      fpHandle = CreateFileMapping(&HFFFFFFFF, 0, PAGE_READWRITE, 0, memSize, vbNullString)
      VirtualAlloc9X = MapViewOfFile(fpHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0)
  End Function
  Public Sub GetWindowsVersion()
      WIN.dwOSVersionInfoSize = Len(WIN)
      If (GetVersionEx(WIN)) = 0 Then Exit Sub  ' in deep doo if this fails
      NTflag = (WIN.dwPlatformId = 2)
      PlatformKnown = True
  End Sub
 
Lần chỉnh sửa cuối:
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"
Trong bài tôi có đề cập tới khu vực có icon luôn luôn hiển thị mà ở đó ToolbarWindow32 có cha là SysPager. Tôi nghĩ đây có thể là trường hợp này. Rất tiếc là tôi đã đề nghị nhưng bạn không cho biết đó là Windows nào.

Với trường hợp như trên bạn hãy chạy từng bước TrayToolbarWnd và cho biết hTB là con của SysPager hay là con của NotifyIconOverflowWindow mà code lại không có icon Unikey để xét thì 99% ToolbarWindow32 với Unikey là con của SysPager. Lúc này thì ta duyệt 2 lượt. Lượt 1 tìm NotifyIconOverflowWindow với ToolbarWindow32, và lượt 2 tìm SysPager với NotifyIconOverflowWindow. Vì lần trước khi tìm thấy NotifyIconOverflowWindow thì code không tìm nữa. Lần này ta thử tìm cả 2. Tìm thấy NotifyIconOverflowWindow rồi thì vẫn tìm SysPager.

Tôi sẽ viết lại để nếu tìm thấy NotifyIconOverflowWindow nhưng không có icon nào của Unikey thì sẽ tìm tiếp trên SysPager.

Còn chuyện tự động tìm phiên bản Windows thì tôi nghĩ là dùng GetVersionEx. Cái này tôi nhờ Tuân làm hộ. Hồi xưa tôi chỉ nhớ số nào, ký hiệu nào là 95, 98, XP. Còn những phiên bản mới hơn XP tôi không quan tâm nên nếu giờ tìm đọc thì mất thời gian.

Tôi chỉ làm Windows XP 10 và XP vì tôi không có các phiên bản khác để biết Tray mặt mũi thế nào, và để test.

À, ngôn ngữ Ba Lan vì Windows phiên bản Ba Lan dùng bởi người Ba Lan mà.
 
Upvote 0
Trong bài tôi có đề cập tới khu vực có icon luôn luôn hiển thị mà ở đó ToolbarWindow32 có cha là SysPager. Tôi nghĩ đây có thể là trường hợp này. Rất tiếc là tôi đã đề nghị nhưng bạn không cho biết đó là Windows nào.

Với trường hợp như trên bạn hãy chạy từng bước TrayToolbarWnd và cho biết hTB là con của SysPager hay là con của NotifyIconOverflowWindow mà code lại không có icon Unikey để xét thì 99% ToolbarWindow32 với Unikey là con của SysPager. Lúc này thì ta duyệt 2 lượt. Lượt 1 tìm NotifyIconOverflowWindow với ToolbarWindow32, và lượt 2 tìm SysPager với NotifyIconOverflowWindow. Vì lần trước khi tìm thấy NotifyIconOverflowWindow thì code không tìm nữa. Lần này ta thử tìm cả 2. Tìm thấy NotifyIconOverflowWindow rồi thì vẫn tìm SysPager.

Tôi sẽ viết lại để nếu tìm thấy NotifyIconOverflowWindow nhưng không có icon nào của Unikey thì sẽ tìm tiếp trên SysPager.

Còn chuyện tự động tìm phiên bản Windows thì tôi nghĩ là dùng GetVersionEx. Cái này tôi nhờ Tuân làm hộ. Hồi xưa tôi chỉ nhớ số nào, ký hiệu nào là 95, 98, XP. Còn những phiên bản mới hơn XP tôi không quan tâm nên nếu giờ tìm đọc thì mất thời gian.

Tôi chỉ làm Windows XP 10 và XP vì tôi không có các phiên bản khác để biết Tray mặt mũi thế nào, và để test.

À, ngôn ngữ Ba Lan vì Windows phiên bản Ba Lan dùng bởi người Ba Lan mà.
Anh đọc lại trên bài này của anh một bài code của anh em đã cải tiến thêm, và thêm hỗ trợ. Thì ra ở đây có 1 người Ba Lan
 
Lần chỉnh sửa cuối:
Upvote 0
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
Bài trong Link tôi chưa đọc nhưng ngày xưa tôi vọc Windows API nên các hàm đều biết. Nhưng cái quan trọng nhất là đọc ra vùng dữ liệu rồi thì phải biết những bai nào có ý nghĩa là gì. Ví như bài trước tôi cũng đọc ra được vùng dữ liệu nhưng trên XP và Windows 10 dwData và iString nó nằm ở những vị trí khác nhau nên khi dùng dwData để đọc ra Tip thì không đúng.

Taskbar hồi xưa tôi cũng vọc nhiều nhưng chỉ trên 98 và XP thôi. Những hàm VirtualAllocEx và Read(Write)ProcessMemory cũng dùng nhiều khi inject code (kiểu như rootkit) vào không gian địa chỉ của process khác.
 
Upvote 0
@Nguyễn Hoàng Oanh Thơ , @Nguyễn Duy Tuân
Bổng dưng đọc lại đoạn Code thấy có Shell_TrayWnd và NotifyIconOverflowWindow , thành ra anh @batman1 đã dựng sẵn tất cả
Tức là sẽ click được lên cả Toolbar và Taskbar.

Mọi người xem Code dưới đây cải tiến lại từ Code của anh @batman1
Và mượn thêm một số Code trên Internet để mọi người tiện việc phát triển
PHP:
Option Explicit
Option Compare Text

#If VBA7 Then
  Private Declare PtrSafe Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
  Private Declare PtrSafe Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
  Private Declare PtrSafe Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
  Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As LongPtr, ByRef lpdwProcessId As Long) As Long
  Private Declare PtrSafe Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Private Declare PtrSafe Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  Private Declare PtrSafe 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 PtrSafe 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 PtrSafe 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 PtrSafe Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long


  Private Declare PtrSafe Function EnumWindows Lib "user32" (ByVal lpEnumFunc As LongPtr, lParam As Any) As Long

  Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, _
                                                                      ByVal lpString As String, _
                                                                      ByVal cch As Long) As Long
  Private Declare PtrSafe Function GetParent Lib "user32" (ByVal hwnd As LongPtr) As Long
  Private Declare PtrSafe Function EnumChildWindows Lib "user32" (ByVal hWndParent _
                                                  As Long, ByVal lpEnumFunc As LongPtr, ByVal lParam As Long) As Long
  Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, _
                                                                    ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

  Private Declare PtrSafe Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, _
                                                                   ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
  Private Declare PtrSafe Function FindWindowX Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, _
                                                                   ByVal hWnd2 As LongPtr, ByVal lpsz1 As Long, ByVal lpsz2 As Long) As Long




  Private Declare PtrSafe Function CreateFileMapping Lib "KERNEL32" Alias "CreateFileMappingA" (ByVal hFile As Long, ByVal lpFileMappigAttributes As Long, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long


  Private Declare PtrSafe Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (ByVal lpDest As Long, ByVal lpSource As Long, ByVal cBytes As Long)
  Private Declare PtrSafe Function MapViewOfFile Lib "KERNEL32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
  Private Declare PtrSafe Function GetVersionEx Lib "KERNEL32" Alias "GetVersionExA" (LpVersionInformation As OSVERSIONINFO) As Long


#Else

  Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, lParam As Any) As Long

  Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, _
                                                                      ByVal lpString As String, _
                                                                      ByVal cch As Long) As Long
  Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
  Private Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent _
                                                  As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
  Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, _
                                                                    ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

  Private Declare Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
                                                                   ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
  Private Declare Function FindWindowX Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, _
                                                                   ByVal hWnd2 As Long, ByVal lpsz1 As Long, ByVal lpsz2 As Long) As Long
  Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
                                       (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
  Private Declare Function ReadProcessMemory Lib "KERNEL32" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByVal lpBuffer As Long, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
  Private Declare Function OpenProcess Lib "KERNEL32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
  Private Declare Function VirtualAllocEx Lib "KERNEL32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
  Private Declare Function CreateFileMapping Lib "KERNEL32" Alias "CreateFileMappingA" (ByVal hFile As Long, ByVal lpFileMappigAttributes As Long, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long

  Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
  Private Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (ByVal lpDest As Long, ByVal lpSource As Long, ByVal cBytes As Long)
  Private Declare Function MapViewOfFile Lib "KERNEL32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
  Private Declare Function GetVersionEx Lib "KERNEL32" Alias "GetVersionExA" (LpVersionInformation As OSVERSIONINFO) As Long
  Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Any) 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 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
#End If

Public Const WM_GETTEXT = &HD
Const PROCESS_VM_OPERATION = &H8
Const PROCESS_VM_READ = &H10
Const PROCESS_VM_WRITE = &H20
Const MEM_RESERVE = &H2000&
Const MEM_COMMIT = &H1000&
Const PAGE_READWRITE = &H4
Const STANDARD_RIGHTS_REQUIRED = &HF0000
Const SECTION_QUERY = &H1
Const SECTION_MAP_WRITE = &H2
Const SECTION_MAP_READ = &H4
Const SECTION_MAP_EXECUTE = &H8
Const SECTION_EXTEND_SIZE = &H10
Const SECTION_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE

Const FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS
Public Type OSVERSIONINFO
    dwOSVersionInfoSize As Long
    dwMajorVersion As Long
    dwMinorVersion As Long
    dwBuildNumber As Long
    dwPlatformId As Long
    szCSDVersion As String * 128
End Type
Public WIN As OSVERSIONINFO
Global MyButton As TBButton, lResult As Long
Private Const WM_COMMAND As Long = &H111
Private Const WM_USER& = &H400
Public Const TB_COMMANDTOINDEX As Integer = (WM_USER + 25)
Public Const TB_GETBUTTONTEXTA As Integer = (WM_USER + 45)
Public Const TB_GETBUTTONTEXTW As Long = (WM_USER + 75)
Public Const TB_GETBUTTONINFO As Long = (WM_USER + 65)
Private PlatformKnown As Boolean  ' have we identified the platform?
Private NTflag As Boolean    ' if so, are we NT family (NT, 2K,XP) or non-NT (9x)?
Public myBTNCnt As Integer
Public myBTNtoPress As Integer
Private Const TBSTATE_HIDDEN As Long = &H8

Private Const TB_BUTTONCOUNT& = (WM_USER + 24)
Private Const TB_GETBUTTON& = (WM_USER + 23)
Private Const MEM_RELEASE& = &H8000
Private Const WM_LBUTTONDOWN& = &H201
Private Const WM_LBUTTONUP& = &H202
Private Const PROCESS_QUERY_INFORMATION& = (&H400)
Private Const PROCESS_ALL_ACCESS& = &H1F0FFF
Private Type TrayMore
    SyshWnd As Long
    SysIconId As Long
End Type

'Private Type TBButton
    'iBitmap As Long
    'idCommand As Long
    'fsState As Byte
    'fsStyle As Byte
    'bReserved1 As Byte
    'bReserved2 As Byte
    'dwData As Long
    'iString As Long
'End Type

Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
  #If Win64 Then
    bReserved(0 To 5) As Byte
    dwData As Long
    dummy(0 To 3) As Byte
  #Else
    bReserved(0 To 1) As Byte
    dwData As Long
  #End If
    iString As Long
End Type
Private Type TRAYDATA
  #If Win64 Then
    hwnd As Long
    dummy(0 To 3) As Byte
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
  #Else
    hwnd As Long
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
  #End If
End Type



Private fpHandle As Long    ' the foreign-process instance handle. When we want
' memory on NT platforms, this is returned to us by
' OpenProcess, and we pass it in to VirtualAllocEx.
Private TitleToFind As String
Sub test_GetTBAppInTaskbarOn()
  Dim Where$
  TurnAppInTaskbar True, Where
  MsgBox Where
End Sub
Sub test_GetTBAppInTaskbarOff()
  Dim Where$
  TurnAppInTaskbar False, Where
  MsgBox Where
End Sub
Private Function TurnAppInTaskbar(Optional Byval TurnOnSysTray As Boolean = True, Optional Where$) As Boolean
  Dim hTB&
    hTB = FindWindow("NotifyIconOverflowWindow", vbNullString)
    If hTB <> 0 Then
        hTB = FindWindowEx(hTB, 0, "ToolbarWindow32", vbNullString)
        If AppInSystemTray(hTB, TurnOnSysTray) Then
          Where$ = "Toolbar": TurnAppInTaskbar = True: Exit Function
        End If
    End If
    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)
              If AppInSystemTray(hTB, TurnOnSysTray) Then
                Where$ = "Taskbar": TurnAppInTaskbar = True
              End If
            End If
        End If
    End If
End Function
Private Function AppInSystemTray(ByVal hTB&, Optional Byval TurnOnSysTray As Boolean = True) As Boolean
  Dim nCount&, k&, sTip$, tb As TBButton, tray As TRAYDATA, _
  pid&, pMemory&, hProcess&, BytesRead&
    If hTB = 0 Then GoTo Ends
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then GoTo Ends
    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" And Not TurnOnSysTray) Or _
               (sTip = "Click to turn on Vietnamese mode" And TurnOnSysTray) Then
            AppInSystemTray = True
            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
    Exit Function
Ends:
  AppInSystemTray = False
End Function
Sub testTB()
    Dim mytitle&
    Dim hparent&
    mytitle = "Unikey MainWnd"
    myBTNCnt = 200 'Bao nhieu Nút tren Toolbar
    myBTNtoPress = 201

    MsgBox FindWindowByTitle(mytitle)
    hparent = FindWindowByTitle(mytitle)
    EnumChildWindow hparent, 0   ' one call directly to list parent
    EnumChildWindows hparent, AddressOf EnumChildWindow, 0

End Sub

  Function FindWindowByTitle&(winTitle&)
  'returns the handle of the top window
  'with the title "winTitle"

      Dim t&

      'set public titletofind to wintitle
      TitleToFind = winTitle
      EnumWindows AddressOf FindWindowByTitlePROC, t
      'reset public titletofind
      TitleToFind = ""

      FindWindowByTitle = t

  End Function


  Function EnumChildWindow&(ByVal hChild&, ByVal lParam&)

      Dim wClass&, wText&, j%, TBhWnd&, xpBuffer&, z1 As Variant, tbcount&
      Dim i&, TBBUTT As TBButton, hProcess&, pMemory&
      wClass = Space(64)
      j = GetClassName(hChild, wClass, 63)
      wClass = Left(wClass, j)
      wText = Space(256)
      j = SendMessageS(hChild, WM_GETTEXT, 255, wText)
      wText = Left(wText, j)

      Debug.Print "Enum " & hChild; ", "; wClass;
      If Len(wText) Then Debug.Print ", """; wText; """";
      Debug.Print
      If wClass = "ToolbarWindow32" Then
          tbcount = SendMessageS(hChild, TB_BUTTONCOUNT, 0, 0)
          MsgBox "Button Count:" & tbcount
          pMemory = VirtualAllocEx(hProcess, ByVal 0, ByVal 1024, MEM_COMMIT, PAGE_READWRITE)
          If tbcount = myBTNCnt Then  'This will select the correct toolbar - Need to find buttoncount
              For i = 0 To tbcount - 1
                  TBhWnd = hChild
                  MsgBox i
                  If i = myBTNtoPress Then
                      '*********************************************************************
                      'This is the part that I am failing on...
                      xpBuffer = drMemoryAlloc(hChild, 1024)

                      ' lResult = SendMessage(TBhWnd, TB_GETBUTTON, i, xpBuffer)
                      lResult = SendMessage(TBhWnd, TB_GETBUTTONINFO, i, xpBuffer)
                      MsgBox "lResult =" & lResult
                      '  drMemoryRead xpBuffer, VarPtr(i), Len(i)
                      '*********************************************************************
                  End If



              Next

          End If
      End If
      EnumChildWindow = 1  ' Continue enumeration
  End Function

  Function FindWindowByTitlePROC(ByVal hwnd&, lParam&) As Boolean
  'this is the callback function procedure..do not change order
  ' or type of parameters in the procedure definition

      If hwnd = 0 Then
          lParam = 0
          'stop enumerating
          FindWindowByTitlePROC = False
      End If

      'see if the Hwnd is the one with the title
      If UCase(GetCaption(hwnd)) Like UCase(TitleToFind) & "*" Then
          'set return value
          lParam = CLng(hwnd)
          'stop enumerating
          FindWindowByTitlePROC = False
      Else
          'continue enumerating (not found)
          FindWindowByTitlePROC = True
      End If

  End Function
  Function GetCaption&(ByVal hwnd&)
  'returns the caption of the window with handle "hwnd"

      Dim sTemp&, c%
      sTemp = String$(255, 0)
      c = GetWindowText(hwnd, sTemp, 256)

      GetCaption = Left$(sTemp, c)

  End Function
  Public Function drMemoryAlloc&(ByVal xpWindow&, ByVal nBytes&)
  '
  ' Returns pointer to a share-able buffer (size nBytes) in target process
  '   that owns xpWindow
  '
      Dim xpThread&    ' target control's thread id
      Dim xpID&        '                  process id
      If WindowsNT Then
          xpThread = GetWindowThreadProcessId(xpWindow, xpID)
          drMemoryAlloc = VirtualAllocNT(xpID, nBytes)
      Else
          drMemoryAlloc = VirtualAlloc9X(nBytes)
      End If
  End Function
  Public Sub drMemoryRead(ByVal xpBuffer&, ByVal myBuffer&, ByVal nBytes&)
      If WindowsNT Then
          ReadProcessMemory fpHandle, xpBuffer, myBuffer, nBytes, 0
      Else
          CopyMemory myBuffer, xpBuffer, nBytes
      End If
  End Sub
Sub test_WindowsNT()
  MsgBox WindowsNT
End Sub
  Public Function WindowsNT() As Boolean
  ' return TRUE if NT-like platform (NT, 2000, XP, etc)
      If Not PlatformKnown Then GetWindowsVersion
      WindowsNT = NTflag
  End Function
  Private Function VirtualAllocNT&(ByVal fpID&, ByVal memSize&)
      fpHandle = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, fpID)
      VirtualAllocNT = VirtualAllocEx(fpHandle, ByVal 0&, ByVal memSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE)
  End Function
  Private Function VirtualAlloc9X&(ByVal memSize&)
      fpHandle = CreateFileMapping(&HFFFFFFFF, 0, PAGE_READWRITE, 0, memSize, vbNullString)
      VirtualAlloc9X = MapViewOfFile(fpHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0)
  End Function
  Public Sub GetWindowsVersion()
      WIN.dwOSVersionInfoSize = Len(WIN)
      If (GetVersionEx(WIN)) = 0 Then Exit Sub  ' in deep doo if this fails
      NTflag = (WIN.dwPlatformId = 2)
      PlatformKnown = True
  End Sub

Mình cũng đanh hoàn thành một bản đóng gói trên Userform có cải tiến fix tết cả các loại Win 32, 64-bit và auto để đưa lên đây. Mình mới test qua code của bạn chạy 0k trên Win10 64-bit. Tư duy viết code của bạn khá giống mình. Các hàm API của bạn tạm thời chạy được nhưng đến một lúc nào đó, máy nào đó 664-bit sẽ lỗi vì một số Handle bạn khai báo kiểu Long, nên sửa là LongPtr. Vì trong Win 64-bit các Handle được phân phối trong phạm vi biến có dung lương 8 BYTE (LongLong, LongPtr), nên một lúc nào đó cái Handle cần tìm nằm ngoài phạm vi của Long thì sẽ lỗi.

Code của mình cơ bản dựa trên căn nguyên của Batman1 nhưng trộn lẫn để tương thích các loại.
 
Upvote 0
Mình cũng đanh hoàn thành một bản đóng gói trên Userform có cải tiến fix tết cả các loại Win 32, 64-bit và auto để đưa lên đây. Mình mới test qua code của bạn chạy 0k trên Win10 64-bit. Tư duy viết code của bạn khá giống mình. Các hàm API của bạn tạm thời chạy được nhưng đến một lúc nào đó, máy nào đó 664-bit sẽ lỗi vì một số Handle bạn khai báo kiểu Long, nên sửa là LongPtr. Vì trong Win 64-bit các Handle được phân phối trong phạm vi biến có dung lương 8 BYTE (LongLong, LongPtr), nên một lúc nào đó cái Handle cần tìm nằm ngoài phạm vi của Long thì sẽ lỗi.

Code của mình cơ bản dựa trên căn nguyên của Batman1 nhưng trộn lẫn để tương thích các loại.
Không biết là có MAC không? Em và anh còn 1 điều giống, nói ra có thể anh sẽ bật cười
 
Upvote 0
hàm API của bạn tạm thời chạy được nhưng đến một lúc nào đó, máy nào đó 664-bit sẽ lỗi vì một số Handle bạn khai báo kiểu Long, nên sửa là LongPtr. Vì trong Win 64-bit các Handle được phân phối trong phạm vi biến có dung lương 8 BYTE (LongLong, LongPtr), nên một lúc nào đó cái Handle cần tìm nằm ngoài phạm vi của Long thì sẽ lỗi.
.
Không bị lỗi nhé anh vì Handle không thuộc vào loại gọi Hàm thực thi của Hàm API
 
Upvote 0
Không bị lỗi nhé anh vì Handle không thuộc vào loại gọi Hàm thực thi của Hàm API

Có chứ. Các Handle của các Window được sinh ra từ CreateWindow() nó chịu sự phân phối của HĐH môi trường 32, 64-bit. Khi lập trình API mình đi tìm cái Handle này nên sẽ ảnh hưởng.
 
Upvote 0
Có chứ. Các Handle của các Window được sinh ra từ CreateWindow() nó chịu sự phân phối của HĐH môi trường 32, 64-bit. Khi lập trình API mình đi tìm cái Handle này nên sẽ ảnh hưởng.
Theo em thì anh đã hiểu lằm LongPtr. LongPtr Nếu đang ở Win32 thì là Long , Win64 sẽ là LongLong
LongPtr được sinh ra để giúp người viết Code dễ dàng hơn. Sẽ như thế này: Office 64 tức là VBA7 (Là một IDE mới cho Ngôn ngữ lập trình VBA): nếu là Win 64bit sẽ là LongLong, Win 32bit sẽ là Long . Để không phải dùng phương pháp tiền xử lý rắc rối thì đó chính là LongPtr
Nếu anh đặt là LongLong thì anh phải qua rất nhiều phương thức tiền xử lý từ: Biến, Sub, Function ... Để tương thích nhiều hệ

Mã:
#If VBA7 Then
  'Thay vì anh chia chúng ra làm 2 như thế này'
  #If Win64 Then
     LongLong
  #Else
     Long
  #End If
  ' Thì không cần như vậy'
  LongPtr là đủ
#Else
  'VBA 6 <-- trở về trước
#End If
Anh có thể xem qua: Handle inheritance
 
Lần chỉnh sửa cuối:
Upvote 0
Theo em thì anh đã hiểu lằm LongPtr. LongPtr Nếu đang ở Win32 thì là Long , Win64 sẽ là LongLong
LongPtr được sinh ra để giúp người viết Code dễ dàng hơn. Sẽ như thế này: Office 64 tức là VBA7 (Là một IDE mới cho Ngôn ngữ lập trình VBA): nếu là Win 64bit sẽ là LongLong, Win 32bit sẽ là Long . Để không phải dùng phương pháp tiền xử lý rắc rối thì đó chính là LongPtr
Nếu anh đặt là LongLong thì anh phải qua rất nhiều phương thức tiền xử lý từ: Biến, Sub, Function ... Để tương thích nhiều hệ

Mã:
#If VBA7 Then
  'Thay vì anh chia chúng ra làm 2 như thế này'
  #If Win64 Then
     LongLong
  #Else
     Long
  #End If
  ' Thì không cần như vậy'
  LongPtr là đủ
#Else
  'VBA 6 <-- trở về - 32 bit'
#End If
Anh có thể xem qua: Handle inheritance

Chắc anh không nhầm đâu. Anh tạo nhiều hàm API cho các nền tảng Windows nên đã cũng phải hiểu về vấn đề này, đặc biệt trong Office. Nếu em chỉ nhận Handle từ các thành phần sinh ra của Application 32-bit thì dù Windows gì cũng là 32-bit, nhưng nến Handle sinh ra từ Application 64-bit thì phạm vi giá trị của nó nằm trong miền giá trị của LongLong/LongPtr (8 Byte). Từ Office 2010 Microsoft cớ 2 phiên bản 32 và 64-bit nên họ mới sinh ra kiểu LongPtr để người lập trình thuận tiện (cái mà em đang nói ở trên), khi nào thì LongPtr là 32 bit, khi nào là 64-bit thì Microsoft nói rất rõ.
 
Lần chỉnh sửa cuối:
Upvote 0
Chắc anh không nhầm đâu. Anh tạo nhiều hàm API cho các nền tảng Windows nên đã cũng phải hiểu về vấn đề này, đặc biệt trong Office. Nếu em chỉ nhận Handle từ các thành phần sinh ra của Application 32-bit thì dù Windows gì cũng là 32-bit, nhưng nến Handle sinh ra từ Application 64-bit thì phạm vi giá trị của nó nằm trong miền giá trị của LongLong/LongPtr (8 Byte). Từ Office 2010 Microsoft cớ 2 phiên bản 32 và 64-bit nên họ mới sinh ra kiểu LongPtr để người lập trình thuận tiện (cái mà em đang nói ở trên), khi nào thì LongPtr là 32 bit, khi nào là 64-bit thì Microsoft nói rất rõ. Điểm khác nhau Handle sinh ra từ loại ứng dụng 32 hay 64 mà miền giá trị của nó ở các phạm vi khác nhau. Bản thân Windows 64-bit nó có 2 bộ DLL trong System32 và SysWow64 là để phục vụ cho hoai loại Application. Thằng 32 sẽ dùng đến nhóm DLL 32, thằng 64 sẽ dùng đến bộ hàm trong DLL 64-bit.

Máy em đang dùng đây là Win10 64bit gồm 2 Office64 2016 và Office64 2010. Như anh nói thì đã gặp lỗi rồi.
 
Upvote 0
Upvote 0
Dựa theo code gốc của anh Batman1, mình hoàn chỉnh thêm code để:
+ Tương thích với các version Windows: XP, Vista, 7, 10 32, 64-bit, Office 32,64-bit
+ Tự tìm Unikey trên các cửa sổ thuộc khu vực Traybar
+ Tự tắt, mở Unikey khi con trỏ ở TextBox nhận thiết bị scanner hay khi thoát thì khôi phục lại unikey

Khai báo kiểu dữ liệu và hàm API tương thích với 32 và 64-bit
PHP:
#If Win64 And VBA7 Then
Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 5) As Byte
    dwData As LongPtr
    iString As LongPtr
End Type
#Else
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
#End If

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
    #If VBA7 Then
    hwnd As LongPtr
    #Else
    hwnd As Long
    #End If
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
End Type

#If VBA7 Then
Private Declare PtrSafe Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As LongPtr
Private Declare PtrSafe Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As LongPtr, ByRef lpdwProcessId As Long) As Long
Private Declare PtrSafe Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Private Declare PtrSafe Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Private Declare PtrSafe Function VirtualAllocEx Lib "kernel32.dll" (ByVal hProcess As LongPtr, ByRef lpAddress As Any, ByRef dwSize As LongPtr, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare PtrSafe Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As LongPtr, ByRef lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As LongPtr, ByRef lpNumberOfBytesWritten As LongPtr) As Long
Private Declare PtrSafe Function VirtualFreeEx Lib "kernel32.dll" (ByVal hProcess As LongPtr, ByRef lpAddress As Any, ByRef dwSize As LongPtr, ByVal dwFreeType As Long) As LongPtr
Private Declare PtrSafe Function CloseHandle Lib "kernel32.dll" (ByVal hObject As LongPtr) As Long
#Else
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
#End If

Phần code xử lý tắt mở Unikey
Mã:
Function VietnameseOff() As Boolean
    'VietnameseOff = True 'Unikey is clicked
    'VietnameseOff = False 'Not Unikey
    VietnameseOff = Vietnamese(True)
End Function

Function VietnameseOn() As Boolean
    'VietnameseOn = True 'Unikey is clicked
    'VietnameseOn = False 'Not Unikey
    VietnameseOn = Vietnamese(False)
End Function

Function Vietnamese(Optional ByVal TurnOff As Boolean = True) As Boolean
    Dim nCount, k As Long, sTip As String
   
    Dim tb As TBButton, tray As TRAYDATA
    Dim tbXp As TBButtonXP, trayXp As TRAYDATAXP 'Windows XP-> < 10
    Dim pid As Long
    #If VBA7 Then
    Dim pMemory As LongPtr, hTB As LongPtr, hProcess As LongPtr, BytesRead As LongPtr
    #Else
    Dim pMemory As Long, hTB As Long, hProcess As Long, BytesRead As Long
    #End If
    'Variables Added by Nguyen Duy Tuan
    Dim HasUnikeybutton As Boolean, sTemp As String, CountLoop As Long
    Dim WinXPVISTA As Boolean, IsUnikeyVN As Boolean
    '----------------------------------
    WinXPVISTA = IsWinXPOrVista
    hTB = TrayToolbarWnd(Not WinXPVISTA)
   
lbBegenFind:
    CountLoop = CountLoop + 1
    If hTB = 0 Then Exit Function
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then Exit Function
    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
        sTip = String(256, Chr(0))
        If WinXPVISTA Then
            ReadProcessMemory hProcess, ByVal pMemory, tbXp, LenB(tbXp), BytesRead
            ReadProcessMemory hProcess, ByVal tbXp.dwData, trayXp, LenB(trayXp), BytesRead
            ReadProcessMemory hProcess, ByVal tbXp.iString, ByVal StrPtr(sTip), 256, BytesRead
        Else
            ReadProcessMemory hProcess, ByVal pMemory, tb, LenB(tb), BytesRead
            ReadProcessMemory hProcess, ByVal tb.dwData, tray, LenB(tray), BytesRead
            ReadProcessMemory hProcess, ByVal tb.iString, ByVal StrPtr(sTip), 256, BytesRead
        End If
       
        sTip = Left(sTip, InStr(1, sTip, Chr(0)) - 1)
       
        'Check window has Unikey button
        sTemp = Replace(sTip, "turn off", "")
        sTemp = Replace(sTemp, "turn on", "")
        HasUnikeybutton = sTemp = "Click to  Vietnamese mode" 'DO NOT CHANGE IT
        '------------------------------
        If HasUnikeybutton Then
            IsUnikeyVN = InStr(sTip, " turn off ") > 0
            If (IsUnikeyVN And TurnOff) Or (Not IsUnikeyVN And Not TurnOff) Then
                If WinXPVISTA Then
                    AutoClickUnikey trayXp.hwnd, trayXp.uCallbackMessage, trayXp.uID
                Else
                    AutoClickUnikey tray.hwnd, tray.uCallbackMessage, tray.uID
                End If
                Vietnamese = True
            End If
            Exit For
        End If
    Next k
   
    If Not WinXPVISTA And (Not HasUnikeybutton And CountLoop = 1) Then 'Unikey may be in "TrayNotifyWnd" area
        hTB = TrayToolbarWnd(False)
        GoTo lbBegenFind
    End If
   
    VirtualFreeEx hProcess, pMemory, 0, MEM_RELEASE
    CloseHandle hProcess
End Function

Private Function TrayToolbarWnd(ByVal CheckFloatWindow As Boolean)
    Dim hTB
    If CheckFloatWindow Then 'run it if OS is not Windows XP
        hTB = FindWindow("NotifyIconOverflowWindow", vbNullString)
    End If
    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

#If VBA7 Then
Private Sub AutoClickUnikey(ByVal TrayHwnd As LongPtr, _
                            ByVal uCallbackMessage As Long, _
                            ByVal TrayUID As LongPtr)
                       
#Else
Private Sub AutoClickUnikey(ByVal TrayHwnd As Long, _
                            ByVal uCallbackMessage As Long, _
                            ByVal TrayUID As Long)
#End If

    PostMessage TrayHwnd, uCallbackMessage, TrayUID, WM_LBUTTONDOWN
    PostMessage TrayHwnd, uCallbackMessage, TrayUID, WM_LBUTTONUP

End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Dựa theo code gốc của anh Batman1, mình hoàn chỉnh thêm code để:
+ Tương thích với các version Windows: XP, Vista, 7, 10 32, 64-bit, Office 32,64-bit
+ Tự tìm Unikey trên các cửa sổ thuộc khu vực Traybar
+ Tự tắt, mở Unikey khi con trỏ ở TextBox nhận thiết bị scanner hay khi thoát thì khôi phục lại unikey

Khai báo kiểu dữ liệu và hàm API tương thích với 32 và 64-bit
PHP:
#If Win64 And VBA7 Then
Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 5) As Byte
    dwData As LongPtr
    iString As LongPtr
End Type
#Else
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
#End If

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
    #If VBA7 Then
    hwnd As LongPtr
    #Else
    hwnd As Long
    #End If
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
End Type

#If VBA7 Then
Private Declare PtrSafe Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As LongPtr
Private Declare PtrSafe Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As LongPtr, ByRef lpdwProcessId As Long) As Long
Private Declare PtrSafe Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Private Declare PtrSafe Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Private Declare PtrSafe Function VirtualAllocEx Lib "kernel32.dll" (ByVal hProcess As LongPtr, ByRef lpAddress As Any, ByRef dwSize As LongPtr, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare PtrSafe Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As LongPtr, ByRef lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As LongPtr, ByRef lpNumberOfBytesWritten As LongPtr) As Long
Private Declare PtrSafe Function VirtualFreeEx Lib "kernel32.dll" (ByVal hProcess As LongPtr, ByRef lpAddress As Any, ByRef dwSize As LongPtr, ByVal dwFreeType As Long) As LongPtr
Private Declare PtrSafe Function CloseHandle Lib "kernel32.dll" (ByVal hObject As LongPtr) As Long
#Else
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
#End If

Phần code xử lý tắt mở Unikey
Mã:
Function VietnameseOff() As Boolean
    'VietnameseOff = True 'Unikey is clicked
    'VietnameseOff = False 'Not Unikey
    VietnameseOff = Vietnamese(True)
End Function

Function VietnameseOn() As Boolean
    'VietnameseOn = True 'Unikey is clicked
    'VietnameseOn = False 'Not Unikey
    VietnameseOn = Vietnamese(False)
End Function

Function Vietnamese(Optional ByVal TurnOff As Boolean = True) As Boolean
    Dim nCount, k As Long, sTip As String
  
    Dim tb As TBButton, tray As TRAYDATA
    Dim tbXp As TBButtonXP, trayXp As TRAYDATAXP 'Windows XP-> < 10
    Dim pid As Long
    #If VBA7 Then
    Dim pMemory As LongPtr, hTB As LongPtr, hProcess As LongPtr, BytesRead As LongPtr
    #Else
    Dim pMemory As Long, hTB As Long, hProcess As Long, BytesRead As Long
    #End If
    'Variables Added by Nguyen Duy Tuan
    Dim HasUnikeybutton As Boolean, sTemp As String, CountLoop As Long
    Dim WinXPVISTA As Boolean, IsUnikeyVN As Boolean
    '----------------------------------
    WinXPVISTA = IsWinXPOrVista
    hTB = TrayToolbarWnd(Not WinXPVISTA)
  
lbBegenFind:
    CountLoop = CountLoop + 1
    If hTB = 0 Then Exit Function
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then Exit Function
    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
        sTip = String(256, Chr(0))
        If WinXPVISTA Then
            ReadProcessMemory hProcess, ByVal pMemory, tbXp, LenB(tbXp), BytesRead
            ReadProcessMemory hProcess, ByVal tbXp.dwData, trayXp, LenB(trayXp), BytesRead
            ReadProcessMemory hProcess, ByVal tbXp.iString, ByVal StrPtr(sTip), 256, BytesRead
        Else
            ReadProcessMemory hProcess, ByVal pMemory, tb, LenB(tb), BytesRead
            ReadProcessMemory hProcess, ByVal tb.dwData, tray, LenB(tray), BytesRead
            ReadProcessMemory hProcess, ByVal tb.iString, ByVal StrPtr(sTip), 256, BytesRead
        End If
      
        sTip = Left(sTip, InStr(1, sTip, Chr(0)) - 1)
      
        'Check window has Unikey button
        sTemp = Replace(sTip, "turn off", "")
        sTemp = Replace(sTemp, "turn on", "")
        HasUnikeybutton = sTemp = "Click to  Vietnamese mode" 'DO NOT CHANGE IT
        '------------------------------
        If HasUnikeybutton Then
            IsUnikeyVN = InStr(sTip, " turn off ") > 0
            If (IsUnikeyVN And TurnOff) Or (Not IsUnikeyVN And Not TurnOff) Then
                If WinXPVISTA Then
                    AutoClickUnikey trayXp.hwnd, trayXp.uCallbackMessage, trayXp.uID
                Else
                    AutoClickUnikey tray.hwnd, tray.uCallbackMessage, tray.uID
                End If
                Vietnamese = True
            End If
            Exit For
        End If
    Next k
  
    If Not WinXPVISTA And (Not HasUnikeybutton And CountLoop = 1) Then 'Unikey may be in "TrayNotifyWnd" area
        hTB = TrayToolbarWnd(False)
        GoTo lbBegenFind
    End If
  
    VirtualFreeEx hProcess, pMemory, 0, MEM_RELEASE
    CloseHandle hProcess
End Function

Private Function TrayToolbarWnd(ByVal CheckFloatWindow As Boolean)
    Dim hTB
    If CheckFloatWindow Then 'run it if OS is not Windows XP
        hTB = FindWindow("NotifyIconOverflowWindow", vbNullString)
    End If
    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

#If VBA7 Then
Private Sub AutoClickUnikey(ByVal TrayHwnd As LongPtr, _
                            ByVal uCallbackMessage As Long, _
                            ByVal TrayUID As LongPtr)
                      
#Else
Private Sub AutoClickUnikey(ByVal TrayHwnd As Long, _
                            ByVal uCallbackMessage As Long, _
                            ByVal TrayUID As Long)
#End If

    PostMessage TrayHwnd, uCallbackMessage, TrayUID, WM_LBUTTONDOWN
    PostMessage TrayHwnd, uCallbackMessage, TrayUID, WM_LBUTTONUP

End Sub

Cảm ơn anh Tuân đã cho thêm một giải pháp để OT tham khảo ạ.
Hic OT vừa tải file về , chưa biết mặt mũi file như thế nào thì (tải đi tải lại mấy lần đều bị như vậy) ... T_T
Nhờ Anh Tuân xem giúp ạ:

hic.png
 
Upvote 0
E
Cảm ơn anh Tuân đã cho thêm một giải pháp để OT tham khảo ạ.
Hic OT vừa tải file về , chưa biết mặt mũi file như thế nào thì (tải đi tải lại mấy lần đều bị như vậy) ... T_T
Nhờ Anh Tuân xem giúp ạ:

View attachment 211515

File Excel chỉ mỗi code VBA thôi không có virus gì đâu. Em anh không hiểu cái thông báo kia từ đâu nhưng em tìm cách để nó cho download nhé.
 
Upvote 0
Upvote 0
Các bạn có dùng phần mềm diệt virus bản quyền/xịn không? Hay nó bị ngu ngơ nhỉ ? Máy mình là máy đóng gói các giải pháp cho nhiều khách hàng cả tây và ta chảng ai báo virus cả. Hay Máy chủ GPE bị nhiễm? :D
 
Upvote 0
Các bạn có dùng phần mềm diệt virus bản quyền/xịn không? Hay nó bị ngu ngơ nhỉ ? Máy mình là máy đóng gói các giải pháp cho nhiều khách hàng cả tây và ta chảng ai báo virus cả. Hay Máy chủ GPE bị nhiễm? :D

Không biết phần mềm trên máy tính của OT có xịn không nhưng công ty phải bỏ ra khoảng 10trieu để mua Win10+Office2016 đó ạ.
 
Upvote 0
Thôi tôi đành lưu file về định dạng XLSM để các phần mềm diệt virus nó có khả năng kiểm tra đc kỹ nội dung trong file để nó có kết luận không ngu ngơ :D . File trước tôi lưu dạng "XLS" để các bạn có thể mở đc cả trên Excel 2003.
 

File đính kèm

Upvote 0
Các bạn có dùng phần mềm diệt virus bản quyền/xịn không? Hay nó bị ngu ngơ nhỉ ? Máy mình là máy đóng gói các giải pháp cho nhiều khách hàng cả tây và ta chảng ai báo virus cả. Hay Máy chủ GPE bị nhiễm? :D
Con virus đây này anh : "AutoClickUnikey"
Có ai mà đi đặt cái tên Macro như thế này. Nó bắt lỗi ngay
 
Upvote 0
Upvote 0
Hóa ra cái phần mềm kia nó ngu ngơ thiệt. Ai lại lấy tên macro để coi là virus chứ :D
Em đâu có dùng phần mềm duyệt Virus. Mấy bạn không biết VBA thì mới lo sợ.
FIle của anh em tải về xem qua mã nguồn tự hiểu là có Virus hay không.
Đây chính là trang chóng sợ hãi giành cho người luôn sợ hãi đây:
https://www.virustotal.com/vi/ - Miễn phí - Hãy tin Cộng đồng tìm virus này
Capture.PNG
Bài đã được tự động gộp:

Hóa ra cái phần mềm kia nó ngu ngơ thiệt. Ai lại lấy tên macro để coi là virus chứ :D
Anh Tuân khi đăng File anh chụp cái ảnh như thế lên, cho các bạn ấy link kiểm tra nữa thì "đố mà than phiền "
 
Lần chỉnh sửa cuối:
Upvote 0
Máy em đang dùng đây là Win10 64bit gồm 2 Office64 2016 và Office64 2010. Như anh nói thì đã gặp lỗi rồi.
Máy em đang dùng đây là Win10 64bit gồm 2 Office64 2016 và Office64 2010. Như anh nói thì đã gặp lỗi rồi.
Cái này tôi biết. Đề phòng mọi người có ý kiến nên tôi viết rất rõ mà
Chỉ dùng với Office 32 bit vì tôi không khai báo cho 64 bit.
Chỉ là bạn không chịu đọc kỹ mà thôi.
 
Upvote 0
Upvote 0
Cái này tôi biết. Đề phòng mọi người có ý kiến nên tôi viết rất rõ mà

Chỉ là bạn không chịu đọc kỹ mà thôi.

Đoạn anh Batman1 trích dẫn là liên quan loạt bài trao đổi về kiểu Long trong môi trường 64 bit giữa em và HeSanbi đấy. :)
 
Upvote 0
Tôi hướng dẫn chóng sợ hãi nhé:
https://www.virustotal.com/vi/ là trang quét virus nhiều định dạng file với hơn 60 phần mềm duyệt virus tiên tiến có cả BKAV. Và luôn luôn update bản mới nhất
Chỉ cần đăng link hoặc file.
Sau đây là hình ảnh cho file mà OT bị WinDefender cho là Virus
Capture.PNG
 
Upvote 0
Vừa đi làm về thì mọi người đã làm xong rồi.
Tuân đã làm thì tin tưởng là chuẩn rồi. Tôi cũng không có các phiên bản Windows khác để test. Nhưng Tuân nên làm thêm để sao không chỉ cho cô OT dùng mà cho cả những người về sau muốn thao tác với các icon khác, ứng dụng khác.

Tức đại loại thế này. Sửa Vietnamese thành Sub chẳng hạn, vd. ListIcons, không có AutoClickUnikey và những cái khác. ListIcons trong vòng lặp For k = 0 To nCount - 1 sẽ nhập các dữ liệu vào mảng TrayInfo(...) As TRAYITEM, mà
Mã:
Private Type TRAYITEM
    hwnd As ...
        uID As ...
        uCallbackMessage As ...
    filename As ...
    sTip As ...
End Type
hwnd, uID, uCallbackMessage thì sao chép từ TRAYDATA(XP) sang. Chỉ còn filename nữa thôi.

Tiếp đó là code để phục vụ cô OT. Vd.

Mã:
Function Vietnamese(Optional ByVal TurnOff As Boolean = True) As Boolean
Dim k As Long
    ListIcons
    For k = 1 To UBound(TrayInfo)
        If TrayInfo(k).filename = "UnikeyNT.exe" Then ' hoặc kiểm tra sTip
            ' làm các việc của cô OT
            Exit For
        End If
    Next k
End Function

Làm thế để nếu ai thích vọc những icon khác, ứng dụng khác thì người ta chỉ việc viết sub của người ta và thay
Mã:
If TrayInfo(k).filename = "UnikeyNT.exe" Then
bằng
Mã:
If TrayInfo(k).filename = "xyz.exe" Then ' hoặc kiểm tra sTip

Ngoài ra người ta có thể không muốn nhấn chuột mà muốn làm các việc khác với icon thì người ta chỉ viết sub thích hợp thôi chứ code chính ListIcons không phải sửa. Vọc với icon thì thoải mái vì có hwnd, uID, uCallbackMessage trong TRAYITEM rồi. Thậm chí có thể gọi Shell_NotifyIcon(NIM_DELETE ... để xóa icon. Tất nhiên xóa icon trên tray thôi chứ ứng dụng vẫn chay.
 
Upvote 0
Tôi hướng dẫn chóng sợ hãi nhé:
https://www.virustotal.com/vi/ là trang quét virus nhiều định dạng file với hơn 60 phần mềm duyệt virus tiên tiến có cả BKAV. Và luôn luôn update bản mới nhất
Chỉ cần đăng link hoặc file.
Sau đây là hình ảnh cho file mà OT bị WinDefender cho là Virus
View attachment 211524
Cảm ơn HeSanbi đã kiểm tra giúp ạ. Không có virut thì yên tâm rồi ạ, mai đến công ty OT tải về test thử xem sao ạ.
OT chưa bào giờ thấy code trong chủ đề nào của OT mà lại khủng khiếp như chủ đề này ạ @@!

Hihi,có lẽ thời gian tới anh Tuân cũng tính nâng cấp Atool tích hợp vấn đề QR-Code này luôn nhỉ :p
----
Thực ra vấn đề của OT cũng đã được Bác Siwtom và Anh Hữu Thắng giúp đỡ giải quyết ổn rồi ạ, từ lúc OT đưa vào sử dụng đến giờ chưa thấy phát sinh vấn đề gì ạ (chắc không sợ mấy chú và mấy ông lái xe bên ngoài quét mã vạch nữa rồi).

Nhưng OT thấy đây là vấn đề chung được nhiều người quan tâm vì thế mà mọi người vẫn đưa rất nhiều giải pháp giải pháp khác nên OT vẫn theo dõi để tham khảo thêm ạ, chứ không có ý muốn đòi hỏi gì thêm ạ.
Với OT thì đã đủ (vì IT chỉ cài cho Unikey ở tất cả các máy) nhưng có thể đối với bạn khác còn gặp phải tính huống khác như không sử dụng Unikey mà lại sử dụng VietKey hoặc những tính huống khác như Bác Siwtom đã đề cập ở bài 154 :D, nên rất mong các Bác/Anh và các bạn tiếp tục trao đổi.

Xin trân trọng cảm ơn tất cả mọi người đã giúp đỡ ạ.
Oanh Thơ
 
Upvote 0
Dựa theo code gốc của anh Batman1, mình hoàn chỉnh thêm code để:
+ Tương thích với các version Windows: XP, Vista, 7, 10 32, 64-bit, Office 32,64-bit
+ Tự tìm Unikey trên các cửa sổ thuộc khu vực Traybar
+ Tự tắt, mở Unikey khi con trỏ ở TextBox nhận thiết bị scanner hay khi thoát thì khôi phục lại unikey

Khai báo kiểu dữ liệu và hàm API tương thích với 32 và 64-bit
PHP:
#If Win64 And VBA7 Then
Private Type TBButton
    iBitmap As Long
    idCommand As Long
    fsState As Byte
    fsStyle As Byte
    bReserved(0 To 5) As Byte
    dwData As LongPtr
    iString As LongPtr
End Type
#Else
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
#End If

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
    #If VBA7 Then
    hwnd As LongPtr
    #Else
    hwnd As Long
    #End If
    uID As Long
    uCallbackMessage As Long
    Reserved(0 To 7) As Long
    hIcon As Long
End Type

#If VBA7 Then
Private Declare PtrSafe Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As LongPtr
Private Declare PtrSafe Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
Private Declare PtrSafe Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As LongPtr, ByRef lpdwProcessId As Long) As Long
Private Declare PtrSafe Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Private Declare PtrSafe Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Private Declare PtrSafe Function VirtualAllocEx Lib "kernel32.dll" (ByVal hProcess As LongPtr, ByRef lpAddress As Any, ByRef dwSize As LongPtr, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare PtrSafe Function ReadProcessMemory Lib "kernel32.dll" (ByVal hProcess As LongPtr, ByRef lpBaseAddress As Any, ByRef lpBuffer As Any, ByVal nSize As LongPtr, ByRef lpNumberOfBytesWritten As LongPtr) As Long
Private Declare PtrSafe Function VirtualFreeEx Lib "kernel32.dll" (ByVal hProcess As LongPtr, ByRef lpAddress As Any, ByRef dwSize As LongPtr, ByVal dwFreeType As Long) As LongPtr
Private Declare PtrSafe Function CloseHandle Lib "kernel32.dll" (ByVal hObject As LongPtr) As Long
#Else
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
#End If

Phần code xử lý tắt mở Unikey
Mã:
Function VietnameseOff() As Boolean
    'VietnameseOff = True 'Unikey is clicked
    'VietnameseOff = False 'Not Unikey
    VietnameseOff = Vietnamese(True)
End Function

Function VietnameseOn() As Boolean
    'VietnameseOn = True 'Unikey is clicked
    'VietnameseOn = False 'Not Unikey
    VietnameseOn = Vietnamese(False)
End Function

Function Vietnamese(Optional ByVal TurnOff As Boolean = True) As Boolean
    Dim nCount, k As Long, sTip As String
  
    Dim tb As TBButton, tray As TRAYDATA
    Dim tbXp As TBButtonXP, trayXp As TRAYDATAXP 'Windows XP-> < 10
    Dim pid As Long
    #If VBA7 Then
    Dim pMemory As LongPtr, hTB As LongPtr, hProcess As LongPtr, BytesRead As LongPtr
    #Else
    Dim pMemory As Long, hTB As Long, hProcess As Long, BytesRead As Long
    #End If
    'Variables Added by Nguyen Duy Tuan
    Dim HasUnikeybutton As Boolean, sTemp As String, CountLoop As Long
    Dim WinXPVISTA As Boolean, IsUnikeyVN As Boolean
    '----------------------------------
    WinXPVISTA = IsWinXPOrVista
    hTB = TrayToolbarWnd(Not WinXPVISTA)
  
lbBegenFind:
    CountLoop = CountLoop + 1
    If hTB = 0 Then Exit Function
    GetWindowThreadProcessId hTB, pid
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    If hProcess = 0 Then Exit Function
    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
        sTip = String(256, Chr(0))
        If WinXPVISTA Then
            ReadProcessMemory hProcess, ByVal pMemory, tbXp, LenB(tbXp), BytesRead
            ReadProcessMemory hProcess, ByVal tbXp.dwData, trayXp, LenB(trayXp), BytesRead
            ReadProcessMemory hProcess, ByVal tbXp.iString, ByVal StrPtr(sTip), 256, BytesRead
        Else
            ReadProcessMemory hProcess, ByVal pMemory, tb, LenB(tb), BytesRead
            ReadProcessMemory hProcess, ByVal tb.dwData, tray, LenB(tray), BytesRead
            ReadProcessMemory hProcess, ByVal tb.iString, ByVal StrPtr(sTip), 256, BytesRead
        End If
      
        sTip = Left(sTip, InStr(1, sTip, Chr(0)) - 1)
      
        'Check window has Unikey button
        sTemp = Replace(sTip, "turn off", "")
        sTemp = Replace(sTemp, "turn on", "")
        HasUnikeybutton = sTemp = "Click to  Vietnamese mode" 'DO NOT CHANGE IT
        '------------------------------
        If HasUnikeybutton Then
            IsUnikeyVN = InStr(sTip, " turn off ") > 0
            If (IsUnikeyVN And TurnOff) Or (Not IsUnikeyVN And Not TurnOff) Then
                If WinXPVISTA Then
                    AutoClickUnikey trayXp.hwnd, trayXp.uCallbackMessage, trayXp.uID
                Else
                    AutoClickUnikey tray.hwnd, tray.uCallbackMessage, tray.uID
                End If
                Vietnamese = True
            End If
            Exit For
        End If
    Next k
  
    If Not WinXPVISTA And (Not HasUnikeybutton And CountLoop = 1) Then 'Unikey may be in "TrayNotifyWnd" area
        hTB = TrayToolbarWnd(False)
        GoTo lbBegenFind
    End If
  
    VirtualFreeEx hProcess, pMemory, 0, MEM_RELEASE
    CloseHandle hProcess
End Function

Private Function TrayToolbarWnd(ByVal CheckFloatWindow As Boolean)
    Dim hTB
    If CheckFloatWindow Then 'run it if OS is not Windows XP
        hTB = FindWindow("NotifyIconOverflowWindow", vbNullString)
    End If
    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

#If VBA7 Then
Private Sub AutoClickUnikey(ByVal TrayHwnd As LongPtr, _
                            ByVal uCallbackMessage As Long, _
                            ByVal TrayUID As LongPtr)
                      
#Else
Private Sub AutoClickUnikey(ByVal TrayHwnd As Long, _
                            ByVal uCallbackMessage As Long, _
                            ByVal TrayUID As Long)
#End If

    PostMessage TrayHwnd, uCallbackMessage, TrayUID, WM_LBUTTONDOWN
    PostMessage TrayHwnd, uCallbackMessage, TrayUID, WM_LBUTTONUP

End Sub
Giờ OT mới để ý cái video của anh Tuân, hấp dẫn thật ^_^
Form này anh có đưa tình huống xử lý lỗi khi bật CapsLock không vậy ạ (hiện OT đang chưa có điều kiện để thử).
 
Upvote 0
Cảm ơn HeSanbi đã kiểm tra giúp ạ. Không có virut thì yên tâm rồi ạ, mai đến công ty OT tải về test thử xem sao ạ.
OT chưa bào giờ thấy code trong chủ đề nào của OT mà lại khủng khiếp như chủ đề này ạ @@!

Hihi,có lẽ thời gian tới anh Tuân cũng tính nâng cấp Atool tích hợp vấn đề QR-Code này luôn nhỉ :p
----
Thực ra vấn đề của OT cũng đã được Bác Siwtom và Anh Hữu Thắng giúp đỡ giải quyết ổn rồi ạ, từ lúc OT đưa vào sử dụng đến giờ chưa thấy phát sinh vấn đề gì ạ (chắc không sợ mấy chú và mấy ông lái xe bên ngoài quét mã vạch nữa rồi).

Nhưng OT thấy đây là vấn đề chung được nhiều người quan tâm vì thế mà mọi người vẫn đưa rất nhiều giải pháp giải pháp khác nên OT vẫn theo dõi để tham khảo thêm ạ, chứ không có ý muốn đòi hỏi gì thêm ạ.
Với OT thì đã đủ (vì IT chỉ cài cho Unikey ở tất cả các máy) nhưng có thể đối với bạn khác còn gặp phải tính huống khác như không sử dụng Unikey mà lại sử dụng VietKey hoặc những tính huống khác như Bác Siwtom đã đề cập ở bài 154 :D, nên rất mong các Bác/Anh và các bạn tiếp tục trao đổi.

Xin trân trọng cảm ơn tất cả mọi người đã giúp đỡ ạ.
Oanh Thơ

@Nguyễn Hoàng Oanh Thơ
Nếu bài viết đã nhận được kết quả thì lời khuyên của tôi:
1. OT sửa lại bài viết , tổng hợp lại bài và thêm: "Bài viết đã hoàn thành:" có thể sao chép code tốt nhất để đại diện ở bài đăng chính của OT
2. Tải lên file đã được anh @batman1 hoặc file hỗ trợ tốt nhất.
3. Tag @tên người đã hỗ trợ đóng góp cho bạn. và để tên người đóng góp chính là anh @batman1
(Sự đền đáp dễ nhất)

Không biết OT có hiểu điều tôi nói không?
 
Upvote 0
@Nguyễn Hoàng Oanh Thơ
Nếu bài viết đã nhận được kết quả thì lời khuyên của tôi:
1. OT sửa lại bài viết , tổng hợp lại bài và thêm: "Bài viết đã hoàn thành:" có thể sao chép code tốt nhất để đại diện ở bài đăng chính của OT
2. Tải lên file đã được anh @batman1 hoặc file hỗ trợ tốt nhất.
3. Tag @tên người đã hỗ trợ đóng góp cho bạn. và để tên người đóng góp chính là anh @batman1
(Sự đền đáp dễ nhất)

Không biết OT có hiểu điều tôi nói không?

Cảm ơn HeSanbi đã góp ý, OT cũng đã thông tin cụ thể code mà OT đang sử dụng trong chủ đề ở bài 88 rồi ạ:
https://www.giaiphapexcel.com/diendan/threads/khắc-phục-qr-code-sai-do-bộ-gõ-tiếng-việt.140358/page-5#post-902734

OT sẽ tạo file đính kèm và thông tin ở bài 1 ạ,cũng nhờ có bạn mà chủ đề mới hấp dẫn tới tận bài này, hi vọng bạn còn tiếp tục nhiều ý tưởng khác nữa mà chưa Show ra ạ :)
OT chúc bạn sức khỏe và thành công!
 
Upvote 0
Upvote 0
Thêm đoạn nữa:
"Mong BQT, lấy đại diện là anh @Hai Lúa Miền Tây , @OverAC , ... Ghim bài viết này. Vì Unikey vừa đi đôi với Người Việt vừa đi đôi với Excel,
có ích cho rất nhiều người sử dụng" ( ... gì gì đó)
 
Upvote 0
Upvote 0
Vừa đi làm về thì mọi người đã làm xong rồi.
Tuân đã làm thì tin tưởng là chuẩn rồi. Tôi cũng không có các phiên bản Windows khác để test. Nhưng Tuân nên làm thêm để sao không chỉ cho cô OT dùng mà cho cả những người về sau muốn thao tác với các icon khác, ứng dụng khác.

Tức đại loại thế này. Sửa Vietnamese thành Sub chẳng hạn, vd. ListIcons, không có AutoClickUnikey và những cái khác. ListIcons trong vòng lặp For k = 0 To nCount - 1 sẽ nhập các dữ liệu vào mảng TrayInfo(...) As TRAYITEM, mà
Mã:
Private Type TRAYITEM
    hwnd As ...
        uID As ...
        uCallbackMessage As ...
    filename As ...
    sTip As ...
End Type
hwnd, uID, uCallbackMessage thì sao chép từ TRAYDATA(XP) sang. Chỉ còn filename nữa thôi.

Tiếp đó là code để phục vụ cô OT. Vd.

Mã:
Function Vietnamese(Optional ByVal TurnOff As Boolean = True) As Boolean
Dim k As Long
    ListIcons
    For k = 1 To UBound(TrayInfo)
        If TrayInfo(k).filename = "UnikeyNT.exe" Then ' hoặc kiểm tra sTip
            ' làm các việc của cô OT
            Exit For
        End If
    Next k
End Function

Làm thế để nếu ai thích vọc những icon khác, ứng dụng khác thì người ta chỉ việc viết sub của người ta và thay
Mã:
If TrayInfo(k).filename = "UnikeyNT.exe" Then
bằng
Mã:
If TrayInfo(k).filename = "xyz.exe" Then ' hoặc kiểm tra sTip

Ngoài ra người ta có thể không muốn nhấn chuột mà muốn làm các việc khác với icon thì người ta chỉ viết sub thích hợp thôi chứ code chính ListIcons không phải sửa. Vọc với icon thì thoải mái vì có hwnd, uID, uCallbackMessage trong TRAYITEM rồi. Thậm chí có thể gọi Shell_NotifyIcon(NIM_DELETE ... để xóa icon. Tất nhiên xóa icon trên tray thôi chứ ứng dụng vẫn chay.

Cảm ơn anh đã tín nhiệm. Để viết một class tổng thể như vậy cũng có thể được nhưng e chưa biết tính ứng dụng ở đâu trong phạm vi Excel ? Có thể lúc nào đó tạo chủ đề mới với ý tưởng ở topic khác rồi mấy thành viên tâm huyết cùng đóng góp sẽ tập trung hơn.
 
Upvote 0
Cảm ơn anh đã tín nhiệm. Để viết một class tổng thể như vậy cũng có thể được nhưng e chưa biết tính ứng dụng ở đâu trong phạm vi Excel ? Có thể lúc nào đó tạo chủ đề mới với ý tưởng ở topic khác rồi mấy thành viên tâm huyết cùng đóng góp sẽ tập trung hơn.
Hi anh, Cho em hỏi là nếu quét mã vạch như vậy thì có cách nào hiển thị tất cả các thông tin trên mã vạch đó không?
 
Upvote 0
Hi anh, Cho em hỏi là nếu quét mã vạch như vậy thì có cách nào hiển thị tất cả các thông tin trên mã vạch đó không?

Hiển thị hết mà. Cấu tạo của mã vạch do bộ phận thiết kế và đặc thù sản phẩm bào người ta bao gồn nhiều thông tin như mã hàng, trọng lượng, chiều cao, chiều rộng,.... nó được trộn thành bộ mã. CÓ nơi người ta dùng dấu "-" để phân biệt nhóm mã có nơi quy ước số ký tự trong dải ký tự. Vậy nên nếu bạn muốn bóc tách thông tin từ mã vạch thì phải đọc hiểu được nhà phân phối họ đang cấu tạo gì, từ đó dùng thuật toán tách chuỗi để nhặt ra các loại thông tin. Bạn có thể xem một phần bài giảng lập trình VBA của mình về giải thuật tách chuỗi tại đây

 
Upvote 0
Thôi tôi đành lưu file về định dạng XLSM để các phần mềm diệt virus nó có khả năng kiểm tra đc kỹ nội dung trong file để nó có kết luận không ngu ngơ :D . File trước tôi lưu dạng "XLS" để các bạn có thể mở đc cả trên Excel 2003.

Xin chào Anh @Nguyễn Duy Tuân,
Hôm nay OT tải tập tin xlsm về thì không thấy thông báo có virut nữa , OT đã test thử kết quả đã xử lý được vấn đề Unikey.
Nhưng trường hợp bật CapsLock thì QR_Code lấy thông tin sai ạ, anh Tuân bổ sung thêm trường hợp xử lý vấn đề CapsLock giống anh Hữu Thắng nữa sẽ an toàn hơn ạ.
Cảm ơn anh đã cho OT thêm một cách để tham khảo ạ.
 
Upvote 0
Xin góp vui với các cụ một cách tiếp cận hơi củ chuối nhưng tôi nghĩ cũng có thể làm được.
Sử dụng Registry của Unikey để thiết lập chế độ gõ Việt hay Anh.
Unkey nhớ trạng thái ở registry
[HKEY_CURRENT_USER\Software\PkLong\UniKey]
Với Key là Vietnamese theo 2 trạng thái
"Vietnamese"=dword:00000001 ==> tiếng Việt và "Vietnamese"=dword:00000000 ==> tiếng Anh.
Vậy để muốn thiết lập unikey ở chế độ gõ nào ta có thể tiếp cận như sau:
1. Giết chương trình Unikey đang chạy - không hay lắm nhưng cũng đành
2. Sửa cái Registry Vietnamese thành 0 >> đó về tiếng anh
3. Khởi động lại Unikey với Shell hoặc một file bat!
Cách này hơi củ chuối nhưng cũng có thể áp dụng được.
Code VBA cho tiếp cận này cũng không hoàn toàn quá khó với đa số các cụ ở đây!
Xin chia sẻ với các cụ!
 
Lần chỉnh sửa cuối:
Upvote 0
Xin góp vui với các cụ một cách tiếp cận hơi củ chuối nhưng tôi nghĩ cũng có thể làm được.
Sử dụng Registry của Unikey để thiết lập chế độ gõ Việt hay Anh.
Unkey nhớ trạng thái ở registry
[HKEY_CURRENT_USER\Software\PkLong\UniKey]
Với Key là Vietnamese theo 2 trạng thái
"Vietnamese"=dword:00000001 ==> tiếng Việt và "Vietnamese"=dword:00000000 ==> tiếng Anh.
Vậy để thiết lập unikey ở chế độ nào thì:
1. Kill Unikey task
2.Sửa cái registry đó về tiếng anh
3. khởi động lại Unikey với Shell hoặc một file bat!
Cách này hơi củ chuối nhưng cũng có thể áp dụng được.
Xin chia sẻ với các cụ!

Cháu cảm ơn Bác @paulsteigel đã tham gia ạ.
Xin chia sẻ với các cụ!
:D
 
Upvote 0
Xin chia sẻ một cách tiếp cận hơi củ chuối nhưng tôi nghĩ cũng có thể làm được.
Sử dụng Registry của Unikey để thiết lập chế độ gõ Việt hay Anh.
Unkey nhớ trạng thái ở registry
[HKEY_CURRENT_USER\Software\PkLong\UniKey]
Với Key là Vietnamese theo 2 trạng thái
"Vietnamese"=dword:00000001 ==> tiếng Việt và "Vietnamese"=dword:00000000 ==> tiếng Anh.
Vậy để thiết lập unikey ở chế độ nào thì:
1. Kill Unikey task
2.Sửa cái registry đó về tiếng anh
3. khởi động lại Unikey với Shell hoặc một file bat!
Cách này hơi củ chuối nhưng cũng có thể áp dụng được.
Xin chia sẻ với các cụ!
Bác đã nhầm to rồi . Đó là giao diện Việt - Anh của Unikey chứ không phải bật tắt chế độ gõ. Bác nên kiểm tra độ chính xác trước khi đăng
 
Upvote 0
Bác đã nhầm to rồi . Đó là giao diện Việt - Anh của Unikey chứ không phải bật tắt chế độ gõ. Bác nên kiểm tra độ chính xác trước khi đăng
Bạn thử kiểm tra chút đi nào. Bật tiếng Việt của Unikey, thoát Unkey và vào key này kiểm tra
[HKEY_CURRENT_USER\Software\PkLong\UniKey] và kiểm tra "Vietnamese"=dword:00000001
bạn sẽ thấy nó là 1 và sửa nó thành 0 rồi bật unikey lên bạn sẽ thấy nó là E
"VietGUI"=dword:00000001 sẽ là giao diện đấy

Toàn bộ registry của Unkey quản lý là đây ạ
Windows Registry Editor Version 5.00

"ShowDlg"=dword:00000000
"Vietnamese"=dword:00000001
"CodeTable"=dword:00000000
"SwitchKey"=dword:00000001
"InputMethod"=dword:00000000
"FreeMarking"=dword:00000001
"ModernStyle"=dword:00000000
"VietGUI"=dword:00000001
"InConvCharset"=dword:0000000b
"OutConvCharset"=dword:00000000
"ClipboardConvert"=dword:00000001
"MacroEnabled"=dword:00000000
"AutoNonVnRestore"=dword:00000001
"UseUnicodeClipboard"=dword:00000000
"AlwaysMacro"=dword:00000000
"UseIME"=dword:00000000
"SpellCheckEnabled"=dword:00000001
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn thử kiểm tra chút đi nào. Bật tiếng Việt của Unikey rồi thoát nó vào key này
[HKEY_CURRENT_USER\Software\PkLong\UniKey] và kiểm tra "Vietnamese"=dword:00000001
bạn sẽ thấy nó là 1 và sửa nó thành 0 rồi bật unikey lên bạn sẽ thấy nó là E
"VietGUI"=dword:00000001 sẽ là giao diện đấy
À ý bác nói thoát khỏi rồi sửa Registry khởi động lại Unikey. Vậy cũng sẽ rối
 
Upvote 0
À ý bác nói thoát khỏi rồi sửa Registry khởi động lại Unikey. Vậy cũng sẽ rối
Mình chỉ muốn chia sẻ một cách tiếp cận nhỏ - củ chuối thôi - góp chung vào giải pháp lớn mà anh Tuân, anh Batman, các anh/ chị khác đã chia sẻ!
Hy vọng sẽ giúp các bạn gặp vấn đề có thể xử lý được bài toán của mình.
 
Upvote 0
Xin chào Anh @Nguyễn Duy Tuân,
Hôm nay OT tải tập tin xlsm về thì không thấy thông báo có virut nữa , OT đã test thử kết quả đã xử lý được vấn đề Unikey.
Nhưng trường hợp bật CapsLock thì QR_Code lấy thông tin sai ạ, anh Tuân bổ sung thêm trường hợp xử lý vấn đề CapsLock giống anh Hữu Thắng nữa sẽ an toàn hơn ạ.
Cảm ơn anh đã cho OT thêm một cách để tham khảo ạ.

Vấn đề Caplock không phải khó. Về góc độ chuyên môn tôi khuyên Userform và nay đã có API kiểm soát đc Unikey là tuyệt vời. Việc bẫy và chặn ký tự chưa bao giờ tôi đánh giá là hoàn thiện, chưa kể đến vấn đề tốc độ.
Có lẽ mình dừng tham gia dự án này, coi đó là ví dụ tham khảo với nhiều người cùng học hỏi. Nếu có dự án khác thì hoàn thiện hơn vài điểm nữa.
File tôi gửi lên GPE này là Excel mà mấy pm các bạn nghi virus thì đúng là ngu có ngẫu hứng :) . Không hiểu cơ chế virus của Excel là như thế nào.
 
Upvote 0
Vấn đề Caplock không phải khó. Về góc độ chuyên môn tôi khuyên Userform và nay đã có API kiểm soát đc Unikey là tuyệt vời. Việc bẫy và chặn ký tự chưa bao giờ tôi đánh giá là hoàn thiện, chưa kể đến vấn đề tốc độ.
Có lẽ mình dừng tham gia dự án này, coi đó là ví dụ tham khảo với nhiều người cùng học hỏi. Nếu có dự án khác thì hoàn thiện hơn vài điểm nữa.
File tôi gửi lên GPE này là Excel mà mấy pm các bạn nghi virus thì đúng là ngu có ngẫu hứng :) . Không hiểu cơ chế virus của Excel là như thế nào.
Em thấy WinDefender nó bảo vệ Win theo chế độ nghiêm ngặc. Chuyện dùng Win API vào System thì nó phát hiện và cảnh báo là đúng.
Anh phải thông cảm cho các bạn thôi.
Thời đại này các bạn còn sợ Virus là vì do không chuyên. Đang sử dụng có khi thấy CPU, RAM tăng đột ngột muốn tắt máy tính.
Thì Virus là phải sợ hơn nhiều chứ. Càng sợ càng phụ thuộc phần mềm phát hiện Virus, Trojan. Phát hiện cái là quất đi ngay. Lại yên tâm sử dụng.
Cho nên máy tính các bạn cao lắm cũng chỉ 10 phần mềm. Nếu là máy ở công ty chắc không dám rục rịch cài gì luôn chứ phải. Nhở có gì xảy ra cái là alô mấy anh IT vô. Mấy ảnh nghe bài nhạc Opera xong, lại yên tâm "Chắc mấy ảnh vừa duyệt con Virus lấy tiền chuột đây".

Gặp file Excel của anh đăng mà các bạn cũng sợ. Cái này liên quan đến Tim và Gan, Nên cũng phải cần "phần mềm quét" Tim và Gan luôn.
 
Upvote 0
Thử sử dụng bộ gõ EV key làm rất nhanh. Khi ta sử dụng ứng dụng nào cần quét mã vạch thì cho nó tự sang tiếng Anh E. Còn qua phần mềm khác thì nó tự chuyển sang tiếng Việt V. Để làm vậy ta chỉ cần tích vào ô loại trừ ứng dụng tự động trong phần cài đặt EV key. Mở phần mêm cần gõ tiếng anh rồi bấm cho EV key nó chuyển sang E. Làm vậy tự động lần sau nó tự chuyển qua E cho mình luôn rất sướng...
 
Upvote 0

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

Back
Top Bottom