Compartilhar via


TN054: chamando DAO diretamente usando classes DAO MFC

Observação

O DAO é usado com bancos de dados do Access e tem suporte do Office 2013. O DAO 3.6 é a versão final e é considerado obsoleto. O ambiente e os assistentes do Visual C++ não dão suporte a DAO (embora as classes DAO estejam incluídas e você ainda possa usá-las). A Microsoft recomenda que você use modelos OLE DB ou ODBC e MFC para novos projetos. Use DAO apenas na manutenção de aplicativos existentes.

Ao usar as classes de banco de dados MFC DAO, pode haver situações nas quais é necessário usar o DAO diretamente. Normalmente, esse não será o caso, mas o MFC forneceu alguns mecanismos auxiliares para facilitar a simplificação das chamadas diretas de DAO ao combinar o uso das classes MFC com chamadas diretas de DAO. Fazer chamadas diretas de DAO para os métodos de um objeto DAO gerenciado por MFC requer apenas algumas linhas de código. Se precisar criar e usar objetos DAO que não sejam gerenciados pelo MFC, terá um pouco mais de trabalho chamando o objeto Release. Esta nota técnica explica quando você pode querer chamar o DAO diretamente, o que os auxiliares do MFC podem fazer para ajudá-lo e como usar as interfaces OLE do DAO. Por fim, esta nota fornece algumas funções de exemplo mostrando como fazer chamadas de DAO diretamente para recursos de segurança do DAO.

Quando fazer chamadas de DAO diretas

As situações mais comuns para fazer chamadas de DAO diretas ocorrem quando as coleções precisam ser atualizadas ou quando você está implementando recursos não encapsulados pelo MFC. O recurso mais significativo não exposto pelo MFC é a segurança. Se você quiser implementar recursos de segurança, precisará usar diretamente os objetos Usuários e Grupos do DAO. Além da segurança, há apenas alguns outros recursos do DAO sem suporte do MFC. Neles se incluem a clonagem de conjunto de registros e os recursos de replicação de banco de dados, bem como algumas adições tardias ao DAO.

Uma breve visão geral da implementação do DAO e do MFC

O encapsulamento de DAO do MFC facilita o uso do DAO manipulando muitos dos detalhes para que você não precise se preocupar com pequenas coisas. Isso inclui a inicialização do OLE, a criação e o gerenciamento dos objetos DAO (especialmente os objetos de coleção), a verificação de erros e o fornecimento de uma interface fortemente tipada e mais simples (sem VARIANT ou argumentos BSTR). Você pode fazer chamadas de DAO diretas e ainda aproveitar esses recursos. Tudo o que seu código deve fazer é chamar Release para todos os objetos criados por chamadas de DAO diretas e não modificar nenhum dos ponteiros de interface dos quais o MFC possa depender internamente. Por exemplo, não modifique o membro m_pDAORecordset de um objeto aberto CDaoRecordset, a menos que você entenda todas as ramificações internas. No entanto, você pode usar a interface m_pDAORecordset para chamar o DAO diretamente para obter a coleção Fields. Nesse caso, o membro m_pDAORecordset não seria modificado. Você simplesmente precisa chamar Release no objeto de coleção Fields quando terminar de usar o objeto.

Descrição de auxiliares para facilitar chamadas de DAO

Os auxiliares fornecidos para facilitar a chamada de DAO são os mesmos auxiliares que são usados internamente nas classes de Banco de Dados DAO do MFC. Esses auxiliares são usados para verificar os códigos de retorno ao fazer uma chamada de DAO direta, registrar a saída de depuração em log, verificar se há erros esperados e lançar exceções apropriadas, se necessário. Há duas funções auxiliares subjacentes e quatro macros que são mapeadas para um desses dois auxiliares. A melhor explicação seria simplesmente ler o código. Consulte DAO_CHECK, DAO_CHECK_ERROR, DAO_CHECK_MEM e DAO_TRACE no AFXDAO.H para ver as macros e consulte AfxDaoCheck e AfxDaoTrace no DAOCORE.CPP.

Usando as interfaces OLE do DAO

