今回作成することになるコンテナアプリケーションは、一連のオブジェクトをファイルに保存する機能を備えています。各オブジェクトは保存時に表示されていた適切な位置に描画されることになります。構造化ストレージを作成することになります。このメソッドでは最上位のルートストレージを作成します。lpszFileNameがNULLの場合は、一時ファイルに支持される構造化ストレージをStgCreateDocfileで作成します。STGM_TRANSACTEDを指定していることから、ストレージに対する書き込みはCommitを呼び出すまでファイルには反映されません。STGM_SHARE_EXCLUSIVEを指定すると後述のIRootStorage::SwitchToFileの呼び出しで失敗するため、指定しないようにします。WriteClassStgでルートストレージにCLSIDを書き込んでいるのは、作成したファイルを一意に識別できるようにするためです。これは必須な処理ではありません。一連のオブジェクトの数や名前といった補足情報を書き込むためです。ストリームにはSTGM_SHARE_EXCLUSIVEが必須であり、STGM_TRANSACTEDは指定することができません。オブジェクト自体はこのストリームではなく、別個サブストレージに格納されることになります。lpszFileNameがNULLでない場合は、StgOpenStorageでストレージをオープンします。ReadClassStgで取得したCLSIDとファイルのCLSIDを比較します。Destroyという自作メソッドで破棄します。これはルートストレージではなく、ルートストレージの直下に作成したサブストレージです。サブストレージの作成は、前々節で取り上げたCreateObjectで行っています。&pStorage);CreateStorageを呼び出せば、m_pRootStorageの下にサブストレージを作成することができます。1"のような形にしています。取得したpStorageはCSite::Initによってメンバ変数に保存されることになります。コンテナのメニューから「保存」を選択した場合は、SaveObjectが呼ばれます。ここでは、現在作成されている一連のオブジェクトがファイルに保存されます。TEXT("オブジェクトが作成されていません。TRUE;}m_nObjectCountが0である場合は保存するオブジェクトが存在しないため、処理を続行しないようにします。そこで選択したファイルが第2引数に返されます。その前にSeekを呼び出すことで常にストリームの先頭から書き込まれるようにしておきます。その後に個々のオブジェクトの位置(RECT構造体)が書き込まれていきます。p->Saveは内部でOleSaveを呼び出し、これによってオブジェクトがサブストレージにデータを保存します。このためにはルートストレージの出力先となるファイルパスがszFilePathのものでなければなりません。IRootStorage::SwitchToFileによって出力先を変更します。コンテナのメニューから「開く」を選択した場合は、LoadObjectが呼ばれます。ここでは、保存していたオブジェクトがロードされます。TRUE;}ファイルを構造化ストレージとしてオープンするには、CreateRootStorageにファイルパスを指定します。ファイルを開くダイアログから取得できます。Readでオブジェクトの数を取得します。SaveObjectでは最初にオブジェクトの数を書き込んでいたため、これは成立します。オブジェクトの数を取得したら、その数だけをオブジェクトをロードすることになります。これをOpenStorageに指定することで、オブジェクトが格納されているサブストレージをオープンします。オブジェクトを識別するIOleObjectを取得できます。オブジェクトと通信するためのCSiteを作成します。Initを呼び出すことで、オブジェクトやサブストレージなどの各情報をメンバ変数に保存します。