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

📄 safearray.cpp

📁 KepWare的OPC Client 示例.面向C
💻 CPP
字号:
// **************************************************************************
// safearray.cpp
//
// Description:
//	This class wraps this struct for local useage.  Do not use CSafeArray
//	if the data must be passed to another process via COM.
//
//	typedef struct  tagSAFEARRAY
//		{
//		USHORT cDims;
//		USHORT fFeatures;
//		ULONG cbElements;
//		ULONG cLocks;
//		PVOID pvData;
//		SAFEARRAYBOUND rgsabound[ 1 ];
//		}	SAFEARRAY;
//
// DISCLAIMER:
//	This programming example is provided "AS IS".  As such Kepware, Inc.
//	makes no claims to the worthiness of the code and does not warranty
//	the code to be error free.  It is provided freely and can be used in
//	your own projects.  If you do find this code useful, place a little
//	marketing plug for Kepware in your code.  While we would love to help
//	every one who is trying to write a great OPC client application, the 
//	uniqueness of every project and the limited number of hours in a day 
//	simply prevents us from doing so.  If you really find yourself in a
//	bind, please contact Kepware's technical support.  We will not be able
//	to assist you with server related problems unless you are using KepServer
//	or KepServerEx.
// **************************************************************************


#include "stdafx.h"
#include "safearray.h"


// **************************************************************************
// operator new
//
// Description:
//	Custom new operator that allocates enough memory to manage a single or
//	two dimension array.  No actual array memory is allocated here.
//
// Parameters:
//  none
//
// Returns:
//  void * - Pointer to new CSafeArray object.
// **************************************************************************
void *CSafeArray::operator new (size_t s)
	{
	// SAFEARRAY has enough memory on its own to manage a single dimension
	// array.  If we add one more SAFEARRAYBOUND, then it can manage a second
	// dimension.  For our purposes this is all we will ever need.
	void *p = malloc (sizeof (SAFEARRAY) + sizeof (SAFEARRAYBOUND));

	// Handle allocation error:
	if (!p)
		{
#ifdef _WIN32_WCE
		return (NULL);
#else
		throw (-1);
#endif//_WIN32_WCE
		}
	
	// Initialize allocated memory zero:
	memset (p, 0, sizeof (SAFEARRAY) + sizeof (SAFEARRAYBOUND));

	// Return pointer to allocated memory:
	return (p);
	}

// **************************************************************************
// operator delete
//
// Description:
//	Custom delete operator.
//
// Parameters:
//  none
//
// Returns:
//  void
// **************************************************************************
void CSafeArray::operator delete (void *p)
	{
	// Free allocated memory:
	if (p)
		free (p);
	}

// **************************************************************************
// CSafeArray ()
//
// Description:
//	Copy constructor.
//
// Parameters:
//  const CSafeArray	&cSrc	CSafeArray object to copy properties from.
//
// Returns:
//  none
// **************************************************************************
CSafeArray::CSafeArray (const CSafeArray &cSrc)
	{
	// Copy properties:
	cDims = cSrc.cDims;
	fFeatures = cSrc.fFeatures;
	cbElements = cSrc.cbElements;
	cLocks = cSrc.cLocks;
	
	rgsabound [0] = cSrc.rgsabound [0];
	rgsabound [1] = cSrc.rgsabound [1];
	
	// Allocate memory:
	DWORD cdwBytes = cSrc.GetByteLength ();
	Alloc (cdwBytes);

	// Copy data into our memory block:
	memcpy (pvData, cSrc.pvData, cdwBytes);
	}

// **************************************************************************
// CSafeArray ()
//
// Description:
//	Constructor for 2-D array.
//
// Parameters:
//  WORD		wRows				Number of rows to allocate.
//	WORD		wCols				Number of columns to allocate.
//	WORD		wBytesPerElement	Number of bytes per array element.
//	void		*pData				Pointer to data to initialize array with.
//									  If NULL, array is not initialized.
//
// Returns:
//  none
// **************************************************************************
CSafeArray::CSafeArray (WORD wRows, WORD wCols, WORD wBytesPerElement, void *pData /*=NULL*/)
	{
	// Initialize member variables:

	// If number of row is 1, then 1-D array, else 2-D:
	cDims = (wRows > 1) ? 2 : 1;
	fFeatures = FADF_FIXEDSIZE;
	cbElements = wBytesPerElement;
	cLocks = 0;
	
	// If a 2-D array:
	if (cDims == 2)
		{
		// We shouldn't have single element arrays
		ASSERT ((DWORD)wRows * (DWORD)wCols > 1);

		// Set bounds for rows:
		rgsabound [0].lLbound = 0;
		rgsabound [0].cElements = wRows;
		
		// Set bounds for columns:
		rgsabound [1].lLbound = 0;
		rgsabound [1].cElements = wCols;
		}

	// Else a 1-D array:
	else
		{
		// Set bounds for columns (no rows):
		rgsabound[0].lLbound = 0;
		rgsabound[0].cElements = wCols;
		}

	// Allocate memory for data:
	DWORD dwSize = (DWORD)wRows * (DWORD)wCols * (DWORD)wBytesPerElement;
	Alloc (dwSize);

	// Load data into our memory block if data is provided:
	if (pData)
		memcpy (pvData, pData, dwSize);
	}

// **************************************************************************
// CSafeArray
//
// Description:
//	Constructor for 1-D array.
//
// Parameters:
//	DWORD		cdwElements			Number of elements to allocate.
//	WORD		wBytesPerElement	Number of bytes per array element.
//	void		*pData				Pointer to data to initialize array with.
//									  If NULL, array is not initialized.
//
// Returns:
//  none
// **************************************************************************
CSafeArray::CSafeArray (DWORD cdwElements, WORD wBytesPerElement, void *pData /*=NULL*/)
	{
	// We shouldn't have single element arrays:
	ASSERT (cdwElements > 1);

	// Initialize member variables:
	cDims = 1;
	fFeatures = FADF_FIXEDSIZE;
	cbElements = wBytesPerElement;
	cLocks = 0;
	
	// Set bounds:
	rgsabound[0].lLbound = 0;
	rgsabound[0].cElements = cdwElements;
	
	// Allocate memory for data:
	Alloc (cdwElements * wBytesPerElement);

	// Load data into our memory block if data is provided:
	if (pData)
		memcpy (pvData, pData, cdwElements * wBytesPerElement);
	}

// **************************************************************************
// ~CSafeArray ()
//
// Description:
//	Destructor.
//
// Parameters:
//  none
//
// Returns:
//  none
// **************************************************************************
CSafeArray::~CSafeArray ()
	{
	// Free memory we allocated for data:
	if (pvData)
		free (pvData);
	}

// **************************************************************************
// operator =
//
// Description:
//	Custom assignment operator.
//
// Parameters:
//  const SAFEARRAY		&cSrc		Object to assign properties from.
//
// Returns:
//  void
// **************************************************************************
void CSafeArray::operator = (const SAFEARRAY &cSrc)
	{
	ASSERT (cSrc.cDims <= 2);

	// Get size of array to copy:
	DWORD dwNewSize = ((CSafeArray &)cSrc).GetByteLength ();

	// Save our current size:
	DWORD dwOldSize = GetByteLength ();

	// If size is different, dimensioning may be different as well:
	if (dwNewSize != dwOldSize)
		{
		// If new size is larger than our current size, we will
		// need to allocate a larger block of memory for data:f
		if (dwNewSize > dwOldSize)
			{
			// Free old memory:
			if (pvData)
				{
				free (pvData);
				pvData = NULL;
				}

			// Allocate new memory:
			Alloc (dwNewSize);
			}

		// Assign basic properties:
		cDims = cSrc.cDims;
		fFeatures = FADF_FIXEDSIZE;
		cbElements = cSrc.cbElements;
		cLocks = 0;

		// Set bound "0" for 1-D and 2-D arrays:
		rgsabound [0] = cSrc.rgsabound [0];

		// Set bound "1" for 2-D arrays only:
		if (cSrc.cDims == 2)
			rgsabound [1] = cSrc.rgsabound [1];
		}

	// Copy the array data:
	memcpy (pvData, cSrc.pvData, dwNewSize);
	}

// **************************************************************************
// Alloc ()
//
// Description:
//	Called to allocate memory for array.
//
// Parameters:
//  DWORD		cdwBytes	Number of bytes to allocate.
//
// Returns:
//  void
// **************************************************************************
void CSafeArray::Alloc (DWORD cdwBytes)
	{
	ASSERT (!pvData);
	ASSERT (cdwBytes);

	// Allocate specified number of bytes.  If succeed, indicated by an
	// non=NULL pointer return, then initialize the memory to zero:
	if (pvData = malloc (cdwBytes))
		{
		memset (pvData, 0, cdwBytes);
		return;
		}

	// If we get here, there was an allocation error.
#ifdef _WIN32_WCE
	AfxThrowUserException ();
#else
	throw (-1);
#endif //_WIN32_WCE
	}

// **************************************************************************
// GetByteLength ()
//
// Description:
//	Called to get size of array.
//
// Parameters:
//  none
//
// Returns:
//  DWORD - size of array in bytes.
// **************************************************************************
DWORD CSafeArray::GetByteLength () const
	{
	// Return the array length in bytes (number of elements times the
	// number of bytes per element):
	return (GetNumElements () * (DWORD)cbElements);
	}

// **************************************************************************
// GetNumElements ()
//
// Description:
//	Called to get the number of elements in array.
//
// Parameters:
//  none
//
// Returns:
//  DWORD - number of elements.
// **************************************************************************
DWORD CSafeArray::GetNumElements () const
	{
	// We assume 1-D or 2-D.  Check for debugging:
	ASSERT (cDims > 0 && cDims < 3);

	// Calculate the number of elements (product of dimension bounds)
	DWORD dwSize = 1;
	for (unsigned short i = 0; i < cDims; i++)
		dwSize *= rgsabound [i].cElements;

	// Return result:
	return (dwSize);
	}

