2013-04-26 16 views
42

Ho scritto un set di componenti che si collegano tra loro tramite le proprietà dell'interfaccia pubblicate. Sono registrati e installati in un pacchetto di progettazione.Bug e soluzioni alternative all'interfaccia pubblicate

Utilizzare le proprietà di interfaccia pubblicate non è così comune in Delphi e, quindi, non sorprende che non funzioni altrettanto bene.

Funziona correttamente quando i componenti si trovano sullo stesso modulo, tuttavia i collegamenti delle proprietà dell'interfaccia tra componenti su moduli diversi causano problemi.

A differenza dei collegamenti oggetto ai componenti su un altro modulo, i collegamenti di interfaccia non sembrano essere riconosciuti da IDE. Quello che intendo è meglio descritto da un esempio, quando hai 2 moduli aperti in IDE e hai collegamenti tra i componenti su di essi, quindi provando a passare alla visualizzazione modulo come testo (Alt + F12) farebbe in modo che l'IDE si lamenti correttamente:

Module 'UnitXXX.pas' has open descendents or linked modules. Cannot close.

Ma se la proprietà è un'interfaccia allora questo non accade, ciò che accade invece è che il collegamento è tagliato (e questa è la migliore delle ipotesi quando si utilizza meccanismo di notifica per cancellare i riferimenti, altrimenti sei lasciato con un puntatore non valido)

Un altro problema, probabilmente come conseguenza dello stesso bug, è che quando si apre un progetto in IDE, l'ordine in cui verranno riaperti i moduli d non è definito, quindi IDE può provare ad aprire un modulo che contiene componenti che hanno collegamenti di interfaccia con componenti su un altro modulo, ma quell'altro modulo non viene ancora ricreato. In questo modo si ottengono effettivamente collegamenti AV o interrotti.

Indietro negli anni '90 mentre ho usato Datasets e Datasources Ricordo problemi simili con i collegamenti tra le forme che scompaiono, quindi questo è un po 'simile.

Come soluzione temporanea ho aggiunto proprietà pubblicate duplicate, per ogni proprietà di interfaccia ne ho aggiunto un'altra dichiarata come TComponent. Ciò rende Delphi consapevole del fatto che esiste un collegamento tra le forme, ma a dir poco è una brutta soluzione.

Quindi mi chiedo se c'è qualcosa che posso fare per risolvere questo problema? È un bug IDE e probabilmente non risolvibile direttamente, ma forse posso ignorare qualcosa o altrimenti collegarlo al meccanismo di streaming per risolvere in modo più efficace questo bug.

Non sono mai andato così in profondità nel meccanismo di streaming, ma ho il sospetto che il meccanismo di Fixup debba occuparsi di questo. C'è un csFixupsTComponentState quindi spero che sia possibile una soluzione.

Modifica: Utilizzo D2007.

Aggiornamento:

new updated esempio riproducibile caricato a http://www.filedropper.com/fixupbugproject2

Aggiunto property ComponentReference: TComponent in modo che sia facile da confrontare e tracciare l'interfaccia vs Streaming componente.

Ho ristretto il problema a livello di assemblatore che è un po 'fuori dalla mia profondità.

Nel procedimento GlobalFixupReferences in classes unità chiama:

(GetOrdProp(FInstance, FPropInfo) <> 0)

che alla fine esegue:

function TInterfacedComponent.GetInterfaceReference: IInterface; 
begin 
// uncomment the code bellow to avoid exception 
{ if (csLoading in ComponentState) and (FInterfaceReference = nil) then 
    // leave result unassigned to avoid exception 
    else 
} 
    result := FInterfaceReference; // <----- Exception happens here 
end; 

Come si può vedere dal commento, l'unico modo che ho trovato per evitare l'eccezione è lasciare il risultato non assegnato, ma ciò interrompe la funzionalità poiché il confronto sopra riportato in GlobalFixupReferences non riesce a causa di GetOrdProp <> 0, che interrompe il collegamento .

tracciando più profonda la posizione più precisa eccezione è in

procedure _IntfCopy(var Dest: IInterface; const Source: IInterface); in system unità

Questa linea, in particolare, solleva una read of address 0x80000000

{ Now we're into the less common cases. } 
@@NilSource: 
     MOV  ECX, [EAX]  // get current value 

Quindi, perché MOV fallisce e che cosa c'è di sbagliato con ECX o EAX Non ne ho idea.

+5

Questa è una domanda interessante. Sembra un po 'oltre la mia esperienza personale. Ho il sospetto che tu abbia un progetto dimostrativo che possa aiutare qualsiasi investigatore in erba. –

+1

@DavidHeffernan È abbastanza facile da riprodurre, tutto ciò che serve è un discendente di TComponent con una proprietà pubblicata di tipo IInterface. Registrarlo, installare il pacchetto e rilasciarne uno su ciascuno dei due moduli vuoti. Detto questo, potrei farlo io stesso e lasciarti giocare con questo ... –

+1

Penso che sarebbe di grande aiuto se lo facessi. Abbassare le barriere per noi. –

risposta

1

Per riassumere, il problema si verifica solo con le proprietà dell'interfaccia pubblicate che hanno un metodo getter e la proprietà punta al componente su un altro modulo/modulo (e tale modulo/modulo non è stato ancora ricreato). In tal caso, il ripristino del modulo DFM causa un AV.

Sono abbastanza sicuro che il bug è nel codice ASM in GetOrdProp, ma è oltre la mia capacità di fissare, in modo che il più semplice soluzione è quello di utilizzare un campo al posto di un metodo getter e leggerlo direttamente nella proprietà. Questo è, fortunatamente abbastanza buono per il mio caso al momento.

In alternativa, è possibile dichiarare la proprietà come TComponent invece di interfaccia, quindi scrivere un discendente TComponentProperty, ignorare ComponentMayBeSetTo per filtrare componente che non supporta l'interfaccia necessaria. E naturalmente registrarlo utilizzando RegisterPropertyEditor

+0

C'è una voce di controllo di qualità per questo? –

+0

no, non credo nel CQ, sulla base dell'esperienza precedente ... –

+1

Questo perpetua solo il problema. Non puoi lamentarti che non è corretto se non lo sanno. Puoi lamentarti se lo fanno :) (Non che ti stia accusando di lamentarti, ma ottieni ciò che intendo.) –

Problemi correlati