WinFBE, Need some help to make Dropfile event works

Windows specific questions.
Post Reply
AngFerreiras
Posts: 6
Joined: Dec 10, 2022 5:10

WinFBE, Need some help to make Dropfile event works

Post by AngFerreiras »

Hello, im having troubles dealing with dropping files in WinFBE.

I need to get the file name and path of the files i drop in a button, copy that image in a directory and send it to a picturebox but i had been unable to figure out how Dropfiles event works in winFBE.

This code works using other libraries but with WinFBE this method seens to be broken.

Code: Select all

 
Function FuncInfo( BYVAL hWnd As hwnd, BYVAL wMsg As Uint, BYVAL wParam As wparam) As LRESULT
  
  Dim As Wstring * MAX_PATH szFName
  
  Select Case wMsg
	  Case WM_DropFiles
		 DragQueryFile( Cast( hDrop, wParam ), 0, szFName, Max_Path )
		print szFName
	  End Select
  
  Function = DefSubclassProc( hwnd, wMsg, 0, 0 )
  
  End Function
 
With WinFBE i get the function for the event.

Code: Select all

Function Ventana_Button3_DropFiles( ByRef sender As wfxButton, ByRef e As EventArgs ) As LRESULT
	Function = 0
End Function
Since the variable WMsg and wParam are missing I cant use the same method, i had tried to many things but nothing seems to work.
Since the cursor changes when I drag the file I must assume that the event is already set to accept data.

The documentation says
In the Windows API language this is actually a message or notification generated by the operating system that then flows through the application's message pump eventually finding its way to the procedure handler for the application. If you have ever seen Win32 API style programs then you will recognize functions containing large SELECT CASE statements having such things as WM_COMMAND, WM_NOTIFY, WM_PAINT, WM_SIZE, etc. The visual designer hides all of the complexity of message pumps and that SELECT CASE from you by instead redirecting the message to an Event Handler that you define yourself.
. But is not clear to me how i cant define the DropFiles event.
Apparently the info is send to the data clipboard as CF_HDROP an it should be possible to retrieve it using DragQueryFile, but i had been unable to figure out how.

Can someone help me with this issue? .
PaulSquires
Posts: 999
Joined: Jul 14, 2005 23:41

Re: WinFBE, Need some help to make Dropfile event works

Post by PaulSquires »

AngFerreiras wrote: Dec 13, 2022 19:47 Since the variable WMsg and wParam are missing I cant use the same method, i had tried to many things but nothing seems to work.
That's not entirely true. You can access those values from the incoming "e As EventArgs" parameter to the event handler.

Add this to your event handler:

Code: Select all

''
''
Function Ventana_Button3_DropFiles( ByRef sender As wfxButton, ByRef e As EventArgs ) As LRESULT
   Dim As Wstring * MAX_PATH szFName
   DragQueryFile( Cast( hDrop, e.wParam ), 0, szFName, Max_Path )
   print szFName
   Function = 0
End Function
Notice the use of "e.wParam"
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBE, Need some help to make Dropfile event works

Post by deltarho[1859] »

You'll need to use 'DragFinish Cast( hDrop, e.wParam )' otherwise you'll get a memory leak.
AngFerreiras
Posts: 6
Joined: Dec 10, 2022 5:10

Re: WinFBE, Need some help to make Dropfile event works

Post by AngFerreiras »

PaulSquires wrote: Dec 13, 2022 23:39 That's not entirely true. You can access those values from the incoming "e As EventArgs" parameter to the event handler.
Thanks a lot, one of the things i tried was using e but without .wParam, it was never going to work the way i tried... :-/
deltarho[1859] wrote: Dec 14, 2022 1:41 You'll need to use 'DragFinish Cast( hDrop, e.wParam )' otherwise you'll get a memory leak.

Thanks for the advise, i will add the line "DragFinish Cast( hDrop, e.wParam )" to my code, I was not going to finalize the drag since I dint knew the propose of it, now I know, thanks.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBE, Need some help to make Dropfile event works

Post by deltarho[1859] »

Over at the PowerBASIC forum, there is a discussion on using %WS_EX_ACCEPTFILES. During the discussion, it was learnt that if an application is running with administrator rights, the WM_DropFiles fails to work in Windows 10.

Try this – run WinFBE with admin rights and then try a Drag&Drop with a bas file. It appears as if it is going to work, but the 'Drop' fails.

I ran Notepad with admin rights – no Drop.

Why? No idea. It seems to be a security issue and the system is looking after us. It seems to me that Microsoft are over doing it a bit.

I am looking for a definitive reason, but have not found one yet. :)

Added:

This reminds me of an issue I had some years ago with an application which invoked the UAC control _ I have mine at full throttle. Instead of manually running, I decided to put it into the StartUp folder. The UAC message did not appear, but more to the point, the application did not run. Not a word from the system. I gave the application elevated privileges, which bypasses the UAC. That solved that problem. :)
Pierre Bellisle
Posts: 56
Joined: Dec 11, 2016 17:22

Re: WinFBE, Need some help to make Dropfile event works

Post by Pierre Bellisle »

To make an elevated application accept, let's say, files from Windows Explorer,
one must use "ChangeWindowMessageFilter". This is not an issue, this is normal UIPI (UAC) behavior.
See How to Enable Drag and Drop for an Elevated MFC Application on Windows

Here is an example of a listbox that accept one or many dropped files, even if the program run elevated.

Code: Select all

#Define JumpCompiler "<D:\Dev\Free\Compiler\fbc64.exe>" '1.08.0
#Define JumpCompilerCmd "<-s gui -w pedantic "D:\Dev\Free\bas\~~Default.rc">"
'_____________________________________________________________________________

#define unicode
#Include Once "windows.bi"
#Include Once "win\shellapi.bi"

#Define Listbox    101
#Define ButtonExit 201

#Define MSGFLT_ALLOW 1
#Define WM_COPYGLOBALDATA &H0049

Declare Function ChangeWindowMessageFilter Lib "User32.dll" ALIAS "ChangeWindowMessageFilter" _
(BYVAL dwMessage AS DWORD, BYVAL dwFlag AS DWORD) AS LONG

Dim Shared As HINSTANCE hInstance : hInstance = GetModuleHandle(NULL)
'_____________________________________________________________________________

PRIVATE FUNCTION IsUserAdmin() AS BOOLEAN
 DIM IsMember            AS LONG
 DIM AdministratorsGroup AS SID POINTER
 DIM ntAuthority         AS SID_IDENTIFIER_AUTHORITY = ({0, 0, 0, 0, 0, 5}) 'SECURITY_NT_AUTHORITY

 IF AllocateAndInitializeSid(@NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, _
                             DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, _
                             @AdministratorsGroup) THEN
   IF CheckTokenMembership(NULL, AdministratorsGroup, @IsMember) THEN
     FUNCTION = IsMember
   END IF
   FreeSid(AdministratorsGroup)
 END IF

END FUNCTION
'_____________________________________________________________________________

Function WndProc(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM) As Integer
 Static hListbox    As HWND
 Static hButtonExit As HWND
 Static hFont       As HFONT

 Function = 0

 Select Case (uMsg)

   Case WM_CREATE

     'Get Windows default font
     Dim LogicalFont AS LOGFONT
     SystemParametersInfo(SPI_GETICONTITLELOGFONT, SIZEOF(LOGFONT), @LogicalFont, 0)
     hFont = CreateFontIndirect(@LogicalFont)

     'Button
     hButtonExit = CreateWindowEx(0, "Button", "E&xit", _
                                  WS_CHILD Or WS_VISIBLE Or BS_CENTER Or WS_TABSTOP Or _
                                  BS_NOTIFY Or BS_TEXT Or BS_VCENTER, _
                                  10, 325, 205, 30, _
                                  hWnd, Cast(HMENU, ButtonExit), _
                                  hInstance, NULL)
     SendMessage(hButtonExit, WM_SETFONT, Cast(WPARAM, hFont), TRUE)

     'Listbox
     hListbox   = CreateWindowEx(WS_EX_CLIENTEDGE OR WS_EX_ACCEPTFILES, "Listbox", "", _
                                 WS_CHILD OR WS_VISIBLE OR WS_TABSTOP OR _ 'LBS_OWNERDRAWFIXED OR _ LBS_NODATA OR '
                                 LBS_NOTIFY OR WS_TABSTOP OR WS_VSCROLL, _ ' OR WS_HSCROLL
                                 10, 10, 205, 310, _
                                 hWnd, Cast(HMENU, Listbox), _
                                 hInstance, NULL)
     SendMessage(hListbox, WM_SETFONT, Cast(UInteger, hFont), TRUE)
     Dim sInfo As wString * 64
     sInfo = "Drop a file or a group of files on this listbox"
     SendMessage(hListbox, LB_ADDSTRING, 0, Cast(lParam, Sadd(sInfo)))

     'Accept or refuse drop
     'DragAcceptFiles(hListbox, False)
     'DragAcceptFiles(hListbox, True)

     If IsUserAdmin() Then
       'Enable Drop on Elevated Application from a non-elevated application
       ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ALLOW)
       ChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ALLOW)
       ChangeWindowMessageFilter(WM_COPYGLOBALDATA, MSGFLT_ALLOW)
     End If

   Case WM_COMMAND
     Select Case LoWord(wParam)
       Case ButtonExit, IDCANCEL
         If HiWord(wParam) = BN_CLICKED Then
           PostMessage(hWnd, WM_CLOSE, 0, 0)
           Exit Function
         EndIf
     End Select

   Case WM_DROPFILES
     Dim DroppedFileCount As Long
     Dim FileIndex        As Long
     Dim wFileName        As wString * Max_Path

     DroppedFileCount = DragQueryFile(Cast(hDrop, wParam), MAXDWORD, BYVAL 0, 0) 'Get dropped files count
     For FileIndex = 0 TO DroppedFileCount - 1
       DragQueryFile(Cast(hDrop, wParam), FileIndex, wFileName, Max_Path) 'Get every files
       SendMessage(hListbox, LB_ADDSTRING, 0, Cast(lParam, Sadd(wFileName)))
       SendMessage(hListbox, LB_SETCURSEL, SendMessage(hListbox, LB_GETCOUNT, 0, 0) - 1, 0) 'Select an item and scroll it to view
     Next

     'Get control handle from dropped mouse cursor position
     'DragQueryPoint(hDrop, CursorPos)
     'MapWindowPoints(hWnd, %HWND_DESKTOP, CursorPos, 1)
     'hWindowFromPoint = WindowFromPoint(CursorPos)

     DragFinish(Cast(hDrop, wParam)) 'Releases memory that Windows allocated for the drag buffer

   Case WM_SIZE
     If wParam <> SIZE_MINIMIZED Then
       Dim As LONG SizeX = LOWORD(LPARAM)
       Dim As LONG SizeY = HIWORD(LPARAM)
       MoveWindow(hListbox, 10, 10, SizeX - 20, SizeY - 50, TRUE)
       MoveWindow(hButtonExit, 10, SizeY - 35, SizeX - 20, 30, TRUE)
     End IF

   Case WM_DESTROY
     DeleteObject(hFont)
     PostQuitMessage(0)
     Exit Function

 End Select

 Function = DefWindowProc(hWnd, uMsg, wParam, lParam)

End Function
'_____________________________________________________________________________

Function WinMain(ByVal hInstance As HINSTANCE, ByVal hPrevInst As HINSTANCE, _
                 ByVal CmdLine As WString Ptr, ByVal CmdShow As Integer) As UINT
 Dim wsAppName  As WString * 64
 Dim WinClass   As WNDCLASS
 Dim WindowSize As SIZEL
 Dim hWnd       As HWND
 Dim wMsg       As MSG

 wsAppName              = "GetDroppedFiles" & SizeOf(UInteger) * 8
 WindowSize.cx          = 600
 WindowSize.cy          = 200
 WinClass.hIcon         = ExtractIcon(hInstance, "%SystemRoot%\system32\shell32.dll", 293) 'o
 WinClass.style         = CS_HREDRAW Or CS_VREDRAW
 WinClass.lpfnWndProc   = ProcPtr(WndProc)
 WinClass.cbClsExtra    = 0
 WinClass.cbWndExtra    = 0
 WinClass.hInstance     = hInstance
 WinClass.hCursor       = LoadCursor(NULL, IDC_ARROW)
 WinClass.hbrBackground = Cast(HGDIOBJ, COLOR_BTNFACE + 1) 'Default color
 WinClass.lpszMenuName  = NULL
 WinClass.lpszClassName = @wsAppName

 If (RegisterClass(@WinClass)) Then
   hWnd = CreateWindowEx(WS_EX_WINDOWEDGE, _
                         wsAppName, wsAppName, _
                         WS_OVERLAPPED OR WS_CLIPCHILDREN Or WS_DLGFRAME Or WS_BORDER Or WS_VISIBLE Or WS_CAPTION Or _
                         WS_MAXIMIZEBOX Or WS_MINIMIZEBOX Or WS_SIZEBOX Or WS_SYSMENU , _
                         (GetSystemMetrics(SM_CXSCREEN) - WindowSize.cx) / 2, _ 'PosX
                         (GetSystemMetrics(SM_CYSCREEN) - WindowSize.cy) / 2, _ 'PosY
                         WindowSize.cx, WindowSize.cy, _ 'SizeX, SizeY
                         NULL, NULL, hInstance, NULL)

   ShowWindow(hWnd, SW_SHOW)
   UpdateWindow(hWnd)

   While GetMessage(@wMsg, ByVal NULL, 0, 0) > 0
     If IsDialogMessage(hWnd, @wMsg) = 0 Then
       TranslateMessage(@wMsg)
       DispatchMessage(@wMsg)
     End If
   Wend

  End If
  DestroyIcon(WinClass.hIcon)

  Function = wMsg.message

End Function
'_____________________________________________________________________________

End WinMain(hInstance, NULL, Command(), SW_NORMAL) 'Call main() and return the error code to the OS
'_____________________________________________________________________________
'
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBE, Need some help to make Dropfile event works

Post by deltarho[1859] »

