2014-09-19 32 views
6

Sto utilizzando gli stili Delphi XE6 e VCL. Ho l'applicazione principale e le DLL. La mia applicazione principale ha abilitato i temi di runtime e sto usando i file in stile vcl. Ho fatto una cosa abbastanza simile alle mie DLL. Ho attivato temi di runtime e aggiunto VCL.Themes, VCL.Styles in usi e file di risorse con file in stile VCL al suo interno. Quando viene caricata la DLL, carico lo stile VCL dalle risorse e lo imposto per il gui DLL. L'app principale e la DLL non sono costruite con pacchetti di runtime.Lo stile VCL della DLL interessa TMenuItem nell'applicazione

Ora ho la GUI dell'app principale in stile con il proprio stile e gui DLL con stile proprio. Questo sembra funzionare bene fino a ...

Quando faccio clic sul pulsante nella mia app principale quale evento apre TPopupMenu è in stile con lo stesso stile della GUI DLL invece dello stile dell'app principale. Se navigo nel menu ottengo anche AV e il programma si blocca. Dai un'occhiata all'immagine allegata.

Cosa sto sbagliando? L'unica soluzione che attualmente vedo sarebbe quella di rendere il mio TPopupMenu personalizzato derivato da qualche altro controllo. enter image description here


Come promesso ho preparato semplice programma demo che è simile alla mia domanda. Consiste in un'applicazione host con il proprio stile e DLL con stile aggiunto alla risorsa. Eseguilo e fai clic sul pulsante Popup, quindi prova a selezionare qualcosa dal popup. Crollerà e si fermerà in alcuni StdWindowProc o qualcosa del genere. Inoltre, se si accede al menu di sistema della finestra (angolo in alto a sinistra) quando si tenta di selezionare qualcosa da quel menu, si noterà che il menu di sistema ha lo stile di gui DLL e si blocca anche. Collegamento a file rar: dropbox.com/sh/f2jmbsmw18akpyg/AAA6SWdBmVhf6n6K-mvYLLmua?dl=0

enter image description here

Grazie per il vostro aiuto.

+0

La spiegazione più probabile è che si passino oggetti VCL oltre il limite tra i moduli, il che non è consentito a meno che non si utilizzino pacchetti di runtime. –

+1

L'altra possibilità che posso pensare è che gli stili VCL codificano forse l'enumerazione delle risorse dei flub e enumerano le risorse lungo l'intero processo. Una rapida scansione del codice suggerisce che potrebbe essere un problema se "AutoDiscoverStyleResources' è' True'. Quella chiamata a "EnumModules" sembra un po 'incerta per me. –

+1

Se non riesci a eseguire il debug di questo, suppongo che ci stia chiedendo di approfondire. Per fare ciò potrebbe essere necessario avere un codice che mostri il problema. –

risposta

6

Questo è un problema fondamentale con gli stili VCL e il modo in cui essi modellano i menu. Lo stile è implementato con un hook di processo ampio. In particolare un hook CBT installato da una chiamata a SetWindowsHookEx da TCustomStyleEngine.CreateSysHook nell'unità Vcl.Themes. In effetti, l'hook si applica solo al thread GUI, ma è a livello di processo nel senso che c'è esattamente un thread GUI nel processo.

Poiché sono presenti più istanze del VCL nell'applicazione (una nella DLL e una nell'applicazione), vengono installati due ganci. Questo è uno di troppo. Il gancio installato più di recente (la DLL come accade) vince, ed è per questo che lo stile del menu DLL infetta il tuo eseguibile. E perché si verifica una violazione di accesso. La DLL sta tentando di operare su un menu che appartiene all'eseguibile. E così, nonostante i tuoi migliori sforzi, hai finito con il codice DLL che accede agli oggetti VCL dal file eseguibile dell'host.

Non esiste un modo semplice per aggirare questo problema e supportare completamente gli stili in entrambi i moduli. Quello che abbiamo qui è una conseguenza fondamentale del design. Il sistema non è stato progettato per supportare più istanze VCL. Se si desidera utilizzare gli stili VCL in più moduli, i progettisti si aspettano di utilizzare i pacchetti di runtime.

Suppongo che si possa essere in grado di ottenere una certa trazione eseguendo la DLL da un thread completamente diverso. Ciò implicherebbe il caricamento della DLL da quel thread diverso in modo che il VCL sia inizializzato nel thread. E tutte le chiamate alla DLL dovrebbero provenire da quel thread. E avresti bisogno di eseguire un loop di messaggi in quel thread. È possibile che tu possa essere in grado di fare quel lavoro, ma ne dubito. Anche con tutte le condizioni menzionate, è ancora necessario gestire il fatto che si hanno due thread GUI che presentano tutti i tipi di problemi con la gestione della coda di input.

Forse un altro approccio potrebbe essere quello di disinstallare l'hook dalla DLL. Finché la tua DLL non mostra i menu, potresti essere in grado di cavartela disinstallando quel gancio. Disattiva lo stile per i menu mostrati dalla DLL, ma forse è accettabile.

Questa versione della DLL (dopo averla semplificata in qualche modo anche) disattiva il hook.

library VCLStyleDLL; 

{$R 'Style.res' 'Style.rc'} 

uses 
    VCL.Styles, 
    VCL.Themes, 
    VCL.SysStyles; // to gain access to TSysPopupStyleHook 

{$R *.res} 

begin 
    TStyleManager.TrySetStyle('Glossy', false); 
    TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook); 
end. 

Con questa versione della DLL, l'eseguibile host non presenta i problemi descritti nella domanda.

+0

Grazie David per la tua spiegazione. Da allora abbiamo utilizzato AlphaControls di terze parti per applicare la skin alla nostra app, ma ora abbiamo deciso di utilizzare gli stili Delphi VCL e sto solo scoprendo la tecnologia che sta dietro. Grazie anche per la modifica/revisione del mio post e rendere questo argomento più leggibile. Lo apprezzo molto. – Nix

+0

Siete i benvenuti. Grazie per aver fatto un ottimo lavoro nel fornire informazioni e lavorare con noi per fare una buona domanda e risolvere il tuo problema. A proposito, dovresti, quando sei pronto, accettare la risposta che ritieni sia la migliore. La tua scelta. –

+0

+1 spiegazione eccellente :) –

7

Come David dice che questo è causato dal fatto che ogni istanza VCL installa un hook per rilevare quando viene creato un menu popup (# 32768). Quindi ci sono due istanze di hook che funzionano allo stesso tempo.

Come soluzione temporanea è possibile disabilitare il gancio di stile popupmenu nella dll (o nell'app) utilizzando la funzione UnRegisterSysStyleHook definita nell'unità Vcl.SysStyles.

TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook); 
+0

+1 per mostrare il modo ufficiale di annullare la registrazione di questo hook –

+0

Non ero a conoscenza di ciò, ma perché ho appena iniziato con gli stili VCL e non ho ancora familiarità con loro. Da allora abbiamo utilizzato i controlli Alpha di terze parti, ma abbiamo deciso di utilizzare gli stili VCL delphi. Grazie. – Nix