[solved] How to copy the most recently modified file in a certain directory to the clipboard Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
GEV
Posts: 1002
Joined: 25 Feb 2014, 00:50

[solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by GEV » 26 Dec 2015, 03:46

Code: Select all

; Retrieve file names in a certain directory sorted by modification date:
FileList =  ; Initialize to be blank
Loop, %A_MyDocuments%\*.*
; create a list of those files consisting of the time the file was modified and the file name separated by tab
FileList = %FileList%%A_LoopFileTimeModified%`t%A_LoopFileName%`n
Sort, FileList, R  ;   ; Sort by time modified in reverse order
Loop, parse, FileList, `n
{
    if A_LoopField =  ; omit the last linefeed (blank item) at the end of the list.
        continue
    StringSplit, FileItem, A_LoopField, %A_Tab%  ; Split into two parts at the tab char
     ; FileItem1 is FileTimeModified und FileItem2 is FileName
	 MsgBox, %A_MyDocuments%\%FileItem2%
	; FileToClipboard("%A_MyDocuments%\%FileItem2%")		; doesn't work
	; FileToClipboard(%A_MyDocuments%\FileItem2, "")	; doesn't work
		break
}
return

; https://autohotkey.com/board/topic/23162-how-to-copy-a-file-to-the-clipboard/#entry149937
FileToClipboard(PathToCopy)
{
    ; Expand to full path:
    Loop, %PathToCopy%, 1
        PathToCopy := A_LoopFileLongPath    
    ; Allocate some movable memory to put on the clipboard.
    ; This will hold a DROPFILES struct, the string, and an (extra) null terminator
    ; 0x42 = GMEM_MOVEABLE(0x2) | GMEM_ZEROINIT(0x40)
    hPath := DllCall("GlobalAlloc","uint",0x42,"uint",StrLen(PathToCopy)+22)   
    ; Lock the moveable memory, retrieving a pointer to it.
    pPath := DllCall("GlobalLock","uint",hPath)    
    NumPut(20, pPath+0) ; DROPFILES.pFiles = offset of file list    
    ; Copy the string into moveable memory.
    DllCall("lstrcpy","uint",pPath+20,"str",PathToCopy)    
    ; Unlock the moveable memory.
    DllCall("GlobalUnlock","uint",hPath)    
    DllCall("OpenClipboard","uint",0)
    ; Empty the clipboard, otherwise SetClipboardData may fail.
    DllCall("EmptyClipboard")
    ; Place the data on the clipboard. CF_HDROP=0xF
    DllCall("SetClipboardData","uint",0xF,"uint",hPath)
    DllCall("CloseClipboard")
}
Any ideas?
Last edited by GEV on 28 Dec 2015, 13:11, edited 1 time in total.

just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to copy the most recently modified file in a certain directory to the clipboard

Post by just me » 26 Dec 2015, 04:03

Function calls are expressions:

Code: Select all

; FileToClipboard("%A_MyDocuments%\%FileItem2%")		; doesn't work <<<<< in v1.1 but might work in v2
FileToClipboard(A_MyDocuments . "\" . FileItem2)	
?

:xmas:

GEV
Posts: 1002
Joined: 25 Feb 2014, 00:50

Re: How to copy the most recently modified file in a certain directory to the clipboard

Post by GEV » 26 Dec 2015, 04:23

Thanks, but it doesn't seem to work for me.

just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to copy the most recently modified file in a certain directory to the clipboard

Post by just me » 26 Dec 2015, 05:31

What do you want to do with the file after copying it to the clipboard?

GEV
Posts: 1002
Joined: 25 Feb 2014, 00:50

Re: How to copy the most recently modified file in a certain directory to the clipboard

Post by GEV » 26 Dec 2015, 05:50

I often take screenshots and share them with friends in a social network after pasting the last picture via Ctrl+V in a dialog.
Last edited by GEV on 26 Dec 2015, 06:16, edited 1 time in total.

just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to copy the most recently modified file in a certain directory to the clipboard  Topic is solved

Post by just me » 26 Dec 2015, 05:52

OK, try this one:

Code: Select all

#NoEnv
; Retrieve files in a certain directory sorted by modification date:
FileList :=  "" ; Initialize to be blank
; Create a list of those files consisting of the time the file was modified and the file path separated by tab
Loop, %A_MyDocuments%\*.*
   FileList .= A_LoopFileTimeModified . "`t" . A_LoopFileLongPath . "`n"
Sort, FileList, R  ;   ; Sort by time modified in reverse order
Loop, Parse, FileList, `n
{
   If (A_LoopField = "") ; omit the last linefeed (blank item) at the end of the list.
      Continue
   StringSplit, FileItem, A_LoopField, %A_Tab%  ; Split into two parts at the tab char
   ; FileItem1 is FileTimeModified und FileItem2 is FileName
   MsgBox, 36, Last modified file, %FileItem1% - %FileItem2%`n`nDo you want to continue?
   IfMsgBox, Yes
      ClipBoardSetFiles(FileItem2)
   Break
}
ExitApp

ClipboardSetFiles(FilesToSet, DropEffect := "Copy") {
   ; FilesToSet - list of fully qualified file pathes separated by "`n" or "`r`n"
   ; DropEffect - preferred drop effect, either "Copy", "Move" or "" (empty string)
   Static TCS := A_IsUnicode ? 2 : 1 ; size of a TCHAR
   Static PreferredDropEffect := DllCall("RegisterClipboardFormat", "Str", "Preferred DropEffect")
   Static DropEffects := {1: 1, 2: 2, Copy: 1, Move: 2}
   ; -------------------------------------------------------------------------------------------------------------------
   ; Count files and total string length
   TotalLength := 0
   FileArray := []
   Loop, Parse, FilesToSet, `n, `r
   {
      If (Length := StrLen(A_LoopField))
         FileArray.Push({Path: A_LoopField, Len: Length + 1})
      TotalLength += Length
   }
   FileCount := FileArray.Length()
   If !(FileCount && TotalLength)
      Return False
   ; -------------------------------------------------------------------------------------------------------------------
   ; Add files to the clipboard
   If DllCall("OpenClipboard", "Ptr", A_ScriptHwnd) && DllCall("EmptyClipboard") {
      ; HDROP format ---------------------------------------------------------------------------------------------------
      ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
      hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 20 + (TotalLength + FileCount + 1) * TCS, "UPtr")
      pDrop := DllCall("GlobalLock", "Ptr" , hDrop)
      Offset := 20
      NumPut(Offset, pDrop + 0, "UInt")         ; DROPFILES.pFiles = offset of file list
      NumPut(!!A_IsUnicode, pDrop + 16, "UInt") ; DROPFILES.fWide = 0 --> ANSI, fWide = 1 --> Unicode
      For Each, File In FileArray
         Offset += StrPut(File.Path, pDrop + Offset, File.Len) * TCS
      DllCall("GlobalUnlock", "Ptr", hDrop)
      DllCall("SetClipboardData","UInt", 0x0F, "UPtr", hDrop) ; 0x0F = CF_HDROP
      ; Preferred DropEffect format ------------------------------------------------------------------------------------
      If (DropEffect := DropEffects[DropEffect]) {
         ; Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
         ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
         hMem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "UPtr")
         pMem := DllCall("GlobalLock", "Ptr", hMem)
         NumPut(DropEffect, pMem + 0, "UChar")
         DllCall("GlobalUnlock", "Ptr", hMem)
         DllCall("SetClipboardData", "UInt", PreferredDropEffect, "Ptr", hMem)
      }
      DllCall("CloseClipboard")
      Return True
   }
   Return False
}

GEV
Posts: 1002
Joined: 25 Feb 2014, 00:50

Re: How to copy the most recently modified file in a certain directory to the clipboard

Post by GEV » 26 Dec 2015, 05:59

Thanks a lot! Works a treat.

joexcm
Posts: 7
Joined: 24 Jan 2023, 14:25

Re: How to copy the most recently modified file in a certain directory to the clipboard

Post by joexcm » 26 Jan 2023, 11:57

just me wrote:
26 Dec 2015, 05:52
OK, try this one:

Code: Select all

#NoEnv
; Retrieve files in a certain directory sorted by modification date:
FileList :=  "" ; Initialize to be blank
; Create a list of those files consisting of the time the file was modified and the file path separated by tab
Loop, %A_MyDocuments%\*.*
   FileList .= A_LoopFileTimeModified . "`t" . A_LoopFileLongPath . "`n"
Sort, FileList, R  ;   ; Sort by time modified in reverse order
Loop, Parse, FileList, `n
{
   If (A_LoopField = "") ; omit the last linefeed (blank item) at the end of the list.
      Continue
   StringSplit, FileItem, A_LoopField, %A_Tab%  ; Split into two parts at the tab char
   ; FileItem1 is FileTimeModified und FileItem2 is FileName
   MsgBox, 36, Last modified file, %FileItem1% - %FileItem2%`n`nDo you want to continue?
   IfMsgBox, Yes
      ClipBoardSetFiles(FileItem2)
   Break
}
ExitApp

ClipboardSetFiles(FilesToSet, DropEffect := "Copy") {
   ; FilesToSet - list of fully qualified file pathes separated by "`n" or "`r`n"
   ; DropEffect - preferred drop effect, either "Copy", "Move" or "" (empty string)
   Static TCS := A_IsUnicode ? 2 : 1 ; size of a TCHAR
   Static PreferredDropEffect := DllCall("RegisterClipboardFormat", "Str", "Preferred DropEffect")
   Static DropEffects := {1: 1, 2: 2, Copy: 1, Move: 2}
   ; -------------------------------------------------------------------------------------------------------------------
   ; Count files and total string length
   TotalLength := 0
   FileArray := []
   Loop, Parse, FilesToSet, `n, `r
   {
      If (Length := StrLen(A_LoopField))
         FileArray.Push({Path: A_LoopField, Len: Length + 1})
      TotalLength += Length
   }
   FileCount := FileArray.Length()
   If !(FileCount && TotalLength)
      Return False
   ; -------------------------------------------------------------------------------------------------------------------
   ; Add files to the clipboard
   If DllCall("OpenClipboard", "Ptr", A_ScriptHwnd) && DllCall("EmptyClipboard") {
      ; HDROP format ---------------------------------------------------------------------------------------------------
      ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
      hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 20 + (TotalLength + FileCount + 1) * TCS, "UPtr")
      pDrop := DllCall("GlobalLock", "Ptr" , hDrop)
      Offset := 20
      NumPut(Offset, pDrop + 0, "UInt")         ; DROPFILES.pFiles = offset of file list
      NumPut(!!A_IsUnicode, pDrop + 16, "UInt") ; DROPFILES.fWide = 0 --> ANSI, fWide = 1 --> Unicode
      For Each, File In FileArray
         Offset += StrPut(File.Path, pDrop + Offset, File.Len) * TCS
      DllCall("GlobalUnlock", "Ptr", hDrop)
      DllCall("SetClipboardData","UInt", 0x0F, "UPtr", hDrop) ; 0x0F = CF_HDROP
      ; Preferred DropEffect format ------------------------------------------------------------------------------------
      If (DropEffect := DropEffects[DropEffect]) {
         ; Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
         ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
         hMem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "UPtr")
         pMem := DllCall("GlobalLock", "Ptr", hMem)
         NumPut(DropEffect, pMem + 0, "UChar")
         DllCall("GlobalUnlock", "Ptr", hMem)
         DllCall("SetClipboardData", "UInt", PreferredDropEffect, "Ptr", hMem)
      }
      DllCall("CloseClipboard")
      Return True
   }
   Return False
}
Hi @just me, thanks so much for this script. I'm trying to use it to copy and paste plugins into my music software via hotkeys (to save time) but I'm having problems.
I've got two shortcuts for plugin 1 and plugin 2 but after the first time ClipBoardSetFiles is used, either shortcut is just pasting the same thing - i.e. the ClipBoardSetFiles doesn't seem to be working any more and it's just the Send, ^v which is working. Sometimes it doesn't seem to work at all or there's a long delay before it starts working too which feels related.
FYI I deleted the sorting aspect of your original script so there's a chance I deleted something important there. The Sleep 1000 and Clipboard:= are just attempts to get it to work but they don't serve any other purpose or help.

Any help you can give would be really appreciated.

Thanks,
Joe

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetTitleMatchMode, 2


ClipboardSetFiles(FilesToSet, DropEffect := "Copy") {
   ; FilesToSet - list of fully qualified file pathes separated by "`n" or "`r`n"
   ; DropEffect - preferred drop effect, either "Copy", "Move" or "" (empty string)
   Static TCS := A_IsUnicode ? 2 : 1 ; size of a TCHAR
   Static PreferredDropEffect := DllCall("RegisterClipboardFormat", "Str", "Preferred DropEffect")
   Static DropEffects := {1: 1, 2: 2, Copy: 1, Move: 2}
   ; -------------------------------------------------------------------------------------------------------------------
   ; Count files and total string length
   TotalLength := 0
   FileArray := []
   Loop, Parse, FilesToSet, `n, `r
   {
      If (Length := StrLen(A_LoopField))
         FileArray.Push({Path: A_LoopField, Len: Length + 1})
      TotalLength += Length
   }
   FileCount := FileArray.Length()
   If !(FileCount && TotalLength)
      Return False
   ; -------------------------------------------------------------------------------------------------------------------
   ; Add files to the clipboard
   If DllCall("OpenClipboard", "Ptr", A_ScriptHwnd) && DllCall("EmptyClipboard") {
      ; HDROP format ---------------------------------------------------------------------------------------------------
      ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
      hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 20 + (TotalLength + FileCount + 1) * TCS, "UPtr")
      pDrop := DllCall("GlobalLock", "Ptr" , hDrop)
      Offset := 20
      NumPut(Offset, pDrop + 0, "UInt")         ; DROPFILES.pFiles = offset of file list
      NumPut(!!A_IsUnicode, pDrop + 16, "UInt") ; DROPFILES.fWide = 0 --> ANSI, fWide = 1 --> Unicode
      For Each, File In FileArray
         Offset += StrPut(File.Path, pDrop + Offset, File.Len) * TCS
      DllCall("GlobalUnlock", "Ptr", hDrop)
      DllCall("SetClipboardData","UInt", 0x0F, "UPtr", hDrop) ; 0x0F = CF_HDROP
      ; Preferred DropEffect format ------------------------------------------------------------------------------------
      If (DropEffect := DropEffects[DropEffect]) {
         ; Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
         ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
         hMem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "UPtr")
         pMem := DllCall("GlobalLock", "Ptr", hMem)
         NumPut(DropEffect, pMem + 0, "UChar")
         DllCall("GlobalUnlock", "Ptr", hMem)
         DllCall("SetClipboardData", "UInt", PreferredDropEffect, "Ptr", hMem)
      }
      DllCall("CloseClipboard")
      Return True
   }
   Return False
}

