2011-12-17 19 views
7

Vorrei essere in grado di:Come posso confrontare gli oggetti di Word Interop per "l'uguaglianza di riferimento" E determinare la raccolta o l'oggetto genitore a cui, ad esempio, appartiene un paragrafo?

  1. confrontare i proxy Word interoperabilità COM su una base "uguaglianza di riferimento"; e
  2. mappa da un oggetto specifico (ad esempio un paragrafo) alla raccolta proviene, o almeno
  3. determinare se due paragrafi provengono dalla stessa sezione e quale viene relativamente prima del precedente

Perché voglio farlo? Sto cercando di creare un componente aggiuntivo di Word che funzioni in modo simile a un correttore ortografico nel senso che viene eseguito in background (per sfondo intendo rubando regolarmente il tempo dal thread Word principale utilizzando SendMessage) e analizza il documento per alcuni testo "token". Voglio essere in grado di mantenere una collezione di token e aggiornarli mentre il documento cambia. Un esempio specifico di questo è se l'utente modifica un determinato paragrafo, voglio riesaminare il paragrafo e aggiornare la mia struttura dati che punta a quel paragrafo. Se non c'è modo di mappare tra il paragrafo modificato dall'utente (cioè il paragrafo in cui inizia l'intervallo di selezione) e un paragrafo che ho "memorizzato" in una struttura dati, non posso farlo.


Esempio di codice per la voce # 1, sopra

Se scrivo il seguente codice VBA:

Dim Para1 As Paragraph 
Dim Para2a As Paragraph 
Dim Para2b As Paragraph 
Set Para1 = ActiveDocument.Paragraphs(1) 
Set Para2a = Para1.Next 
Set Para2b = Para1.Next.Next.Previous 
If Para2a Is Para2b Then 
    Debug.Print ("Para2a Is Para2b") 
Else 
    Debug.Print ("Para2a Is Not Para2b") 
End If 

Poi sto ottenendo l'output:

"Para2a Is Not Para2b" 

Che è forse fisicamente vero (diversi proxy COM) ma non logicamente t rue. Devo essere in grado di confrontare quei paragrafi e determinare se sono logicamente lo stesso paragrafo sottostante.

(Sto pianificando di scrivere il componente aggiuntivo in C#, ma il codice VBA sopra riportato dimostra il tipo di problema che ho bisogno di superare prima di fare troppa codifica).

Per gli articoli 2 e 3 sopra, si spera che siano auto-esplicativi. Supponiamo che abbia un riferimento di paragrafo (proxy interopiano). Voglio capire "dove" è nel documento. Appartiene alla Sezione 1? È in un footer? Senza questa capacità, tutto ciò che posso ragionevolmente fare per ottenere un'idea di dove le cose provengono è riesaminare l'intero documento ogni volta che cambia, il che è ovviamente assurdamente inefficiente e non sarà abbastanza tempestivo per l'utente dell'app.

Ogni pensiero è molto apprezzato! Sono felice di pubblicare ulteriori informazioni, se necessario.

+0

Sì, non contare sul recupero dello stesso oggetto. Confronta i loro range. –

risposta

2

La navigazione dei dettagli dell'eguaglianza di riferimento nel contesto di COM Interop è sempre un esercizio interessante.

Non sono a conoscenza dei dettagli di implementazione dei metodi Paragraph.Next() e Paragraph.Previous(), tuttavia il comportamento che presentano è molto simile a come le raccolte basate su COM agiscono in generale per quanto riguarda la creazione di Runtime Callable Wrapper.

In genere, se possibile, il framework evita di creare nuove istanze RCW in risposta a ulteriori riferimenti agli oggetti COM che hanno già un RCW inizializzato e assegnato.Se esiste già un RCW per un puntatore specifico su IUnknown, viene incrementato un conteggio di riferimento interno gestito da tale RCW, quindi viene restituito RCW. Ciò consente al framework di evitare l'incremento del numero di riferimenti dell'oggetto COM effettivo (AddRef).

Le raccolte basate su COM, che sono oggetti COM con rappresentazioni gestite che implementano IEnumerable, sembrano generare un nuovo RCW ogni volta che si accede a un elemento, anche se tale elemento è già stato utilizzato durante la sessione.

Ad esempio:

Word.Document document = Application.ActiveDocument; 
Paragraphs paragraphs = document.Paragraphs; 

Paragraph first = paragraphs[1]; 
Paragraph second = paragraphs[1]; 

bool thisIsFalse = (first == second); 

Se si vuole fare qualsiasi tipo di "uguaglianza di riferimento" il controllo, è necessario sfuggire dalla collezione COM basata, in particolare nel tuo caso: l'oggetto Paragraphs. È possibile farlo semplicemente afferrando i suoi figli e la loro memorizzazione nella propria, puramente gestito e raccolta prevedibile, in questo modo:

List<Paragraph> niceParagraphs = paragraphs.Cast<Paragraph>().ToList(); 

Sebbene l'utilizzo di LINQ con interoperabilità COM può sembrare un po 'paura (se lo fa non tu ... dovrebbe davvero!) Sono abbastanza sicuro che il codice sopra è sicuro e non lascerà riferimenti penzoloni là fuori, o qualsiasi altra cosa cattiva. Non ho testato il codice sopra in modo esaustivo, tuttavia.

Non dimenticare di rilasciare correttamente quelle risorse quando hai finito con loro, almeno se le tue esigenze richiedono quel livello di prudenza.

+0

Quindi, a volte gli oggetti vengono inoltrati, via eventi, ecc. - C'è comunque, ignorando che RCW potrebbe essere un'istanza diversa - colpire sotto il cofano e vedere dove sta puntando l'RCW? Quindi, come forse una versione più costosa del '(primo == secondo)' controllo sopra, ma che restituisce vero? – BrainSlugs83

+1

Quindi, ho continuato a cercare su Google, e ho trovato, quello che credo, un articolo che hai scritto, @Matt. Mettendolo qui come risponde alla mia domanda qui sopra: http://badecho.com/2010/09/outlook-com-interop-and-reference-equality-for-unique-runtime-callable-wrapper-objects/ – BrainSlugs83