| View previous topic :: View next topic |
| Author |
Message |
franck8244 Power Member


Joined: 06 Mar 2003 Posts: 699 Location: Geneva...
|
Posted: Mon Dec 05, 2011 3:58 pm Post subject: |
|
|
| Quote: | | Is that actually necessary? |
Indeed, here it's not needed , I just took a send_copydata function where it was needed ... _________________ TC#88260 - |
|
| Back to top |
|
 |
Samuel Power Member


Joined: 29 Aug 2003 Posts: 1612 Location: Brandenburg, Germany
|
|
| Back to top |
|
 |
Balderstrom Power Member


Joined: 11 Oct 2005 Posts: 2024
|
Posted: Mon Dec 05, 2011 4:58 pm Post subject: |
|
|
There's a request I believe for retrieving the selected file list via the new WM_COPYData mechanism.
And now that it's implemented, a few things I've asked in the past could be done:
ActiveTab#, ActiveTabName
And with the 64bit compile using lazarus, most of the Window Panels/Controls are all classed Window#
---- It would be great to be able to query the HWND of a given control by name.
E.g. command char might be "G" and implemented similiar to how TC can accept an EM_UserCommand or CD-path by name --- but instead return the HWND of the given control.
There are a number of things that are not possible or very difficult with the lazarus compile since all controls except the FileLists are classed Window#. |
|
| Back to top |
|
 |
ZoSTeR Senior Member

Joined: 29 Jul 2004 Posts: 403
|
Posted: Wed Dec 07, 2011 6:37 am Post subject: |
|
|
Example for AutoIt:
| Code: | #Include <GUIConstantsEx.au3>
#include <SendMessage.au3>
Opt('GUIOnEventMode', 1)
Global $hGUI
_Main()
Func _Main()
Local $iBtn
$hGUI = GUICreate('Test', 150, 50)
GUISetOnEvent($GUI_EVENT_CLOSE, 'Event_GUIClose')
$iBtn = GUICtrlCreateButton('Click Here', 10, 10, 100, 30)
GUICtrlSetOnEvent(-1, 'handle_button_press')
; This registers the function to call when we receive a WM_COPYDATA (0x004A) back from TC:
GUIRegisterMsg(0x004A, 'Our_Func_for_WM_COPYDATA')
GUISetState()
While 1
Sleep(500)
WEnd
EndFunc ;==>_Main
Func _Msg2TC($prmCommand = "A")
$hTC = WinGetHandle("[CLASS:TTOTAL_CMD]")
$dwData = Asc("G") + 256 * Asc("A")
$lpDataLen = StringLen($prmCommand)
$lpData = DllStructCreate("char[" & $lpDataLen + 1 & "]")
DllStructSetData($lpData, 1, $prmCommand)
$lpDataPtr = DllStructGetPtr($lpData)
$structCOPYDATA = DllStructCreate("dword;dword;ptr")
DllStructSetData($structCOPYDATA, 1, $dwData)
DllStructSetData($structCOPYDATA, 2, $lpDataLen)
DllStructSetData($structCOPYDATA, 3, $lpDataPtr)
$ptrCOPYDATA = DllStructGetPtr($structCOPYDATA)
$arrReturn = _SendMessage($hTC, 0x004A, $hGUI, $ptrCOPYDATA)
EndFunc
Func Our_Func_for_WM_COPYDATA($hWnd, $iMsg, $wParam, $lParam)
$returnCOPYDATA = DllStructCreate("dword;dword;ptr", $lParam)
$returnDWData = DllStructGetData($returnCOPYDATA, 1)
$returnLPDataLen = DllStructGetData($returnCOPYDATA, 2)
$returnLPDataPtr = DllStructGetData($returnCOPYDATA, 3)
$returnLPData = DllStructCreate("char[" & $returnLPDataLen + 1 & "]", $returnLPDataPtr)
$retValue = DllStructGetData($returnLPData, 1)
; Avoid MsgBox in real life at this point (see AutoIt Help 'GUIRegisterMsg')
MsgBox(0,"TC Reply", $retValue)
EndFunc
Func handle_button_press()
_Msg2TC()
EndFunc
Func Event_GUIClose()
Exit
EndFunc |
|
|
| Back to top |
|
 |
