/************************************************************************** THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Copyright 2001 Microsoft Corporation. All Rights Reserved. **************************************************************************/ /************************************************************************** File: Persist.cpp Description: CTSFEditWnd::_Save() and _Load() implementation **************************************************************************/ /************************************************************************** #include statements **************************************************************************/ #include "TSFEdit.h" #include "PropLdr.h" /************************************************************************** global variables and definitions **************************************************************************/ /************************************************************************** local function prototypes **************************************************************************/ #define BLOCK_SIZE 256 void CTSFEditWnd::_SaveToFile(LPTSTR pszFile) { if(pszFile) { HANDLE hFile; hFile = CreateFile( pszFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(INVALID_HANDLE_VALUE != hFile) { IStream *pStream; //create a stream on global memory if(SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &pStream))) { LARGE_INTEGER li; _Save(pStream); //initialize the file SetFilePointer(hFile, 0, NULL, FILE_BEGIN); SetEndOfFile(hFile); //set the stream pointer to the start of the stream li.QuadPart = 0; pStream->Seek(li, STREAM_SEEK_SET, NULL); //write the contents of the stream to the file BYTE buffer[BLOCK_SIZE]; ULONG uRead; HRESULT hr; uRead = 0; hr = pStream->Read(buffer, BLOCK_SIZE, &uRead); while(uRead > 0) { DWORD dwWritten; WriteFile(hFile, buffer, uRead, &dwWritten, NULL); uRead = 0; hr = pStream->Read(buffer, BLOCK_SIZE, &uRead); } pStream->Release(); } CloseHandle(hFile); } } } /************************************************************************** CTSFEditWnd::_Save() **************************************************************************/ void CTSFEditWnd::_Save(IStream *pStream) { if(pStream) { HRESULT hr; //write the plain UNICODE text into the stream LPWSTR pwsz; LONG cch; ULONG uWritten; LARGE_INTEGER li; ULONG uSize; //set the stream pointer to the start of the stream li.QuadPart = 0; pStream->Seek(li, STREAM_SEEK_SET, NULL); //get the text if(SUCCEEDED(_GetText(&pwsz, &cch))) { TF_PERSISTENT_PROPERTY_HEADER_ACP PropHeader; //write the size, in BYTES, of the text uSize = cch * sizeof(WCHAR); hr = pStream->Write(&uSize, sizeof(ULONG), &uWritten); //write the text, including the NULL_terminator, into the stream hr = pStream->Write(pwsz, uSize, &uWritten); //free the memory allocated by _GetText GlobalFree(pwsz); //enumerate the properties in the context IEnumTfProperties *pEnumProps; hr = m_pContext->EnumProperties(&pEnumProps); if(SUCCEEDED(hr)) { ITfProperty *pProp; ULONG uFetched; while(SUCCEEDED(pEnumProps->Next(1, &pProp, &uFetched)) && uFetched) { //enumerate all the ranges that contain the property IEnumTfRanges *pEnumRanges; hr = pProp->EnumRanges(m_EditCookie, &pEnumRanges, NULL); if(SUCCEEDED(hr)) { IStream *pTempStream; //create a temporary stream to write the property data to hr = CreateStreamOnHGlobal(NULL, TRUE, &pTempStream); if(SUCCEEDED(hr)) { ITfRange *pRange; while(SUCCEEDED(pEnumRanges->Next(1, &pRange, &uFetched)) && uFetched) { //reset the temporary stream's pointer li.QuadPart = 0; pTempStream->Seek(li, STREAM_SEEK_SET, NULL); //get the property header and data for the range hr = m_pServices->Serialize(pProp, pRange, &PropHeader, pTempStream); /* Write the property header into the primary stream. The header also contains the size of the property data. */ hr = pStream->Write(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uWritten); //reset the temporary stream's pointer li.QuadPart = 0; pTempStream->Seek(li, STREAM_SEEK_SET, NULL); //copy the property data from the temporary stream into the primary stream ULARGE_INTEGER uli; uli.QuadPart = PropHeader.cb; hr = pTempStream->CopyTo(pStream, uli, NULL, NULL); pRange->Release(); } pTempStream->Release(); } pEnumRanges->Release(); } pProp->Release(); } pEnumProps->Release(); } //write a property header with zero size and guid into the stream as a terminator ZeroMemory(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP)); hr = pStream->Write(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uWritten); } } } /************************************************************************** CTSFEditWnd::_LoadFromFile() **************************************************************************/ void CTSFEditWnd::_LoadFromFile(LPTSTR pszFile) { if(pszFile) { HANDLE hFile; hFile = CreateFile( pszFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(INVALID_HANDLE_VALUE != hFile) { IStream *pStream; //create a stream on global memory if(SUCCEEDED(CreateStreamOnHGlobal(NULL, TRUE, &pStream))) { //read the contents of the file into the stream LARGE_INTEGER li; //set the stream pointer to the start of the stream li.QuadPart = 0; pStream->Seek(li, STREAM_SEEK_SET, NULL); //write the contents of the stream to the file BYTE buffer[BLOCK_SIZE]; ULONG uRead; HRESULT hr; uRead = 0; ReadFile(hFile, buffer, BLOCK_SIZE, &uRead, NULL); while(uRead > 0) { ULONG uWritten; hr = pStream->Write(buffer, uRead, &uWritten); uRead = 0; ReadFile(hFile, buffer, BLOCK_SIZE, &uRead, NULL); } _Load(pStream); pStream->Release(); } CloseHandle(hFile); } } } /************************************************************************** CTSFEditWnd::_Load() **************************************************************************/ void CTSFEditWnd::_Load(IStream *pStream) { if(NULL == pStream) { return; } //can't do this if someone has a lock if(_IsLocked(TS_LF_READ)) { return; } _ClearText(); HRESULT hr; ULONG uRead; LARGE_INTEGER li; ULONG uSize; //set the stream pointer to the start of the stream li.QuadPart = 0; pStream->Seek(li, STREAM_SEEK_SET, NULL); //get the size of the text, in BYTES. This is the first ULONG in the stream hr = pStream->Read(&uSize, sizeof(ULONG), &uRead); if(SUCCEEDED(hr) && (sizeof(ULONG) == uRead)) { LPWSTR pwsz; //allocate a buffer for the text plus one NULL character pwsz = (LPWSTR)GlobalAlloc(GPTR, uSize + sizeof(WCHAR)); if(NULL != pwsz) { //get the plain UNICODE text from the stream hr = pStream->Read(pwsz, uSize, &uRead); if(SUCCEEDED(hr) && (uSize == uRead)) { TF_PERSISTENT_PROPERTY_HEADER_ACP PropHeader; //put the text into the edit control, but don't send a change notification BOOL fOldNotify = m_fNotify; m_fNotify = FALSE; SetWindowTextW(m_hwndEdit, pwsz); m_fNotify = fOldNotify; /* Read each property header and property data from the stream. The list of properties is terminated by a TF_PERSISTENT_PROPERTY_HEADER_ACP structure with a cb member of zero. */ hr = pStream->Read(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uRead); while( SUCCEEDED(hr) && (sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP) == uRead) && (0 != PropHeader.cb)) { ITfProperty *pProp; hr = m_pContext->GetProperty(PropHeader.guidType, &pProp); if(SUCCEEDED(hr)) { /* Have TSF read the property data from the stream. This call will request a read lock, so make sure it can be granted or else this method will fail. */ CTSFPersistentPropertyLoader *pLoader = new CTSFPersistentPropertyLoader(&PropHeader, pStream); hr = m_pServices->Unserialize(pProp, &PropHeader, NULL, pLoader); pProp->Release(); } hr = pStream->Read(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uRead); } } GlobalFree(pwsz); } } }