[求助] [VBA] 如何向Total Commander 中发送WM_COPYDATA 消息

https://club.excelhome.net/thread-1684243-1-1.html

参照下述网址将代码改成64位用的了,一直没有成功,请坛子里面的高手帮忙看看,谢谢。
我怀疑是跟这句相关,但尝试了好几种方案也没有成功。
cds.cbData = Len(UserCMD)+1

'cds.cbData = Len(UserCMD)
'cds.cbData = Len(UserCMD)*2
'cds.cbData =( Len(UserCMD)+1)*2

参考链接: https://stackoverflow.com/questi … am-in-vba-for-excel

Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
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

Public Type CopyDataStruct
    dwData As LongPtr
    cbData As LongPtr
    lpData As LongPtr
End Type
Private Const WM_COPYDATA = &H4A
Sub test()
    Dim newPath As String
    ThisFile = "D:\xxx\xxx.mhtml"
    newPath = ThisFile & "\:\n" & "\0"
    hwndTC = FindWindow("TTOTAL_CMD", vbNullString)
    result = SendMessage(hwndTC, 1075, 4001, 0)  'FocusLeft
    result = SendMessage(hwndTC, 1075, 3001, 0)  'NewTab
    
    Call TC_SetPath(hwndTC, newPath)
End Sub

Sub TC_SetPath(hwndTarget, UserCMD As String)
    Dim cds As CopyDataStruct
    
    cds.dwData = Asc("C") + 256 * Asc("D")
    cds.cbData = Len(UserCMD)+1
    cds.lpData = StrPtr(UserCMD)
    
    ' Send the WM_COPYDATA message
    result = SendMessage(hwndTarget, WM_COPYDATA, 0, cds)
End Sub

这个帖子别沉了啊。
这种问题不太好搞,得要懂VBA,还得用TC
辛苦坛子里的高手们帮忙看看了。谢谢。

这个问题不好搞,试了半天也没成功,只能通过间接法弄了。
原理
通过VBA 向AHK发送WM_COPYDATA,再由AHK 转送到TC
用法

  1. usercmd.ini中配置对应的命令,例如
[em_focusfile]
cmd=CD
param=D:\SoftX\AHK_Scripts_V2\Lib\
  1. 运行下面的ahk脚本
  2. 在Excel 中运行下述VBA代码

#Requires AutoHotkey >=2.0
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
}

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

Function WndFromPID(ByVal Xpid As LongPtr) As LongPtr
    'https://stackoverflow.com/questions/7807150/how-can-i-get-a-handle-to-a-window-of-executed-process-in-vba
    Dim Nhwnd As LongPtr, Npid As Long, Nthread_id As Long
    ' Get the first window handle.
    Nhwnd = FindWindow(vbNullString, vbNullString)  ' NOT (ByVal 0&, ByVal 0& ) !
    ' Loop until we find the target or we run out of windows
    Do While Nhwnd <> 0
        ' See if this window has a parent. If not, it is a top-level window
        If GetParent(Nhwnd) = 0 Then
            ' This is a top-level window. See if it has the target instance handle
            Nthread_id = GetWindowThreadProcessId(Nhwnd, Npid)
            If Npid = Xpid Then
                WndFromPID = Nhwnd      ' This is the target
                Exit Do
            End If
        End If
        Nhwnd = GetWindow(Nhwnd, 2)     ' Examine the next window [2 = GW_HWNDNEXT]
    Loop
End Function