rmmaniac Junior Member

Joined: 13 Apr 2009 Posts: 9
|
Posted: Sun Jun 10, 2012 9:18 am Post subject: |
|
|
| can we use this new feature to opentabs file or open bartton file(not via user command) in a Ahk script ?. is there an example. Thanks |
|
| Back to top |
|
 |
fallmq Junior Member

Joined: 28 Jun 2012 Posts: 14
|
Posted: Sun Oct 14, 2012 6:03 am Post subject: |
|
|
I attemp to write a autohotkey script in order to send a em_xx cmd to TC, I see the sample code here and did a test, unfortunately it didn't work, anybody can tell me what is the problem in my code?
PS: I am using autohotkey_L 1.1.08.01 x64, and Total commander 8.01 rc5 X64
| Code: |
#NoTrayIcon
#SingleInstance force
SetBatchLines -1
SendMode, Input
TC_SendWMCopyData("EM", "em_test", "", "ahk_class TTOTAL_CMD")
return
TC_SendWMCopyData( cmdType, byRef cmd, byRef addParams="", aWin="A" )
{
Critical
VarSetCapacity( CopyDataStruct, A_PtrSize * 3 )
if( A_IsUnicode )
{
VarSetCapacity( cmdA, StrPut(cmd, "cp0"))
Loop, % StrLen(cmd)
NumPut( Asc(SubStr(cmd, A_Index, 1)), cmdA, A_Index - 1, "Char")
}
NumPut( Asc(SubStr(cmdType,1,1)) + 256 * Asc(SubStr(cmdType,2,1)), CopyDataStruct )
NumPut( StrLen(cmd) + (cmdType="CD" ? 5 : 1), CopyDataStruct, A_PtrSize )
NumPut((A_IsUnicode ? &cmdA : &cmd), CopyDataStruct, A_PtrSize * 2)
Loop, % (cmdType=="CD" ? 2 : 0)
NumPut( Asc(SubStr(addParams, A_Index, 1)), (A_IsUnicode ? cmdA : cmd), (StrLen(cmd) + A_Index), "Char" )
SendMessage, 0x4A,, &CopyDataStruct,, ahk_id %aWin%
return
}
|
and here is my em_cmd
| Code: |
[em_test]
button=
cmd=notepad
|
|
|
| Back to top |
|
 |
Balderstrom Power Member


