简介:这是一份适用于Windows开发环境的ADO组件集合,集中提供msado15.dll的32位(X86)与64位(X64)各版本文件。对于需要基于VC++、VB、Delphi等工具开发数据库应用程序的开发者,或经常遭遇“未找到msado15.dll”类错误的运维人员来说,可按目标系统架构直接选用,避免因组件缺失或位数不匹配导致的运行异常。压缩包共194个文件,包含96个DLL、96个TXT说明文档、1个DLL工具EXE和1个DLL之家HTM,整套资源约33.7MB。其中DLL按不同ADO版本与平台分类,TXT记录对应文件的技术说明,EXE可用于修复/注册/卸载DLL,HTM提供查询帮助。已有2475人学习下载。资源可同时覆盖从Windows XP/Server 2003到Windows 7/Server 2008 R2及更高版本的环境需求,开发者既能获取对应位数的ADO核心库,也能借助工具与文档快速定位版本冲突、缺失引用等问题,适合在数据库项目开发、部署排错时做备用组件库。
1. msado15.dll 为什么成了老项目的拦路虎:系统里明明有,程序却说找不到
客户现场最常见的翻车现场是这样的:一台 64 位 Win10 机器上装了个老 VB6 编译的程序,一打开就弹“未找到提供程序”0x80004005,你打开 System32 目录,msado15.dll 就在那儿躺着,注册表 HKEY_CLASSES_ROOT\CLSID 下面也有 InprocServer32,但程序就是连不上 Access。原因基本都出在位数上——msado15.dll 是 ADO(ActiveX Data Objects)的核心组件,32 位和 64 位系统各有独立版本,把 32 位 DLL 塞进 64 位进程里加载,COM 机制根本不理你。这份资源把 32 位和 64 位的 msado15.dll 都备齐了,适合做老项目迁移、远程运维补环境、或者二次开发需要分发运行时的人。下面从原理到部署、再到排查,按我实际处理的顺序过一遍。
2. 先搞懂 ADO 的位数隔离:WOW64 重定向与两份同名文件
2.1 WOW64 重定向:为什么同名的 DLL 有两份
64 位 Windows 为了让 32 位程序能跑起来,做了一层 WOW64 兼容层。32 位程序访问 C:\Windows\System32 时,文件系统重定向器会透明地指到 C:\Windows\SysWOW64;读写 HKLM\Software 时,会被重定向到 HKLM\Software\WOW6432Node。也就是说,32 位进程眼里看到的系统目录和注册表,跟 64 位进程看到的不是同一个位置。
这就带来一个结果:msado15.dll 在 System32 和 SysWOW64 里各有一份,正常情况下系统自带,你不用管。问题出在两种常见操作上:一是拿 64 位的 msado15.dll 覆盖到 SysWOW64,二是用第三方“修复工具”把 32 位文件搬到了 System32。覆盖法在本机可能暂时能跑,换一台机器、或者程序稍后调用 ADO 的高级接口(比如 RDS、流对象)时,就会出位数字节错位的问题。
注册表那部分更绕。HKEY_CLASSES_ROOT 本身不重定向,但 HKCR 是 HKLM\Software 和 HKCU\Software 的合并视图,所以 HKCR\CLSID 下的 InprocServer32 在 32 位程序眼里,实际读的是 WOW6432Node 里的项。这个特性后面排查会反复用到,先把对应关系记清楚:
| 查看入口 | 64 位进程看到的 | 32 位进程看到的 |
|---|---|---|
| System32 目录 | 真实的 64 位 msado15.dll | 被重定向到 SysWOW64 |
| SysWOW64 目录 | 不可见(除非显式写路径) | 真实的 32 位 msado15.dll |
| HKLM\Software\Classes\CLSID | 64 位 COM 注册项 | WOW6432Node 映射后的项 |
| HKCR\CLSID...\InprocServer32 | 64 位键值 | 合并视图中 WOW6432Node 的值 |
这段关系是后面所有排查的地基。你看到“注册表里有、程序读不到”的诡异现象,十有八九是视角错了——你用 64 位的 regedit 看注册表,看到的键和 32 位程序读到的根本不是同一个键。
2.2 检查本机 msado15.dll 的位数与版本
拿到一台出问题的机器,我一般先不开程序,直接确认文件实体。先看两个路径下的文件:
dir C:\Windows\System32\msado15.dll dir C:\Windows\SysWOW64\msado15.dllSystem32 下的是给 64 位进程用的,SysWOW64 下的是给 32 位进程用的。正常机器的文件大小和版本号会有差异,如果两者完全一致,就值得怀疑是谁手动覆盖过文件。用 PowerShell 看文件版本更直观:
(Get-Item C:\Windows\System32\msado15.dll).VersionInfo | Format-List FileVersion, FileSize (Get-Item C:\Windows\SysWOW64\msado15.dll).VersionInfo | Format-List FileVersion, FileSizeFileVersion 会显示类似 6.1.7600.16385(Win7 自带)或 6.2.9200.16384(Win8 以上)的字符串。系统自带的 msado15.dll 版本从 Win7 到 Win11 基本停留在 ADO 2.8 的版本号区间,不会跟着 Windows 大版本升级,所以你判断的关键是位数而不是版本号大小。如果两个目录版本相同,八成是有人在 SysWOW64 里放了 64 位文件,或者反过来。
再看注册表里的 COM 注册指向。64 位视角下:
reg query "HKLM\SOFTWARE\Classes\CLSID\{00000514-0000-0010-8000-00AA006D2EA4}\InprocServer32" reg query "HKLM\SOFTWARE\WOW6432Node\Classes\CLSID\{00000514-0000-0010-8000-00AA006D2EA4}\InprocServer32"前一条查 64 位 ADODB.Connection 类,后一条查 32 位的。注意看返回的默认值指向哪个目录:64 位要指向 System32,32 位要指向 SysWOW64。这个 CLSID 是 ADODB.Connection 的标准类标识,如果查不到默认值,说明 COM 注册坏了;如果指向的路径写错了,说明注册时用了错误位数的 regsvr32。
2.3 Jet 与 ACE:和位数强绑定的另一个变量
msado15.dll 本身只是 ADO 运行时,真正连数据库还要靠 OLE DB Provider。这里最容易踩坑的是两个 Provider 的位数限制。
Microsoft.Jet.OLEDB.4.0 只有 32 位编译版。它从 XP 时代就是系统组件,32 位程序直接用没问题,但 64 位程序永远无法通过它打开 .mdb 文件——不是连接串写错了,是 Provider 本身没有 64 位实现。Microsoft.ACE.OLEDB.12.0 和 16.0 是 Office 2007 之后随 Access 提供的 Provider,倒是有 64 位版,但安装时和 Office 的位数强绑定:64 位 Office 配 64 位 ACE 引擎,32 位 Office 配 32 位 ACE 引擎,装反了连 Excel 数据导入都起不来。
这也是“access数据库64位系统驱动程序”这类检索需求出现的根源:老项目从 32 位系统迁到 64 位,程序里还写着 Microsoft.Jet.OLEDB.4.0,系统里就算 msado15.dll 注册得好好的,也一样报“未找到提供程序”。我遇到这类现场,第一反应不是补 DLL,而是先看程序连接串里写的 Provider 是什么。
3. 部署落地:把 msado15.dll 注册进目标机器
3.1 regsvr32 注册命令与位数匹配
注册 msado15.dll 的标准命令是 regsvr32,但位数匹配是玄学重灾区。64 位 DLL 要用 64 位 regsvr32.exe(System32 下的那个),32 位 DLL 要用 32 位 regsvr32.exe(SysWOW64 下的那个)。从普通命令提示符里直接敲 regsvr32,运行的是 System32 下的 64 位版本,用它注册 SysWOW64 里的 32 位 DLL,注册表项会写进 64 位视图,程序照样找不到。
而且要管理员权限,不然 COM 写入 HKLM 会失败,报 0x80004005 或者“拒绝访问”。我习惯在批处理里强制走提权流程,同时显式指定 regsvr32 的完整路径:
@echo off net session >nul 2>&1 if %errorlevel% neq 0 ( echo 请右键以管理员身份运行 exit /b 1 ) echo 注册 64 位 msado15.dll %SystemRoot%\System32\regsvr32.exe %SystemRoot%\System32\msado15.dll /s echo 注册 32 位 msado15.dll %SystemRoot%\SysWOW64\regsvr32.exe %SystemRoot%\SysWOW64\msado15.dll /s reg query "HKLM\SOFTWARE\Classes\CLSID\{00000514-0000-0010-8000-00AA006D2EA4}\InprocServer32" /v "" 2>nul reg query "HKLM\SOFTWARE\WOW6432Node\Classes\CLSID\{00000514-0000-0010-8000-00AA006D2EA4}\InprocServer32" /v "" 2>nul echo 注册完成net session 判断管理员权限,非管理员直接退出。两条 regsvr32 分别用不同位数的注册程序,结尾用 reg query 验证注册结果。注意这里 /s 参数是静默模式,不要加在路径前面,我见过有人把 /s 写在 regsvr32 和 dll 路径之间,导致参数被当成文件名解析失败。注册完的 InprocServer32 默认值应该分别指向 System32 和 SysWOW64 下的 msado15.dll,如果指向反了,说明注册程序选错位数了。
3.2 三种分发方式:本机注册、安装包静默、免注册 COM
现场给一台电脑补环境,手动注册就够了。但要往几十台机器上推,或者做安装包,就得换个姿势。
第一种是本机手动注册,适合客户现场临时处理,一条命令的事,但容易漏掉位数匹配,我把 3.1 的 bat 存成 U 盘里的批处理文件,去现场直接双击。
第二种是安装包静默注册。用 NSIS 或 Inno Setup 打包时,在安装脚本里调用 regsvr32 /s。我用 Inno Setup 时是这样写的:
[Run] Filename: "{sys}\regsvr32.exe"; Parameters: "/s {sys}\msado15.dll"; Flags: runhidden 64bit Filename: "{syswow64}\regsvr32.exe"; Parameters: "/s {syswow64}\msado15.dll"; Flags: runhidden{ sys } 和 { syswow64 } 是 Inno Setup 预定义常量,分别指向真实 System32 和 SysWOW64。注意第一位 Flags 加了 64bit,表示在 64 位安装模式下运行;第二段不加,默认走 32 位视角,调用的就是 SysWOW64 下的注册程序。如果两个方向搞反,装完之后程序照样报错,而且因为是静默安装,用户根本不知道哪一步出了问题。
第三种是免注册 COM(RegFree COM),适合绿色软件分发,不需要往系统里写注册表。做法是给程序配一个 manifest 文件,在其中声明依赖的 COM 组件 CLSID 和 dll 路径。优点是卸载干净,不污染系统;缺点是 ADO 这种老组件对 manifest 隔离支持不算好,我只在内部小工具上用过,给外部客户还是老老实实注册。
3.3 服务场景下 Session 0 的坑
程序如果是 Windows 服务或计划任务,注册表环境在 Session 0 里同样生效,但有一个额外的坑:服务账户通常只加载 HKLM 里的 COM 项,不加载 HKCU 里的用户级注册。regsvr32 注册 ADO 时写的是 HKLM,所以服务账户一般没问题;但如果你之前用某个普通用户身份手动注册过,而且注册程序把部分项写进了 HKCU\Software\Classes,那服务起来时读不到用户级注册表,照样报错。检查方法很简单,看 HKCU\Software\Classes\CLSID 下有没有 ADO 相关的键:
reg query "HKCU\SOFTWARE\Classes\CLSID\{00000514-0000-0010-8000-00AA006D2EA4}" 2>nul查到的话就删掉,然后重新用管理员身份按 3.1 的脚本注册 HKLM 视图。这样能避免同一个 DLL 在两处注册,后续排查时少一个干扰项。
4. 代码里调用 ADO 的位数匹配:连接串、编译目标与 ODBC 驱动
4.1 连接字符串里 Provider 的写法差异
部署层面弄完,剩下就看代码。同一个 msado15.dll,代码里 Provider 写错了照样连不上。C# 里典型的 ADO 连接写法是这样:
using ADODB; var conn = new Connection(); // 32 位环境可用:Jet Provider 只能连 .mdb conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\data\\old.mdb;"; conn.Open(); // 64 位环境可用:ACE Provider 连 .accdb 或 .mdb conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\data\\new.accdb;"; conn.Open();第一段代码在 64 位进程里必然报“未找到提供程序”,原因前面说了,Jet Provider 没有 64 位版。换成 ACE Provider 能不能跑,取决于机器装没装对应位数的 ACE 引擎。注意连接串里 Data Source 路径不要写相对路径,服务场景下当前目录经常不是你想象的目录,我一般用 Path.GetFullPath 先生成绝对路径再拼进去。
这一段的坑在于:项目编译目标如果选 AnyCPU,在 64 位系统上运行时默认被 JIT 成 64 位进程,那 Jet 永远用不了;编译目标改 x86,进程就是 32 位,Jet 能用了,但 ACE 引擎必须是 32 位版。同一个连接串在这两种进程位数下表现完全不同,所以先确认进程位数再谈 Provider。
4.2 编译目标设为 x86 的两种办法
VS 里可以在项目属性-生成-目标平台里改,也可以直接改 csproj:
<PropertyGroup> <PlatformTarget>x86</PlatformTarget> </PropertyGroup>改完之后,程序跑起来就是 32 位进程,加载 SysWOW64 下的 msado15.dll,连 Microsoft.Jet.OLEDB.4.0 就正常了。VB6、Delphi 这类老编译器没有 AnyCPU 的概念,编译产物本来就是 32 位,所以它们跑在 64 位系统上反而更省心——只要 32 位 ADO 注册好就行。这也是为什么你看到很多老财务系统在 64 位 Win10 上稳定运行,因为它们整个进程是 32 位,Jet Provider 能用。
要注意的是,改 x86 之后,进程内容一次性读入内存的上限和 64 位 API 访问会受限,比如无法读写大于 2GB 的数组。但 ADO 连数据库这种场景通常不涉及,别因为强迫症盲目改回 AnyCPU,数据库连接稳定才是第一位的。
4.3 ODBC 驱动位数也要一起看
有些老代码不走 OLE DB,而是走 ODBC。Windows 自带的 ODBC 数据源管理器有两个入口,很多人不知道:System32 下的 odbcad32.exe 是 64 位管理器,SysWOW64 下的 odbcad32.exe 是 32 位管理器。老程序里用 DSN 连接数据库时,DSN 必须建在对应位数的管理器里。
%SystemRoot%\System32\odbcad32.exe %SystemRoot%\SysWOW64\odbcad32.exe排查方法:在 32 位管理器里建一个指向旧库的 DSN,然后程序里把连接串改成 DSN=olddsn; 看能不能通。这招能区分是 msado15.dll 的问题还是 ODBC 驱动的问题。我处理过一个案例,程序报错“ODBC 驱动未找到”,查了半小时才发现 DSN 建在了 64 位管理器里,32 位程序根本读不到。这个坑和 msado15.dll 的位数隔离是同一个套路,只是入口藏在 SysWOW64 里,不容易想到。
5. 避坑排查:常见的五个现场与处理顺序
5. 常见问题排查:报错信息与对应处理
5.1 现象:regsvr32 注册成功,程序仍报“未找到提供程序”
原因:regsvr32 的位数选错了。普通命令提示符里敲 regsvr32,实际调用的是 System32 下的 64 位版本,把 32 位 DLL 注册进了 64 位注册表视图。ADODB.Connection 的 CLSID 有两个视图,32 位程序读的是 WOW6432Node 那个,你注册进 64 位视图它就看不见。
解决:删除错误视图里的注册项,再用对应位数的 regsvr32 注册一次。操作顺序是:先用 64 位 regsvr32 /u 注销 System32 下的 DLL,再用 SysWOW64 的 regsvr32 注册 SysWOW64 下的 DLL,最后用 3.1 的 reg query 命令核对两个视图的 InprocServer32 指向。从那以后我注册任何 COM 组件都先确认 DLL 所在目录和 regsvr32 所在目录同位数,不偷懒。
5.2 现象:报错 0x800A0E7A“找不到文件或程序集”
原因:64 位进程尝试加载 32 位 COM 组件,或者反过来。VB6 编译的程序是 32 位进程,如果系统里的 ADO 被注册成了 64 位视图,COM 机制在解析 CLSID 时找不到匹配位数,就会报这个错。另一种情况是 C# AnyCPU 程序,64 位系统上跑成 64 位进程,但连接串里写的是 Jet Provider,只有 32 位实现。
解决:先确认进程位数。任务管理器-详细信息-平台列能看到 x86 还是 x64。进程是 32 位就按 3.1 注册 32 位视图;进程是 64 位就改代码里的 Provider 为 ACE 并安装 64 位 ACE 引擎。如果旧库是 .mdb 且目标机器装的是 64 位 Office,可以试试用 ACE 64 位连 .mdb,多数情况下能通,个别带复杂宏的库会不稳定,这种就老实把进程改成 x86。
5.3 现象:VBA 引用里 msado15.dll 变成“丢失引用”
原因:Office 的 VBA 工程里引用了 ADODB,但系统里 ADO 的 COM 注册项被清理工具删掉或改坏了。常见于装过各类“系统优化软件”的机器,注册表里 CLSID 的 InprocServer32 被标记删除,程序一启动就找不到类型库。Office 本身不修复这类引用,只在打开工程时报“文件丢失或未找到”。
解决:重新注册 msado15.dll 后刷新 VBA 引用。打开 VBA 编辑器,工具-引用,找到丢失的项取消勾选再勾上,或者把引用路径重新指向 C:\Windows\SysWOW64\msado15.dll(Office 32 位)或 System32(Office 64 位)。这一步做完还要确认引用项前面的勾不再显示“丢失”,否则每次打开文件都会弹一次提示。
5.4 现象:注册 32 位 DLL 时报 0x8002801C“类型库冲突”
原因:机器上同时存在 64 位和 32 位两个 ADO 版本,且两边注册的 TypeLib 版本号冲突。ADO 的 TypeLib 主版本在注册表 HKCR\TypeLib 下,位数不同时版本 ID 相同但平台标记不同,如果两边都注册了同一版本,AppID 解析就会混乱。常见于在已正常注册 64 位 ADO 的系统上拿着 32 位 DLL 手动再注册一遍,又没有先注销。
解决:按顺序注销再注册,不同时保留两个位数的重复注册。命令行里依次执行 64 位 regsvr32 /u 和 32 位 regsvr32 /u,清理干净的标志是 reg query 查不到 InprocServer32 的默认值。然后再只注册需要的那个位数。如果你的程序是 32 位而系统里只有 64 位 ADO 被用得死死的,建议不要强行注册 32 位,优先把程序迁移到 64 位连接方案更省事。
5.5 现象:注册过程提示 0x80004005 注册表写入失败
原因:权限不足。regsvr32 写 HKLM\Software\Classes 需要管理员权限,普通用户运行会直接拒绝。还有一种情况是企业域环境下组策略限制了 HKLM 写入,或者杀毒软件拦截了 COM 注册动作。看起来像 DLL 损坏,其实是写入被挡。
解决:确认运行批处理时右键选了“以管理员身份运行”,并在杀毒软件里临时放行 regsvr32.exe。域环境限制的话联系管理员加白名单。注册前可以先跑一下 3.1 开头的 net session 检查,批处理自己判断权限,没权限就直接退出并提示,省得后面被各种奇怪报错绕晕。
6. 快速验证一套 msado15.dll 是否可用:VBS 最小连接测试
部署和排查都做完,最后要确认“真的能连”而不是“看起来注册好了”。我习惯用一个 VBS 脚本做最小化验证,它只做三件事:检查两个目录的文件版本、抽查注册表 InprocServer32、实际发起一次 ADO 连接。哪怕连一个不存在的数据库文件也没关系,只要报错信息从“未找到提供程序”变成“文件路径找不到”,就说明 ADO 组件已经被正确加载了。
' 最小化验证:msado15.dll 文件、注册表、实际连接 Set fso = CreateObject("Scripting.FileSystemObject") ' 1. 检查文件是否存在 If fso.FileExists("C:\Windows\System32\msado15.dll") Then WScript.Echo "System32 msado15.dll 文件存在" Else WScript.Echo "System32 msado15.dll 缺失" End If If fso.FileExists("C:\Windows\SysWOW64\msado15.dll") Then WScript.Echo "SysWOW64 msado15.dll 文件存在" Else WScript.Echo "SysWOW64 msado15.dll 缺失" End If ' 2. 尝试创建 ADODB.Connection 对象 On Error Resume Next Set conn = CreateObject("ADODB.Connection") If Err.Number <> 0 Then WScript.Echo "创建 Connection 失败,错误号: " & Err.Number & " - " & Err.Description WScript.Quit End If Err.Clear ' 3. 故意连接一个不存在的 mdb 文件,测 Provider 加载 conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\nonexistent\test.mdb;" conn.Open If Err.Number <> 0 Then If InStr(Err.Description, "找不到文件") > 0 Or InStr(Err.Description, "文件路径") > 0 Then WScript.Echo "Jet Provider 加载成功,报错属于预期(文件不存在)" Else WScript.Echo "Jet Provider 加载失败: " & Err.Number & " - " & Err.Description End If Else WScript.Echo "连接意外成功,请检查路径" End If脚本的核心设计是第三段。正常的验证逻辑是连一个真实存在的库,但现场没有合适的 mdb 文件时,连不存在的路径反而更有用:如果 Jet Provider 已正确注册,错误会停在“文件不存在”;如果 Provider 没注册,错误会停在“未找到提供程序”。两种错误的区别一眼就能判断 ADO 环境是否就绪。里面对错误描述用 InStr 判断,是因为不同 Windows 版本的本地化语言会把“找不到文件”翻译得不一样,中文版是“文件找不到”,英文版是“Could not find file”,所以写两个常见子串兜底。脚本用 cscript 命令行跑就行:cscript test_ado.vbs。看到“Jet Provider 加载成功”才算过关。
从那以后我每次给机器补完 msado15.dll,都会强制走一遍这个最小连接测试,确认报错从“未找到提供程序”变成“文件不存在”才算交付,不然回去路上心里总悬着。这套流程看着多,实际上手三分钟,希望帮到你。
本文还有配套的精品资源,点击获取