350 lines
12 KiB
C++
350 lines
12 KiB
C++
/**************************************************************************
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|