C# WinForm打开Access关闭窗体不退出Access及兼容问题咨询
问题描述
我正在使用如下代码打开MS Access数据库:
public partial class Start_Baseet : System.Windows.Forms.Form { string MyFile = Environment.CurrentDirectory + "\\Baseet.accde"; Microsoft.Office.Interop.Access.Application AccApp = new Microsoft.Office.Interop.Access.Application(); public Start_Baseet() { InitializeComponent(); } public void OpenDb() { AccApp.Visible = true; AccApp.OpenCurrentDatabase(MyFile, false, "017014a"); AccApp.RunCommand(AcCommand.acCmdAppMaximize); } private void Start_Basset_Load(object sender, EventArgs e) { try { OpenDb(); } catch { AccApp.Quit(); MessageBox.Show("Missing Files", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); } finally { this.Close(); } } }
上述代码可正常运行,但当finally块执行this.Close()关闭窗体时,已打开的Access数据库会同步关闭。需要实现关闭WinForm窗体时不关闭已启动的Access应用。
已尝试的无效修改
我尝试使用如下逻辑修改程序启动代码,但问题仍然存在:
static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //Application.Run(new Start_Baseet()); Start_Baseet frm = new Start_Baseet(); frm.Show(); }
附加异常
两台设备运行表现不一致:
- 开发设备安装32位Office 2016,调试或运行发布版本程序时,Access程序可正常启动,但
Baseet.accde数据库无法打开 - 另一台设备安装64位Office 2016,运行发布的程序可正常工作
解决方案
关闭WinForm时Access同步退出问题
根因
AccApp作为Access COM对象被声明为窗体类的实例成员,窗体关闭后实例被垃圾回收,COM对象引用计数归零,关联的Access进程会自动退出。- 修改
Main方法时直接调用frm.Show()没有启动Windows窗体消息循环,窗体显示后主线程会立刻执行完所有代码退出,整个应用进程终止,自然会关闭启动的Access进程。
修复方法
核心思路是解除WinForm进程对Access COM对象的引用绑定,让Access作为独立进程运行,不需要依赖窗体持有对象。
- 引入命名空间:
using System.Runtime.InteropServices; - 不要把Access COM对象放在窗体类中持有,将启动Access、打开数据库的逻辑放到主程序入口,操作完成后主动释放COM引用,再退出WinForm进程即可。参考代码如下:
[STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Microsoft.Office.Interop.Access.Application accApp = null; string dbPath = Path.Combine(Application.StartupPath, "Baseet.accde"); try { accApp = new Microsoft.Office.Interop.Access.Application(); accApp.Visible = true; accApp.OpenCurrentDatabase(dbPath, false, "017014a"); accApp.RunCommand(AcCommand.acCmdAppMaximize); // 释放当前进程对COM对象的持有,Access转为独立进程运行 Marshal.ReleaseComObject(accApp); accApp = null; } catch { if (accApp != null) { accApp.Quit(); Marshal.ReleaseComObject(accApp); } MessageBox.Show("Missing Files", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); return; } // 所有操作完成后直接退出当前WinForm程序,不影响已启动的Access Application.Exit(); }
如果需要保留启动窗体逻辑,只需在调用this.Close()前,调用Marshal.ReleaseComObject(AccApp)并将AccApp置为null,确保窗体不再持有COM对象的引用即可。
32位Office设备无法打开数据库问题
根因
这是进程架构与COM组件架构不匹配导致的:
- 若项目编译时平台目标设置为
x64,生成的程序为64位进程,64位进程无法调用32位Office提供的32位COM Interop接口,因此只能启动Access进程,无法执行打开数据库的调用;64位Office设备上进程与COM架构匹配,可正常运行。 - 若
Baseet.accde是用64位Access编译生成的,本身不兼容32位Access环境,也会导致32位设备打开失败。
修复方法
- 右键项目进入「属性-生成」页面,将平台目标设置为
x86,重新编译后即可在32位Office的开发机上正常运行。32位程序可通过WOW64层在64位系统上运行,但无法调用64位COM组件,因此如果要同时适配32位、64位Office环境,需要分别编译x86、x64两个版本的程序分发给对应设备。 - 检查
Baseet.accde文件的编译环境,若需要跨架构运行,可先将数据库保存为accdb格式测试兼容性,或分别在对应架构的Access中生成对应版本的accde文件。
内容的提问来源于stack exchange,提问作者Csharp Newbie
相关产品推荐
相关产品推荐

