📄 storage32.c
字号:
TRACE("(%p, %ld, %p, %p, %p)\n",
iface, ciidExclude, rgiidExclude,
snbExclude, pstgDest);
/*
* Perform a sanity check
*/
if ( pstgDest == 0 )
return STG_E_INVALIDPOINTER;
/*
* Enumerate the elements
*/
hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
if ( hr != S_OK )
return hr;
/*
* set the class ID
*/
IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
IStorage_SetClass( pstgDest, &curElement.clsid );
do
{
/*
* Obtain the next element
*/
hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
if ( hr == S_FALSE )
{
hr = S_OK; /* done, every element has been copied */
break;
}
if (curElement.type == STGTY_STORAGE)
{
/*
* open child source storage
*/
hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
STGM_READ|STGM_SHARE_EXCLUSIVE,
NULL, 0, &pstgChild );
if (hr != S_OK)
break;
/*
* Check if destination storage is not a child of the source
* storage, which will cause an infinite loop
*/
if (pstgChild == pstgDest)
{
IEnumSTATSTG_Release(elements);
return STG_E_ACCESSDENIED;
}
/*
* create a new storage in destination storage
*/
hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
0, 0,
&pstgTmp );
/*
* if it already exist, don't create a new one use this one
*/
if (hr == STG_E_FILEALREADYEXISTS)
{
hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
STGM_WRITE|STGM_SHARE_EXCLUSIVE,
NULL, 0, &pstgTmp );
}
if (hr != S_OK)
break;
/*
* do the copy recursively
*/
hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
snbExclude, pstgTmp );
IStorage_Release( pstgTmp );
IStorage_Release( pstgChild );
}
else if (curElement.type == STGTY_STREAM)
{
/*
* create a new stream in destination storage. If the stream already
* exist, it will be deleted and a new one will be created.
*/
hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
0, 0, &pstrTmp );
if (hr != S_OK)
break;
/*
* open child stream storage
*/
hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
STGM_READ|STGM_SHARE_EXCLUSIVE,
0, &pstrChild );
if (hr != S_OK)
break;
/*
* Get the size of the source stream
*/
IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
/*
* Set the size of the destination stream.
*/
IStream_SetSize(pstrTmp, strStat.cbSize);
/*
* do the copy
*/
hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
NULL, NULL );
IStream_Release( pstrTmp );
IStream_Release( pstrChild );
}
else
{
WARN("unknown element type: %ld\n", curElement.type);
}
} while (hr == S_OK);
/*
* Clean-up
*/
IEnumSTATSTG_Release(elements);
return hr;
}
/*************************************************************************
* MoveElementTo (IStorage)
*/
HRESULT WINAPI StorageImpl_MoveElementTo(
IStorage* iface,
const OLECHAR *pwcsName, /* [string][in] */
IStorage *pstgDest, /* [unique][in] */
const OLECHAR *pwcsNewName,/* [string][in] */
DWORD grfFlags) /* [in] */
{
FIXME("not implemented!\n");
return E_NOTIMPL;
}
/*************************************************************************
* Commit (IStorage)
*
* Ensures that any changes made to a storage object open in transacted mode
* are reflected in the parent storage
*
* NOTES
* Wine doesn't implement transacted mode, which seems to be a basic
* optimization, so we can ignore this stub for now.
*/
HRESULT WINAPI StorageImpl_Commit(
IStorage* iface,
DWORD grfCommitFlags)/* [in] */
{
FIXME("(%ld): stub!\n", grfCommitFlags);
return S_OK;
}
/*************************************************************************
* Revert (IStorage)
*
* Discard all changes that have been made since the last commit operation
*/
HRESULT WINAPI StorageImpl_Revert(
IStorage* iface)
{
FIXME("not implemented!\n");
return E_NOTIMPL;
}
/*************************************************************************
* DestroyElement (IStorage)
*
* Stategy: This implementation is build this way for simplicity not for speed.
* I always delete the top most element of the enumeration and adjust
* the deleted element pointer all the time. This takes longer to
* do but allow to reinvoke DestroyElement whenever we encounter a
* storage object. The optimisation reside in the usage of another
* enumeration stategy that would give all the leaves of a storage
* first. (postfix order)
*/
HRESULT WINAPI StorageImpl_DestroyElement(
IStorage* iface,
const OLECHAR *pwcsName)/* [string][in] */
{
StorageImpl* const This=(StorageImpl*)iface;
IEnumSTATSTGImpl* propertyEnumeration;
HRESULT hr = S_OK;
BOOL res;
StgProperty propertyToDelete;
StgProperty parentProperty;
ULONG foundPropertyIndexToDelete;
ULONG typeOfRelation;
ULONG parentPropertyId;
TRACE("(%p, %s)\n",
iface, debugstr_w(pwcsName));
/*
* Perform a sanity check on the parameters.
*/
if (pwcsName==NULL)
return STG_E_INVALIDPOINTER;
/*
* Create a property enumeration to search the property with the given name
*/
propertyEnumeration = IEnumSTATSTGImpl_Construct(
This->base.ancestorStorage,
This->base.rootPropertySetIndex);
foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
propertyEnumeration,
pwcsName,
&propertyToDelete);
IEnumSTATSTGImpl_Destroy(propertyEnumeration);
if ( foundPropertyIndexToDelete == PROPERTY_NULL )
{
return STG_E_FILENOTFOUND;
}
/*
* Find the parent property of the property to delete (the one that
* link to it). If This->dirProperty == foundPropertyIndexToDelete,
* the parent is This. Otherwise, the parent is one of it's sibling...
*/
/*
* First, read This's StgProperty..
*/
res = StorageImpl_ReadProperty(
This->base.ancestorStorage,
This->base.rootPropertySetIndex,
&parentProperty);
assert(res);
/*
* Second, check to see if by any chance the actual storage (This) is not
* the parent of the property to delete... We never know...
*/
if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
{
/*
* Set data as it would have been done in the else part...
*/
typeOfRelation = PROPERTY_RELATION_DIR;
parentPropertyId = This->base.rootPropertySetIndex;
}
else
{
/*
* Create a property enumeration to search the parent properties, and
* delete it once done.
*/
IEnumSTATSTGImpl* propertyEnumeration2;
propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
This->base.ancestorStorage,
This->base.rootPropertySetIndex);
typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
propertyEnumeration2,
foundPropertyIndexToDelete,
&parentProperty,
&parentPropertyId);
IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
}
if ( propertyToDelete.propertyType == PROPTYPE_STORAGE )
{
hr = deleteStorageProperty(
This,
foundPropertyIndexToDelete,
propertyToDelete);
}
else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
{
hr = deleteStreamProperty(
This,
foundPropertyIndexToDelete,
propertyToDelete);
}
if (hr!=S_OK)
return hr;
/*
* Adjust the property chain
*/
hr = adjustPropertyChain(
This,
propertyToDelete,
parentProperty,
parentPropertyId,
typeOfRelation);
return hr;
}
/************************************************************************
* StorageImpl_Stat (IStorage)
*
* This method will retrieve information about this storage object.
*
* See Windows documentation for more details on IStorage methods.
*/
HRESULT WINAPI StorageImpl_Stat( IStorage* iface,
STATSTG* pstatstg, /* [out] */
DWORD grfStatFlag) /* [in] */
{
StorageImpl* const This = (StorageImpl*)iface;
HRESULT result = StorageBaseImpl_Stat( iface, pstatstg, grfStatFlag );
if ( !FAILED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName )
{
CoTaskMemFree(pstatstg->pwcsName);
pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
strcpyW(pstatstg->pwcsName, This->pwcsName);
}
return result;
}
/*********************************************************************
*
* Internal Method
*
* Perform the deletion of a complete storage node
*
*/
static HRESULT deleteStorageProperty(
StorageImpl *parentStorage,
ULONG indexOfPropertyToDelete,
StgProperty propertyToDelete)
{
IEnumSTATSTG *elements = 0;
IStorage *childStorage = 0;
STATSTG currentElement;
HRESULT hr;
HRESULT destroyHr = S_OK;
/*
* Open the storage and enumerate it
*/
hr = StorageBaseImpl_OpenStorage(
(IStorage*)parentStorage,
propertyToDelete.name,
0,
STGM_SHARE_EXCLUSIVE,
0,
0,
&childStorage);
if (hr != S_OK)
{
return hr;
}
/*
* Enumerate the elements
*/
IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
do
{
/*
* Obtain the next element
*/
hr = IEnumSTATSTG_Next(elements, 1, ¤tElement, NULL);
if (hr==S_OK)
{
destroyHr = StorageImpl_DestroyElement(
(IStorage*)childStorage,
(OLECHAR*)currentElement.pwcsName);
CoTaskMemFree(currentElement.pwcsName);
}
/*
* We need to Reset the enumeration every time because we delete elements
* and the enumeration could be invalid
*/
IEnumSTATSTG_Reset(elements);
} while ((hr == S_OK) && (destroyHr == S_OK));
/*
* Invalidate the property by zeroing it's name member.
*/
propertyToDelete.sizeOfNameString = 0;
StorageImpl_WriteProperty(parentStorage->base.ancestorStorage,
indexOfPropertyToDelete,
&propertyToDelete);
IStorage_Release(childStorage);
IEnumSTATSTG_Release(elements);
return destroyHr;
}
/*********************************************************************
*
* Internal Method
*
* Perform the deletion of a stream node
*
*/
static HRESULT deleteStreamProperty(
StorageImpl *parentStorage,
ULONG indexOfPropertyToDelete,
StgProperty propertyToDelete)
{
IStream *pis;
HRESULT hr;
ULARGE_INTEGER size;
size.u.HighPart = 0;
size.u.LowPart = 0;
hr = StorageBaseImpl_OpenStream(
(IStorage*)parentStorage,
(OLECHAR*)propertyToDelete.name,
NULL,
STGM_WRITE | STGM_SHARE_EXCLUSIVE,
0,
&pis);
if (hr!=S_OK)
{
return(hr);
}
/*
* Zap the stream
*/
hr = IStream_SetSize(pis, size);
if(hr != S_OK)
{
return hr;
}
/*
* Release the stream object.
*/
IStream_Release(pis);
/*
* Invalidate the property by zeroing it's name member.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -