将VARIANT转换为字节,反之亦然

Convert VARIANT to bytes and vise versa?

本文关键字:反之亦然 字节 VARIANT 转换      更新时间:2023-10-16

我需要能够在系统注册表中保存一个VARIANT(用于COM自动化),然后稍后从那里读取它。

我认为最简单的方法是将其转换为字节数组,然后保存它(并反过来处理)。问题是我不想开始实现VARIANT可能包含的所有数据类型(包括对象和数组)的所有可能性。

所以我很好奇是否有办法做到这一点?(即序列化一个VARIANT)

在这里找到了这个解决方案。它没有覆盖所有的角落,但它是目前为止我见过的最接近的:

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;
}