Page 1 of 1

Set and Get Clipboard Files (Windows, MacOS)

Posted: Tue Apr 25, 2023 6:02 pm
by mk-soft
After I had the function running for MacOS, I also implemented it for Windows. Still missing for Linux ;)

Org Link: MacOS Tips & Tricks

Update v1.01.4

Code: Select all

;-TOP

; Comment : Set and Get Clipboard Files
; Author  : mk-soft
; Version : v1.01.4
; Create  : 24.04.2023
; Update  : 25.04.2023

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Windows
    ;-- Window
    
    Procedure SetClipboardFile(FileName.s)
      Protected r1, Size, len, *hGlobal, *dropfiles.DROPFILES
      len = StringByteLength(FileName) + SizeOf(Character)
      size = len + SizeOf(Character) + SizeOf(DROPFILES)
      *hGlobal = GlobalAlloc_(#GHND, size)
      If *hGlobal
        *dropfiles = GlobalLock_(*hGlobal)
        If *dropfiles
          *dropfiles\pFiles = SizeOf(DROPFILES)
          *dropfiles\fNC = #False
          *dropfiles\fWide = #True
          PokeS(*dropfiles + SizeOf(DROPFILES), FileName)
          GlobalUnlock_(*dropfiles)
          If OpenClipboard_(0)
            r1 = SetClipboardData_(#CF_HDROP, *hGlobal)
            CloseClipboard_()
          EndIf
        EndIf
        GlobalFree_(*hGlobal)
      EndIf
      ProcedureReturn r1
    EndProcedure
    
    Procedure SetClipboardFiles(List Files.s())
      Protected r1, Size, len, *hGlobal, *dropfiles.DROPFILES, *ofs
      
      ForEach Files()
        len + StringByteLength(Files()) + SizeOf(Character)
      Next
      size = len + SizeOf(Character) + SizeOf(DROPFILES)
      *hGlobal = GlobalAlloc_(#GHND, size)
      If *hGlobal
        *dropfiles = GlobalLock_(*hGlobal)
        If *dropfiles
          *dropfiles\pFiles = SizeOf(DROPFILES)
          *dropfiles\fNC = #False
          *dropfiles\fWide = #True
          *ofs = *dropfiles + SizeOf(DROPFILES)
          ForEach Files()
            PokeS(*ofs, Files())
            *ofs + StringByteLength(Files()) + SizeOf(Character)
          Next
          GlobalUnlock_(*dropfiles)
          If OpenClipboard_(0)
            r1 = SetClipboardData_(#CF_HDROP, *hGlobal)
            CloseClipboard_()
          EndIf
        EndIf
        GlobalFree_(*hGlobal)
      EndIf
      ProcedureReturn r1
    EndProcedure
    
    Procedure GetClipboardFiles(List Files.s())
      Protected cnt, *hGlobal, *dropfiles.DROPFILES, *ofs1.Character, *ofs2.ascii
      
      ClearList(Files())
      
      If IsClipboardFormatAvailable_(#CF_HDROP)
        If OpenClipboard_(0)
          *hGlobal = GetClipboardData_(#CF_HDROP)
          If *hGlobal
            *dropfiles = GlobalLock_(*hGlobal)
            If *dropfiles\fWide
              *ofs1 = *dropfiles + *dropfiles\pFiles
              While *ofs1\c
                AddElement(Files())
                Files() = PeekS(*ofs1)
                *ofs1 + StringByteLength(Files()) + SizeOf(Character)
              Wend
            Else
              *ofs2 = *dropfiles + *dropfiles\pFiles
              While *ofs2\a
                AddElement(Files())
                Files() = PeekS(*ofs2, -1, #PB_Ascii)
                *ofs2 + StringByteLength(Files(), #PB_Ascii) + SizeOf(Ascii)
              Wend
            EndIf
            GlobalUnlock_(*dropfiles)
            GlobalFree_(*hGlobal)
            cnt = ListSize(Files())
          EndIf
          CloseClipboard_()
        EndIf
      EndIf
      
      ProcedureReturn cnt
    EndProcedure
    
  CompilerCase #PB_OS_Linux
    ;-- Linux TODO
    
  CompilerCase #PB_OS_MacOS
    ;-- macOS
    
    Macro CocoaString(NSString)
      PeekS(CocoaMessage(0, NSString, "UTF8String"), -1, #PB_UTF8)
    EndMacro
    
    Procedure SetClipboardFile(FileName.s)
      Protected r1, pool, fileURL, objectsToCopy, pasteboard
      
      pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
      
      fileURL = CocoaMessage(0, 0, "NSURL fileURLWithPath:$", @FileName)
      objectsToCopy = CocoaMessage(0, 0, "NSArray arrayWithObject:", fileURL)
      pasteboard = CocoaMessage(0, 0, "NSPasteboard generalPasteboard")
      CocoaMessage(0, pasteboard, "clearContents")
      r1 = CocoaMessage(0, pasteboard, "writeObjects:", objectsToCopy)
      
      CocoaMessage(0, pool, "release")
      
      ProcedureReturn r1
    EndProcedure
    
    Procedure SetClipboardFiles(List Files.s())
      Protected r1, pool, fileURL, objectsToCopy, pasteboard, filename.s, cnt
      
      pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
      
      cnt = ListSize(Files())
      objectsToCopy = CocoaMessage(0, 0, "NSMutableArray arrayWithCapacity:", cnt)
      ForEach Files()
        filename = Files()
        fileURL = CocoaMessage(0, 0, "NSURL fileURLWithPath:$", @filename)
        CocoaMessage(0, objectsToCopy, "addObject:", fileURL)
      Next
      pasteboard = CocoaMessage(0, 0, "NSPasteboard generalPasteboard")
      CocoaMessage(0, pasteboard, "clearContents")
      r1 = CocoaMessage(0, pasteboard, "writeObjects:", objectsToCopy)
      
      CocoaMessage(0, pool, "release")
      
      ProcedureReturn r1
    EndProcedure
    
    Procedure GetClipboardFiles(List Files.s())
      Protected pool, number, dictionary, classURL, arrayObjects, pasteboard, urls, fileURL, string, cnt, index
      
      ClearList(Files())
      
      pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
      
      number = CocoaMessage(0, 0, "NSNumber numberWithBool:", #True)
      dictionary = CocoaMessage(0, 0, "NSDictionary dictionaryWithObject:", number, "forKey:$", @"NSPasteboardURLReadingFileURLsOnlyKey")
      classURL = CocoaMessage(0, 0, "NSURL class")
      arrayObjects = CocoaMessage(0, 0, "NSArray arrayWithObject:", classURL)
      pasteboard = CocoaMessage(0, 0, "NSPasteboard generalPasteboard")
      urls = CocoaMessage(0, pasteboard, "readObjectsForClasses:", arrayObjects, "options:", dictionary)
      
      cnt = CocoaMessage(0, urls, "count")
      If cnt >= 1
        For index = 0 To cnt - 1
          fileURL = CocoaMessage(0, urls, "objectAtIndex:", index)
          string = CocoaMessage(0, fileURL, "path")
          AddElement(Files())
          Files() = CocoaString(string)
        Next
      EndIf
      
      CocoaMessage(0, pool, "release")
      
      ProcedureReturn cnt
    EndProcedure
    
CompilerEndSelect

; ****

CompilerIf #PB_Compiler_IsMainFile
  ;-- Examples
  
  #example = 3
  
  CompilerIf #example = 1
    
    filename.s = OpenFileRequester("", "", "", 0)
    If filename
      r1 = SetClipboardFile(filename)
      If r1 
        Debug "Ok"
      Else
        Debug "False"
      EndIf
    EndIf
    
  CompilerElseIf #example = 2
    
    Global NewList FileList.s()
    
    filename.s = OpenFileRequester("", "", "", 0, #PB_Requester_MultiSelection)
    While filename
      AddElement(FileList())
      FileList() = filename
      filename = NextSelectedFileName()
    Wend
    
    If FileSize(FileList())
      r1 = SetClipboardFiles(FileList())
      If r1 
        Debug "Ok"
      Else
        Debug "False"
      EndIf
    EndIf
  CompilerElseIf #example = 3
    
    Global NewList FileList.s()
    
    If GetClipboardFiles(FileList())
      ForEach FileList()
        Debug FileList()
      Next
    Else
      Debug "No Clipboard Files"
    EndIf
  CompilerEndIf
  
CompilerEndIf

Re: Set and Get Clipboard Files (Windows, MacOS)

Posted: Tue Apr 25, 2023 8:07 pm
by Caronte3D
Thank you very much! :D

Re: Set and Get Clipboard Files (Windows, MacOS)

Posted: Sun Apr 30, 2023 6:46 pm
by Kwai chang caine
That works here, i have the full path of the file and OK when i use #example = 1 or 2
Appaently your nice code only copy the path, not the object here
Because if i right clic, i not have PASTE in the pop menu
Thanks for sharing 8)

Re: Set and Get Clipboard Files (Windows, MacOS)

Posted: Sun Apr 30, 2023 7:01 pm
by Caronte3D
Kwai chang caine wrote: Sun Apr 30, 2023 6:46 pm Appaently your nice code only copy the path, not the object here
Because if i right clic, i not have PASTE in the pop menu
Ups! That's true :?

Re: Set and Get Clipboard Files (Windows, MacOS)

Posted: Sun Apr 30, 2023 7:40 pm
by mk-soft
That is correct,

but pasting in the "Finder" with fileURL's in the clipboard works correctly. The Finder then copies these files.
In your app you also only get the fileURLs. What you do with them is up to you ;)

Re: Set and Get Clipboard Files (Windows, MacOS)

Posted: Sun Apr 30, 2023 8:04 pm
by Kwai chang caine
For me it's W10, but it's the same thing i imagine ...
Ok no problem, if it's the good behavior :wink:
Again thanks for all your great shared codes 8)

Re: Set and Get Clipboard Files (Windows, MacOS)

Posted: Sun Apr 30, 2023 8:41 pm
by Caronte3D
mk-soft wrote: Sun Apr 30, 2023 7:40 pm That is correct,

but pasting in the "Finder" with fileURL's in the clipboard works correctly. The Finder then copies these files.
In your app you also only get the fileURLs. What you do with them is up to you ;)
But... If I was copy a file from my program to the clipboard, I expect to be able to do Ctrl+V to a folder on the windows file browser :?
It's not possible?

Re: Set and Get Clipboard Files (Windows, MacOS)

Posted: Sun Apr 30, 2023 9:17 pm
by mk-soft
It works here. Example 2.

- So select files with OpneFileRequester.
- Open Windows File Explorer
- Ctrl + v

Windows Explorer will also copy these files

Re: Set and Get Clipboard Files (Windows, MacOS)

Posted: Sun Apr 30, 2023 9:58 pm
by Caronte3D
Oh! Yea! Sorry, my mistake. Works nice! :D

Re: Set and Get Clipboard Files (Windows, MacOS)

Posted: Mon May 01, 2023 6:19 pm
by Kwai chang caine
I have found the probleme here (Thanks to RASHAD) because several of his code not works too on my PC :wink:
I have not actived option "Visual XP" on compiler option
Thanks for this very nice code 8)