2009-04-28 23 views
11

En Delphi He utilizado ShellExecute durante años para iniciar (y, opcionalmente, esperar) otras aplicaciones. Ahora bien, necesito que una de estas aplicaciones aparezca en uno de mis formularios de la aplicación Delphi. He intentado el siguiente código como una prueba simple para abrir el Bloc de notas (que sí lo hace) y para mostrar el resultado dentro de PAnel1 en mi formulario (que no es así). ¿Puede una persona amable ponerme en el camino correcto? Gracias Cómo copiar a otra aplicación y hacer que aparezca en formato delphi

var 
    Rec   : TShellExecuteInfo; 
    wnd : HWnd; 
const 
    AVerb = 'open'; 
    AParams = ''; 
    AFileName = 'Notepad.exe'; 
    ADir = ''; 
begin 
    FillChar(Rec, SizeOf(Rec), #0); 

    Rec.cbSize  := SizeOf(Rec); 
    Rec.fMask  := SEE_MASK_NOCLOSEPROCESS; 
    Rec.lpVerb  := PChar(AVerb); 
    Rec.lpFile  := PChar(AfileName); 
    Rec.lpParameters := PChar(AParams); 
    Rec.lpDirectory := PChar(Adir); 
    Rec.nShow  := sw_Show; 

    ShellExecuteEx(@Rec); 

    wnd := Windows.FindWindow('Notepad', nil); 
    Windows.SetParent(Wnd, PAnel1.Handle); 

end; 
+0

¿Qué desea hacer con el menú principal del Bloc de notas? – Alex

Respuesta

15

Todo verificación de errores omitidos, pero esto debe empezar:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    Rec: TShellExecuteInfo; 
const 
    AVerb = 'open'; 
    AParams = ''; 
    AFileName = 'Notepad.exe'; 
    ADir = ''; 
begin 
    FillChar(Rec, SizeOf(Rec), #0); 

    Rec.cbSize  := SizeOf(Rec); 
    Rec.fMask  := SEE_MASK_NOCLOSEPROCESS; 
    Rec.lpVerb  := PChar(AVerb); 
    Rec.lpFile  := PChar(AfileName); 
    Rec.lpParameters := PChar(AParams); 
    Rec.lpDirectory := PChar(Adir); 
    Rec.nShow  := SW_HIDE; 

    ShellExecuteEx(@Rec); 
    WaitForInputIdle(Rec.hProcess, 5000); 

    fNotepadHandle := Windows.FindWindow('Notepad', nil); 
    Windows.SetParent(fNotepadHandle, Handle); 

    Resize; 
    ShowWindow(fNotepadHandle, SW_SHOW); 
end; 

procedure TForm1.FormResize(Sender: TObject); 
begin 
    if IsWindow(fNotepadHandle) then begin 
    SetWindowPos(fNotepadHandle, 0, 0, 0, ClientWidth, ClientHeight, 
     SWP_ASYNCWINDOWPOS); 
    end; 
end; 

Lo que definitivamente debe hacer es enumerar las ventanas del nuevo proceso, en lugar de simplemente utilizar cualquier identificador de ventana que FindWindow() devoluciones.

+0

Brillante, gracias. Solo desearía haber entendido en detalle lo que está sucediendo .....! Desactivado ahora para eliminar algunos bits y ver qué sucede. Gracias de nuevo. Bri –

+0

Tengo curiosidad: ¿eso maneja minimizar, maximizar el cambio de z orden y tal? ¿O debería agregar algunas funciones más TForm1.Form * para eso? Se ve bastante bien. – paxdiablo

+0

El único problema es que los botones de la barra de título del Bloc de notas se conservan, por lo que aún se puede minimizar, maximizar o cerrar el Bloc de notas.Para una solución adecuada, probablemente se deba eliminar toda la barra de subtítulos. Dependiendo de los requisitos, más podría ser necesario, pero el problema en la pregunta se resuelve por el código anterior. – mghie

0

que va a ser un asunto difícil, si es aún posible.

He visto enfoques que funcionarán para aplicaciones basadas en texto: generalmente capturan el resultado estándar del proceso tal como sucede y lo ponen en un control de texto.

Pero de lo que estás hablando es de una aplicación gráfica hecha y derecha (Bloc de notas, a pesar de trabajar en texto, mostrar píxeles, no códigos de caracteres).

Por lo tanto, a menos que el Bloc de notas proporciona una interfaz donde se puede:

  • solicitud de caracteres arbitrarios en la memoria intermedia; y
  • enviar pulsaciones de teclas arbitrarias al programa, Diría que no tiene mucha suerte.

Definitivamente un kludge, pero una opción es monitorear continuamente las ventanas del Bloc de notas y asegurarse de que siempre se superpone sobre el área del cliente de formularios. Eso es bastante horrible, ya que tiene que detener el movimiento, el cambio de tamaño, la minimización, etc. y mantienen su orden z justo encima de sus aplicaciones. No desearía esos requisitos en mi peor enemigo.

¿Ha pensado en utilizar un editor de control creado específicamente para Delphi (o un editor de ActiveX que puede incorporar)? Ese podría ser un mejor enfoque.

+0

Considero que el Bloc de notas es solo un marcador de posición para que otros programas prueben esta técnica. Y aunque estoy de acuerdo con su sentimiento general de no hacer esto, si hay otra forma, simplemente establecer el HWND padre y hacer el posicionamiento no es tan difícil. – mghie

+0

Un control ActiveX/OLE definitivamente sería preferible. Sin embargo, es ciertamente posible poner la ventana de otra aplicación dentro de su aplicación. He hecho algo así en VB, pero creo que utilicé un formulario MDI. Y debería ser relativamente fácil capturar y enviar pulsaciones de teclas a otro formulario de Windows mediante subclases. Pero ha pasado casi una década desde que me metí con ese tipo de cosas. – Calvin

2
var 
    URL: string; 
begin 
    URL:= DBMemoURL.Text; 
    // ShellExecute(self.WindowHandle,'open', PChar(URL), nil, nil, SW_SHOW); //default browser 
    ShellExecute(self.WindowHandle,'open','chrome.exe', PChar(URL), nil, SW_SHOW); 
Cuestiones relacionadas