テクニカル ノート 54: MFC DAO クラス使用中の DAO の直接呼び出し

Note

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 のユーザーおよびグループ オブジェクトを直接使用する必要があります。 セキュリティ以外で、MFC でサポートされていない DAO の他の機能はごく少数です。 これには、レコードセットの複製機能、データベース レプリケーション機能、および DAO へのいくつかの遅延追加が含まれます。

DAO と MFC の実装の概要

MFC で DAO をラップして細部の多くを処理することで DAO を簡単に使用できるようになるため、細かいことを心配する必要がなくなります。 これには、OLE の初期化、DAO オブジェクト (特にコレクション オブジェクト) の作成と管理、エラー チェック、厳密に型指定された (VARIANT または BSTR 引数のない) より単純なインターフェイスの提供などが含まれます。 DAO の直接呼び出しを行うことができる一方で、これらの機能を引き続き利用できます。 コードで必要なことは、DAO の直接呼び出しによって作成されたオブジェクトに対して Release を呼び出すこと、および MFC が内部で依存する可能性のあるいずれのインターフェイス ポインターも変更 "しない" ことです。 たとえば、内部的な影響を "すべて" 理解していない限り、開かれている CDaoRecordset オブジェクトの m_pDAORecordset メンバーを変更してはいけません。 ただし、m_pDAORecordset インターフェイスを使用して DAO を直接呼び出して、Fields コレクションを取得することはできます。 この場合、m_pDAORecordset メンバーは変更されません。 オブジェクトの操作が完了したら、Fields コレクション オブジェクトに対して Release を呼び出すだけです。

DAO 呼び出しをより容易にするヘルパーの説明

DAO 呼び出しをより容易にするために用意されているヘルパーは、MFC DAO データベース クラスで内部的に使用されるヘルパーと同じです。 これらのヘルパーは、DAO の直接呼び出しを行うとき、デバッグ出力をログに記録するとき、予想されるエラーの有無を調べるとき、および必要に応じて適切な例外をスローするときに、リターン コードを確認するために使用されます。 2 つの基になるヘルパー関数と、これら 2 つのヘルパーのいずれかにマップされる 4 つのマクロがあります。 詳しい知りたい場合は、コードをよく読んでください。 マクロを確認するには、AFXDAO.H の DAO_CHECKDAO_CHECK_ERRORDAO_CHECK_MEM、および DAO_TRACE を参照してください。また、DAOCORE.CPP の AfxDaoCheck および AfxDaoTrace を参照してください。

DAO OLE インターフェイスの使用

DAO オブジェクト階層内の各オブジェクトの OLE インターフェイスは、\Program Files\Microsoft Visual Studio .NET 2003\VC7\include ディレクトリにあるヘッダー ファイル DBDAOINT.H で定義されています。 これらのインターフェイスには、DAO 階層全体を操作できるメソッドが用意されています。

DAO インターフェイスの多くのメソッドでは、BSTR オブジェクト (OLE オートメーションで使用される長さのプレフィックスが付いた文字列) を操作する必要があります。 BSTRオブジェクトは、通常、VARIANT データ型内にカプセル化されます。 MFC クラス COleVariant 自体は、VARIANT データ型から継承されます。 プロジェクトを ANSI と Unicode のどちらを対象にビルドするかに応じて、DAO インターフェイスから ANSI または Unicode で BSTR が返されます。 V_BSTR と V_BSTRT の 2 つのマクロは、必要な型の BSTR を DAO インターフェイスが確実に取得できるようにするために役立ちます。

V_BSTR では、COleVariantbstrVal メンバーが抽出されます。 このマクロは、通常、COleVariant の内容を DAO インターフェイスのメソッドに渡す必要がある場合に使用します。 次のコード フラグメントは、V_BSTR マクロを利用する DAO DAOUser インターフェイスの 2 つのメソッドの宣言と実際の使用法の両方を示しています。

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

前述の COleVariant コンストラクターに指定された VT_BSTRT 引数により、アプリケーションの ANSI バージョンをビルドする場合は COleVariant に ANSI BSTR が含まれ、Unicode バージョンをビルドする場合は Unicode BSTR が含まれることが保証されることに注意してください。 これは、DAO から期待されていることです。

もう 1 つのマクロである V_BSTRT を使用すると、ビルドの種類 (ANSI または Unicode) に応じて、COleVariant の ANSI または Unicode bstrVal メンバーを抽出できます。 次のコードは、BSTR 値を COleVariant から CString に抽出する方法を示しています。

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

V_BSTRT マクロは、COleVariant に保存されている他の型を開くための他の手法と共に、DAOVIEW サンプルに示されています。 具体的には、この変換は CCrack::strVARIANT メソッドで実行されます。 このメソッドでは、可能であれば、COleVariant の値を CString のインスタンスに変換します。

DAO の直接呼び出しの簡単な例

場合によっては、基になる DAO コレクション オブジェクトを更新することが必要になる状況が発生することがあります。 通常ではこの操作は必要ありませんが、必要になった場合でもその手順は簡単です。 コレクションを更新する必要がある状況の例として、マルチユーザー環境で作業していて複数のユーザーが新しい tabledef を作成する場合が挙げられます。 この場合、自分の tabledef コレクションが古くなる可能性があります。 コレクションを更新するのに必要な作業は、特定のコレクション オブジェクトの Refresh メソッドを呼び出し、エラーの有無を確認するだけです。

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

現時点で、すべての DAO コレクション オブジェクト インターフェイスは、MFC DAO データベース クラスのドキュメント化されていない実装の詳細であることに注意してください。

DAO セキュリティ機能のための DAO の直接使用

MFC DAO データベース クラスでは、DAO セキュリティ機能をラップしません。 いくつかの DAO セキュリティ機能を使用するには、DAO インターフェイスのメソッドを呼び出す必要があります。 次の関数では、システム データベースを設定した後、ユーザーのパスワードを変更します。 この関数は、この後で定義する他の 3 つの関数を呼び出します。

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

    // ...
}

次の 4 つの例では、次の方法を示します。

  • システム 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();
}

関連項目

番号順テクニカル ノート
カテゴリ別テクニカル ノート