TN054:在使用 MFC DAO 类时直接调用 DAO

注释

DAO 与 Access 数据库一起使用,并通过 Office 2013 提供支持。 DAO 3.6 是最终版本,它被视为已过时。 Visual C++ 环境和向导不支持 DAO(尽管包含 DAO 类,但仍可使用它们)。 Microsoft建议对新项目使用 OLE DB 模板ODBC 和 MFC 。 应仅在维护现有应用程序时使用 DAO。

使用 MFC DAO 数据库类时,可能需要直接使用 DAO。 通常,情况并非如此,但 MFC 提供了一些帮助程序机制,以便在将 MFC 类与直接 DAO 调用结合使用时简化直接 DAO 调用。 对 MFC 托管 DAO 对象的方法进行直接 DAO 调用应该只需要几行代码。 如果需要创建和使用 MFC 管理的 DAO 对象,则必须通过实际调用 Release 对象来执行更多工作。 此技术说明介绍了何时可能想要直接调用 DAO、MFC 帮助程序可执行的作以及如何使用 DAO OLE 接口。 最后,此说明提供了一些示例函数,演示如何直接为 DAO 安全功能调用 DAO。

何时进行直接 DAO 调用

进行直接 DAO 调用的最常见情况发生在需要刷新集合或实现 MFC 未包装的功能时。 MFC 未公开的最重要功能是安全性。 如果要实现安全功能,则需要直接使用 DAO 用户和 Group(s) 对象。 除了安全性,MFC 还仅支持其他几个 DAO 功能。 其中包括记录集克隆和数据库复制功能,以及 DAO 的一些后期添加。

DAO 和 MFC 实现的简要概述

MFC 的 DAO 包装使使用 DAO 更容易处理许多详细信息,因此无需担心小事情。 这包括 OLE 的初始化、DAO 对象的创建和管理(尤其是集合对象)、错误检查以及提供强类型化、更简单的接口(无 VARIANTBSTR 参数)。 你可以进行直接 DAO 调用,但仍可以利用这些功能。 所有代码都必须对直接 DAO 调用创建的任何对象进行调用 Release而不 修改 MFC 在内部可能依赖的任何接口指针。 例如,除非你了解所有内部影响,否则不要修改打开CDaoRecordset对象的m_pDAORecordset成员。 但是,可以使用 m_pDAORecordset 接口直接调用 DAO 以获取 Fields 集合。 在这种情况下,不会修改 m_pDAORecordset 成员。 完成对象后,只需调用 Release Fields 集合对象。

帮助程序的说明,以简化 DAO 调用

为简化调用 DAO 而提供的帮助程序与 MFC DAO 数据库类内部使用的帮助程序相同。 这些帮助程序用于在进行直接 DAO 调用、记录调试输出、检查预期错误以及在必要时引发适当的异常时检查返回代码。 有两个基础帮助程序函数和四个宏映射到这两个帮助程序之一。 最好的解释是只读取代码。 请参阅 AFXDAO 中的DAO_CHECK、DAO_CHECK_ERRORDAO_CHECK_MEMDAO_TRACE。H 查看宏,并在 DAOCORE 中看到 AfxDaoCheckAfxDaoTrace。CPP。

使用 DAO OLE 接口

DAO 对象层次结构中每个对象的 OLE 接口在头文件 DBDAOINT 中定义。H,位于 \Program Files\Microsoft Visual Studio .NET 2003\VC7\include 目录中。 这些接口提供用于作整个 DAO 层次结构的方法。

对于 DAO 接口中的许多方法,需要作对象 BSTR (OLE 自动化中使用的长度前缀字符串)。 对象 BSTR 通常封装在 VARIANT 数据类型中。 MFC 类 COleVariant 本身继承自 VARIANT 数据类型。 根据你是否为 ANSI 或 Unicode 生成项目,DAO 接口将返回 ANSI 或 Unicode BSTR。 两个宏(V_BSTR和V_BSTRT)可用于确保 DAO 接口获取 BSTR 预期的类型。

V_BSTR将提取 a COleVariant. 的 bstrVal 成员。 当需要将 a COleVariant 的内容传递给 DAO 接口的方法时,通常使用此宏。 以下代码片段显示了 DAO DAOUser 接口的声明和实际用途,这些方法利用V_BSTR宏:

COleVariant varOldName;
COleVariant varNewName(_T("NewUser"), VT_BSTRT);

// Code to assign pUser to a valid value omitted DAOUser *pUser = NULL;

// These method declarations were taken from DBDAOINT.H
// STDMETHOD(get_Name) (THIS_ BSTR FAR* pbstr) PURE;
// STDMETHOD(put_Name) (THIS_ BSTR bstr) PURE;
DAO_CHECK(pUser->get_Name(&V_BSTR (&varOldName)));
DAO_CHECK(pUser->put_Name(V_BSTR (&varNewName)));

请注意,VT_BSTRTCOleVariant上述构造函数中指定的参数可确保在生成应用程序的 ANSI BSTRCOleVariant 版本和应用程序的 Unicode BSTR 版本时,会有 ANSI。 这是 DAO 期望的。

另一个宏V_BSTRT将提取 ANSI 或 Unicode bstrVal 成员 COleVariant ,具体取决于生成类型(ANSI 或 Unicode)。 以下代码演示如何将值从 a COleVariant 中提取BSTR到以下项CString

COleVariant varName(_T("MyName"), VT_BSTRT);
CString str = V_BSTRT(&varName);

DAOVIEW 示例中演示了V_BSTRT宏以及打开存储在其中 COleVariant的其他类型的其他方法。 具体而言,此转换是在方法中 CCrack::strVARIANT 执行的。 如果可能,此方法会将 a COleVariant 的值转换为实例 CString

直接调用 DAO 的简单示例

需要刷新基础 DAO 集合对象时,可能会出现这种情况。 通常,这不应是必需的,但如果有必要,则这是一个简单的过程。 需要刷新集合的示例是在具有多个用户创建新 tabledefs 的多用户环境中作时。 在这种情况下,tabledefs 集合可能已过时。 若要刷新集合,只需调用 Refresh 特定集合对象的方法并检查错误:

DAO_CHECK(pMyDaoDatabase->m_pDAOTableDefs->Refresh());

请注意,目前所有 DAO 集合对象接口都是 MFC DAO 数据库类的未记录实现详细信息。

直接将 DAO 用于 DAO 安全功能

MFC DAO 数据库类不会包装 DAO 安全功能。 必须调用 DAO 接口的方法才能使用某些 DAO 安全功能。 以下函数设置系统数据库,然后更改用户的密码。 此函数调用随后定义的另外三个函数。

void ChangeUserPassword()
{
    // Specify path to the Microsoft Access *// system database
    CString strSystemDB =
        _T("c:\\Program Files\\MSOffice\\access\\System.mdw");

    // Set system database before MFC initilizes DAO
    // NOTE: An MFC module uses only one instance
    // of a DAO database engine object. If you have
    // called a DAO object in your application prior
    // to calling the function below, you must call
    // AfxDaoTerm to destroy the existing database
    // engine object. Otherwise, the database engine
    // object already in use will be reused, and setting
    // a system datbase will have no effect.
    //
    // If you have used a DAO object prior to calling
    // this function it is important that DAO be
    // terminated with AfxDaoTerm since an MFC
    // module only gets one copy of the database engine
    // and that engine will be reused if it hasn't been
    // terminated. In other words, if you do not call
    // AfxDaoTerm and there is currently a database
    // initialized, setting the system database will
    // have no effect.
    SetSystemDB(strSystemDB);

    // User name and password manually added
    // by using Microsoft Access
    CString strUserName = _T("NewUser");
    CString strOldPassword = _T("Password");
    CString strNewPassword = _T("NewPassword");

    // Set default user so that MFC will be able
    // to log in by default using the user name and
    // password from the system database
    SetDefaultUser(strUserName, strOldPassword);

    // Change the password. You should be able to
    // call this function from anywhere in your
    // MFC application
    ChangePassword(strUserName, strOldPassword, strNewPassword);

    // ...
}

接下来的四个示例演示如何:

  • 设置系统 DAO 数据库(。MDW 文件)。

  • 设置默认用户和密码。

  • 更改用户的密码。

  • 更改 . 的密码。MDB 文件。

设置系统数据库

