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

时间:2014-05-05 04:49:17

标签: c++ windows winapi com

我需要能够在系统注册表中保存VARIANT(用于COM自动化),然后再从那里读回来。

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

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

1 个答案:

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