有关用ATL写OLE DB数据消费者的问题,请各位高手指教:

Aizz 2002-09-09 04:14:36
我用ATL Wizzard写数据消费者,试过JET,ODBC都不能连接到我的.mdb数据库,但是建连接时测试连接却是正确的;而且我用ADO可以连接到.mdb(证明驱动没问题),可能是什么问题?
我在测试代码里面直接调用那个表名称的类的Open方法,例如:
数据库中有一个DATA表,那么用Cosumer时如果指定DATA表,那么建好的工程里面应该有一个CDATA类,我调用的就是CDATA的Open方法,结果返回失败。

希望我说清楚了我的问题,呵呵。

请指教...
...全文
100 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
Aizz 2002-09-29
  • 打赏
  • 举报
回复
谢谢 Sogald_2001 的回复。

我大概测试了一下,除了默认的SHARE_DENY_NONE外,所有的权限都不能单独使用。READ,WRITE,READWRITE和SHARE_DENY_NONE的组合也无效;而用ODBC驱动就没问题。估计这个是Access的功能限制造成的。

如果是Access 2000建的数据库,用3.51是无法访问的(Access97的数据库用4.0没测过,我想应该可以吧)。

本来以为一个很简单的问题,没想到浪费了大家这么多时间思考,又没想到竟然答案也这么简单,呵呵。

谢谢在这里回复的所有人,谢谢大家的帮助!
sogald_2001 2002-09-28
  • 打赏
  • 举报
回复
如果要使用4.0的JET引擎,楼上有人说了,MSDN中也有,就是删除 这行代码:
dbinit.AddProperty(DBPROP_AUTH_PERSIST_SENSITIVE_AUTHINFO, false);
另外,就是DB_INIT_MODE取值问题,如上面所述,和3.15的一样,不能组合
Aizz 2002-09-28
  • 打赏
  • 举报
回复

非常感谢 Sogald_2001 的回复,现在的问题解决了。

不过有两个问题不解,想再麻烦一下:
1、在你的回复中提到使用Jet的连接字符串是错误的,为什么不能用Jet?因为我觉得ADO实际应该是OLE DB的封装吧,可是ADO里可以使用连接字符串,是ADO经过处理了吗?
2、按我的理解,如果是OLE DB Provider for ODBC,那么实际上应该是通过ODBC和数据库连接,然后通过OLE DB访问;如果用Jet,那么应该是直接通过OLE访问的,两相比较,是不是Jet的速度要快呢?

请指教,谢谢!

(PS:我在测试代码中用了重复的调用是为了看看到底是哪个调用出错的,呵呵)
sogald_2001 2002-09-28
  • 打赏
  • 举报
回复
我想我该更正我上面的文字,使用JET是可以的,而且我也和你一样认为速度是应该要快些的。

向导生成的代码,严格的来说是没有错误的,不过可能是因为引擎的问题吧,
要改一些地方:

dbinit.AddProperty(DBPROP_INIT_MODE, (long)11);

11 是DB_MODE_READWRITE 和 DB_MODE_SHARE_DENY_WRITE的组合,组合老是出错的:)(我也不清楚为什么,可能是ACCESS是桌面数据库的原因吧)
你可以改成1(DB_MODE_READ),DB_MODE_READWRITE 不组合的话
DB_MODE_SHARE_EXCLUSIVE, DB_MODE_SHARE_DENY_WRITE 都是可以用的。

另外, hr = db.Open(_T("Microsoft.Jet.OLEDB.4.0"), &dbinit);
把这儿的Microsoft.Jet.OLEDB.4.0该成Microsoft.Jet.OLEDB.3.51
应该可以用了:)

caitou123 2002-09-28
  • 打赏
  • 举报
回复
gz
sogald_2001 2002-09-27
  • 打赏
  • 举报
回复
呵呵,你早该贴出代码的:)

首先,因为你把数据库用ODBC数据库小程序配置好可,你这里是AccessDB
那么,你用ATL向导的时候,选择OLE DB for ODBC驱动程序,然后选择你配置好的AccessDB数据库就行了。
得到的相关的代码如下:

// USER.H : Declaration of the CUSER class

#ifndef __USER_H_
#define __USER_H_

class CUSERAccessor
{
public:
LONG m_ID;
TCHAR m_NAME[51];
TCHAR m_PASSWORD[51];

BEGIN_COLUMN_MAP(CUSERAccessor)
COLUMN_ENTRY(1, m_ID)
COLUMN_ENTRY(2, m_NAME)
COLUMN_ENTRY(3, m_PASSWORD)
END_COLUMN_MAP()

void ClearRecord()
{
memset(this, 0, sizeof(*this));
}
};

class CUSER : public CTable<CAccessor<CUSERAccessor> >
{
public:
HRESULT Open()
{
HRESULT hr;

hr = OpenDataSource();
if (FAILED(hr))
return hr;

return OpenRowset();
}
HRESULT OpenDataSource()
{
HRESULT hr;
CDataSource db;
CDBPropSet dbinit(DBPROPSET_DBINIT);

dbinit.AddProperty(DBPROP_AUTH_PERSIST_SENSITIVE_AUTHINFO, false);
dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("AccessDb"));
dbinit.AddProperty(DBPROP_INIT_PROMPT, (short)4);
dbinit.AddProperty(DBPROP_INIT_LCID, (long)2052);
hr = db.Open(_T("MSDASQL"), &dbinit);
if (FAILED(hr))
return hr;

return m_session.Open(db);
}
HRESULT OpenRowset()
{
return CTable<CAccessor<CUSERAccessor> >::Open(m_session, _T("User"));
}
CSession m_session;
};

#endif // __USER_H_




然后,你的Initialize方法是这么写的:
STDMETHODIMP CAccessDB::Initialize()
{
CUSER my;
HRESULT hr;
hr=my.OpenDataSource();
if (FAILED(hr))
return(hr);
hr=my.OpenRowset();
if (FAILED(hr))
return(6);
if (FAILED(my.Open()))
return(8);

return S_OK;
}

my.Open() ,该方法内部已经调用了OpenDataSource 和 OpenRowset
你上面的方法调用是重复的,可以很简单的这样写:
STDMETHODIMP CAccessDb::Initialize()
{
return my.Open();
}


你原来连接数据库的时候,是使用JET数据库引擎的吧,呵呵,那是连接字符串,这么用是错误的。
基本上就是这样吧,希望我没有说错:)
Aizz 2002-09-27
  • 打赏
  • 举报
回复
谢谢 sogald_2001 的回复

我想大概的代码应该就是这么多了。
User表中有ID,NAME,PASSWORD,XPASS,STATUS几个字段,ID是Access里的自动编号字段,其他字段的类型可以从User.h中得知。
如果有什么遗漏请指出。

请指教,谢谢。
Aizz 2002-09-27
  • 打赏
  • 举报
回复
//这是stdafx.h
#if !defined(AFX_STDAFX_H__1372B834_517A_4BC8_AFC4_D06921A8851D__INCLUDED_)
#define AFX_STDAFX_H__1372B834_517A_4BC8_AFC4_D06921A8851D__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define STRICT
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#define _ATL_APARTMENT_THREADED

#include <atlbase.h>
//You may derive a class from CComModule and use it if you want to override
//something, but do not change the name of _Module
extern CComModule _Module;
#include <atlcom.h>
#include <atldbcli.h>

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_STDAFX_H__1372B834_517A_4BC8_AFC4_D06921A8851D__INCLUDED)

//这是stdafx.cpp
#include "stdafx.h"

#ifdef _ATL_STATIC_REGISTRY
#include <statreg.h>
#include <statreg.cpp>
#endif

#include <atlimpl.cpp>

//这是AccessDB.h,Consumer的名字叫AccessDB,接口是IAccessDB
#ifndef __ACCESSDB_H_
#define __ACCESSDB_H_

