Qual è il modo corretto per implementare un'estensione del gestore della proprietà gestita?

StackOverflow https://stackoverflow.com/questions/3200245

Domanda

Ora che .NET CLR 4.0 supporta il funzionamento fianco a fianco (SXS) dovrebbe ora essere possibile scrivere shell Estensioni in codice gestito. Ho tentato questo e codificato con successo un gestore di proprietà che implementa ipropertystore, iinitializewithstream e ipropertystorecapabilità.

Il gestore Funziona bene ed è chiamato come previsto durante la navigazione dei file tramite l'esploratore. Funziona anche bene nella visualizzazione del Proprietà personalizzate nel pannello Anteprima e il pannello "Detail" Proprietà file.

Tuttavia, quando cerco di Modifica una proprietà nel pannello Anteprima, quindi fai clic su "Salva" Io ricevo un "file in uso" che dice questo Il file è aperto in Esplora risorse.

Alcuni TIDBITS:

    .
  1. Quando Explorer chiama IINITILizeWithStream.Initialize La proprietà STGM è impostata su STGM_Share_Deny_Write.
  2. e in nessun punto ha chiamato Explorer Call IPropertystore.setValue o IPropertystore.Commit.
  3. Vedo le chiamate ripetute sul mio gestore su fili diversi per le stesse proprietà del file.
  4. Allora, cosa devo cambiare (o impostare il registro) per ottenere la proprietà Salva sul lavoro?

    Aggiornamento:

    Grazie a Ben l'ho lavorato. La "parte difficile" (almeno per me) era capire che COM Interrope non chiamerebbe mai smaltire o finalizzare sul mio PropertyHandler. Questo stava lasciando i file che ho lavorato aperto fino a quando il GC ha corso.

    Fortunatamente, il "protocollo del gestore di proprietà" funziona in modo tale che quando Iinitializewithsream.initialize () è richiamato per un lettura () il StreamMode è readonly e quando viene chiamato per un setValue () il StreamMode è readwrite e commit () sarà chiamato alla fine.

    int IInitializeWithStream.Initialize( IStream stream, uint grfMode )
    {
        _stream = stream;
        _streamMode = (Stgm)grfMode;
    
        Load();
    
        // We release here cause if this is a read operation we won't get called back, 
        // and our finializer isn't called. 
        if ( ( _streamMode & Stgm.ReadWrite ) != Stgm.ReadWrite )
        {
            Marshal.ReleaseComObject( _stream );
            _stream = null;
        }
        return HResult.S_OK;
    }
    
    int IPropertyStore.Commit()
    {
        bool result = false;
    
        if ( _stream != null )
        {
            result = WriteStream( _stream );
            Marshal.ReleaseComObject( _stream );
            _stream = null;
        }
    
        return result ? HResult.S_OK : HResult.E_FAIL;
    }
    
    .

È stato utile?

Soluzione

Sì, devi aggiungere () il flusso per mantenerlo aperto e mantenere il riferimento vivo correttamente.

Nota che l'indicizzatore utilizzerà il gestore della proprietà per aprire anche il file.Quindi, se perde l'oggetto Stream, il file rimarrà aperto.È possibile utilizzare il Procexp Sysinternals per dire quale processo ha aperto il file o procone per dire quali chiamate e parametri utilizzati.

Altri suggerimenti

Explorer tenta di garantire che non interferisca con altre applicazioni che potrebbero avere il file aperto.Il file potrebbe essere legittimamente in uso da un'altra applicazione?C'è un gestore di anteprima aperto?

A volte, vediamo i gestori di proprietà che manteniamo i loro flussi aperti più a lungo del necessario (o i gestori basati su file che aprono il file con autorizzazioni restrittive).Puoi verificare se stai rilasciando il flusso in modo tempestivo?

Infine, non penso che sia correlato al tuo problema immediato, ma usando le estensioni di shell .NET non è supportato.Si consiglia di non essere incorporato in qualsiasi prodotto.

-ben

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top