Page 1 of 1

AutoHotKey script to get the path to the selected file

Posted: 10 Feb 2023 22:26
by Texano88
How can I get the path to the selected file in Xyplorer in AutoHotKey?
For explorer there is the function:

Code: Select all

Explorer_GetSelection() {
   WinGetClass, winClass, % "ahk_id" . hWnd := WinExist("A")
   if !(winClass ~= "^(Progman|WorkerW|(Cabinet|Explore)WClass)$")
      Return

   shellWindows := ComObjCreate("Shell.Application").Windows
   if (winClass ~= "Progman|WorkerW") ; IShellWindows::Item:    https://goo.gl/ihW9Gm
      ; IShellFolderViewDual:   https://goo.gl/gnntq3
      shellFolderView := shellWindows.Item( ComObject(VT_UI4 := 0x13, SWC_DESKTOP := 0x8) ).Document
   else {
      for window in shellWindows ; ShellFolderView object: https://tinyurl.com/yh92uvpa
         if (hWnd = window.HWND) && (shellFolderView := window.Document)
            break
   }
   for item in shellFolderView.SelectedItems
      result .= (result = "" ? "" : "`n") . item.Path
   ;~ if !result
   ;~ result := shellFolderView.Folder.Self.Path
   Return result
}
Thank you

Re: AutoHotKey script to get the path to the selected file

Posted: 10 Feb 2023 22:33
by highend
By sending a script to XY that sends back the current selected file to the script's window. WM_COPYDATA / RECEIVE...

Re: AutoHotKey script to get the path to the selected file

Posted: 10 Feb 2023 23:34
by Texano88
I found a script in this thread viewtopic.php?t=15121, but it doesn't seem to work, i just get empty msgboxe

Re: AutoHotKey script to get the path to the selected file

Posted: 10 Feb 2023 23:37
by highend
And now you want us to guess which of those scripts you've used?

Re: AutoHotKey script to get the path to the selected file

Posted: 10 Feb 2023 23:44
by Texano88
Sorry, I forgot to specify which one:

Code: Select all

/*
    XYGetPath()     - paths of target window's selected items
    XYGetAll()      - paths of all items in the target window's folder
    XYGetSelected() - path of target window's folder

    example:
        F1::
            path := XYGetPath()
            all := XYGetAll()
            sel := XYGetSelected()
            MsgBox % path
            MsgBox % all
            MsgBox % sel
        return

*/

; Get our own HWND (we have no visible window)
DetectHiddenWindows, On
G_OwnHWND := WinExist("Ahk_PID " DllCall("GetCurrentProcessId"))
G_OwnHWND += 0

; Get messages back from XYplorer
OnMessage(0x4a, "Receive_WM_COPYDATA")

F1::
    path := XYGetPath()
    all  := XYGetAll()
    sel  := XYGetSelected()
    MsgBox % path
    MsgBox % all
    MsgBox % sel
return


XYGetPath()
{
    return XY_Get()
}


XYGetAll()
{
   return XY_Get(true)
}


XYGetSelected()
{
   return XY_Get(, true)
}


XY_Get(bAll:=false, bSelection:=false)
{
    global dataReceived, G_OwnHWND

    xyQueryScript =
    ( LTrim Join
        ::
        if (!%bAll% && !%bSelection%) {
            $return = "<curpath>";
        } elseif (%bAll%) {
            $return = listpane(, , , "<crlf>");
        } elseif (%bSelection%) {
            $return = get("SelectedItemsPathNames", "<crlf>");
        }
        copydata %G_OwnHWND%, "$return", 2;
    )

    Send_WM_COPYDATA(xyQueryScript)

    return dataReceived
}


GetXYHWND() {
    IfWinActive, ahk_class ThunderRT6FormDC
    {
        WinGet, xyHwnd, ID, ahk_class ThunderRT6FormDC
    } else {
        WinGet, xyHwnd, List, ahk_class ThunderRT6FormDC
        if (xyHwnd)
            xyHwnd := xyHwnd1
    }

    return xyHwnd
}


Send_WM_COPYDATA(message) {
   xyHwnd := GetXYHWND()

   if !(xyHwnd)
       return

   size := StrLen(message)
   if !(A_IsUnicode) {
      VarSetCapacity(data, size * 2, 0)
      StrPut(message, &data, size, "UTF-16")
   } else {
      data := message
   }
   VarSetCapacity(COPYDATA, A_PtrSize * 3, 0)
   NumPut(4194305, COPYDATA, 0, "Ptr")
   NumPut(size * 2, COPYDATA, A_PtrSize, "UInt")
   NumPut(&data, COPYDATA, A_PtrSize * 2, "Ptr")
   result := DllCall("User32.dll\SendMessageW", "Ptr", xyHWND, "UInt", 74, "Ptr", 0, "Ptr", &COPYDATA, "Ptr")
   return
}


Receive_WM_COPYDATA(wParam, lParam) {
   global dataReceived

   stringAddress := NumGet(lParam + 2 * A_PtrSize)
   copyOfData := StrGet(stringAddress)
   cbData := NumGet(lParam + A_PtrSize) / 2
   StringLeft, dataReceived, copyOfData, cbData

   return
}

Re: AutoHotKey script to get the path to the selected file

Posted: 11 Feb 2023 00:00
by highend
That one works 100% fine here...

Reduce it, send a simple text "hello" to XY with it?

Re: AutoHotKey script to get the path to the selected file

Posted: 12 Feb 2023 19:55
by Texano88
I put the code in an empty script and it works, it's probably a compatibility issue with my other scripts

Re: AutoHotKey script to get the path to the selected file

Posted: 25 Feb 2023 19:20
by Norn
I'm trying to convert to AHK V2. . .

Code: Select all

#Requires AutoHotkey v2.0.2

; Get our own HWND (we have no visible window)
DetectHiddenWindows 1
G_OwnHWND := WinExist("Ahk_PID " DllCall("GetCurrentProcessId"))
G_OwnHWND += 0

; Get messages back from XYplorer
OnMessage(0x4a, "Receive_WM_COPYDATA")

F1::
{
    path := XYGetPath()
    all  := XYGetAll()
    sel  := XYGetSelected()
    MsgBox path
    MsgBox all
    MsgBox sel
return
}


XYGetPath()
{
    return XY_Get()
}


XYGetAll()
{
   return XY_Get(true)
}


XYGetSelected()
{
   return XY_Get(, true)
}


XY_Get(bAll:=false, bSelection:=false)
{
    global dataReceived, G_OwnHWND

    xyQueryScript :=
    ( LTrim Join
        ::
        if (!%bAll% && !%bSelection%) {
            $return = "<curpath>";
        } elseif (%bAll%) {
            $return = listpane(, , , "<crlf>");
        } elseif (%bSelection%) {
            $return = get("SelectedItemsPathNames", "<crlf>");
        }
        copydata %G_OwnHWND%, "$return", 2;
    )

    Send_WM_COPYDATA(xyQueryScript)

    return dataReceived
}


GetXYHWND() {
    If WinActive("ahk_class ThunderRT6FormDC")
    {
        xyHwnd := WinGetID("ahk_class ThunderRT6FormDC")
    } else {
        xyHwnd := WinGetList("ahk_class ThunderRT6FormDC")
        if (xyHwnd)
            xyHwnd := "xyHwnd1"
    }

    return xyHwnd
}


Send_WM_COPYDATA(message) {
   xyHwnd := GetXYHWND()

   if !(xyHwnd)
       return

   size := StrLen(message)
   if !(StrLen(Chr(0xFFFF))) {
      VarSetStrCapacity(&data, size * 2, 0)
      StrPut(message, &data, size, "UTF-16")
   } else {
      data := message
   }
   VarSetStrCapacity(&COPYDATA, A_PtrSize * 3, 0)
   NumPut(4194305, COPYDATA, 0, "Ptr")
   NumPut(size * 2, COPYDATA, A_PtrSize, "UInt")
   NumPut(&data, COPYDATA, A_PtrSize * 2, "Ptr")
   result := DllCall("User32.dll\SendMessageW", "Ptr", xyHWND, "UInt", 74, "Ptr", 0, "Ptr", &COPYDATA, "Ptr")
   return
}


