This is a mirror of official site:

How can I implement SAFEARRAY.ToString() without going insane?

| Monday, September 24, 2012
A colleague needed some help with manipulating SAFEARRAYs.

I have some generic code to execute WMI queries and store the result as strings. Normally, Variant­Change­Type(VT_BSTR) does the work, but Variant­Change­Type doesn't know how to convert arrays (e.g. VT_ARRAY | VT_INT). And there doesn't seem to be an easy way to convert the array element-by-element because Safe­Array­Get­Element expects a pointer to an object of the underlying type, so I'd have to write a switch statement for each variant type. Surely there's an easier way?
One suggestion was to use the ATL CComSafeArray template, but since it's a template, the underlying type of the array needs to be known at compile time, but we don't know the underlying type until run time, which is exactly the problem.

Let's start with the big switch statement and then do some optimization. All before we start typing, because after all the goal of this exercise is to avoid having to type out the massive switch statement. (Except that I have to actually type it so you have something to read.)

Here's the version we're trying to avoid having to type:

HRESULT SafeArrayGetElementAsString(
    SAFEARRAY *psa,
    long *rgIndices,
    LCID lcid, // controls conversion to string
    unsigned short wFlags, // controls conversion to string
    BSTR *pbstrOut)
  *pbstrOut = nullptr;
  HRESULT hr = SafeArrayGetVartype(psa, &vt);
  if (SUCCEEDED(hr)) {
    switch (vt) {
    case VT_I2:
        SHORT iVal;
        hr = SafeArrayGetElement(psa, rgIndices, &iVal);
        if (SUCCEEDED(hr)) {
          hr = VarBstrFromI2(iVal, lcid, wFlags, pbstrOut);
    case VT_I4:
        LONG lVal;
        hr = SafeArrayGetElement(psa, rgIndices, &lVal);
        if (SUCCEEDED(hr)) {
          hr = VarBstrFromI4(lVal, lcid, wFlags, pbstrOut);

QR: Inline image 1

Posted via email from Jasper-net