2016-08-08 18 views
0

Also ich versuche, SQLite mit MFC-Dialogen in Visual Studio 2010 zu verwenden. Ich bin unklar, wie die Rückruffunktion zu verwenden, um das Ergebnis der Abfrage zu speichern, die versucht wird Zählen Sie die Anzahl der Tabellen in meiner Datenbank in die Variable m_Results. Gibt es das überhaupt, oder muss ich trotzdem auf die Variable nTables zugreifen?C++ MFC SQLite sqlite3_exec Callback

static int callback(void *data, int argc, char **argv, char **azColName){ 
    int i; 
    fprintf(stderr, "%s: ", (const char*)data); 
    data = argv[0]; 
    return 0; 
} 

BOOL CDBpracticeDlg::OnInitDialog(){ 
    ... 

    // TODO: Add extra initialization here 
    sqlite3 *db; 
    char *zErrMsg = 0; 
    int rc; 
    char *sql; 
    const char* data = "Callback function called"; 

    rc = sqlite3_open("structInfo_Test.db", &db); 

    if(rc){ 
     fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); 
     return(0); 
    }else{ 
     fprintf(stderr, "Opened database successfully\n"); 
    } 

    /* Create SQL statement */ 
    sql = "Select Count(*) as nTables FROM sqlite_master where type='table';"; 

    /* Execute SQL statement */ 
    rc = sqlite3_exec(db, sql, callback, &m_Results, &zErrMsg); 
    if(rc != SQLITE_OK){ 
     char error[200]; 
     strcpy(error,"SQL error: "); 
     strcat(error,zErrMsg); 
     m_Results = error; 
     fprintf(stderr, "SQL error: %s\n", zErrMsg); 
     sqlite3_free(zErrMsg); 
    }else{ 
     fprintf(stdout, "Operation done successfully\n"); 
    } 
    UpdateData(FALSE); 
    sqlite3_close(db); 

    return TRUE; // return TRUE unless you set the focus to a control 
} 

Antwort

1

Der Rückruf für die sqlite3_exec API ist weit underdocumented. Die Tatsache, dass es mit irreführenden Parameternamen behauptet wird, hilft auch nicht viel. natürlichere formalen Parameternamen Providing geht ein langer Weg:

static int callback(void* context, // user-provided object (4th param to sqlite3_exec) 
        int columnCount,  // number of columns 
        char** columnValues, // array of column values as C-style strings 
        char** columnName) // array of column names as C-style strings 

das m_Results Objekt aus dem callback zu aktualisieren, müssen Sie einfach Kontext auf den richtigen Typ werfen, und verwenden Sie diese:

static int callback(void* context, int columnCount, 
        char** columnValues, char** columnNames) { 
    CMyType& results = *static_cast<CMyType*>(context); 
    // Use 'results' which is a reference to 'm_Results'. 
    for (int index = 0; index < columnCount; ++index) { 
     // Assuming CMyType has operator+=(const char*) (like a CString) 
     results += columnNames[index]; 
     results += ": "; 
     results += columnValues[index]; 
    } 
    // Return 0 to continue invoking the callback for the remaining rows in the result 
    // set. Returning non-zero will terminate the callbacks, and sqlite3_exec() 
    // returns SQLITE_ABORT. 
    return 0; 

Alternativ können Sie this anstelle von &m_Results an sqlite3_exec() übergeben und ein öffentliches Klassenmitglied aus Ihrem Rückruf aufrufen:

static int callback(void* context, int columnCount, 
        char** columnValues, char** columnNames) { 
    CDBpracticeDlg* obj = static_cast<CDBpracticeDlg*>(context); 
    // Delegate callback to class member implementation 
    return obj->MyCallback(columnCount, columnValues, columnNames); 
} 

... 

rc = sqlite3_exec(db, sql, callback, this, nullptr); 
+0

Danke für Ihre Antwort. Ich habe versucht, Sie Lösung, aber ich bekam Fehler mit der Ergebnisse + = columnNames [index]; Wie verketten Sie zwei Zeiger? –

+0

@ J.Ting: Übergeben Sie den CString an die Funktion. Warum sollten Sie sich mit den Zeigern beschäftigen, wenn Sie bereits MFC – cha

+0

@J.Ting haben: Da Sie uns nie gesagt haben, welcher Typ 'm_Results' ist, musste ich einen annehmen. Diese Antwort demonstrierte, wie Daten an den Rückruf übergeben werden. Sie müssen die Details zur Verwendung dieser Daten selbst ausarbeiten. – IInspectable