CVariantArray






2.57/5 (4投票s)
2002年5月13日
7分钟阅读

80518

1709
二维VARIANT数组
引言
CVariantArray
是一个包装类,用于管理一个和两个维度的 VARIANT
结构数组。它最常用于客户端/服务器分布式处理项目(例如数据库服务器),以及在 Visual Basic 和 Visual C++ 之间传递数据。我花了大量时间在互联网上搜索、阅读技术文档以及通过反复试验,才创建了这个数组。
概述
该类支持所有基本的 C 数据类型,以及 DATE
。struct tm
、SYSTEMTIME
和字符串,包括 char*
、wchar_t*
、string 模板
、CString
和 UString
。内部所有字符串都存储为 UNICODE BSTR
,无论该类是为 UNICODE 编译还是非 UNICODE 编译。该类不支持任何 VARIANT
指针类型(例如 IDispatch
、IUnknown
等),也不支持嵌套数组(SAFEARRAY
)。唯一的例外是 BSTR
。它为每种支持的数据类型都提供了 Put()
和 Get()
方法,并支持 CString
(供在 MFC 项目中使用该数组的开发者)或 string
(供 STL 用户)的兼容性。
类中还包括了流、FILE
和 HANDLE
的输入/输出运算符。这允许您只用一行代码即可将整个数组保存到文件或流中。例如:
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 版本不支持流、FILE
和 struct tm
。
实现细节
在 VariantArray.h 的顶部附近,有两个定义可以打开或关闭CString
和 UString
的支持。请取消注释适合您项目的行。如果没有任何行被取消注释,则会包含 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 - 所需单元格的零基列号。向量(一维)数组不需要指定列。
注释
- 这些函数中的每一个都会修改第三个参数以包含单元格的值,前提是单元格的数据类型相同。如果单元格的数据类型不同,则会发生错误。
- 对于第三个参数为
char **string
的版本,该方法将分配足够的内存来容纳以 null 结尾的字符串。调用函数必须使用delete
运算符来释放内存。 - 对于第三个参数为
long stringlen
的版本,如果 stringlen 不足以容纳字符串,则函数将返回所需长度(加上 null 终止符)。在这种情况下,调用函数应重新分配其缓冲区并使用新值再次调用该函数。 - 由于
DATE
和double
的数据类型相同,请使用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.h 和 VariantArray.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 编译器。