不使用 DAO 压缩 Microsoft Access 数据库

Compacting Microsoft Access Database without using DAO

我用CDatabaseclass打开了一个ACCDBA​​ccess数据库。 driver 是:_T("Microsoft Access Driver (*.mdb, *.accdb)").

我可以打开和使用数据库 OK(已经这样做了很多年):

if (DatabaseExist(m_strMDBPath))
{
    // AJT v10.5.0 Take into account the DB mode
    strDriver = GetJETDriverEx(bAccDbMode);

    // AJT v10.5.0 Take into account the DB password (decrypted!)
    strDBConnectString.Format(_T("Driver={%s};DBQ=%s;Pwd=%s"),
        (LPCTSTR)strDriver, (LPCTSTR)m_strMDBPath,
        (LPCTSTR)m_toolsMSA.DecryptDatabasePassword(strPassword));

    try
    {
        //OutputDebugString(L"DB Open - Begin\n");
        if (m_Database.OpenEx(strDBConnectString, CDatabase::noOdbcDialog))
        {
            //OutputDebugString(L"DB Open - End\n");
        }
    }
    catch (CDBException* e)
    {
        // If a database exception occurred, show error msg
        AfxMessageBox(L"Database error: " + e->m_strError);
    }
}

我在以编程方式压缩数据库时遇到问题。以前我使用的是 DAO:

Microsoft.Office.Interop.Access.Dao

但这需要安装 Access 2013 Runtime。我不想再安装它了,因为我的电脑上安装了 Access 2016。

执行压缩的代码使用了 DBEngine 命令:

Microsoft.Office.Interop.Access.Dao.DBEngine objDbEngine = new Microsoft.Office.Interop.Access.Dao.DBEngine();

但是现在我需要一种新的方法来压缩数据库,因为我不再有 DAO 引用。最终用户可能没有安装 Access 2016,但我会告诉他们安装 Access 2016 运行时。

我可以使用什么替代方法以编程方式在我的 MFC 项目中压缩此 ACCDB?


请注意,我有一个底层 C# .Net DLL 工具,因此如果它比 C++ 更容易,我可以将任何此类压缩添加到该 C# 库中。


这就是我之前使用需要 2013 运行时的 DAO 的方式:


我试过这个:

#pragma once
#import "C:\Program Files\Microsoft Office\root\Office16\ACEDAO.DLL" named_guids rename("EOF", "ACEDAO_EOF")  


static void Test(CString strDB, CString strDbCompacted)
{
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    DAO::_DBEngine* pDBEngine = NULL;
    HRESULT hr = CoCreateInstance(__uuidof(DAO::DBEngine), NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (LPVOID*)&pDBEngine);
    if (SUCCEEDED(hr) && pDBEngine)
    {
        _bstr_t bstrDatabase = strDB.AllocSysString();
        _bstr_t bstrDatabaseCompacted = strDbCompacted.AllocSysString();
        try
        {
            pDBEngine->CompactDatabase(bstrDatabase, bstrDatabaseCompacted, L";pwd=xxx");
        }
        catch (_com_error& e)
        {
            _bstr_t bstrSource(e.Source());
            _bstr_t bstrDescription(e.Description());
            WCHAR wsBuffer[255];
            wsprintf(wsBuffer, L"Source : %s\nDescription : %s", (LPCTSTR)bstrSource, (LPCTSTR)bstrDescription);
            MessageBox(NULL, wsBuffer, L"Error", MB_OK | MB_ICONSTOP);
        }
        pDBEngine->Release();
    }
}

但它失败了,甚至没有到达 catch 处理程序。

我只是在寻找一种简单的方法来支持压缩,更改 MDB 和 ACCDB 的密码...我什至尝试添加 acedao.dll 作为对 C# 控制台项目的引用,但它不会接受它。


我尝试使用评论中提到的后期绑定。这是函数:

public void CompactAccessDatabase(string strSourceDB, string strTargetDB, string strPassword)
{
    try
    {
        dynamic dbEngine = Activator.CreateInstance(Type.GetTypeFromProgID("DAO.DbEngine"));

        string strDecryptedPassword = "";
        if(!string.IsNullOrEmpty(strPassword))
        {
            if (!DecryptDatabasePassword(strPassword, ref strDecryptedPassword))
            {
                SimpleLog.Log("DecryptDatabasePassword returned false");
            }
            strDecryptedPassword = "pwd=" + strDecryptedPassword;
        }
        dbEngine.CompactDatabase(strSourceDB, strTargetDB, null, null, strDecryptedPassword);
    }
    catch (Exception ex)
    {
        SimpleLog.Log(ex);
    }
}

但我遇到了一个例外:

<LogEntry Date="2022-05-26 13:06:49" Severity="Exception" Source="MSAToolsLibrary.MSAToolsLibraryClass.CompactAccessDatabase" ThreadId="1">
  <Exception Type="System.ArgumentNullException" Source="System.Activator.CreateInstance">
    <Message>Value cannot be null.
Parameter name: type</Message>
    <StackTrace>   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at System.Activator.CreateInstance(Type type)
   at MSAToolsLibrary.MSAToolsLibraryClass.CompactAccessDatabase(String strSourceDB, String strTargetDB, String strPassword) in D:\My Programs22\MSAToolsLibrary\MSAToolsLibrary\MSAToolsLibraryClass.cs:line 1649</StackTrace>
  </Exception>
</LogEntry>

根据评论和链接答案中提到的原则,我最终能够为我的 64 位构建提供此代码:

public void CompactAccessDatabase(string strSourceDB, string strTargetDB, string strPassword)
{
    try
    {
        dynamic dbEngine = Activator.CreateInstance(Type.GetTypeFromProgID("DAO.DBEngine.120"));

        string strDecryptedPassword = "";
        string strDBConnectionString = "";
        if(!string.IsNullOrEmpty(strPassword))
        {
            if (!DecryptDatabasePassword(strPassword, ref strDecryptedPassword))
            {
                SimpleLog.Log("DecryptDatabasePassword returned false");
            }
            strDBConnectionString = ";pwd=" + strDecryptedPassword;
        }
        dbEngine.CompactDatabase(strSourceDB, strTargetDB, null, null, strDBConnectionString);
    }
    catch (Exception ex)
    {
        SimpleLog.Log(ex);
    }
}