0

我在尝试启动我的应用程序时遇到此错误,我已将问题隔离到此代码功能,但我不明白为什么会发生这种情况......

void checkDB()
{
    sqlite3 *db;
    int rc=0;
    size_t i;
    char *zErrMsg = 0;

    HMODULE hModule = GetModuleHandleW(NULL);
    WCHAR path[MAX_PATH];
    char buffer[MAX_PATH*4];
    int len;
    GetModuleFileNameW(hModule, path, MAX_PATH);
    len =lstrlenW(path);
    path[len-13]='\0';
    buffer[0]='\0';

    wcscat_s(path,sizeof(path),L"test.db\0");
    GetFileAttributes(path);
    if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(path) && GetLastError()==ERROR_FILE_NOT_FOUND)
    {
        wcstombs_s(&i,buffer,sizeof(buffer), path, wcslen(path) );
        rc= sqlite3_open(buffer,&db);

        rc=sqlite3_exec(db,"create table Recipe (Recipe_Num INTEGER PRIMARY KEY AUTOINCREMENT, Recipe_Image VARCHAR(30), Recipe_Name VARCHAR(200))",NULL,0,&zErrMsg);
        sqlite3_free(zErrMsg);
        rc=sqlite3_exec(db,"create table Recipe_Step (Recipe_Num INTEGER, Step_Num INTEGER, Description VARCHAR(2000))",NULL,0,&zErrMsg);
        if(rc!=SQLITE_OK)
        {
            sqlite3_close(db);
        }
        else
        {
        sqlite3_close(db);
        }
    }

}
4

1 回答 1

1

您是否有可能超出某些原始char/WCHAR缓冲区?

我建议您对代码进行现代化改造并使用健壮的字符串类,例如std::wstringCString[W]使用它们的运算符重载,而不是原始数组和原始 C 字符串函数,例如wcscat_s()(您正在滥用:您应该传递_countof(path)而不是sizeof(path),因为“大小”必须是以WCHARs 表示,而不是字节)。

并且要将 Unicode UTF-16 转换为 ANSI/MBCS,您可以使用ATL 助手,例如CW2A而不是wcstombs_s().

例如:

// Assume Unicode builds, so GetModuleFileName is actually GetModuleFileNameW,
// CString is CStringW, etc.

CString strPath;
WCHAR* pszPath = strPath.GetBuffer(MAX_PATH);
GetModuleFileName(hModule, pszPath, MAX_PATH);
// check GetModuleFileName()'s return value...
strPath.ReleaseBuffer();

// Operate on strPath using operator+= to concatenate strings, etc.
strPath += L"test.db";

....

if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(strPath) && GetLastError()==ERROR_FILE_NOT_FOUND)
{
    // Convert from UTF-16 to ANSI
    CW2A buffer(strPath);
    rc = sqlite3_open(buffer, &db);
    ....

}

此外,您正在泄漏字符串内存,因为您sqlite3_free(zErrMsg)在第二次调用sqlite3_exec(). 我建议使用 RAII 模式和 C++ 析构函数的强大功能来尝试编写自动释放资源的代码。您可以在这些字符串上编写一个简单的包装器,sqlite3_free()在析构函数中调用,例如:

class SqlLiteErrorMsg
{
public:   
    SqlLiteErrorMsg()
       : errorMsg(nullptr)
    {}

    ~SqlLiteErrorMsg()
    {
        sqlite3_free(errorMsg);
    }

    char** GetAddressOf()
    {
        return &errorMsg;
    }    

    char* Get()
    {
        return errorMsg;
    }

private:
    // Ban copy
    SqlLiteErrorMsg(const SqlLiteErrorMsg&);
    SqlLiteErrorMsg& operator=(const SqlLiteErrorMsg&);

    char* errorMsg;
};

可以围绕sqlite3*指针构建类似的包装器。

于 2013-03-28T19:13:02.397 回答