首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

從 JavaScript/VBScript 向 COM 元件傳遞陣列:VARIANT 與 SafeArray 處理

     編輯:VC 教學

IDL 介面定義

[id(1), helpstring("方法 InputArray")] HRESULT InputArray([in] VARIANT vData);

腳本端建立陣列差異

  • VBScript:陣列直接對應 SAFEARRAY,VARIANT.vt = VT_ARRAY | VT_VARIANT,效能優異(100k 元素亦流暢)。
  • JavaScript:陣列非真正陣列,傳至 COM 時封裝為集合物件,VARIANT.vt = VT_DISPATCH,需透過 IDispatch::Invoke(DISPID_NEWENUM) 取得列舉器逐一讀取,效能極差(CPU/記憶體佔用極高)。

COM 端統一處理代碼

STDMETHODIMP CBigParamCtl::InputArray(VARIANT vData)
{
    LPBYTE pData = NULL;
    DWORD nLen = 0;
    HRESULT hr;

    if (vData.vt == VT_DISPATCH) {
        // JavaScript 陣列
        hr = VariantEnumToBytes(vData.pdispVal, &pData, &nLen);
    } else {
        // VBScript 陣列
        hr = VariantArrayToBytes(&vData, &pData, &nLen);
    }

    if (SUCCEEDED(hr)) {
        // ... 處理 pData ...
        delete[] pData;
    }
    return S_OK;
}

JavaScript 陣列解析:VariantEnumToBytes

HRESULT VariantEnumToBytes(IDispatch* disp, LPBYTE* ppBytes, DWORD* pdwBytes)
{
    HRESULT hr;
    DISPPARAMS noArgs = {0};
    CComVariant resultV;

    // 取得 _NewEnum 列舉器
    hr = disp->Invoke(DISPID_NEWENUM, IID_NULL, LOCALE_SYSTEM_DEFAULT,
        DISPATCH_PROPERTYGET, &noArgs, &resultV, NULL, NULL);
    if (FAILED(hr) || FAILED(resultV.ChangeType(VT_UNKNOWN))) return E_FAIL;
    if (resultV.vt != VT_UNKNOWN && resultV.vt != VT_DISPATCH) return E_FAIL;

    CComQIPtr pEnum(resultV.punkVal);
    if (!pEnum) return E_FAIL;

    // 計算元素數
    *pdwBytes = 0;
    while (pEnum->Skip(1) == S_OK) (*pdwBytes)++;

    // 配置記憶體
    *ppBytes = new BYTE[*pdwBytes];
    int nCount = 0;
    CComVariant elemV;
    pEnum->Reset();

    // 逐一讀取並轉換
    while (pEnum->Next(1, &elemV, NULL) == S_OK) {
        if (elemV.vt != VT_I4) { hr = S_FALSE; break; } // 修正 proxy bug
        int nTmp = elemV.lVal;
        (*ppBytes)[nCount++] = (BYTE)nTmp;
    }
    return S_OK;
}

VBScript 陣列解析:VariantArrayToBytes

HRESULT VariantArrayToBytes(VARIANT* pVariant, LPBYTE* ppBytes, DWORD* pdwBytes)
{
    if (pVariant->vt != (VT_VARIANT | VT_BYREF)) return E_INVALIDARG;
    if (!(pVariant->pvarVal->vt & VT_ARRAY)) return E_INVALIDARG;

    SAFEARRAY* pX = (pVariant->pvarVal->vt & VT_BYREF)
        ? *(pVariant->pvarVal->pparray)
        : pVariant->pvarVal->parray;

    if (SafeArrayGetDim(pX) != 1) return E_INVALIDARG;

    *ppBytes = NULL; *pdwBytes = 0;
    VARIANT* pArray = NULL;
    HRESULT hr = SafeArrayAccessData(pX, (void**)&pArray);
    if (SUCCEEDED(hr)) {
        *pdwBytes = pX->rgsabound->cElements;
        *ppBytes = new BYTE[*pdwBytes];
        _variant_t v;
        for (DWORD i = 0; i < *pdwBytes; i++) {
            v = pArray[i];
            v.ChangeType(VT_UI1);
            (*ppBytes)[i] = v.bVal;
        }
        SafeArrayUnaccessData(pX);
    }
    SafeArrayDestroy(pX);
    return hr;
}

效能建議

大量資料傳遞(>10k 元素)強烈建議使用 VBScript 或改用二進位 Blob/檔案傳輸,避免 JavaScript 陣列轉換的效能災難。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved