快捷搜索:

COM组件开发实践(四)---From C++ to COM :Part 1

一,C++客户重用C++工具

假设已经有一个可以重用的类,我们就可以在自己的法度榜样中去重用它,只必要将其定义和实现文件加入到我们自己的工程中,并且在应用它的文件中包孕此类的定义文件就可以了,这也是我们最常用的C++标准重用措施。就拿我自己来说,在CodeProject上碰到对照好的控件代码,都是这样直接用到自己的项目中来的。

下面就给出我这个系列的第一个代码示例,在接下来的几篇文章中,将基于此代码赓续进行改进,一步步从C++走向COM.

简单先容下我们要重用的C++工具,它是一个简单的类似数据库的工具,用来治理内存中的数据,它包孕一个指向“数据库”中所有表的指针数组,体实际是一个字符串数组,每个数组元素表示表格的一行。别的这个类还包孕有一个数据表表名的数组。

DBSRV.h文件:

typedeflongHRESULT;//模拟COM中的HRESULT

//内存数据库类

classCDB

{

//Interfaces

public:

//Interfacefordataaccess

HRESULTRead(shortnTable,shortnRow,LPTSTRlpszData);//读数据,nTable指定命据表,nRow指定命据行

HRESULTWrite(shortnTable,shortnRow,LPCTSTRlpszData);//写数据,nTable指定命据表,nRow指定命据行

//Interfacefordatabasemanagement

HRESULTCreate(short&nTable,LPCTSTRlpszName);//创建数据表,表名为lpszName

HRESULTDelete(shortnTable);//删除数据表

//Interfacefordatabaseinformation

HRESULTGetNumTables(short&nNumTables);//获取数据表个数

HRESULTGetTableName(shortnTable,LPTSTRlpszName);//获取指定命据表表名,nTable为数据表索引号

HRESULTGetNumRows(shortnTable,short&nRows);//获取指定命据表的数据行数,nTable为数据表索引号,nRows保存返回的行数

//Implementation

private:

CPtrArray   m_arrTables;   //指向“数据库”中所有表的指针数组

CStringArraym_arrNames;//数据表名称数组

public:

~CDB();

};

DBSRV.cpp文件:

#include"stdafx.h"

#include"..InterfaceDBsrv.h"

//Databaseobject

HRESULTCDB::Read(shortnTable,shortnRow,LPTSTRlpszData)

{

CStringArray*pTable;

pTable=(CStringArray*)m_arrTables[nTable];

lstrcpy(lpszData,(*pTable)[nRow]);

returnNO_ERROR;

}

HRESULTCDB::Write(shortnTable,shortnRow,LPCTSTRlpszData)

{

CStringArray*pTable;

pTable=(CStringArray*)m_arrTables[nTable];

pTable->SetAtGrow(nRow,lpszData);

returnNO_ERROR;

}

HRESULTCDB::Create(short&nTable,LPCTSTRlpszName)

{

CStringArray*pTable=newCStringArray;

nTable=m_arrTables.Add(pTable);

m_arrNames.SetAtGrow(nTable,lpszName);

returnNO_ERROR;

}

HRESULTCDB::Delete(shortnTable)

{

CStringArray*pTable;

pTable=(CStringArray*)m_arrTables[nTable];

deletepTable;

m_arrTables[nTable]=NULL;

m_arrNames[nTable]="";

if(nTable==m_arrTables.GetSize()-1)

{

m_arrTables.RemoveAt(nTable);

m_arrNames.RemoveAt(nTable);

}

returnNO_ERROR;

}

HRESULTCDB::GetNumTables(short&nNumTables)

{

nNumTables=m_arrTables.GetSize();

returnNOERROR;

}

HRESULTCDB::GetTableName(shortnTable,LPTSTRlpszName)

{

lstrcpy(lpszName,m_arrNames[nTable]);

returnNO_ERROR;

}

HRESULTCDB::GetNumRows(shortnTable,short&nRows)

{

CStringArray*pTable;

pTable=(CStringArray*)m_arrTables[nTable];

returnpTable->GetSize();

}

CDB::~CDB()

{

shortnNumTables;

for(GetNumTables(nNumTables);nNumTables>0;GetNumTables(nNumTables))

{

Delete(nNumTables-1);

}

}

pDC->TextOut(10,10,pDoc->m_csData);

第一节中的标准重用措施有一个大年夜搭档:类的实今世码被泄露了,而这想必不是我们想要的结果。要办理这个问题,我们可以应用DLL将类的代码打包成一个DLL,并供给一个用于阐明函数和布局的头文件,这样实今世码就封装起来了。基于上一节的代码,我们改动如下:

一)先改动接口文件:1)为每个成员函数添加_declspec(dllexport)声明;2)为CDB类添加成员函数Release(),用于在工具不再被应用时删除自己;3)声明类工厂CDBSrvFactory;4)声明返回类工厂工具的引出函数DllGetClassFactoryObject,用于创建对应的类工厂

typedeflongHRESULT;

#defineDEF_EXPORT_declspec(dllexport)

classCDB

{

//Interfaces

public:

//Interfacefordataaccess

HRESULTDEF_EXPORTRead(shortnTable,shortnRow,LPWSTRlpszData);

HRESULTDEF_EXPORTWrite(shortnTable,shortnRow,LPCWSTRlpszData);

//Interfacefordatabasemanagement

HRESULTDEF_EXPORTCreate(short&nTable,LPCWSTRlpszName);

HRESULTDEF_EXPORTDelete(shortnTable);

//Interfaseparaobtenberinformacionsobrelabasededatos

HRESULTDEF_EXPORTGetNumTables(short&nNumTables);

HRESULTDEF_EXPORTGetTableName(shortnTable,LPWSTRlpszName);

HRESULTDEF_EXPORTGetNumRows(shortnTable,short&nRows);

ULONGDEF_EXPORTRelease();//CPPTOCOM:needtofreeanobjectintheDLL,sinceitwasallocatedhere

//Implementation

private:

CPtrArraym_arrTables;   //ArrayofpointerstoCStringArray(the"database")

CStringArraym_arrNames;//Arrayoftablenames

public:

~CDB();

};

classCDBSrvFactory

{

//Interface

public:

HRESULTDEF_EXPORTCreateDB(CDB**ppObject);

ULONG DEF_EXPORTRelease();

};

HRESULTDEF_EXPORTDllGetClassFactoryObject(CDBSrvFactory**ppObject);

在另一个DBSrvFact.cpp文件中实现类工厂:

#include"..interfacedbsrv.h"//留意:接口头文件是DLL项目和客户法度榜样共享的

//Createanewdatabaseobjectandreturnapointertoit

HRESULTCDBSrvFactory::CreateDB(CDB**ppvDBObject)

{

*ppvDBObject=newCDB;

returnNO_ERROR;

}

ULONGCDBSrvFactory::Release()

{

deletethis;

return0;

}

HRESULTDEF_EXPORTDllGetClassFactoryObject(CDBSrvFactory**ppObject)

{

*ppObject=newCDBSrvFactory;

returnNO_ERROR;

}

编译后天生引入库文件(.LIB)和动态链接库文件(.DLL)。

三)改动客户法度榜样

1)因为前面我们已经为CDB类添加了删除自己的函数Release(),是以在CDBDoc的析构函数中改动我们应用的CDB工具的删除要领如下:

CDBDoc::~CDBDoc()

{

if(m_pDB)

{

m_pDB->Release();//不再是deletem_pDB

m_pDB=NULL;

}

}

2)创建CDB类工具的要领改变了,我们经由过程对应的类工厂工具来创建CDB工具,而不再是直接地new一个CDB工具出来了。

BOOLCDBDoc::OnNewDocument()

{

if(!CDocument::OnNewDocument())

returnFALSE;

//新建数据库工具

//m_pDB=newCDB;

CDBSrvFactory*pDBFactory=NULL;//对应的类工厂工具

DllGetClassFactoryObject(&pDBFactory);//获取对应的类工厂

pDBFactory->CreateDB(&m_pDB);//由类工厂认真创建所哀求的工具

pDBFactory->Release();//donotneedthefactoryanymore

//初始化数据成员变量

}

您可能还会对下面的文章感兴趣: