La API de Windows permite realizar esta tarea con SHFileOperation. Vamos a usar esa función a la que le pasaremos una lista de archivos de origen y una carpeta de destino.
Según la ayuda MSDN esa lista debe pasarse como un conjunto de cadenas seguidas separadas por un caracter nulo y terminada en un doble nulo. La cadena de la ruta de destino sigue la misma regla, pero en esta ocasión será una sola cadena.
La lista de archivos y/o carpetas se le pasa como una lista tipo TStrings. La función crea la carpeta de destino y en ella copia los elementos fuente.
Veamos los ejemplos de código en C/C++ y en delphi:
Comenzamos con C/C++:
cpp
#include <Shellapi.h> // Crea una carpeta y las subcarpetas de una ruta dada void CreatePath(char* Path) { int l = strlen(Path); char* fin = Path; do{ if(*fin && *fin != '\\') continue; *fin = 0; CreateDirectory(Path, 0); if(l) *fin = '\\'; }while(*fin++ && l--); } // Copia una lista de archivos y/o Carpetas en una carpeta destino dada int XCopy(HWND hWnd, TStrings *From, String To) { if(!From || To=="") return -1; CreatePath(To.c_str()); // uso un caracter \255 como paso intermedio luego lo sustituiré por nulos String sFrom = StringReplace(From->Text, "\r\n", "\255", TReplaceFlags()<<rfReplaceAll) + "\255"; for(int i=1; i<=sFrom.Length(); i++) if(sFrom[i] == '\255') sFrom[i] = 0; To.SetLength(To.Length()+1); To[To.Length()]='\0'; SHFILEOPSTRUCT FS; ZeroMemory(&FS, sizeof(SHFILEOPSTRUCT)); FS.hwnd = hWnd; FS.wFunc = FO_COPY; FS.pFrom = sFrom.c_str(); FS.pTo = To.c_str();; FS.fFlags = FOF_NOCONFIRMMKDIR | FOF_NOCONFIRMATION; return SHFileOperation(&FS); }
Un ejemplo de uso:
cpp
TStrings *From = new TStringList; From->Add("C:\\AEAT\\Renta2009\\.install4j"); // Carpeta fuente From->Add("C:\\AEAT\\Renta2009\\CloudScape"); // Carpeta fuente From->Add("C:\\AEAT\\Renta2009\\derby.log"); // Archivo fuente XCopy(Handle, From, "F:\\Prueba\\Mio\\fin"); delete From;
Ahora voy a colocar el mismo código en delphi:
delphi
uses ShellApi; // Crea una carpeta y las subcarpetas de una ruta dada procedure CreatePath(Path: string); var l, fin: integer; begin l:= Length(Path); fin:= 0; repeat if (Path[fin] = '\') or (l = 0) then begin if l>0 then Path[fin]:= #0; CreateDirectory(PCHAR(Path), 0); if l>0 then Path[fin]:= '\'; end; inc(fin); dec(l); until (l<0); end; // Copia una lista de archivos y/o Carpetas en una carpeta destino dada function XCopy(Handle: HWND; From: TStrings; Dest: String): integer; var FS: SHFILEOPSTRUCT; SFrom: string; begin Result:= -1; if(From.Count > 0) or (Dest <> '') then begin CreatePath(PCHAR(Dest)); SFrom:= StringReplace(From.Text, #13+#10, #0, [rfReplaceAll]); ZeroMemory(@FS, sizeof(SHFILEOPSTRUCT)); FS.wnd:= Handle; FS.wFunc:= FO_COPY; FS.pFrom:= PCHAR(SFrom + #0); FS.pTo:= PCHAR(Dest + #0); FS.fFlags:= FOF_NOCONFIRMMKDIR or FOF_NOCONFIRMATION; Result:= SHFileOperation(FS); end; end;
Y un ejemplo de uso:
delphi
var From: TStrings; begin From:= TStringList.Create; From.Add('C:\AEAT\Renta2009\.install4j'); // Carpeta fuente From.Add('C:\AEAT\Renta2009\CloudScape'); // Carpeta fuente From.Add('C:\AEAT\Renta2009\derby.log'); // Archivo fuente XCopy(Handle, From, 'F:\Prueba\Mio\fin'); From.Free; end;
Espero que el código sea claro y os sea de utilidad.
Saludos.
Edito para reparar hipervínculo