使用Pythonnet调用C# DLL的运行时错误(数据库兼容性问题)
问题分析与解决方案
从你反编译的代码和环境描述来看,核心问题集中在数据库连接字符串语法错误、驱动兼容性以及潜在的代码逻辑缺陷上,以下是具体分析和解决步骤:
一、核心问题定位
1. 连接字符串拼接错误(最直接的诱因)
在GetRecordset方法中,连接字符串的拼接存在明显语法问题:
string connectionString = "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + this.PathDB + NomeDB + "Jet OLEDB:Database Password=123456";
传入的NomeDB参数是@"\Coils.mdb;"(带末尾分号),拼接后Data Source部分会变成[PathDB]\Coils.mdb;,随后直接追加密码参数,导致整个连接字符串格式混乱——密码参数没有用分号与前面的内容分隔,OLEDB驱动无法正确解析,这是办公电脑频繁抛出运行时错误的主要原因。
2. 数据库驱动兼容性问题
办公电脑安装的是Microsoft Database Engine 2010,而代码中使用的Microsoft.JET.OLEDB.4.0是32位专属驱动:
- 如果你的PyInstaller编译的是64位程序,或者办公电脑默认以64位环境运行,会直接出现驱动找不到的错误;
- ACE驱动(
Microsoft.ACE.OLEDB.12.0)是JET的官方替代方案,支持32/64位,更适配高版本.NET环境。
3. 潜在的数组越界风险
LoadRanghiAmmessi方法中直接对vRanghi[index]赋值,如果查询返回的行数超过数组长度,会抛出索引越界异常,这可能是“部分数据能运行、默认数据不行”的诱因之一。
二、具体解决方案
1. 修复连接字符串格式
修改GetRecordset方法中的拼接逻辑,确保参数分隔正确:
// 先去除NomeDB末尾的分号,避免路径包含无效字符 string dbFullPath = this.PathDB + NomeDB.TrimEnd(';'); // 使用格式化字符串保证语法正确 string connectionString = string.Format( "Provider=Microsoft.JET.OLEDB.4.0;Data Source={0};Jet OLEDB:Database Password=123456", dbFullPath );
如果改用ACE驱动(推荐适配新环境),则连接字符串改为:
string connectionString = string.Format( "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Jet OLEDB:Database Password=123456", dbFullPath );
2. 确保程序与驱动位数匹配
- 若坚持使用JET驱动(仅32位):
需用32位Python 2.7环境编译代码,PyInstaller命令指定32位打包:pyinstaller --distpath dist32 --workpath build32 --specpath spec32 your_script.py - 若改用ACE驱动:
确保办公电脑安装的是对应位数的Microsoft Access Database Engine 2010(32位/64位需与程序一致)。
3. 修复数组越界逻辑
将固定数组改为动态集合存储结果,再安全复制到传入数组:
public int LoadRanghiAmmessi(int[] vRanghi, string geometria) { List<int> ranghiList = new List<int>(); CrConnection connection = new CrConnection(this.PathDB); OleDbDataReader recordset = null; try { // 执行第一个查询 string query = "SELECT * FROM RanghiAmmessi WHERE (Geometria='" + geometria + "') ORDER BY NRanghi"; recordset = connection.GetRecordset(query, @"\Coils.mdb;"); if (recordset != null && recordset.HasRows) { while (recordset.Read()) { ranghiList.Add(int.Parse(recordset["NRanghi"].ToString())); } } else { // 关闭第一个结果集,执行备用查询 if (recordset != null) recordset.Close(); query = "SELECT * FROM RanghiAmmessi WHERE (Geometria='*') ORDER BY NRanghi"; recordset = connection.GetRecordset(query, @"\Coils.mdb;"); if (recordset != null && recordset.HasRows) { while (recordset.Read()) { ranghiList.Add(int.Parse(recordset["NRanghi"].ToString())); } } } } finally { // 确保结果集被关闭 if (recordset != null) recordset.Close(); } // 安全复制到传入数组,避免越界 int validCount = Math.Min(ranghiList.Count, vRanghi.Length); ranghiList.CopyTo(0, vRanghi, 0, validCount); return validCount; }
4. 解决.NET版本与EF冲突
在程序目录下添加app.config文件(PyInstaller打包时需包含),指定.NET兼容性与EF版本重定向:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> <runtime> <NetFx40_LegacySecurityPolicy enabled="true"/> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-6.2.0.0" newVersion="5.0.0.0" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
打包时需在PyInstaller的spec文件中添加该配置,确保它与exe同目录。
三、验证步骤
- 优先修复连接字符串问题,重新编译C# DLL(若可修改);若无法修改DLL,可尝试调整
PathDB的格式(比如确保末尾不带斜杠),间接修正拼接后的路径。 - 确认程序位数与驱动匹配,测试数据库连接是否正常。
- 测试默认数据和其他数据,验证异常是否消除。
内容的提问来源于stack exchange,提问作者Jonadri Bundo
相关产品推荐
相关产品推荐

