Using WM_DROPFILES for dropping files onto application

Using WM_DROPFILES for dropping files onto application

Hi,

I am trying to allow drag and drop files into an application I'm developing for ease of use. When the user drags and drops a file onto the application, the WM_DROPFILES message is to be activated. I can't get this to work unfortunately, I've allowed drag and drop files in the window properties and have used the DragAcceptFiles(ghwndMain,.TRUE.) subroutine upon dialog creation. 

From searching around it seems that others have used the ChangeWindowMessageFilterEx function to allow the WM_DROPFILES and WM_COPYDATA messages to be activated, but there doesn't seem to be an definition for this in any of the *.f90 windows api interface files provided with Intel Fortran 2011. Am I doing something wrong or is there another way round this?

I'm using Windows 7, VS 2008, Intel Fortran 2011 XE SP1

Many thanks,

Bryce

 

17 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
Steve Lionel (Intel)'s picture

Unfortunately, Microsoft adds API calls faster than we can add them to the modules.ChangeWindowMessageFilterEx is new in Windows 7 and we don't have a declaration for it. You can add your own in the meantime. If I get a chance tomorrow I'll write it up for you.

I'll let others comment on what you're trying to do - it's not a topic I am familiar with from a programming sense.

Steve

>>...When the user drags and drops a file onto the application, the WM_DROPFILES message is to be activated.
>>I can't get this to work unfortunately, I've allowed drag and drop files in the window properties and have used
>>the DragAcceptFiles(ghwndMain,.TRUE.) subroutine upon dialog creation...

I don't see a note about a handler for WM_DROPFILES message. Did you create it?

As soon as the application receives WM_DROPFILES message a processing needs to be done inside that handler and two more Win32 API functions need to be called:
...
OnDropFilesHandler
...
DragQueryFile( hDrop, ... );
DragFinish( hDrop );
...

An easier way, which I have successfully used, is:

 DRAG AND DROP: If a filename is dragged onto the application's icon
 then the application should open as if called with that filename's
 name on the command line.
At the start of your application, find out if an input file was given on the command line using a call to NARGS and then
get the filename using GETARGS.

>>DRAG AND DROP: If a filename is dragged onto the application's icon
>>then the application should open as if called with that filename's
>>name on the command line.

I wouldn't consider it as a solution of the problem because it doesn't help to understand why a handler for WM_DROPFILES message is Not processed. How '...a command line...' workaround is going to work when the application ( with some UI ) is already working and it has a window that could "accept" files for processing?

Thank you for your replies. Regardless of whether this is the most effective way forward, it would be very useful for me to learn how to reference external functions like windows api for future issues similiar to this. I've added something similiar to what Sergey has for handling the message but I haven't got any sign of the WM_DROPFILES message to appear. So if I was to declare an external reference (I've never done this before) to ChangeWindowMessageFilterEx so I can allow the WM_DROPFILES would it be something like the attached? - this gives an unresolved external symbol error. 

!DEC$ IF .NOT. DEFINED (extrawin_ )
!DEC$ DEFINE xextrawin_

!DEC$ objcomment lib:"user32.lib"

MODULE extrawin
use ifwinty

interface !lib=user32.lib (+version.lib)
function ChangeWindowMessageFilterEx (hWnd, message, action, pChangeFilterStruct)
import
integer(BOOL) ChangeWindowMessageFilterEx
!DEC$ ATTRIBUTES DEFAULT :: ChangeWindowMessageFilterEx
!DEC$ ATTRIBUTES STDCALL,ALIAS : "_ChangeWindowMessageFilterEx" :: ChangeWindowMessageFilterEx
integer(HANDLE) hWnd
integer(UINT) message
integer(DWORD) action
integer(LPVOID) pChangeFilterStruct
end function ChangeWindowMessageFilterEx
end interface

!DEC$ IF .NOT. DEFINED(__extrawin_INCLUDE)
END MODULE extrawin
!DEC$ ENDIF

!DEC$ ENDIF ! /* extrawin_ */

...then make sure that when you create its window, you give the application the correct style to enable it to accept drag-and-drop-files....

(from MSDN help)

HWND CreateWindowEx( DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam );

Parameters dwExStyle

[in] Specifies the extended style of the window. This parameter can be one of the following values:

ValueDescription

WS_EX_ACCEPTFILES

Specifies that a window created with this style accepts drag-drop files.

...and so on for various other styles.

>>... I haven't got any sign of the WM_DROPFILES message to appear...

Please try to use Spy++ utility ( included with some Visual Studios and with all Platform SDKs ). It is very easy to use and you will be able to see all Windows messages your application receives.

For example, in Visual Studio 2005 the utility is located at:

[ VS2005InstallDir ]\Common7\Tools\Spyxx.exe

>>...WS_EX_ACCEPTFILES...

I verified a coiple of Platform SDK examples and they don't use that style for windows. However, it makes sence to verify and test in your application.

Did you resolve the problem? If No would you be able to provide a test project ( for VS 2008 )?

I have written several windows programs and here is an example of defining a class and creating a window from it which generates the WM_DROPFILES messages, even though neither do I not use a call to DragAcceptFiles nor explicitly set the WM_EX_ACCEPTFILES style.

! Register the MAIN window class, if not already
! registered by a previous instance
if(hPrevInstance .eq. 0) then

     wc%lpszClassName    = LOC(lpszClassName)
     wc%lpfnWndProc        = LOC(MainWndProc)
     wc%style            = IOR(IOR(CS_VREDRAW , CS_HREDRAW),CS_OWNDC)
     wc%hInstance        = hInstance
     wc%hIcon            = LoadIcon( hInstance, LOC(lpszIconName))
     wc%hCursor            = LoadCursor( NULL, IDC_ARROW )
     wc%hbrBackground    = hclassbrush        ! try a different background brush
     wc%lpszMenuName    = 0
     wc%cbClsExtra        = 0
     wc%cbWndExtra        = 0
     i2                    =  RegisterClass(wc)
!    write(i2char,'(i20)') i2
!     ret=messagebox(0,'Registerclass return='//i2char//''c, &
!                    'Register Main window class 'c, &
!                    MB_OK)
end if

!****************************CREATE AND SHOW MAIN WINDOW***************************************8
! create the main window,

hmenu        = LoadMenu(hInstance, LOC(lpszMenuName))
haccel        = LoadAccelerators(hInstance, LOC(lpszAcceltabname))

hWnd        = CreateWindow(    lpszClassName,          &
                        lpszAppName,                &
                        INT(WS_OVERLAPPEDWINDOW),   &
                        50,                         &
                        0,                          &
                        550,                        &
                        550,                        &
                        NULL,                       &
                        hmenu,                      &
                        hInstance,                  &
                        NULL                        &
                        )
!                                  
i    = ShowWindow( hWnd, SW_SHOWNORMAL)

When I drag and drop a file onto its window, the following code in the MainWndProc detects the fact and tells me about the file dropped...(lpszMessage and lpszDropFileName are both 150 character buffers)

!****************************************************************
!*     WM_DROPFILES:     Drag and drop message      *
!****************************************************************
    case (WM_DROPFILES)
        retlog=messagebox(hWnd,"WM_DROPFILES message detected"c,&
                "MainWndProc messages"c, MB_OK)
        hDrop=wParam
        retint=DragQueryFile(hDrop, -1, 0, ncharDropFile)
        write(lpszmessage,*) retint
        lpszmessage=TRIM(ADJUSTL(lpszmessage))//" files dropped"c
        retlog=messagebox(hWnd,lpszmessage,&
                    "Drag and drop data"c, MB_OK)
    
        nchardropfile=150
    ! files are numbered from zero, so first file is '0', second file
    ! is '1', etc. in call to DragQueryFile        
        do i=1,retint
            retnew=DragQueryFile(hDrop, i-1, lpszDropFileName, ncharDropFile)

            write(lpszmessage,*) retnew
            lpszmessage=TRIM(ADJUSTL(lpszmessage))//" characters in file"c
            retlog=messagebox(hWnd,lpszmessage,&
                    "Drag and drop data"c, MB_OK)

            write(lpszmessage,*) lpszDropFileName(1:retnew)
            lpszmessage=TRIM(ADJUSTL(lpszmessage))//" = file name"c
            retlog=messagebox(hWnd,lpszmessage,&
                    "Drag and drop data"c, MB_OK)
        enddo

            MainWndProc    =    0

Please can you give some details about your application, such as whether or not it is a true Windows application that uses RegisterClass to register a window class in the usual way and CreatWindow to create a window with a message loop whose messages are handled by your own MainWndProc?

I have created such applications in the past and WM_DROPFILEs messages appear quite normally and are handled when I drag and drop a file onto an open window, even though I may not have explicitly specified a WS_EX_ACCEPTFILES window style or called DragAcceptFiles with the window handle. So your inability to get the WM_DROPFILES messages is puzzling, unless your application is non-standard and you are trying to bolt a drag-and-drop style onto it.

Here is an example:

! Register the MAIN window class, if not already
! registered by a previous instance
if(hPrevInstance .eq. 0) then

     wc%lpszClassName    = LOC(lpszClassName)
     wc%lpfnWndProc        = LOC(MainWndProc)
     wc%style            = IOR(IOR(CS_VREDRAW , CS_HREDRAW),CS_OWNDC)
     wc%hInstance        = hInstance
     wc%hIcon            = LoadIcon( hInstance, LOC(lpszIconName))
     wc%hCursor            = LoadCursor( NULL, IDC_ARROW )
     wc%hbrBackground    = hclassbrush        ! try a different background brush
     wc%lpszMenuName    = 0
     wc%cbClsExtra        = 0
     wc%cbWndExtra        = 0
     i2                    =  RegisterClass(wc)
     write(i2char,'(i20)') i2
!     ret=messagebox(0,'Registerclass return='//i2char//''c, &
!                    'Register Main window class 'c, &
!                    MB_OK)
end if

!****************************CREATE AND SHOW MAIN WINDOW***************************************8
! create the main window,

hmenu        = LoadMenu(hInstance, LOC(lpszMenuName))
haccel        = LoadAccelerators(hInstance, LOC(lpszAcceltabname))

hWnd        = CreateWindow(    lpszClassName,          &
                        lpszAppName,                &
                        INT(WS_OVERLAPPEDWINDOW),   &
                        50,                         &
                        0,                          &
                        550,                        &
                        550,                        &
                        NULL,                       &
                        hmenu,                      &
                        hInstance,                  &
                        NULL                        &
                        )
!                                            
i    = ShowWindow( hWnd, SW_SHOWNORMAL)

The WM_DROPFILES messages are handled thus in a MainWndProc:

!****************************************************************
!*     WM_DROPFILES:     Drag and drop message                  *
!****************************************************************
    case (WM_DROPFILES)
        retlog=messagebox(hWnd,"WM_DROPFILES message detected"c,&
                "MainWndProc messages"c, MB_OK)
        hDrop=wParam
        retint=DragQueryFile(hDrop, -1, 0, ncharDropFile)
        write(lpszmessage,*) retint
        lpszmessage=TRIM(ADJUSTL(lpszmessage))//" files dropped"c
        retlog=messagebox(hWnd,lpszmessage,&
                    "Drag and drop data"c, MB_OK)
    
        nchardropfile=150
    ! files are numbered from zero, so first file is '0', second file
    ! is '1', etc. in call to DragQueryFile        
        do i=1,retint
            retnew=DragQueryFile(hDrop, i-1, lpszDropFileName, ncharDropFile)

            write(lpszmessage,*) retnew
            lpszmessage=TRIM(ADJUSTL(lpszmessage))//" characters in file"c
            retlog=messagebox(hWnd,lpszmessage,&
                    "Drag and drop data"c, MB_OK)

            write(lpszmessage,*) lpszDropFileName(1:retnew)
            lpszmessage=TRIM(ADJUSTL(lpszmessage))//" = file name"c
            retlog=messagebox(hWnd,lpszmessage,&
                    "Drag and drop data"c, MB_OK)
        enddo
            MainWndProc    =    0

>>...Please can you give some details about your application, such as whether or not it is a true Windows application...

It is Not explained for 100% by the user but I think this is a QuickWin ( Fortran 90 ) application. If it would be a '...true Windows application...' we wouldn't have that discussion here.

If it is a QUICKWIN application, you can get it to work by

a) getting the framewindow handle using
    HWND=GETHWNDQQ(QWIN$FRAMEWINDOW)
 b) calling DragAcceptFiles with the frame window handle using
call dragacceptfiles(HWND, .true.),

c) subclassing the frame window's message-handling procedure using SetWindowLong, for example

! get the handle HWNDPROC to the default Quickwin window procedure
 HWNDPROC=GetWindowLong(HWND, GWL_WNDPROC)
!Replace the frame window's message-handling procedure with your window procedure, saving the handle to the default procedure
in HWNDPREV (HWNDPREV will be identical to HWNDPROC)
  HWNDPREV=SetWindowLong(HWND, GWL_WNDPROC, LOC(MyWndProc))

and then

d) getting your sub-class procedure MyWndProc to handle the WM_DROPFILES messages that are then sent to the frame window when you drag-and-drop files onto it.
Your procedure should return 0 (MyWndProc=0) after you have processed the message. To prevent your Quickwin application from freezing, all other windows messages must be passed by default on to the original window procedure (handle HWNDPROC) using a function call to CallWindowProc, for example

 integer function MyWndProc ( hWnd, mesg, wParam, lParam )
!DEC$ IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_MyWndProc@16':: MyWndProc
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS : 'MyWndProc' :: MyWndProc
!DEC$ ENDIF
   use dflib
   use dfwin

   implicit none
...
...
...
     select case (mesg)
     
      case (WM_DROPFILES)
          message='WM_DROPFILES MESSAGE RECEIVED...'C
        retint=messageboxqq(message,'QUICKWIN SUB-CLASSED WINDOW MESSAGE HANDLING PROCESSING'C,&
        MB$OK.OR.MB$ICONEXCLAMATION)