#include "resource.h" // main symbols

/////////////////////////////////////////////////////////////////////////////
// CAccessDB
class ATL_NO_VTABLE CAccessDB :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CAccessDB, &CLSID_AccessDB>,
public IDispatchImpl<IAccessDB, &IID_IAccessDB, &LIBID_ACCDBLib>
{
public:
CAccessDB()
{
}

DECLARE_REGISTRY_RESOURCEID(IDR_ACCESSDB)
DECLARE_NOT_AGGREGATABLE(CAccessDB)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CAccessDB)
COM_INTERFACE_ENTRY(IAccessDB)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// IAccessDB
public:
STDMETHOD(Initialize)();
};

#endif //__ACCESSDB_H_

//这是AccessDB.cpp,实现了一个Initialize()方法
#include "stdafx.h"
#include "AccDB.h" //AccDB是工程名,AccDB.h是Consumer自动生成的
#include "AccessDB.h"
#include "USER.h" //USER是数据库中的一个Table

/////////////////////////////////////////////////////////////////////////////
// CAccessDB

STDMETHODIMP CAccessDB::Initialize()
{
CUSER my;
HRESULT hr;
hr=my.OpenDataSource();
if (FAILED(hr))
return(hr);
hr=my.OpenRowset();
if (FAILED(hr))
return(6);
if (FAILED(my.Open()))
return(8);

return S_OK;
}

//这是USER.h,也是Consumer自动生成的。
#ifndef __USER_H_
#define __USER_H_

class CUSERAccessor
{
public:
LONG m_ID;
TCHAR m_NAME[16];
TCHAR m_PASSWORD[16];
SHORT m_STATUS;
TCHAR m_XPASS[16];

BEGIN_COLUMN_MAP(CUSERAccessor)
COLUMN_ENTRY(1, m_ID)
COLUMN_ENTRY(2, m_NAME)
COLUMN_ENTRY(3, m_PASSWORD)
COLUMN_ENTRY(4, m_XPASS)
COLUMN_ENTRY(5, m_STATUS)
END_COLUMN_MAP()

/*DEFINE_COMMAND(CUSERAccessor,_T(" \
SELECT \
* \
FROM USER"))
*/
DEFINE_COMMAND(CUSERAccessor, _T(" \
SELECT \
ID, \
NAME, \
PASSWORD, \
XPASS, \
STATUS \
FROM USER"))
// You may wish to call this function if you are inserting a record and wish to
// initialize all the fields, if you are not going to explicitly set all of them.
void ClearRecord()
{
memset(this, 0, sizeof(*this));
}
};

class CUSER : public CCommand<CAccessor<CUSERAccessor> >
{
public:
HRESULT Open()
{
HRESULT hr;

hr = OpenDataSource();
if (FAILED(hr))
return hr;

return OpenRowset();
}
HRESULT OpenDataSource()
{
HRESULT hr;
CDataSource db;
CDBPropSet dbinit(DBPROPSET_DBINIT);

dbinit.AddProperty(DBPROP_AUTH_CACHE_AUTHINFO, true);
dbinit.AddProperty(DBPROP_AUTH_ENCRYPT_PASSWORD, false);
dbinit.AddProperty(DBPROP_AUTH_MASK_PASSWORD, false);
dbinit.AddProperty(DBPROP_AUTH_PASSWORD, OLESTR(""));
dbinit.AddProperty(DBPROP_AUTH_USERID, OLESTR("Admin"));
dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("C:\\DATA.mdb"));
dbinit.AddProperty(DBPROP_INIT_MODE, (long)11);
dbinit.AddProperty(DBPROP_INIT_PROMPT, (short)4);
dbinit.AddProperty(DBPROP_INIT_PROVIDERSTRING, OLESTR(""));
dbinit.AddProperty(DBPROP_INIT_LCID, (long)1033);
//dbinit.AddProperty(DBPROP_AUTH_PERSIST_SENSITIVE_AUTHINFO, false);
hr = db.Open(_T("Microsoft.Jet.OLEDB.4.0"), &dbinit);
if (FAILED(hr))
return hr;

return m_session.Open(db);
}
HRESULT OpenRowset()
{
// Set properties for open
CDBPropSet propset(DBPROPSET_ROWSET);
propset.AddProperty(DBPROP_IRowsetChange, true);
propset.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);