// **************************************************************************
// GetNumRows ()
//
// Description:
//	Called to get number of rows in array.
//
// Parameters:
//  none
//
// Returns:
//  DWORD - number of rows.
// **************************************************************************
DWORD CSafeArray::GetNumRows () const
	{
	// We assume 1-D or 2-D.  Check for debugging:
	ASSERT (cDims > 0 && cDims < 3);
	
	// If 1-D, data is stored as columns (1 row implied):
	if (cDims == 1)
		return (1);

	// else if 2-D , dimension 0 is rows:
	return (rgsabound [0].cElements);
	}

// **************************************************************************
// GetNumCols ()
//
// Description:
//	Called to get number of columns in array.
//
// Parameters:
//  none
//
// Returns:
//  DWORD - number of columns.
// **************************************************************************
DWORD CSafeArray::GetNumCols () const
	{
	// We assume 1-D or 2-D.  Check for debugging:
	ASSERT (cDims > 0 && cDims < 3);
	
	// If 1-D, dimension 0 is columns:
	if (cDims == 1)
		return (rgsabound [0].cElements);

	// else if 2-D, dimension 1 is columns:
	return (rgsabound [1].cElements);
	}

// **************************************************************************
// Format ()
//
// Description:
//	Formats the array to a tab delimited string, in row major order where 
//	each row (except the last) is terminated with a CR-LF.
//
// Parameters:
//  CString		&str	Output string with tab delimited data.
//	VARTYPE		vt		Variant used to specify data type.
//
// Returns:
//  void
// **************************************************************************
void CSafeArray::Format (CString &str, VARTYPE vt) const
	{
	// Get array size in bytes:
	DWORD dwSize = GetByteLength ();

	// Get number of columns (dimension 0 if 1-D, dimension 1 if 2-D):
	DWORD dwCols = cDims == 1 ? rgsabound [0].cElements : rgsabound [1].cElements;

	// Clear output string:
	str.Empty ();

	// Get pointer to first byte if data:
	LPBYTE lpByte = (LPBYTE)pvData;
	DWORD dwCol = 0;

	// Clear array bit from the data type:
	vt &= ~VT_ARRAY;


	// Loop over bytes (increment loop index by bytes per element and 
	// increment data pointer by same):
	for (DWORD i = 0; i < dwSize; i += cbElements, lpByte += cbElements)
		{
		// Create a scratch buffer to contain formatted element value:
		TCHAR szNum [32];

		// Single byte elements (byte, char):
		if (cbElements == 1)
			{
			if (vt == VT_UI1)
				_stprintf (szNum, _T("%u"), *lpByte);
			else
				_stprintf (szNum, _T("%d"), *(char *)lpByte);
			}
		
		// Two-byte elements (short, word):
		else if (cbElements == 2)
			{
			if (vt == VT_I2)
				_stprintf (szNum, _T("%d"), *(short *)lpByte);
			else
				_stprintf (szNum, _T("%u"), *(WORD *)lpByte);
			}
		
		// Four-byte elements (long, float, dword):
		else if (cbElements == 4)
			{
			if (vt == VT_I4)
				_stprintf (szNum, _T("%d"), *(long *)lpByte);
			else if (vt == VT_R4)
				_stprintf (szNum, _T("%G"), *(float *)lpByte);
			else
				_stprintf (szNum, _T("%u"), *(DWORD *)lpByte);
			}

		// Eight-byte elements (double):
		else if (cbElements == 8)
			_stprintf (szNum, _T("%G"), *(double *)lpByte);

		// Bad format - return:
		else
			{
#ifdef _DEBUG
			str = _T("Unknown array format");
#endif
			return;
			}

		// Delimit each element within the row
		if (dwCol != 0)
			str += _T('\t');

		// Append the formatted element data
		str += szNum;

		// Terminate each row 
		if (++dwCol == dwCols)
			{
			str += _T("\r\n");
			dwCol = 0;
			}
		}
	}

// **************************************************************************
// operator ==
//
// Description:
//	Custom comparison operator.
//
// Parameters:
//  none
//
// Returns:
//  void
// **************************************************************************
bool CSafeArray::operator == (const SAFEARRAY &cSrc) const
	{
	// If neither object is initialized, objects are the same so return true.
	if (!cSrc.pvData && !pvData)
		return (true);

	// If one object is initialized, but not the other, the objects
	// different so return false.
	if ((!cSrc.pvData && pvData) || (cSrc.pvData && !pvData))
		return (false);

	// If we make it here, we know both objects are initialized.  We need
	// to look more closely to see if they are the same.
	
	// Get size of both arrays:
	DWORD dwSrcLen = ((CSafeArray &)cSrc).GetByteLength ();
	DWORD dwLen = GetByteLength ();

	// If lengths are different, the objects are different so return false.
	if (dwSrcLen != dwLen)
		return (false);

	// Compare the memory as a vector (ignore dimensions, size of 
	// element etc.).  Return result.
	return (memcmp (cSrc.pvData, pvData, GetByteLength ()) == 0);
	}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -