65.9K
CodeProject 正在变化。 阅读更多。
Home

CVariantArray

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.57/5 (4投票s)

2002年5月13日

7分钟阅读

viewsIcon

80518

downloadIcon

1709

二维VARIANT数组

引言

CVariantArray 是一个包装类,用于管理一个和两个维度的 VARIANT 结构数组。它最常用于客户端/服务器分布式处理项目(例如数据库服务器),以及在 Visual Basic 和 Visual C++ 之间传递数据。我花了大量时间在互联网上搜索、阅读技术文档以及通过反复试验,才创建了这个数组。

概述

该类支持所有基本的 C 数据类型,以及 DATEstruct tmSYSTEMTIME 和字符串,包括 char*wchar_t*string 模板CStringUString。内部所有字符串都存储为 UNICODE BSTR,无论该类是为 UNICODE 编译还是非 UNICODE 编译。该类不支持任何 VARIANT 指针类型(例如 IDispatchIUnknown 等),也不支持嵌套数组(SAFEARRAY)。唯一的例外是 BSTR。它为每种支持的数据类型都提供了 Put()Get() 方法,并支持 CString(供在 MFC 项目中使用该数组的开发者)或 string(供 STL 用户)的兼容性。

类中还包括了流、FILEHANDLE 的输入/输出运算符。这允许您只用一行代码即可将整个数组保存到文件或流中。例如:

    CVariantArray array;
    // populate the array here.

    fstream os;
    os.open("somefile.dat",ios::out | ios::trunc);
    if(os.is_open())
    {
        os << array;
        os.close();
    }

WinCE 版本不支持流、FILEstruct tm

实现细节

VariantArray.h 的顶部附近,有两个定义可以打开或关闭 CStringUString 的支持。请取消注释适合您项目的行。如果没有任何行被取消注释,则会包含 string 模板类,除非 _WIN32_WCE(用于 WinCE 项目)也被定义。
//////////////////////////////////////////////////////////////////

//

// uncomment the next line if your are using MFC

//#define _MFC_

//

// uncomment the next line if you are using the DataReel library

//#define _DATAREEL_

//

//

//////////////////////////////////////////////////////////////////

方法和运算符

CVariantArray();
virtual ~CVariantArray();
注释
类构造函数/析构函数
int Create(long rows, long cols);
参数
rows - 数组中零基的行数
cols - 数组中零基的列数。如果 cols = 0,则创建一个一维数组(向量)。

返回值
成功时返回 0,否则返回非零值。

注释
可以通过两种方式创建数组。Create 方法会创建带有空行和空列的数组,而 Attach 方法会用一个预先定义的数组创建数组。

int Attach(VARIANT* vt);
参数
VARIANT* vt - 指向 VARIANT 的指针,该 VARIANT 是一个 SAFEARRAY

注释
VARIANT 类型必须是 (VT_VARIANT | VT_ARRAY)。CVariantArray> 将用 VARIANT 中的数组替换 CVariantArray 类中的所有数据。
bool IsValidArray();
参数


返回值
如果数组有效,则返回 true,否则返回 false

注释
验证 CVariantArray 是否已构造为数组。如果它是数组,则返回 true,如果不是数组,则返回 false
VARIANT* Detach();
参数


返回值
CVariantArray 类所表示的 VARIANT

注释
调用 Detach 方法后,CVariantArray 类将不再有效。
调用函数必须调用 VariantClear() 来释放分离的数组。如果忽略此操作,将会发生内存泄漏。
void Destroy()
参数


返回值


注释
删除数组中的所有数据。正确销毁所有字符串。
long GetRows();
参数


返回值
返回数组中的行数。
long GetCols();
参数


返回值
返回数组中的列数。
int Redim(long rows);
参数
rows - 数组中的新行数

返回值
如果数组成功调整大小,则返回 0,否则返回非零值。

注释
列数不能更改。如果 rows 小于当前行数,则多余的行中的数据将被正确销毁。如果 rows 大于当前行数,则新行中所有列的数据类型都将设置为 VT_NULL,表示该单元格不包含任何有效数据。
int GetAtString(UString& string, long row, long col = 0)
int GetAtString(CString& string, long row, long col = 0);
int GetAtString(string& string, long row, long col = 0);
参数
row - 所需单元格的零基行号
col - 所需单元格的零基列号。向量(一维)数组不需要指定列。
string - 一个 STL 字符串模板对象
UString - DataReel 库中定义的字符串类。 _DATAREEL_ 必须在 CVariantArray.h 中定义。CString - MFC 字符串类。_MFC_ 必须在 CVariantArray.h 中定义。

