PDA

Visualizza la versione completa : [DELPHI] Could not obtain OLE control window handle


firefox88
15-02-2007, 11:03
Salve a tutti,

dal momento che la mia applicazione lavora in multithreading con TADOTable e TADOQuery, sono costretto a lanciare CoInitializeEx(nil, COINIT_MULTITHREADED) quale prima istruzione del mio programma.

Sto realizzando un'applicazione Delphi con interfaccia MDI.
Su un form è presente una TADOQuery. Putroppo, nel momento in cui la form incriminata viene creata come MDIChildren, viene lanciata l'eccezione "Could not obtain OLE control window handle". Ciò non accade se la form viene creata automaticamente all'inizio e mostrata come modal form.

Che cosa posso fare? Devo forse togliere CoInitializeEx(nil, COINIT_MULTITHREADED) e mettere un CoInitialize(nil) e CoUninitialize rispettivamente all'inizio e alla fine del metodo Execute di ciascuno dei miei thread?

Grazie in anticipo :)

Whitecrowsrain
16-02-2007, 10:30
Originariamente inviato da firefox88
Salve a tutti,

dal momento che la mia applicazione lavora in multithreading con TADOTable e TADOQuery, sono costretto a lanciare CoInitializeEx(nil, COINIT_MULTITHREADED) quale prima istruzione del mio programma.

Sto realizzando un'applicazione Delphi con interfaccia MDI.
Su un form è presente una TADOQuery. Putroppo, nel momento in cui la form incriminata viene creata come MDIChildren, viene lanciata l'eccezione "Could not obtain OLE control window handle". Ciò non accade se la form viene creata automaticamente all'inizio e mostrata come modal form.

Che cosa posso fare? Devo forse togliere CoInitializeEx(nil, COINIT_MULTITHREADED) e mettere un CoInitialize(nil) e CoUninitialize rispettivamente all'inizio e alla fine del metodo Execute di ciascuno dei miei thread?

Grazie in anticipo :)

mmm...

io credo che dovresti mettere nel MAIN(o form padre) sia IL TAdoConnection che i vari TAdoQuery e TAdoTAble che poi utilizzi con le varie finestre figlie(che ovviamente avranno un USES MAIN in incipit)...

esempio

nel main


class main : class(Tform)
{
...
db:TADOConnection;
qry:TADOQuery;
tb: TADOTable;
}
...
procedure main.FormShow(Sender: TObject);
begin
//imposti i valori di connessione
db.ConnectionString:='....';
//connetti il database
db.connected:=true;
//imposti i qry e i table
qry.connection:=db;
tb.connection:=db;
end;


nella form figlia


...
implementation
uses main;
...
procedure figlia.usaqry;
begin
main.qry.close;
main.qry.sql.clear;
main.qry.sql.text:='SELECT ....' ;
...
end;



spero di esser stato chiaro...
ciao
:ciauz:

alka
17-02-2007, 11:16
Non ho ben compreso il problema, ma forse si sta utilizzando una stessa ADOConnection da più thread differenti?

firefox88
17-02-2007, 22:29
Mi scuso per la risposta tardiva, comunque sì, sto usando la stessa TADOConnection (e altri componenti TADOQuery, TADOTable, ecc...) da più thread differenti. Per ora ho risolto mettendo un CoInitialize(nil) all'inizio del metodo Execute di ogni thread che si avvale di oggetti ADO.

Esiste un metodo più "pulito"?

alka
18-02-2007, 14:33
Originariamente inviato da firefox88
Esiste un metodo più "pulito"?
Sì: non si possono usare componenti da più thread, a meno di non prendere provvedimenti specifici, in quanto le classi della VCL (salvo quelle appositamente progettate) non sono multithreading. Questo consente di massimizzare le performance dell'intera libreria, ma è necessario proteggere l'accesso ai componenti quando questo avviene da più thread.

E' possibile risolvere il problema in due modi (sono i primi che mi vengono in mente).

Quello più semplice è, secondo me, la creazione di un componente ADOConnection (e correlati) per ciascun thread che deve accedere ai dati, affinché non vi sia il tentativo di accesso contemporaneo ad un unico componente.

In alternativa, è possibile "sincronizzare" l'accesso ai componenti delegandolo al thread primario dell'applicazione, attraverso l'uso del metodo Synchronize che viene fornito dalla classe TThread.

So che è una spiegazione a grandi linee... prova a ricercare un po' di documentazione a riguardo per chiarire gli aspetti inerenti all'uso delle classi e dei metodi citati ed eventualmente scrivi ancora se hai altri dubbi.

Ciao! :ciauz:

firefox88
18-02-2007, 16:28
Non ti preoccupare, la tua spiegazione è stata molto esauriente, e ho capito perfettamente qual è il problema.

Nel mio caso, il rischio che due thread vengano eseguiti in simultanea e perciò lavorino insieme con la stessa TADOConnection non esiste: ho fatto in modo che, benché la TADOConnection sia una sola e creata in design-time, i thread "secondari" non vengano mai eseguiti insieme. Dunque ci sono massimo due thread attivi: quello principale e uno solo fra i secondari.

Devo dire che piano piano sto imparando a utilizzare i thread e a comprenderne l'utilità, ma una cosa ancora non mi è chiara: l'utilizzo di Synchronize. La documentazione dice:


Synchronize causes the call specified by Method to be executed using the main thread, thereby avoiding multi-thread conflicts. If you are unsure whether a method call is thread-safe, call it from within the Synchronize method to ensure that it executes in the main thread.

Se ho capito bene, Synchronize serve ad eseguire un determinato metodo sul thread principale nonostante lo si lanci da un thread secondario. Ma se il thread principale sta già eseguendo una procedura per conto suo, la interrompe per riprenderla in seguito oppure attende che sia terminata e quindi esegue quanto richiesto dal thread secondario?
In genere per lanciare qualcosa sul thread principale adopero i messaggi.

alka
18-02-2007, 16:44
Originariamente inviato da firefox88
Devo dire che piano piano sto imparando a utilizzare i thread e a comprenderne l'utilità, ma una cosa ancora non mi è chiara: l'utilizzo di Synchronize. [...]

Il funzionamento di Synchronize è molto semplice. Non fa altro che inserire nella coda dei messaggi dell'applicazione un messaggio specifico, a cui viene allegato l'indirizzo del metodo da eseguire.


Originariamente inviato da firefox88
Ma se il thread principale sta già eseguendo una procedura per conto suo, la interrompe per riprenderla in seguito oppure attende che sia terminata e quindi esegue quanto richiesto dal thread secondario?
Il thread principale è generalmente impegnato a verificare la presenza dei messaggi in coda per l'applicazione e a gestirli; siccome la Synchronize non fa altro che inserire un ulteriore messaggio in coda, questo verrà gestito quando tutti i messaggi precedenti sono stati serviti.


Originariamente inviato da firefox88
In genere per lanciare qualcosa sul thread principale adopero i messaggi.
In tal caso, credo sia molto probabile che tu abbia già implementato qualcosa del tutto simile al meccanismo di funzionamento di Synchronize. :)

Ciao! :ciauz:

firefox88
18-02-2007, 17:11
In tal caso, credo sia molto probabile che tu abbia già implementato qualcosa del tutto simile al meccanismo di funzionamento di Synchronize. :)

Già... E mi sembrava strano che non si potesse fare in altro modo. :)

alka
18-02-2007, 17:22
Originariamente inviato da firefox88
Già... E mi sembrava strano che non si potesse fare in altro modo. :)
Altri modi ci sono: usare Mutex, Critical Section, semafori, ecc. :)

Lo strumento più adatto dipende dall'esigenza.

Ciao! :ciauz:

Loading