return CCommand<CAccessor<CUSERAccessor> >::Open(m_session, NULL, &propset);
}
CSession m_session;
};

#endif // __USER_H_
Aizz 2002-09-26
  • 打赏
  • 举报
回复
谢谢 topikachu 的回复。

我试过注释该行,程序仍旧出错。
可以麻烦你随便建一个Consumer,然后用我之前贴出的代码添加一个接口,测试代码调用一下看看有没有错误吗?

请指教,谢谢。
sogald_2001 2002-09-26
  • 打赏
  • 举报
回复
刚刚我测试了,没有问题。
或许你该把代码帖出来,让大家帮你分析
topikachu 2002-09-26
  • 打赏
  • 举报
回复
当初ms也让我吃了药,其他的数据源一切正常,就是jet的有问题
以下摘自msdn

FIX: DB_E_ERRORSOCCURRED from Jet Provider During OpenDataSource

Q223180


--------------------------------------------------------------------------------
The information in this article applies to:

Microsoft Visual Studio 6.0 SP3
Microsoft OLE DB Provider for Jet, version 4.0

--------------------------------------------------------------------------------


SYMPTOMS
When using the Jet OLE DB Provider 4.0 with a Wizard-generated Active Template Library (ATL) OLE DB Consumer template class, a call to the Open or OpenDataSource method returns an HRESULT of DB_E_ERRORSOCCURRED.



CAUSE
The ATL OLE DB Consumer Wizard generates an OpenDataSource method that includes DBPROP_PERSIST_SENSITIVE_AUTHINFO as one of the initialization properties for the provider. The Jet OLE DB Provider 4.0 is not designed to accept this property and returns an HRESULT of DB_E_ERRORSOCCURRED.



STATUS
Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article.

This bug was corrected in Visual Studio 6.0 Service Pack 3. For more information about Visual Studio service packs, please see the following articles in the Microsoft Knowledge Base:

Q194022 INFO: Visual Studio 6.0 Service Packs, What, Where, Why

Q194295 HOWTO: Tell That Visual Studio 6.0 Service Packs Are Installed



MORE INFORMATION
When the ATL OLE DB Consumer Wizard generates a consumer template class using the Jet OLE DB Provider, it generates an OpenDataSource method as in the following code example:



HRESULT OpenDataSource()
{
HRESULT hr;
CDataSource db;
CDBPropSet dbinit(DBPROPSET_DBINIT);

dbinit.AddProperty(DBPROP_AUTH_CACHE_AUTHINFO, true);
dbinit.AddProperty(DBPROP_AUTH_ENCRYPT_PASSWORD, false);
dbinit.AddProperty(DBPROP_AUTH_MASK_PASSWORD, false);
dbinit.AddProperty(DBPROP_AUTH_PASSWORD, OLESTR(""));
dbinit.AddProperty(DBPROP_AUTH_PERSIST_ENCRYPTED, false);
dbinit.AddProperty(DBPROP_AUTH_PERSIST_SENSITIVE_AUTHINFO, false);
dbinit.AddProperty(DBPROP_AUTH_USERID, OLESTR("Admin"));
dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("C:\\NW97.mdb"));
dbinit.AddProperty(DBPROP_INIT_MODE, (long)16);
dbinit.AddProperty(DBPROP_INIT_PROMPT, (short)4);
dbinit.AddProperty(DBPROP_INIT_PROVIDERSTRING, OLESTR(""));
dbinit.AddProperty(DBPROP_INIT_LCID, (long)1033);

hr = db.Open(_T("Microsoft.Jet.OLEDB.4.0"), &dbinit);
if (FAILED(hr))
return hr;

return m_session.Open(db);
}
If you comment out the following line, the method does not generate a DB_E_ERRORSOCCURRED HRESULT with the Jet OLE DB Provider 4.0:


// dbinit.AddProperty(DBPROP_AUTH_PERSIST_SENSITIVE_AUTHINFO, false);
The updated ATL OLE DB Consumer Wizard installed by Visual C++ version 6.0 Service Pack 3 does not include this line of code when it generates a consumer template class for the provider, thus avoiding this error.

Additional query words:

Keywords : kbservicepack kbDatabase kbJET kbConsumer kbVS600sp2 kbVS600SP1 kbVS600sp3fix kbGrpVCDB
Issue type : kbbug
Technology :


Last Reviewed: May 19, 1999
© 2001 Microsoft Corporation. All rights reserved. Terms of Use.




--------------------------------------------------------------------------------
Send feedback to MSDN.Look here for MSDN Online resources.

后来一直用sqlserver,没有再试过access,也不知道ms自己改好了么
Aizz 2002-09-26
  • 打赏
  • 举报
回复
谢谢 topikachu 和 sogald_2001 的回复。

to topikachu:
我的VC已经打了SP5。ATL有专门的SP吗?如果有麻烦给一个链接可以吗?因为我用modem上网,M$的速度太慢了,呵呵。

to sogald_2001:
我参考的是MSDN里面说明的建立Provider的step by step,而且前面 comeovercom 贴的代码是Wizzard生成的代码,和我生成的除了名字外没有一点出入,我想应该可以说明我的步骤无误吧。我怀疑的是我的测试方法会不会有错误。

请两位指教,谢谢。
sogald_2001 2002-09-25
  • 打赏
  • 举报
回复
向导应该没有错误,我以前阅读ATL源代码的时候,测试过OLE DB部分,而且做过一些简单的整理,整个的向导生成过程是没有错误的。
现在在网吧,所以没有程序可以贴上,你可以参考ATL的程序员指南,里面有一些简单的例子。
topikachu 2002-09-24
  • 打赏
  • 举报
回复
vc++的向导有错误,先到ms下载一个最新的sp来.装上后还有问题再来问.
Aizz 2002-09-19
  • 打赏
  • 举报
回复
UP
Aizz 2002-09-18
  • 打赏
  • 举报
回复
Sorry,up...
Aizz 2002-09-17
  • 打赏
  • 举报
回复
谢谢 luxyi 的回复。

我在之前的帖子应该已经说清楚了我的Consumer的建立方法,我真的只是加了一个接口和自己的测试代码(添加的方法我之前已经说明了),其他Wizzard生成的东西我一点儿都没有改过,如果你按照我上面说的办法,完全可以重现我的程序。

请指教,谢谢。
luxyi 2002-09-17
  • 打赏
  • 举报
回复
那你只能把所有的源码都贴出来了。
Aizz 2002-09-17
  • 打赏
  • 举报
回复
谢谢 luxyi 的回复。

谢谢你的调试方法。

我没有写过SQL语句,和数据库的联系全部都是Wizzard自动生成的,我仅仅是加了一个接口。自动生成的源代码中有这么一句,大概是:
DEFINE_COMMAND(_T("SELECT \
ID \
NAME \
FROM TABLE1"))
(ID,NAME是TABLE1表中的字段名)
这句是唯一的SQL语句,除此之外没有任何SQL了。

请指教,谢谢。
luxyi 2002-09-17
  • 打赏
  • 举报
回复
-2147217900 == 0x80040E14 == DB_E_ERRORSINCOMMAND,说明你的SQL命令有问题,所以估计不是什么consumer的问题。检查一下SQL命令吧。

关于调试,打开你consumer的project,在project(menu)->settings(menu)->debug(tab)->executable for debug session(edit)输入你的console程序路径,就可以调试你的consumer了。
加载更多回复(16)

3,245

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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