1. Christopher Craft
  2. PowerBuilder
  3. Wednesday, 10 July 2024 00:34 AM UTC

PB 2022

I am writing code to support Copy/Paste of Files to my application.  I use the following to get the information.

IF guOS.OpenClipboard(0) THEN
   lptr = guOS.GetClipboardData(15)
   lsFile = Space( liAllocate )
   liFiles = guOS.DragQueryFile( lptr, -1, lsFile, liAllocate )
   FOR liNdx = 1 TO liFiles
       lsFile = Space( liAllocate )
       guOS.DragQueryFile( lptr, liNdx - 1, lsFile, liAllocate )
       istr_DocInfo[liNdx].FileLoc = lsFile
       istr_DocInfo[liNdx].Descr = f_GetFileName(lsFile)
       //MessageBox("Paste", lsFile)
   NEXT
   guOS.EmptyClipboard()
   guOS.CloseClipboard()
END IF

Do I need to call DragFinish() even though I did not use the dropped files structure?  I just want to make sure I am managing the memory properly.

Thanks,

Chris Craft

Accepted Answer
Christopher Craft Accepted Answer Pending Moderation
  1. Thursday, 11 July 2024 22:35 PM UTC
  2. PowerBuilder
  3. # Permalink

Since I had some challenges implementing this I wanted to post what I ended up doing in case others might need it!  There are references to other objects/structures that I have not included but If you ever need that part just let me know.  Thanks again for your input - can't say it enough how much these forums help us out!

Chris Craft

/*** Declarations ***/
FUNCTION boolean IsClipboardFormatAvailable ( ulong nFormat ) LIBRARY 'user32.dll'
FUNCTION boolean OpenClipboard ( longptr hWnd ) LIBRARY 'user32.dll'
FUNCTION boolean EmptyClipboard ( ) LIBRARY 'user32.dll'
FUNCTION boolean CloseClipboard ( ) LIBRARY 'user32.dll'
FUNCTION longptr GetClipboardData ( ulong nFormat ) LIBRARY 'user32.dll'
FUNCTION Long ShellExecute (long hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, integer nShowCmd ) LIBRARY "shell32.dll" ALIAS FOR "ShellExecuteW"
FUNCTION ulong DragQueryFile( longptr hDrop, ulong nFile, ref string sFileName, ulong nCB ) LIBRARY 'shell32.dll' ALIAS FOR "DragQueryFileW"
SUBROUTINE DragAcceptFiles( longptr hWnd, boolean bAccept ) LIBRARY 'shell32.dll' ALIAS FOR "DragAcceptFiles"
SUBROUTINE DragFinish(longptr hDrop) LIBRARY "shell32.dll"

/*** RMB event ***/
// This determines if we have files in the Clipboard
IF guOS.IsClipboardFormatAvailable(CF_HDROP) THEN
     App.im_PopUp.RMBAddItem("-", ipothis, "")
     App.im_PopUp.RMBAddItem("Paste", ipothis, "le_paste")
END IF

/*** le_paste event ***/
LongPtr lptr

IF guOS.OpenClipboard(0) THEN
     lptr = guOS.GetClipboardData(CF_HDROP)
     ProcessFiles(lptr, TRUE)
     guOS.CloseClipboard()
END IF

/*** ProcessFiles function ***/
public function integer processfiles (longptr aptrhandle, boolean abclipboard);
Long llKeyIdx
String lsFile
Integer liNdx, liFiles, liAllocate = 1024

// Always Clear the Array!
istr_DocInfo = istr_ClearInfo

// Get the Primary Key Idx
llKeyIdx = GetKeyIdx()
IF IsNull(llKeyIdx) THEN
     MessageBox("Information", "Must have an Entry/ID in order to associate a file.")
     RETURN 0
ELSEIF ibNoDocumentTypes THEN
     MessageBox("Information", "Must have document types setup in order to associate a file.")
     RETURN 0
END IF

// Get how many files were dropped so we can loop through them
ibProcessing = TRUE
SetPointer(HourGlass!)
lsFile = Space( liAllocate )
liFiles = guOS.DragQueryFile( aptrHandle, -1, lsFile, liAllocate )
FOR liNdx = 1 TO liFiles
     istr_DocInfo[liNdx].RecordType = FILEDOC
     // Get the File and load the array
     lsFile = Space( liAllocate )
     guOS.DragQueryFile( aptrHandle, liNdx - 1, lsFile, liAllocate )
     istr_DocInfo[liNdx].FileLoc = lsFile
     istr_DocInfo[liNdx].Descr = f_GetFileName(lsFile)
NEXT

// If the Files came from the Clipboard then call EmptyClipboard() instead of DragFinish()!
// NOTE: DragFinish() would cause Famous to Crash when the next OpenClipboard() is called!
IF abClipboard THEN
     guOS.EmptyClipboard()
ELSE
     guOS.DragFinish(aptrHandle)