! Insert code for handling your dropped files here...
        MyWndProc=0

!     DEFAULT PROCESSING
    case default
!        Let the default window proc handle all other messages
        MyWndProc = CallWindowProc(HWNDPROC, mesg, wParam, lParam )

    end select

The handle HWNDPROC needs to be made available to the MyWndProc code by defining it in a module that you can USE (or, if you are old-fashioned, put it into a labelled common block).

I have tested the above with one of my own QuickWin applications and it works fine.

Attachments: 

AttachmentSize
Download dropfilesmessage.jpg94.94 KB
app4619's picture

@Anthony That looks useful! For the record, as it just happens to be something I have been looking at today:

!DEC$ IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_MyWndProc@16':: MyWndProc
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS : 'MyWndProc' :: MyWndProc
!DEC$ ENDIF

can be replaced with:

!DEC$ ATTRIBUTES STDCALL, DECORATE, ALIAS : 'MyWndProc':: MyWndProc

Which will work for x32 and x64. The x64 build ignores the decorate on stdcall it would appear.

Steve Lionel (Intel)'s picture

It's not that it ignore it, it supplies the appropriate decoration, which is none.

Steve
app4619's picture

 <quote>It's not that it ignore it, it supplies the appropriate decoration, which is none. </quote>

Indeed! The help files says IA32 decorates and then makes no comment on x64. I will remember that quote next time the wife wants me to decorate the lounge. :-)

Login to leave a comment.