[VBA] Send user_command

Discuss and announce Total Commander plugins, addons and other useful tools here, both their usage and their development.

Moderators: white, Hacker, petermad, Stefan2

Post Reply
valuex
Junior Member
Junior Member
Posts: 25
Joined: 2014-12-25, 13:53 UTC

[VBA] Send user_command

Post by *valuex »

Background
I want to send WM_COPYDATA from excel VBA to TC.
And have tried the direct way, viewtopic.php?t=80948, but it does NOT work.
So here is an indirect way, that is to send WM_COPYDATA to ahk, and then ahk will forward the WM_COPYDATA to TC.
how to use it
1. set your command in usercmd.ini
2. save and launch the ahk script
3. run the vba code from MS Excel

VBA code -64bit only

Code: Select all

Option Explicit

Private Declare PtrSafe Function FindWindow Lib "USER32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function SendMessage Lib "USER32" Alias "SendMessageA" (ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As LongPtr
Private Declare PtrSafe Function GetWindowTextLength Lib "USER32" Alias "GetWindowTextLengthA" (ByVal hWnd As Long) 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 GetWindow Lib "USER32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare PtrSafe Function IsWindowVisible Lib "USER32" (ByVal hWnd As Long) As Boolean
Public Declare PtrSafe Function GetParent Lib "user32.dll" (ByVal hWnd As LongPtr) As LongPtr
Public Declare PtrSafe Function GetWindowThreadProcessId Lib "USER32" (ByVal hWnd As LongPtr, lpdwProcessId As Long) As Long

Public Type CopyDataStruct
    dwData As LongPtr
    cbData As Long
    lpData As LongPtr
End Type
Private Const WM_COPYDATA = &H4A
Private Const GW_HWNDNEXT = 2
Function GetHiddenWinHwndByTitle(strWinTitle) As Long
    Dim lhWndP As Long
    If GetHandleFromPartialCaption(lhWndP, strWinTitle) = True Then
        GetHiddenWinHwndByTitle = lhWndP
    Else
        GetHiddenWinHwndByTitle = 0
    End If
End Function


Sub TC_SendUserCMD()
    Dim UserCMD As String
    UserCMD = "em_focusfile"
    
    Dim cds As CopyDataStruct, result As LongPtr
    Dim hwndAHKInterposer As Long
    Dim wParam As Long
    wParam = 0
    hwndAHKInterposer = GetHiddenWinHwndByTitle("TC-VBA-Interposer")
    'Debug.Print hwndAHKInterposer
    If (hwndAHKInterposer > 0) Then
        cds.dwData = Asc("E") + 256 * Asc("M")
        cds.cbData = Len(UserCMD) * 2 + 2  'The size, in bytes
        cds.lpData = StrPtr(UserCMD)
        result = SendMessage(hwndAHKInterposer, WM_COPYDATA, wParam, cds)
        Debug.Print hwndAHKInterposer
    End If
End Sub



Private Function GetHandleFromPartialCaption(ByRef lWnd As Long, ByVal sCaption As String) As Boolean
    'https://copyprogramming.com/howto/how-to-locate-the-window-using-findwindow-function-in-windowapi-using-vba
    Dim lhWndP As Long
    Dim sStr As String
    GetHandleFromPartialCaption = False
    lhWndP = FindWindow(vbNullString, vbNullString) 'PARENT WINDOW
    Do While lhWndP <> 0
        sStr = String(GetWindowTextLength(lhWndP) + 1, Chr$(0))
        GetWindowText lhWndP, sStr, Len(sStr)
        sStr = Left$(sStr, Len(sStr) - 1)
        If InStr(1, sStr, sCaption) > 0 Then
            GetHandleFromPartialCaption = True
            lWnd = lhWndP
            Debug.Print sStr
            Exit Do
        End If
        lhWndP = GetWindow(lhWndP, GW_HWNDNEXT)
    Loop
End Function

Autohotkey V2 code

Code: Select all

Persistent
; global retVal:=""
MyGui:=Gui()
MyGui.Title := "TC-VBA-Interposer"
MyGui.Show("hide w500 h200")
TC_Interposer()
return
TC_Interposer()
{    ;https://wincmd.ru/forum/viewtopic.php?p=110848&sid=0dfde01723b39e508e96d62c00a7a9b5
    If WinExist("ahk_class TTOTAL_CMD") ;&& WinActive("ahk_class TTOTAL_CMD")
        OnMessage(0x4a, TC_Receive_WM_COPYDATA)  ; 0x4a is WM_COPYDATA          
    else
        MsgBox "TC does NOT exist"
}

TC_Receive_WM_COPYDATA(wParam, lParam, msg, hwnd)
{  
    PtrPos:=NumGet(lParam + A_PtrSize * 2,0,"Ptr")
    retVal:=StrGet(PtrPos)
    if(retVal)
    {
        ; MsgBox retVal 
        TC_SendUserCommand(retVal) 
    }     
}

/*
TC_SendUserCommand()
fucntion: send user defined command in the usercmd.ini to TC
agruments: command name <em_xxxx> in usercmd.ini
return: none
*/

TC_SendUserCommand(userCommand) 
{
    ; https://www.autohotkey.com/boards/viewtopic.php?p=538463&sid=4471e03917209854441ac07ebdc70901#p538463
    static dwData := 19781  ;Ord("E") +256*Ord("M")
    static WM_COPYDATA := 0x4A
    cbData := Buffer(StrPut(userCommand, 'CP0'))
    StrPut(userCommand, cbData, 'CP0')
    COPYDATASTRUCT := Buffer(A_PtrSize * 3)
    NumPut('Ptr', dwData, 'Ptr', cbData.size, 'Ptr', cbData.ptr, COPYDATASTRUCT)
    MsgResult:=SendMessage( WM_COPYDATA,, COPYDATASTRUCT,, 'ahk_class TTOTAL_CMD')
    return MsgResult
}
Post Reply