共用方式為


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 物件方法時,只需要幾行程式代碼。 如果您需要建立和使用 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 呼叫,但仍會利用這些功能。 您所有的程式碼必須呼叫 Release ,以處理直接 DAO 呼叫所創建的任何物件,且不可修改 MFC 可能在內部依賴的任何介面指標。 例如,除非您瞭解所有內部影響,否則請勿修改開啟CDaoRecordset物件的m_pDAORecordset成員。 不過,您可以使用 m_pDAORecordset 介面直接呼叫 DAO 來取得 Fields 集合。 在此情況下,不會修改 m_pDAORecordset 成員。 當您完成 物件時,只需要在 Fields 集合物件上呼叫 Release

協助工具的描述,以促進 DAO 呼叫的便利性

為了讓呼叫 DAO 更容易提供的協助程式,與 MFC DAO 資料庫類別內部所使用的協助程式相同。 這些輔助工具用於檢查執行直接 DAO 呼叫時的傳回碼、記錄偵錯輸出、確認預期的錯誤,並在必要時拋出適當的例外狀況。 有兩個底層輔助函式和四個宏,分別映射到這兩個底層輔助函式之一。 最好的說明是只閱讀程序代碼。 請參閱 AFXDAO.H 中的 DAO_CHECKDAO_CHECK_ERRORDAO_CHECK_MEMDAO_TRACE 巨集,另外在 DAOCORE.CPP 中查看 AfxDaoCheckAfxDaoTrace

使用 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 會擷取 COleVariant 成員。 當您需要將 COleVariant 的內容傳遞至 DAO 介面的某個方法時,通常會使用此巨集。 下列程式碼片段顯示了兩個使用 V_BSTR 巨集的 DAO DAOUser 介面方法的宣告和實際用法。

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在上述建構函式中指定的COleVariant參數可確保:如果您建置應用程式的 ANSI 版本,中將會有 ANSI BSTRCOleVariant;而如果您建置應用程式的 Unicode 版本,則將會有 Unicode BSTR。 這是 DAO 預期的結果。

另一個巨集 V_BSTRT 會根據建置的類型(ANSI 或 Unicode)來擷取 bstrVal 成員的 Unicode 或 ANSI 型態。 下列程式代碼示範如何將BSTR值從COleVariant擷取到CString中:

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

V_BSTRT 巨集及其他用於開啟儲存在 COleVariant 中不同類型的技術都會在 DAOVIEW 範例中進行示範。 具體而言,這個翻譯是以 CCrack::strVARIANT 方法執行。 如果可能,這個方法會將 COleVariant 的值轉換為 CString 的實例。

直接呼叫 DAO 的簡單範例

可能會發生需要重新整理基礎 DAO 集合物件的情況。 通常,這不應該是必要的,但如果有必要,這是一個簡單的程式。 在多用戶環境中進行操作時,假如有多位使用者同時建立新的 tabledefs,這可能是需要重新整理集合的情況。 在此情況下,您的 tabledefs 集合可能會過時。 若要重新整理集合,您只需呼叫 Refresh 特定集合物件的 方法並檢查錯誤:

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

請注意,目前所有的 DAO 集合物件介面都是 MFC 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();
}

另請參閱

依編號的技術注意事項
依類別排序的技術注意事項