Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Volver a mostrar una ventana abierta con ShellExecute (https://www.clubdelphi.com/foros/showthread.php?t=85566)

jplj 01-04-2014 21:26:15

Volver a mostrar una ventana abierta con ShellExecute
 
Hola

Tengo una aplicación que muestra un digamos "listado de documentos" que el usuario puede abrir con un simple click.
Para "abrir" un documento/fichero, se copia el fichero al directorio temporal del usuario y posteriormente se abre con ShellExecute.
Código Delphi [-]
    ShellExecute(Self.Handle, nil, PChar(tmpFileName),'', '',SW_SHOWNORMAL);

Ahora bien, el usuario sigue trabajando y sigue abirendo, minimizando, ... vamos que llena la pantalla, y más pronto que tarde vuelve a intentar abrir un documento que ya está abierto y "tapado" por muchos otros ...

Lo que yo quería es poder "traer al frente" el documento abierto, y no tener que "abrir" una nueva copia.

Buscando he encontrado la función ShowWindowAsync.

Código Delphi [-]
ShowWindowAsync(HWND_ventana, SW_MAXIMIZE);

Pero hace falta el handle de la ventana que se genera al llamar a ShellExecute.

¿Cómo podría obtener este handle?, y si no es posible ¿de qué otra forma podria hacerlo?


Muchas gracias de antemano.
Un Saludo

nlsgarcia 01-04-2014 22:06:04

jplj,

Cita:

Empezado por jplj
...¿de qué otra forma podría hacerlo?...

Pregunto: ¿Has considerado la idea de mostrar el archivo en un TListBox?

Revisa este código:
Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
begin
   ListBox1.Items.LoadFromFile('FileTest.txt');
end;
El código anterior carga un archivo en disco a un TListBox, la idea también aplica para un TMemo o un TRichEdit y puedes mostrar la información en pantallas separadas si tu aplicación así lo requiere.

Espero sea útil :)

Nelson.

jplj 01-04-2014 23:31:53

No es posible. Los documentos pueden ser desde una hoja d cálculo a una imagen, pdf, presentación, ...
En principio cualquier tipo de archivo que suela ser empleado para almacenar información.

ecfisa 02-04-2014 00:56:30

Hola jplj.

A ver si te sirve de este modo...
Código Delphi [-]
...
implementation
 
// En el ejemplo filtra documentos abiertos con: Block de notas, Adobe Reader y Libre Office. 
// (Agrega o cambia por los que desees)
function EnumWndProc(Handle: HWND; CB: TComboBox): BOOL; stdcall;
var
  Name: array[0..128] of Char;
  s: string;
begin
  Result := True;
  SendMessage(Handle, WM_GETTEXT, Sizeof(Name), integer(@Name));
  SetString(s ,PChar(@Name[0]), Length(Name));
  s:= UpperCase(s);
  if (AnsiPos('.TXT', s) > 0) or (AnsiPos('.PDF', s) > 0) or (AnsiPos('.ODS', s) > 0) then
    CB.Items.AddObject(Name, TObject(Handle));
end;

// Actualizar lista al entrar al combo
procedure TForm1.ComboBox1Enter(Sender: TObject);
begin
  ComboBox1.clear;
  EnumWindows(@EnumWndProc, LPARAM(ComboBox1));
  ComboBox1.ItemIndex:= 0;
end;

// Traer al frente la ventana seleccionada
procedure TForm1.ComboBox1Change(Sender: TObject);
var
  Wnd: HWND;
begin
  with TComboBox(Sender) do
  begin
    Wnd:= FindWindow(nil, PChar(Items[ItemIndex]));
    if Wnd <> 0 then
    begin
      ShowWindow(Wnd, SW_SHOWNORMAL);
      BringWindowToTop(Wnd);
    end;
  end;
end;
...
Del mismo modo podría implementarse mediante un TListBox que se hiciera visible ante el click de un botón y se ocultara luego de la selección.

Saludos :)

nlsgarcia 02-04-2014 07:35:49

jplj,

Cita:

Empezado por jplj
...Volver a mostrar una ventana abierta con ShellExecute..."traer al frente" el documento abierto, y no tener que "abrir" una nueva copia...En principio cualquier tipo de archivo que suela ser empleado para almacenar información...

