Win32 API 日本語リファレンス
ホームSystem.Com.StructuredStorage › IPersistStorage

IPersistStorage

COM
IID0000010a-0000-0000-c000-000000000046継承元IPersist自前メソッド開始 vtbl4

公式ドキュメント

コンテナーアプリケーションが、格納しているオブジェクトの 1 つにストレージオブジェクトを渡し、そのストレージオブジェクトの読み込みと保存を行えるようにします。

メソッド 6

vtbl = vtable インデックス(0始まり)。HSP等からCOMメソッドをインデックス指定で呼ぶ際に使用します。0〜2 は IUnknown。

vtbl 4 HRESULT IsDirty()

オブジェクトが、現在のストレージに最後に保存されてから変更されたかどうかを判定します。

戻り値

このメソッドは、オブジェクトが変更されたことを示すために S_OK を返します。それ以外の場合は S_FALSE を返します。

解説(Remarks)

オブジェクトを閉じる前に保存すべきかどうかを判定するには、このメソッドを使用します。オブジェクトのダーティフラグは、IPersistStorage::Save メソッドで条件付きでクリアされます。

たとえば、各オブジェクトに対して IPersistStorage::IsDirty メソッドを呼び出し、その後ダーティなオブジェクトに対してのみ IPersistStorage::Save メソッドを呼び出すことで、File Save 操作を最適化できます。

呼び出し側への注意

エラーの戻りコードは、いずれもオブジェクトが変更されたことを示すものとして扱う必要があります。このメソッドが明示的に S_FALSE を返さない限り、オブジェクトは保存しなければならないと想定してください。

実装側への注意

格納しているオブジェクトを持たないオブジェクトは、単に自身のダーティフラグを確認して適切な結果を返します。

1 つ以上のオブジェクトを格納しているコンテナーは、格納しているオブジェクトのいずれかが最後に保存されてから変更された場合に設定される、内部のダーティフラグを維持する必要があります。

vtbl 5 HRESULT InitNew(IStorage* pStg)

新しいストレージオブジェクトを初期化します。

pStgIStorage*in初期化される新しいストレージオブジェクトへの IStorage ポインター。コンテナーは、自身のストレージオブジェクト内に入れ子のストレージオブジェクトを作成します(IStorage::CreateStorage を参照)。その後、コンテナーは WriteClassStg 関数を呼び出して、新しいストレージオブジェクトをオブジェクトクラス識別子(CLSID)で初期化します。

戻り値

このメソッドは次の値を返すことがあります。

戻りコード 説明
S_OK
メソッドは正常に完了しました。
CO_E_ALREADYINITIALIZED
オブジェクトは、IPersistStorage::Load メソッドまたは IPersistStorage::InitNew メソッドのいずれかへの以前の呼び出しによって、すでに初期化されています。
E_OUTOFMEMORY
メモリ不足のため、ストレージオブジェクトは初期化されませんでした。
E_FAIL
メモリ不足以外の何らかの理由により、ストレージオブジェクトは初期化されませんでした。

解説(Remarks)

コンテナーアプリケーションは、たとえば InsertObject コマンドで新しいオブジェクトを初期化する必要がある場合に、このメソッドを呼び出すことができます。

IPersistStorage インターフェイスをサポートするオブジェクトは、実行中は常に有効なストレージオブジェクトにアクセスできなければなりません。これには、オブジェクトが作成された直後で、まだ永続化されていない時点も含まれます。この間、オブジェクトのコンテナーは IPersistStorage::InitNew の呼び出しを通じて、ストレージへの有効な IStorage ポインターをオブジェクトに提供する必要があります。コンテナーの状態によっては、この目的のために一時ファイルを作成しなければならない場合があります。

オブジェクトが IStorage インスタンスを保持したい場合は、AddRef を呼び出して参照カウントをインクリメントする必要があります。

IPersistStorage::InitNew の呼び出し後、オブジェクトは読み込み済み状態または実行状態のいずれかになります。たとえば、オブジェクトクラスがインプロセスサーバーを持つ場合、オブジェクトは実行状態になります。ただし、オブジェクトが既定のハンドラーを使用する場合、コンテナーによる InitNew の呼び出しはハンドラーの実装を呼び出すだけで、オブジェクトを実行しません。後でコンテナーがオブジェクトを実行すると、ハンドラーがそのオブジェクトに対して InitNew メソッドを呼び出します。

呼び出し側への注意

通常は IPersistStorage::InitNew を直接呼び出すのではなく、次の処理を行う OleCreate ヘルパー関数を呼び出します。
  1. CoCreateInstance 関数を呼び出して、オブジェクトクラスのインスタンスを作成します。
  2. 新しいインスタンスに対して IPersistStorage インターフェイスをクエリします。
  3. InitNew メソッドを呼び出してオブジェクトを初期化します。
