IPaper::Simpan
Fokus utama dalam kode sampel ini adalah bagaimana COPaper dapat memuat dan menyimpan data kertasnya dalam file campuran. Implementasi metode IPaper, Load, dan Save dibahas secara rinci.
Berikut ini adalah metode IPaper::Save dari Paper.cpp.
STDMETHODIMP COPaper::CImpIPaper::Save(
SHORT nLockKey,
IStorage* pIStorage)
{
HRESULT hr = E_FAIL;
IStream* pIStream;
ULONG ulToWrite, ulWritten;
if (OwnThis())
{
if (m_bLocked && m_cLockKey == nLockKey && NULL != pIStorage)
{
// Use the COM service to mark this compound file as one
// that is handled by our server component, DllPaper.
WriteClassStg(pIStorage, CLSID_DllPaper);
// Use the COM Service to write user-readable clipboard
// format into the compound file.
WriteFmtUserTypeStg(pIStorage, m_ClipBdFmt,
TEXT(CLIPBDFMT_STR));
// Create the stream to be used for the actual paper data.
// Call it "PAPERDATA".
hr = pIStorage->CreateStream(
STREAM_PAPERDATA_USTR,
STGM_CREATE | STGM_WRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
0,
0,
&pIStream);
if (SUCCEEDED(hr))
{
// Obtained a stream. Write data to it.
// First, write PAPER_PROPERTIES structure.
m_PaperProperties.lInkArraySize = m_lInkDataEnd+1;
m_PaperProperties.crWinColor = m_crWinColor;
m_PaperProperties.WinRect.right = m_WinRect.right;
m_PaperProperties.WinRect.bottom = m_WinRect.bottom;
ulToWrite = sizeof(PAPER_PROPERTIES);
hr = pIStream->Write(&m_Paper_Properties, ulToWrite,
&ulWritten);
if (SUCCEEDED(hr) && ulToWrite != ulWritten)
hr = STG_E_CANTSAVE;
if (SUCCEEDED(hr))
{
// Now, write the complete array of Ink Data.
ulToWrite = m_PaperProperties.lInkArraySize *
sizeof(INKDATA);
hr = pIStream->Write(m_paInkData, ulToWrite, &ulWritten);
if (SUCCEEDED(hr) && ulToWrite != ulWritten)
hr = STG_E_CANTSAVE;
}
// Release the stream.
pIStream->Release();
}
}
UnOwnThis();
}
// Notify all other connected clients that Paper is now saved.
if (SUCCEEDED(hr))
m_pBackObj->NotifySinks(PAPER_EVENT_SAVED, 0, 0, 0, 0);
return hr;
}
Dalam hubungan klien dan server ini, COPaper tidak membuat file campuran yang digunakan untuk menyimpan data kertas. Untuk metode Simpan dan Muat , klien meneruskan penunjuk antarmuka IStorage untuk file campuran yang ada. Kemudian menggunakan IStorage untuk menulis dan membaca data dalam file campuran tersebut. Di IPaper::Simpan di atas, beberapa jenis data disimpan.
CLSID untuk DllPaper, CLSID_DllPaper, diserialisasikan dan disimpan dalam aliran khusus yang dikontrol COM dalam objek penyimpanan yang disebut "\001CompObj". Fungsi layanan WriteClassStg melakukan penyimpanan ini. Data CLSID yang disimpan ini dapat digunakan untuk mengaitkan konten penyimpanan dengan komponen DllPaper yang dibuat dan dapat menafsirkannya. Dalam sampel ini, penyimpanan akar diteruskan oleh StoClien, dan dengan demikian seluruh file campuran dikaitkan dengan komponen DllPaper. Data CLSID ini dapat diambil nanti dengan panggilan ke fungsi layanan ReadClassStg .
Karena DllPaper menangani data yang dapat diedit, juga sesuai untuk merekam format clipboard dalam penyimpanan. Fungsi layanan WriteFmtUserTypeStg dipanggil untuk menyimpan penentuan format clipboard dan nama yang dapat dibaca pengguna untuk format tersebut. Nama yang dapat dibaca pengguna dimaksudkan untuk tampilan GUI dalam daftar pilihan. Nama yang diteruskan di atas menggunakan makro, CLIPBDFMT_STR, yang didefinisikan sebagai "DllPaper 1.0" di Paper.h. Data clipboard yang disimpan ini dapat diambil nanti dengan panggilan ke fungsi layanan ReadFmtUserTypeStg. Fungsi ini mengembalikan nilai string yang dialokasikan menggunakan alokator memori tugas. Pemanggil bertanggung jawab untuk membebaskan string.
Simpan berikutnya membuat aliran di penyimpanan untuk data kertas COPaper. Aliran disebut "PAPERDATA" dan diteruskan menggunakan makro STREAM_PAPERDATA_USTR. Metode IStorage::CreateStream mengharuskan string ini berada di Unicode. Karena string diperbaiki pada waktu kompilasi, makro didefinisikan sebagai Unicode dalam Paper.h.
#define STREAM_PAPERDATA_USTR L"PAPERDATA"
'L' sebelum string, menunjukkan LONG, mencapai ini.
Metode CreateStream membuat dan membuka aliran dalam penyimpanan yang ditentukan. Penunjuk antarmuka IStream untuk aliran baru diteruskan dalam variabel penunjuk antarmuka penelepon. AddRef dipanggil pada penunjuk antarmuka ini dalam CreateStream, dan pemanggil harus melepaskan pointer ini setelah menggunakannya. Metode CreateStream melewati banyak bendera mode akses, sebagai berikut.
STGM_CREATE | STGM_WRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE
STGM_CREATE membuat aliran baru atau menimpa salah satu nama yang sama yang sudah ada. STGM_WRITE membuka aliran dengan izin tulis. STGM_DIRECT membuka aliran untuk akses langsung, dibandingkan dengan akses yang ditransaksikan. STGM_SHARE_EXCLUSIVE membuka file untuk penggunaan eksklusif dan tidak dibagikan oleh pemanggil.
Setelah aliran PAPERDATA berhasil dibuat, antarmuka IStream digunakan untuk menulis ke dalam aliran. Metode IStream::Write digunakan untuk terlebih dahulu menyimpan konten struktur PAPER_PROPERTIES. Ini pada dasarnya adalah header properti di bagian depan aliran. Karena nomor versi adalah hal pertama dalam file, nomor tersebut dapat dibaca secara independen untuk menentukan cara menangani data yang mengikuti. Jika jumlah data yang benar-benar ditulis tidak sama dengan jumlah yang diminta, metode Simpan dibatalkan, dan mengembalikan STG_E_CANTSAVE.
Menyimpan seluruh array data tinta ke dalam aliran itu sederhana.
// Now write the complete array of Ink Data.
ulToWrite = m_PaperProperties.lInkArraySize * sizeof(INKDATA);
hr = pIStream->Write(m_paInkData, ulToWrite, &ulWritten);
if (SUCCEEDED(hr) && ulToWrite != ulWritten)
hr = STG_E_CANTSAVE;
Karena metode IStream::Write beroperasi pada array byte, jumlah byte data tinta yang disimpan dalam array dihitung dan operasi tulis dimulai pada awal array. Jika jumlah data yang benar-benar ditulis tidak sama dengan jumlah yang diminta, metode Simpan mengembalikan STG_E_CANTSAVE.
Setelah aliran ditulis, metode IPaper::Save merilis pointer IStream yang digunakannya.
Metode Simpan juga memanggil klien IPaperSink (dalam metode CoPaper internal NotifySinks) untuk memberi tahu klien bahwa operasi penyimpanan selesai. Pada titik ini, metode Simpan kembali ke klien panggilan, yang biasanya akan merilis penunjuk IStorage .