1308 lines
34 KiB
C++
1308 lines
34 KiB
C++
//------------------------------------------------------------------------------
|
|
//
|
|
// File: impfile.cpp
|
|
// Copyright (C) 1995-1997 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// Purpose:
|
|
// Implementation of CLocImpFile, which provides the ILocFile interface for
|
|
// the parser.
|
|
//
|
|
// MAJOR IMPLEMENTATION FILE.
|
|
//
|
|
// Owner:
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
#include "dllvars.h"
|
|
#include "resource.h"
|
|
|
|
#include "impfile.h"
|
|
#include "impparse.h"
|
|
#include "xml_supp.h"
|
|
|
|
# define MAX_BUFFER 8192
|
|
|
|
|
|
// TODO: Format constants go here.
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Constructor for CLocImpFile.
|
|
//------------------------------------------------------------------------------
|
|
CLocImpFile::CLocImpFile(
|
|
ILocParser *pParentClass) // Pointer to parent class, normally NULL.
|
|
{
|
|
//
|
|
// C.O.M. initialization
|
|
//
|
|
|
|
m_pParentClass = pParentClass;
|
|
m_ulRefCount = 0;
|
|
|
|
//
|
|
// IMP file initialization
|
|
//
|
|
|
|
m_pOpenSourceFile = NULL;
|
|
|
|
|
|
m_pReporter = NULL;
|
|
|
|
m_FileType = ftMNCFileType;
|
|
|
|
AddRef();
|
|
IncrementClassCount();
|
|
|
|
m_dwCountOfStringTables = 0;
|
|
m_pstmSourceString = NULL;
|
|
m_pstgSourceStringTable = NULL;
|
|
m_pstgSourceParent = NULL;
|
|
m_pstmTargetString = NULL;
|
|
m_pstgTargetStringTable = NULL;
|
|
m_pstgTargetParent = NULL;
|
|
|
|
m_bXMLBased = false;
|
|
|
|
// Format initialization.
|
|
|
|
// TODO: initialize implementation member variables here.
|
|
|
|
return;
|
|
} // end of CLocImpFile::CLocImpFile()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Destructor for CLocImpFile.
|
|
//------------------------------------------------------------------------------
|
|
CLocImpFile::~CLocImpFile()
|
|
{
|
|
DEBUGONLY(AssertValid());
|
|
|
|
if (m_pOpenSourceFile != NULL)
|
|
{
|
|
m_pOpenSourceFile->Close();
|
|
delete m_pOpenSourceFile;
|
|
}
|
|
|
|
DecrementClassCount();
|
|
|
|
// Format deinitialization.
|
|
|
|
// TODO: perform any implementation cleanup here.
|
|
|
|
return;
|
|
} // end of CLocImpFile::~CLocImpFile()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Increment the object reference count. Return the new reference count.
|
|
//------------------------------------------------------------------------------
|
|
ULONG
|
|
CLocImpFile::AddRef()
|
|
{
|
|
if (m_pParentClass != NULL)
|
|
{
|
|
m_pParentClass->AddRef();
|
|
}
|
|
|
|
return ++m_ulRefCount;
|
|
} // end of CLocImpFile::AddRef()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Decrement the object reference count. If it goes to 0, delete the object.
|
|
// Return the new reference count.
|
|
//------------------------------------------------------------------------------
|
|
ULONG
|
|
CLocImpFile::Release()
|
|
{
|
|
LTASSERT(m_ulRefCount != 0);
|
|
|
|
if (m_pParentClass != NULL)
|
|
{
|
|
m_pParentClass->Release();
|
|
}
|
|
|
|
m_ulRefCount--;
|
|
if (0 == m_ulRefCount)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return m_ulRefCount;
|
|
} // end of CLocImpFile::Release()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Query whether this object supports a given interface.
|
|
//
|
|
// Return values: some kind of result code
|
|
// ppvObj will point to this object if it supports the desired
|
|
// interface, be NULL if not.
|
|
//------------------------------------------------------------------------------
|
|
HRESULT
|
|
CLocImpFile::QueryInterface(
|
|
REFIID iid, // Desired interface.
|
|
LPVOID *ppvObj) // Return pointer to object with interface.
|
|
// Note that it's a hidden double pointer.
|
|
{
|
|
LTASSERT(ppvObj != NULL);
|
|
|
|
if (m_pParentClass != NULL)
|
|
{
|
|
return m_pParentClass->QueryInterface(iid, ppvObj);
|
|
}
|
|
else
|
|
{
|
|
SCODE scRetVal = E_NOINTERFACE;
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if (IID_IUnknown == iid)
|
|
{
|
|
*ppvObj = (IUnknown *)this;
|
|
scRetVal = S_OK;
|
|
}
|
|
else if (IID_ILocFile == iid)
|
|
{
|
|
*ppvObj = (ILocFile *)this;
|
|
scRetVal = S_OK;
|
|
}
|
|
|
|
if (S_OK == scRetVal)
|
|
{
|
|
AddRef();
|
|
}
|
|
return ResultFromScode(scRetVal);
|
|
}
|
|
} // end of CLocImpFile::QueryInterface()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Check object for validity. Asserts if not! (debug only)
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
CLocImpFile::AssertValidInterface()
|
|
const
|
|
{
|
|
AssertValid();
|
|
|
|
return;
|
|
} // end of CLocImpFile::AssertValidInterface()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Open the file and make sure it is the correct type. Return TRUE if it is,
|
|
// FALSE if not or on error.
|
|
//------------------------------------------------------------------------------
|
|
BOOL
|
|
CLocImpFile::OpenFile(
|
|
const CFileSpec &fsFileSpec, // Name of file to open.
|
|
CReporter &Reporter) // Reporter object for messages.
|
|
{
|
|
DEBUGONLY(fsFileSpec.AssertValid());
|
|
DEBUGONLY(Reporter.AssertValid());
|
|
|
|
const CPascalString &pstrFileName = fsFileSpec.GetFileName();
|
|
BOOL fRetVal = FALSE;
|
|
|
|
LTTRACEPOINT("OpenFile()");
|
|
// Set reporter pointer for the duration of this function.
|
|
m_pReporter = &Reporter;
|
|
|
|
try
|
|
{
|
|
CFileException excFile;
|
|
|
|
m_pstrFileName = pstrFileName; // Initialize source filename.
|
|
m_idFile = fsFileSpec.GetFileId();
|
|
|
|
if (m_pOpenSourceFile != NULL)
|
|
{
|
|
// If source file pointer seems to be open already, close it.
|
|
|
|
m_pOpenSourceFile->Close();
|
|
delete m_pOpenSourceFile;
|
|
m_pOpenSourceFile = NULL;
|
|
}
|
|
|
|
// Open the source file. Doesn't throw an exception if the open
|
|
// fails, but does return FALSE and put the info in an exception
|
|
// structure if you supply one.
|
|
|
|
m_pOpenSourceFile = new CLFile;
|
|
fRetVal = m_pOpenSourceFile->Open(m_pstrFileName,
|
|
CFile::modeRead | CFile::shareDenyNone, &excFile);
|
|
if (!fRetVal)
|
|
{
|
|
ReportException(&excFile);
|
|
m_pOpenSourceFile->Abort();
|
|
delete m_pOpenSourceFile;
|
|
m_pOpenSourceFile = NULL;
|
|
// fRetCode is already FALSE.
|
|
}
|
|
else
|
|
{
|
|
// Verify() assumes it is in a try/catch frame.
|
|
|
|
fRetVal = Verify();
|
|
}
|
|
}
|
|
catch(CException *e)
|
|
{
|
|
ReportException(e);
|
|
delete m_pOpenSourceFile;
|
|
m_pOpenSourceFile = NULL;
|
|
fRetVal = FALSE;
|
|
// m_pReporter will be NULLed by normal cleanup code below.
|
|
e->Delete();
|
|
}
|
|
catch(...)
|
|
{
|
|
// Reset the reporter pointer, no idea if it will still be valid by
|
|
// the time the destructor gets called. The only other thing that
|
|
// needs to be cleaned up is the source file, which will be handled in
|
|
// the destructor.
|
|
|
|
m_pReporter = NULL;
|
|
throw;
|
|
}
|
|
|
|
m_pReporter = NULL;
|
|
|
|
return fRetVal;
|
|
} // end of CLocImpFile::OpenFile()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Return the file type (a ft* constant from impfile.h). If you only have one
|
|
// file type, you can just return it directly.
|
|
//------------------------------------------------------------------------------
|
|
FileType
|
|
CLocImpFile::GetFileType()
|
|
const
|
|
{
|
|
return m_FileType;
|
|
} // end of CLocImpFile::GetFileType()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Return the file description in strDesc, according to the file type. If you
|
|
// have only one file type, you can just return a string directly.
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
CLocImpFile::GetFileTypeDescription(
|
|
CLString &strDesc) // Place to return file description string.
|
|
const
|
|
{
|
|
LTVERIFY(strDesc.LoadString(g_hDll, IDS_IMP_FILE_DESC));
|
|
return;
|
|
} // end of CLocImpFile::GetFileTypeDescription()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Return the names of any associated files as a list of strings in lstFiles.
|
|
// Returns TRUE if there are any, FALSE if not.
|
|
//------------------------------------------------------------------------------
|
|
BOOL
|
|
CLocImpFile::GetAssociatedFiles(
|
|
CStringList &lstFiles) // Return associated file names here.
|
|
const
|
|
{
|
|
DEBUGONLY(lstFiles.AssertValid());
|
|
LTASSERT(lstFiles.GetCount() == 0);
|
|
|
|
// TODO: If your files have associated files, put them in lstFiles here.
|
|
UNREFERENCED_PARAMETER(lstFiles);
|
|
|
|
return FALSE;
|
|
} // end of CLocImpFile::GetAssociatedFiles()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Enumerate all the localizable items in this file. Returns TRUE on success,
|
|
// FALSE on error.
|
|
//------------------------------------------------------------------------------
|
|
BOOL
|
|
CLocImpFile::EnumerateFile(
|
|
CLocItemHandler &ihItemHandler, // Localizable-item handler and
|
|
// reporter object all in one!
|
|
const CLocLangId &lid, // Source language ID object.
|
|
const DBID &dbidFileId) // Database ID of file, used as parent
|
|
// for all top-level items in the
|
|
// file.
|
|
{
|
|
DEBUGONLY(ihItemHandler.AssertValid());
|
|
DEBUGONLY(lid.AssertValid());
|
|
DEBUGONLY(dbidFileId.AssertValid());
|
|
|
|
LTTRACEPOINT("EnumerateFile()");
|
|
|
|
// Set reporter pointer for the duration of this function.
|
|
m_pReporter = &ihItemHandler;
|
|
|
|
if (NULL == m_pOpenSourceFile)
|
|
{
|
|
// Source file isn't open, whoops.
|
|
|
|
LTASSERT(0 && "Source file isn't open in CLocImpFile::EnumerateFile()");
|
|
return FALSE;
|
|
}
|
|
|
|
// Retrieve and store the ANSI code page value. Note that some types
|
|
// of files use OEM code pages instead, or even use both. To get the
|
|
// OEM code page, do GetCodePage(cpDos) instead.
|
|
m_cpSource = lid.GetCodePage(cpAnsi);
|
|
|
|
BOOL bRet = TRUE;
|
|
|
|
try
|
|
{
|
|
bRet = EnumerateStrings(ihItemHandler,dbidFileId,FALSE);
|
|
}
|
|
catch(CException *e)
|
|
{
|
|
ReportException(e);
|
|
bRet = FALSE;
|
|
// m_pReporter will be NULLed by normal cleanup code below.
|
|
e->Delete();
|
|
}
|
|
catch (...)
|
|
{
|
|
// Reset the reporter pointer, no idea if it will still be valid by
|
|
// the time the destructor gets called. Reset the process pointer,
|
|
// since it definitely won't be valid! The only other thing that
|
|
// needs to be cleaned up is the source file, which will be handled in
|
|
// the destructor.
|
|
|
|
m_pReporter = NULL;
|
|
throw;
|
|
}
|
|
|
|
m_pReporter = NULL; // Reset reporter pointer.
|
|
|
|
return bRet;
|
|
} // end of CLocImpFile::EnumerateFile()
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Create a new target file be replacing resources in the source file with the
|
|
// localized items from Espresso.
|
|
//------------------------------------------------------------------------------
|
|
BOOL
|
|
CLocImpFile::GenerateFile(
|
|
const CPascalString &pstrTargetFile,// Name of target file.
|
|
CLocItemHandler &ihItemHandler, // Localizable-item handler and
|
|
// reporter object all in one!
|
|
const CLocLangId &lidSource, // Source language ID object.
|
|
const CLocLangId &lidTarget, // Target language ID object.
|
|
const DBID &dbidParent) // Database ID of file, used as
|
|
// parent for all top-level items
|
|
// in the file.
|
|
{
|
|
DEBUGONLY(pstrTargetFile.AssertValid());
|
|
DEBUGONLY(ihItemHandler.AssertValid());
|
|
DEBUGONLY(lidSource.AssertValid());
|
|
DEBUGONLY(lidTarget.AssertValid());
|
|
DEBUGONLY(dbidParent.AssertValid());
|
|
|
|
BOOL fRetVal = FALSE;
|
|
|
|
// Set reporter pointer for the duration of this function.
|
|
m_pReporter = &ihItemHandler;
|
|
|
|
if (NULL == m_pOpenSourceFile)
|
|
{
|
|
// Source file isn't open, whoops.
|
|
|
|
LTASSERT(0 && "Source file isn't open in CLocImpFile::GenerateFile()");
|
|
return FALSE;
|
|
}
|
|
|
|
// Retrieve and store the ANSI code page values for the source and target
|
|
// files. Note that some types of files use OEM code pages instead, or
|
|
// even use both. To get the OEM code page, do GetCodePage(cpDos) instead.
|
|
m_cpSource = lidSource.GetCodePage(cpAnsi);
|
|
m_cpTarget = lidTarget.GetCodePage(cpAnsi);
|
|
|
|
try
|
|
{
|
|
m_pstrTargetFile = pstrTargetFile; // Initialize target filename.
|
|
|
|
CFileStatus fsFileStatus;
|
|
|
|
CLFile::CopyFile(m_pstrFileName,m_pstrTargetFile,FALSE);
|
|
|
|
CLFile::GetStatus(m_pstrTargetFile, fsFileStatus);
|
|
if(fsFileStatus.m_attribute & CFile::readOnly)
|
|
{
|
|
fsFileStatus.m_attribute &= ~CFile::readOnly;
|
|
CLFile::SetStatus(m_pstrTargetFile, fsFileStatus);
|
|
}
|
|
|
|
fRetVal = EnumerateStrings(ihItemHandler,dbidParent,TRUE);
|
|
|
|
}
|
|
catch(CException *e)
|
|
{
|
|
ReportException(e, ImpEitherError);
|
|
fRetVal = FALSE;
|
|
// m_pReporter will be NULLed by normal cleanup code.
|
|
e->Delete();
|
|
}
|
|
catch(...)
|
|
{
|
|
// Generic exception handling is needed here because otherwise
|
|
// target file will not be cleaned up. Also, no idea if reporter
|
|
// pointer will still be valid by the time the destructor is
|
|
// called. The process pointer definitely won't be valid, so reset
|
|
// it too. The source file will be cleaned up by the destructor.
|
|
|
|
m_pReporter = NULL;
|
|
throw;
|
|
}
|
|
|
|
// Cleanup.
|
|
|
|
if (!fRetVal)
|
|
{
|
|
try
|
|
{
|
|
// Nuke the target file if the generate failed.
|
|
|
|
CLFile::Remove(pstrTargetFile);
|
|
}
|
|
catch(CException *e)
|
|
{
|
|
ReportException(e, ImpTargetError);
|
|
// fRetVal is already FALSE
|
|
// m_pReporter will be NULLed by normal cleanup code.
|
|
e->Delete();
|
|
}
|
|
catch(...)
|
|
{
|
|
// Generic exception handling is needed here because otherwise
|
|
// target file will not be cleaned up. Also, no idea if reporter
|
|
// pointer will still be valid by the time the destructor is
|
|
// called. The process pointer is already NULL. The source file
|
|
// will be cleaned up by the destructor.
|
|
|
|
m_pReporter = NULL;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// Normal cleanup code.
|
|
|
|
m_pReporter = NULL; // Reset reporter pointer.
|
|
|
|
return fRetVal;
|
|
} // end of CLocImpFile::GenerateFile()
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// TODO:
|
|
// Verify that a file is a ???, as best we can. When we're reasonably sure,
|
|
// set the reporter confidence level to high -- until then, messages will be
|
|
// discarded, not displayed. This is also the place where m_FileType is set.
|
|
//
|
|
// Returns TRUE if so, FALSE if not or on error, or throws an exception.
|
|
//
|
|
// Normally there is need to catch exceptions in this function, they will
|
|
// be caught and handled by a higher level. To avoid memory leaks, consider
|
|
// using automatic variables or CByteArrays (as described and demonstrated in
|
|
// the utility function FindSignature() below) instead of dynamic allocation.
|
|
//------------------------------------------------------------------------------
|
|
BOOL
|
|
CLocImpFile::Verify()
|
|
{
|
|
DEBUGONLY(AssertValid());
|
|
LTASSERT(m_pReporter != NULL);
|
|
DEBUGONLY(m_pReporter->AssertValid());
|
|
|
|
// ...
|
|
|
|
// Set confidence level to high and return that we recognize this file.
|
|
|
|
m_pReporter->SetConfidenceLevel(CReporter::High);
|
|
return TRUE;
|
|
} // end of CLocImpFile::Verify()
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Reports the exception described by *pException. Since the message can be
|
|
// retrieved directly from the exception, there is no need (as far as reporting
|
|
// goes) to catch or handle different kinds of exceptions separately. Normally,
|
|
// there is no reason for your code to call this function, since under normal
|
|
// circumstances you don't have to catch exceptions.
|
|
//
|
|
// THIS FUNCTION IS USED BY THE FRAMEWORK! DO NOT REMOVE IT!
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
CLocImpFile::ReportException(
|
|
CException *pException, // Exception to be reported.
|
|
ImpFileError WhichFile) // Defaults to ImpSourceError (most common).
|
|
const
|
|
{
|
|
const UINT MAX_MESSAGE = 256;
|
|
|
|
CLString strContext;
|
|
CLString strMessage;
|
|
char *pszMessage;
|
|
|
|
LTASSERT(m_pReporter != NULL);
|
|
DEBUGONLY(m_pReporter->AssertValid());
|
|
|
|
pszMessage = strMessage.GetBuffer(MAX_MESSAGE);
|
|
LTASSERT(pszMessage != NULL);
|
|
pException->GetErrorMessage(pszMessage, MAX_MESSAGE);
|
|
strMessage.ReleaseBuffer();
|
|
|
|
switch (WhichFile)
|
|
{
|
|
case ImpNeitherError: // By convention, report errors not really in any
|
|
// file against the source file.
|
|
case ImpSourceError:
|
|
m_pstrFileName.ConvertToCLString(strContext, CP_ACP);
|
|
break;
|
|
|
|
case ImpTargetError:
|
|
m_pstrTargetFile.ConvertToCLString(strContext, CP_ACP);
|
|
break;
|
|
|
|
case ImpEitherError:
|
|
{
|
|
CLString strSource, strTarget;
|
|
|
|
m_pstrFileName.ConvertToCLString(strSource, CP_ACP);
|
|
m_pstrTargetFile.ConvertToCLString(strTarget, CP_ACP);
|
|
|
|
strContext.Format(g_hDll, IDS_IMP_OR, (const char *) strSource,
|
|
(const char *) strTarget);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
LTASSERT(0 && "WhichFile is bad during CLocImpFile::ReportException");
|
|
break;
|
|
}
|
|
|
|
CContext ctx(strContext, m_idFile, otFile, vProjWindow);
|
|
|
|
m_pReporter->IssueMessage(esError, ctx, strMessage);
|
|
|
|
return;
|
|
} // end of CLocImpFile::ReportException()
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Reports a message to the user. Note that the message will be discarded
|
|
// unless the reporter's confidence level had been set high (see Verify()).
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
CLocImpFile::ReportMessage(
|
|
MessageSeverity sev, // Severity of message.
|
|
// (esError, esWarning, esNote)
|
|
UINT nMsgId, // ID of string resource to load for message.
|
|
ImpFileError WhichFile) // Defaults to ImpSourceError (most common).
|
|
const
|
|
{
|
|
CLString strContext;
|
|
|
|
LTASSERT(m_pReporter != NULL);
|
|
DEBUGONLY(m_pReporter->AssertValid());
|
|
|
|
switch (WhichFile)
|
|
{
|
|
case ImpNeitherError: // By convention, report errors not really in any
|
|
// file against the source file.
|
|
case ImpSourceError:
|
|
m_pstrFileName.ConvertToCLString(strContext, CP_ACP);
|
|
break;
|
|
|
|
case ImpTargetError:
|
|
m_pstrTargetFile.ConvertToCLString(strContext, CP_ACP);
|
|
break;
|
|
|
|
case ImpEitherError:
|
|
{
|
|
CLString strSource, strTarget;
|
|
|
|
m_pstrFileName.ConvertToCLString(strSource, CP_ACP);
|
|
m_pstrTargetFile.ConvertToCLString(strTarget, CP_ACP);
|
|
|
|
strContext.Format(g_hDll, IDS_IMP_OR, (const char *) strSource,
|
|
(const char *) strTarget);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
LTASSERT(0 && "WhichFile is bad during CLocImpFile::ReportMessage");
|
|
break;
|
|
}
|
|
|
|
CContext ctx(strContext, m_idFile, otFile, vProjWindow);
|
|
|
|
m_pReporter->IssueMessage(sev, ctx, g_hDll, nMsgId);
|
|
|
|
return;
|
|
} // end of CLocImpFile::ReportMessage()
|
|
|
|
|
|
#ifdef LTASSERT_ACTIVE
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Asserts if the object is not valid. Any functions you add should probably
|
|
// call this function (in DEBUGONLY()) first thing -- see Verify() and Enum().
|
|
//------------------------------------------------------------------------------
|
|
void
|
|
CLocImpFile::AssertValid()
|
|
const
|
|
{
|
|
// Check base class.
|
|
|
|
CLObject::AssertValid();
|
|
|
|
// Check C.O.M. data. m_pParentClass should always be NULL.
|
|
// Correct range for m_ulRefCount is unknown, but make sure it hasn't
|
|
// wrapped around by checking for less than 100 (if we ever exceed
|
|
// 100 references from below, there's probably something wrong too!).
|
|
|
|
LTASSERT(NULL == m_pParentClass);
|
|
LTASSERT(m_ulRefCount < 100);
|
|
|
|
// Check filename strings.
|
|
|
|
m_pstrFileName.AssertValid();
|
|
m_pstrTargetFile.AssertValid();
|
|
|
|
// If the file object pointers are non-NULL, check the objects.
|
|
|
|
if (m_pOpenSourceFile != NULL)
|
|
{
|
|
m_pOpenSourceFile->AssertValid();
|
|
}
|
|
// If the reporter pointer is non-NULL, check the object.
|
|
|
|
if (m_pReporter != NULL)
|
|
{
|
|
m_pReporter->AssertValid();
|
|
}
|
|
|
|
// If the process object pointer is non-NULL, check the object.
|
|
|
|
// Make sure m_FileType is one of the valid types.
|
|
|
|
switch (m_FileType)
|
|
{
|
|
case ftMNCFileType:
|
|
case ftUnknown:
|
|
// TODO: add cases for all ft* constants in impfile.h here.
|
|
// case ftFoo1FileType:
|
|
// case ftFoo2FileType:
|
|
// These are all OK. Do nothing.
|
|
break;
|
|
|
|
default:
|
|
// This is bad!
|
|
LTASSERT(0 && "m_FileType is bad during CLocImpFile::AssertValid()");
|
|
}
|
|
|
|
// Can't check code page values, they could be just about anything
|
|
// and still valid.
|
|
|
|
// TODO: check any checkable implementation member variables here.
|
|
|
|
return;
|
|
} // end of CLocImpFile::AssertValid()
|
|
|
|
|
|
#endif // _DEBUG
|
|
|
|
|
|
//Creating a parent node
|
|
//ihItemHandler -> Required to send item
|
|
//dbidFileId -> Id of the parent of node
|
|
//pNewParentId -> New Id will be assigned can be used if this node has
|
|
// child
|
|
//szNodeRes -> Res ID of the node
|
|
//szNodeString -> String of the node
|
|
// <- Returns success or failure
|
|
|
|
BOOL CLocImpFile::CreateParentNode(CLocItemHandler & ihItemHandler,
|
|
const DBID & dbidFileId,
|
|
DBID & pNewParentId,
|
|
const char * szNodeRes,
|
|
const char * szNodeString)
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
CLocItemSet isItemSet;
|
|
|
|
CLocUniqueId uid;
|
|
CPascalString pstrText,pstrId;
|
|
try
|
|
{
|
|
CLocItem *pLocItem = new CLocItem();
|
|
|
|
pstrId.SetString(szNodeRes,strlen(szNodeRes),m_cpSource);
|
|
|
|
uid.GetResId().SetId(pstrId);
|
|
|
|
pstrText.SetString(szNodeString,strlen(szNodeString),m_cpSource);
|
|
|
|
uid.GetTypeId().SetId(pstrText);
|
|
|
|
uid.SetParentId(dbidFileId);
|
|
|
|
//set up pLocItem
|
|
|
|
pLocItem->SetUniqueId(uid);
|
|
|
|
pLocItem->SetFDisplayable(TRUE);
|
|
pLocItem->SetFExpandable(TRUE);
|
|
pLocItem->SetFNoResTable(TRUE);
|
|
pLocItem->SetIconType(CIT::Expandable);
|
|
|
|
//Add the node to Item set
|
|
isItemSet.Add(pLocItem);
|
|
|
|
//Send node to espresso
|
|
|
|
fRetVal = ihItemHandler.HandleItemSet(isItemSet);
|
|
|
|
// If OK, retrieve DBID.
|
|
|
|
if (fRetVal)
|
|
{
|
|
pNewParentId.Clear();
|
|
pNewParentId = pLocItem->GetMyDatabaseId();
|
|
}
|
|
isItemSet.ClearItemSet();
|
|
}
|
|
catch (CMemoryException *pMemoryException)
|
|
{
|
|
CLString strContext;
|
|
|
|
strContext.LoadString(g_hDll, IDS_MNC_GENERIC_LOCATION);
|
|
|
|
m_pReporter->IssueMessage(esError, strContext, g_hDll, IDS_MNC_NO_MEMORY,
|
|
g_locNull);
|
|
fRetVal = FALSE;
|
|
pMemoryException->Delete();
|
|
}
|
|
catch(CException *pException)
|
|
{
|
|
ReportException(pException);
|
|
pException->Delete();
|
|
fRetVal = FALSE;
|
|
}
|
|
return fRetVal;
|
|
|
|
}
|
|
|
|
//Creating a child node
|
|
//ihItemHandler -> Required to send item
|
|
//dbidFileId -> Id of the parent of node
|
|
//pNewParentId -> New Id to be use for items belonging to this child
|
|
//szNodeRes -> Res ID of the node
|
|
//szNodeString -> String of the node
|
|
// <- Returns success or failure
|
|
|
|
|
|
BOOL CLocImpFile::CreateChildNode(CLocItemHandler & ihItemHandler,
|
|
const DBID & dbidFileId,
|
|
DBID & pNewParentId,
|
|
const char * szNodeRes,
|
|
const char * szNodeString)
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
CLocItemSet isItemSet;
|
|
|
|
CLocUniqueId uid;
|
|
CPascalString pstrText,pstrId;
|
|
try
|
|
{
|
|
CLocItem *pLocItem = new CLocItem();
|
|
|
|
pstrId.SetString(szNodeRes,strlen(szNodeRes),m_cpSource);
|
|
|
|
pstrText.SetString(szNodeString,strlen(szNodeString),m_cpSource);
|
|
|
|
uid.GetResId().SetId(pstrId);
|
|
|
|
uid.GetTypeId().SetId(pstrText);
|
|
|
|
uid.SetParentId(dbidFileId);
|
|
|
|
//set up pLocItem
|
|
|
|
pLocItem->SetUniqueId(uid);
|
|
|
|
pLocItem->SetFDisplayable(TRUE);
|
|
pLocItem->SetFExpandable(FALSE);
|
|
pLocItem->SetFNoResTable(TRUE);
|
|
pLocItem->SetIconType(CIT::String);
|
|
|
|
//Add the node to Item set
|
|
isItemSet.Add(pLocItem);
|
|
|
|
//Send node to espresso
|
|
|
|
fRetVal = ihItemHandler.HandleItemSet(isItemSet);
|
|
|
|
// If OK, retrieve DBID.
|
|
|
|
if (fRetVal)
|
|
{
|
|
pNewParentId.Clear();
|
|
pNewParentId = pLocItem->GetMyDatabaseId();
|
|
}
|
|
isItemSet.ClearItemSet();
|
|
}
|
|
catch (CMemoryException *pMemoryException)
|
|
{
|
|
CLString strContext;
|
|
|
|
strContext.LoadString(g_hDll, IDS_MNC_GENERIC_LOCATION);
|
|
|
|
m_pReporter->IssueMessage(esError, strContext, g_hDll, IDS_MNC_NO_MEMORY,
|
|
g_locNull);
|
|
fRetVal = FALSE;
|
|
pMemoryException->Delete();
|
|
}
|
|
catch(CException *pException)
|
|
{
|
|
ReportException(pException);
|
|
pException->Delete();
|
|
fRetVal = FALSE;
|
|
}
|
|
return fRetVal;
|
|
|
|
}
|
|
|
|
|
|
BOOL CLocImpFile::EnumerateStrings(CLocItemHandler & ihItemHandler,
|
|
const DBID & dbidFileId,
|
|
BOOL fGenerating)
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
|
|
try
|
|
{
|
|
fRetVal = OpenStream(FALSE);
|
|
if(!fRetVal)
|
|
goto exit_clean;
|
|
|
|
if(fGenerating)
|
|
fRetVal = OpenStream(TRUE);
|
|
if(!fRetVal)
|
|
goto exit_clean;
|
|
|
|
if (m_bXMLBased)
|
|
fRetVal = ProcessXMLStrings(ihItemHandler,dbidFileId,fGenerating);
|
|
else
|
|
fRetVal = ProcessStrings(ihItemHandler,dbidFileId,fGenerating);
|
|
}
|
|
catch(CException *pException)
|
|
{
|
|
ReportException(pException);
|
|
pException->Delete();
|
|
fRetVal = FALSE;
|
|
}
|
|
|
|
exit_clean:
|
|
if(m_pstmSourceString)
|
|
m_pstmSourceString->Release();
|
|
if(m_pstgSourceStringTable)
|
|
m_pstgSourceStringTable->Release();
|
|
if(m_pstgSourceParent)
|
|
m_pstgSourceParent->Release();
|
|
if(fGenerating)
|
|
{
|
|
if(m_pstmTargetString)
|
|
m_pstmTargetString->Release();
|
|
if(m_pstgTargetStringTable)
|
|
m_pstgTargetStringTable->Release();
|
|
if(m_pstgTargetParent)
|
|
m_pstgTargetParent->Release();
|
|
}
|
|
return fRetVal;
|
|
}
|
|
|
|
BOOL CLocImpFile::ProcessStrings(CLocItemHandler & ihItemHandler,
|
|
const DBID & dbidFileId,
|
|
BOOL fGenerating)
|
|
{
|
|
DBID dbidParentId,dbidNodeId;
|
|
BOOL fRetVal = TRUE;
|
|
BOOL bUseBraces = ::IsConfiguredToUseBracesForStringTables();
|
|
|
|
fRetVal = CreateParentNode(ihItemHandler,dbidFileId,dbidParentId,"String Table","String Table");
|
|
for(DWORD i=0; i < m_dwCountOfStringTables;i++)
|
|
{
|
|
ULONG dwBytesRead;
|
|
OLECHAR FAR* psz;
|
|
char szTemp[MAX_BUFFER];
|
|
CLocItemSet lsItemSet;
|
|
int nLength = 0;
|
|
|
|
dbidNodeId.Clear();
|
|
m_pstmSourceString->Read(&m_clsidSnapIn,sizeof(CLSID),&dwBytesRead);
|
|
StringFromCLSID(m_clsidSnapIn,&psz);
|
|
wcstombs(szTemp,psz,MAX_BUFFER);
|
|
nLength = strlen(szTemp);
|
|
LTASSERT((szTemp[0] == '{') && (szTemp[nLength - 1] == '}'));
|
|
|
|
// strip braces if configured so
|
|
CString strGUID(szTemp);
|
|
if ( !bUseBraces && strGUID[0] == _T('{') && strGUID[strGUID.GetLength() - 1] == _T('}'))
|
|
strGUID = strGUID.Mid(1, strGUID.GetLength() - 2);
|
|
|
|
fRetVal = CreateChildNode(ihItemHandler,dbidParentId,dbidNodeId,strGUID,strGUID);
|
|
m_pstmSourceString->Read(&m_dwCountOfStrings,sizeof(DWORD),&dwBytesRead);
|
|
if(fGenerating)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwBytesWritten;
|
|
hr = m_pstmTargetString->Write(&m_clsidSnapIn,sizeof(CLSID),&dwBytesWritten);
|
|
hr = m_pstmTargetString->Write(&m_dwCountOfStrings,sizeof(DWORD),&dwBytesWritten);
|
|
}
|
|
for(DWORD j = 0;j < m_dwCountOfStrings;j++)
|
|
{
|
|
DWORD dwCharCount;
|
|
|
|
m_pstmSourceString->Read(&m_dwID,sizeof(DWORD),&dwBytesRead);
|
|
m_pstmSourceString->Read(&m_dwRefCount,sizeof(DWORD),&dwBytesRead);
|
|
m_pstmSourceString->Read(&dwCharCount,sizeof(DWORD),&dwBytesRead);
|
|
WCHAR *pString;
|
|
pString = new WCHAR[dwCharCount + 1];
|
|
m_pstmSourceString->Read(pString,dwCharCount * 2,&dwBytesRead);
|
|
pString[dwCharCount] = L'\0';
|
|
int nSize = WideCharToMultiByte(m_cpSource,0,pString,dwCharCount,szTemp,dwCharCount*2,NULL,NULL);
|
|
szTemp[nSize] = '\0';
|
|
AddItemToSet(lsItemSet,dbidNodeId,m_dwID,szTemp);
|
|
delete []pString;
|
|
if(!fGenerating)
|
|
fRetVal = ihItemHandler.HandleItemSet(lsItemSet);
|
|
else
|
|
fRetVal = GenerateStrings(ihItemHandler,lsItemSet);
|
|
lsItemSet.ClearItemSet();
|
|
}
|
|
}
|
|
|
|
return fRetVal;
|
|
}
|
|
|
|
BOOL CLocImpFile::ProcessXMLStrings(CLocItemHandler & ihItemHandler,
|
|
const DBID & dbidFileId,
|
|
BOOL fGenerating)
|
|
{
|
|
DBID dbidParentId,dbidNodeId;
|
|
BOOL bOK = TRUE;
|
|
BOOL bUseBraces = ::IsConfiguredToUseBracesForStringTables();
|
|
|
|
// check if we have a table
|
|
if (m_spStringTablesNode == NULL)
|
|
return FALSE;
|
|
|
|
// create node
|
|
bOK = CreateParentNode(ihItemHandler, dbidFileId, dbidParentId, "String Table", "String Table");
|
|
if (!bOK)
|
|
return bOK;
|
|
|
|
// read the strings from XML document
|
|
CStringTableMap mapStringTables;
|
|
HRESULT hr = ReadXMLStringTables(m_spStringTablesNode, mapStringTables);
|
|
if (FAILED(hr))
|
|
return FALSE;
|
|
|
|
// iterate thru read data
|
|
CStringTableMap::iterator it;
|
|
for (it = mapStringTables.begin(); it != mapStringTables.end(); ++it)
|
|
{
|
|
std::wstring wstrGUID = it->first;
|
|
const CStringMap& rStrings = it->second;
|
|
|
|
dbidNodeId.Clear();
|
|
|
|
// convert 2 ansi
|
|
CString strGUID;
|
|
wcstombs(strGUID.GetBuffer(wstrGUID.length()), wstrGUID.c_str(), wstrGUID.length());
|
|
strGUID.ReleaseBuffer();
|
|
|
|
// strip braces if configured so
|
|
if ( !bUseBraces && strGUID[0] == _T('{') && strGUID[strGUID.GetLength() - 1] == _T('}'))
|
|
strGUID = strGUID.Mid(1, strGUID.GetLength() - 2);
|
|
|
|
bOK = CreateChildNode(ihItemHandler, dbidParentId, dbidNodeId, strGUID, strGUID);
|
|
if (!bOK)
|
|
return bOK;
|
|
|
|
// handle the strings in map
|
|
CStringMap::iterator its;
|
|
for (its = rStrings.begin(); its != rStrings.end(); ++its)
|
|
{
|
|
DWORD dwID = its->first;
|
|
std::wstring text = its->second;
|
|
|
|
DWORD dwCharCount = text.length();
|
|
CString strText;
|
|
char *pBuffer = strText.GetBuffer(dwCharCount*2);
|
|
if (pBuffer == NULL)
|
|
return FALSE;
|
|
int nSize = WideCharToMultiByte(m_cpSource, 0, text.c_str(), dwCharCount,
|
|
pBuffer, dwCharCount*2, NULL, NULL);
|
|
pBuffer[nSize] = '\0';
|
|
strText.ReleaseBuffer();
|
|
|
|
// use/update the string
|
|
CLocItemSet lsItemSet;
|
|
AddItemToSet(lsItemSet, dbidNodeId, dwID, strText);
|
|
|
|
bOK = ihItemHandler.HandleItemSet(lsItemSet);
|
|
if (!bOK)
|
|
return bOK;
|
|
|
|
if(fGenerating)
|
|
{
|
|
CLocItem *pLocItem = lsItemSet.GetAt(0);
|
|
if (!pLocItem)
|
|
return FALSE;
|
|
|
|
std::wstring strNewVal = pLocItem->GetLocString().GetString();
|
|
hr = UpdateXMLString(m_spTargetStringTablesNode, wstrGUID, dwID, strNewVal);
|
|
CString strMsg = strGUID;
|
|
if (FAILED(hr))
|
|
return FALSE;
|
|
}
|
|
lsItemSet.ClearItemSet();
|
|
|
|
if (!bOK)
|
|
return bOK;
|
|
}
|
|
}
|
|
|
|
// save XML document to the file
|
|
if (fGenerating)
|
|
{
|
|
hr = SaveXMLContents(m_pstrTargetFile, m_spTargetStringTablesNode);
|
|
if (FAILED(hr))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CLocImpFile::AddItemToSet(CLocItemSet & isItemSet,
|
|
const DBID &dbidNodeId,
|
|
DWORD dwID,
|
|
LPCSTR szText)
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
CPascalString pstrText;
|
|
CLocUniqueId uid;
|
|
ULONG lItemType = 1;
|
|
|
|
try
|
|
{
|
|
CLocItem * pNewItem = new CLocItem;
|
|
pstrText.SetString(szText,strlen(szText),m_cpSource);
|
|
uid.GetResId().SetId(dwID);
|
|
uid.GetTypeId().SetId(lItemType);
|
|
uid.SetParentId(dbidNodeId);
|
|
|
|
pNewItem->SetUniqueId(uid);
|
|
|
|
CLocString lsString;
|
|
|
|
pNewItem->SetIconType(CIT::String);
|
|
lsString.SetString(pstrText);
|
|
|
|
pNewItem->SetFDevLock(FALSE);
|
|
pNewItem->SetFUsrLock(FALSE);
|
|
pNewItem->SetFExpandable(FALSE);
|
|
pNewItem->SetFDisplayable(FALSE);
|
|
pNewItem->SetFNoResTable(FALSE);
|
|
lsString.SetCodePageType(cpAnsi);
|
|
lsString.SetStringType(CST::Text);
|
|
pNewItem->SetLocString(lsString);
|
|
isItemSet.Add(pNewItem);
|
|
fRetVal = TRUE;
|
|
}
|
|
catch (CMemoryException *pMemoryException)
|
|
{
|
|
CLString strContext;
|
|
|
|
strContext.LoadString(g_hDll, IDS_MNC_GENERIC_LOCATION);
|
|
|
|
m_pReporter->IssueMessage(esError, strContext, g_hDll, IDS_MNC_NO_MEMORY,
|
|
g_locNull);
|
|
fRetVal = FALSE;
|
|
pMemoryException->Delete();
|
|
}
|
|
catch(CException *pException)
|
|
{
|
|
ReportException(pException);
|
|
pException->Delete();
|
|
fRetVal = FALSE;
|
|
}
|
|
return fRetVal;
|
|
}
|
|
|
|
BOOL CLocImpFile::OpenStream(BOOL fGenerating)
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if(!fGenerating)
|
|
{
|
|
hr = StgOpenStorage(m_pstrFileName,NULL,STGM_TRANSACTED | STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&m_pstgSourceParent);
|
|
if(!FAILED(hr))
|
|
{
|
|
CPascalString pstrStorage,pstrStream;
|
|
pstrStorage.SetString("String Table",strlen("String Table"),cpAnsi);
|
|
pstrStream.SetString("Strings",strlen("Strings"),cpAnsi);
|
|
|
|
hr = m_pstgSourceParent->OpenStorage(pstrStorage,NULL,STGM_READ | STGM_SHARE_EXCLUSIVE,NULL,0,&m_pstgSourceStringTable);
|
|
if(!FAILED(hr))
|
|
{
|
|
HRESULT hr = m_pstgSourceStringTable->OpenStream(pstrStream,0,STGM_READ | STGM_SHARE_EXCLUSIVE,0,&m_pstmSourceString);
|
|
if(!FAILED(hr))
|
|
{
|
|
DWORD dwBytesRead;
|
|
m_pstmSourceString->Read(&m_dwCountOfStringTables,sizeof(DWORD),&dwBytesRead);
|
|
}
|
|
else
|
|
fRetVal = FALSE;
|
|
}
|
|
else
|
|
{
|
|
fRetVal = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// try to open this as XML document
|
|
m_spStringTablesNode.Release(); // release the old one (if such exist)
|
|
hr = OpenXMLStringTable(m_pstrFileName, &m_spStringTablesNode);
|
|
if (SUCCEEDED(hr))
|
|
m_bXMLBased = true;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
CLString strMessage, strFilePath;
|
|
|
|
m_pstrFileName.ConvertToCLString(strFilePath, CP_ACP);
|
|
strMessage.Format(g_hDll, IDS_MSC_ERR_OPENSTORAGE, strFilePath);
|
|
LTASSERT(m_pReporter != NULL);
|
|
m_pReporter->IssueMessage(esError, CLString(g_hDll, IDS_MNC_GENERIC_LOCATION),strMessage);
|
|
|
|
fRetVal = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else if (!m_bXMLBased)
|
|
{
|
|
hr = StgOpenStorage(m_pstrTargetFile,NULL,STGM_READWRITE | STGM_SHARE_EXCLUSIVE,NULL,0,&m_pstgTargetParent);
|
|
if(!FAILED(hr))
|
|
{
|
|
CPascalString pstrStorage,pstrStream;
|
|
pstrStorage.SetString("String Table",strlen("String Table"),cpAnsi);
|
|
pstrStream.SetString("Strings",strlen("Strings"),cpAnsi);
|
|
|
|
hr = m_pstgTargetParent->OpenStorage(pstrStorage,NULL,STGM_READWRITE | STGM_SHARE_EXCLUSIVE ,NULL,0,&m_pstgTargetStringTable);
|
|
if(!FAILED(hr))
|
|
{
|
|
HRESULT hr = m_pstgTargetStringTable->CreateStream(pstrStream, STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE,0,0,&m_pstmTargetString);
|
|
if(!FAILED(hr))
|
|
{
|
|
DWORD dwBytesRead;
|
|
hr = m_pstmTargetString->Write(&m_dwCountOfStringTables,sizeof(DWORD),&dwBytesRead);
|
|
}
|
|
else
|
|
fRetVal = FALSE;
|
|
}
|
|
else
|
|
fRetVal = FALSE;
|
|
}
|
|
else
|
|
fRetVal = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// try to open this as XML document
|
|
m_spTargetStringTablesNode.Release(); // release the old one (if such exist)
|
|
hr = OpenXMLStringTable(m_pstrTargetFile, &m_spTargetStringTablesNode);
|
|
if (FAILED(hr))
|
|
fRetVal = FALSE;
|
|
}
|
|
return fRetVal;
|
|
}
|
|
|
|
BOOL CLocImpFile::GenerateStrings(CLocItemHandler & ihItemHandler,
|
|
CLocItemSet & isItemSet)
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
INT iNoOfElements = 0;
|
|
DWORD dwBytesWritten,dwCharCount;
|
|
WCHAR *pLocText;
|
|
HRESULT hr;
|
|
|
|
try
|
|
{
|
|
if(ihItemHandler.HandleItemSet(isItemSet))
|
|
{
|
|
while(iNoOfElements < isItemSet.GetSize())
|
|
{
|
|
CLocItem *pLocItem;
|
|
CPascalString pstrText;
|
|
|
|
pLocItem = isItemSet.GetAt(iNoOfElements);
|
|
|
|
hr = m_pstmTargetString->Write(&m_dwID,sizeof(DWORD),&dwBytesWritten);
|
|
hr = m_pstmTargetString->Write(&m_dwRefCount,sizeof(DWORD),&dwBytesWritten);
|
|
|
|
pstrText = pLocItem->GetLocString().GetString();
|
|
dwCharCount = pstrText.GetStringLength();
|
|
hr = m_pstmTargetString->Write(&dwCharCount,sizeof(DWORD),&dwBytesWritten);
|
|
pLocText = pstrText.GetStringPointer();
|
|
hr = m_pstmTargetString->Write(pLocText,dwCharCount * 2,&dwBytesWritten);
|
|
pstrText.ReleaseStringPointer();
|
|
iNoOfElements++;
|
|
}
|
|
}
|
|
}
|
|
catch(CException *pException)
|
|
{
|
|
ReportException(pException);
|
|
pException->Delete();
|
|
fRetVal = FALSE;
|
|
}
|
|
|
|
return fRetVal;
|
|
}
|
|
|