コンテナーアプリケーションは、後でオブジェクトに対する操作で使用するために、オブジェクトへの IPersistStorage ポインターをキャッシュする必要があります。

実装側への注意

IPersistStorage::InitNew の実装は、次の手順に従ってオブジェクトを既定の状態に初期化する必要があります。
  1. オブジェクトがこのストレージに自身を保存する際に必要となるストリームやストレージへのポインターを、あらかじめ開いてキャッシュします。
  2. AddRef を呼び出し、渡されたストレージポインターをキャッシュします。
  3. WriteFmtUserTypeStg 関数を呼び出して、オブジェクトのネイティブなクリップボード形式とユーザータイプ文字列をストレージオブジェクトに書き込みます。
  4. オブジェクトのダーティフラグを設定します。
最初の 2 つの手順は、メモリが少ない状況でもオブジェクトが自身を保存できるようにするうえで特に重要です。ストリームおよびストレージのインターフェイスへのポインターをあらかじめ開いて保持しておくことで、このストレージへの保存操作がメモリ不足によって失敗しないことが保証されます。

このメソッドの実装は、すでに初期化された後に IPersistStorage::InitNew メソッドまたは IPersistStorage::Load メソッドのいずれかへの呼び出しを受け取った場合、CO_E_ALREADYINITIALIZED エラーコードを返す必要があります。

vtbl 6 HRESULT Load(IStorage* pStg)

既存のストレージからオブジェクトを読み込みます。

pStgIStorage*inオブジェクトの読み込み元となる既存のストレージへの IStorage ポインター。

戻り値

このメソッドは次の値を返すことがあります。

戻りコード 説明
S_OK
メソッドは正常に完了しました。
CO_E_ALREADYINITIALIZED
オブジェクトは、IPersistStorage::Load メソッドまたは IPersistStorage::InitNew メソッドへの以前の呼び出しによって、すでに初期化されています。
E_OUTOFMEMORY
メモリ不足のため、オブジェクトは読み込まれませんでした。
E_FAIL
メモリ不足以外の何らかの理由により、オブジェクトは読み込まれませんでした。

解説(Remarks)

このメソッドは、既存のストレージからオブジェクトを初期化します。コンテナーアプリケーションがこのメソッドを呼び出した場合、オブジェクトは読み込み済み状態になります。既定のハンドラーが呼び出した場合、このメソッドはオブジェクトを実行状態にします。

オブジェクトが読み込み済みまたは実行中の間は、既定のハンドラーまたはオブジェクト自身のいずれかが IStorage ポインターを保持できます。

呼び出し側への注意

通常は IPersistStorage::Load を直接呼び出すのではなく、次の処理を行う OleLoad ヘルパー関数を呼び出します。
  1. オブジェクトクラスの未初期化のインスタンスを作成します。
  2. 新しいインスタンスに対して IPersistStorage インターフェイスをクエリします。
  3. Load を呼び出して、既存のストレージからオブジェクトを初期化します。
また、複合ファイルにオブジェクトを挿入するために(ドラッグアンドドロップやクリップボードの貼り付け操作などで)OleCreateFromData 関数または OleCreateFromFile 関数を呼び出すときにも、このメソッドは間接的に呼び出されます。

コンテナーは、後でオブジェクトに対する操作で使用するために、IPersistStorage ポインターをキャッシュする必要があります。

実装側への注意

実装では、オブジェクトを読み込むために次の手順を実行する必要があります。
  1. ストレージオブジェクト内のオブジェクトのストリームを開き、必要なデータをオブジェクトの内部データ構造に読み込みます。
  2. オブジェクトのダーティフラグをクリアします。
  3. AddRef メソッドを呼び出し、渡されたストレージポインターをキャッシュします。
  4. オブジェクトがこのストレージに自身を保存する際に必要となるストリームやストレージへのポインターを、開いたまま保持してキャッシュします。
  5. オブジェクトに必要なその他の既定の初期化を実行します。
手順 3 と 4 は、メモリが少ない状況でもオブジェクトが自身を保存できるようにするうえで特に重要です。ストレージおよびストリームのインターフェイスへのポインターを保持しておくことで、このストレージへの保存操作がメモリ不足によって失敗しないことが保証されます。

このメソッドの実装は、すでに初期化された後に IPersistStorage::InitNew メソッドまたは IPersistStorage::Load メソッドのいずれかへの呼び出しを受け取った場合、CO_E_ALREADYINITIALIZED エラーコードを返す必要があります。

vtbl 7 HRESULT Save(IStorage* pStgSave, BOOL fSameAsLoad)

オブジェクトと、それが格納しているすべての入れ子オブジェクトを、指定されたストレージオブジェクトに保存します。オブジェクトは NoScribble モードに入ります。

pStgSaveIStorage*inオブジェクトの保存先となるストレージへの IStorage ポインター。
fSameAsLoadBOOLin

指定されたストレージが、IPersistStorage::InitNewIPersistStorage::Load、または IPersistStorage::SaveCompleted のいずれかの呼び出しによってオブジェクトに渡された現在のストレージであるかどうかを示します。

このパラメーターは、Save As(名前を付けて保存)または Save A Copy To(コピーの保存)操作を実行する場合、あるいは完全な保存を実行する場合に FALSE に設定されます。後者の場合、このメソッドは一時ファイルに保存し、元のファイルを削除して、一時ファイルの名前を変更します。

このパラメーターは、メモリが少ない状況で完全な保存を実行する場合、またはダーティなコンポーネントのみを保存する高速な増分保存を実行する場合に TRUE に設定されます。

戻り値

このメソッドは次の値を返すことがあります。

戻りコード 説明
S_OK
メソッドは正常に完了しました。
STG_E_MEDIUMFULL
ディスクの空き容量不足のため、オブジェクトは保存されませんでした。
E_FAIL
ディスクの空き容量不足以外のエラーにより、オブジェクトを保存できませんでした。

解説(Remarks)

このメソッドは、オブジェクトと、それが格納しているすべての入れ子オブジェクトを、指定されたストレージに保存します。また、オブジェクトを NoScribble モードにします。そのため、その後 IPersistStorage::SaveCompleted メソッドの呼び出しによってオブジェクトが Normal モードに戻されるまで、オブジェクトは自身のストレージに書き込むことができません。

ストレージオブジェクトが、読み込み元または作成元と同じである場合、保存操作ではストレージオブジェクトに増分変更を書き込める場合があります。それ以外の場合は、完全な保存を行う必要があります。

このメソッドは、入れ子オブジェクトを保存するために、IPersistStorage::Save メソッド、OleSave 関数、または IStorage::CopyTo メソッドを再帰的に呼び出します。

このメソッドは IStorage::Commit メソッドを呼び出しません。また、CLSID をストレージオブジェクトに書き込むこともしません。これらの作業はいずれも呼び出し側の責任です。

呼び出し側への注意

通常は IPersistStorage::Save を直接呼び出すのではなく、次の手順を実行する OleSave ヘルパー関数を呼び出します。
  1. WriteClassStg 関数を呼び出して、オブジェクトのクラス識別子をストレージに書き込みます。
  2. IPersistStorage::Save メソッドを呼び出します。
  3. 必要に応じて、ストレージオブジェクトに対して IStorage::Commit メソッドを呼び出します。
その後、コンテナーアプリケーションは保存を完了するために必要なその他の操作を実行し、各オブジェクトに対して SaveCompleted メソッドを呼び出します。

埋め込みオブジェクトが IPersistStorage::Save メソッドを入れ子オブジェクトに渡す場合、入れ子オブジェクトに対してこのメソッドを呼び出す前に、自身の IPersistStorage::SaveCompleted メソッドへの呼び出しを受け取る必要があります。

vtbl 8 HRESULT SaveCompleted(IStorage* pStgNew)

オブジェクトに、自身のストレージオブジェクトへ書き込めるようになったことを通知します。

pStgNewIStorage*in保存前のストレージオブジェクトと異なる場合の、新しいストレージオブジェクトへの IStorage ポインター。保存操作中に現在のストレージオブジェクトが変わらない場合、このポインターは NULL にできます。オブジェクトが HandsOff モードにある場合、このパラメーターは NULL 以外でなければなりません。

戻り値

このメソッドは次の値を返すことがあります。

戻りコード 説明
S_OK
メソッドは正常に完了しました。
E_OUTOFMEMORY
メモリ不足のため、オブジェクトは HandsOff モードまたは NoScribble モードのままになりました。通常、このエラーは、オブジェクトが pStgNew 内の必要なストリームおよびストレージオブジェクトを開けない場合に発生します。
E_INVALIDARG
pStgNew パラメーターが無効です。通常、このエラーは、オブジェクトが HandsOff モードにあるときに pStgNewNULL である場合に発生します。
E_UNEXPECTED
オブジェクトが Normal モードにあり、IPersistStorage::Save または IPersistStorage::HandsOffStorage への以前の呼び出しがありませんでした。

解説(Remarks)

このメソッドは、オブジェクトに、Normal モードに戻って再び自身のストレージオブジェクトに書き込めるようになったことを通知します。オブジェクトは NoScribble モードまたは HandsOff モードを抜けます。

オブジェクトが HandsOff モードから戻る場合、pStgNew パラメーターは NULL 以外でなければなりません。HandsOffFromNormal モードでは、このパラメーターは、IPersistStorage::HandsOffStorage メソッドによって取り消されたストレージオブジェクトを置き換える、新しいストレージオブジェクトです。このストレージオブジェクト内のデータは、取り消されたストレージオブジェクトのデータのコピーです。HandsOffAfterSave モードでは、このデータは直近に保存されたデータと同じです。取り消されたストレージオブジェクト内のデータとは同じではありません。

