在线等:怎么用c++实现在局域网中客户机端对服务器数据库的访问? 最好给个例子、代码示例。谢谢

faynxy123 2003-09-12 03:01:41
同上
...全文
193 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
tiny_yan 2003-09-18
  • 打赏
  • 举报
回复
VC中实现对ADO操作通常有三种方法:

#import方法;

利用MFC OLE的ClassWizard;

通过Windows API中COM相关的函数。

在这三种方法中,#import是最方便的方法,它允许产生一个类似VB的类结构,使程序开发变得很方便。下面分别介绍这三种方法。

1.#import方法

在#import方法中,需要提供所要包含的类型库的路径和名称,VC能够自动产生一个对GUIDs的定义,以及自动生成对ADO对象的封装。对任何引用的类型库,VC会在编译的时候自动生成两个文件:

头文件(.tlh):包含了所列举的类型和对类型库中对象的定义;

实现文件(.tli):对类型库对象模型中的方法产生封装。

例如,在stdafx.h文件中增加对msado15.dd的

#import之后,VC会产生msado15.tlh和msado15.tli两个文件。

#import能够使用一个新的类_com_ptr_t,它也被称为智能指针。智能指针能够自动执行QuyerInterface、AddRef和Release函数。

下面的代码演示了如何使用#import在应用中实现对ADO的操作:

#import “c:\program files\common files\system\ado\msado15.dll” \no_namespace

rename ( “EOF”, “adoEOF” )

重命名EOF是必要的,因为典型的VC应用都已经定义了EOF作为常数-1。

通常来说,操作一个自动化对象需要定义和初始化一个用来操作的变量。可以通过使用智能指针

(_com_ptr_t)的构造函数传递一个有效的CLSID或者是PROGID,也可以通过_com_ptr_t::CreateInstance()方法来定义对象。具体代码如下所示:

_ConnectionPtr Conn1( __uuidof( Connection ) );

也可以采用下面的代码实现同样的功能:

_ConnectionPtr Conn1 = NULL; //定义对象

HRESULT hr = S_OK;

//创建实例

hr =Conn1.CreateInstance( __uuidof( Connection ) );

推荐采用第二种方式,因为用第一种方式不能返回一个失败的HRESULT,所以也就不能判断ADO连接对象是成功还是失败,以及失败的原因。注意这里的__uuidof( Connection)中的Connection是在.tlh文件中定义的。通过把它传递给方法CreateInstance,就可以创建一个有效的ADOConnection对象。

需要注意的是#import的no_namespace属性,它告诉编译器该类在不在一个单独的名字空间中。使用no_namespace意味着不需要在初始化变量时引用名字空间。当然如果在应用中需要导入多个类型库时,最好不要使用no_namespace,以免引起名字冲突。

下面是一个简单的采用了#import方法的基于ADO应用的示例代码:

#include <windows.h>

#import <msado15.dll> rename(“EOF”, “adoEOF”)

void main()

{

HRESULT hr = S_OK;

//因为没有在#import中指定no_namespace,所以必须采用ADODB::这样的形式来定义变量类型

ADODB::_RecordsetPtr Rs1 = NULL;

//通过ODBC建立ADO连接

_bstr_t Connect( “DSN=AdoDemo;UID=sa;PWD=;” );

_bstr_t Source ( “SELECT * FROM Authors” );

CoInitialize();

//初始化Rs1对象

hr = Rs1.CreateInstance( __uuidof( ADODB::Recordset ) );

//省略对返回值hr的判断

Rs1->Open( Source,

Aonnect,

ADODB::adOpenForwardOnly,

ADODB::adLockReadOnly,

-1 );

//此处可以添加对记录集Rs1进行操作的代码

Rs1->Close();

Rs1 = NULL;

::MessageBox( NULL,“Success!”,“”,MB_OK );

CoUninitialize();

}

2.用MFC OLE创建ADO应用

MFC OLE同样能够封装(wrapper)一个类型库,但是与#import不同,它不能从类型库中产生枚举类型。MFC类CString和COleVariant隐藏了BSTRS和Variants的细节。由MFC OLE产生的类都继承了类ColeDispatchDriver,由ADO产生的失败的HRESULTS被封装在类ColeDispatchException中。

用MFC OLE ClassWizard创建ADO应用的步骤如下:

从Tools菜单中,选择Options选项中的Directories tab条目,在Show Directories中的Library Files中增加路径C:\program files\common files\system\ado,设置包含ADO类型库的路径。

从View菜单中,激活ClassWizard,点击Add Class按钮并选择“From A Type Library...”选项,然后在Type Library dialog box对话框中,从C:\program files\common files\system\ado中选择文件msado15.dll,在Confirm Classes对话框中,选择所有列出的类并按OK按钮退出ClassWizard。这样,ClassWizard便生成了两个文件msado15.h和msado15.cpp。

下面是实现ADO应用的示例代码:

//初始化COM对象

AfxOleInit();

...

//定义数据集对象

_Recordset Rs1;

COleException e;

COleVariant Connect( “DSN=AdoDemo;UID=sa;PWD=;” );

COleVariant Source ( “SELECT * FROM Authors” );

//创建数据集对象

Rs1.CreateDispatch(“ADODB.Recordset.2.0”,&e );

Rs1.Open( (VARIANT) Source,

(VARIANT) Connect,

0, 1, -1 );

//此处可以添加对结果集Rs1进行处理的代码

Rs1.Close();

Rs1.ReleaseDispatch();

AfxMessageBox(“Success!”);

3.用COM API创建ADO工程

#import和MFC OLE都围绕着一个给定的自动化对象产生了一个封装类,它们分别继承自_com_ptr_t和ColeDispatchDriver。其实也可以通过使用Windows API函数直接初始化ADO对象。为了直接使用ADO和COM对象,需要添加两个头文件adoid.h和adoint.h,这两个头文件定义了CLSIDs、接口定义和操作ADO类型库所需要的枚举类型。此外,还需要增加头文件INITGUID.H。

为了能够编译用COM API创建的ADO工程文件,还需要在机器中安装OLE DB SDK或者是MSDASDK工具。下面是利用API创建ADO的简单的示例代码:

#include <windows.h>

#include <initguid.h>

#include “adoid.h” // ADO的GUID's

#include “adoint.h” // ADO的类、枚举等等

void main()

{

HRESULT hr = S_OK;

// ADORecordset 是在adoint.h中定义的

ADORecordset*Rs1 = NULL;

VARIANT Source;

VARIANT Connect;

VariantInit( &Source );

VariantInit( &Connect );

Source.vt = VT_BSTR;

Source.bstrVal = ::SysAllocString( L“SELECT * FROM Authors”);

Connect.vt = VT_BSTR;

Connect.bstrVal = ::SysAllocString( L“DSN=AdoDemo;UID=sa;PWD=;” );

hr = CoCreateInstance( CLSID_CADORecordset,

NULL,

CLSCTX_INPROC_SERVER,

IID_IADORecordset,

(LPVOID *) &Rs1 );

if( SUCCEEDED( hr ) ) hr = Rs1->Open

(Source,

Connect,

adOpenForwardOnly,

adLockReadOnly,

-1 );

//对记录集Rs1进行处理

if( SUCCEEDED( hr ) ) hr = Rs1->Close();

if( SUCCEEDED( hr ) ) { Rs1->Release(); Rs1 = NULL; }

if( SUCCEEDED( hr ) ) ::MessageBox( NULL, “Success!”, “”, MB_OK );

}

C++ Extensions

如果用C++进行ADO应用程序开发,应该使用ADO C++ Extensions。我们知道,用VB或者VBScript来操作ADO是非常方便的,但是如果使用C++或者是Java,就必须要处理类似Variants这样的数据结构以实现和C++数据结构的转换,而这种处理无疑是所有C++开发人员都很头疼的事情。但如果使用C++ Extensions的话,ADO就不需要从数据提供者处得到列信息,而是在设计时刻使用开发人员提供的列信息。以下是一个简单的示例:

//创建和具体记录相对应的类

class CAuthor : public CADORecordBinding

{

BEGIN_ADO_BINDING(CCustomRs1)

ADO_VARIABLE_LENGTH_ENTRY4(1,

adVarChar, m_szau_id, sizeof(m_szau_id), FALSE)

ADO_VARIABLE_LENGTH_ENTRY4(2,

adVarChar,m_szau_fname,sizeof(m_szau_fname), FALSE)

ADO_VARIABLE_LENGTH_ENTRY4(3,

adVarChar,m_szau_lname,sizeof(m_szau_lname), FALSE)

END_ADO_BINDING()

protected:

char m_szau_id[12];

char m_szau_fname[21];

char m_szau_lname[41];

};

void FetchAuthorData()

{

CAuthor author;

//记录集对象

_RecordsetPtr pRs;

IADORecordBinding *piAdoRecordBinding;

//获取COM对象接口指针

pRs.CreateInstance(__uuidof(Recordset));

//得到需要的记录集

pRs->Open(“select au_id,au_fname,au_lname from Employees”,“Provider=SQLOLEDB;Data Source=sureshk1;Database=pubs;User Id=sa;Password=;”,

adOpenForwardOnly,

adLockReadOnly,

adCmdText);

//查询接口IADORecordBinding

pRs->QueryInterface(__uuidof(IADORecordBinding),(LPVOID*)&piAdoRecordBinding);

//绑定对象

piAdoRecordBinding->BindToRecordset(&author);

//得到记录中的相关内容

while (VARIANT_FALSE == pRs->EOF) {

printf(“%s %s %s”, author.m_szau_id,

author.m_szau_fname, author.m_szau_lname);

pRs->MoveNext();

}

//释放对象

piAdoRecordBinding->Release();

}
pengdali 2003-09-18
  • 打赏
  • 举报
回复
1.配置ODBC,建立ODBC和SQL SERVER的连接ODBCTEST
2.在VC++通过该ODBC调用SQL SERVER的STORED PROCEDURE(szTypes )
#include "stdafx.h"
#include "DatabaseServer.h"
#include <stdarg.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CDatabaseServer::CDatabaseServer()
{

}

CDatabaseServer::~CDatabaseServer()
{

}

bool CDatabaseServer::getConnectionString(char *szConnectionString)
{
char szServerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwSize=sizeof(szServerName) ;
if(!GetComputerName(szServerName,&dwSize))
return false ;


if(!szConnectionString)
return false ;

char szUserName[] = "SA";
char szPassword[] = "";
char szDatabase[] = "IPLOMA";//ADD YOU DATEBASE NAME

sprintf(szConnectionString,"DSN=ODBCTEST;uid=%s;pwd=%s;",szServerName,szDatabase,szUserName,szPassword); //建立CONNECTION STRING

return true;
}

VARIANT CDatabaseServer::getExecStoredProcedure(char *szTypes,SAFEARRAY *pSPFields)
{
_variant_t vtResultRows;
try
{
_CommandPtr pCmdPtr;
_RecordsetPtr pRecordset;
HRESULT hr ;

hr = pCmdPtr.CreateInstance(__uuidof(Command));

char szConnectionString[255];
getConnectionString(szConnectionString);
_variant_t vtConnectionString(szConnectionString);
pCmdPtr->put_ActiveConnection(vtConnectionString);

pCmdPtr->CommandType = adCmdStoredProc; //CALL SQL SP
pCmdPtr->CommandText = szTypes ; //YOU SP NAME
hr = pCmdPtr->Parameters->Refresh();

long lBound,uBound ;
HRESULT hresult ;
// Getting Safe Array's Lower and Upper Bounds
hresult = SafeArrayGetLBound(pSPFields, 1, &lBound);
hresult = SafeArrayGetUBound(pSPFields, 1, &uBound);

variant_t vtParamVal;
_variant_t Index;
Index.vt = VT_I2;
Index.iVal = 1 ;
for (long iElements=lBound;iElements<=uBound;iElements++)
{
hresult = SafeArrayGetElement(pSPFields, &iElements, &vtParamVal);
pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal) ;
Index.iVal++ ;
}

//Execute current Stored Procedure
_variant_t vEffected ;
pRecordset = pCmdPtr->Execute(&vEffected,NULL,NULL);
if (pRecordset->BOF || pRecordset->EndOfFile)
throw ;
// Get result set in the form of array
vtResultRows = pRecordset->GetRows(-1);
return vtResultRows.Detach() ;
}
catch(_com_error &e)
{
ATLTRACE((LPCSTR)e.Description());
}
vtResultRows.vt = VT_EMPTY ;
return vtResultRows.Detach();
}

long CDatabaseServer::setExecStoredProcedure(char *szTypes,SAFEARRAY *pSPFields)
{
_variant_t vtResultRows;
try
{
_CommandPtr pCmdPtr;
_RecordsetPtr pRecordset;
HRESULT hr ;

hr = pCmdPtr.CreateInstance(__uuidof(Command));

char szConnectionString[255];
getConnectionString(szConnectionString);
_variant_t vtConnectionString(szConnectionString);
pCmdPtr->put_ActiveConnection(vtConnectionString);

pCmdPtr->CommandType = adCmdStoredProc;
pCmdPtr->CommandText = szTypes ;
hr = pCmdPtr->Parameters->Refresh();

long lBound,uBound;
HRESULT hresult;
// Getting Safe Array's Lower and Upper Bounds
hresult = SafeArrayGetLBound(pSPFields, 1, &lBound);
hresult = SafeArrayGetUBound(pSPFields, 1, &uBound);

variant_t vtParamVal;
_variant_t Index;
Index.vt = VT_I2;
Index.iVal = 1 ;
for (long iElements=lBound;iElements<=uBound;iElements++)
{
hresult = SafeArrayGetElement(pSPFields, &iElements, &vtParamVal);
pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal) ;
Index.iVal++ ;
}

_variant_t vEffected ;
pCmdPtr->Execute(&vEffected,NULL,NULL);

// We Are Expecting That Stored Procedures Return ID for Entity to which
// NSERT/UPDATE/DELETE operation is being performed
return (long)pCmdPtr->Parameters->Item["RETURN_VALUE"]->Value ;
}
catch(_com_error &e)
{
ATLTRACE((LPCSTR)e.Description());
}
return 0;
}
faynxy123 2003-09-18
  • 打赏
  • 举报
回复
要结帖了,大家快点啊
liuyun2003 2003-09-12
  • 打赏
  • 举报
回复
使用ADO连接。我想C++应该有例子吧。

22,209

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