テクニカル ノート 54: MFC DAO クラス使用中の DAO の直接呼び出し
注意
Visual C++ .NET では、Visual C++ 開発環境およびウィザードでは DAO はサポートされなくなりました (DAO クラスは含まれているので、このクラスを使うことはできます)。 新規プロジェクトの作成には、OLE DB テンプレートまたは ODBC および MFC の使用をお勧めします。 DAO は、既存のアプリケーションを保守するためだけに使用してください。
MFC (Microsoft Foundation Class) の 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 に追加された 2、3 の機能があります。
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 つの下層ヘルパー関数とこれらのヘルパーのいずれかに割り当てる 4 つのマクロがあります。 コードを読んで理解することをお勧めします。 マクロについては、AFXDAO.H の DAO_CHECK、DAO_CHECK_ERROR、DAO_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 インターフェイス内の多くのメソッドを使用するには、OLE オートメーションで使用される固定長の文字列を表す BSTR オブジェクトを使用します。 BSTR オブジェクトは、通常は、データ型 VARIANT にカプセル化されています。 MFC クラスの COleVariant は、データ型 VARIANT を継承しています。 構築するプロジェクトが ANSI と Unicode のどちらを使用するかによって、DAO インターフェイスは ANSI または Unicode の BSTR を返します。 V_BSTR と V_BSTRT の 2 つのマクロを使用すると、DAO インターフェイスは目的のタイプの BSTR を確実に受け取ることができます。
V_BSTR マクロは、COleVariant の bstrVal メンバーを抽出します。 通常このマクロは、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 バージョンとしてビルドした場合は ANSI の BSTR が COleVariant に、Unicode バージョンとしてビルドした場合は Unicode の BSTR が COleVariant に渡されます。 これは DAO で予想される動作です。
もう一方のマクロ V_BSTRT は、アプリケーションが ANSI と Unicode のいずれのバージョンにビルドされたかに応じて、COleVariant の bstrVal メンバーを ANSI または Unicode で抽出します。 COleVariant の BSTR 値を CString に抽出する方法の例を次に示します。
COleVariant varName( _T( "MyName" ), VT_BSTRT );
CString str = V_BSTRT( &varName );
V_BSTRT マクロ、および COleVariant に格納されているデータ型を抽出するその他の手法については、Visual C++ の配布 CD に収録されているサンプル DAOVIEW を参照してください。 ここで説明したような変換の例は、CCrack::strVARIANT メソッドに示されています。 CCrack::strVARIANT メソッドは、COleVariant の値から CString のインスタンスへの変換を可能な限り行います。
DAO の直接呼び出しの簡単な例
下層の DAO コレクション オブジェクトの書き直しが必要となることがあります。 通常はその必要はありませんが、手順は簡単です。 コレクションを書き直す状況の例としては、マルチユーザー環境で複数のユーザーがテーブル定義を新規作成する場合が考えられます。 この場合、アプリケーションのテーブル定義コレクションが無効になる可能性があります。 コレクションを書き直すには、そのコレクション オブジェクトの 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 affect.
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->get_Count( &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();
}