オブジェクトが NoScribble モードから戻る場合、pStgNew パラメーターは NULL でも NULL 以外でもかまいません。NULL の場合、オブジェクトは再び自身のストレージオブジェクトにアクセスできます。NULL 以外の場合、コンポーネントオブジェクトは、自身の HandsOffStorage メソッドへの呼び出しを受け取ったかのように振る舞う必要があります。コンポーネントオブジェクトがこの呼び出しをシミュレートできない場合、そのコンテナーは実際に HandsOffStorage メソッドを呼び出す準備をしておく必要があります。

このメソッドは、読み込み済みまたは実行中のすべての入れ子オブジェクトを再帰的に呼び出す必要があります。

このメソッドがエラーコードを返した場合、オブジェクトは Normal モードに戻されません。そのため、コンテナーオブジェクトは別の保存方法を試すことができます。

vtbl 9 HRESULT HandsOffStorage()

オブジェクトに、コンテナーから渡されたすべてのストレージオブジェクトを解放し、HandsOff モードに入るよう指示します。

戻り値

このメソッドは、オブジェクトが HandsOff モードに正常に入ったことを示すために S_OK を返します。

解説(Remarks)

このメソッドは、オブジェクトに、保持しているすべてのストレージオブジェクトを解放させ、その後の IPersistStorage::SaveCompleted 呼び出しまで HandsOff モードに入らせます。HandsOff モードでは、オブジェクトは何もできず、機能する操作は閉じる操作のみです。

コンテナーアプリケーションは通常、完全な保存またはメモリが少ない状況での完全な保存操作の際に、オブジェクトに現在のストレージへのすべてのポインターを強制的に解放させるために、このメソッドを呼び出します。これらのシナリオでは、HandsOffStorage の呼び出しは OleSave または IPersistStorage::Save のいずれかの呼び出しの後に行われ、オブジェクトを HandsOffAfterSave モードにします。このメソッドを呼び出すことは、コンテナーアプリケーションが完全な保存の一環として現在のファイルを削除できるようにするため、またはメモリが少ない状況での保存の一環として IRootStorage::SwitchToFile メソッドを呼び出せるようにするために必要です。

コンテナーアプリケーションは、オブジェクトが Normal モードにあるときに、オブジェクトを HandsOffFromNormal モードにするためにもこのメソッドを呼び出します。

コンポーネントオブジェクトが HandsOffAfterSave モードまたは HandsOffFromNormal モードのいずれかにある間は、そのオブジェクトに対するほとんどの操作が失敗します。そのため、コンテナーはできるだけ早くオブジェクトを Normal モードに戻す必要があります。コンテナーアプリケーションは、IPersistStorage::SaveCompleted メソッドを呼び出すことでこれを行い、このメソッドは新しいストレージオブジェクトのストレージポインターをコンポーネントオブジェクトに返します。

実装側への注意

このメソッドは、入れ子のストリームやストレージへのポインターを含め、現在のストレージオブジェクトへのすべてのポインターを解放する必要があります。オブジェクトが入れ子オブジェクトを格納している場合、コンテナーアプリケーションは、読み込み済みまたは実行中のすべての入れ子オブジェクトに対して、このメソッドを再帰的に呼び出す必要があります。
出典・ライセンス: 上記「公式ドキュメント」の内容は Microsoft の Win32 API ドキュメント(MicrosoftDocs/sdk-api)を日本語に翻訳・改変したものです。© Microsoft Corporation. CC BY 4.0 で提供。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)

HSP用 COM定義

#usecom / #comfunc によるHSPのCOM呼び出し定義。数字は vtbl インデックス(0始まり)。クラスIDが無い場合 #usecom の末尾は "{}"、ある場合は "{CLSID}"

#define global IID_IPersistStorage "{0000010A-0000-0000-C000-000000000046}"
#usecom global IPersistStorage IID_IPersistStorage "{}"
#comfunc global IPersistStorage_IsDirty          4
#comfunc global IPersistStorage_InitNew          5 sptr
#comfunc global IPersistStorage_Load             6 sptr
#comfunc global IPersistStorage_Save             7 sptr,int
#comfunc global IPersistStorage_SaveCompleted    8 sptr
#comfunc global IPersistStorage_HandsOffStorage  9
; ※数字は vtbl インデックス(0始まり)。0/1/2 は IUnknown(QueryInterface/AddRef/Release)。
; ※このインターフェースは直接 CoCreateInstance するクラスIDが無いため "{}"(他メソッド/アクティベーションで取得)。
; ※ハンドル/void*等の不透明ポインタは IronHSP では intptr 指定が可能。