⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 common.cpp

📁 用测试OLE DB提供者的一个程序。能够测试出OEL DB提供者到底实现了哪些接口?很灵的。
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	//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 + -