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

Liên hệ QC

Hoàng Nhật Phương

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

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

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

Xin trân trọng cảm ơn BQT đã tạo ra và đã mang đến cho tôi và mọi người một nơi thật tuyệt vời, một nơi để mọi người cùng nhau có thể trao đổi/học hỏi và cùng nhau thành công trong sự nghiệp.
 
Lần chỉnh sửa cuối:
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

  • Barcode_Scanner_Unikey.xls
    297.5 KB · Đọc: 59
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
Web KT
Back
Top Bottom