注释
这些函数中的每一个都会将单元格的数据类型转换为字符串。数字数据类型使用“%d”转换,浮点数或双精度数使用“%f”转换。DATE 类型转换为“mm/dd/yyyy hh:mm:ss”格式。
int GetAt(VARIANT& vt, long row, long col = 0);
int GetAt(char** string, long row, long col= 0);
int GetAt(char* string, long stringlen, long row, long col = 0);
int GetAt(UString& string, long row, long col = 0 );
int GetAt(CString& string, long row, long col = 0);
int GetAt(char& val, long row, long col = 0);
int GetAt(short& val, long row, long col = 0);
int GetAt(unsigned short& val, long row, long col = 0);
int GetAt(int& val, long row, long col = 0);
int GetAt(unsigned int& val, long row, long col = 0);
int GetAt(long& val, long row, long col = 0);
int GetAt(unsigned long& val, long row, long col = 0);
int GetAt(float& val, long row, long col = 0);
int GetAt(double& val, long row, long col = 0);
int GetAt(struct tm& tm, long row, long col = 0);
int GetAtDate(DATE& val, long row, long col = 0); 

参数
row - 所需单元格的零基行号
col - 所需单元格的零基列号。向量(一维)数组不需要指定列。

注释

  1. 这些函数中的每一个都会修改第三个参数以包含单元格的值,前提是单元格的数据类型相同。如果单元格的数据类型不同,则会发生错误。
  2. 对于第三个参数为 char **string 的版本,该方法将分配足够的内存来容纳以 null 结尾的字符串。调用函数必须使用 delete 运算符来释放内存。
  3. 对于第三个参数为 long stringlen 的版本,如果 stringlen 不足以容纳字符串,则函数将返回所需长度(加上 null 终止符)。在这种情况下,调用函数应重新分配其缓冲区并使用新值再次调用该函数。
  4. 由于 DATEdouble 的数据类型相同,请使用 GetAtDATE 来获取 DATE 数据类型。
int SetAt(VARIANT& vt, long row, long col = 0);
int SetAt(const char* string, long row, long col = 0);
int SetAt(const wchar_t* string, long row, long col = 0);
int SetAt(const UString& string, long row, long col = 0);
int SetAt(const CString& string, long row, long col = 0);
int SetAt(const string& string, long row, long col = 0);
int SetAt(const char val, long row, long col = 0);
int SetAt(const unsigned char val, long row, long col = 0);
int SetAt(const short val, long row, long col = 0);
int SetAt(const unsigned short val, long row, long col = 0);
int SetAt(const int val, long row, long col = 0);
int SetAt(const unsigned int val, long row, long col = 0);
int SetAt(const long val, long row, long col = 0);
int SetAt(const unsigned long val, long row, long col = 0);
int SetAt(const double val, long row, long col = 0);
int SetAt(const struct tm& tm, long row, long col = 0);
int SetAt(const SYSTEMTIME& tm, long row, long col = 0);
int SetAtZuluDateTime(long row, long col = 0);
int SetAtLocalDateTime(long row, long col = 0);    
int SetAtDate(const DATE val, long row, long col = 0);
参数
row - 所需单元格的零基行号
col - 所需单元格的零基列号。向量(一维)数组不需要指定列。

注释
这些函数中的每一个都会正确销毁单元格的当前内容,然后以指定的数据类型进行修改。
int Sort(long lKeyCol, bool bAscending = true);
参数
lKeyCol - 用于执行排序的列号。bAscending - true 按升序排序行,false 按降序排序。

注释
此函数通过指定的列按升序或降序对所有行进行排序,使用了 Dr. Robert Sedgewick 的快速排序算法 http://www.yendor.com/programming/sort/
long Find(long lKeyCol, CVariantObj& key)
参数
lKeyCol - 包含所需值的列号
key - 一个 VARIANT,其中包含要搜索的值。

返回值
找到 key 的零基行号,如果未找到 key,则为 -1。
注释
对数组执行线性搜索以查找 key 值。
const VARIANT* GetArray()
参数


返回值
返回 CVariantArray 类中表示的 VARIANT。该 VARIANT **未**被复制,因此调用函数可能进行的任何更改都将反映在 CVariantArray 类中。调用函数 **不得**使用返回的值调用 InitVariant

示例

CVariantArray 非常易于使用,正如客户端/服务器演示项目所示。您只需要在项目中包含 VariantArray.hVariantArray.cpp,例如:

#include "VariantArray.h"

在服务器端,将数组附加到 CVariantArray 类:

int foo(VARIANT* vt)
{
    CVariantArray array;
    array.Attach(vt)
}

然后,将数据项插入数组:

    array.SetAt("something", row,col);
    long lItem = 123;
    array.SetAt(lItem, row,col);

类中提供了一个 Detach() 方法,但在服务器自动化方法返回之前,不一定需要使用它。CVariantArray 的析构函数会为您处理。

客户端与服务器端类似:

int foo(VARIANT* vt)
{
    CVariantArray array;
    VARIANT vt;
    // call server to get the data 

    array.Attach(&vt)
}

演示中的服务器项目只有一个暴露给自动化对象的函数 - ExecuteSQL()。它模拟从数据库检索数据,创建数组,用从数据库接收到的数据填充数组,并将数据返回给客户端。在演示中,没有实际的数据库调用。为了保持简单,数据在程序中是硬编码的。

STDMETHODIMP CDatabaseObj::GetArray(long nDims, VARIANT *array)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState())
	if( nDims < 1 || nDims > 2)
		return S_FALSE;

	// create a 2-dimensional array with six columns and three rows

	long nRows = 3;
	long nCols = nDims == 1 ? 1 : 6;
	CVariantArray ay;
	ay.Attach(array);
	// Create the array

	ay.Create(nRows,nCols);
	// populate the array with the column headers.

	// Column headerings are not required by

	// the CVariantArray class.  It knows nothing about

	// them.

	for(long i= 0; i < nCols; i++)
		ay.SetAt(names[i], 0,i);
	// populate rows 1 and 2 with actional data.  In this example

	// we are using only char* data, but it can be any elementry

	// data type.

	for(long col = 0; col < nCols; col++)
	{
		ay.SetAt(row1[col],1,col);
	}

	for(col = 0; col < nCols; col++)
	{
		ay.SetAt(row2[col], 2,col);
	}

	return S_OK;
}

客户端演示是一个支持自动化的 MFC 对话框项目。当按下“GetData”按钮时,它会调用 CoCreateIntance() 来创建客户端/服务器链接,调用 ExecuteSQL() 方法,然后在一个网格中显示返回的数据。

以下是从服务器获取数据的代码:

void CClientMFCDlg::OnButon2DArray() 
//

// Create the com object, get the data from

// the server, release the com obmect, and 

// finally display the data.

{
	HRESULT hr = 0;
	IDatabaseObj* pObj;
	hr = CoCreateInstance(CLSID_DatabaseObj, 
				NULL, 
				CLSCTX_INPROC_SERVER,
				IID_IDatabaseObj, 
				(void**) &pObj);
	if(hr == S_OK)
	{
		VARIANT vt;
		VariantInit(&vt);
		hr = pObj->GetArray(2,&vt);
		pObj->Release();
		DisplayResults(vt);

	}
	
}


void CClientMFCDlg::OnButton1DArray() 
{
	HRESULT hr = 0;
	IDatabaseObj* pObj;
	hr = CoCreateInstance(CLSID_DatabaseObj, 
				NULL, 
				CLSCTX_INPROC_SERVER,
				IID_IDatabaseObj, 
				(void**) &pObj);
	if(hr == S_OK)
	{
		VARIANT vt;
		VariantInit(&vt);
		hr = pObj->GetArray(1,&vt);
		pObj->Release();
		DisplayResults(vt);

	}
	
}

此函数从数组中检索数据并将其显示在网格中。

void CClientMFCDlg::DisplayResults(VARIANT& vt)
// Create the CVariantArray object and attached the

// VARIANT array that was received from the server.

// Then populate the grid control with the data.

{
	CVariantArray ay;
	// attach the VARIANT to the class

	ay.Attach(&vt);
	// get number of rows and columns in

	// the array

	long nRows = ay.GetRows();
	long nCols = ay.GetCols();
	// set up the grid with the number of

	// rows and columns in the array.

	m_Grid.SetCols(nCols);
	m_Grid.SetRows(nRows+1);
	m_Grid.SetFixedRows(1);
	m_Grid.SetFixedCols(0);
#if defined(_MFC_)
	CString data;
#elif defined(_DATAREEL_)
	UString data;
#else
	string data;
#endif
	m_Grid.SetRow(0);
	// reset the width of each column in the grid

	for(long i = 0; i < nCols; i++)
	{
		long width = m_Grid.GetColWidth(i);
		width += 80;
		m_Grid.SetColWidth(i,width);
	}
	// Get the data from each column row using a CString 

	// data type.

	for(long row = 0; row < nRows; row++)
	{
		for(long col = 0; col < nCols; col++)
		{
			// get a string 

			ay.GetAt(data,row,col);
			// put it in the grid

#if defined(_MFC_)
			m_Grid.SetTextMatrix(row,col,data);
#else
			m_Grid.SetTextMatrix(row,col,data.c_str());
#endif
		}
	}

}

历史

版本 1.1 增加了对非 MFC 程序的 string 模板类的支持。

版本 2.0
  • 主要升级是为了支持一维向量。参数进行了重新排列,使得对于一维数组,列号可以省略。
  • 演示项目包括 Win32 和 WinCE 演示。Win32 演示需要 MSVC++ 6.0,WinCE 演示需要 eVC++ 3.0 编译器。
© . All rights reserved.