END IF

// All done!
ibProcessing = FALSE
SetPointer(Arrow!)

// Launch Assign Window for the first Index - The others will get Processed in AssignDocument()
IF liFiles > 0 THEN
     SetDocument(1)
END IF

RETURN 1
end function

 

Comment
  1. Miguel Leeuwe
  2. Thursday, 11 July 2024 22:53 PM UTC
Thanks for sharing!
  1. Helpful
  1. Christopher Craft
  2. Friday, 12 July 2024 22:27 PM UTC
One thing to note - the Windows Clipboard does not store anything if you select 'Copy' from an attachment within an Email because the file does not exist on the File System. If anyone has any thoughts on how to determine this I am all ears - from what I have read it is not an easy task.
  1. Helpful
  1. John Fauss
  2. Monday, 15 July 2024 04:22 AM UTC
I suggest you post this follow-up question as a new, separate post so that it has better visibility, Chris.
  1. Helpful
There are no comments made yet.
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Wednesday, 10 July 2024 04:59 AM UTC
  2. PowerBuilder
  3. # 1

Hi,

Have you seen these? (I know "copy/paste" is not the same as dragging files, but you seem to want to use "drag" ?

https://www.brucearmstrong.org/2012/10/implementing-drag-and-drop-from-your.html

https://anvil-of-time.com/powerbuilder/powerbuilder-dragging-files-onto-the-application/

regards

Comment
  1. Christopher Craft
  2. Wednesday, 10 July 2024 16:47 PM UTC
Thanks Miguel - I did see these. Bruce's is about dragging from the PB app which I am not needing. Matt's post I am currently using (along with Email drag/drop support) and I know I needed to call DragFinish there.

The only post I found ( http://vbnet.mvps.org/code/system/cb_dragqueryfile.htm ) mentioned you didn't need the DragFinish but it seemed odd because I am requesting the HDROP format in the GetClipboardData call.
  1. Helpful
  1. Miguel Leeuwe
  2. Wednesday, 10 July 2024 17:16 PM UTC
yw, for dragging emails from Outlook, you can use a (free) DLL from Catsoft to enable that. However, right now I cannot find the link.

This might also be another solution: https://tonyfederer.github.io/OutlookFileDrag/

  1. Helpful
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Wednesday, 10 July 2024 02:00 AM UTC
  2. PowerBuilder
  3. # 2

Hi, Chris - 

My guess (and that's all it is) is that it would not hurt or be harmful to issue the DragFinish WinAPI function on the HDROP structure immediately before calling the EmptyClipboard API.

Since Windows creates and populates the HDROP structure in response to the GetClipboardData API, I believe you should use the DragFinish API to let Windows know that you are done with it.

I think this would be a good question to ask on a forum such as StackOverflow.com, if you can do so without disclosing you are calling these WinAPI functions from a PB application (my impression is that the developers that respond to questions on that forum don't fully respect PB development).

HTH. Best regards, John

Comment
  1. Christopher Craft
  2. Wednesday, 10 July 2024 20:20 PM UTC
Thank you for that info. I am always trying to figure out when to use LongPtr compared to Long. If I see any 'Handle' types like HANDLE, HWND, HDROP, ...pretty much any data type that begins with H, should I declare it in PB as LongPtr?
  1. Helpful
  1. John Fauss
  2. Wednesday, 10 July 2024 20:56 PM UTC
In general, yes, but there are a few exceptions, such as HRESULT (it resolves to a 32-bit signed integer data type, so it's PB equivalent is Long). This is why I keep that bookmark readily accessible. However, that list is not exhaustive, so it's possible you may run into a typedef that is not listed. When this happens, I use the "Search -> "Find in Files" (Shortcut: Ctrl+Shift+F) feature in Notepad++ to search for the data type definition in all of the header (.h) files in whatever Windows SDK I have available, such as: C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0.
  1. Helpful
  1. Christopher Craft
  2. Thursday, 11 July 2024 22:27 PM UTC
Ok - after multiple tests this is what I have found. Calling DragFinish() will cause the application to crash on the next OpenClipboard() call. I tried different iterations like not calling EmptyClipboard or calling it before DragFinish() and it still crashed. I also played with passing in a different Window handle to OpenClipboard() but still the same result. I ended up just calling EmptyClipboard() with no DragFinish() and then the crash went away. Don't know why this call would cause an issue but it sure didn't like it. I will post my code I ended up with so you can check it out.



Also, I found the articles you wrote on 'Interfacing PB Applications with the Windows API'! They were awesome! One thing that might be nice to have is a quick cross-reference table that shows the Windows Data Types and what it maps to in PB. Thank you for posting those - another bookmarked webpage!
  1. Helpful
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.
We use cookies which are necessary for the proper functioning of our websites. We also use cookies to analyze our traffic, improve your experience and provide social media features. If you continue to use this site, you consent to our use of cookies.