VSS信息的读取的操作有一个影响性能的作业,定位它的行数我不找了,自己看吧。就像这样:
while(enumerator.MoveNext())
{
/// 空循环
}
这个问题困扰了我很久,今天早上无聊的我开始去寻找资料,看了很多很多地方。一些老外好像也碰到这个问题,他们在讨论板上提出了,解决的方法就是我上面写的那段。直到enumerator.MoveNext()返回false,就是迭代完之后,才可以做下一个历史迭代。
否则你就会看到
An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in VssInfo.exe.
Additional information: A history operation is already in progress.
Additional information: A history operation is already in progress.
我的第一直觉就是com对象没有释放所引起的。
如果使用System.Runtime.InteropServices.Marshal.ReleaseComObject(enumerator) 很明显这样会报错,因为迭代器是com Interop产生的.net对象,并不是对COM接口的直接代理。
下面是MSDN上的C++版操作VSS的范例
Sample code
#include <windows.h>
#include <ocidl.h>
#include <stdio.h>
#include "ssauto.h"
void ListVersions( IVSSDatabase* db, LPCSTR path )
{
BSTR bstrval;
char lpbuf[200];
char lpbuf2[200];
IVSSItem *vssi;
IVSSVersion *vers;
IVSSVersions *vx;
LPUNKNOWN lpunk;
IEnumVARIANT *ppvobj;
VARIANT st;
OLECHAR* svalue;
BSTR bstrValue;
int x;
ULONG fetched;
long lvnum;
if( (x = MultiByteToWideChar(CP_ACP, 0, path, -1, svalue, 0 )) != 1)
{
svalue = new OLECHAR[x];
if( MultiByteToWideChar(CP_ACP, 0, path, -1, svalue, x ) == 0 )
MessageBox(NULL, "Error in Conversion", "Multibytetowide", MB_OK);
}
else
svalue = L"";
bstrValue = SysAllocString(svalue);
if( S_OK == db->get_VSSItem(bstrValue, FALSE, &vssi) )
{
if( S_OK == vssi->get_Versions( 0l, &vx ) )
{
if( S_OK == vx->_NewEnum(&lpunk) )
{
if(!FAILED(lpunk->
QueryInterface(IID_IEnumVARIANT, (void**)&ppvobj)))
{
vssi->get_Spec( &bstrval );
x = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)bstrval, -1,
lpbuf, sizeof(lpbuf), NULL, NULL );
printf("History of: %s\n", lpbuf );
printf("ACTION USER NAME VERSION NUMBER\n");
do
{
ppvobj->Next( 1UL, &st, &fetched );
if( fetched != 0 )
{
if(!FAILED(st.punkVal->
QueryInterface(IID_IVSSVersion,(void**)&vers)))
{
vers->get_Action( &bstrval );
WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)bstrval, -1,
lpbuf, sizeof(lpbuf), NULL, NULL );
vers->get_Username( &bstrval );
WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)bstrval, -1,
lpbuf2, sizeof( lpbuf2 ), NULL, NULL );
vers->get_VersionNumber( &lvnum );
printf("%s %s %ld\n", lpbuf, lpbuf2, lvnum );
vers->Release();
}
st.punkVal->Release();
}
} while( fetched != 0 );
ppvobj->Release(); }
lpunk->Release();
}
vx->Release();
}
vssi->Release();
}
SysFreeString(bstrValue);
}
C++在操作com上都遵循了用完就释放的规则,但是迭代器该如何释放呢?
Sample code
#include <windows.h>
#include <ocidl.h>
#include <stdio.h>
#include "ssauto.h"
void ListVersions( IVSSDatabase* db, LPCSTR path )
{
BSTR bstrval;
char lpbuf[200];
char lpbuf2[200];
IVSSItem *vssi;
IVSSVersion *vers;
IVSSVersions *vx;
LPUNKNOWN lpunk;
IEnumVARIANT *ppvobj;
VARIANT st;
OLECHAR* svalue;
BSTR bstrValue;
int x;
ULONG fetched;
long lvnum;
if( (x = MultiByteToWideChar(CP_ACP, 0, path, -1, svalue, 0 )) != 1)
{
svalue = new OLECHAR[x];
if( MultiByteToWideChar(CP_ACP, 0, path, -1, svalue, x ) == 0 )
MessageBox(NULL, "Error in Conversion", "Multibytetowide", MB_OK);
}
else
svalue = L"";
bstrValue = SysAllocString(svalue);
if( S_OK == db->get_VSSItem(bstrValue, FALSE, &vssi) )
{
if( S_OK == vssi->get_Versions( 0l, &vx ) )
{
if( S_OK == vx->_NewEnum(&lpunk) )
{
if(!FAILED(lpunk->
QueryInterface(IID_IEnumVARIANT, (void**)&ppvobj)))
{
vssi->get_Spec( &bstrval );
x = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)bstrval, -1,
lpbuf, sizeof(lpbuf), NULL, NULL );
printf("History of: %s\n", lpbuf );
printf("ACTION USER NAME VERSION NUMBER\n");
do
{
ppvobj->Next( 1UL, &st, &fetched );
if( fetched != 0 )
{
if(!FAILED(st.punkVal->
QueryInterface(IID_IVSSVersion,(void**)&vers)))
{
vers->get_Action( &bstrval );
WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)bstrval, -1,
lpbuf, sizeof(lpbuf), NULL, NULL );
vers->get_Username( &bstrval );
WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)bstrval, -1,
lpbuf2, sizeof( lpbuf2 ), NULL, NULL );
vers->get_VersionNumber( &lvnum );
printf("%s %s %ld\n", lpbuf, lpbuf2, lvnum );
vers->Release();
}
st.punkVal->Release();
}
} while( fetched != 0 );
ppvobj->Release(); }
lpunk->Release();
}
vx->Release();
}
vssi->Release();
}
SysFreeString(bstrValue);
}
C++在操作com上都遵循了用完就释放的规则,但是迭代器该如何释放呢?
Marshal.ReleaseComObject(((ICustomAdapter)enumerator).GetUnderlyingObject());
Marshal.ReleaseThreadCache();
提供对自定义封送拆收器包装的基础对象的访问权限。
[C#] object GetUnderlyingObject();
返回值
适配器对象包含的对象。
今天的心情渐渐变好了......