Revisa este código:
Código Delphi [-]
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
   FileName : Array[0..3] of String = ('Nelson.txt', 'Nelson.xlsx', 'Nelson.pdf', 'Nelson.jpg');
   FilePrg : Array[0..3] of String = (' - NotePad',
                                      ' - Microsoft Excel',
                                      ' - Adobe Reader',
                                      ' - Windows Photo Viewer');

var
   Form1: TForm1;

implementation

{$R *.dfm}

// Inicializa un TListBox con archivos de Windows
procedure TForm1.FormCreate(Sender: TObject);
var
   i : Integer;
begin
   for i  := Low(FileName) to High(FileName) do
      ListBox1.Items.Add(FileName[i]);
end;

// Abre una sola ventana de un archivo con su aplicación por default en Windows
procedure TForm1.Button1Click(Sender: TObject);
var
  WindowHandle : THandle;
  WindowName : String;

begin

  WindowName := FileName[ListBox1.ItemIndex] + FilePrg[ListBox1.ItemIndex];

  WindowHandle := FindWindow(nil,PChar(WindowName));

  if SetForegroundWindow(WindowHandle) then
     ShowWindow(WindowHandle, SW_SHOWNORMAL)
  else
     ShellExecute(0, nil, PChar(FileName[ListBox1.ItemIndex]),'', '',SW_SHOWNORMAL);

end;

end.
El código anterior en Delphi 7 bajo Windows 7 Professional x32, permite abrir los archivos contenidos en el TListBox con su aplicación por default en Windows por medio de ShellExecute y en caso de ser seleccionados nuevamente colocar la ventana de la aplicación en el tope del Z-Order (Si esta activa) o abrirla nuevamente si esta fue previamente cerrada, en resumen: Se abre una sola ventana por archivo seleccionado.

Nota: Es fundamental que se coloque el nombre correcto de la aplicación (Como aparece en la ventana de la misma), en el formato: " - ApplicationName", si lo anterior no es correcto la aplicación se abrirá tantas veces como sea llamada.

Revisa esta información:
Espero sea útil :)

Nelson.

jplj 02-04-2014 12:32:39

Muchas gracias por vuestra ayuda ...

Voy a trabajar con las ideas que me habéis proporcionado, y comentaré la solución si la hayo o los problemas que me encuentre.

De todas formas un par de apuntes rápidos:
  • Cuando decía
    Cita:

    ... aplicación que muestra un digamos "listado de documentos" que ...
    Era un simplificación, realmente se muestra una información de los documentos de una forma bastante más compleja.

  • La idea propuesta por nlsgarcia:
    Cita:

    WindowName := FileName[ListBox1.ItemIndex] + FilePrg[ListBox1.ItemIndex];
    WindowHandle := FindWindow(nil,PChar(WindowName));
    Es lo que he intentado pero me encontre que no fuí capaz de averiguar el nombre de la ventana.
    • ¿El standar de título de una ventana es NombreFichero + ' - ' + NombreAplicación?
    • Se presupone que conocemos por anticipado el nombre de la aplicación que abrirá el documento, y en mi caso no es así. ¿Sería posible conocer en tiempo de ejecución cuál es la aplicación predeterminada para abrir un tipo determinado de archivo?, creo que conseguirlo sería la mejor forma solucionar el problema.

Lo dicho, muchas gracias :)

jplj 02-04-2014 14:50:13

Repecto a ...

Cita:

◦ ... ¿Sería posible conocer en tiempo de ejecución cuál es la aplicación predeterminada para abrir un tipo determinado de archivo? ...
La solución puede ser FindExecutable function

nlsgarcia 02-04-2014 15:26:12

jplj

Cita:

Empezado por jplj
¿El standard de título de una ventana es NombreFichero + ' - ' + NombreAplicación?

Si es correcto ^\||/

Cita:

Empezado por jplj
¿Sería posible conocer en tiempo de ejecución cuál es la aplicación predeterminada para abrir un tipo determinado de archivo?

Si es posible, sin embargo lo que se requiere en tu caso es el nombre de la ventana en el formato NombreFichero + ' - ' + NombreAplicación, por lo cual el nombre de la aplicación por default (Ejecutable en Disco), no corresponderá necesariamente con el nombre de la aplicación en la ventana de la misma en el formato anteriormente mencionado.

Revisa este código:
Código Delphi [-]
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
   FileName : Array[0..3] of String = ('Nelson.txt', 'Nelson.xlsx', 'Nelson.pdf', 'Nelson.jpg');

var
   Form1: TForm1;

implementation

{$R *.dfm}

// Obtiene la lista de Ventanas Activas
function EnumWndProc(Handle: HWND; LP: TStrings): BOOL; stdcall;
var
   WindowName: array[0..128] of Char;
   AuxStr: string;

begin

   Result := True;

   SendMessage(Handle, WM_GETTEXT, Sizeof(WindowName), integer(@WindowName));

   SetString(AuxStr ,PChar(@WindowName[0]), Length(WindowName));

   AuxStr := LowerCase(AuxStr);

   if (AnsiPos('.txt', AuxStr) > 0)
   or (AnsiPos('.xlsx', AuxStr) > 0)
   or (AnsiPos('.pdf', AuxStr) > 0)
   or (AnsiPos('.jpg', AuxStr) > 0)
   then
      LP.Add(WindowName);

end;

// Inicializa un TListBox con archivos de Windows
procedure TForm1.FormCreate(Sender: TObject);
var
   i : Integer;
begin
   for i  := Low(FileName) to High(FileName) do
      ListBox1.Items.Add(FileName[i]);
end;

// Abre una sola ventana de un archivo con su aplicación por default en Windows
procedure TForm1.Button1Click(Sender: TObject);
var
   WindowHandle : THandle;
   WindowName : String;
   ListPrg : TStringList;
   i : Integer;

begin

   ListPrg := TStringList.Create;

   EnumWindows(@EnumWndProc, LPARAM(ListPrg));

   WindowName := EmptyStr;

   for i := 0 to ListPrg.Count - 1 do
      if AnsiPos(FileName[ListBox1.ItemIndex],ListPrg.Strings[i]) > 0 then
      begin
         WindowName := ListPrg[i];
         Break;
      end;

   if WindowName = EmptyStr then
      ShellExecute(0, nil, PChar(FileName[ListBox1.ItemIndex]),'', '',SW_SHOWNORMAL)
   else
   begin
      WindowHandle := FindWindow(nil,PChar(WindowName));

      if SetForegroundWindow(WindowHandle) then
         ShowWindow(WindowHandle, SW_SHOWNORMAL);
   end;

   ListPrg.Free

end;

end.
El código anterior (Versión 2 del código del Msg #5) en Delphi 7 bajo Windows 7 Professional x32, permite abrir de forma automática los archivos contenidos en el TListBox con su aplicación por default en Windows por medio de ShellExecute y en caso de ser seleccionados nuevamente, colocar la ventana de la aplicación en el tope del Z-Order si esta activa por medio de las APIs EnumWindows, FindWindow y SetForegroundWindow o abrirla nuevamente si esta fue previamente cerrada, en resumen: Se abre una sola ventana por archivo seleccionado.

Nota: El nombre de la ventana (Segundo parámetro de la funcion FinWindow), debe estar en el formato "DocumentName - ApplicationName" el cual es obtenido de forma automática por medio de la función EnumWindows.

Revisa esta información:
Espero sea útil :)

Nelson.

Chris 02-04-2014 22:35:14

Este es un problema extraño. ShellExecute en su segunda llamada debería activar automáticamente la ventana en la que ya está abierto el documento. Esto puede deverse a un problema en la configuración del registro o un problema con tu código.

Por ejemplo, si abres un documento desde el explorador, la segunda vez que lo intentas abrirlo (haciendo doble-click) te debería activar la ventana previamente creada con el documento.

Intenta modificar tu código colocando el verbo explícitamente. Además pasaremos nil en los parámentros y ruta del archivo (nil != '') y por último el handle del escritorio, normalmente 0.
Código Delphi [-]
ShellExecute(0, 'open', PChar(tmpFileName), nil, nil, SW_SHOW);

jplj 02-04-2014 23:25:40

Chris he comprobado lo que me dices, tanto en W7 con en XP abre una nueva ventana. Ocurre lo mismo desde el explorador.

Nelson, exactamente lo que andaba buscando :)

Muchas gracias por vuestra ayuda.
Juan P.


La franja horaria es GMT +2. Ahora son las 00:37:50.

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