📄 common.cpp
字号:
//We need to take N-Dimensions of Data and convert it to a string
//For example: We have a 3D data, where z-dim has 2 elements, y-Dim has 3 ele
//and x-dim has 2 elements we end up with the following matrix of points
// (z, y, x) => value [[[
// (1, 1, 1) => 1
// (1, 1, 2) => 2
// (1, 2, 1) => 3 ][
// (1, 2, 2) => 4
// (1, 3, 1) => 5 ][
// (1, 3, 2) => 6
// (2, 1, 1) => 7 ]][[
// (2, 1, 2) => 8
// (2, 2, 1) => 9 ][
// (2, 2, 2) => A
// (2, 3, 1) => B ][
// (2, 3, 2) => C
// ]]]
//So what we need to generate is a string of:
// [ [[1,2][3,4][5,6]] [[7,8][9,A][B,C]] ]
//The algorythm we are using is bascially based upon a "ripple" counter.
//We keep a counter for each dimension. So when CounterDim[0] hits the Upper
//Limit, we increment CounterDim[1] and set CounterDim[0] back to LowerLimit.
//This continues until all have reached the upper limit together:
//{CounterDim[n-1]==UpperLimt, ... Dim[0]==UpperLimit}
//The braces are determined by rising/falling edges of the ripple counter.
//Everytime a dimension restarts its value from Upper->Lower we see a "][".
//So we have a pre and a post set of - "[[[" braces "]]]" for the number of dimensions.
//You'll notices the set of braces in the above example on the rising/falling
//edges of the ripple counter....
HRESULT hr = S_OK;
VARIANT Variant;
VariantInit(&Variant);
CHAR* psz = pszBuffer;
ULONG i,iDim, ulInnerElements = 0;
ULONG cDimensions = SafeArrayGetDim(pSafeArray);
BOOL bDone = FALSE;
//No-op
if(cDimensions < 1)
return E_FAIL;
//Make sure there is no Array in the type
wType &= ~VT_ARRAY;
ULONG ulStrLen, ulSizeLeft = ulMaxSize;
pszBuffer[0] = EOL;
LONG* rgIndices = NULL;
SAFE_ALLOC(rgIndices, LONG, cDimensions);
//Loop over all dimenstions and fill in "pre" info...
for(iDim=0; iDim<cDimensions; iDim++)
{
//Fill in lower bound
LONG lLowerBound = 0;
SafeArrayGetLBound(pSafeArray, iDim+1, &lLowerBound);
rgIndices[iDim] = lLowerBound;
//Fill in outer dimension indicater
strcat(pszBuffer, "[");
}
//Calculate the total number of inner items...
//This is easy, all dimensions will have the same number "inner" items
//IE: rg[y][x] - all y arrays have x elements.
//IE: rg[z][y][x] - all z arrays, have y arrays, which have x elements
ulInnerElements = pSafeArray->rgsabound[0].cElements;
while(!bDone)
{
//Dimension[0] always goes through a complete cycle every time
//Just do this part of the ripple counter seperately...
for(i=0; i<ulInnerElements; i++)
{
//Initialize Variant
VariantInit(&Variant);
V_VT(&Variant) = wType;
//Obtain the Data from the SafeArray
TESTC(hr = SafeArrayGetElement(pSafeArray, rgIndices, &V_I4(&Variant)));
rgIndices[0]++;
//Adjust next string placement
ulStrLen = strlen(psz);
psz = psz + ulStrLen;
ulSizeLeft -= ulStrLen;
//Convert VARIANT To String
TESTC(hr = VariantToString(&Variant, psz, ulSizeLeft, CONV_NONE));
//Array Seperator
if(i<ulInnerElements-1)
strcat(psz, ",");
//Clear the Variant, (could be outofline memory...)
XTEST(NULL, VariantClear(&Variant));
}
//Adjust the other Dimensions of the ripple counter
for(iDim=0; iDim<cDimensions; iDim++)
{
LONG lUpperBound = 0;
SafeArrayGetUBound(pSafeArray, iDim+1, &lUpperBound);
//Increment this ripple if below max bound, and exit out (break)
if(rgIndices[iDim] < lUpperBound)
{
rgIndices[iDim]++;
//Need to add opening braces...
for(ULONG j=iDim; j>0; j--)
strcat(psz, "[");
break;
}
//Otherwise reset this one and move onto the
//next Dimension (ie: Don't break...)
else if(iDim != cDimensions-1)
{
LONG lLowerBound = 0;
SafeArrayGetLBound(pSafeArray, iDim+1, &lLowerBound);
rgIndices[iDim] = lLowerBound;
strcat(psz, "]");
}
//If we have hit the last Dimension and its over the value
//This means were done...
else
{
bDone = TRUE;
}
}
}
//Display Right outer braces
for(iDim=0; iDim<cDimensions; iDim++)
strcat(pszBuffer, "]");
CLEANUP:
XTEST(NULL, VariantClear(&Variant));
SAFE_FREE(rgIndices);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// HRESULT StringToSafeArray
//
/////////////////////////////////////////////////////////////////////////////
HRESULT StringToSafeArray(WCHAR* pwszBuffer, DBTYPE wType, SAFEARRAY** ppSafeArray)
{
ASSERT(pwszBuffer);
ASSERT(ppSafeArray);
ASSERT(!(wType & VT_ARRAY));
//This method is capable of handling N-Dimenstions of Data!!
//We need to a String of N Dimensions and turn it into a SafeArray
//For example: We have a 3D data, where z-dim has 2 elements, y-Dim has 3 ele
//and x-dim has 2 elements we end up with the following matrix of points
// (z, y, x) => value [[[
// (1, 1, 1) => 1
// (1, 1, 2) => 2
// (1, 2, 1) => 3 ][
// (1, 2, 2) => 4
// (1, 3, 1) => 5 ][
// (1, 3, 2) => 6
// (2, 1, 1) => 7 ]][[
// (2, 1, 2) => 8
// (2, 2, 1) => 9 ][
// (2, 2, 2) => A
// (2, 3, 1) => B ][
// (2, 3, 2) => C
// ]]]
//So we could be passed a string of:
// [ [[1,2][3,4][5,6]] [[7,8][9,A][B,C]] ]
//The algorythm we are using is bascially based upon a "ripple" counter.
//We keep a counter for each dimension. So when CounterDim[0] hits the Upper
//Limit, we increment CounterDim[1] and set CounterDim[0] back to LowerLimit.
//This continues until all have reached the upper limit together:
//{CounterDim[n-1]==UpperLimt, ... Dim[0]==UpperLimit}
//The braces are determined by rising/falling edges of the ripple counter.
//Everytime a dimension restarts its value from Upper->Lower we see a "][".
//So we have a pre and a post set of - "[[[" braces "]]]" for the number of dimensions.
//You'll notices the set of braces in the above example on the rising/falling
//edges of the ripple counter....
HRESULT hr = S_OK;
VARIANT Variant;
VariantInit(&Variant);
WCHAR wszBuffer[MAX_COL_SIZE];
wszBuffer[0] = EOL;
WCHAR* pwsz = pwszBuffer;
ULONG i,iDim, ulInnerElements = 0;
//Determine the Number of Dimensions...
ULONG cDimensions = 0;
while(pwsz[0]==L'[')
{
cDimensions++;
pwsz++;
wcscat(wszBuffer, L"]");
}
//Find the End of the Data (where everever "]...") is...
WCHAR* pwszNext = pwsz;
WCHAR* pwszEnd = pwsz;
WCHAR* pwszCurEnd = wcsstr(pwsz, L"]");
WCHAR* pwszEndString = wcsstr(pwsz, wszBuffer);
//No-op
if(cDimensions < 1)
return E_FAIL;
//Create SafeArray
SAFEARRAY* pSafeArray = NULL;
*ppSafeArray = NULL;
LONG* rgIndices = NULL;
SAFEARRAYBOUND* rgSafeArrayBounds = NULL;
//Indices array...
SAFE_ALLOC(rgIndices, LONG, cDimensions);
memset(rgIndices, 0, cDimensions*sizeof(LONG));
//SafeArrayBounds array...
SAFE_ALLOC(rgSafeArrayBounds, SAFEARRAYBOUND, cDimensions);
memset(rgSafeArrayBounds, 0, cDimensions*sizeof(SAFEARRAYBOUND));
//Need to find out how many elements are in Dim[0]
while(pwszNext && pwszNext < pwszCurEnd)
{
ulInnerElements++;
rgIndices[0]++;
pwszNext = wcsstr(pwszNext, L",");
if(pwszNext)
pwszNext++;
}
//Now from the [] notation find out how many elements in the other dimenstions
// [ [[1,2][3,4][5,6]] [[7,8][9,A][B,C]] ]
//The algorythm we will use is:
//Everytime we see a "]" we need to increment the next Dimension elements
//Everytime we see a "[" we need to reset the previous Dimension elements
//TODO
//Currently this algorythm only handles 1 dimension.
//No reason it couldn't use the above method and work for more, just on
//a time constraint, and the only provider we have supports max 1 dim...
ASSERT(cDimensions == 1);
//Create the SafeArrayBounds
for(iDim=0; iDim<cDimensions; iDim++)
{
rgSafeArrayBounds[iDim].lLbound = 0;
rgSafeArrayBounds[iDim].cElements = rgIndices[0];
}
//Now actually create the SafeArray
pSafeArray = SafeArrayCreate(wType, cDimensions, rgSafeArrayBounds);
ASSERT(pSafeArray);
pwszCurEnd = wcsstr(pwsz, L"]");
rgIndices[0] = 0;
pwszNext = pwsz;
for(i=0; i<ulInnerElements; i++)
{
//Obtain the start and end of the value
pwszEnd = wcsstr(pwszNext, L",");
if(pwszEnd==NULL || pwszEnd>pwszCurEnd)
pwszEnd = pwszCurEnd;
//Setup rgIndicaes
rgIndices[0] = i;
//Convert Value to a Variant
wcsncpy(wszBuffer, pwszNext, pwszEnd-pwszNext);
wszBuffer[pwszEnd-pwszNext] = wEOL;
XTESTC(NULL, hr = StringToVariant(wszBuffer, wType, &Variant, CONV_NONE));
//Add this Value to the SafeArray
TESTC(hr = SafeArrayPutElement(pSafeArray, rgIndices, &V_I4(&Variant)));
XTEST(NULL, VariantClear(&Variant));
//Incement to next value...
pwszNext = wcsstr(pwszNext, L",");
if(pwszNext)
pwszNext += 1;
}
//Everything complete successfully...
*ppSafeArray = pSafeArray;
CLEANUP:
XTEST(NULL, VariantClear(&Variant));
SAFE_FREE(rgIndices);
SAFE_FREE(rgSafeArrayBounds);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CHAR* strDuplicate
//
/////////////////////////////////////////////////////////////////////////////
CHAR* strDuplicate(CHAR* psz)
{
//no-op case
if(!psz)
return NULL;
ULONG cLen = strlen(psz);
//Allocate space for the string
CHAR* pszBuffer = NULL;
SAFE_ALLOC(pszBuffer, CHAR, cLen+1);
//Now copy the string
strcpy(pszBuffer, psz);
CLEANUP:
return pszBuffer;
}
/////////////////////////////////////////////////////////////////////////////
// WCHAR* wcsDuplicate
//
/////////////////////////////////////////////////////////////////////////////
WCHAR* wcsDuplicate(WCHAR* pwsz)
{
//no-op case
if(!pwsz)
return NULL;
ULONG cLen = wcslen(pwsz);
//Allocate space for the string
WCHAR* pwszBuffer = NULL;
SAFE_ALLOC(pwszBuffer, WCHAR, cLen+1);
//Now copy the string
wcscpy(pwszBuffer, pwsz);
CLEANUP:
return pwszBuffer;
}
/////////////////////////////////////////////////////////////////////////////
// HRESULT DBIDToString
//
/////////////////////////////////////////////////////////////////////////////
HRESULT DBIDToString(DBID* pDBID, WCHAR* pwsz, ULONG ulMaxLen)
{
ASSERT(pwsz);
WCHAR pwszBuffer[MAX_NAME_LEN];
//No-op
if(pDBID == NULL)
{
wcscpy(pwsz, L"NULL");
return S_OK;
}
//ColumnID (SubItem) DBID
switch(pDBID->eKind)
{
case DBKIND_NAME:
swprintf(pwsz, L"{\"%s\"}", pDBID->uName.pwszName);
break;
case DBKIND_PROPID:
swprintf(pwsz, L"{%d}", pDBID->uName.ulPropid);
break;
case DBKIND_GUID:
StringFromGUID2(pDBID->uGuid.guid, pwsz, ulMaxLen);
break;
case DBKIND_GUID_NAME:
StringFromGUID2(pDBID->uGuid.guid, pwszBuffer, ulMaxLen);
swprintf(pwsz, L"{%s,\"%s\"}", pwszBuffer, pDBID->uName.pwszName);
break;
case DBKIND_GUID_PROPID:
StringFromGUID2(pDBID->uGuid.guid, pwszBuffer, ulMaxLen);
swprintf(pwsz, L"{%s,%d}", pwszBuffer, pDBID->uName.ulPropid);
break;
case DBKIND_PGUID_NAME:
StringFromGUID2(*pDBID->uGuid.pguid, pwszBuffer, ulMaxLen);
swprintf(pwsz, L"{&%s,\"%s\"}", pwszBuffer, pDBID->uName.pwszName);
break;
case DBKIND_PGUID_PROPID:
StringFromGUID2(*pDBID->uGuid.pguid, pwszBuffer, ulMaxLen);
swprintf(pwsz, L"{&%s,%d}", pwszBuffer, pDBID->uName.ulPropid);
break;
default:
ASSERT(!"Unhandled Type!");
break;
};
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// BOOL IsVariableType
//
/////////////////////////////////////////////////////////////////////////////
BOOL IsVariableType(DBTYPE wType)
{
//According to OLEDB Spec Appendix A (Variable-Length Data Types)
switch(wType)
{
case DBTYPE_STR:
case DBTYPE_WSTR:
case DBTYPE_BYTES:
return TRUE;
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// BOOL IsFixedType
//
/////////////////////////////////////////////////////////////////////////////
BOOL IsFixedType(DBTYPE wType)
{
return !IsVariableType(wType);
}
/////////////////////////////////////////////////////////////////////////////
// BOOL IsNumericType
//
/////////////////////////////////////////////////////////////////////////////
BOOL IsNumericType(DBTYPE wType)
{
//According to OLEDB Spec Appendix A (Numeric Data Types)
switch(wType)
{
case DBTYPE_I1:
case DBTYPE_I2:
case DBTYPE_I4:
case DBTYPE_I8:
case DBTYPE_UI1:
case DBTYPE_UI2:
case DBTYPE_UI4:
case DBTYPE_UI8:
case DBTYPE_R4:
case DBTYPE_R8:
case DBTYPE_CY:
case DBTYPE_DECIMAL:
case DBTYPE_NUMERIC:
return TRUE;
}
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -