资讯动态

Windows 64位环境下dmoci开发库接入C/C++工程实战指南

发布时间:2026/9/10 2:12:14 来源:尧图企业网站定制
简介dmoci开发库是面向C/C开发者的达梦7数据库客户端接口工具包专为Windows 64位环境设计可配合Visual C工程使用。它提供标准API用于数据查询、插入、更新、删除及事务管理帮助开发者在64位系统上直接对接达梦数据库适合需要构建国产数据库应用或进行系统集成的中高级C/C程序员。压缩包内共21个文件以18个dll动态库为主另含1个头文件、1个导入库和1个配置文件大小约3.33MBdll供程序运行时调用头文件声明接口lib用于编译链接结构简洁便于集成。已有895人学习对希望快速上手达梦数据库的开发者尤为实用。通过这份开发库开发者可获得完整的DMOCI头文件与库文件在Visual Studio中快速配置连接参数、执行SQL并处理结果集免去自行摸索接口细节的时间从而更高效地完成达梦7数据库应用的开发与调试。 如果你手里正好有一份 dmoci 开发库项目又要求用 C/C 在 Windows 上跑一个 64 位的客户端程序我猜你大概率和我第一次拿到这套包时一样面对一堆 .h、.lib 和 dll 文件一时不知道从哪下手。dmoci 是一套数据库访问接口库调用风格完全对齐 Oracle 的 OCI 规范专门供 C/C 程序连接数据库、执行 SQL、取回结果集。后面挂着的 64 位意味着你的程序必须按 x64 平台来编译链接运行环境也得是 64 位系统否则光是加载 dll 这一关就会卡住。这篇文章我就按真实的开发顺序把环境准备、工程接入、最小示例、常见坑一次讲完。适合刚接手这类库的 C/C 开发者也适合需要在 64 位环境下做数据对接中间件的朋友参考。1. 先搞明白 dmoci 开发库到底是什么1.1 名字拆解DM 和 OCI 合在一起意味着什么dmoci 这个名字可以拆成 DM 和 OCI 两半。DM 指达梦数据库也就是国内常见的关系型数据库产品OCI 则是 Oracle 提出的一套 C 语言数据库访问接口规范。dmoci 开发库就是厂商按照 OCI 这套规范重新实现的客户端库函数名、参数顺序、句柄模式统统向 OCI 看齐让原来写过 Oracle OCI 程序的开发者几乎不用重新学一遍接口体系。这里有个容易混淆的点它不是 ODBC也不是 JDBC更不是某个 ORM 框架而是更靠近数据库内核的一层 C 接口。你用 dmoci 写出来的程序本质上是直接和数据库的客户端通信协议打交道少了中间层转换。对性能敏感的系统集成、数据采集程序来说这种贴近底层的方式能省掉不少开销。很多人第一次接触 OCI 系列接口会觉得函数名太长、句柄太多但只要你理解它背后的模型后面写起来其实非常顺手。1.2 为什么 C/C 项目更要看重 64 位C/C 项目选择 OCI 这类接口而不是 ODBC/JDBC主要原因是层级少、控制力强。OCI 接口允许程序员自己管理句柄、绑定变量、定义结果集缓冲区在大量循环插入、批量查询场景下性能优势比较明显。很多中间件、交易系统、工业数据采集程序到今天仍然大规模使用 C/C 写数据库对接层就是这个道理。而 64 位的价值更加直接32 位程序只能访问约 4GB 内存遇到需要缓存大量数据做批处理的应用就会很吃力换成 64 位程序后内存上限大幅提升配合 64 位的 dmoci 开发库数据吞吐能力完全是另一个量级。所以dmoci C/C 64 位这种组合不是随便拼出来的标签它背后表达的是一个面向高性能、大规模数据的工程选型。2. 动手前必须准备的 64 位环境2.1 拿到一套完整的开发包先分清头文件、导入库和动态库在 Windows 上做 dmoci 开发首先要确保你手上的库是完整的一套。通常有三种获取途径一是安装达梦数据库服务端的时候安装目录下的 include 和 lib 文件夹里自带 C/C 接口二是单独安装客户端开发包三是厂商官网或原项目提供的压缩包。不管从哪来完整开发包至少要包含三类文件头文件核心是 dci.h配套的还有 dciDataTypes.h、dciFunctions.h 等负责声明接口和数据类型。导入库一般叫 dci.lib 这类 .lib 文件负责在编译链接阶段向程序提供符号信息。动态库核心是 dmoci.dll还有它依赖的 dms.dll、dmapi.dll 等负责程序运行时真正被加载。头文件、导入库、动态库三样缺一不可。我见过不少人只拷贝了一个 dll 到工程里编译时报找不到头文件链接时报找不到 lib最后才反应过来是自己手里的包不完整。另外要注意 64 位版本的识别如果目录结构里有 x86、x64 这种二级文件夹或者文件名带 64 后缀就按 x64 那个拿没有明确标注时用 dumpbin 命令检查最可靠。2.2 位数匹配数据库、开发库、应用程序三者必须统一64 位开发最常见的问题不是代码本身而是位数不匹配。我给一个判断顺序数据库服务端是 64 位还是 32 位通常不重要64 位程序连 32 位数据库服务的情况也常见真正重要的是编译程序时链接的 dmoci 开发库必须是 64 位版本。开发库位数、应用程序目标平台、运行时加载的 dll 位数这三点必须一致。你可以在 Visual Studio 开发者命令行里执行下面这条命令来检查dumpbin /headers C:\dmdbms\dmoci\bin\dmoci.dll看到输出里的machine (x64)就说明是 64 位版本看到machine (x86)就是 32 位版本。我实际踩过的坑是开发包是 x64但工程没切换平台编译成 Win32运行时又被别的软件在路径里塞了一个旧版 32 位 dll程序加载顺序一错报错信息每次都绕开真正原因排查了老半天才定位到位数上。2.3 开发工具和前置验证工具方面我建议用 Visual Studio 2017 或 2019 的社区版安装时勾上使用 C 的桌面开发这一项。Windows 7 64 位系统也能跑但 VS2019 比较新记得提前装好系统对应的更新补丁。VS Code 也可以利用 tasks.json 配置好 cl.exe 或者 MinGW-w64 编译命令就行不过对于新手来说VS 的工程配置更直观。另外开发机上最好装一下达梦的客户端命令行工具比如 disql。先用命令行确认数据库连接地址、端口、用户名密码都正常再去调试 C/C 代码。默认端口一般 5236但实际项目里改过的不少所以连接地址里的 IP 和端口不要硬编码最好做成配置项。你连服务端都连不上就去调 C 代码很容易把网络问题和代码问题混在一起。3. 把 dmoci 库正确接入工程3.1 Visual Studio 工程配置的完整步骤我以 VS2019 为例。新建一个 C 空项目后按下面顺序配置顶部解决方案平台下拉框把 Win32 切换成 x64。如果没有 x64点配置管理器新建一个 x64 平台。右键项目 - 属性 - 配置选择所有配置避免 Debug 和 Release 各配一遍。C/C - 常规 - 附加包含目录填入头文件路径例如C:\dmdbms\dmoci\include。链接器 - 常规 - 附加库目录填入C:\dmdbms\dmoci\lib。链接器 - 输入 - 附加依赖项手工加上dci.lib。生成项目把 dmoci.dll 以及依赖的 dll 复制到 exe 同一目录或者配置到 PATH。这里有个细节附加依赖项里加 dci.lib 就够了不需要把所有 dll 都写进依赖项。运行库建议选多线程调试 (MDd)或多线程 (MD)也就是动态 CRT不要选 MT。选 MT 在部分情况下会出现堆管理器不一致导致的崩溃排查起来非常头疼。3.2 用 CMake 集成连命令行党也能直接跑现在不少新项目直接上 CMake。CMakeLists 里把 include 和 lib 目录导出来就行cmake_minimum_required(VERSION 3.10) project(dmoci_demo C) set(DMOCI_INCLUDE_DIR C:/dmdbms/dmoci/include) set(DMOCI_LIB_DIR C:/dmdbms/dmoci/lib) include_directories(${DMOCI_INCLUDE_DIR}) link_directories(${DMOCI_LIB_DIR}) add_executable(dmoci_demo main.c) target_link_libraries(dmoci_demo dci)然后在有 CMakeLists.txt 的目录执行cmake -S . -B build -G Visual Studio 16 2019 -A x64 cmake --build build --config Release-A x64这个参数是关键它强制生成 64 位工程。忘掉这一步后面框架链接的库还是 32 位运行必炸。如果你用的是 Linux 或者交叉编译环境可以去掉 Visual Studio 的生成器指定让 CMake 自动检测原生编译器。3.3 C 工程务必处理 extern C 的问题如果工程是 C 写的头文件又没做extern C保护直接用 C 编译器去编译链接时会因为符号被 C 修饰改名而出现 unresolved external symbol。稳妥做法是在包含头文件前包一层extern C { #include dci.h }C 工程不用管这个。用 Visual Studio 建 C 工程又想偷懒的话也可以直接用extern C包裹所有需要的头文件。这是我实际项目里遇到过的最隐蔽的链接报错之一代码写得完全没问题编译全过就是链接阶段报一堆符号找不到最后发现是 C 名称修饰在捣鬼。4. 第一个最小程序连接、查询、取数全过程4.1 OCI 编程的最小模型先建立起来OCI 写起来有自己的固定套路核心是句柄这个概念。你可以把句柄想象成去银行办事时拿到的各种凭证环境句柄相当于进入银行大堂的身份错误句柄用来接收柜台的回答服务器句柄对应你选定的办事窗口服务上下文句柄是当前正在进行的业务场景会话句柄就是你登录后的账户凭证。一个最简程序必须按顺序创建这些句柄然后连接、执行、取数、释放。顺序乱了或者漏掉某个句柄轻则返回错误码重则程序直接崩溃。和 JDBC 那种 Connection、Statement 的面向对象封装不同OCI 的句柄体系更细但灵活性也更强。理解了这套句柄模型后面看 dmoci 的任何示例代码都会很轻松。4.2 一个能跑通的连接查询示例这里给出我调通的一个精简版用 C 语言写编译成 x64#include stdio.h #include string.h #include dci.h int main() { OCIEnv *envhp NULL; OCIError *errhp NULL; OCIServer *srvhp NULL; OCISvcCtx *svchp NULL; OCISession *authp NULL; OCIStmt *stmthp NULL; OCIDefine *defhp NULL; char name[128] {0}; if (OCIEnvCreate(envhp, OCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL) ! OCI_SUCCESS) { printf(create env failed\n); return -1; } OCIHandleAlloc(envhp, (dvoid **)errhp, OCI_HTYPE_ERROR, 0, NULL); OCIHandleAlloc(envhp, (dvoid **)srvhp, OCI_HTYPE_SERVER, 0, NULL); OCIHandleAlloc(envhp, (dvoid **)svchp, OCI_HTYPE_SVCCTX, 0, NULL); const char *server 192.168.1.10:5236; OCIServerAttach(srvhp, errhp, (const text *)server, (sb4)strlen(server), OCI_DEFAULT); OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, srvhp, 0, OCI_ATTR_SERVER, errhp); OCIHandleAlloc(envhp, (dvoid **)authp, OCI_HTYPE_SESSION, 0, NULL); OCIAttrSet(authp, OCI_HTYPE_SESSION, (const text *)SYSDBA, (ub4)strlen(SYSDBA), OCI_ATTR_USERNAME, errhp); OCIAttrSet(authp, OCI_HTYPE_SESSION, (const text *)SYSDBA, (ub4)strlen(SYSDBA), OCI_ATTR_PASSWORD, errhp); OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, OCI_DEFAULT); OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, authp, 0, OCI_ATTR_SESSION, errhp); OCIHandleAlloc(envhp, (dvoid **)stmthp, OCI_HTYPE_STMT, 0, NULL); const char *sql SELECT NAME FROM TEST_TABLE; OCIStmtPrepare(stmthp, errhp, (const text *)sql, (ub4)strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT); OCIDefineByPos(stmthp, defhp, errhp, 1, name, sizeof(name), SQLT_STR, NULL, NULL, NULL, OCI_DEFAULT); OCIStmtExecute(svchp, stmthp, errhp, 1, 0, NULL, NULL, OCI_DEFAULT); while (OCIFetch(stmthp, errhp, 1, OCI_DEFAULT) OCI_SUCCESS) { printf(name %s\n, name); } OCISessionEnd(svchp, errhp, authp, OCI_DEFAULT); OCIHandleFree(stmthp, OCI_HTYPE_STMT); OCIHandleFree(authp, OCI_HTYPE_SESSION); OCIHandleFree(svchp, OCI_HTYPE_SVCCTX); OCIHandleFree(srvhp, OCI_HTYPE_SERVER); OCIHandleFree(errhp, OCI_HTYPE_ERROR); OCIHandleFree(envhp, OCI_HTYPE_ENV); return 0; }为了方便阅读我把每次 API 调用后的错误检查都省略了。真实代码里每个函数返回非 OCI_SUCCESS 之后都应该用 OCIErrorGet 取出错误信息打印出来否则出了问题只能干瞪眼。你想在笔记本上快速复现的话把 TEST_TABLE 换成你自己库里的真实表名即可。4.3 从编译到跑通整条链路代码准备好后编译路径我再强调一遍头文件目录加到 includedci.lib 加到链接exe 旁边摆上 dmoci.dll 和它依赖的 dms.dll然后以 x64 平台编译。启动程序如果看到控制台把 TEST_TABLE 里的 NAME 列全部打出来说明整条链路通了。第一次调通非常关键。我见过不少同事上来就想封装框架、写线程池结果连最小示例都没跑通最后排查问题花了三四天。先把最小链路跑通再把代码往工程里搬这是最省时间的策略。跑通之后再把连接串、用户名、密码改成可配置项用配置文件或环境变量管理起来。5. 我踩过的坑常见问题与排查技巧5.1 提示找不到 dmoci.dll现象程序编译成功双击 exe 报找不到 dmoci.dll或者 0xC0000135。原因基本就两种一是 dll 没放在 exe 目录或 PATH 中二是同目录下放了一个 32 位版本的 dll系统加载时直接拒绝。用 Process Explorer 或者任务管理器查看 exe 加载了哪个路径的 dmoci.dll比瞎猜快得多。保险做法把开发包里 x64 目录下的 dll 全部复制到 exe 目录然后随手用 dumpbin 或者文件属性确认一下位数。这一步看起来啰嗦但能省下后面排查环境问题的半天时间。5.2 编译通过链接报一堆 unresolved external symbol这个错误十有八九是 C 工程没做 extern C 包装或者 dci.lib 根本没加进依赖项。64 位环境下还有一个隐藏原因附加库目录指向了 32 位 lib。VS 链接器不会因为你选了 x64 就自动去 64 位目录找路径配错它照样找不到正确的符号。处理方式按顺序来第一确认 extern C 包了头文件第二确认 dci.lib 所在目录确实是 64 位版本第三在属性页附加依赖项里敲上 dci.lib 之后确认字母没拼错。我之前把 dci.lib 敲成了 dmi.lib链接器给出的错误信息根本联想不到是拼写问题。5.3 程序崩在启动阶段返回 0xC0000005这类崩溃常见于句柄没初始化或者 OCIAttrSet、OCIServerAttach 的入参类型不对。64 位下字符串长度参数是 ub4也就是无符号 32 位整数指针句柄是 64 位传给接口时必须保持类型一致。还有一类情况是定义了局部数组把它的地址传给 OCIDefineByPos 关联结果集然后数组超出作用域被回收取数时写到了垃圾地址。检查这类问题建议把每个 OCI 调用的返回值都打出来定位到第一个失败调用。如果你的代码像我上面示例一样省略了错误检查这时候就得老老实实补回来。失败调用一旦定位到再去查函数签名和参数类型比盯着屏幕发呆有效得多。5.4 查询出来的中文变成问号字符集问题。dmoci 在 Windows 上的默认字符集和数据库实例字符集可能不一致。处理办法有两个方向一是程序里连接后通过 OCIAttrSet 把会话字符集属性显式设置成和数据库一致的编码例如 UTF-8 或 GBK二是源文件里中文字面量统一处理SQL 语句里的中文字符串尽量用参数绑定不要直接拼接。我在项目里遇到的多数乱码都是数据库字符集是 UTF-8、程序默认走 GBK 导致的。还有一类情况是编译器的源代码字符集和执行字符集不一致。用 Visual Studio 的话可以在高级设置里把字符集项统一或者在代码文件头部用 pragma 指定。5.5 快速排查对照表症状优先怀疑对象快速检查手段程序启动报缺少 dlldll 没复制 / 位数不对dumpbin /headers 查看 dll 位数链接阶段一堆符号找不到extern C 没做 / lib 路径不对搜索完整错误行里的符号名定位库运行崩溃 0xC0000005句柄未初始化 / 缓冲区失效逐行定位第一个失败调用查询中文乱码数据库字符集和客户端字符集不一致OCIAttrSet 显式设置字符集连接超时或连不上端口、IP、防火墙先用 disql 命令行动态验证这张表里的问题都不是很少见的个例很多项目刚切到 64 位环境时都会碰到其中一两样。你把这些排查顺序背下来遇到问题就知道从哪下手不用每次从零开始。6. 最后聊几句个人经验做完这个 64 位 dmoci 对接项目之后我有几点体会比较深。第一拿到库先验证位数再写一行代码。用 dumpbin 看 dll 头部一分钟成本能省下后面调链接错误的一整天。尤其是从别人手里交接过来的开发包你根本不知道他给你的是 x86 还是 x64。第二把 dmoci 封装成自己的数据访问层时别急着把所有 OCI 句柄都包进对象。句柄的创建、传递、释放顺序要单独梳理。释放顺序尽量和环境句柄创建顺序相反或者至少保证会话句柄先于服务器句柄释放否则偶发的崩溃会让你很痛苦。第三64 位下面试程序内存使用更宽松但缓冲区定义、函数返回码、字符集这些 C 语言的老问题不会消失。老老实实做错误检查比任何高级技巧都管用。第四数据库版本和开发库版本尽量保持一致。客户端库版本如果比服务端新很多或旧很多在某些 SQL 语法和结果集元数据上可能踩到兼容性边缘。做生产项目之前先在测试库验一遍协议兼容性。最后再多说一句如果团队里不止一个人做这个对接层建议优先把 CMake 那套配置固化到版本库里。后面同事拉下代码用-A x64一下就能编译不用再盯着 VS 属性页逐项配置这才是真正能一劳永逸的好习惯。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价