Receive_WM_COPYDATA(wParam, lParam) {
   global dataReceived

   stringAddress := NumGet(lParam + 2 * A_PtrSize)
   copyOfData := StrGet(stringAddress)
   cbData := NumGet(lParam + A_PtrSize) / 2
   dataReceived := StringLeft(copyOfData, cbData)

   return
}

Re: AutoHotKey script to get the path to the selected file

Posted: 25 Feb 2023 19:31
by highend
and?

Re: AutoHotKey script to get the path to the selected file

Posted: 25 Feb 2023 20:14
by Horst
And what will be the benefit using AHK v2.
Its almost incompatible with existing scripts
and you will not found many users of it which can help you.

Re: AutoHotKey script to get the path to the selected file

Posted: 26 Feb 2023 01:19
by GreetingsFromPoland
Norn wrote: 25 Feb 2023 19:20 I'm trying to convert to AHK V2. . .
hi! i have a few AHK scripts that i wrote and use with XY. i upgraded to AHKv2, but continue to compile into EXE for v1 (set the Base as v1). i did find this converter on their forums - https://github.com/mmikeww/AHK-v2-script-converter/ and used QuickConvertorV2.ahk to create v2-versions of my scripts and it worked really well for mine (not super complicated scripts).

it may help you out as well !

Re: AutoHotKey script to get the path to the selected file

