TN054. Вызов DAO напрямую при использовании классов DAO MFC

Примечание.

DAO используется с базами данных Access и поддерживается до Office 2013. Версия DAO 3.6 является окончательной и считается устаревшей. Среда и мастеры Visual C++ не поддерживают DAO (хотя классы DAO включены и их можно использовать). Корпорация Майкрософт рекомендует использовать шаблоны OLE DB или ODBC и MFC для новых проектов. Для обслуживания существующих приложений следует использовать только DAO.

При использовании классов баз данных DAO MFC могут возникнуть ситуации, когда необходимо использовать DAO напрямую. Как правило, это не так, но MFC предоставил некоторые вспомогательные механизмы для упрощения прямых вызовов DAO при сочетании использования классов MFC с прямыми вызовами DAO. Выполнение прямых вызовов DAO к методам объекта DAO, управляемого MFC, должно требовать только несколько строк кода. Если вам нужно создать и использовать объекты DAO, которые не управляются MFC, вам придется немного больше работать, вызвав Release объект. В этой технической заметке объясняется, когда может потребоваться напрямую вызвать DAO, какие вспомогательные средства MFC могут помочь вам и как использовать интерфейсы OLE DAO. Наконец, эта заметка содержит некоторые примеры функций, показывающих, как вызывать DAO напрямую для функций безопасности DAO.

Когда делать прямые вызовы DAO

Наиболее распространенные ситуации при выполнении прямых вызовов DAO возникают, когда коллекции необходимо обновить или при реализации функций, не упакованных mFC. Наиболее важным компонентом, не предоставляемым MFC, является безопасность. Если вы хотите реализовать функции безопасности, необходимо напрямую использовать объекты DAO User(s) и Group(s). Помимо безопасности, существует только несколько других функций DAO, которые не поддерживаются MFC. К ним относятся клонирование наборов записей и функции реплика tion базы данных, а также несколько поздних добавлений в DAO.

Краткий обзор реализации DAO и MFC

Оболочка DAO MFC упрощает использование DAO, обрабатывая многие детали, чтобы не беспокоиться о маленьких вещах. Это включает инициализацию OLE, создание и управление объектами DAO (особенно объектами коллекции), ошибками проверка и предоставление строго типизированного, простого интерфейса (без variant или BSTR аргументов). Вы можете выполнять прямые вызовы DAO и по-прежнему использовать эти функции. Весь код должен выполнять вызов Release любых объектов, созданных прямыми вызовами DAO, и не изменять какие-либо указатели интерфейса, которые MFC может полагаться на внутренние. Например, не изменяйте элемент m_pDAORecordset открытого CDaoRecordset объекта, если вы не понимаете все внутренние последствия. Однако вы можете использовать интерфейс m_pDAORecordset для вызова DAO непосредственно для получения коллекции Fields. В этом случае элемент m_pDAORecordset не будет изменен. Необходимо просто вызвать Release объект коллекции Fields после завершения работы с объектом.

Описание вспомогательных функций для упрощения вызовов DAO

Вспомогательные средства, предоставляемые для упрощения вызова DAO, являются теми же вспомогательными средствами, которые используются внутренне в классах базы данных DAO MFC. Эти вспомогательные средства используются для проверка кодов возврата при выполнении прямого вызова DAO, ведения журнала выходных данных отладки, проверка для ожидаемых ошибок и создания соответствующих исключений при необходимости. Существует две базовые вспомогательные функции и четыре макроса, которые сопоставляются с одним из этих двух вспомогательных элементов. Лучше всего объяснить, чтобы просто прочитать код. См. DAO_CHECK, DAO_CHECK_ERROR, DAO_CHECK_MEM и DAO_TRACE в AFXDAO. H, чтобы просмотреть макросы и просмотреть AfxDaoCheck и AfxDaoTrace в DAOCORE. CPP.

Использование интерфейсов OLE DAO

Интерфейсы OLE для каждого объекта в иерархии объектов DAO определяются в файле заголовка DBDAOINT. H, который находится в каталоге \Program Files\Microsoft Visual Studio .NET 2003\VC7\include. Эти интерфейсы предоставляют методы, позволяющие управлять всей иерархией DAO.

Для многих методов в интерфейсах DAO необходимо управлять BSTR объектом (строка с префиксом длины, используемой в автоматизации OLE). Объект BSTR обычно инкапсулируется в типе данных VARIANT . Класс COleVariant MFC наследует от типа данных VARIANT . В зависимости от того, будет ли вы создавать проект для ANSI или Юникода, интерфейсы DAO будут возвращать ANSI или Юникод BSTR. Два макроса, V_BSTR и V_BSTRT, полезны для определения того, что интерфейс DAO получает BSTR ожидаемый тип.

V_BSTR извлекает элемент bstrVal объекта COleVariant. Этот макрос обычно используется, когда необходимо передать содержимое 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_BSTRT в случае сборки версии ANSI приложения и Юникода для версии Юникода BSTR приложения будет использоваться ANSI BSTRCOleVariant.COleVariant Это то, что ожидает DAO.

Другой макрос, V_BSTRT, извлекает член COleVariant ANSI или Юникод bstrVal в зависимости от типа сборки (ANSI или Юникод). В следующем коде показано, как извлечь BSTR значение из a COleVariant в CString:

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

Макрос V_BSTRT, а также другие методы открытия других типов, хранящихся в COleVariant, демонстрируются в примере DAOVIEW. В частности, этот перевод выполняется в методе CCrack::strVARIANT . Этот метод, где это возможно, преобразует значение объекта COleVariant в экземпляр CString.

Простой пример прямого вызова к DAO

Ситуации могут возникнуть, когда необходимо обновить базовые объекты коллекции DAO. Как правило, это не обязательно, но это простая процедура, если это необходимо. Пример того, когда может потребоваться обновить коллекцию, при работе в многопользовательской среде с несколькими пользователями, создающих новые табличные файлы. В этом случае коллекция tabledefs может стать устаревшим. Чтобы обновить коллекцию, необходимо просто вызвать Refresh метод определенного объекта коллекции и проверка для ошибок:

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

Обратите внимание, что в настоящее время все интерфейсы объектов коллекции DAO являются незадокументированных сведений о реализации классов баз данных DAO MFC.

Использование DAO непосредственно для функций безопасности DAO

Классы баз данных DAO MFC не упаковывают функции безопасности 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();
}

См. также

Технические примечания по номеру
Технические примечания по категории