下面是一个示例函数,用于设置应用程序将使用的系统数据库。 在进行任何其他 DAO 调用之前,必须调用此函数。

// Set the system database that the
// DAO database engine will use

void SetSystemDB(CString& strSystemMDB)
{
    COleVariant varSystemDB(strSystemMDB, VT_BSTRT);

    // Initialize DAO for MFC
    AfxDaoInit();
    DAODBEngine* pDBEngine = AfxDaoGetEngine();

    ASSERT(pDBEngine != NULL);

    // Call put_SystemDB method to set the *// system database for DAO engine
    DAO_CHECK(pDBEngine->put_SystemDB(varSystemDB.bstrVal));
}

设置默认用户和密码

若要设置系统数据库的默认用户和密码,请使用以下函数:

void SetDefaultUser(CString& strUserName,
    CString& strPassword)
{
    COleVariant varUserName(strUserName, VT_BSTRT);
    COleVariant varPassword(strPassword, VT_BSTRT);

    DAODBEngine* pDBEngine = AfxDaoGetEngine();
    ASSERT(pDBEngine != NULL);

    // Set default user:
    DAO_CHECK(pDBEngine->put_DefaultUser(varUserName.bstrVal));

    // Set default password:
    DAO_CHECK(pDBEngine->put_DefaultPassword(varPassword.bstrVal));
}

更改用户的密码

若要更改用户的密码,请使用以下函数:

void ChangePassword(CString &strUserName,
    CString &strOldPassword,
    CString &strNewPassword)
{
    // Create (open) a workspace
    CDaoWorkspace wsp;
    CString strWspName = _T("Temp Workspace");

    wsp.Create(strWspName, strUserName, strOldPassword);
    wsp.Append();

    // Determine how many objects there are *// in the Users collection
    short nUserCount;
    short nCurrentUser;
    DAOUser *pUser = NULL;
    DAOUsers *pUsers = NULL;

    // Side-effect is implicit OLE AddRef()
    // on DAOUser object:
    DAO_CHECK(wsp.m_pDAOWorkspace->get_Users(&pUsers));

    // Side-effect is implicit OLE AddRef()
    // on DAOUsers object
    DAO_CHECK(pUsers->getcount(&nUserCount));

    // Traverse through the list of users
    // and change password for the userid
    // used to create/open the workspace
    for(nCurrentUser = 0; nCurrentUser <nUserCount; nCurrentUser++)
    {
        COleVariant varIndex(nCurrentUser, VT_I2);
        COleVariant varName;

        // Retrieve information for user nCurrentUser
        DAO_CHECK(pUsers->get_Item(varIndex, &pUser));

        // Retrieve name for user nCurrentUser
        DAO_CHECK(pUser->get_Name(&V_BSTR(&varName)));

        CString strTemp = V_BSTRT(&varName);

        // If there is a match, change the password
        if (strTemp == strUserName)
        {
            COleVariant varOldPwd(strOldPassword, VT_BSTRT);
            COleVariant varNewPwd(strNewPassword, VT_BSTRT);

            DAO_CHECK(pUser->NewPassword(V_BSTR(&varOldPwd),
                V_BSTR(&varNewPwd)));

            TRACE("\t Password is changed\n");
        }
    }
    // Clean up: decrement the usage count
    // on the OLE objects
    pUser->Release();
    pUsers->Release();
    wsp.Close();
}

更改 . 的密码MDB 文件

更改 . 的密码MDB 文件,使用以下函数:

void SetDBPassword(LPCTSTR pDB,
    LPCTSTR pszOldPassword,
    LPCTSTR pszNewPassword)
{
    CDaoDatabase db;
    CString strConnect(_T(";pwd="));

    // the database must be opened as exclusive
    // to set a password
    db.Open(pDB, TRUE, FALSE, strConnect + pszOldPassword);

    COleVariant NewPassword(pszNewPassword, VT_BSTRT),
                OldPassword(pszOldPassword, VT_BSTRT);

    DAO_CHECK(db.m_pDAODatabase->NewPassword(V_BSTR(&OldPassword),
        V_BSTR(&NewPassword)));

    db.Close();
}

另请参阅

按编号列出的技术说明
按类别列出的技术说明