我需要能够在系统注册表中保存VARIANT(用于COM自动化),然后再从那里读回来。
我认为最简单的方法是将其转换为字节数组,然后将其保存(并以相反的方式反转该过程。)问题是我不想开始实现所有可能性VARIANT可能包含的数据类型(包括对象和数组。)
所以我很好奇是否有办法做到这一点? (即序列化VARIANT。)
答案 0 :(得分:1)
找到此解决方案in here。它并没有覆盖所有角落,但它是我迄今为止看到的最接近的角落:
STDMETHODIMP CVarToByteArrayCvt::CvtVariantToByteArray(VARIANT srcVariant, VARIANT *retval)
{
CComVariant vSrcData(srcVariant); // any VARIANT type
IStream *pStream;
HRESULT hRes;
STATSTG statstg;
LPBYTE buf;
ULONG cbRead, ulStreamSize;
USHORT i;
VariantClear(retval);
hRes = CreateStreamOnHGlobal(NULL, TRUE, &pStream); // IStream based on memory handler
if(hRes==S_OK) {
if((vSrcData.vt & VT_ARRAY)==0) { // not an array
hRes = vSrcData.WriteToStream(pStream); // writes VARIANT to a stream (array of bytes)
}
else { // special array handling
hRes = pStream->Write(&srcVariant.vt, sizeof(VARTYPE), NULL); // stores element type
hRes = pStream->Write(&srcVariant.parray->rgsabound[0].lLbound, sizeof(LONG), NULL); // stores lower boundary
hRes = pStream->Write(&srcVariant.parray->rgsabound[0].cElements, sizeof(ULONG), NULL); // stores number of elements
LPVOID ptr;
hRes = SafeArrayAccessData(vSrcData.parray, (LPVOID *)&ptr);
switch (vSrcData.vt & (~VT_ARRAY)) {
case VT_UNKNOWN:
case VT_DISPATCH:
{
LPUNKNOWN *punkValArr = (LPUNKNOWN *)ptr;
for(i = 0; i < srcVariant.parray->rgsabound[0].cElements; i++) {
CComPtr<IPersistStream> spStream;
if(punkValArr[i] != NULL)
hRes = punkValArr[i]->QueryInterface(IID_IPersistStream, (void**)&spStream);
if(spStream != NULL)
OleSaveToStream(spStream, pStream);
else
WriteClassStm(pStream, CLSID_NULL);
}
}
case VT_UI1:
case VT_I1:
{
BYTE *pbyteValArr = (BYTE *)ptr;
for(i = 0; i < srcVariant.parray->rgsabound[0].cElements; i++) {
hRes = pStream->Write((void *)&pbyteValArr[i], sizeof(BYTE), NULL);
}
}
break;
case VT_I2:
case VT_UI2:
case VT_BOOL:
{
short *pshortValArr = (short *)ptr;
for(i = 0; i < srcVariant.parray->rgsabound[0].cElements; i++) {
hRes = pStream->Write((void *)&pshortValArr[i], sizeof(short), NULL);
}
}
break;
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_INT:
case VT_UINT:
case VT_ERROR:
{
long *plongValArr = (long *)ptr;
for(i = 0; i < srcVariant.parray->rgsabound[0].cElements; i++) {
hRes = pStream->Write((void *)&plongValArr[i], sizeof(long), NULL);
}
}
break;
case VT_R8:
case VT_CY:
case VT_DATE:
{
double *pdoubleValArr = (double *)ptr;
for(i = 0; i < srcVariant.parray->rgsabound[0].cElements; i++) {
hRes = pStream->Write((void *)&pdoubleValArr[i], sizeof(double), NULL);
}
}
break;
case VT_BSTR:
{
BSTR *pbstrValArr = (BSTR *)ptr;
for(i = 0; i < srcVariant.parray->rgsabound[0].cElements; i++) {
CComBSTR bstrVal = pbstrValArr[i];
hRes = bstrVal.WriteToStream(pStream);
}
}
break;
case VT_VARIANT:
{
VARIANT *pvariantValArr = (VARIANT *)ptr;
for(i = 0; i < srcVariant.parray->rgsabound[0].cElements; i++) {
CComVariant varVal = pvariantValArr[i];
hRes = varVal.WriteToStream(pStream);
}
}
break;
}
SafeArrayUnaccessData(vSrcData.parray);
};
if(hRes==S_OK) {
hRes = pStream->Stat(&statstg, STATFLAG_NONAME);
if(hRes==S_OK) {
ulStreamSize = (ULONG)statstg.cbSize.QuadPart;
retval->vt=VT_ARRAY|VT_UI1;
retval->parray = SafeArrayCreateVector(VT_UI1, 0, ulStreamSize);
if(retval->parray!=NULL) {
hRes = SafeArrayAccessData(retval->parray, (LPVOID *)&buf);
if(hRes==S_OK) {
_LARGE_INTEGER pos;
pos.QuadPart = 0;
hRes = pStream->Seek(pos, STREAM_SEEK_SET, NULL);
hRes = pStream->Read(buf, ulStreamSize, &cbRead);
SafeArrayUnaccessData(retval->parray);
};
};
};
};
pStream->Release();
};
return hRes;
}
STDMETHODIMP CVarToByteArrayCvt::CvtByteArrayToVariant(VARIANT srcByteArray, VARIANT *retval)
{
HRESULT hRes = S_OK;
LPBYTE buf;
IStream *pStream;
ULONG cbWritten;
CComVariant destVariant;
USHORT i;
VariantClear(retval);
if(srcByteArray.vt==(VT_ARRAY|VT_UI1)) { // is it really a byte array
hRes = SafeArrayAccessData(srcByteArray.parray, (LPVOID *)&buf);
if(hRes==S_OK) {
hRes = CreateStreamOnHGlobal(NULL, TRUE, &pStream); // IStream based on memory handler
if(hRes==S_OK) {
_LARGE_INTEGER pos;
pos.QuadPart = 0;
hRes = pStream->Seek(pos, STREAM_SEEK_SET, NULL);
hRes = pStream->Write(buf, retval->parray->rgsabound[0].cElements, &cbWritten);
if(hRes==S_OK) {
hRes = pStream->Seek(pos, STREAM_SEEK_SET, NULL);
VARTYPE vt;
hRes = pStream->Read((LPVOID)&vt, sizeof(VARTYPE), NULL);
if((vt & VT_ARRAY)==0) { // not an array
hRes = pStream->Seek(pos, STREAM_SEEK_SET, NULL);
hRes = destVariant.ReadFromStream(pStream);
if(hRes==S_OK) VariantCopy(retval, &destVariant);
}
else { // handling an array
retval->vt = vt;
LONG lBound;
ULONG cElems;
LPVOID ptr;
hRes = pStream->Read((LPVOID)&lBound, sizeof(LONG), NULL);
hRes = pStream->Read((LPVOID)&cElems, sizeof(ULONG), NULL);
retval->parray = SafeArrayCreateVector(vt & ~VT_ARRAY, lBound, cElems);
hRes = SafeArrayAccessData(retval->parray, &ptr);
switch (vt & (~VT_ARRAY)) {
case VT_UNKNOWN:
case VT_DISPATCH:
{
LPUNKNOWN *punkArr = (LPUNKNOWN *)ptr;
for(i = 0; i < retval->parray->rgsabound[0].cElements; i++) {
punkArr[i] = NULL;
OleLoadFromStream(pStream,
((vt & VT_UNKNOWN)!=0) ? IID_IUnknown : IID_IDispatch,
(void**)&punkArr[i]);
}
}
case VT_UI1:
case VT_I1:
{
BYTE *pbyteValArr = (BYTE *)ptr;
for(i = 0; i < retval->parray->rgsabound[0].cElements; i++) {
hRes = pStream->Read((void *)&pbyteValArr[i], sizeof(BYTE), NULL);
}
}
break;
case VT_I2:
case VT_UI2:
case VT_BOOL:
{
short *pshortValArr = (short *)ptr;
for(i = 0; i < retval->parray->rgsabound[0].cElements; i++) {
hRes = pStream->Read((void *)&pshortValArr[i], sizeof(short), NULL);
}
}
break;
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_INT:
case VT_UINT:
case VT_ERROR:
{
long *plongValArr = (long *)ptr;
for(i = 0; i < retval->parray->rgsabound[0].cElements; i++) {
hRes = pStream->Read((void *)&plongValArr[i], sizeof(long), NULL);
}
}
break;
case VT_R8:
case VT_CY:
case VT_DATE:
{
double *pdoubleValArr = (double *)ptr;
for(i = 0; i < retval->parray->rgsabound[0].cElements; i++) {
hRes = pStream->Read((void *)&pdoubleValArr[i], sizeof(double), NULL);
}
}
break;
case VT_BSTR:
{
BSTR *pbstrValArr = (BSTR *)ptr;
for(i = 0; i < retval->parray->rgsabound[0].cElements; i++) {
CComBSTR bstrVal;
pbstrValArr[i] = NULL;
hRes = bstrVal.ReadFromStream(pStream);
pbstrValArr[i] = ::SysAllocString((wchar_t *)bstrVal);
}
}
break;
case VT_VARIANT:
{
VARIANT *pvariantValArr = (VARIANT *)ptr;
for(i = 0; i < retval->parray->rgsabound[0].cElements; i++) {
CComVariant varVal;
hRes = varVal.ReadFromStream(pStream);
VariantCopy(&pvariantValArr[i], &varVal);
}
}
break;
}
SafeArrayUnaccessData(retval->parray);
};
};
pStream->Release();
};
SafeArrayUnaccessData(srcByteArray.parray);
};
};
return hRes;
}