wxSQLite3 的使用,MFC 应用编程
1. VS2022 创建立MFC默认多文档程序框架
简单起见,都在APP类中测试
打印输出在底部的OutputWnd类的窗口中
2. 配置属性修改:
2.1 用多字节字符集,简化编程
2.2 使用MFC静态库,减少依赖
3. 基本框架修改:
在APP类中增加OnFileOpen菜单消息响应函数,把原来的注释掉,测试程序直接写在OnFileOpen中。
在APP类中增加两个打印函数,并定义成宏,方便调试,具体的输出定义在OutputWnd类中,
因为都是保护变量,需要在主框架MainFrm中定义相关的中间调用函数,
4. 本来打算用编译好的wsSQLite3的静态库,但是加入后和MFC的库中函数重复定义,就干脆用wxSQLite3的源文件。
4.1把wxsqlite3-4.5.1.zip\wxsqlite3-4.5.1\sqlite3secure\src 下所有的文件复制到工程的工作目录,
4.2. 把sqlite3.h和sqlite3secure.c加入工程,对sqlite3secure.c的属性修改为不用预编译头
4.3 工程配置属性 AllConfigurations,C/C++, 预处理, 预处理定义, 中加入
SQLITE_ENABLE_RTREE
SQLITE_ENABLE_COLUMN_METADATA
SQLITE_HAS_CODEC=1
SQLITE3ENCRYPT_EXPORTS
SQLITE_ENABLE_FTS3
SQLITE_ENABLE_FTS3_PARENTHESIS
SQLITE_SECURE_DELETE
SQLITE_SOUNDEX
CODEC_TYPE=CODEC_TYPE_AES256
4.4 编译时codec.c 函数不安全告警,按msdn的说明在文件中关闭告警。
#pragma warning(disable : 4996)
5.主要程序段:
5.1 MFCwxSqliteTest.h
// MFCwxSqliteTest.h : main header file for the MFCwxSqliteTest application // #pragma once #ifndef __AFXWIN_H__ #error "include 'pch.h' before including this file for PCH" #endif #include "resource.h" // main symbols #include "sqlite3.h" #define PRINT theApp.PrintDebug // CMFCwxSqliteTestApp: // See MFCwxSqliteTest.cpp for the implementation of this class // class CMFCwxSqliteTestApp : public CWinAppEx { public: CMFCwxSqliteTestApp() noexcept; int PrintDebug(TCHAR* fmt, ...); int PrintDebug(CString str); //static int sqlcallback(void* NotUsed, int argc, char** argv, char** azColName); static int callback(void* NotUsed, int argc, char** argv, char** azColName); static int callback2(void* data, int argc, char** argv, char** azColName); // Overrides public: virtual BOOL InitInstance(); virtual int ExitInstance(); // Implementation UINT m_nAppLook; BOOL m_bHiColorIcons; virtual void PreLoadState(); virtual void LoadCustomState(); virtual void SaveCustomState(); afx_msg void OnAppAbout(); DECLARE_MESSAGE_MAP() afx_msg void OnFileOpen(); }; extern CMFCwxSqliteTestApp theApp;
5.2 MFCwxSqliteTest.cpp
// MFCwxSqliteTest.cpp : Defines the class behaviors for the application. // #include "pch.h" #include "framework.h" #include "afxwinappex.h" #include "afxdialogex.h" #include "MFCwxSqliteTest.h" #include "MainFrm.h" #include "ChildFrm.h" #include "MFCwxSqliteTestDoc.h" #include "MFCwxSqliteTestView.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CMFCwxSqliteTestApp BEGIN_MESSAGE_MAP(CMFCwxSqliteTestApp, CWinAppEx) ON_COMMAND(ID_APP_ABOUT, &CMFCwxSqliteTestApp::OnAppAbout) // Standard file based document commands ON_COMMAND(ID_FILE_NEW, &CWinAppEx::OnFileNew) //ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen) // Standard print setup command ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinAppEx::OnFilePrintSetup) ON_COMMAND(ID_FILE_OPEN, &CMFCwxSqliteTestApp::OnFileOpen) END_MESSAGE_MAP() // CMFCwxSqliteTestApp construction CMFCwxSqliteTestApp::CMFCwxSqliteTestApp() noexcept { m_bHiColorIcons = TRUE; m_nAppLook = 0; // support Restart Manager m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS; #ifdef _MANAGED // If the application is built using Common Language Runtime support (/clr): // 1) This additional setting is needed for Restart Manager support to work properly. // 2) In your project, you must add a reference to System.Windows.Forms in order to build. System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException); #endif // TODO: replace application ID string below with unique ID string; recommended // format for string is CompanyName.ProductName.SubProduct.VersionInformation SetAppID(_T("MFCwxSqliteTest.AppID.NoVersion")); // TODO: add construction code here, // Place all significant initialization in InitInstance } // The one and only CMFCwxSqliteTestApp object CMFCwxSqliteTestApp theApp; // CMFCwxSqliteTestApp initialization BOOL CMFCwxSqliteTestApp::InitInstance() { // InitCommonControlsEx() is required on Windows XP if an application // manifest specifies use of ComCtl32.dll version 6 or later to enable // visual styles. Otherwise, any window creation will fail. INITCOMMONCONTROLSEX InitCtrls; InitCtrls.dwSize = sizeof(InitCtrls); // Set this to include all the common control classes you want to use // in your application. InitCtrls.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&InitCtrls); CWinAppEx::InitInstance(); // Initialize OLE libraries if (!AfxOleInit()) { AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE; } AfxEnableControlContainer(); EnableTaskbarInteraction(); // AfxInitRichEdit2() is required to use RichEdit control // AfxInitRichEdit2(); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need // Change the registry key under which our settings are stored // TODO: You should modify this string to be something appropriate // such as the name of your company or organization SetRegistryKey(_T("Local AppWizard-Generated Applications")); LoadStdProfileSettings(4); // Load standard INI file options (including MRU) InitContextMenuManager(); InitKeyboardManager(); InitTooltipManager(); CMFCToolTipInfo ttParams; ttParams.m_bVislManagerTheme = TRUE; theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL, RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams); // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate(IDR_MFCwxSqliteTestTYPE, RUNTIME_CLASS(CMFCwxSqliteTestDoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(CMFCwxSqliteTestView)); if (!pDocTemplate) return FALSE; AddDocTemplate(pDocTemplate); // create main MDI Frame window CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME)) { delete pMainFrame; return FALSE; } m_pMainWnd = pMainFrame; // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // Dispatch commands specified on the command line. Will return FALSE if // app was launched with /RegServer, /Register, /Unregserver or /Unregister. if (!ProcessShellCommand(cmdInfo)) return FALSE; // The main window has been initialized, so show and update it pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); return TRUE; } int CMFCwxSqliteTestApp::ExitInstance() { //TODO: handle additional resources you may have added AfxOleTerm(FALSE); return CWinAppEx::ExitInstance(); } // CMFCwxSqliteTestApp message handlers // CAboutDlg dialog used for App About class CAboutDlg : public CDialogEx { public: CAboutDlg() noexcept; // Dialog Data #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support // Implementation protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() noexcept : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // App command to run the dialog void CMFCwxSqliteTestApp::OnAppAbout() { CAboutDlg aboutDlg; aboutDlg.DoModal(); } // CMFCwxSqliteTestApp customization load/save methods void CMFCwxSqliteTestApp::PreLoadState() { BOOL bNameValid; CString strName; bNameValid = strName.LoadString(IDS_EDIT_MENU); ASSERT(bNameValid); GetContextMenuManager()->AddMenu(strName, IDR_POPUP_EDIT); bNameValid = strName.LoadString(IDS_EXPLORER); ASSERT(bNameValid); GetContextMenuManager()->AddMenu(strName, IDR_POPUP_EXPLORER); } void CMFCwxSqliteTestApp::LoadCustomState() { } void CMFCwxSqliteTestApp::SaveCustomState() { } // CMFCwxSqliteTestApp message handlers //sql执行回调函数 int CMFCwxSqliteTestApp::callback(void* NotUsed, int argc, char** argv, char** azColName) { int i; for (i = 0; i < argc; i++) { PRINT("%s = %s", azColName[i], argv[i] ? argv[i] : "NULL"); } return 0; } int CMFCwxSqliteTestApp::callback2(void* data, int argc, char** argv, char** azColName) { int i; PRINT("%s: ", (const char*)data); for (i = 0; i < argc; i++) { PRINT("%s = %s", azColName[i], argv[i] ? argv[i] : "NULL"); } //printf("\n"); return 0; } void CMFCwxSqliteTestApp::OnFileOpen() { // TODO: Add your command handler code here sqlite3* db = NULL; char* zErrMsg = 0; int rc = 0; char* sql = NULL; const char* data = "Callback function called"; CFileDialog dlgFile(TRUE, _T("DataBase File(*.db)|*.DB"), _T("Test.db"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("DataBase File(*.db)|*.db|RTF Files (*.rtf)|*.rtf|All Files (*.*)|*.*||"), NULL); if (IDOK == dlgFile.DoModal()) { PRINT(dlgFile.GetPathName()); rc = sqlite3_open(dlgFile.GetPathName(), &db); rc = sqlite3_key(db, "password", 8); //使用密码,第一次为设置密码,以后为解密,最后是密码长度 printf("\n rc = %d", rc); //rc = sqlite3_rekey(db,NULL,0); //清空密码 //rc = sqlite3_rekey(db,"password2",9); //修改密码 //创建一张表 sql = "CREATE TABLE COMPANY(" \ "ID INT PRIMARY KEY NOT NULL," \ "NAME TEXT NOT NULL," \ "AGE INT NOT NULL," \ "ADDRESS CHAR(50)," \ "SALARY REAL );"; rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg); //插入一些记录 sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " \ "VALUES (1, 'Paul', 32, 'California', 20000.00 ); " \ "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " \ "VALUES (2, 'Allen', 25, 'Texas', 15000.00 ); " \ "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \ "VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );" \ "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \ "VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );"; rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg); //查询记录,并在回调函数中打印记录 sql = "SELECT * from COMPANY"; rc = sqlite3_exec(db, sql, callback2, (void*)data, &zErrMsg); if (rc != SQLITE_OK) { printf("SQL error: %s\n", zErrMsg); sqlite3_free(zErrMsg); } else { printf("Operation done successfully\n"); } //关闭数据库 sqlite3_close(db); } } int CMFCwxSqliteTestApp::PrintDebug(TCHAR* fmt, ...) { TCHAR buffer[10240]; va_list argptr; int cnt; va_start(argptr, fmt); //cnt = _vstprintf(buffer, fmt, argptr); // A or W but ISO C cnt = _vstprintf_s(buffer, 10240, fmt, argptr); // A or W but ISO C //cnt = swprintf(buffer, fmt, argptr); // only W //cnt = wsprintf(buffer, fmt, argptr); // not %f va_end(argptr); ((CMainFrame*)m_pMainWnd)->PrintDebug(buffer); return(cnt); } int CMFCwxSqliteTestApp::PrintDebug(CString str) { return PrintDebug(str.GetBuffer()); }
5.2 COutputWnd.cpp 改动很少,就贴个打印函数,MFC自动生成的大段代码就不贴了。
void COutputWnd::PrintDebug(TCHAR* str) { int iCount = m_wndOutputBuild.GetCount(); if (iCount > 100) { for (int i = 0; i < 10; i++) { m_wndOutputBuild.DeleteString(0); } } m_wndOutputBuild.AddString(str); iCount = m_wndOutputBuild.GetCount(); m_wndOutputBuild.SetCurSel(iCount - 1); }
5.3 另外MainFrm中加了个打印函数,很小的改动,不贴了。
6.运行结果