不使用 DAO 压缩 Microsoft Access 数据库
Compacting Microsoft Access Database without using DAO
我用CDatabase
class打开了一个ACCDB
Access数据库。 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);
}
}
我用CDatabase
class打开了一个ACCDB
Access数据库。 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);
}
}