I am 'splitting hairs' here, but we don't need to 'Declare Function ChangeWindowMessageFilter ...'. It is declared in "winuser.bi" whch is included in "windows.bi" provided that we use '#Define _WIN32_WINNT &h0600' at the head of our code for Windows Vista and above. We can also remove '#Define MSGFLT_ALLOW 1' as that is in "winuser.bi"

ChangeWindowMessageFilter was introduced in Windows Vista and has process-wide scope. This worried Microsoft, and this API is no longer recommended. They are now recommending ChangeWindowMessageFilterEx, introduced in Widows7, to control access to specific windows as required.

In this case, we need to use '#Define _WIN32_WINNT &h0601' for Windows 7.

In Pierre's code, I changed the three statements beginning with ChangeWindowMessageFilter to
ChangeWindowMessageFilterEx(hWnd, WM_DROPFILES, MSGFLT_ALLOW, Null)
ChangeWindowMessageFilterEx(hWnd, WM_COPYDATA, MSGFLT_ALLOW, Null)
ChangeWindowMessageFilterEx(hWnd, WM_COPYGLOBALDATA, MSGFLT_ALLOW, Null)

So far, so good. It complies with no errors or warnings. I checked the return values of all three, and they were non-zero, indicating a success.

I have a slight problem. Running Pierre's code with admin rights sees dropping files fail. :)

What is particularly annoying is the above approach works with PowerBASIC. With PB they don't have to worry about _WIN32_WINNT, and they tend to use DWORD an awful lot with Windows APIs. With FB the safe way is to stick to the MS datatypes like glue. On checking the declaration of ChangeWindowMessageFilterEx in "winuser.bi" it looks OK to me, although the fourth parameter is not optional which it should be according to MSDN. With PB the default for parameter passing is BYREF so, for the fourth parameter, BYVAL %Null is used. Is the fourth parameter problematic here?
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBE, Need some help to make Dropfile event works

Post by deltarho[1859] »

Apologies to AngFerreiras. I should have started a new thread when I brought up admin rights and dropping files because I doubt that his opening post application intends to run with admin rights. Pierre would have responded in the new thread, and I would have got bogged down in the new thread with ChangeWindowMessageFilterEx. I was on topic here but, on reflection, I was actually how can I put it, hanging by a thread? :)
Pierre Bellisle
Posts: 56
Joined: Dec 11, 2016 17:22

Re: WinFBE, Need some help to make Dropfile event works

Post by Pierre Bellisle »

I have a slight problem. Running Pierre's code with admin rights sees dropping files fail.
In Pierre's code, I changed...
It is not exactly my code if you change it. ;-]
ChangeWindowMessageFilterEx() won't work, ChangeWindowMessageFilter() will.

For the 'splitting hairs' part, maybe you are right...
Last edited by Pierre Bellisle on Dec 19, 2022 23:42, edited 1 time in total.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: WinFBE, Need some help to make Dropfile event works

Post by coderJeff »

Looks like ChangeWindowMessageFilterEx is per window, so each window I guess?

ChangeWindowMessageFilterEx(hListbox, WM_DROPFILES, MSGFLT_ALLOW, Null)
ChangeWindowMessageFilterEx(hListbox, WM_COPYDATA, MSGFLT_ALLOW, Null)
ChangeWindowMessageFilterEx(hListbox, WM_COPYGLOBALDATA, MSGFLT_ALLOW, Null)
Pierre Bellisle
Posts: 56
Joined: Dec 11, 2016 17:22

Re: WinFBE, Need some help to make Dropfile event works

Post by Pierre Bellisle »

Yes, with proper hListbox control handle, ChangeWindowMessageFilterEx() will work...
Using hWnd, only ChangeWindowMessageFilter() work.
Pierre Bellisle
Posts: 56
Joined: Dec 11, 2016 17:22

Re: WinFBE, Need some help to make Dropfile event works

Post by Pierre Bellisle »

AngFerreiras,
If you don't need the elevated Administrator's drop file workaround,
just delete the IsUserAdmin() function and the 'If IsUserAdmin() Then'...'End If' part in my code above.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: WinFBE, Need some help to make Dropfile event works

Post by deltarho[1859] »

Pierre wrote:It is not exactly my code if you change it.
True but I didn't want any credit as you introduced ChangeWindowMessageFilter over at PB.

@coderJeff
Yes I was using the wrong handle for 'Ex'. :) Problem solved. Thanks.
Pierre wrote:Yes, with proper hListbox control handle, ChangeWindowMessageFilterEx() will work...
Using hWnd, only ChangeWindowMessageFilter() work.
Yep. :)

So use Microsoft's recommendation, but make sure you target the correct window, :lol:, and don't forget to use '#Define _WIN32_WINNT &h0601' otherwise you will get 'Variable not declared, ChangeWindowMessageFilterEx ...'
Post Reply