如何两次打开一个复合文档?

Cline 2006-10-21 04:49:22
如何两次打开一个复合文档,第一次以读的方式打开,并且Keep一些IStorage接口指针.第二次以读写方式打开,然后先读取流中数把,最后写入新的数据.代码如下,运行到Ln95:时报"Access denied"错误.

如果把Ln42的共享方式改成STGM_SHARE_DENY_NONE,本行报"Invalid flags".
如果把Ln42行去掉,Ln95能成功.

//Create a compound file
const WCHAR* pwszFileName = L"C:\\Test.stg";
const WCHAR* pwszStorageName = L"TestStorage";
const WCHAR* pwszStreamName = L"TestStream";
CComPtr<IStorage> pRootStg;
HRESULT hr = ::StgCreateDocfile(pwszFileName, STGM_READWRITE|STGM_CREATE |STGM_SHARE_EXCLUSIVE, 0, &pRootStg) ;
ASSERT(SUCCEEDED(hr));

//Create a sub storage
CComPtr<IStorage> pSubStg;
hr = pRootStg->CreateStorage(pwszStorageName,STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &pSubStg);
ASSERT(SUCCEEDED(hr));



//Create a stream inside of the sub storage
CComPtr<IStream> pStream;
hr = pSubStg->CreateStream(pwszStreamName,STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0 , 0, &pStream);

ASSERT(SUCCEEDED(hr));

//Write some data to the stream
const TCHAR* pszTestData = _T("Test data");
ULONG ulWrittenLen = 0;
hr = pStream->Write(pszTestData, sizeof(TCHAR) * _tcslen(pszTestData), &ulWrittenLen);
ASSERT(SUCCEEDED(hr));

//Release all strorage and stream
pStream = NULL;
pSubStg = NULL;
pRootStg = NULL;

//Open this compound file with readable mode.
CComPtr<IStorage> pRootStgR;
CComPtr<IStorage> pSubStgR;
for(;;)
{
//Open root storage
hr = ::StgOpenStorage(pwszFileName, NULL, STGM_DIRECT_SWMR|STGM_READ|STGM_SHARE_DENY_NONE, NULL, 0, &pRootStgR);
ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
break;

//Open sub storage
Ln42: hr = pRootStgR->OpenStorage(pwszStorageName, NULL, STGM_DIRECT_SWMR|STGM_READ|STGM_SHARE_EXCLUSIVE, NULL, 0, &pSubStgR);

ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
break;
break;

}



//Open this compound file with writable mode
CComPtr<IStorage> pRootStgW;
CComPtr<IStorage> pSubStgW;
char* pszOldData = NULL;

for(;;)
{
//Open root storage
hr = ::StgOpenStorage(pwszFileName, NULL, STGM_DIRECT_SWMR|STGM_READWRITE|STGM_SHARE_DENY_WRITE, NULL, 0, &pRootStgW);
ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
break;

//Open sub storage
hr = pRootStgW->OpenStorage(pwszStorageName, NULL, STGM_DIRECT_SWMR|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &pSubStgW);
ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
break;

//Open stream
CComPtr<IStream> pStreamW;
hr = pSubStgW->OpenStream(pwszStreamName, NULL, STGM_DIRECT_SWMR|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &pStreamW);
ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
break;

//Read old data
STATSTG Status;
hr = pStreamW->Stat(&Status, STATFLAG_DEFAULT);
ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
break;

pszOldData = new char[Status.cbSize.LowPart + 1];
ULONG ulReadLen = 0;
hr = pStreamW->Read(pszOldData, Status.cbSize.LowPart, &ulReadLen);
ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
break;
ASSERT(ulReadLen == Status.cbSize.LowPart);
pszOldData[Status.cbSize.LowPart] = '\0';

//Clean old data
ULARGE_INTEGER ZERO_INTEGER;
ZERO_INTEGER.HighPart = 0;
ZERO_INTEGER.LowPart = 0;
Ln95: hr = pStreamW->SetSize(ZERO_INTEGER);
ASSERT(SUCCEEDED(hr));
if(FAILED(hr))
break;

//Write new data
const TCHAR* pszNewData = _T("New data");
hr = pStreamW->Write(pszNewData, sizeof(TCHAR) * _tcslen(pszNewData), &ulWrittenLen);
ASSERT(SUCCEEDED(hr));
break;

}

if(pszOldData)
delete[] pszOldData;
...全文
212 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
Cline 2006-10-24
  • 打赏
  • 举报
回复
谢谢大家的建议.

根据soarer(暮鼓残阳) 的建议,我先把以只读方式打开的所有IStorage和IStream指针释放了,然后再以读写方式打开,用完关之.

如果其它模块要访问最初以只读方式打开的数据,再重新打开文件,以获取相应的IStorage*和IStream*.
soarer 2006-10-22
  • 打赏
  • 举报
回复
我也遇到过这个问题
在L42处,就算是我只是为了读而打开一个sub storage,也要用STGM_SHARE_EXCLUSIVE,否则失败
这在msdn的例子上也是这么干的
见http://windowssdk.msdn.microsoft.com/en-us/library/ms535371(VS.80).aspx

L42跟L95的冲突,是权限冲突了,前面你用share exclusive方式打开了,后面你再打开并且要改变stream的大小那肯定是有冲突了

解决方案是,不要先打开读,写操作完成后,再读。
DentistryDoctor 2006-10-22
  • 打赏
  • 举报
回复
弄这么复杂,没看明白。
Torch009 2006-10-22
  • 打赏
  • 举报
回复

3,245

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