Windows集成ICU静态库后Redshift ODBC驱动加载失败(错误IM003)
问题背景
首次在Windows环境下基于Visual Studio 2015修改Amazon Redshift ODBC遗留代码,集成ICU 72静态库。完成代码修改、头文件/库依赖配置后,通过命令行脚本编译DLL并打包MSI。原代码编译运行正常,但添加最小化ICU相关代码后,用pyodbc测试连接时触发错误:
InterfaceError: ('IM003', '[IM003] Specified driver could not be loaded due to system error 126: The specified module could not be found. (Amazon Redshift ODBC Driver (x64), C:\Program Files\Amazon Redshift ODBC Driver x64\Drivers\rsodbc.dll). (160) (SQLDriverConnect)')
添加的ICU代码片段:
#include <unicode/ucnv.h> #include <unicode/unistr.h> #include <unicode/urename.h> #include <unicode/stringpiece.h> SQLRETURN SQL_API SQLExecDirectW(SQLHSTMT phstmt, SQLWCHAR* pwCmd, SQLINTEGER cchLen) { icu::UnicodeString ustr(pwCmd, cchLen*sizeof(SQLWCHAR)); //... }
测试Python代码:
import pyodbc query = 'anything' statement = f"SELECT '{query}'" print(statement) cnxn = pyodbc.connect('Driver={Amazon Redshift ODBC Driver (x64)};Server=xxx;Port=5439;Database=dev;UID=xxx;PWD=xxx') cursor = cnxn.cursor() cursor.execute(statement) val = cursor.fetchall()[0][0]
补充信息:Linux环境无此问题;用dumpbin检查rsodbc.dll发现,链接ICU后SQLDriverConnect的存在形式有变化。
解决思路
1. 确认ICU静态库的链接配置
确保链接的是ICU的纯静态版本(如icuuc.lib、icuin.lib等静态库文件,而非动态库对应的导入库)。如果误链接动态库的导入库,会导致rsodbc.dll依赖ICU的动态文件(如icuuc72.dll),但MSI未打包这些DLL,就会触发错误126。检查VS项目的链接器输入项,确认所有ICU相关库均为静态库。
2. 检查rsodbc.dll的依赖项
用dumpbin /dependents rsodbc.dll命令或Dependency Walker(需x64版本)分析DLL的依赖链:
- 查看是否存在缺失的动态库(比如未部署的ICU动态文件、VC++运行时库)
- 确认是否有隐性依赖的系统组件未被打包进MSI
3. 排查符号导出问题
ODBC驱动必须导出标准的ODBC API函数(如SQLDriverConnect、SQLExecDirectW等)才能被ODBC管理器识别。添加ICU代码后,可能因符号导出规则变化导致ODBC无法找到必要函数:
- 用
dumpbin /exports rsodbc.dll对比修改前后的导出表,确认SQLDriverConnectA/SQLDriverConnectW是否在导出列表中 - 检查函数名称是否符合ODBC规范(不能有C++ mangled名称,需通过
extern "C"声明导出)
注意:你的SQLExecDirectW函数需要添加extern "C"修饰,避免被C++编译器修改符号名称。
4. 验证ICU静态库的编译参数
ICU静态库的编译配置需与你的ODBC驱动完全匹配:
- 确保ICU是用VS2015工具链编译的,且启用了静态编译(配置时加
--enable-static参数) - 确认ICU的架构(x64)、字符集设置与驱动一致
- 若ICU默认依赖动态VC++运行时,需修改编译参数使其静态链接运行库,避免隐性依赖
5. 检查MSI打包的文件完整性
- 确认MSI是否包含了VS2015的x64版本VC++ Redistributable,或者将驱动项目的运行库设置为静态链接(VS属性→C/C++→代码生成→运行库,选择
/MT或/MTd) - 检查MSI部署后,rsodbc.dll所在目录是否包含所有必要的依赖文件(即使是静态库,部分组件可能仍需配套的数据文件)
6. 测试DLL加载路径
将rsodbc.dll直接放到系统路径(如C:\Windows\System32),或把所有依赖文件(若有)放到rsodbc.dll同目录下,再测试pyodbc连接,排除MSI部署时的路径问题。
内容的提问来源于stack exchange,提问作者rahman

