.NET CLR 4.0 がサイド バイ サイド (SxS) 操作をサポートするようになったので、マネージ コードでシェル拡張機能を記述できるようになりました。私はこれを試み、IPropertyStore、IInitializeWithStream、および IPropertyStoreCapabilities を実装するプロパティ ハンドラーのコーディングに成功しました。
ハンドラーは正常に動作し、エクスプローラーを介してファイルを参照するときに期待どおりに呼び出されます。また、プレビュー パネルとファイル プロパティの「詳細」パネルにカスタム プロパティを表示する際にも問題なく動作します。
しかし、プレビュー パネルでプロパティを編集しようとして [保存] をクリックすると、ファイルが Windows エクスプローラーで開かれていることを示す「ファイルは使用中です」というエラーが表示されます。
いくつかのヒント:
- エクスプローラーが IInitializeWithStream.Initialize を呼び出すと、STGM プロパティが STGM_SHARE_DENY_WRITE に設定されます。
- そして、エクスプローラーが IPropertyStore.SetValue または IPropertyStore.Commit を呼び出すことはありませんでした。
- 同じファイル プロパティに対して、異なるスレッドでハンドラが繰り返し呼び出されています。
では、プロパティの保存を機能させるには、何を変更 (またはレジストリに設定) する必要がありますか?
アップデート:
ベンのおかげでうまくいきました。「難しい部分」(少なくとも私にとって) は、COM 相互運用が PropertyHandler で Dispose または Finalize を呼び出すことは決してないことを理解することでした。これは、GC が実行されるまで、処理したファイルを開いたままにしていました。
幸いなことに、「プロパティ ハンドラー プロトコル」は、IInitializeWithSream.Initialize() が ReadValue() に対して呼び出されると、streamMode が ReadOnly になり、SetValue() に対して呼び出されると、streamMode が ReadWrite になり、Commit() が呼び出されるように機能します。最後に。
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;
}