Joined: 11 Oct 2005 Posts: 2024
|
Posted: Wed Oct 17, 2012 4:03 pm Post subject: |
|
|
That looks like the current version of my code, I think yer not calling it correctly.
| Code: | TC_SendWMCopyData("EM", "em_test", "", "ahk_class TTOTAL_CMD")
return
TC_SendWMCopyData( cmdType, byRef cmd, byRef addParams="", aWin="A" ) |
Note parameter #2: cmd, is a byRef - it has to be a variable.
So you call it like this: | Code: | | TC_SendWMCopyData("EM", gCmd:="em_test", gNul:="", "ahk_class TTOTAL_CMD") |
But I use a higher-level function to call into TC_SendWMCopyData
e.g. | Code: | TC_EMC( cmd, wID="ahk_class TTOTAL_CMD")
{
TC_SendWMCopyData( "EM", cmd, params:="", wID )
return
} |
So you would do:
Which keeps global variables out of the namespace as well.
EDIT: That wont work, in my actual TC_EMC, I also call:
TC_Activate()
| Code: | TC_EMC( cmd, wID="ahk_class TTOTAL_CMD", activateWin=FALSE, showMsg=FALSE )
{
TC_Activate( wID, activateWin, showMsg, cmd )
TC_SendWMCopyData( "EM", cmd, params:="", wID )
return
} |
Wherein, wID is assigned to it's ID# (ahk_id).
| Code: | TC_Activate( byRef wID, activateWin=TRUE, showMsg=TRUE, cmd="" )
{
wID:=QueryWinID(wID, TRUE)
; MsgBox, %A_ThisFunc% :: wID: %wID%
if(!activateWin ) ;&& WinExist("ahk_id " wID))
return FALSE
if( showMsg )
MsgBox,,%A_ThisFunc%, % "Activating TC" ( cmd ? ", for command: " cmd "`n" : "`n"), 1
MsgBox, %A_ThisFunc%, Activating TC
WinActivate, ahk_id %wID%
return TRUE
}
QueryWinID( aWin="A", canExist=FALSE, winText="", notTitle="", notText="" )
{
; MsgBox,, %A_ThisFunc%, aWin: %aWin%, canExist: %canExist%
if( !(retVal:=WinActiveA( aWin, winText, notTitle, notText )) )
retVal:=( !canExist ? 0 : WinExistA( aWin, winText, notTitle, notText ))
return retVal
}
WinActiveA( aWin="", winText="", notTitle="", notText="" )
{
return WinActive( (aWin+0 ? "ahk_id " aWin : aWin), winText, notTitle, notText )
}
WinExistA( aWin="", winText="", notTitle="", notText="" )
{
return WinExist( (aWin+0 ? "ahk_id " aWin : aWin), winText, notTitle, notText )
}
|
Now you don't necessarily have to do all that. But the WMCopyData function is expecting a ID# so minimally you need to do
wID:=WinExist("ahk_class TTOTAL_CMD")
or
wID:=WinActive("ahk_class TTOTAL_CMD")
So long as it's the only instance of TC running, it would be fine.
It's probably a slight bug that the default variable for wID is ="A" in TC_SendWMCopyData() as that wont work with the SendMessage --- I just never use it like that and didn't really notice --- I always call it with caller functions, like TC_EMC(), TC_CMD() and TC_CD()
| Code: | TC_CMD( cmd, wID="ahk_class TTOTAL_CMD", activateWin=FALSE, post=TRUE, showMsg=FALSE )
{
TC_Activate( wID, activateWin, showMsg, cmd )
if( !post )
SendMessage, 0x433, TC_@( cmd ), 0x0,, ahk_id %wID%
else
PostMessage, 0x433, TC_@( cmd ), 0x0,, ahk_id %wID%
return TRUE
}
TC_@( cm_cmd="" )
{
static
static init := 0
global TC__TotalCmd@INC
local iCmd, iCmd1, iCmd2, iCmd3, iTmp, retVal, tmpVar
if( !init && init := 1 && !ErrorLevel:="")
{
local aDrive, aFile, aPath
if(!(aPath:=TC__TotalCMD@INC))
{
EnvGet, aPath, COMMANDER_PATH
; MsgBox, TC__TotalCmd@INC: %TC__TotalCmd@INC%
if( !aPath )
{
EnvGet, aDrive, SystemDrive
if(!FileExist(aPath:=aDrive "\TotalCmd"))
if(!FileExist(aPath:=ProgramFiles "\TotalCMD"))
aPath:=ProgramFiles
FileSelectFile, TC__TotalCmd@INC,, %aPath%,Location of TotalCMD.inc file?,*.inc
}
else
TC__TotalCmd@INC:=aPath "\TotalCMD.inc"
}
; MsgBox, TC__TotalCmd@INC: %TC__TotalCmd@INC%
; MsgBox, aPath: %aPath%
SplitPath( TC__TotalCmd@INC, aFile )
; MsgBox, aFile: %aFile%`nErrorLevel: %ErrorLevel%
onErrorExit((ErrorLevel || !RegExMatch( aFile, "i)^TotalCMD.inc$")) && !(init:=0), "ERROR: Invalid TotalCMD.inc File.")
FileRead, TcmdINC, %TC__TotalCmd@INC%
Loop, Parse, TcmdINC, `n, `r
{
if( !regExMatch( A_LoopField, "^cm_([a-zA-Z]+)([0-9]+)?=([0-9]+);", iCmd ) )
continue
if( iCmd3 > 6000 && iCmd3 <= 20000)
continue
if( iCmd3 > 5000 && iCmd3 <= 5500)
continue
else
if( iCmd3 > 2060 && iCmd3 <= 2120 ) ; cm_GotoDriveA ...
continue
else
if( iCmd3 >= 701 && iCmd3 <= 900 ) ; cm_UserMenu1 ... cm_UserMenu300
continue
else
if( iCmd3 >= 271 && iCmd3 <= 299 ) ; cm_SrcCustomView1 - 29
continue
else
if( iCmd3 >= 171 && iCmd3 <= 199 ) ; cm_RightCustomView1 - 29
continue
else
if( iCmd3 >= 71 && iCmd3 <= 99 ) ; cm_LeftCustomView1 - 29
continue
tmpVar = cm_%iCmd1%%iCmd2%
StringUpper, tmpVar, tmpVar
%tmpVar% := iCmd3
}
if( !cm_cmd )
return
}
Sleep, 50
if( !cm_cmd )
return
; if( )
onErrorExit( !inStr( cm_cmd, "cm_"), "UnSupported: Input must be a `cm_` string." cm_cmd ": " %cm_cmd%, A_ThisFunc )
StringUpper, cm_cmd, cm_cmd
if( retVal := %cm_cmd% )
return retVal
if( RegExMatch( cm_cmd, "^CM_(LEFT|RIGHT|SRC)(CUSTOMVIEW)(\d+)$", iCmd ) )
{
onErrorExit( ( iCmd3 < 1 || iCmd3 > 29 ), "Illegal value for: " cm_cmd, A_ThisFunc )
local LEFT := 0, RIGHT := 100, SRC := 200
return % ( %iCmd1% + iCmd3 + 70 )
}
if( RegExMatch( cm_cmd, "^(CM_)(USERMENU)(\d+)$", iCmd ) )
{
onErrorExit( ( iCmd3 < 1 || iCmd3 > 200 ), "Illegal value for: " cm_cmd, A_ThisFunc )
return ( iCmd3 + 700 )
}
if( RegExMatch( cm_cmd, "CM_(LEFT|RIGHT|SRC|TRG)(ACTIVATETAB|SORTBYCOL)(\d+)", iCmd ) )
{
onErrorExit( ( iCmd3 < 1 || iCmd3 > 99 ), "Illegal value for: " cm_cmd , A_ThisFunc )
local SRC := 0, TRG := 100, LEFT := 200, RIGHT := 300
local ACTIVATETAB := 5000, SORTBYCOL := 6000
return % ( %iCmd1% + %iCmd2% + iCmd3 )
}
if( RegExMatch( cm_cmd, "(CM_)(GOTODRIVE)([A-Z])", iCmd ) )
{
return ( ASC(iCmd3) + 2000 -4 )
}
;onErrorExit( TRUE, "Variable: " cm_cmd " doesn't exist!", A_ThisFunc )
}
onErrorExit( checkEval, errMsg="", fn="", delay=3 )
{
if( !checkEval )
return 0
if((!ErrorLevel || ErrorLevel:=1) && !errMsg)
Exit
RegExMatch(fn, "^([^:]+)(::([^ ].*))?$", rTmp )
msg := ( rTmp1 ? rTmp1 "(" rTmp3 "): " : "" ) errMsg
MsgBox,, % A_ScriptName " :: " rTmp1, % msg, % delay
Exit
}
SplitPath( fullPath, byRef aFile="", byRef aDir="", byRef aExt="", byRef aDrive="", byRef aNameOnly="" )
{
fullPath.=((inStr(FileExist(fullPath), "D") && SubStr(fullPath, 0) <> "\") ? "\" : "")
SplitPath, fullPath, aFile, aDir, aExt, aNameOnly, aDrive
aDir.=(aDir && (aDir==aDrive)) ? "\" : ""
return
} |
TC_CD() is a neat piece of code, but it pretty much requires a LIB.ahk as it uses a fair number of defined functions, not really pasteable here. |
|
| Back to top |
|
 |
fallmq Junior Member

Joined: 28 Jun 2012 Posts: 14
|
Posted: Thu Oct 18, 2012 9:55 am Post subject: |
|
|
thanks Balderstrom, my code can work now,
just as you said, the problem is on the last param of TC_SendWMCopyData, a winExist("ahk_class TTOTAL_CMD") or WinActive("ahk_class TTOTAL_CMD") should be necessary.
I have another two questions:
1. the input parameter of "CD" is so complex, src" `r"target" ", do we MUST write the parameter like this?
2. it seems the "CD" and "EM" are both internal message format defined by TC, but I didn't find the detail information for these message types, can you tell you where can I get the detail description? |
|
| Back to top |
|
 |
Stefan2 Senior Member


Joined: 13 Sep 2007 Posts: 264 Location: Germany, EU
|
Posted: Thu Oct 18, 2012 12:55 pm Post subject: |
|
|
Interesting topic! Please don't hesitate anybody to explain in most possible details ... i am learning too. _________________ Greetings, Stefan. |
|
| Back to top |
|
 |
Balderstrom Power Member


Joined: 11 Oct 2005 Posts: 2024
|
Posted: Thu Oct 18, 2012 2:07 pm Post subject: |
|
|
Mr.Ghisler used half of a carriage return "`r" of an "`r`n" to separate two possible variables, as a SendMessage can only pass a single parameter. Likewise, a file path can't contain a partial carriage return.
Thus, SRC_Path "`r" TRG_Path
Since it is possible to only change a single panel's path, e.g.
examplePath:="`r" TRG_Path ; Only change Target Panel
examplePath:=SRC_Path "`r" ; Only change Source Panel
examplePath:=SRC_Path "`r" TRG_Path ; Change both Panels. |
|
| Back to top |
|
 |
Balderstrom Power Member


Joined: 11 Oct 2005 Posts: 2024
|
Posted: Thu Oct 18, 2012 2:19 pm Post subject: |
|
|
| Code: | WinActiveA( aWin="", winText="", notTitle="", notText="" )
{
return WinActive( (aWin+0 ? "ahk_id " aWin : aWin), winText, notTitle, notText )
} |
That was one of my favorite compact functions.
It allows you to pass around either a "string" for aWin (e.g. ahk_class TTOTAL_CMD), or a winID.
aWin+0 will be an empty-string if it IS a string and you add 0 to it.
aWin+0 will remain a number if it was a number and you add 0 to it.
Thus we have, | Code: | if( aWin+0 ) ; if a number
return WinActive("ahk_id " aWin, winText, notTitle, notText)
else
return WinActive(aWin, winText, notTitle, notText) |
I usually pass around winID's but not always, by utilizing a custom WinActive or WinExist, you don't have to worry about what you passed to a given function - be it a title string, an ahk_class, or a plain ID# without prefacing it with "ahk_id".
Thus it becomes cleaner to write functions that rely on each other when you can do:
SomeFunction(winID, TRUE)
And within SomeFunction() we validate the winID by using WinActiveA() or WinExistA() instead of the vanilla AHK functions WinActive/WinExist. If you use the default AHK functions, then you need to always know what it is you are passing around --- and in a scripting language that mutates strings to numbers and vica versa - it is beneficial to have functions that can handle both as well. |
|
| Back to top |
|
 |
nsp Power Member


Joined: 04 Dec 2005 Posts: 718 Location: Lyon (FRANCE)
|
Posted: Fri Oct 19, 2012 1:34 am Post subject: |
|
|
| fallmq wrote: | thanks Balderstrom, my code can work now,
just as you said, the problem is on the last param of TC_SendWMCopyData, a winExist("ahk_class TTOTAL_CMD") or WinActive("ahk_class TTOTAL_CMD") should be necessary.
I have another two questions:
1. the input parameter of "CD" is so complex, src" `r"target" ", do we MUST write the parameter like this?
2. it seems the "CD" and "EM" are both internal message format defined by TC, but I didn't find the detail information for these message types, can you tell you where can I get the detail description? |
The complete syntax is in fact :
<Left>\r<Right>\0
<Source>\r<Target>\0S
<Left>\r<Right>\0T open in new Tab
If you only need to open in current source tab you can define a user command em_cd with command cd AND %A As parameter;
After, you can use your em_cd like sending em_cd D:\MyFolder it will also allows you to add filter like em_cd *.ini *.reg *.key
-- edited --
We already add such discussion on em_cmd and specific CD command in 2006 ! http://ghisler.ch/board/viewtopic.php?p=104086#104086 and http://www.ghisler.ch/board/viewtopic.php?p=105246 |
|
| Back to top |
|
 |
nsp Power Member


Joined: 04 Dec 2005 Posts: 718 Location: Lyon (FRANCE)
|
Posted: Fri Oct 19, 2012 2:03 am Post subject: |
|
|
Details are on the forum or in the history.txt !!! |
|
| Back to top |
|
 |
Hurdet Member

Joined: 10 May 2003 Posts: 189
|
Posted: Wed Dec 05, 2012 12:50 am Post subject: |
|
|
| ZoSTeR wrote: | Example for AutoIt:
| Code: | #Include <GUIConstantsEx.au3>
#include <SendMessage.au3>
Opt('GUIOnEventMode', 1)
Global $hGUI
_Main()
Func _Main()
Local $iBtn
$hGUI = GUICreate('Test', 150, 50)
GUISetOnEvent($GUI_EVENT_CLOSE, 'Event_GUIClose')
$iBtn = GUICtrlCreateButton('Click Here', 10, 10, 100, 30)
GUICtrlSetOnEvent(-1, 'handle_button_press')
; This registers the function to call when we receive a WM_COPYDATA (0x004A) back from TC:
GUIRegisterMsg(0x004A, 'Our_Func_for_WM_COPYDATA')
GUISetState()
While 1
Sleep(500)
WEnd
EndFunc ;==>_Main
Func _Msg2TC($prmCommand = "A")
$hTC = WinGetHandle("[CLASS:TTOTAL_CMD]")
$dwData = Asc("G") + 256 * Asc("A")
$lpDataLen = StringLen($prmCommand)
$lpData = DllStructCreate("char[" & $lpDataLen + 1 & "]")
DllStructSetData($lpData, 1, $prmCommand)
$lpDataPtr = DllStructGetPtr($lpData)
$structCOPYDATA = DllStructCreate("dword;dword;ptr")
DllStructSetData($structCOPYDATA, 1, $dwData)
DllStructSetData($structCOPYDATA, 2, $lpDataLen)
DllStructSetData($structCOPYDATA, 3, $lpDataPtr)
$ptrCOPYDATA = DllStructGetPtr($structCOPYDATA)
$arrReturn = _SendMessage($hTC, 0x004A, $hGUI, $ptrCOPYDATA)
EndFunc
Func Our_Func_for_WM_COPYDATA($hWnd, $iMsg, $wParam, $lParam)
$returnCOPYDATA = DllStructCreate("dword;dword;ptr", $lParam)
$returnDWData = DllStructGetData($returnCOPYDATA, 1)
$returnLPDataLen = DllStructGetData($returnCOPYDATA, 2)
$returnLPDataPtr = DllStructGetData($returnCOPYDATA, 3)
$returnLPData = DllStructCreate("char[" & $returnLPDataLen + 1 & "]", $returnLPDataPtr)
$retValue = DllStructGetData($returnLPData, 1)
; Avoid MsgBox in real life at this point (see AutoIt Help 'GUIRegisterMsg')
MsgBox(0,"TC Reply", $retValue)
EndFunc
Func handle_button_press()
_Msg2TC()
EndFunc
Func Event_GUIClose()
Exit
EndFunc |
|
When i use:
| Code: | | $dwData = Asc("G") + 256 * Asc("A") |
It work fine.
Instead, when i use:
| Code: | | $dwData = Asc("G") + 256 * Asc("W") |
for unicode it return only 1 character.
Why? |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|