Posted: 26 Feb 2023 10:05
by Norn
I knew nothing about programming, scripting before using XYplorer, I'm trying to learn more about scripting, AHK v2 looks easier to remember than v1.
i upgraded to AHKv2, but continue to compile into EXE for v1 (set the Base as v1). i did find this converter on their forums - [url wrote:https://github.com/mmikeww/AHK-v2-script-converter/[/url] and used QuickConvertorV2.ahk to create v2-versions of my scripts and it worked really well for mine (not super complicated scripts).
Yep, this helps convert the little bit I learned in v1, thanks. For this complex script it fails to convert, a lot of errors:

Code: Select all

#Requires AutoHotkey v2.0.2

; Get our own HWND (we have no visible window)
DetectHiddenWindows(true)
G_OwnHWND := WinExist("Ahk_PID " DllCall("GetCurrentProcessId"))
G_OwnHWND += 0

; Get messages back from XYplorer
OnMessage(0x4a, Receive_WM_COPYDATA)

F1::
{ ; V1toV2: Added bracket
    path := XYGetPath()
    all  := XYGetAll()
    sel  := XYGetSelected()
    MsgBox(path)
    MsgBox(all)
    MsgBox(sel)
return
} ; Added bracket before function


XYGetPath()
{
    return XY_Get()
}


XYGetAll()
{
   return XY_Get(true)
}


XYGetSelected()
{
   return XY_Get(, true)
}


XY_Get(bAll:=false, bSelection:=false)
{
    global dataReceived, G_OwnHWND

    xyQueryScript := "
    ( LTrim Join
        ::
      {
        if (!bAll && !bSelection) {
            $return = "<curpath>";
        } elseif (bAll) {
            $return = listpane(, , , "<crlf>");
        } elseif (bSelection) {
            $return = get("SelectedItemsPathNames", "<crlf>");
        }
        copydata G_OwnHWND, "$return", 2;
	  }
    )"

    Send_WM_COPYDATA(xyQueryScript)

    return dataReceived
}


GetXYHWND() {
    if WinActive("ahk_class ThunderRT6FormDC")
    {
        xyHwnd := WinGetID("ahk_class ThunderRT6FormDC")
    } else {
        oxyHwnd := WinGetList("ahk_class ThunderRT6FormDC")
        axyHwnd := Array()
        xyHwnd := oxyHwnd.Length
        For v in oxyHwnd
        {
		    axyHwnd.Push(v)
        }
        if (axyHwnd.Length)
            xyHwnd := axyHwnd[1]
    }

    return xyHwnd
}


Send_WM_COPYDATA(message) {
   xyHwnd := GetXYHWND()

   if !(xyHwnd)
       return

   size := StrLen(message)
   if !(StrLen(Chr(0xFFFF))) {
      data := Buffer(size * 2, 0) ; V1toV2: if 'data' is a UTF-16 string, use 'VarSetStrCapacity(&data, size * 2)'
      StrPut(message, &data, size, "UTF-16")
   } else {
      data := message
   }
   COPYDATA := Buffer(A_PtrSize * 3, 0) ; V1toV2: if 'COPYDATA' is a UTF-16 string, use 'VarSetStrCapacity(&COPYDATA, A_PtrSize * 3)'
   NumPut("Ptr", 4194305, COPYDATA, 0)
   NumPut("UInt", size * 2, COPYDATA, A_PtrSize)
   NumPut("Ptr", &data, COPYDATA, A_PtrSize * 2)
   result := DllCall("User32.dll\SendMessageW", "Ptr", xyHwnd, "UInt", 74, "Ptr", 0, "Ptr", COPYDATA, "Ptr")
   return
}


Receive_WM_COPYDATA(wParam, lParam) {
   global dataReceived

   stringAddress := NumGet(lParam + 2 * A_PtrSize, "UPtr")
   copyOfData := StrGet(stringAddress)
   cbData := NumGet(lParam + A_PtrSize, "UPtr") / 2
   dataReceived := SubStr(copyOfData, 1, cbData)

   return
}
I install two versions and can run two versions of the script, but for beginners like me, it seems that there is no need to continue learning the syntax of v1.

For AHK v2:

Code: Select all

#Requires AutoHotkey v2.0.2

; Get our own HWND (we have no visible window)
DetectHiddenWindows(true)
G_OwnHWND := WinExist("Ahk_PID " DllCall("GetCurrentProcessId"))
G_OwnHWND += 0


; Get messages back from XYplorer
OnMessage(0x4a, Receive_WM_COPYDATA)

global dataReceived := ""

F1::
{
    path := XYGetPath()
    all  := XYGetAll()
    sel  := XYGetSelected()
    MsgBox path
    MsgBox all
    MsgBox sel
return
}


XYGetPath()
{
    return XY_Get()
}


XYGetAll()
{
   return XY_Get(true)
}


XYGetSelected()
{
   return XY_Get(, true)
}


XY_Get(bAll:=false, bSelection:=false)
{
    xyQueryScript := '::if (!' bAll ' && !' bSelection ') {$return = "<curpath>"`;} elseif (' bAll ') {$return = listpane(, , , "<crlf>")`;} elseif (' bSelection ') {$return = get("SelectedItemsPathNames", "<crlf>")`;} copydata ' G_OwnHWND ', "$return", 2`;'

    Send_WM_COPYDATA(xyQueryScript)

    return dataReceived
}


GetXYHWND() {
	static xyClass := 'ahk_class ThunderRT6FormDC'

	if hwnd := WinActive(xyClass)
		return hwnd
	else if WinExist(xyClass)
		return WinGetList(xyClass)[1]
}


Send_WM_COPYDATA(message) {
   xyHwnd := GetXYHWND()

   if !(xyHwnd)
       return

   size := StrLen(message)
   if !(StrLen(Chr(0xFFFF))) {
      data := Buffer(size * 2, 0)
      StrPut(message, &data, size, "UTF-16")
   } else {
      data := message
   }

   COPYDATA := Buffer(A_PtrSize * 3)
   NumPut("Ptr", 4194305, COPYDATA, 0)
   NumPut("UInt", size * 2, COPYDATA, A_PtrSize)
   NumPut("Ptr", StrPtr(data), COPYDATA, A_PtrSize * 2)

   return DllCall("User32.dll\SendMessageW", "Ptr", xyHwnd, "UInt", 74, "Ptr", 0, "Ptr", COPYDATA, "Ptr")
}


Receive_WM_COPYDATA(wParam, lParam, *) {
	global dataReceived := StrGet(
		NumGet(lParam + 2 * A_PtrSize, 'Ptr'), ; COPYDATASTRUCT.lpData, ptr to a str presumably
		NumGet(lParam + A_PtrSize, 'UInt') / 2 ; COPYDATASTRUCT.cbData, count bytes of lpData, /2 to get count chars in unicode str
	)
}

Re: AutoHotKey script to get the path to the selected file

Posted: 01 Mar 2023 13:17
by elbitjusticiero
If you want to do this while the XYplorer window is active, you can just save the clipboard, send Ctrl+P, read the clipboard (it will contain the full path and filename) and restore the clipboard.

If you want to do this while the XYplorer window is not active, you can try using CtrlSend to send the Ctrl+P combo to XYplorer.

Re: AutoHotKey script to get the path to the selected file

Posted: 14 Jun 2023 22:50
by Norn
Make it work on Floating Preview.

Code: Select all

;AUTHOR   : https://www.xyplorer.com/xyfc/viewtopic.php?p=211970#p211970
;Function : XYplorer Get Selection (AHK v2)

#Requires AutoHotkey v2


; Get messages back from XYplorer
OnMessage(0x4a, Receive_WM_COPYDATA)
dataReceived := ""

F1::
{
    path := XYGetPath()
    all  := XYGetAll()
    sel  := XYGetSelected()
    MsgBox path
    MsgBox all
    MsgBox sel
return
}


XYGetPath()
{
    return XY_Get()
}


XYGetAll()
{
	return XY_Get(true)
}


XYGetSelected()
{
	return XY_Get(, true)
}


XY_Get(bAll:=false, bSelection:=false)
{
    xyQueryScript := '::if (!' bAll ' && !' bSelection ') {$return = "<curpath>"`;} elseif (' bAll ') {$return = listpane(, , , "<crlf>")`;} elseif (' bSelection ') {$return = get("SelectedItemsPathNames", "<crlf>")`;} copydata ' A_ScriptHwnd ', "$return", 2`;'

    Send_WM_COPYDATA(xyQueryScript)

    return dataReceived
}


GetXYHWND() {
    static xyClass := 'ahk_class ThunderRT6FormDC'

    if WinExist(xyClass) {
        for xyid in WinGetList(xyClass)
            if WinGetControls(xyid).length > 10                ; The Floating Preview has only a few controls
                return xyid
    }
}


Send_WM_COPYDATA(message) {
	if !xyHwnd := GetXYHWND()
	   return

	size := StrLen(message)

	COPYDATA := Buffer(A_PtrSize * 3)
	NumPut("Ptr", 4194305, COPYDATA, 0)
	NumPut("UInt", size * 2, COPYDATA, A_PtrSize)
	NumPut("Ptr", StrPtr(message), COPYDATA, A_PtrSize * 2)

	return SendMessage(0x004A, 0, COPYDATA,, xyHwnd,,,, TimeOut:=3000) ; 0x004A is WM_COPYDATA.
	;return DllCall("User32.dll\SendMessageW", "Ptr", xyHwnd, "UInt", 74, "Ptr", 0, "Ptr", COPYDATA, "Ptr")
	;return DllCall("User32.dll\SendMessageTimeout", "Ptr", xyHwnd, "UInt", 74, "Ptr", 0, "Ptr", COPYDATA, "UInt", 2, "UInt", TimeOut:=3000, "PtrP", Result:=0, "Ptr")
}


Receive_WM_COPYDATA(wParam, lParam, *) {
	global dataReceived := StrGet(
		NumGet(lParam + 2 * A_PtrSize, 'Ptr'),   ; COPYDATASTRUCT.lpData, ptr to a str presumably
		NumGet(lParam + A_PtrSize, 'UInt') / 2   ; COPYDATASTRUCT.cbData, count bytes of lpData, /2 to get count chars in unicode str
	)
}