사용자 도구

사이트 도구


kb:comvariant

COM Variant

COM과 관련된 여러 오브젝트들이 VARIANT라는 것을 함수 인자로 받아들인다. 아래의 코드들은 이 VARIANT와 C 타입 간의 상호 변환을 다룬다.

화폐 단위 변환

void CVarUseDlg::OnCurrency() 
{
    VARIANT myVar;
    myVar.vt = VT_CY;
 
    // put 15.15 into the currency variant.
    CURRENCY myValue;
    myValue.Hi = 0;
    myValue.Lo = (LONG)(15*10000 + 1537); // set the value to $15.15;
    myVar.cyVal = myValue;
    //or
    myValue.int64 = (151234);
    myVar.cyVal = myValue;
 
    //Now get the value from a float and put it into the currency.
    float myMoney = (float)5.37;
    myVar.vt = VT_R4;
    myVar.fltVal = myMoney;
    //no loss of precission.
    VariantChangeType(&myVar, &myVar, 0, VT_CY);
 
    //Now get the value from a String
    USES_CONVERSION;
    myVar.bstrVal = SysAllocString(L"$23.4345");
    myVar.vt = VT_BSTR;
    VariantChangeType(&myVar, &myVar, 0, VT_CY);
 
    //Finally output a currency to a string.
    myVar.cyVal.int64 += myVar.cyVal.int64; // + myVar.cyVal;
    VariantChangeType(&myVar, &myVar, 0, VT_BSTR);
}

문자열 변환

void CVarUseDlg::OnStrings() 
{
    //Create a BSTR and assign it to a Variant
    BSTR x = SysAllocString(L"Hello");
    VARIANT myVariant;
    myVariant.vt = VT_BSTR;
    myVariant.bstrVal = x;
    SysFreeString(x);
 
    //Create a CString and change it to a variant;
    CString myCString(_T("My String"));
    CString mySecondString;
 
    //This is required to use the T2COLE macro.
    USES_CONVERSION;
 
    BSTR y = SysAllocString(T2COLE(myCString));
    myVariant.bstrVal = y;
    mySecondString = y;
    SysFreeString(y);
 
    //Create two BSTRs and add them.
    BSTR a = SysAllocString(L"One two ");
    BSTR b = SysAllocString(L"three four.");
    _bstr_t my_bstr_t(a, TRUE);
    my_bstr_t += b;
    myVariant.bstrVal = my_bstr_t;
    // or
    myVariant.bstrVal = _bstr_t(a, FALSE) + b;
 
    //Change a bstr to a CString.
    CString ANewString(b);
    //or if CString already exists.
    myCString = b;
 
    //Use of CComBSTR
    CComBSTR myCComBSTR(L"Hello");
    myCComBSTR.Append(L", how are you?");
    VARIANT varFromCCom;
    varFromCCom.vt = VT_BSTR;
    varFromCCom.bstrVal = myCComBSTR;
}

기본형 변환

void CVarUseDlg::OnBasic() 
{
    //create a variant of the character 'c'
    VARIANT varC;
    varC.vt=VT_UI1;
    varC.cVal = 'c';
 
    //create a variant of the short 12
    VARIANT varS;
    varS.vt = VT_I2;
    varS.iVal = 12;
 
    //create a variant of the long 1234567;
    VARIANT varL;
    varL.vt = VT_I4;
    varL.lVal = 1234567;    
}

SAFEARRAY 변환

void CVarUseDlg::OnSafeArray() 
{
    //Create a standard array;
    int* pMyOriginalArray = new int[100];
    for(int count = 0; count < 100; count++) pMyOriginalArray[count] = count;
 
    //Now get ready to put it into a safe array
    HRESULT hr;
    //create an array bound
    SAFEARRAYBOUND rgsabound[1];
    rgsabound[0].lLbound = 0;       //The first (and only) collumn of our array starts at 0.
    rgsabound[0].cElements = 100;   //and has 100 elements.
 
    //create the array
    SAFEARRAY FAR* pMySafeArray;
    pMySafeArray = SafeArrayCreate(VT_I4, 1, rgsabound); //create the array of 4byte integers, one dimension
 
    //now access the safe array's data.
    int* pData;
    hr = SafeArrayAccessData(  pMySafeArray, (void**)&pData); //Get a pointer to the data.
 
    //copy the 400 bytes of data from our old array to the new one.
    memcpy(pData, pMyOriginalArray, 400);
 
    //here we verify to you that the data is correct.
    for(count = 0; count < 100; count++) ASSERT(pData[count] == pMyOriginalArray[count]);
    SafeArrayUnaccessData(pMySafeArray);
 
    //To put the SafeArray in a Variant
    VARIANT myVariant; 
    myVariant.parray = pMySafeArray;
    myVariant.vt = VT_ARRAY|VT_I4; // state it's an array and what type it holds.
 
    //pass the Variant to a function call.  
    FunctionCallWithVariant(myVariant);
    //see that the original array was modified.
    hr = SafeArrayAccessData(myVariant.parray, (void**)&pData); //Get a pointer to the data.
    ASSERT(pData[0] == 1234);
    SafeArrayUnaccessData(pMySafeArray);
 
    //Copy the variant.
    VARIANT NewVariant;
    NewVariant.vt = VT_EMPTY; // must set variant type for copy to work.
    hr = VariantCopy(&NewVariant, &myVariant);
 
    //check array in copy of variant
    int* pNewData;
    hr = SafeArrayAccessData(NewVariant.parray, (void**) &pNewData);
    for(count = 0; count < 100; count++) ASSERT(pData[count] == pNewData[count]);
    ASSERT(pData != pNewData); //copying the varriant created a new copy of the 
                               //array it contained too.  There is now 2 copies of the data.
    SafeArrayUnaccessData(NewVariant.parray);
 
    //Or you could use CreateVector to create the 1 dimensional array.
    SAFEARRAY* pMyVector = SafeArrayCreateVector(VT_I4, -50, 100);  //Vecoor of VT_I4, starting at 0
                                                                //with 100 elements.
    int* pVectorData;
    hr = SafeArrayAccessData(pMyVector, (void**)&pVectorData);
    memcpy(pVectorData, pMyOriginalArray, 400); //copy the 400 bytes of data from our old array into the new one.
    int element;
    long location[1] = {-50};
    hr = SafeArrayGetElement(pMyVector, location, (void*)&element);
    ASSERT(element == 0); //element -50 is the first element from the original array
    location[0] = 0;
    hr = SafeArrayGetElement(pMyVector, location, (void*)&element);
    ASSERT(element == 50); // element 0 is the 50th element from the original array
    delete[] pMyOriginalArray;
    hr = SafeArrayDestroy(pMySafeArray);
    hr = SafeArrayDestroy(pMyVector);
    hr = SafeArrayDestroy(NewVariant.parray);
}

OLEARRAY 변환

void CVarUseDlg::OnOleArray() 
{
    //Create and fill an array.
    int* pMyOriginalArray = new int[100];
    int* pData;
    for(int count = 0; count < 100; count++) pMyOriginalArray[count]=count;
 
    //Put it into a safe array.
    COleSafeArray myOleSafeArray;
    myOleSafeArray.CreateOneDim(VT_I4, 100, pMyOriginalArray); // create one dimension array of 4-byte values
                                                               // 100 entries w/data from pMyOriginalArray.
    // Access that safe array.
    //Get a pointer to the Data.
    myOleSafeArray.AccessData((void**)&pData); 
    //verify all of the data.
    for(count = 0; count < 100; count++) ASSERT(pData[count] == pMyOriginalArray[count]);
    myOleSafeArray.UnaccessData();
 
    //clean up.
    delete[] pMyOriginalArray;  
}

다차원배열 변환

void CVarUseDlg::OnMultiDimensionArray() 
{
    short pMyOriginalData[2][3][4][5];
    HRESULT hr;
    //initialize data
    for(short a = 0; a < 2; a++)
        for(short b = 0; b < 3; b++)
            for(short c = 0; c < 4; c++)
                for(short d = 0; d < 5; d++)
                    pMyOriginalData[a][b][c][d] = a*b*c*d;
 
    SAFEARRAY* pMyArray;
    SAFEARRAYBOUND rgsabound[4];
    for(int count = 2; count < 6; count++)
    {
        rgsabound[count - 2].lLbound = 0;
        rgsabound[count - 2].cElements = count;
    }
    pMyArray = SafeArrayCreate(VT_I2, 4, rgsabound);
    short* pData;
    hr = SafeArrayAccessData(pMyArray, (void**)&pData);
    memcpy(pData, pMyOriginalData, 2*3*4*5*2);
    short element;
    long location[4] = {1,2,3,4};
    hr = SafeArrayGetElement(pMyArray, location, (void*)&element);
    ASSERT(element == 1*2*3*4);
 
    hr = SafeArrayDestroy(pMyArray);
    ASSERT(hr != S_OK);
    hr = SafeArrayUnaccessData(pMyArray);
    hr = SafeArrayDestroy(pMyArray);
    ASSERT(hr == S_OK);
}

날짜변환

void CVarUseDlg::OnDate() 
{
    VARIANT timeSelection;
    COleDateTime timeNow;
    DATE curDate;
    HRESULT hr;
    //Get current Time.
    timeNow = COleDateTime::GetCurrentTime();
 
    //Put time into variant.
    timeSelection.vt = VT_DATE;
    timeSelection.date = timeNow.m_dt;
 
    //Convert Variant into string using Variant Change Type.
    hr = VariantChangeType(&timeSelection, &timeSelection, 0, VT_BSTR);
    CString sCurTime(timeSelection.bstrVal);
 
    //Get Time as System Time.
    SYSTEMTIME mySysTime;
    timeNow.GetAsSystemTime(mySysTime);
 
    //Use COleDateTime functionality to get change SYSTEMTIME into DATE.
    COleDateTime pastTime(mySysTime);
    curDate = pastTime.m_dt;
 
 
    //Use COldeDateTime Format command to get date as CString.
    LPCTSTR format = _T("%X %z");  //Current time and time zone.
    //Note see "strftime" help for valid formating strings. 
    CString sTime = pastTime.Format(format);
}

VARIANT를 인자로 함수 호출

void CVarUseDlg::FunctionCallWithVariant(VARIANT myVariant)
{
    HRESULT hr;
    int* pData;
    int count;
    hr = SafeArrayAccessData(myVariant.parray, (void**)&pData); //access the array stored in the varriant.
    for(count = 0; count < 100; count++) ASSERT(pData[count] == count); //check data;
    pData[0] = 1234; //modify data
    SafeArrayUnaccessData(myVariant.parray);
}

참고

kb/comvariant.txt · 마지막으로 수정됨: 2014/11/06 19:59 (바깥 편집)