#IfWinActive, Ableton Live 10 Suite
+q::
ClipBoardSetFiles("J:\Documents\Ableton\User Library\AutoHotKey presets\Pro-Q 3.vstpreset", "Copy")
Sleep 1000
Send, ^v
Clipboard:=
Return

+a::
ClipBoardSetFiles("J:\Documents\Ableton\User Library\AutoHotKey presets\Audio Rack - DryWet.adg", "Copy")
Sleep 1000
Send, ^v
Clipboard:=
Return

just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by just me » 27 Jan 2023, 05:04

@joexcm,

I don't see any errors in the code which might cause the issue.

Check the value returned by ClipboardSetFiles(). If it is 0 (false) something went wrong:

Code: Select all

+q::
If !ClipBoardSetFiles("J:\Documents\Ableton\User Library\AutoHotKey presets\Pro-Q 3.vstpreset", "Copy")
	MsgBox, 16, Error!, A_LastError: %A_LastError%

You can also try to change the following line

Code: Select all

   If DllCall("OpenClipboard", "Ptr", A_ScriptHwnd) && DllCall("EmptyClipboard") {
to

Code: Select all

   If DllCall("OpenClipboard", "Ptr", 0) && DllCall("EmptyClipboard") {

Give Ableton some time to process the clipboard data before you paste again.

joexcm
Posts: 7
Joined: 24 Jan 2023, 14:25

Re: [solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by joexcm » 27 Jan 2023, 07:03

Hi @just me, thanks for the reply.

For the error checking, would that be

Code: Select all

+q::
If !ClipBoardSetFiles("J:\Documents\Ableton\User Library\AutoHotKey presets\Pro-Q 3.vstpreset", "Copy")
	MsgBox, 16, Error!, A_LastError: %A_LastError%
ClipBoardSetFiles("J:\Documents\Ableton\User Library\AutoHotKey presets\Pro-Q 3.vstpreset", "Copy")
Send, ^v
Return
If so, no message box came up. In the console, it looks like this.

Code: Select all

Script lines most recently executed (oldest first).  Press [F5] to refresh.  The seconds elapsed between a line and the one after it is in parentheses to the right (if not 0).  The bottommost line's elapsed time is the number of seconds since it executed.

---- C:\Users\Joe\Desktop\Autohotkey scripts\Copy paste 4 27.01.23.ahk
009: TCS := A_IsUnicode ? 2 : 1
010: PreferredDropEffect := DllCall("RegisterClipboardFormat", "Str", "Preferred DropEffect")
011: DropEffects := {1: 1, 2: 2, Copy: 1, Move: 2}
003: SendMode,Input
006: {
055: Return (10.45)
056: if !ClipBoardSetFiles("J:\Documents\Ableton\User Library\AutoHotKey presets\Pro-Q 3.vstpreset", "Copy")  
014: TotalLength := 0
015: FileArray := []
016: Loop,Parse,FilesToSet,
,

018: if (Length := StrLen(A_LoopField))  
019: FileArray.Push({Path: A_LoopField, Len: Length + 1})  
020: TotalLength += Length
021: }
022: FileCount := FileArray.Length()
023: if !(FileCount && TotalLength)  
027: if DllCall("OpenClipboard", "Ptr", 0) && DllCall("EmptyClipboard")  
030: hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 20 + (TotalLength + FileCount + 1) * TCS, "UPtr")
031: pDrop := DllCall("GlobalLock", "Ptr" , hDrop)
032: Offset := 20
033: NumPut(Offset, pDrop + 0, "UInt")  
034: NumPut(!!A_IsUnicode, pDrop + 16, "UInt")  
035: For Each,File in FileArray
036: Offset += StrPut(File.Path, pDrop + Offset, File.Len) * TCS
037: DllCall("GlobalUnlock", "Ptr", hDrop)  
038: DllCall("SetClipboardData","UInt", 0x0F, "UPtr", hDrop)  
040: if (DropEffect := DropEffects[DropEffect])  
043: hMem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "UPtr")
044: pMem := DllCall("GlobalLock", "Ptr", hMem)
045: NumPut(DropEffect, pMem + 0, "UChar")  
046: DllCall("GlobalUnlock", "Ptr", hMem)  
047: DllCall("SetClipboardData", "UInt", PreferredDropEffect, "Ptr", hMem)  
048: }
049: DllCall("CloseClipboard")  
050: Return,True
058: ClipBoardSetFiles("J:\Documents\Ableton\User Library\AutoHotKey presets\Pro-Q 3.vstpreset", "Copy")  
014: TotalLength := 0
015: FileArray := []
016: Loop,Parse,FilesToSet,
,

018: if (Length := StrLen(A_LoopField))  
019: FileArray.Push({Path: A_LoopField, Len: Length + 1})  
020: TotalLength += Length
021: }
022: FileCount := FileArray.Length()
023: if !(FileCount && TotalLength)  
027: if DllCall("OpenClipboard", "Ptr", 0) && DllCall("EmptyClipboard")  
030: hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 20 + (TotalLength + FileCount + 1) * TCS, "UPtr")
031: pDrop := DllCall("GlobalLock", "Ptr" , hDrop)
032: Offset := 20
033: NumPut(Offset, pDrop + 0, "UInt")  
034: NumPut(!!A_IsUnicode, pDrop + 16, "UInt")  
035: For Each,File in FileArray
036: Offset += StrPut(File.Path, pDrop + Offset, File.Len) * TCS
037: DllCall("GlobalUnlock", "Ptr", hDrop)  
038: DllCall("SetClipboardData","UInt", 0x0F, "UPtr", hDrop)  
040: if (DropEffect := DropEffects[DropEffect])  
043: hMem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "UPtr")
044: pMem := DllCall("GlobalLock", "Ptr", hMem)
045: NumPut(DropEffect, pMem + 0, "UChar")  
046: DllCall("GlobalUnlock", "Ptr", hMem)  
047: DllCall("SetClipboardData", "UInt", PreferredDropEffect, "Ptr", hMem)  
048: }
049: DllCall("CloseClipboard")  
050: Return,True
059: Send,^v
060: Return (3.16)

Press [F5] to refresh.
The line change didn't have an effect either. I've spent some more time troubleshooting and the script works perfectly in Explorer, so I think Ableton must be handling the clipboard in an unusual way.
When using the script, I can see in Free Clipboard Viewer that the correct plugin has being copied, but nothing happens in Ableton unless I ctrl-C a plugin within the program. If that's happened then the script just pastes that same plugin (i.e. the Send ^v part is all that's registering), ignoring the new files that the script should be replacing them with.

Thanks again, really appreciate it. I'd love this to work!

just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by just me » 27 Jan 2023, 11:00

@joexcm, if possible you could try to check with the Free Clipboard Viewer whether Ableton stores some additional/other clipboard formats.

joexcm
Posts: 7
Joined: 24 Jan 2023, 14:25

Re: [solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by joexcm » 30 Jan 2023, 10:51

Ok so very interesting.
If I copy the plugin preset within Ableton (technically it's a preset file for the plugin as you can't paste the plugin itself) it doesn't register on the system clipboard at all but I can paste it onto a track - so there's some kind of internal Ableton clipboard system.
Whereas if I copy the preset in Explorer, it does appear on the clipboard and can also be pasted onto a track.

Having compared the two clipboards in Free Clipboard Viewer, what's on the clipboard from the autohotkey script is much smaller than a manual ctrl-c, so I wonder if Ableton is relying on some of the additional information that's currently not being stored? I couldn't attach the files so here's a Drive folder - https://drive.google.com/drive/folders/1xJTv0pS2csKBXp51138UHTGeL4VKUsxQ?usp=sharing admins please let me know if this isn't allowed/how else to upload weird clipboard files.

joexcm
Posts: 7
Joined: 24 Jan 2023, 14:25

Re: [solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by joexcm » 04 Feb 2023, 10:40

Hi @just me, you wouldn't know how to also copy these other clipboard parameters would you?
Thanks for all your help.

just me
Posts: 9425
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by just me » 05 Feb 2023, 07:08

Would you please provide the IDs/names of found clipboard formats here as text?
I don't have much hope that I can do it.

joexcm
Posts: 7
Joined: 24 Jan 2023, 14:25

Re: [solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by joexcm » 05 Feb 2023, 16:05

Hi just me, thanks for your reply. If I've got the right idea, the ones I get from your script are:
"Preview, List of Files, Preferred DropEffect".

With a manual copy I get:
"Preview, List of Files, DataObject, ShellIDList Array, DataObjectAttributes, DataObjectAttributesRequiringElevation, Shell Object Offsets, Preferred DropEffect, AsyncFlag, FileName, FileContents (empty), FileNameW,FileGroupDescriptorW, Ole Private Data"

I imagine it's not all of those parameters that need copying in order for Ableton to understand but it's knowing which one it's looking for... Thanks.

william_ahk
Posts: 482
Joined: 03 Dec 2018, 20:02

Re: [solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by william_ahk » 27 Feb 2023, 23:23

Hey @just me, I got a similar problem where the application won't recognize the clipboard files with only CF_HDROP. I fixed it by putting CF_FILENAME in addition. Please revise this cuz I don't know anything about C++ :D . Also hope you can release your function in the Script and Libraries section, it's really useful.

Code: Select all

ClipboardSetFiles(FilesToSet, DropEffect := "Copy") {
   ; FilesToSet - list of fully qualified file pathes separated by "`n" or "`r`n"
   ; DropEffect - preferred drop effect, either "Copy", "Move" or "" (empty string)
   Static TCS := A_IsUnicode ? 2 : 1 ; size of a TCHAR
   Static PreferredDropEffect := DllCall("RegisterClipboardFormat", "Str", "Preferred DropEffect")
   Static DropEffects := {1: 1, 2: 2, Copy: 1, Move: 2}
   ; -------------------------------------------------------------------------------------------------------------------
   ; Count files and total string length
   TotalLength := 0
   FileArray := []
   Loop, Parse, FilesToSet, `n, `r
   {
      If (Length := StrLen(A_LoopField))
         FileArray.Push({Path: A_LoopField, Len: Length + 1})
      TotalLength += Length
   }
   FileCount := FileArray.Length()
   If !(FileCount && TotalLength)
      Return False
   ; -------------------------------------------------------------------------------------------------------------------
   ; Add files to the clipboard
   If DllCall("OpenClipboard", "Ptr", A_ScriptHwnd) && DllCall("EmptyClipboard") {
      ; HDROP format ---------------------------------------------------------------------------------------------------
      ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
      hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 20 + (TotalLength + FileCount + 1) * TCS, "UPtr")
      pDrop := DllCall("GlobalLock", "Ptr" , hDrop)
      Offset := 20
      NumPut(Offset, pDrop + 0, "UInt")         ; DROPFILES.pFiles = offset of file list
      NumPut(!!A_IsUnicode, pDrop + 16, "UInt") ; DROPFILES.fWide = 0 --> ANSI, fWide = 1 --> Unicode
      For Each, File In FileArray
         Offset += StrPut(File.Path, pDrop + Offset, File.Len) * TCS
      DllCall("GlobalUnlock", "Ptr", hDrop)
      DllCall("SetClipboardData","UInt", 0x0F, "UPtr", hDrop) ; 0x0F = CF_HDROP
      
      File := FileArray[1]

      VarSetCapacity(ShortPath, 260)
      ShortLength := DllCall("GetShortPathName", "Str", File.Path, "Str", ShortPath, "Uint", 260)
      hName := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", ShortLength + 1, "UPtr")
      pName := DllCall("GlobalLock", "Ptr", hName)
      StrPut(ShortPath, pName, ShortLength, "CP0")
      DllCall("GlobalUnlock", "Ptr", hName)
      DllCall("SetClipboardData", "UInt", 0xC006, "Ptr", hName) ; 0xC006 = CF_FILENAME

      hNameW := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", File.Len * TCS, "UPtr")
      pNameW := DllCall("GlobalLock", "Ptr", hNameW)
      StrPut(File.Path, pNameW, File.Len * TCS)
      DllCall("GlobalUnlock", "Ptr", hNameW)
      DllCall("SetClipboardData", "UInt", 0xC007, "Ptr", hNameW) ; 0xC007 = CF_FILENAMEW

      ; Preferred DropEffect format ------------------------------------------------------------------------------------
      If (DropEffect := DropEffects[DropEffect]) {
         ; Write Preferred DropEffect structure to clipboard to switch between copy/cut operations
         ; 0x42 = GMEM_MOVEABLE (0x02) | GMEM_ZEROINIT (0x40)
         hMem := DllCall("GlobalAlloc", "UInt", 0x42, "UInt", 4, "UPtr")
         pMem := DllCall("GlobalLock", "Ptr", hMem)
         NumPut(DropEffect, pMem + 0, "UChar")
         DllCall("GlobalUnlock", "Ptr", hMem)
         DllCall("SetClipboardData", "UInt", PreferredDropEffect, "Ptr", hMem)
      }
      DllCall("CloseClipboard")
      Return True
   }
   Return False
}

joexcm
Posts: 7
Joined: 24 Jan 2023, 14:25

Re: [solved] How to copy the most recently modified file in a certain directory to the clipboard

Post by joexcm » 28 Feb 2023, 05:11

Damn I had my hopes up there — still not working for me :/ Glad you got it working for you though!

Post Reply

Return to “Ask for Help (v1)”