PDA

Ver la Versión Completa : Reemplazar archivo al reinicar el equipo


seoane
30-06-2006, 18:28:21
El objetivo es reemplazar un archivo por otro, si se puede en el momento, se reemplaza pero si no se puede la operacion se deja pendiente hasta el siguiente reinicio del equipo. Windows se encargara de realizar la operacion antes de cargar ningun otro programa.

Lo primero es hacer una funcion que compruebe si sobre alguno de los archivos existe ya alguna operacion pendiente ya que eso podria llevar a erroes. La funcion seria la siguiente:


uses Registry;

function Pendiente(Archivo: string): Boolean;
var
Buffer: PChar;
Size: Integer;
i: integer;
begin
Result := FALSE;
with TRegistry.Create do
try
Access := KEY_READ;
RootKey := HKEY_LOCAL_MACHINE;
if OpenKey('\SYSTEM\CurrentControlSet\Control\Session Manager', FALSE) then
begin
if ValueExists('PendingFileRenameOperations') then
begin
Size := GetDataSize('PendingFileRenameOperations');
if Size > 0 then
try
GetMem(Buffer, Size);
try
Fillchar(Buffer^, Size, #0);
ReadBinaryData('PendingFileRenameOperations', Buffer^, Size);
for i := 0 to Size - 2 do
if Buffer[i] = #0 then
Buffer[i] := #13
else
Buffer[i] := upcase(Buffer[i]);
if StrPos(Buffer, PChar(Uppercase(Archivo))) <> nil then
Result := TRUE;
finally
FreeMem(Buffer);
end;
except
end;
end;
CloseKey;
end;
finally
Free;
end;
end;


Una vez tomada esa precaucion podemos reemplzara un archivo por otro, o si el archivo de destino es una cadena vacia, borrar el original.


procedure Reemplazar(Viejo, Nuevo: string);
begin
if Pendiente(Viejo) or Pendiente(Nuevo) then
Exit;
if Nuevo = '' then
begin
if FileExists(Viejo) then
if not DeleteFile(Viejo) then
MoveFileEx(PChar(Viejo), nil, MOVEFILE_DELAY_UNTIL_REBOOT or
MOVEFILE_REPLACE_EXISTING);
end
else
begin
if not MoveFileEx(PChar(Nuevo), PChar(Viejo), MOVEFILE_REPLACE_EXISTING) then
begin
MoveFileEx(PChar(Nuevo), PChar(Viejo), MOVEFILE_DELAY_UNTIL_REBOOT or
MOVEFILE_REPLACE_EXISTING)
end;
end;
end;


Ejemplos de uso:

Reemplazar('Viejo.txt','Nuevo.txt');
// Incluso podemos borrarnos a nosotros mismos
Reemplazar(ParamStr(0),'');

jhonalone
20-03-2008, 23:10:59
No se si esto es para alguna versión determinada de Windows. Lo estoy probando con Windows ME y no funciona. No sé si será porque el fichero Viejo es un .exe o por la versión de Windows. En el código no puede haber errores, pues lo he pegado directamente, y ha complilado perfectamente.

Es una lástima, porque para el proyecto que estoy desarrollando me venía fenomenal la función.

Gracias Soane, porque tu producción de trucos y apoyos es superior.

Un Saludo.

seoane
20-03-2008, 23:40:12
Como informa aquí microsoft, esta función MoveFileEx solo esta disponible en Windows 2000/XP o superior:

http://msdn2.microsoft.com/en-us/library/aa365240(VS.85).aspx

Lo siento.

jhonalone
21-03-2008, 00:36:30
Gracias Seoane, cada vez me sorprendes más con tus conocimientos. Todos agradecemos tu esfuerzo. Buscaré otra solución.

De nuevo Gracias por responderme tan pronto.

jhonalone
23-03-2008, 00:42:05
Hola Domingo:
Estoy intentando desarrollar una función para haga la misma tarea en W98 y ME y todos los posteriores, creo que voy a aprovechar parte de la tuya. Pero tengo un problema que no he solucionado aún: no sé cómo puedo obtener la ruta completa de un fichero en formato MS-DOS, es decir en 8 caracteres con su extensión y sus CCCCCC~1.CCC. Si tú lo sabes, me ahorrarás mucho tiempo. Cuando tenga la función te la cuento.

Un saludo

seoane
23-03-2008, 01:25:20
Hola jhonalone, creo que encontraras el siguiente enlace interesante.

http://www.clubdelphi.com/foros/showpost.php?p=167116&postcount=11

jhonalone
23-03-2008, 12:42:41
Muy interesante, (como todo lo que tú haces), pero creo que tiene un par de inconvenientes:
1.-En Windows antiguos (ME) que es donde lo estoy probando,
no te deja renombrar el fichero .exe ni desde su propio
DOS, si el fichero está en uso.
2.-Ya había yo estado probando con GetShortPathName. Pero
tiene el inconveniente de que la ruta larga no puede ser
mayor de 67 bytes. Sólo vale con rutas próximas a C:\.

Seguiré investigando, pues me cuesta trabajo rendirme.

Un Saludo

jhonalone
23-03-2008, 12:52:49
Me estoy temiendo, que voy a tener que confeccionar la ruta a "pedal", con FindFirstFile o algo así.
Si al final consigo hacer la rutina, ya la colgaré para que otro no tenga que currárselo.

Voy a ver.

jhonalone
23-03-2008, 15:35:10
Compañeros, TENGO QUE RECTIFICARME. Pensaba que el problema estaba en la longitud de la cadena. Pues haciendo pruebas, he comprobado que es porque existen mas de 4 subdirectorios que comienzan con las mismas 8 letras dentro del mismo directorio. Hasta el cuarto todo va bien. Si intentas averiguar la cadena corta desde el quinto, por orden de creación, ya se desmadra el GetShortPaathName. Si alguien quiere comprobarlo, puede hacerlo con esta sencilla función.

Function Ruta:string;
var
DirActual:String;
corto:array [1..400] of char;
longitud:Cardinal;
begin
GetDir(0,DirActual);
GetShortPathName(PChar(DirActual),@corto,longitud);
Ruta:=corto;
end;