K
KWienhold
I'm currently working on a project in C# (VS 2003 SP1, .Net 1.1) that
utilizes IStream/IStorage COM-Elements.
Up to now I have gotten everything to work to my satisfaction, but now
I have come across a problem I can't really explain:
When deleting an object from an IStorage, the space it used up will not
be freed, but rather marked as unused and overwritten the next time you
add an object to the storage.
This is obviously working as intended (according to the MSDN) and there
is no simple way to change this behavior.
Since my compound files can contain quite large amounts of data, this
seemed somewhat wasteful (especially given the fact that these files
will probably be sent through Email or uploaded to FTP sites), so I
intended to write a simple function that takes the contents of one
file, copies it to a temporary file, deletes the old and copies the old
contents back to the new file. According to the information I found
about this subject this should free the unused space.
Unfortunately all information I found on the topic was geared towards
C++, wrapping it in C# seems to make things a little more interesting
(as it does for most COM-Interfaces, in my experience).
I create a temporary IStorage using CreateDocFile pass it to the CopyTo
function, along with the parameters that closest resemble the ones I
saw in the C++ examples (0, Guid.Empty, (IntPtr)null), this results in
a COMException saying that an error occured due to an invalid pointer.
According to the MSDN this should only be caused when the pointer to
the IStorage is invalid, but the IStorage-object I pass is definately
functional (I tried adding substorages, streams etc.).
Here are some code snippets from my project that may be relevant:
The lines that actually cause the error:
---------------------------------------------------------------------------------------------------------------------------------------
string TempFile = System.IO.Path.GetTempFileName();
System.IO.File.Delete(TempFile);
APIImports.IStorage TempStorage =
APIImports.CreateStorage(TempFile,m_Read,m_Write);
Document.CopyTo(0,Guid.Empty,(IntPtr)null,TempStorage);
---------------------------------------------------------------------------------------------------------------------------------------
The CreateStorage-function:
---------------------------------------------------------------------------------------------------------------------------------------
IStorage RetVal = null;
uint STGM_Flags = 0;
int ErrCode = -1;
if (Read && !Write)
STGM_Flags = STGM_Flags | STGM_ACCESS_READ;
else if (!Read && Write)
STGM_Flags = STGM_Flags | STGM_ACCESS_WRITE;
else if (Read && Write)
STGM_Flags = STGM_Flags | STGM_ACCESS_READWRITE;
else
return null;
STGM_Flags = STGM_Flags | STGM_SHARE_EXCLUSIVE;
ErrCode = StgCreateDocfile(Path,STGM_Flags,0,out RetVal);
if (ErrCode == 0)
return RetVal;
else
{
Marshal.ThrowExceptionForHR(ErrCode);
return null;
}
---------------------------------------------------------------------------------------------------------------------------------------
My definition for IStorage::CopyTo
---------------------------------------------------------------------------------------------------------------------------------------
void CopyTo(
uint ciidExclude,
Guid rgiidExclude,
IntPtr snbExclude,
IStorage pstgDest);
---------------------------------------------------------------------------------------------------------------------------------------
Any comments would be appreciated.
Sincerely,
Kevin Wienhold
utilizes IStream/IStorage COM-Elements.
Up to now I have gotten everything to work to my satisfaction, but now
I have come across a problem I can't really explain:
When deleting an object from an IStorage, the space it used up will not
be freed, but rather marked as unused and overwritten the next time you
add an object to the storage.
This is obviously working as intended (according to the MSDN) and there
is no simple way to change this behavior.
Since my compound files can contain quite large amounts of data, this
seemed somewhat wasteful (especially given the fact that these files
will probably be sent through Email or uploaded to FTP sites), so I
intended to write a simple function that takes the contents of one
file, copies it to a temporary file, deletes the old and copies the old
contents back to the new file. According to the information I found
about this subject this should free the unused space.
Unfortunately all information I found on the topic was geared towards
C++, wrapping it in C# seems to make things a little more interesting
(as it does for most COM-Interfaces, in my experience).
I create a temporary IStorage using CreateDocFile pass it to the CopyTo
function, along with the parameters that closest resemble the ones I
saw in the C++ examples (0, Guid.Empty, (IntPtr)null), this results in
a COMException saying that an error occured due to an invalid pointer.
According to the MSDN this should only be caused when the pointer to
the IStorage is invalid, but the IStorage-object I pass is definately
functional (I tried adding substorages, streams etc.).
Here are some code snippets from my project that may be relevant:
The lines that actually cause the error:
---------------------------------------------------------------------------------------------------------------------------------------
string TempFile = System.IO.Path.GetTempFileName();
System.IO.File.Delete(TempFile);
APIImports.IStorage TempStorage =
APIImports.CreateStorage(TempFile,m_Read,m_Write);
Document.CopyTo(0,Guid.Empty,(IntPtr)null,TempStorage);
---------------------------------------------------------------------------------------------------------------------------------------
The CreateStorage-function:
---------------------------------------------------------------------------------------------------------------------------------------
IStorage RetVal = null;
uint STGM_Flags = 0;
int ErrCode = -1;
if (Read && !Write)
STGM_Flags = STGM_Flags | STGM_ACCESS_READ;
else if (!Read && Write)
STGM_Flags = STGM_Flags | STGM_ACCESS_WRITE;
else if (Read && Write)
STGM_Flags = STGM_Flags | STGM_ACCESS_READWRITE;
else
return null;
STGM_Flags = STGM_Flags | STGM_SHARE_EXCLUSIVE;
ErrCode = StgCreateDocfile(Path,STGM_Flags,0,out RetVal);
if (ErrCode == 0)
return RetVal;
else
{
Marshal.ThrowExceptionForHR(ErrCode);
return null;
}
---------------------------------------------------------------------------------------------------------------------------------------
My definition for IStorage::CopyTo
---------------------------------------------------------------------------------------------------------------------------------------
void CopyTo(
uint ciidExclude,
Guid rgiidExclude,
IntPtr snbExclude,
IStorage pstgDest);
---------------------------------------------------------------------------------------------------------------------------------------
Any comments would be appreciated.
Sincerely,
Kevin Wienhold