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
AHK code
Code: Select all
#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
}
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