C语言如何通过ADO连接Access数据库?

99ANYc3cd6
预计阅读时长 28 分钟
位置: 首页 C语言 正文

这是一个比较经典的技术组合,尤其是在一些遗留系统或 Windows 桌面应用开发中,虽然现在有更现代的替代方案(如 C++/CLI + A.NET 或直接使用 ODBC),但理解 C + ADO + Access 的原理依然非常有价值。

c语言 ado access
(图片来源网络,侵删)

核心概念

  1. C 语言: 我们使用的编程语言。
  2. ADO (ActiveX Data Objects): 一个微软的数据库访问技术,它提供了一个高级的、易于使用的接口来访问各种数据源,ADO 是通过 COM (Component Object Model) 技术实现的,这意味着在 C 语言中我们需要使用 COM API 来调用它。
  3. Microsoft Access: 我们的数据库文件,通常是一个 .accdb.mdb 文件,它本身是一个文件型数据库,我们通过 OLE DB 驱动程序来访问它。

开发环境准备

在开始编码之前,你需要确保你的开发环境已经准备就绪。

编译器

你需要一个 Windows 下的 C/C++ 编译器,最常用的是:

  • Visual Studio: 最简单、最推荐的选择,安装时请确保勾选“使用 C++ 的桌面开发”工作负载。
  • MinGW (GCC for Windows): 如果你习惯使用 GCC,也可以配置 MinGW。

ADO 库

ADO 的库文件和头文件通常包含在 Windows SDK 或 Visual Studio 中,只要你安装了 Visual Studio 的 C++ 开发环境,就已经拥有了所需的一切。

  • 头文件: #include <adoidl.h>#include <adoint.h>
  • 库文件: msado15.lib (这是最常用的 ADO 类型库)

Access 数据库

创建一个简单的 Access 数据库文件,mydatabase.accdb,并在其中创建一个表。

c语言 ado access
(图片来源网络,侵删)

示例表 Employees: | ID | FirstName | LastName | Department | |----|-----------|----------|------------| | 1 | John | Doe | IT | | 2 | Jane | Smith | HR | | 3 | Peter | Jones | Sales |


创建 Access 数据库和 DSN (可选)

对于初学者,创建一个 DSN (Data Source Name) 可以简化连接字符串,但对于生产环境,推荐使用“无 DSN”的连接字符串,因为它更灵活,不依赖于系统配置。

方法 A: 创建 DSN (简单)

  1. 在 Windows 中搜索 “ODBC 数据源” 并打开它。
  2. 选择 “DSN 用户数据源” 或 “DSN 系统数据源”,然后点击 “添加”。
  3. 在驱动程序列表中,找到 Microsoft Access Driver (.mdb, .accdb) 并点击 “完成”。
  4. 为数据源命名,MyAccessDB
  5. 点击 “选择...” 按钮,浏览并选择你创建的 mydatabase.accdb 文件。
  6. 点击 “确定” 保存。

方法 B: 无 DSN (推荐)

我们将在代码中直接指定驱动程序和数据库文件路径,无需配置 DSN。


编写 C 代码

我们将创建一个 C 程序,演示如何连接数据库、执行查询、读取数据、插入数据和关闭连接。

c语言 ado access
(图片来源网络,侵删)

核心 ADO 对象:

  • CoInitialize: 初始化 COM 库。必须在调用任何 ADO 函数前执行。
  • CoUninitialize: 释放 COM 库。必须在程序结束时执行。
  • _ConnectionPtr: 代表与数据库的连接。
  • _RecordsetPtr: 代表一个记录集(查询结果)。
  • _CommandPtr: 代表一个要执行的命令(如 SQL 语句)。

下面是一个完整的示例代码:

// ado_access_example.c
#define WIN32_LEAN_AND_MEAN
#define INITGUID
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <olectl.h> // For OleInitialize
#include <adoidl.h> // ADO 头文件
#include <adoint.h> // ADO 头文件
// 链接 ADO 库
#pragma comment(lib, "ole32.lib") // For CoInitialize
#pragma comment(lib, "msado15.lib") // For ADO
// 定义一个用于处理错误的宏
#define CHECK_HR(hr, msg) \
    if (FAILED(hr)) { \
        printf("错误: %s (HRESULT: 0x%08X)\n", msg, hr); \
        goto Cleanup; \
    }
void main()
{
    HRESULT hr = S_OK;
    _RecordsetPtr pRecordset = NULL;
    _ConnectionPtr pConnection = NULL;
    _bstr_t strConnect; // 使用 _bstr_t 自动处理 BSTR 的内存管理
    _bstr_t strQuery;
    // 1. 初始化 COM 库
    hr = CoInitialize(NULL);
    CHECK_HR(hr, "初始化 COM 失败");
    // 2. 创建 Connection 对象实例
    hr = pConnection.CreateInstance(__uuidof(Connection));
    CHECK_HR(hr, "创建 Connection 对象失败");
    // 3. 定义连接字符串
    // --- 选择一种连接方式 ---
    // 方法 A: 使用 DSN (简单)
    // strConnect = "DSN=MyAccessDB;";
    // 方法 B: 无 DSN (推荐,更灵活)
    // 将路径替换为你自己的 .accdb 文件路径
    strConnect = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\path\\to\\your\\mydatabase.accdb;Persist Security Info=False;";
    // 4. 打开数据库连接
    printf("正在连接数据库...\n");
    hr = pConnection->Open(strConnect, "", "", adConnectUnspecified);
    CHECK_HR(hr, "打开数据库连接失败");
    printf("连接成功!\n\n");
    // 5. 执行查询并获取记录集
    strQuery = "SELECT ID, FirstName, LastName, Department FROM Employees;";
    printf("正在执行查询: %s\n", (char*)strQuery);
    pRecordset = pConnection->Execute(strQuery, NULL, adCmdText);
    if (pRecordset != NULL && pRecordset->State == adStateOpen)
    {
        printf("查询成功,获取到记录集,\n");
        printf("--------------------------------------------------\n");
        printf("%-5s %-10s %-10s %s\n", "ID", "FirstName", "LastName", "Department");
        printf("--------------------------------------------------\n");
        // 6. 遍历记录集
        while (!pRecordset->adoEOF)
        {
            // 使用 Fields->GetItem(column_name)->GetValue() 获取字段值
            // 使用 Fields->GetItem(column_index)->GetValue() 也可以
            long id = (long)pRecordset->Fields->GetItem("ID")->GetValue();
            _bstr_t firstName = pRecordset->Fields->GetItem("FirstName")->GetValue();
            _bstr_t lastName = pRecordset->Fields->GetItem("LastName")->GetValue();
            _bstr_t department = pRecordset->Fields->GetItem("Department")->GetValue();
            printf("%-5ld %-10s %-10s %s\n", id, (char*)firstName, (char*)lastName, (char*)department);
            // 移动到下一条记录
            pRecordset->MoveNext();
        }
        printf("--------------------------------------------------\n\n");
    }
    else
    {
        printf("未能获取记录集,\n");
    }
    // 7. 执行插入操作
    printf("正在执行插入操作...\n");
    _bstr_t insertSQL = "INSERT INTO Employees (FirstName, LastName, Department) VALUES ('Alice', 'Williams', 'IT');";
    pConnection->Execute(insertSQL, NULL, adCmdText);
    printf("插入成功!\n\n");
    // 8. 清理资源
Cleanup:
    if (pRecordset != NULL)
    {
        if (pRecordset->State == adStateOpen)
        {
            pRecordset->Close();
        }
        pRecordset.Release();
        pRecordset = NULL;
    }
    if (pConnection != NULL)
    {
        if (pConnection->State == adStateOpen)
        {
            pConnection->Close();
        }
        pConnection.Release();
        pConnection = NULL;
    }
    // 9. 反初始化 COM 库
    CoUninitialize();
    printf("程序执行完毕,\n");
    system("pause"); // 暂停,以便查看输出
}

编译和运行

如果你使用的是 Visual Studio:

  1. 创建一个新的 "Windows 桌面控制台应用" 项目(确保使用 C++ 模板,因为 C 项目无法直接链接 C++ 库,但我们可以通过一些技巧或直接创建 C++ 项目但用 C 语法来写)。
  2. 将上面的代码复制到 .cpp 文件中(main.cpp)。
  3. 编译并运行,Visual Studio 会自动链接 msado15.lib

如果你使用的是 命令行 (cl.exe):

# 假设代码文件是 ado_access_example.c
cl ado_access_example.c /link msado15.lib ole32.lib

然后运行生成的 ado_access_example.exe

重要提示: 运行此程序时,请确保:

  1. 你的系统安装了 Microsoft Access Database Engine,如果你的电脑上没有安装 Office,你可能需要单独下载并安装这个引擎(64 位版本或 32 位版本,需要与你的编译器和应用程序匹配),这是 Provider=Microsoft.ACE.OLEDB.12.0; 能够工作的前提。
  2. 代码中的数据库文件路径是绝对正确的。

常见问题与注意事项

  1. HRESULT 错误: ADO 函数返回 HRESULT,你需要检查它是否为 S_OKSUCCEEDED 宏,如果失败,可以使用 GetErrorInfo 获取更详细的错误信息,但这在 C 中比较繁琐。
  2. COM 对象的生命周期: 使用 CreateInstance 创建对象后,必须使用 Release() 方法来释放它,这是 COM 的引用计数机制,否则会导致内存泄漏。
  3. _bstr_tVARIANT: ADO 内部使用 BSTR(一种 COM 字符串)和 VARIANT(一种通用数据类型)来传递数据。_bstr_t 是 C++ 的一个智能指针类,可以极大地简化 BSTR 的内存管理,在纯 C 语言中,你需要手动调用 SysAllocStringSysFreeString,非常麻烦,这也是为什么这个例子虽然后缀是 .c,但使用了 C++ 特性,或者建议直接创建 C++ 项目的原因。
  4. 32位 vs 64位:
    • 你的编译器、ADO 库、Access 数据库引擎和应用程序必须是统一的平台(要么全是 32 位,要么全是 64 位)。
    • 如果你编译的是 32 位程序,在 64 位 Windows 上运行,它会使用 WOW64 子系统去访问 32 位的驱动和库,反之,64 位程序无法直接加载 32 位 DLL。
    • 最常见的错误是 "Microsoft.ACE.OLEDB.12.0" 提供程序未找到,这通常是因为平台不匹配。
  5. SQL 注入: 如果你的 SQL 语句来自用户输入,绝对不要直接拼接字符串,应该使用参数化查询(_CommandPtr 对象的 Parameters 集合)来防止 SQL 注入攻击。

使用 C 语言和 ADO 操作 Access 数据库的流程可以总结为:

  1. 初始化 COM (CoInitialize)。
  2. 创建 ADO 对象 (_ConnectionPtr, _RecordsetPtr 等)。
  3. 构建连接字符串
  4. 打开连接 (pConnection->Open)。
  5. 执行命令或查询 (pConnection->ExecutepRecordset->Open)。
  6. 处理记录集 (遍历、读取字段值)。
  7. 关闭和释放对象 (Close, Release)。
  8. 反初始化 COM (CoUninitialize)。

尽管这个技术栈看起来有些复古,但它在理解 Windows 底层数据库访问机制方面是一个很好的实践,对于新的项目,如果你必须使用 C 语言,可以考虑更直接、更底层的 ODBC API,或者使用 C++ 来获得更现代、更安全的编程体验。

-- 展开阅读全文 --
头像
织梦如何获取当前点击的图片地址?
« 上一篇 今天
C语言drawpixel函数如何使用?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]