658 lines
18 KiB
C++
658 lines
18 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
||
|
//
|
||
|
// File: layscrpt.cxx
|
||
|
//
|
||
|
// Contents: Code for the LayoutScript method
|
||
|
//
|
||
|
//
|
||
|
// History: 22-Apr-96 SusiA Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "layouthd.cxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <dirfunc.hxx>
|
||
|
#include "layout.hxx"
|
||
|
#include "laylkb.hxx"
|
||
|
#include "laywrap.hxx"
|
||
|
|
||
|
#define NULL_TERM L'\0'
|
||
|
#define BACKSLASH L'\\'
|
||
|
#define MAX_BUFFER 0x10000
|
||
|
|
||
|
//#define UNIT_TEST
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CLayoutRootStorage::FreeStmList
|
||
|
//
|
||
|
// Synopsis: Free the stream linked list
|
||
|
//
|
||
|
// Arguments: [pStmList] -- Pointer STREAMLIST node
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CLayoutRootStorage::FreeStmList( STREAMLIST *pStmList)
|
||
|
{
|
||
|
STREAMLIST *ptmp = pStmList;
|
||
|
|
||
|
while (pStmList)
|
||
|
{
|
||
|
ptmp = pStmList->pnext;
|
||
|
|
||
|
#ifdef UNIT_TEST
|
||
|
wprintf(L"STGTY_STREAM %ls\n", pStmList->pwcsStmName );
|
||
|
#endif
|
||
|
CoTaskMemFree(pStmList->pwcsStmName);
|
||
|
pStmList->pStm->Release();
|
||
|
delete pStmList;
|
||
|
|
||
|
pStmList = ptmp;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CLayoutRootStorage::FreeStgList
|
||
|
//
|
||
|
// Synopsis: Free the storage linked list
|
||
|
//
|
||
|
// Arguments: [pStgList] -- Pointer STORAGELIST node
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CLayoutRootStorage::FreeStgList( STORAGELIST *pStgList)
|
||
|
{
|
||
|
STORAGELIST *ptmp;
|
||
|
|
||
|
while (pStgList)
|
||
|
{
|
||
|
ptmp = pStgList->pnext;
|
||
|
#ifdef UNIT_TEST
|
||
|
wprintf(L"STGTY_STORAGE %ls\n", pStgList->pwcsStgName );
|
||
|
#endif
|
||
|
|
||
|
CoTaskMemFree(pStgList->pwcsStgName);
|
||
|
pStgList->pStg->Release();
|
||
|
delete pStgList;
|
||
|
|
||
|
pStgList = ptmp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CLayoutRootStorage::ProcessOpen
|
||
|
//
|
||
|
// Synopsis: Open the storage or stream
|
||
|
//
|
||
|
// Arguments: [pwcsElementPathName] -- full "path" name of element to open
|
||
|
// [dwType] STGTY_STORAGE or STGTY_STREAM
|
||
|
// [ppIstgStm] interface pointer to the opened Storage or Stream
|
||
|
// [cOffset] offset of beginning of the read
|
||
|
//
|
||
|
// Returns: Appropriate status code
|
||
|
//
|
||
|
// History: 22-Apr-96 SusiA Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
SCODE CLayoutRootStorage::ProcessOpen(OLECHAR *pwcsElementPathName,
|
||
|
DWORD dwType,
|
||
|
void **ppIStgStm,
|
||
|
LARGE_INTEGER cOffset)
|
||
|
{
|
||
|
SCODE sc = S_OK;
|
||
|
|
||
|
IStorage *pStgNew;
|
||
|
IStream *pStmNew;
|
||
|
|
||
|
IStorage *pStg = this;
|
||
|
|
||
|
STORAGELIST *pStgList;
|
||
|
STREAMLIST *pStmList;
|
||
|
|
||
|
OLECHAR *pwcsStg = pwcsElementPathName,
|
||
|
*pwcsTemp = pwcsElementPathName;
|
||
|
|
||
|
OLECHAR *pwcsBuffer;
|
||
|
|
||
|
if ( (!pwcsElementPathName) || (pwcsElementPathName[0] == NULL_TERM))
|
||
|
{
|
||
|
return STG_E_PATHNOTFOUND;
|
||
|
}
|
||
|
|
||
|
// process storage path
|
||
|
while (1)
|
||
|
{
|
||
|
while ((*pwcsTemp) && (*pwcsTemp != BACKSLASH))
|
||
|
{
|
||
|
pwcsTemp++;
|
||
|
}
|
||
|
|
||
|
pwcsBuffer = (OLECHAR *) CoTaskMemAlloc
|
||
|
((INT)(pwcsTemp - pwcsElementPathName + 1) *
|
||
|
sizeof(OLECHAR) );
|
||
|
|
||
|
if (!pwcsBuffer)
|
||
|
{
|
||
|
return STG_E_INSUFFICIENTMEMORY;
|
||
|
}
|
||
|
|
||
|
lstrcpynW (pwcsBuffer,
|
||
|
pwcsElementPathName,
|
||
|
(INT)(pwcsTemp - pwcsElementPathName + 1));
|
||
|
|
||
|
pwcsBuffer[pwcsTemp - pwcsElementPathName] = NULL_TERM;
|
||
|
|
||
|
if (!(*pwcsTemp))
|
||
|
{
|
||
|
//we are at the end, now handle leaf Storage or stream
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pStgList = _pStgList;
|
||
|
|
||
|
// see if this storage is already in the list
|
||
|
while (pStgList)
|
||
|
{
|
||
|
if (!(lstrcmpW(pwcsBuffer, pStgList->pwcsStgName )))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pStgList = pStgList->pnext;
|
||
|
}
|
||
|
if (pStgList)
|
||
|
{
|
||
|
pStgNew = pStgList->pStg;
|
||
|
CoTaskMemFree(pwcsBuffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sc = pStg->OpenStorage(pwcsBuffer+(pwcsStg-pwcsElementPathName),
|
||
|
NULL,
|
||
|
STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,
|
||
|
NULL,
|
||
|
0,
|
||
|
&pStgNew);
|
||
|
if (FAILED(sc))
|
||
|
{
|
||
|
CoTaskMemFree(pwcsBuffer);
|
||
|
return sc;
|
||
|
}
|
||
|
|
||
|
// add the storage to the list
|
||
|
pStgList = _pStgList;
|
||
|
|
||
|
if (NULL == (_pStgList = new STORAGELIST))
|
||
|
{
|
||
|
CoTaskMemFree(pwcsBuffer);
|
||
|
pStgNew->Release();
|
||
|
return STG_E_INSUFFICIENTMEMORY;
|
||
|
}
|
||
|
|
||
|
_pStgList->pwcsStgName = pwcsBuffer;
|
||
|
_pStgList->pStg = pStgNew;
|
||
|
_pStgList->pnext = pStgList;
|
||
|
|
||
|
}
|
||
|
|
||
|
pStg = pStgNew;
|
||
|
pwcsStg = ++pwcsTemp;
|
||
|
|
||
|
}
|
||
|
|
||
|
//process leaf storage
|
||
|
if (dwType == STGTY_STORAGE)
|
||
|
{
|
||
|
sc = pStg->OpenStorage(pwcsBuffer+(pwcsStg-pwcsElementPathName),
|
||
|
NULL,
|
||
|
STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,
|
||
|
NULL,
|
||
|
0,
|
||
|
&pStgNew);
|
||
|
if (FAILED(sc))
|
||
|
{
|
||
|
CoTaskMemFree(pwcsBuffer);
|
||
|
return sc;
|
||
|
}
|
||
|
|
||
|
// add the storage to the list
|
||
|
pStgList = _pStgList;
|
||
|
|
||
|
if (NULL == (_pStgList = new STORAGELIST))
|
||
|
{
|
||
|
CoTaskMemFree(pwcsBuffer);
|
||
|
pStgNew->Release();
|
||
|
return STG_E_INSUFFICIENTMEMORY;
|
||
|
}
|
||
|
|
||
|
_pStgList->pwcsStgName = pwcsBuffer;
|
||
|
_pStgList->pStg = pStgNew;
|
||
|
_pStgList->pnext = pStgList;
|
||
|
|
||
|
*ppIStgStm = (void *) pStgNew;
|
||
|
}
|
||
|
//process leaf stream
|
||
|
else
|
||
|
{
|
||
|
sc = pStg->OpenStream(pwcsBuffer+(pwcsStg-pwcsElementPathName),
|
||
|
NULL,
|
||
|
STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,
|
||
|
0,
|
||
|
&pStmNew);
|
||
|
|
||
|
if (FAILED(sc))
|
||
|
{
|
||
|
CoTaskMemFree(pwcsBuffer);
|
||
|
return sc;
|
||
|
}
|
||
|
|
||
|
pStmList = _pStmList;
|
||
|
|
||
|
if (NULL == (_pStmList = new STREAMLIST))
|
||
|
{
|
||
|
CoTaskMemFree(pwcsBuffer);
|
||
|
pStmNew->Release();
|
||
|
return STG_E_INSUFFICIENTMEMORY;
|
||
|
}
|
||
|
|
||
|
_pStmList->pwcsStmName = pwcsBuffer;
|
||
|
_pStmList->pStm = pStmNew;
|
||
|
_pStmList->fDone = FALSE;
|
||
|
_pStmList->cOffset = cOffset;
|
||
|
_pStmList->pnext = pStmList;
|
||
|
|
||
|
*ppIStgStm = (void *) pStmNew;
|
||
|
}
|
||
|
|
||
|
return sc;
|
||
|
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CLayoutRootStorage::ProcessItem
|
||
|
//
|
||
|
// Synopsis: Construct an unprocessed script from an app provided script
|
||
|
//
|
||
|
// Arguments: [pLayoutItem] -- Pointer to a StorageLayout element of the array
|
||
|
// [fStmDone] -- indicate whether the stream finished reading
|
||
|
//
|
||
|
// Returns: Appropriate status code
|
||
|
//
|
||
|
// History: 22-Apr-96 SusiA Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
SCODE CLayoutRootStorage::ProcessItem( StorageLayout *pLayoutItem, BOOL *fStmDone )
|
||
|
{
|
||
|
SCODE sc = S_OK;
|
||
|
|
||
|
STREAMLIST *pStmList = _pStmList;
|
||
|
STORAGELIST *pStgList = _pStgList;
|
||
|
IStorage *pStgNew;
|
||
|
IStream *pStmNew;
|
||
|
|
||
|
ULARGE_INTEGER libNewPosition;
|
||
|
ULONG cbRead;
|
||
|
|
||
|
BYTE abBuffer[MAX_BUFFER];
|
||
|
BYTE *pb = abBuffer;
|
||
|
BOOL fBigBuffer = FALSE;
|
||
|
|
||
|
*fStmDone = FALSE;
|
||
|
|
||
|
if ((pLayoutItem->cOffset.QuadPart < 0) || (pLayoutItem->cBytes.QuadPart < 0))
|
||
|
{
|
||
|
return STG_E_INVALIDPARAMETER;
|
||
|
}
|
||
|
|
||
|
switch (pLayoutItem->LayoutType)
|
||
|
{
|
||
|
|
||
|
case STGTY_STORAGE:
|
||
|
|
||
|
#ifdef UNIT_TEST
|
||
|
wprintf(L"STGTY_STORAGE %ls %lu%lu %lu%lu\n",
|
||
|
pLayoutItem->pwcsElementName,
|
||
|
pLayoutItem->cOffset.HighPart,
|
||
|
pLayoutItem->cOffset.LowPart,
|
||
|
pLayoutItem->cBytes.HighPart,
|
||
|
pLayoutItem->cBytes.LowPart);
|
||
|
#endif
|
||
|
|
||
|
while (pStgList)
|
||
|
{
|
||
|
if (!(lstrcmpW(pLayoutItem->pwcsElementName,
|
||
|
pStgList->pwcsStgName )))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pStgList = pStgList->pnext;
|
||
|
}
|
||
|
|
||
|
// if storage was not found in the list, open the storage
|
||
|
// and add it to the list
|
||
|
if (!pStgList)
|
||
|
{
|
||
|
sc = ProcessOpen(pLayoutItem->pwcsElementName,
|
||
|
STGTY_STORAGE,
|
||
|
(void **)&pStgNew,
|
||
|
pLayoutItem->cOffset);
|
||
|
|
||
|
if (FAILED(sc))
|
||
|
{
|
||
|
// the application may try to open Storages
|
||
|
// that do not really exist in the compound file,
|
||
|
// and we will let them try.
|
||
|
if (sc == STG_E_FILENOTFOUND)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return sc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case STGTY_STREAM:
|
||
|
|
||
|
#ifdef UNIT_TEST
|
||
|
wprintf(L"STGTY_STREAM %ls %lu%lu %lu%lu\n",
|
||
|
pLayoutItem->pwcsElementName,
|
||
|
pLayoutItem->cOffset.HighPart,
|
||
|
pLayoutItem->cOffset.LowPart,
|
||
|
pLayoutItem->cBytes.HighPart,
|
||
|
pLayoutItem->cBytes.LowPart);
|
||
|
#endif
|
||
|
|
||
|
while (pStmList)
|
||
|
{
|
||
|
if (!(lstrcmpW(pLayoutItem->pwcsElementName,
|
||
|
pStmList->pwcsStmName )))
|
||
|
{
|
||
|
pStmNew = pStmList->pStm;
|
||
|
break;
|
||
|
}
|
||
|
pStmList = pStmList->pnext;
|
||
|
}
|
||
|
|
||
|
// if stream was not found in the list, open the stream,
|
||
|
// and add it to the list
|
||
|
if (pStmList)
|
||
|
{
|
||
|
if( pStmList->fDone )
|
||
|
{
|
||
|
*fStmDone = TRUE;
|
||
|
return S_OK;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
sc = ProcessOpen(pLayoutItem->pwcsElementName,
|
||
|
STGTY_STREAM,
|
||
|
(void **)&pStmNew,
|
||
|
pLayoutItem->cOffset);
|
||
|
|
||
|
if (FAILED(sc))
|
||
|
{
|
||
|
// the application may try to open Streams
|
||
|
// that do not really exist in the compound file,
|
||
|
// and we will let them try.
|
||
|
if (sc == STG_E_FILENOTFOUND)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return sc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pStmList = _pStmList;
|
||
|
|
||
|
}
|
||
|
|
||
|
// seek to the correct position
|
||
|
|
||
|
sc = pStmNew->Seek(
|
||
|
pStmList->cOffset,
|
||
|
STREAM_SEEK_SET,
|
||
|
&libNewPosition );
|
||
|
|
||
|
if (FAILED(sc))
|
||
|
{
|
||
|
return sc;
|
||
|
}
|
||
|
|
||
|
// read the stream and update the script information
|
||
|
|
||
|
if (pLayoutItem->cBytes.LowPart > MAX_BUFFER)
|
||
|
{
|
||
|
if (NULL == (pb = (BYTE *) CoTaskMemAlloc(pLayoutItem->cBytes.LowPart)) )
|
||
|
{
|
||
|
return STG_E_INSUFFICIENTMEMORY;
|
||
|
}
|
||
|
fBigBuffer = TRUE;
|
||
|
}
|
||
|
sc = pStmNew->Read(pb,
|
||
|
pLayoutItem->cBytes.LowPart,
|
||
|
&cbRead);
|
||
|
|
||
|
if (fBigBuffer)
|
||
|
{
|
||
|
CoTaskMemFree(pb);
|
||
|
fBigBuffer = FALSE;
|
||
|
pb = abBuffer;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (FAILED(sc))
|
||
|
{
|
||
|
return sc;
|
||
|
}
|
||
|
//we have reached the end of the stream, mark it as done
|
||
|
if (cbRead < pLayoutItem->cBytes.LowPart)
|
||
|
{
|
||
|
pStmList->fDone = TRUE;
|
||
|
}
|
||
|
|
||
|
pStmList->cOffset.QuadPart += cbRead;
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
default:
|
||
|
// we just handle storages and stream types
|
||
|
return STG_E_INVALIDPARAMETER;
|
||
|
|
||
|
}
|
||
|
|
||
|
return sc;
|
||
|
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CLayoutRootStorage::ProcessRepeatLoop
|
||
|
//
|
||
|
// Synopsis: Construct an unprocessed script from an app provided script
|
||
|
//
|
||
|
// Arguments: [pStorageLayout] -- Pointer to storage layout array
|
||
|
// [nEntries] -- Number of entries in the array
|
||
|
// [nRepeatStart] -- address of index of start of repeat loop
|
||
|
//
|
||
|
// Returns: Appropriate status code
|
||
|
//
|
||
|
// History: 22-Apr-96 SusiA Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
SCODE CLayoutRootStorage::ProcessRepeatLoop( StorageLayout *pStorageLayout,
|
||
|
DWORD nEntries,
|
||
|
int * nRepeatStart)
|
||
|
{
|
||
|
SCODE sc = S_OK;
|
||
|
|
||
|
int i,
|
||
|
nLoopCount = 0,
|
||
|
nLoopTimes;
|
||
|
|
||
|
BOOL fDone = FALSE,
|
||
|
fUntilDone;
|
||
|
|
||
|
|
||
|
// Are we going to repeat until all streams are read to the end?
|
||
|
if ((nLoopTimes = (LONG) pStorageLayout[*nRepeatStart].cBytes.LowPart) != STG_TOEND)
|
||
|
fUntilDone = FALSE;
|
||
|
else
|
||
|
{
|
||
|
fUntilDone = TRUE;
|
||
|
nLoopTimes = 1;
|
||
|
}
|
||
|
// finished when all streams are completely read, or we have
|
||
|
// looped through the specified amount of times
|
||
|
while ((!fDone)&&(nLoopCount < nLoopTimes))
|
||
|
{
|
||
|
if (!fUntilDone)
|
||
|
nLoopCount ++;
|
||
|
|
||
|
i = *nRepeatStart;
|
||
|
fDone = TRUE;
|
||
|
|
||
|
// STGTY_REPEAT with 0 bytes indicates the end of this repeat block
|
||
|
while (!((pStorageLayout[++i].LayoutType == STGTY_REPEAT ) &&
|
||
|
(pStorageLayout[i].cBytes.QuadPart == 0)) )
|
||
|
{
|
||
|
if (i >= (LONG) nEntries)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
// beginning of another repeat block
|
||
|
if (pStorageLayout[i].LayoutType == STGTY_REPEAT )
|
||
|
{
|
||
|
if ((pStorageLayout[i].pwcsElementName !=NULL) ||
|
||
|
(pStorageLayout[i].cOffset.QuadPart < 0) ||
|
||
|
(pStorageLayout[i].cBytes.QuadPart < 0) )
|
||
|
{
|
||
|
return STG_E_INVALIDPARAMETER;
|
||
|
}
|
||
|
layChk(ProcessRepeatLoop(pStorageLayout,
|
||
|
nEntries,
|
||
|
&i));
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
layChk(ProcessItem(&(pStorageLayout[i]), &fDone));
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*nRepeatStart = i;
|
||
|
|
||
|
Err:
|
||
|
|
||
|
return sc;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CLayoutRootStorage::ProcessLayout
|
||
|
//
|
||
|
// Synopsis: Construct an unprocessed script from an app provided script
|
||
|
//
|
||
|
// Arguments: [pStorageLayout] -- Pointer to storage layout array
|
||
|
// [nEntries] -- Number of entries in the array
|
||
|
// [grfInterleavedFlag] -- Specifies disposition of control
|
||
|
// structures
|
||
|
//
|
||
|
// Returns: Appropriate status code
|
||
|
//
|
||
|
// History: 22-Apr-96 SusiA Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
SCODE CLayoutRootStorage::ProcessLayout( StorageLayout *pStorageLayout,
|
||
|
DWORD nEntries,
|
||
|
DWORD glfInterleavedFlag)
|
||
|
{
|
||
|
|
||
|
SCODE sc = S_OK;
|
||
|
int i;
|
||
|
BOOL fUnused;
|
||
|
|
||
|
|
||
|
TCHAR *patcScriptName = _pllkb->GetScriptName();
|
||
|
|
||
|
|
||
|
for (i = 0; i < (LONG) nEntries; i++)
|
||
|
{
|
||
|
|
||
|
if (pStorageLayout[i].LayoutType == STGTY_REPEAT )
|
||
|
{
|
||
|
|
||
|
if (pStorageLayout[i].cBytes.QuadPart != 0)
|
||
|
{
|
||
|
if ((pStorageLayout[i].pwcsElementName !=NULL) ||
|
||
|
(pStorageLayout[i].cOffset.QuadPart < 0) ||
|
||
|
(pStorageLayout[i].cBytes.QuadPart < 0) )
|
||
|
{
|
||
|
return STG_E_INVALIDPARAMETER;
|
||
|
}
|
||
|
layChk(ProcessRepeatLoop(pStorageLayout,
|
||
|
nEntries,
|
||
|
&i));
|
||
|
}
|
||
|
else //end repeat block with no matching beginning
|
||
|
{
|
||
|
sc = E_INVALIDARG;
|
||
|
layChk(sc);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
else // (pStorageLayout[i].LayoutType == STGTY_REPEAT )
|
||
|
{
|
||
|
layChk(ProcessItem(&(pStorageLayout[i]), &fUnused));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Err:
|
||
|
if (_pStgList)
|
||
|
{
|
||
|
FreeStgList(_pStgList);
|
||
|
_pStgList = NULL;
|
||
|
}
|
||
|
if (_pStmList)
|
||
|
{
|
||
|
FreeStmList(_pStmList);
|
||
|
_pStmList = NULL;
|
||
|
}
|
||
|
return sc;
|
||
|
|
||
|
}
|