You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ SQLite代码在AutoCAD ObjectARX环境运行时异常如何解决

问题现象

我正在测试一段简单的C++ SQLite代码:

sqlite3* db;
if (sqlite3_open("SteelTable.db", &db) != SQLITE_OK) { 
    sqlite3_close(db);
    return 0;
}

std::string createQuery = "CREATE TABLE WFPROFILE ("
    "ID   INT PRIMARY KEY     NOT NULL,"
    "D    REAL    NOT NULL,"
    "WT   REAL    NOT NULL,"
    "WB   REAL    NOT NULL,"
    "TF   REAL    NOT NULL,"
    "TB   REAL    NOT NULL);";

sqlite3_stmt* createStmt;
sqlite3_prepare(db, createQuery.c_str(), static_cast<int>(createQuery.size()), &createStmt, nullptr);
if (sqlite3_step(createStmt) != SQLITE_DONE) {
    sqlite3_close(db);
    return 0;
}

std::vector<std::string> sqlStmList;
sqlStmList.emplace_back("INSERT INTO WFPROFILE ('ID','D','WT','WB','TF','TB') VALUES ('1','20','10','15','1','1.5');");
sqlStmList.emplace_back("INSERT INTO WFPROFILE ('ID','D','WT','WB','TF','TB') VALUES ('2','25','12','17','2.5','2');");
sqlStmList.emplace_back("INSERT INTO WFPROFILE ('ID','D','WT','WB','TF','TB') VALUES ('3','30','14','19.5','2.5','2.5');");

for (const auto& insertQuery : sqlStmList) {
    sqlite3_stmt* insertStmt;
    sqlite3_prepare(db, insertQuery.c_str(), static_cast<int>(insertQuery.size()), &insertStmt, nullptr);
    if (sqlite3_step(insertStmt) != SQLITE_DONE) {
        sqlite3_close(db);
        return 0;
    }
    
}

sqlite3_close(db);

该代码在控制台可执行程序中运行正常,但将相同代码集成到AutoCAD的ObjectARX C++项目中时,执行到CREATE TABLE语句的位置会抛出运行时异常。

可尝试的修复方案
  • 运行时库版本匹配问题
    AutoCAD本身采用/MD(多线程动态DLL)运行时库编译,若你使用的SQLite预编译库、自行编译的SQLite库采用的运行时库(/MT、/MDd等)与ObjectARX项目的运行时库配置不一致,跨模块内存分配释放时会触发异常。
    修复方式:使用与ObjectARX项目完全匹配的编译器版本(如AutoCAD 2024对应VS2022、AutoCAD 2020对应VS2017),选择相同的运行时库选项重新编译SQLite源码,不要使用第三方预编译的SQLite库。

  • 修正现有代码逻辑错误
    你的代码存在两处可直接触发崩溃的逻辑问题,在宽松的控制台运行环境未触发异常,但在ObjectARX的严格内存管理机制下会直接报错:

  1. sqlite3_open返回非SQLITE_OK时,db指针为无效值,此时调用sqlite3_close(db)属于野指针访问;
  2. 未判断sqlite3_prepare的返回值,若语句编译失败,createStmt为无效指针,后续调用sqlite3_step会直接触发内存访问错误。
    修正后的核心逻辑参考:
sqlite3* db = nullptr;
int ret = sqlite3_open("SteelTable.db", &db);
if (ret != SQLITE_OK) { 
    // 打开失败不需要close无效db指针,可打印错误信息
    acutPrintf(_T("SQLite open failed: %s\n"), sqlite3_errmsg(db));
    return 0;
}

std::string createQuery = "CREATE TABLE IF NOT EXISTS WFPROFILE ("
    "ID   INT PRIMARY KEY     NOT NULL,"
    "D    REAL    NOT NULL,"
    "WT   REAL    NOT NULL,"
    "WB   REAL    NOT NULL,"
    "TF   REAL    NOT NULL,"
    "TB   REAL    NOT NULL);";

sqlite3_stmt* createStmt = nullptr;
ret = sqlite3_prepare_v2(db, createQuery.c_str(), static_cast<int>(createQuery.size()), &createStmt, nullptr);
if (ret != SQLITE_OK) {
    acutPrintf(_T("Prepare failed: %s\n"), sqlite3_errmsg(db));
    sqlite3_close(db);
    return 0;
}
ret = sqlite3_step(createStmt);
if (ret != SQLITE_DONE) {
    acutPrintf(_T("Step failed: %s\n"), sqlite3_errmsg(db));
    sqlite3_finalize(createStmt); // 注意prepare成功后要先释放stmt再关闭db
    sqlite3_close(db);
    return 0;
}
sqlite3_finalize(createStmt); // 正常执行完也要释放stmt资源

此外建议用sqlite3_prepare_v2替代已经过时的sqlite3_prepare接口,错误处理和兼容性更好。

  • 路径权限问题
    ObjectARX插件运行时的默认工作目录为AutoCAD安装目录,普通用户默认没有该目录的写入权限,sqlite3_open用相对路径打开数据库时会创建失败。你可以将数据库路径修改为绝对路径(比如插件所在目录、我的文档目录等有写入权限的路径)测试是否恢复正常。

  • 字符集适配问题
    ObjectARX项目默认使用Unicode字符集,确认你编译的SQLite未强制开启UTF16编码选项,传入的SQL语句字符串为标准UTF8编码,避免解析错误导致的内存越界。

内容的提问来源于stack exchange,提问作者sidb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 15:54:03