As interfaces OLE para cada objeto na hierarquia de objetos DAO são definidas no arquivo de cabeçalho DBDAOINT.H, que é encontrado no diretório \Arquivos de Programas\Microsoft Visual Studio .NET 2003\VC7\include. Essas interfaces fornecem métodos que permitem manipular toda a hierarquia do DAO.

Para muitos dos métodos nas interfaces DAO, você precisará manipular um objeto BSTR (uma cadeia de caracteres prefixada por comprimento usada na automação OLE). O objeto BSTR normalmente é encapsulado dentro do tipo de dados VARIANT. A própria classe MFC COleVariant herda do tipo de dados VARIANT. Dependendo se você criar seu projeto para ANSI ou Unicode, as interfaces DAO retornarão BSTRs ANSI ou Unicode. Duas macros, V_BSTR e V_BSTRT, são úteis para assegurar que a interface DAO obtenha o BSTR do tipo esperado.

O V_BSTR extrairá o membro bstrVal de um COleVariant. Essa macro normalmente é usada quando você precisa passar o conteúdo de um COleVariant para um método de uma interface DAO. O fragmento de código a seguir mostra as declarações e o uso real para dois métodos da interface DAO que aproveitam a macro 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)));

Observe que o argumento VT_BSTRT especificado no construtor COleVariant acima garante que haverá um BSTR ANSI no COleVariant, caso você crie uma versão ANSI do seu aplicativo, e um BSTR Unicode, para uma versão Unicode do seu aplicativo. Isso é o que o DAO espera.

A outra macro, V_BSTRT, extrairá um membro bstrVal ANSI ou Unicode de COleVariant, dependendo do tipo de build (ANSI ou Unicode). O código a seguir demonstra como extrair o valor BSTR de um COleVariant em um CString:

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

A macro V_BSTRT, juntamente com outras técnicas para abrir outros tipos armazenados em COleVariant, é demonstrada no exemplo DAOVIEW. Especificamente, essa tradução é executada no método CCrack::strVARIANT. Esse método, sempre que possível, converte o valor de um COleVariant em uma instância de CString.

Exemplo simples de uma chamada direta de DAO

Situações podem surgir quando for necessário atualizar os objetos de coleção DAO subjacentes. Normalmente isso não é necessário, mas caso se torne, é um procedimento simples. Um exemplo de quando uma coleção pode precisar ser atualizada é ao operar em um ambiente multiusuário com vários usuários criando novos tabledefs. Nesse caso, sua coleção de tabledefs pode ficar obsoleta. Para atualizar a coleção, basta chamar o método Refresh do objeto de coleção específico e verificar se há erros:

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

Observe que atualmente todas as interfaces de objeto da coleção DAO são detalhes de implementação não documentados das classes de banco de dados MFC DAO.

Usar o DAO diretamente para recursos de segurança do DAO

As classes de banco de dados MFC DAO não encapsulam os recursos de segurança do DAO. Você deve chamar métodos de interfaces DAO para usar alguns recursos de segurança do DAO. A função a seguir define o banco de dados do sistema e, em seguida, altera a senha do usuário. Essa função chama três outras funções, que são definidas posteriormente.

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);

    // ...
}

Os próximos quatro exemplos demonstram como:

  • Definir o banco de dados DAO do sistema (arquivo .MDW).

  • Definir o usuário e a senha padrão.

  • Alterar a senha de um usuário.

  • Alterar a senha de um arquivo .MDB.

Configurar o Banco de Dados do Sistema

Abaixo está uma função de exemplo para definir o banco de dados do sistema que será usado por um aplicativo. Essa função deve ser chamada antes que outras chamadas de DAO sejam feitas.

// 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));
}

Definir o usuário e a senha padrão

Para definir o usuário e a senha padrão para um banco de dados do sistema, use a seguinte função:

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));
}

Alterar a senha de um usuário

Para alterar a senha de um usuário, use a seguinte função:

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();
}

Alterar a senha de um arquivo .MDB

Para alterar a senha de um arquivo .MDB, use a seguinte função:

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();
}

Confira também

Observações técnicas por número
Observações técnicas por categoria