2011. 1. 3. 22:29

OLE Automation 에서 배열을 반환하는 방법

MFC 에서 사용하는 방법 (COleSafeArray 클래스 이용)


/*
 * CMfcarrayDoc::GetArray
 *
 * Purpose:
 *  Creates and returns an array.
 *
 * Return Value:
 *  Returns the array.
 *
 */
VARIANT CMfcarrayDoc::GetArray() 
{
    VARIANT vaResult;
    VariantInit(&vaResult);

    SAFEARRAYBOUND sabound[1];  
    SAFEARRAY FAR* psa = NULL;
    BSTR bstr = NULL;     
    HRESULT hr;
    
    // Create an array of size 100
    sabound[0].cElements = 100;
    sabound[0].lLbound = 0;    
    psa = SafeArrayCreate(VT_BSTR, 1, sabound);
    if (psa == NULL)
        AfxThrowOleDispatchException(1004, "Out of Memory");
    
    // Fill each array element with the same string, "contents"
    bstr = SysAllocString(OLESTR("contents")); 
    for (long i=0; i<100; i++)
    {
        hr = SafeArrayPutElement(psa, &i, bstr);
        if (FAILED(hr))
            goto error;
    }  
    SysFreeString(bstr);  
    V_VT(&vaResult) = VT_ARRAY | VT_BSTR;
    V_ARRAY(&vaResult) = psa;    
    return vaResult;
         
error:
    if (bstr) SysFreeString(bstr); 
    if (psa) SafeArrayDestroy(psa);
    AfxThrowOleDispatchException(1003, "Unexpected Failure in GetArray method");
    return vaResult;
}
파일을 다운로드한 후 다음 명령을 사용하여 샘플의 압축을 풀고 적절한 디렉터리 구조에 빌드.
MFCArray.exe - d



      VARIANT _stdcall retVariantArray(void) {
         COleSafeArray saRet;
         DWORD numElements[] = {10, 10}; // 10x10

         // Create the safe-array...
         saRet.Create(VT_R8, 2, numElements);

         // Initialize it with values...
         long index[2];
         for(index[0]=0; index[0]<10; index[0]++) {
            for(index[1]=0; index[1]<10; index[1]++) {
               double val = index[0] + index[1]*10;
               saRet.PutElement(index, &val);
            }
         }

         // Return the safe-array encapsulated in a VARIANT...
         return saRet.Detach();
      }
ATL 에서 SAFEARRAY 구조체 이용


   ...
   #include 
   ...
   long CStrArrayDoc::Sort(VARIANT FAR* vArray)
   {

      long i, j, min;
      BSTR bstrTemp;
      SAFEARRAY FAR* psa = NULL;
      BSTR HUGEP *pbstr;
      HRESULT hr;
      DWORD dwTimeStart;
      LONG cElements, lLBound, lUBound;

      USES_CONVERSION;

      // Type check VARIANT parameter. It should contain a BSTR array
      // passed by reference. The array must be passed by reference it is
      // an in-out-parameter.
      if (V_VT(vArray) != (VT_ARRAY | VT_BSTR))
         AfxThrowOleDispatchException(1001,
           "Type Mismatch in Parameter. Pass a string array by reference");
      psa = V_ARRAY(vArray);
      // Check dimensions of the array.
      if (SafeArrayGetDim(psa) != 1)
         AfxThrowOleDispatchException(1002,
           "Type Mismatch in Parameter. Pass a one-dimensional array");

      dwTimeStart = GetTickCount();

      // Get array bounds.
      hr = SafeArrayGetLBound(psa, 1, &lLBound);
      if (FAILED(hr))
          goto error;
      hr = SafeArrayGetUBound(psa, 1, &lUBound);
      if (FAILED(hr))
          goto error;

      // Get a pointer to the elements of the array.
      hr = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pbstr);
      if (FAILED(hr))
         goto error;

      // Bubble sort.
      cElements = lUBound-lLBound+1;
      for (i = 0; i < cElements-1; i++)
      {
         min = i;
         for (j = i+1; j < cElements; j++)
         {
            // NULL is a valid value for a BSTR. This code treats a NULL
            // BSTR as less than other string values.
            if (pbstr[min] == NULL)
               continue;
            else if (pbstr[j] == NULL
               || wcscmp(pbstr[j], pbstr[min]) < 0)
               min = j;
         }

         //Swap array[min] and array[i].
         bstrTemp = pbstr[min];
         pbstr[min] = pbstr[i];
         pbstr[i] = bstrTemp;
      }

      hr = SafeArrayUnaccessData(psa);
      if (FAILED(hr))
         goto error;

      return GetTickCount()-dwTimeStart;

   error:

      AfxThrowOleDispatchException(1003,
        "Unexpected Failure in FastSort method");
      return 0;

   }
	
서버 테스트

   Private Sub Command1_Click()
      Dim o As Object
      Dim v As Variant
      ReDim v(50) As String
      Dim SortTime As Long

      Set o = CreateObject("StrArray.Document")

      upperbound = 1
      lowerbound = 100
      For n = 0 To 50
          v(n) = "Entry " & Int((upperbound-lowerbound+1)*Rnd+lowerbound)
      Next n

      SortTime = o.Sort(v)
      MsgBox ("Done")
   End Sub

기타 참고: