2010-02-05 16 views
44

Che cos'è TApplication.Handle?Delphi: Che cos'è Application.Handle?

  • Da dove viene?
  • Perché esiste?
  • E soprattutto: perché tutti i moduli hanno come handle della finestra principale?

L'aiuto Delphi dice:

TApplication.Handle

Consente di accedere alla finestra di gestire del modulo principale (finestra) dell'applicazione .

property Handle: HWND; 

Descrizione

Usa maniglia al momento della chiamata API di Windows funzioni che richiedono una finestra padre maniglia. Ad esempio, una DLL che visualizza la propria finestra popup a livello superiore richiede una finestra principale per visualizzare le sue finestre nell'applicazione . L'utilizzo della proprietà Handle rende tali finestre parte dell'applicazione , in modo che siano minimizzate, ripristinate, abilitate e disattivate con l'applicazione.

Se mi concentro sulle parole "l'handle della finestra del modulo principale dell'applicazione", e mi prendo a significare l'handle della finestra del modulo principale dell'applicazione, quindi posso confrontare :

  • "la maniglia di finestra del modulo principale dell'applicazione", con
  • la maniglia finestra della MainForm del Application

, ma non sono la stessa cosa:

Application.MainForm.Handle: 11473728 
Application.Handle: 11079574 

Allora, qual è Application.Handle?

  • Da dove viene?
  • Che handle di finestra di Windows ® è?
  • Se lo è l'handle di finestra di Windows ® di Application 's MainForm, quindi perché non corrispondono?
  • Se è non la maniglia della finestra di Application 's MainForm, allora che cos'è?
  • Ancora più importante: perché è il genitore supremo di ogni modulo?
  • E la cosa più importante: perché tutto va in tilt se cerco di avere un modulo non abbinato (così posso apparire sulla TaskBar), o provare ad usare qualcosa come IProgressDialog?

Davvero quello che sto chiedendo è: qual è la logica di progettazione che rende Application.Handle esiste? Se riesco a capire il perché, il come dovrebbe diventare ovvio.


Aggiornamento Capire attraverso un gioco di venti domande:

Nel parlare la soluzione di fare una finestra sulla barra delle applicazioni, rendendo il suo proprietario null, Peter Below in 2000 said:

Questo può causare alcuni problemi con le forme modali mostrate dai moduli secondari .

Se l'utente si allontana dall'app mentre è attivo un modulo modale e quindi torna al modulo che lo ha mostrato, il modulo modale può nascondere sotto il modulo. E 'possibile affrontare questo facendo in modo il form modale è imparentato alla forma che ha mostrato (usando `params.WndParent`` come sopra)

Ma questo non è possibile con lo standard finestre di dialogo dal Dialogs unità e eccezioni, che hanno bisogno di uno sforzo maggiore per farli lavorare a destra (in pratica la manipolazione Application.OnActivate, alla ricerca di forme modali, imparentata a Application via GetLastActivePopup e portarli alla parte superiore della Z-ordine via SetWindowPos) .

  • Perché un form modale finire bloccato dietro ad altre forme?
  • Quale meccanismo porta in genere una forma modale in primo piano e perché non è funzionale qui?
  • Windows ® è responsabile della visualizzazione di finestre impilate. Che cosa è andato storto che Windows ® non mostra le finestre corrette?

Ha parlato anche con il nuovo stile di Windows estesa che costringe una finestra per comparire sulla barra delle applicazioni (in cui le normali regole di renderlo non-proprietà è insufficiente, poco pratico, o indesiderabili), con l'aggiunta del WS_EX_APPWINDOW esteso stile:

procedure TForm2.CreateParams(var Params: TCreateParams); 
begin 
    inherited CreateParams(params); 

    Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; 
end; 

Ma poi avverte:

Se si fa clic su un pulsante della barra delle forme secondarie mentre un'altra applicazione è attiva questo sarà ancora portare tutte le applicazioni f orms in primo piano. Se non si vuole che ci sia un'opzione

che sta portando tutte le forme in primo piano quando il proprietario della forma è ancora Application.Handle. L'applicazione sta facendo questo? Perché sta facendo questo?Piuttosto che farlo, non dovrebbe farlo non? Qual è lo svantaggio di non facendo questo; vedo il lato negativo di fare esso (menu di sistema del non funzionano propertly, le miniature dei pulsanti della barra delle applicazioni sono inesatte, Windows ® shell non può ridurre al minimo le finestre


In un altro post che fare con la Application, Mike Edenfield says that the parent window sends other window's their minimize, maximize and restore messages:.

questo aggiungerà il pulsante sulla barra delle applicazioni per il modulo, ma ci sono un paio di altri dettagli minori a maniglia. la maggior parte, ovviamente, il modulo riceve ancora minimizzare/massimizzare spediti al form padre (la principale forma di th e applicazione). Per evitare questo, è possibile installare un gestore di messaggi per WM_SYSCOMMAND con l'aggiunta di una linea come ad esempio:

procedure WMSysCommand(var Msg: TMessage); WM_SYSCOMMAND; 

procedure TParentForm.WMSysCommand(var Msg: TMessage); 
begin 
    if Msg.wParam = SC_MINIMIZE then 
    begin 
     // Send child windows message, don't 
     // send to windows with a taskbar button. 
    end; 
end; 

Si noti che questo gestore va nella PARENT forma di quello che si desidera a comportarsi in modo indipendente di> il resto dell'applicazione, in modo da evitare di passare il messaggio minimizzare. È possibile aggiungere simili> codice per SC_MAXIMIZE, SC_RESTORE, ecc

Come è possibile che minimizzare/massimizzare/i messaggi per il mio Windows ® finestre ripristino non stanno andando a mia finestra? È perché i messaggi destinati a una finestra vengono inviati da Windows ® al proprietario della finestra? E in questo caso tutti i moduli in un'applicazione Delphi sono "di proprietà" di Application? Vuol non significa che, per rendere nullo il proprietario:

procedure TForm2.CreateParams(var Params: TCreateParams); 
begin 
    inherited; 
    Params.WndParent := 0; //NULL 
end; 

rimuoverà Application e della finestra della maniglia di interferire con la mia forma, e Windows dovrebbe ancora una volta inviare me mia mimimize/massimizzare/messaggi di ripristino?


Forse, se abbiamo confrontato e contrastato ora un'applicazione "normale" di Windows fa le cose, di come Borland inizialmente progettato applicazioni Delphi per fare le cose - rispetto a questo oggetto Application ed è ciclo principale.

  • quale soluzione era la risoluzione dell'oggetto Application?
  • Che modifica è stata apportata alle versioni successive di Delphi in modo che questi stessi problemi non esistano?
  • Il cambiamento nelle versioni successive di Delphi non ha introdotto altri problemi, che la progettazione iniziale dell'applicazione ha provato così difficile da risolvere?
  • In che modo le nuove applicazioni possono ancora funzionare senza che l'Applicazione interferisca con esse?

Ovviamente Borland ha realizzato il difetto nella progettazione iniziale. Qual era il loro progetto iniziale, quale problema risolveva, qual è il difetto, quale è stato il re-design e come risolve il problema?

+0

Penso che ti interesserà conoscere questi due trucchi: http://yoy.be/item.asp?i89 http://yoy.be/item.asp?i87 –

+2

@Stinh Sanders: i ' Ho visto quelli, loro non risolvono i problemi. Inoltre, mai, mai, mai passare GetDesktopWindow come proprietario di una finestra, come suggeriscono quelli e altri post sull'argomento. Fare così usato per causare il blocco di Windows. È stato un tale problema che Microsoft ha applicato patch a CreateWindow, quindi chiunque ha passato GetDesktopWindow mentre il proprietario viene modificato per utilizzare NULL. E se potessi modificare quel post su ** yoy.com **, lo farei. –

risposta

47

La ragione per la finestra dell'applicazione ha un po 'di una storia sordida. Durante lo sviluppo di Delphi 1, sapevamo che volevamo utilizzare il modello ui "SDI" (Windows sparso su tutto il desktop) per l'IDE. Sapevamo anche che Windows faceva schifo (e lo è ancora) in quel modello. Tuttavia, abbiamo notato che Visual Basic in quel momento utilizzava quel modello e sembrava funzionare bene. Dopo un ulteriore esame, abbiamo scoperto che VB utilizzava una speciale finestra di parcheggio "nascosta" che era usata come "proprietario" (Windows offusca la nozione di genitore e proprietario a volte, ma la distinzione è simile a VCL) per tutte le altre finestre visibili .

Questo è il modo abbiamo risolto il "problema" dove le finestre che contengono il menu principale è stato raramente così concentrata l'elaborazione di Alt-F per il menu File semplicemente non avrebbe funzionato. Usando questa finestra di parcheggio centrale come intermediario, potremmo più facilmente tenere traccia e indirizzare i messaggi alle finestre appropriate.

Questa disposizione anche risolto un altro problema in cui normalmente più finestre di livello superiore sono completamente indipendenti. Facendo in modo che l'applicazione gestisca il "proprietario" di tutte queste finestre, si comporterebbero tutti di concerto. Ad esempio, si sarà notato che quando si seleziona qualsiasi delle finestre dell'applicazione, tutti finestre dell'applicazione muovono verso la parte anteriore e mantengono il loro ordine z rispetto all'altro. Ciò renderebbe anche l'applicazione minimizza e ripristina come un raggruppamento funzionale.

Questa è una conseguenza dell'utilizzo di questo modello. abbiamo eseguito manualmente tutto questo lavoro per mantenere le cose dritte, ma la filosofia di progettazione era quella di non reinventare Windows, ma di sfruttarlo dove potevamo. Questo è anche il motivo per cui un TButton o un TEdit è in realtà una classe e uno stile di Windows "User" BUTTON e EDIT, rispettivamente.

Come si è evoluta di Windows, che il modello "SDI" ha cominciato a cadere in disgrazia. Infatti Windows stesso ha iniziato a diventare "ostile" a quello stile di applicazione. A partire da Windows Vista e continuando a 7, la shell utente non sembra funzionare bene con un'applicazione che utilizza una finestra di parcheggio. Quindi, abbiamo deciso di mescolare le cose in VCL per eliminare la finestra di parcheggio e spostare la sua funzione nella forma principale. Questo ha presentato diversi problemi di "pollo e uova" in base ai quali abbiamo bisogno di avere la finestra di parcheggio disponibile abbastanza presto nell'inizializzazione dell'applicazione in modo che altre finestre possano "collegarsi" ad essa, ma la stessa forma principale potrebbe non essere costruita abbastanza presto. TApplication deve passare attraverso alcuni cerchi per farlo funzionare, e ci sono stati alcuni casi limite che hanno causato problemi, ma la maggior parte dei problemi sono stati risolti. Tuttavia, per qualsiasi applicazione che avanzi, rimarrà utilizzando il modello di finestra di parcheggio precedente.

+3

+1 internets. E accettato. –

+1

+1 per aver ammesso che era sordido. E gli hack di Windows XP aggiunti al livello di gestione delle finestre di Microsoft facevano parte della morte di questo sistema, poiché i temuti bug degli Z-Order quando si eseguivano le app Delphi 7 su XP, iniziarono a spuntare. –

7

Dalla guardando il sorgente in forms.pas (Delphi 2009), sembra che essi creano una finestra "master" in applicazioni Win32 GUI per consentire le chiamate a

  • TApplication.Ridurre al minimo
  • TApplication.Restore
  • ecc

Sembra che i messaggi passati al Application.Handle vengono inoltrati in modo appropriato al MainForm, se esiste. Ciò consentirebbe all'app di rispondere a minimizzare, ecc. Se la finestra principale non è stata creata. Modificando la fonte del progetto è possibile creare un'app delphi senza una finestra principale.

In questo caso, i metodi TApplication funzioneranno ancora, anche se non è stata creata una finestra principale. Non sono sicuro se sto afferrando tutti gli scopi, ma non ho il tempo di esaminare tutto il codice TApplication.

Per le vostre domande:

  • Da dove viene? È l'handle di una finestra creata in TApplication.Create

  • Che maniglia di Windows è? una finestra finta che ogni Delphi applicazione GUI richiede come parte del TApplication astrazione

  • E 'il manico finestre della forma principale del appliation No

  • Se la sua non è la maniglia della MainForm dell'applicazione allora cosa è? Vedi sopra

  • più importante: perché è il genitore supremo di ogni modulo? presumendo che tu abbia ragione che è il genitore supremo, presumo che sia così perché rende facile trovare tutti i moduli nella tua applicazione (enumerando i figli di questo modulo "master").

  • e più importante: perché tutto vada in tilt se cerco di avere una forma sia unparented credo perché il modulo di "master" nascosta sta ottenendo i messaggi di sistema che dovrebbe trasmettere ai suoi figli e/o la mainform, ma non riesci a trovare la forma senza paragoni.

In ogni caso, questo è il mio punto di vista. Probabilmente puoi imparare di più guardando la dichiarazione di applicazione e il codice in forms.pas. La linea di fondo da ciò che vedo è un'astrazione conveniente.

Con i migliori saluti,

applicazioni Don

+1

In Delphi 2007, il VCL è stato modificato in modo da non avere una finestra nascosta, ma puoi anche scegliere il vecchio modo se questo ti aiuta. La finestra nascosta ha impedito il corretto funzionamento dell'anteprima di Windows 7. – mj2008

+0

@ mj2008: hai un link per ulteriori informazioni su questo?Attualmente sto aggiornando un progetto da C++ Builder 2006 -> C++ Builder 2009, e credo di vedere la mia applicazione-> Gestisci ptr come NULL. È questo il caso ora in Builder 2009? E se così fosse, utilizzare MainForm-> Handle sarebbe un buon sostituto? –

+0

@Rob Il controllo Delphi per questo è Application.MainFormOnTaskbar ma non so se si applica a te. In genere un'app aggiornata non ha questa modifica. – mj2008

11

Tutto VCL hanno una finestra di primo livello "nascosto" chiamato Application. Questo viene creato automaticamente all'avvio dell'applicazione. Tra le altre cose è il gestore di messaggi principale di Windows per VCL - quindi Application.ProcessMessages.

Avere la finestra delle applicazioni di primo livello nascosta causa alcune strane cose, in particolare il menu di sistema incompleto che appare nella barra delle applicazioni e le finestre unghie sbagliate in Vista. Versioni successive di Delphi correggono questo.

Tuttavia, non tutte le finestre devono avere come un genitore, Windows tende solo a lavorare meglio se lo è. Tuttavia, qualsiasi modulo creato con Application.CreateForm lo avrà come genitore e sarà anch'esso di proprietà dell'oggetto Application. Dato che sono di proprietà, verranno liberati una volta che l'applicazione viene liberata. Questo succede dietro le quinte in Forms.DoneApplication

+3

I moduli di livello superiore dell'applicazione non hanno la proprietà Parent impostata sulla finestra dell'applicazione! Solo il proprietario è impostato sull'oggetto Application. Giusto per chiarire: Application.ProcessMessages gestisce i messaggi per TUTTE le finestre nel thread principale (tutte le finestre VCL), è in effetti un passaggio in un normale ciclo di elaborazione dei messaggi che si trova in tutte le applicazioni GUI di Windows. –

+0

@Ritsaert Hornstra: quale handle ** fanno ** i moduli di livello superiore della mia applicazione hanno come loro padre? Si noti inoltre che tutti i moduli che creo ** fanno ** hanno 'Application.Handle' come loro padre. –

+0

Quindi questo è probabilmente il motivo per cui http://www.saphua.com/minime/minime.aspx non funziona correttamente con le mie app delphi (7). +1 per quella pepita di informazioni. – cmw

Problemi correlati