TN054: Llamar a DAO directamente mientras se usan clases DAO de MFC

Nota:

DAO se usa con bases de datos de Access y es compatible con Office 2013. DAO 3.6 es la versión final y se considera obsoleta. El entorno y los asistentes de Visual C++ no admiten DAO (aunque se incluyen las clases DAO y todavía se pueden usar). Microsoft recomienda usar plantillas OLE DB o bien ODBC y MFC para proyectos nuevos. Solo debe usar DAO para mantener las aplicaciones existentes.

Al usar las clases de base de datos DAO de MFC, puede haber situaciones en las que sea necesario usar DAO directamente. Normalmente, esto no sucederá, pero MFC ha proporcionado algunos mecanismos auxiliares para facilitar la realización de llamadas DAO directas sencillas al combinar el uso de las clases MFC con llamadas DAO directas. Realizar llamadas DAO directas a los métodos de un objeto DAO administrado por MFC solo debe requerir unas pocas líneas de código. Si necesita crear y usar objetos DAO que no están administrados por MFC, tendrá que realizar un poco más de trabajo llamando Release realmente al objeto. En esta nota técnica se explica cuándo es posible que quiera llamar directamente a DAO, qué pueden hacer los asistentes de MFC para ayudarle y cómo usar las interfaces OLE de DAO. Por último, esta nota proporciona algunas funciones de ejemplo que muestran cómo llamar a DAO directamente para las características de seguridad de DAO.

Cuándo realizar llamadas DAO directas

Las situaciones más comunes para realizar llamadas DAO directas se producen cuando es necesario actualizar las colecciones o cuando se implementan características no ajustadas por MFC. La característica más importante que no expone MFC es la seguridad. Si desea implementar características de seguridad, deberá usar directamente los objetos de usuario y grupos de DAO. Además de la seguridad, solo hay algunas otras características de DAO no compatibles con MFC. Entre ellas se incluyen las características de clonación de conjuntos de registros y replicación de bases de datos, así como algunas adiciones tardías a DAO.

Una breve introducción a la implementación de DAO y MFC

El ajuste de DAO de MFC facilita el uso de DAO mediante el control de muchos de los detalles para que no tenga que preocuparse por las pequeñas cosas. Esto incluye la inicialización de OLE, la creación y administración de los objetos DAO (especialmente los objetos de colección), la comprobación de errores y la provisión de una interfaz fuertemente tipada y sencilla (sin VARIANT o argumentos BSTR). Puede realizar llamadas DAO directas y seguir aprovechando estas características. Todo el código debe hacer es llamar a Release para cualquier objeto creado por llamadas DAO directas y no modificar ninguno de los punteros de interfaz en los que MFC puede depender internamente. Por ejemplo, no modifique el m_pDAORecordset miembro de un objeto CDaoRecordset abierto a menos que comprenda todas las ramificaciones internas. Sin embargo, puede usar la interfaz m_pDAORecordset para llamar a DAO directamente para obtener la colección Fields. En este caso, el miembro m_pDAORecordset no se modificaría. Solo tiene que llamar Release al objeto de colección Fields cuando haya terminado con el objeto.

Descripción de los asistentes para facilitar las llamadas DAO

Los asistentes proporcionados para facilitar las llamadas DAO son los mismos asistentes que se usan internamente en las clases de base de datos DAO de MFC. Estos asistentes se usan para comprobar los códigos de retorno al realizar una llamada DAO directa, registrar la salida de depuración, comprobar si hay errores esperados y producir excepciones adecuadas si es necesario. Hay dos funciones auxiliares subyacentes y cuatro macros que se asignan a uno de estos dos asistentes. La mejor explicación sería simplemente leer el código. Ver DAO_CHECK, DAO_CHECK_ERROR, DAO_CHECK_MEM y DAO_TRACE en AFXDAO.H para ver las macros, y AfxDaoCheck y AfxDaoTrace en DAOCORE.CPP.

Uso de las interfaces OLE de DAO

Las interfaces OLE de cada objeto de la jerarquía de objetos DAO se definen en el archivo de encabezado DBDAOINT.H, que se encuentra en el directorio \Program Files\Microsoft Visual Studio .NET 2003\VC7\include. Estas interfaces proporcionan métodos que permiten manipular toda la jerarquía de DAO.

Para muchos de los métodos de las interfaces DAO, deberá manipular un objeto BSTR (una cadena con prefijo de longitud usada en la automatización OLE). Normalmente, el objeto BSTR se encapsula dentro del tipo de datos VARIANT. La propia clase MFC COleVariant hereda del tipo de datos VARIANT. En función de si compila el proyecto para ANSI o Unicode, las interfaces DAO devolverán BSTR ANSI o Unicode. Dos macros, V_BSTR y V_BSTRT, son útiles para garantizar que la interfaz DAO obtiene el BSTR del tipo esperado.

V_BSTR extraerá el miembro bstrVal de COleVariant. Esta macro se usa normalmente cuando es necesario pasar el contenido de COleVariant a un método de una interfaz DAO. En el fragmento de código siguiente se muestran las declaraciones y el uso real para dos métodos de la interfaz DAOUser de DAO que aprovechan las ventajas de la 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)));

Tenga en cuenta que el argumento VT_BSTRT especificado en el constructor COleVariant anterior garantiza que habrá un ANSI BSTR en COleVariant si compila una versión ANSI de la aplicación y un Unicode BSTR para una versión Unicode de la aplicación. Esto es lo que DAO espera.

La otra macro, V_BSTRT, extraerá un miembro ANSI o Unicode bstrVal de COleVariant según el tipo de compilación (ANSI o Unicode). En el código siguiente se muestra cómo extraer el valor BSTR de COleVariant en CString:

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

La macro V_BSTRT, junto con otras técnicas para abrir otros tipos almacenados en COleVariant, se muestra en el ejemplo DAOVIEW. En concreto, esta traducción se realiza en el método CCrack::strVARIANT. Este método, siempre que sea posible, traduce el valor de COleVariant en una instancia de CString.

Ejemplo sencillo de una llamada directa a DAO

Pueden surgir situaciones cuando es necesario actualizar los objetos de colección DAO subyacentes. Normalmente, esto no debe ser necesario, pero es un procedimiento sencillo si es necesario. Un ejemplo de cuándo es posible que sea necesario actualizar una colección es cuando se trabaja en un entorno multiusuario con varios usuarios que crean nuevas tabledefs. En este caso, la colección tabledefs podría quedar obsoleta. Para actualizar la colección, basta con llamar al método Refresh del objeto de colección determinado y comprobar si hay errores:

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

Tenga en cuenta que actualmente todas las interfaces de objetos de colección DAO son detalles de implementación no documentados de las clases de base de datos DAO de MFC.

Uso de DAO directamente para las características de seguridad de DAO

Las clases de base de datos DAO de MFC no encapsulan las características de seguridad de DAO. Debe llamar a métodos de interfaces DAO para usar algunas características de seguridad de DAO. La siguiente función establece la base de datos del sistema y, a continuación, cambia la contraseña del usuario. Esta función llama a otras tres funciones, que se definen 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);

    // ...
}

En los cuatro ejemplos siguientes se muestra lo siguiente:

  • Cómo establecer la base de datos DAO del sistema (archivo .MDW)

  • Cómo establecer el usuario y la contraseña predeterminados

  • Cómo cambiar la contraseña de un usuario

  • Cómo cambiar la contraseña de un archivo .MDB

Cómo establecer la base de datos del sistema

A continuación se muestra una función de ejemplo para establecer la base de datos del sistema que usará una aplicación. Se debe llamar a esta función antes de que se realicen otras llamadas 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));
}

Cómo establecer el usuario y la contraseña predeterminados

Para establecer el usuario y la contraseña predeterminados para una base de datos del sistema, use la siguiente función:

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

Cambiar la contraseña de un usuario

Para cambiar la contraseña de un usuario, use la siguiente función:

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

Cambiar la contraseña de un archivo .MDB

Para cambiar la contraseña de un archivo .MDB, use la siguiente función:

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

Consulte también

Notas técnicas por número
Notas técnicas por categoría