Ir al contenido


Foto

Drag and Drop Files en Win7 y Win8


  • Por favor identifícate para responder
5 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 07 junio 2015 - 03:17

Es un tema conocido el de arrastrar ficheros y que nuestra aplicación realice acciones con ellos, la API DragQueryFile se encarga de decirnos cuantos se arrastraron y de rellenar un buffer con el nombre de cada uno de ellos. Pero para ello debemos estar en disposición de recibir el mensaje WM_DROPFILES. La API DragAcceptFiles nos habilita para recibirlos.

El problema y el objeto de este truco es que desde Win7 los sistemas de seguridad de Windows filtran los mensajes entre aplicaciones y este es uno de ellos, esto es especialmente cierto cuando la aplicación se ejecuta como administrador, de forma que el código que funcionaba en WinXP, deja de hacerlo. Para solventar el problema debemos deshabilitar el filtro para los mensajes WM_DROPFILES y WM_COPYGLOBALDATA, de ello se encarga la nueva API ChangeWindowMessageFilterEx.

El código que muestro, funciona el WinXP y Win7-8:
 


cpp
  1. #define MSGFLT_ALLOW  1
  2. #define WM_COPYGLOBALDATA 0x0049
  3.  
  4. typedef BOOL (__stdcall *PChangeWindowMessageFilterEx)(HWND hWnd, UINT message, DWORD dwFlag, PVOID pChangeFilterStruct);
  5. PChangeWindowMessageFilterEx _ChangeWindowMessageFilterEx;
  6.  
  7.  
  8. void __fastcall TForm1::FormCreate(TObject *Sender)
  9. {
  10.   // Para usar WM_DROPFILES en Win 7 y Win8 como administrador
  11.   _ChangeWindowMessageFilterEx = (PChangeWindowMessageFilterEx)GetProcAddress(GetModuleHandle("User32.dll"), "ChangeWindowMessageFilterEx");
  12.   if(_ChangeWindowMessageFilterEx){
  13.     _ChangeWindowMessageFilterEx(Handle, WM_DROPFILES, MSGFLT_ALLOW, 0);
  14.     _ChangeWindowMessageFilterEx(Handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, 0);
  15.   }
  16.  
  17.   // Para aceptar arrastrar archivos.
  18.   DragAcceptFiles(Handle, true);
  19. }
  20.  
  21. void __fastcall TForm1::DropFiles(TWMDropFiles& Msg)
  22. {
  23.   char archivo[MAX_PATH];
  24.   // Para recibir todos los archivos arrastrados
  25.   int Count = DragQueryFile((HDROP)Msg.Drop, 0xFFFFFFFF, archivo, sizeof(archivo));
  26.   for(int i=0; i<Count; i++){
  27.     // Recibo cada archivo...
  28.     DragQueryFile((HDROP)Msg.Drop, i, archivo, sizeof(archivo));
  29.     // las acciones a realizar con los nombres obtenidos
  30.     //.........................
  31.   }
  32.  
  33.   DragFinish((HDROP)Msg.Drop);
  34. }

En esta ocasión he usado el sistema de mensajes similar a delphi, para que no se enfade seoane. :p :D

El equivalente en delphi sería lo siguiente:


delphi
  1. const
  2.   MSGFLT_ALLOW = 1;
  3.   WM_COPYGLOBALDATA = $0049;
  4.  
  5. var
  6.   ChangeWindowMessageFilterEx: function(Handle: HWND; Msg: UINT; action: DWORD; pChangeFilterStruct: Pointer): BOOL; stdcall;
  7.  
  8. procedure TForm1.FormCreate(Sender: TObject);
  9. begin
  10.   // Para usar WM_DROPFILES en Win 7 y Win8 como administrador
  11.   @ChangeWindowMessageFilterEx:= GetProcAddress(GetModuleHandle('user32.dll'),'ChangeWindowMessageFilterEx');
  12.   if Assigned(ChangeWindowMessageFilterEx) then
  13.   begin
  14.     ChangeWindowMessageFilterEx(Handle, WM_DROPFILES, MSGFLT_ALLOW, nil);
  15.     ChangeWindowMessageFilterEx(Handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, nil);
  16.   end;
  17.   DragAcceptFiles(Handle, True);
  18. end;
  19.  
  20. procedure TForm1.DropFiles(var Msg : TWMDROPFILES);
  21. var
  22.    Count, i : longInt;
  23.    Archivo : array[0..MAX_PATH] of char;
  24. begin
  25.    // Para recibir todos los archivos arrastrados
  26.    Count := DragQueryFile(Msg.Drop, $FFFFFFFF, nil, 0) ;
  27.    if Count > 0 then
  28.    begin
  29.      for i := 0 to Count -1 do
  30.      begin
  31.       DragQueryFile(Msg.Drop, i, @Archivo, sizeof(Archivo)) ;
  32.        // las acciones a realizar con los nombres obtenidos
  33.        //..............................
  34.      end;
  35.   end;
  36. end;

Subo los fuentes y binarios de un ejemplo sencillo.



Saludos.

Archivos adjuntos


  • 2

#2 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 08 junio 2015 - 12:29

Brillante escafandra  :ap:  :ap:  :ap:


  • 0

#3 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 08 junio 2015 - 02:05

Mucho mas bonito el código en delphi, donde va a parar, jajaja

Excelente como siempre :ap: :ap:
  • 0

#4 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 08 junio 2015 - 10:21

Está muy buena la función DragQueryFile(), solo tengo una duda, ¿no hay problema con versiones de sistema operativo?, me ha tocado que algunas API no funcionan en todos los Windows.

 

Saludos


  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 08 junio 2015 - 03:16

DragQueryFile funciona en WinXP y Win8 y seguirá funcionando. La que no está claro que siga funcionando es ChangeWindowMessageFilter, es por eso que usé ChangeWindowMessageFilterEx pues M$ asegura que es la que se debe usar. La clave para que DragQueryFile funcione bien en Win7 y Win8 es usar antes ChangeWindowMessageFilterEx y esto es lo que me motivó para publicar este truco, pues para WinXP y DragQueryFile hay mucha documentación, pero no tanta para su uso tras win7.

 

En https://msdn.microsoft.com tienes toda la documentación acerca de las APIs que se consideran obsoletas y las nuevas que deben usarse.

 

 

Saludos.

 


  • 1

#6 FerCastro

FerCastro

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 636 mensajes
  • LocationCiudad de México

Escrito 15 junio 2015 - 04:24

Excelente explicación y ejemplo. Yo necesito hacer un drag an drop desde un TTreeView hasta un DBGrid, pero simplemente no doy pie con bola. Algun ejemplo?

 

Saludos!!


  • 0




IP.Board spam blocked by CleanTalk.