Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 20-08-2018
Avatar de newtron
[newtron] newtron is offline
Membrillo Premium
 
Registrado: abr 2007
Ubicación: Motril, Granada
Posts: 3.455
Poder: 20
newtron Va camino a la fama
Gestionar archivos temporales que se abren con terceros programas

Hola a tod@s.


Desde mi programa, como desde tantos imagino, existe la opción de abrir informes con el visor PDF que tenga instalado el ordenador en cuestión. Para esto lo que hago es crear un archivo llamado "DOCUMENTO.PDF" en el directorio temporal de windows y lanzo el programa predeterminado que tenga para abrirlo. Esto lo hago con un nombre de documento genérico porque ahora mismo no se me ocurre cómo podría detectar que se ha cerrado el visor de pdf para poder borrarlo, de esta manera siempre se usa el mismo archivo y no se satura la carpeta temporal de windows.


Ahora me encuentro con un cliente que quiere poder abrir varios documentos de forma simultanea y, claro, no se lo permite porque el anterior está en uso.


¿A alguien se le ocurre la forma de solucionar esto? porque en el momento en el que se abre el visor mi programa no se entera cuando se cierra para poder eliminar el documento temporal, si pudiera encontrar la forma crearía un documento distinto para cada exportación borrandolo posteriormente.


Gracias y un saludo
__________________
Be water my friend.
Responder Con Cita
  #2  
Antiguo 20-08-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.011
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
En cierta ocasión me encontré con ese problema y buscando información encontré una forma de hacerlo que en principio me pareció un poco "bruta" y que iba a ser lento, pero una vez probado funcionó bien y rápido.
Se trata de crear un bucle y comprobar si ya existe, algo así como:
Código:
for i=1 to 100
  if not fileexists("documento"+inttostr(i)+".pdf") then
  begin
    tratarpdf(i)
    break/exists
  end;
Código:
tratarpdf( i :int )
begin
  // aquí se crea, se abre y cuando termina se borra.


end;
Responder Con Cita
  #3  
Antiguo 20-08-2018
Avatar de newtron
[newtron] newtron is offline
Membrillo Premium
 
Registrado: abr 2007
Ubicación: Motril, Granada
Posts: 3.455
Poder: 20
newtron Va camino a la fama
Cita:
Empezado por Casimiro Notevi Ver Mensaje
En cierta ocasión me encontré con ese problema y buscando información encontré una forma de hacerlo que en principio me pareció un poco "bruta" y que iba a ser lento, pero una vez probado funcionó bien y rápido.
Se trata de crear un bucle y comprobar si ya existe, algo así como:
Código:
for i=1 to 100
  if not fileexists("documento"+inttostr(i)+".pdf") then
  begin
    tratarpdf(i)
    break/exists
  end;
Código:
tratarpdf( i :int )
begin
  // aquí se crea, se abre y cuando termina se borra.


end;

Gracias Antonio pero no entiendo la idea. Yo genero un archivo llamado "ARCHIVO1.PDF", lanzo el visor PDF y ¿qué tendría que hacer? ¿un bucle intentando borrarlo hasta que lo permita?


Saludos
__________________
Be water my friend.
Responder Con Cita
  #4  
Antiguo 20-08-2018
ASAPLTDA ASAPLTDA is offline
Miembro
 
Registrado: jun 2003
Ubicación: COLOMBIA-CALI
Posts: 639
Poder: 21
ASAPLTDA Va por buen camino
Smile No lo permite porque el anterior está en uso

Cita:
Empezado por newtron Ver Mensaje
Ahora me encuentro con un cliente que quiere poder abrir varios documentos de forma simultanea y, claro, no se lo permite porque el anterior está en uso
Saludos
Creo que el mensaje del compañero indica que crea un nuevo archivo pdf1, pdf2, pdf3... el cual sera el que abrira el usuario.

cuando el usuario termine de ver el pdf borra el archivo o usas un proceso en batch para borrar todos los df en la carpeta en la noche
Responder Con Cita
  #5  
Antiguo 20-08-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.011
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
En "TratarPDF" se ejecuta una llamada para abrirlo y se espera a que lo cierre.
Una vez devuelto el control al programa delphi, se borrar el pdf.
Código:
TratarPDF( i )
  RunAndWaitShell( ficheropdf ... )   // Creo que tienes también en tu código la función para ejecutar y esperar a que termine
  borrar ficheropdf
end;

Última edición por Casimiro Notevi fecha: 20-08-2018 a las 17:28:14.
Responder Con Cita
  #6  
Antiguo 20-08-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.011
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Aunque si lo que se quiere es que abra múltiples pdfs "independientes" y los tenga abierto cuanto quiera y seguir trabajando con el programa y "pasando" totalmente de los pdf abiertos, lo mismo puede ser una solución el crear una lista donde se van añadiendo los nombres de los pdfs abiertos y cada cierto tiempo intentar borrarlos. Si están en uso dará error y en caso contrario se borrarán.
También sin listas ni nada, a lo bruto, ejecutar el bucle e intentar borrar los que estén "libres".

Código:
procedure timercadaxminutos
  for i=1 to 100
    try
      borrar( 'documento.'+i+'.pdf'
    catch
    end
end
Responder Con Cita
  #7  
Antiguo 20-08-2018
Avatar de newtron
[newtron] newtron is offline
Membrillo Premium
 
Registrado: abr 2007
Ubicación: Motril, Granada
Posts: 3.455
Poder: 20
newtron Va camino a la fama
Cita:
Empezado por Casimiro Notevi Ver Mensaje
Aunque si lo que se quiere es que abra múltiples pdfs "independientes" y los tenga abierto cuanto quiera y seguir trabajando con el programa y "pasando" totalmente de los pdf abiertos, lo mismo puede ser una solución el crear una lista donde se van añadiendo los nombres de los pdfs abiertos y cada cierto tiempo intentar borrarlos. Si están en uso dará error y en caso contrario se borrarán.
También sin listas ni nada, a lo bruto, ejecutar el bucle e intentar borrar los que estén "libres".

Código:
procedure timercadaxminutos
  for i=1 to 100
    try
      borrar( 'documento.'+i+'.pdf'
    catch
    end
end

Ya, eso sería una solución aunque la verdad no me resulta muy elegante. ¿No hay forma de saber cuando se cierra el visor pdf para acto seguido borrar el fichero que ha abierto?


Saludos
__________________
Be water my friend.
Responder Con Cita
  #8  
Antiguo 20-08-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.011
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Depende, si los abres mediante RunAndWaitShell(....,sw_showmodal), justo al cerrar el pdf se podrá borrar por su nombre.
Código:
Tratarpdf( i )
  cFicheroPdf = 'documento'+inttostr(i)+'.pdf';
  RunAndWaitShell( cFicheroPdf, ... ..., sw_showmodal)
  borrar( cFicheroPdf)
Así no tendrías que saber cuándo se ha cerrado.


De otra forma no sé, porque imagino que se tendrá que estar verificando si todavía existe. Algo como lo que comenté antes, mantener una lista de los pdfs que se han abierto y cada cierto tiempo hay que comprobar si está todavía la ventana abierta, en caso contrario se podrá borrar.
A ver si encuentras algo sobre windows.findwindow

Última edición por Casimiro Notevi fecha: 20-08-2018 a las 20:33:57.
Responder Con Cita
  #9  
Antiguo 20-08-2018
Avatar de newtron
[newtron] newtron is offline
Membrillo Premium
 
Registrado: abr 2007
Ubicación: Motril, Granada
Posts: 3.455
Poder: 20
newtron Va camino a la fama
No puedo usar RunAndWaitShell porque son procesos no modales, buscaré lo que me comentas de windows.findwindowa ver qué veo.


Gracias Casimiro y ASAPLTDA.


Saludos
__________________
Be water my friend.
Responder Con Cita
  #10  
Antiguo 21-08-2018
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
La opción que te propone Casimiro sirve para procesos no modales


Código Delphi [-]
begin
  RunAndWaitShell('D:\Prueba.pdf', '', SW_SHOW);
  Beep();
end;


Saludos.
Responder Con Cita
  #11  
Antiguo 21-08-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.011
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Parece que el problema que tiene es saber cuándo ha cerrado el usuario el fichero pdf, para proceder a eliminarlo.
No creo que haya forma de saberlo mediante el nombre de la ventana tampoco porque cada uno puede usar un visor de pdfs distinto y el nombre también será distinto. Creo que la solución pasa por saber qué pdfs se han abierto y luego intentar borrarlos, pero ¿cuándo lo ha cerrado el usuario? Me parece que no va a quedar otra que el bucle:
Código:
for i=1 to 100
  if fileexists('documento'+inttostr(i)+'.pdf') then
    deletefile('documento'+inttostr(i)+'.pdf')
Responder Con Cita
  #12  
Antiguo 21-08-2018
Avatar de newtron
[newtron] newtron is offline
Membrillo Premium
 
Registrado: abr 2007
Ubicación: Motril, Granada
Posts: 3.455
Poder: 20
newtron Va camino a la fama
Andalaleche.... pensaba que esto del "RunAndWaitShell" dejaba "pillado" al programa hasta que no cerrara el visor.



Gracias y un saludo
__________________
Be water my friend.
Responder Con Cita
  #13  
Antiguo 21-08-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.011
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por newtron Ver Mensaje
Andalaleche.... pensaba que esto del "RunAndWaitShell" dejaba "pillado" al programa hasta que no cerrara el visor.
Gracias y un saludo
No, por eso decía que podías borrarlo al "regresar".
Responder Con Cita
  #14  
Antiguo 21-08-2018
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
He visto alguna implementacion de RunAndWaitShell y personalemnte no me gustan mucho. Para no bloquear la app usan la chapuza de ProcessMessages y el flujo de la app puede quedar descontrolado. Prefiero que ShellExecuteEx sea bloqueante hasta terminar la ejecución, pero en un Thread. Tras terminar, el hilo envía un mensaje a la ventana que indicará el fin de la ejecución.


Código Delphi [-]
procedure RunAndWaitShell(Handle: THandle; Operation, FileName, Parameters, Directory: String; nShowCmd: INTEGER);
function ThRunAndWaitShell(var Info: TShellExecuteInfo): BOOL; stdcall;
begin
  ShellExecuteExA(@Info);
  WaitForSingleObject(Info.hProcess, INFINITE);
  SendMessage(Info.wnd, RS_FINISH, 0, 0);
end;
const
{$J+}
  Info: TShellExecuteInfo = ();
begin
  with Info do
  begin
    cbSize:= SizeOf(Info);
    fMask:= SEE_MASK_NOCLOSEPROCESS;
    wnd:= Handle;
    lpVerb:= PAnsiChar(Operation);
    lpFile:= PAnsiChar(FileName);
    lpParameters:= PAnsiChar(Parameters + #0);
    lpDirectory:= PAnsiChar(Directory);
    nShow:= nShowCmd;
    hInstApp:= 0;
  end;
  CloseHandle(CreateThread(nil, 0, @ThRunAndWaitShell, @Info, 0, PDWORD(0)^));
{$J-}
end;


Un ejemplo:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ShellAPI, StdCtrls;

const
  RS_FINISH = WM_USER + 1;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure OnRunAndWaitShell(var Msg: TMessage); message RS_FINISH;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure RunAndWaitShell(Handle: THandle; Operation, FileName, Parameters, Directory: String; nShowCmd: INTEGER);
function ThRunAndWaitShell(var Info: TShellExecuteInfo): BOOL; stdcall;
begin
  ShellExecuteExA(@Info);
  WaitForSingleObject(Info.hProcess, INFINITE);
  SendMessage(Info.wnd, RS_FINISH, 0, 0);
end;
const
{$J+}
  Info: TShellExecuteInfo = ();
begin
  with Info do
  begin
    cbSize:= SizeOf(Info);
    fMask:= SEE_MASK_NOCLOSEPROCESS;
    wnd:= Handle;
    lpVerb:= PAnsiChar(Operation);
    lpFile:= PAnsiChar(FileName);
    lpParameters:= PAnsiChar(Parameters + #0);
    lpDirectory:= PAnsiChar(Directory);
    nShow:= nShowCmd;
    hInstApp:= 0;
  end;
  CloseHandle(CreateThread(nil, 0, @ThRunAndWaitShell, @Info, 0, PDWORD(0)^));
{$J-}
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  RunAndWaitShell(Handle, 'open', 'Archivo.txt', '', '', SW_SHOW);
end;

procedure TForm1.OnRunAndWaitShell(var Msg: TMessage);
begin
  // Fin de ejecución
  ShowMessage('Fin');
end;

end.


El sistema puede complicarse un poco más si queremos ejecutar varios Trheads al mismo tiempo para identificar cual de ellos se cierra y así controlar que visor se cerró.


Saludos.

Última edición por escafandra fecha: 21-08-2018 a las 13:40:47.
Responder Con Cita
  #15  
Antiguo 21-08-2018
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Como me parece que newtron comentaba que le pedían varios visores a la vez, ha modifocado un poquito el código para que RunAndWaitShell devuelva el ThreadId que ejecuta cada vez que será enviado de vuelta mediante el mensaje de finalizacion del vosor concreto. De esta forma tenemos identificado el proceso que se cierra cuyo ThreadId corresponde al que obtuvimos al iniciarlo.


Pongo Un ejemplo con las modificaciones:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ShellAPI, StdCtrls;

const
  RS_FINISH = WM_USER + 1;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Label1: TLabel;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    procedure OnRunAndWaitShell(var Msg: TMessage); message RS_FINISH;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function RunAndWaitShell(Handle: THandle; Operation, FileName, Parameters, Directory: String; nShowCmd: Integer): DWORD;
function ThRunAndWaitShell(var Info: TShellExecuteInfoA): BOOL; stdcall;
begin
  ShellExecuteExA(@Info);
  WaitForSingleObject(Info.hProcess, INFINITE);
  SendMessage(Info.wnd, RS_FINISH, GetCurrentThreadId, 0);
end;
const
{$J+}
  Info: TShellExecuteInfoA = ();
begin
  with Info do
  begin
    cbSize:= SizeOf(Info);
    fMask:= SEE_MASK_NOCLOSEPROCESS;
    wnd:= Handle;
    lpVerb:= PAnsiChar(Operation);
    lpFile:= PAnsiChar(FileName);
    lpParameters:= PAnsiChar(Parameters + #0);
    lpDirectory:= PAnsiChar(Directory);
    nShow:= nShowCmd;
    hInstApp:= 0;
  end;
  CloseHandle(CreateThread(nil, 0, @ThRunAndWaitShell, @Info, 0, Result));
{$J-}
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Caption:= IntToStr(RunAndWaitShell(Handle, 'open', 'd:/Archivo1.txt', '', '', SW_SHOW));
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Label2.Caption:= IntToStr(RunAndWaitShell(Handle, 'open', 'd:/Archivo2.pdf', '', '', SW_SHOW));
end;

procedure TForm1.OnRunAndWaitShell(var Msg: TMessage);
begin
  // Fin de ejecución
  ShowMessage('Fin ' + IntToStr(Msg.WParam));
end;

end.



Espero que con esto quede soluicionada la duda.


Saludos.

Última edición por escafandra fecha: 21-08-2018 a las 13:50:45.
Responder Con Cita
  #16  
Antiguo 21-08-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.011
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Muy bueno. Me lo copio
Lo del processmessages es un poco chapucilla, sí.
Responder Con Cita
  #17  
Antiguo 21-08-2018
Avatar de gatosoft
[gatosoft] gatosoft is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Bogotá, Colombia
Posts: 833
Poder: 21
gatosoft Va camino a la fama
Solo para el registro... si quisiera comprobar si un archivo se encuentra en uso, podrías probar con el código:

Código Delphi [-]
function FileIsInUse(aName : string) : boolean;
var
    HFileRes : HFILE;
begin
  if FileExists(aName) then
  begin
    HFileRes := CreateFile(pchar(aName), GENERIC_READ or
      GENERIC_WRITE,0, nil,
      OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);
    Result := (HFileRes = INVALID_HANDLE_VALUE);
    _lclose(HFileRes);
  end
  else
    Result := false;
end;
Responder Con Cita
  #18  
Antiguo 21-08-2018
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.011
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Me lo copio también
Excelente utilidad.
Responder Con Cita
  #19  
Antiguo 22-08-2018
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Ese código se puede resumir puesot que no es necesario comprobar si el fichero existe. CreateFile ya lo hace:
Código Delphi [-]
function FileIsInUse2(aName : string) : boolean;
var
  HFileRes: HFILE;
begin
  HFileRes := CreateFile(pchar(aName), GENERIC_READ,0, nil, OPEN_EXISTING, 0, 0);
  Result := (HFileRes = INVALID_HANDLE_VALUE);
  _lclose(HFileRes);
end;

Saludos.
Responder Con Cita
  #20  
Antiguo 22-08-2018
Avatar de newtron
[newtron] newtron is offline
Membrillo Premium
 
Registrado: abr 2007
Ubicación: Motril, Granada
Posts: 3.455
Poder: 20
newtron Va camino a la fama
Muchas gracias a todos por vuestras aportaciones, efectivamente esto es lo que necesitaba.


Saludos
__________________
Be water my friend.
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Gestionar archivos adjuntos Delphitest Varios 6 22-12-2014 22:20:43
Archivos Temporales al usar un Query mrmanuel Conexión con bases de datos 3 05-09-2005 19:33:42
Archivos temporales generados por TQuerys Balda Conexión con bases de datos 0 14-04-2005 15:18:29
Como Creo Archivos Temporales en un programa hecho en red jorge restrepo Firebird e Interbase 3 23-12-2003 19:02:23


La franja horaria es GMT +2. Ahora son las 10:51:54.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi