2009-04-28 9 views
11

In Delphi ho utilizzato ShellExecute per anni per avviare (ed eventualmente attendere) altre applicazioni. Ora, però, ho bisogno di avere una di queste applicazioni in uno dei miei moduli di app Delphi. Ho provato il codice qui sotto come un semplice test per aprire il blocco note (che fa) e per visualizzare il risultato all'interno di PAnel1 sul mio modulo (che non funziona). Una persona gentile può mettermi sulla strada giusta? GrazieCome eseguire lo shell su un'altra app e visualizzarla in un 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

Che cosa vuoi fare con il menu principale del Blocco note? – Alex

risposta

15

Tutto il controllo degli errori omesso, ma questo dovrebbe iniziare:

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; 

Cosa si dovrebbe assolutamente fare è enumerare le finestre del nuovo processo, invece di utilizzare qualsiasi handle di finestra che FindWindow() ritorna.

+0

Brillante, grazie. Spero solo di aver capito in dettaglio cosa sta succedendo .....! Off ora per eliminare alcuni bit per vedere cosa succede. Grazie ancora. Bri –

+0

Sono curioso: si tratta di minimizzare, massimizzando il cambio dell'ordine z e così via? O dovresti aggiungere altre funzioni TForm1.Form * per questo? Sembra abbastanza bene. – paxdiablo

+0

L'unico problema è che i pulsanti della barra dei sottotitoli di Blocco note sono conservati, quindi è ancora possibile ridurre a icona, ingrandire o chiudere il Blocco note.Per una soluzione corretta probabilmente è necessario rimuovere l'intera barra dei sottotitoli. A seconda dei requisiti più potrebbe essere necessario, ma il problema nella questione è risolto dal codice di cui sopra. – mghie

0

che sarà un ingannevole, se è ancora possibile.

Ho visto approcci che funzioneranno per applicazioni basate su testo - in genere acquisiscono l'output standard del processo mentre accade e lo inseriscono in un controllo testo.

Ma quello di cui stai parlando è un'applicazione grafica completa (Blocco note, nonostante lavori su testo, pixel di visualizzazione, non codici di caratteri).

Quindi, a meno che il Blocco note fornisce un'interfaccia in cui è possibile:

  • richiesta caratteri arbitrari nel buffer; e
  • invia tasti arbitrari al programma, Direi che sei a corto di fortuna.

Definitivamente un kludge, ma un'opzione è quella di monitorare continuamente le finestre del Blocco note e assicurarsi che sia sempre sovrapposta all'area del client di moduli. Questo è abbastanza orribile dal momento che devi smetterlo di spostarlo, ridimensionarlo, ridurlo al minimo e così via, e mantenere il suo ordine z per essere appena sopra le tue applicazioni. Non vorrei che quei requisiti sul mio peggior nemico.

Hai mai pensato di utilizzare un controllo editor creato appositamente per Delphi (o un editor ActiveX che potresti incorporare)? Potrebbe essere un approccio migliore.

+0

Prendo atto che Blocco note è solo un segnaposto per altri programmi su cui provare questa tecnica. E mentre sono d'accordo con il tuo generale sentimento di non farlo se c'è un altro modo, semplicemente impostare l'HWND genitore e fare il posizionamento non è così difficile. – mghie

+0

Un controllo ActiveX/OLE sarebbe sicuramente preferibile. Tuttavia, è certamente possibile inserire la finestra di un'altra applicazione all'interno dell'applicazione. Ho fatto qualcosa del genere in VB, ma penso di aver usato un modulo MDI. E dovrebbe essere relativamente facile acquisire e inviare sequenze di tasti a un altro modulo di Windows tramite la sottoclasse. Ma è passato quasi un decennio da quando ho incasinato quel genere di cose. – 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); 
Problemi correlati