zoukankan      html  css  js  c++  java
  • 安全传输平台项目——配置管理终端-框架搭建-初始化

    在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

    10-安全传输平台项目-第09天(配置管理终端-框架搭建-初始化)

    目录:
    一、复习
    1、复习数据库写入
    2、复习框架导入
    》创建MFC项目
    二、安全传输平台项目——配置管理终端-框架搭建-初始化
    1、重画背景onDraw
    2、界面切换-CCfgView
    3、界面切换-网点信息管理界面NetInfo
    4、多态知识回顾
    5、多态分析和开源源码走读
    6、小结
    7、管理终端功能简析
    8、初始化-获取配置文件路径
    9、创建对话框
    10、弹窗供用户输入信息
    11、将用户录入数据保存ini文件
    12、全局变量赋值及取消按钮
    13、测试连接数据库
    14、总结

    一、复习

    1、复习数据库写入
    2、复习框架导入

    》创建MFC项目:

    主函数(类似于main)在SecMngAdmin0325.cpp中。

    界面部分在MainFrm.cpp中,需要在其中添加启动的样式:

    1)切换到“类视图”,在“CMainFrame”右键选择“类向导”,选择“类向导”,点击“虚函数”,点击“OnCreateClient”,点击“应用”,点击“确定”。

    然后在其中添加代码:

    >CMainFrame::OnCreateClient重写代码如下:

    BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
    {
        // TODO: 在此添加专用代码和/或调用基类
        if (!wndSplitter.CreateStatic(this, 1, 2)) return false;
    
        if (!wndSplitter.CreateView(0, 1,RUNTIME_CLASS(CFormBackground), CSize(0,0), pContext))     
            return false;
    
        //pContext->m_pNewViewClass RUNTIME_CLASS(CFormUserManager) CFormUserManager
        DWORD dwf = CGfxOutBarCtrl::fDragItems|
            CGfxOutBarCtrl::fEditGroups|
            CGfxOutBarCtrl::fEditItems|
            CGfxOutBarCtrl::fRemoveGroups|
            CGfxOutBarCtrl::fRemoveItems|
            CGfxOutBarCtrl::fAddGroups|
            CGfxOutBarCtrl::fAnimation; 
    
        wndBar.Create(WS_CHILD|WS_VISIBLE, CRect(0,0,0,0), &wndSplitter, 
            wndSplitter.IdFromRowCol(0, 0), dwf);
        wndBar.SetOwner(this);
    
        imaLarge.Create(32, 32, true, 2, 1);
        HICON hIcon;
    
        for (int i=0; i<7; ++i) 
        {
            hIcon= AfxGetApp()->LoadIcon (nImages[i]);
            imaLarge.Add (hIcon);
        }
    
        wndBar.SetImageList(&imaLarge, CGfxOutBarCtrl::fLargeIcon);
        wndBar.SetImageList(&imaSmall, CGfxOutBarCtrl::fSmallIcon);
    
        wndTree.Create(WS_CHILD|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS|TVS_SHOWSELALWAYS, 
            CRect(0,0,0,0), &wndBar, 1010);
        wndTree.SetImageList(&imaSmall, TVSIL_NORMAL);    
        wndBar.SetAnimationTickCount(20);    
        wndBar.SetAnimSelHighlight(200);
    
        wndBar.AddFolder("SecMngServer配置管理", 0);
        wndBar.AddFolder("SecMngAdmin网点管理", 1);
        wndBar.AddFolder("人员管理", 2);
        wndBar.AddFolder("设备管理", 3);
        //wndBar.AddFolder("CA人员操作查询", 4);    
    
        wndBar.InsertItem(0, 0, "SecMngServer配置", 0, 0);
        wndBar.InsertItem(0, 1, "网点信息管理", 1, 0); 
        wndBar.InsertItem(0, 2, "后台业务管理", 4, 0); //
        wndBar.InsertItem(0, 3, "后台交易查询", 5, 0); //
    
        wndBar.InsertItem(1, 0, "前台体系管理", 6, 0);     
        wndBar.InsertItem(1, 1, "前台业务管理", 4, 0);
        wndBar.InsertItem(1, 2, "前台交易查询", 3, 0); 
    
        wndBar.InsertItem(2, 0, "创建人员", 3, 0); 
        wndBar.InsertItem(2, 1, "冻结人员", 4, 0); 
        wndBar.InsertItem(2, 2, "解冻", 2, 0); 
        wndBar.InsertItem(2, 3, "注销人员", 1, 0);     
    
        wndBar.InsertItem(3, 0, "创建设备", 5, 0); 
        wndBar.InsertItem(3, 1, "注销管理", 4, 0); 
    
        wndBar.SetSelFolder(0);
    
        CRect r;
        GetClientRect(&r);
        int w1 = r.Width()/5;
        int w2 = r.Width()/4;
    
        wndSplitter.SetColumnInfo( 0, w1, 0 );
        wndSplitter.SetColumnInfo( 1, w2, 0 );
        wndSplitter.RecalcLayout();
        return true;
    
        //return CFrameWndEx::OnCreateClient(lpcs, pContext);
    }
    CMainFrame::OnCreateClient

    2)在MainFrm.h中,包含相应头文件,添加对象变量定义
    添加

    #include "GfxSplitterWnd.h"
    #include "GfxOutBarCtrl.h"

    然后在class CMainFrame: public CFrameWnd中添加声明:

    // 特性
    public:
        CGfxSplitterWnd        wndSplitter;
        CGfxOutBarCtrl        wndBar;       
        CImageList            imaLarge, imaSmall;       
        CTreeCtrl            wndTree;

    3)这时编译运行,只剩两个错误:

    先解决第二个错误:

    在 CMainFrame::OnCreateClient函数之前添加定义nImages:

    static UINT nImages[] =
    {
        IDI_ICON_SET,
        IDI_ICON_USER,
        IDI_ICON_OP_LOG,
        IDI_ICON_LOG,
        IDI_ICON_REQ,
        IDI_ICON_RE,
        IDI_ICON_REPORT,
    };

    然后添加7张图片:

    ico目录下有(log.ico、op_log.ico、re.ico、report.ico、req.ico、set.ico、user.ico)7个ico图片放入项目的文件夹的下一级res目录下;然后打开“资源视图”,在“secmngAdmin411.rc”右键“添加资源”,点击“导入”,选择这7个ico文件,点击“打开”(这时多了一个Icon目录,里面有这7个文件),右键“属性”进行设置ID:

    其ID 更改:IDC_ICON7(人图标)更改为:IDI_ICON_USER;
    IDC_ICON6更改为:IDI_ICON_SET;
    IDC_ICON5更改为:IDI_ICON_REQ;
    IDC_ICON4更改为:IDI_ICON_REPORT;
    IDC_ICON3更改为:IDI_ICON_RE;
    IDC_ICON2更改为:IDI_ICON_OP_LOG;
    IDC_ICON1更改为:IDI_ICON_LOG;

    注意,每步更改后,点击“都保存”,会弹出警告-修改影响多处,点击“是”。

    4)这时编译运行,只剩1个错误:

    打开“资源视图”,添加“Dialog”:

    在资源视图左侧“Dialog”处右键“插入Dialog”,然后删除“确定”和“取消”按钮,修改对话框的ID(在“IDD_DIALOG1”右键“属性”进行修改ID为:IDD_FORMBACKGROUND_FORM);

    点击对话框,修改属性:修改Border属性“外框对话框”配置成None;Style属性“Popup”配置成child

    点击对话框,右键“添加类”(或者“双击”),然后输入类名:CFormBackground,基类选择: CFormView

    然后,包含类对象:在MainFrm.h头文件中添加   #include "FormBackground.h"

    最后点击“运行”,会弹出:

    二、安全传输平台项目——配置管理终端-框架搭建-初始化

    1、重画背景onDraw

    1)切换到“类视图”,选择“CFormBackground”,右键点击“类向导”,选择“虚函数”:

    然后在其中添加代码:

    >CFormBackground::OnDraw重写代码如下:(注意:函数注释掉的参数pDC打开!

    void CFormBackground::OnDraw(CDC* pDC)
    {
        // TODO: 在此添加专用代码和/或调用基类
        CRect clientRect;
        GetClientRect(&clientRect);    
    
        for(int k = 13 ;k< 18;k++) //绘图示例—显示位图
        {
            CBrush* pTempBrush = NULL;
            CBrush OrigBrush;
            OrigBrush.FromHandle((HBRUSH)pTempBrush); 
    
            CRect rc;
            GetClientRect(&rc);
            //ScreenToClient(&rc);
            try
            {
                CBitmap bmp;
                bmp.LoadBitmap(IDB_BITMAP_BACK);
                CBrush brush(&bmp);
    
                pTempBrush = (CBrush*)pDC->SelectObject(brush);
    
                pDC->Rectangle(rc.left,rc.top, rc.Width(), rc.Height());
                pDC->SelectObject(&OrigBrush);
                break;
            }
            catch(CResourceException* e)
            {
                e->ReportError();
                e->Delete();
            }            
        }
    
        CRect rect;
        GetClientRect(&rect);
        CRect rect2;
        GetClientRect(&rect2);
    
        CFont font ;
        font.CreatePointFont(340, _T("Arial"));
        CString string = "欢迎使用KeyMngServer管理终端";
    
        pDC->SelectObject(&font);
        pDC->SetBkMode(TRANSPARENT);
        rect.OffsetRect(6, -90); //背影
        pDC->SetTextColor( RGB(192, 192, 192));
        pDC->DrawText(string, &rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER);
    
        rect2.OffsetRect(0, -100);
        pDC->SetTextColor( RGB(0, 0, 0));
        pDC->DrawText(string, &rect2, DT_SINGLELINE|DT_CENTER|DT_VCENTER);    
    
    }
    void CFormBackground::OnDraw(CDC* pDC)

    2)bmp目录下有(background.bmp)1个bmp图片放入项目的文件夹的下一级res目录下;然后打开“资源视图”,在“secmngAdmin411.rc”右键“添加资源”,点击“导入”,选择这1个bmp文件,点击“打开”(这时多了一个Bitmap目录,里面有这7个文件),右键“属性”进行设置ID:

    其ID 更改:IDB_BITMAP1更改为:IDB_BITMAP_BACK;

    最后点击“运行”,会弹出:

    2、界面切换-CCfgView

    CMainFram类中添加视图切换自定义消息

    1)在MainFrm.h中添加自定义消息声明:

    // 生成的消息映射函数
    protected:    
    DECLARE_MESSAGE_MAP()
    afx_msg long OnOutbarNotify(WPARAM wParam, LPARAM lParam);//声明

    2)在MainFrm.cpp中添加自定义消息映射:
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
    … …
    ON_MESSAGE(WM_OUTBAR_NOTIFY, OnOutbarNotify) // 注意不能添加分号!!!
    ……
    END_MESSAGE_MAP()

    3)在MainFrm.cpp中添加消息映射函数的实现

    long CMainFrame::OnOutbarNotify(WPARAM wParam, LPARAM lParam)
    {     
        switch (wParam)
        {        
           case NM_OB_ITEMCLICK:
               // cast the lParam to an integer to get the clicked item
              {
                   int index = (int) lParam;
                   CString cText, cs1;
                   cText = wndBar.GetItemText(index);                
                   CCreateContext   Context;
             
                   if (cText==_T("SecMngServer配置"))
                   {
                       Context.m_pNewViewClass = RUNTIME_CLASS(CCfgView);
                       Context.m_pCurrentFrame = this;
                       Context.m_pLastView = (CView *)wndSplitter.GetPane(0,1);
                       wndSplitter.DeleteView(0,1);
                       wndSplitter.CreateView(0,1,RUNTIME_CLASS(CCfgView),CSize(500,0),&Context);
                       CCfgView *pNewView=(CCfgView *)wndSplitter.GetPane(0,1);                      
                       wndSplitter.RecalcLayout();
                          pNewView->OnInitialUpdate();
                       wndSplitter.SetActivePane(0,1);  
                       //IsHisKeyRecovry=0;           
                   }
                   
                   else if (cText==_T("网点信息管理"))
                   {                   
                       Context.m_pNewViewClass = RUNTIME_CLASS(CDlgNetInfo);
                       Context.m_pCurrentFrame = this;
                       Context.m_pLastView = (CView *)wndSplitter.GetPane(0,1);
                       wndSplitter.DeleteView(0,1);
                       wndSplitter.CreateView(0,1,RUNTIME_CLASS(CDlgNetInfo),CSize(500,0),&Context);
                       CDlgNetInfo *pNewView=(CDlgNetInfo *)wndSplitter.GetPane(0,1);                      
                       wndSplitter.RecalcLayout();
                       pNewView->OnInitialUpdate();
                       wndSplitter.SetActivePane(0,1);
                   }    
                   
                   else if (cText==_T("后台业务管理"))
                   {
                         //AfxMessageBox(cText);
                       Context.m_pNewViewClass = RUNTIME_CLASS(CSysAll);
                       Context.m_pCurrentFrame = this;
                       Context.m_pLastView = (CView *)wndSplitter.GetPane(0,1);
                       wndSplitter.DeleteView(0,1);
                       wndSplitter.CreateView(0,1,RUNTIME_CLASS(CSysAll),CSize(500,0),&Context);
                       CSysAll *pNewView=(CSysAll *)wndSplitter.GetPane(0,1);                      
                       wndSplitter.RecalcLayout();
                       pNewView->OnInitialUpdate();
                       wndSplitter.SetActivePane(0,1); 
                   } 
              }
            
            return 0;
              
            case NM_OB_ONLABELENDEDIT:
                // cast the lParam to an OUTBAR_INFO * struct; it will contain info about the edited item
                // return 1 to do the change and 0 to cancel it
                {
                    /*
                    if(IsLoginOutFlag == 1)
                    {
                        AfxMessageBox("人员已登出,请重新登录CA人员以进行相应操作。");
                        return 1;
                    }
                    */
                    
                    OUTBAR_INFO * pOI = (OUTBAR_INFO *) lParam;
                    TRACE2("Editing item %d, new text:%s
    ", pOI->index, pOI->cText);
                }
                return 1;
                
            case NM_OB_ONGROUPENDEDIT:
                // cast the lParam to an OUTBAR_INFO * struct; it will contain info about the edited folder
                // return 1 to do the change and 0 to cancel it
                {
                    /*
                    if(IsLoginOutFlag == 1)
                    {
                        AfxMessageBox("人员已登出,请重新登录人员以进行相应操作。");
                        return 1;
                    }
                    */
    
                    OUTBAR_INFO * pOI = (OUTBAR_INFO *) lParam;
                    TRACE2("Editing folder %d, new text:%s
    ", pOI->index, pOI->cText);
                }
                return 1;
                
            case NM_OB_DRAGITEM:
                // cast the lParam to an OUTBAR_INFO * struct; it will contain info about the dragged items
                // return 1 to do the change and 0 to cancel it
                {
                    /*
                    if(IsLoginOutFlag == 1)
                    {
                        AfxMessageBox("人员已登出,请重新登录人员以进行相应操作。");
                        return 1;
                    }*/
    
                    OUTBAR_INFO * pOI = (OUTBAR_INFO *) lParam;
                    TRACE2("Drag item %d at position %d
    ", pOI->iDragFrom, pOI->iDragTo);
                }
                return 1;
        }
        return 0;
    }
    long CMainFrame::OnOutbarNotify(WPARAM wParam, LPARAM lParam)

    4)打开“资源视图”,添加“Dialog”:

    (1)在资源视图左侧“Dialog”处右键“插入Dialog”,然后删除“确定”和“取消”按钮,修改对话框的ID(在“IDD_DIALOG2”右键“属性”进行修改ID为:IDD_DIALOG_CFG);

    (2)点击对话框,修改属性:修改Border属性“外框对话框”配置成None;Style属性“Popup”配置成child;

    (3)点击对话框,右键“添加类”,然后输入类名:CCfgView,基类选择: CFormView

    (4)然后,包含类对象:在MainFrm.h头文件中添加   #include "CfgView.h"

    (5)在IDD_DIALOG_CFG的Dialog中添加:

    3、界面切换-网点信息管理界面NetInfo

    (1)在资源视图左侧“Dialog”处右键“插入Dialog”,然后删除“确定”和“取消”按钮,修改对话框的ID(在“IDD_DIALOG3”右键“属性”进行修改ID为:IDD_DIALOG_NETMNG);

    (2)点击对话框,修改属性:修改Border属性“外框对话框”配置成None;Style属性“Popup”配置成child;

    (3)点击对话框,右键“添加类”,然后输入类名:CDlgNetInfo,基类选择: CFormView

    (4)然后,包含类对象:在MainFrom头文件中添加   #include "DlgNetInfo.h"

    (5)在IDD_DIALOG_CFG的Dialog中添加:

    同理,

    为COpTranView类添加Dialog资源(id可以命名:IDD_DIALOG_TRAN)

    CSysAll类添加Dialog资源(id可以命名:IDD_DIALOG_SYSALL)

    4、多态知识回顾

    面向对象:封装(功能相近或相似的代码集成)继承(子类可以使用父类的变量和函数)多态(主要发生在函数调用区间,同样的函数传递不同的参数,调用的结果不同)

    多态机制:

    1)父类指针指向子类对象;2)继承;3)虚函数重写

    》测试:

    class parent
    {
        public:
            virtual void print()
            {
                printf("I am parent.
    ");
            }
    }
    
    class child:public parent
    {
        public:
            virtual void print()
            {
                printf("I am child.
    ");
            }
    }
    
    void howToPrint(parent *p)
    {
        p->print();
    }
    
    int main()
    {
        parent p1;
        child c1;
        howToPrint(&p1);
        howToPrint(&c1);//多态
    }
    test.cpp

    多态实现的原理:1)每个类对象有一个vptr指针,指向虚函数表首地址;2)虚函数表

    5、多态分析和开源源码走读

    为什么重写了OnCreateClient函数,可以实现左侧的样式?

    》项目中的多态分析:

    6、小结:

    》对接开源框架相关:

    1)创建MFC项目;

    2)导入开源文件  9个(.cpp .h);

    3)CString --> const char *  在项目上右键--> 属性 --> 字符集:使用unicode字符集 --> 使用多字节字符集;

      VS2013:如果,上述操作不生效。使用管理员身份运行:vc_mbcsmfc.exe

    4)导入.cur图片资源 --> MFC项目资源目录res中;

    5)“资源视图”标签,任意一个目录上 右键“添加资源”-->“导入”选择res中的.cur 文件(3个)添加到项目中。

    6)根据错误提示,修改ID;

    7)添加消息宏定义 resource.h  -->正常编译

    #define ID_GFX_SMALLICON                50000
    #define ID_GFX_LARGEICON                50001
    #define ID_GFX_RENAMEITEM                50002
    #define ID_GFX_REMOVEITEM                50003
    #define ID_GFX_GROUPICON                 50004
    #define ID_GFX_FONTCICON                 50005
    #define ID_GFX_BACKCICON                 50006

    8)给CMainFrame类 重写父类的 onCreateClient() 虚函数;

    9)添加代码实现 QQ 抽屉效果:(1)视图的切分;(2)视图的切换;

    10)添加类对应头文件 --MainFrm.h

    #include "GfxSplitterWnd.h"
    #include "GfxOutBarCtrl.h"

    11)添加类变量 --MainFrm.h

    public:
        CGfxSplitterWnd        wndSplitter;
        CGfxOutBarCtrl        wndBar;       
        CImageList            imaLarge, imaSmall;       
        CTreeCtrl            wndTree;

    12)添加控件Dialog

      在“资源视图”的“Dialog”目录上右击,添加一个新的Dialog

      修改ID、修改Dialog属性 Border --> None、修改 Style属性 Popup -->child

    13)给Dialog添加类CFormBackground

      继承自CFormView 类

      #include "FormBackground.h" 添加到 MainFrm.cpp或MainFrm.h

    14)onCreateClient() 函数实现之前 nImages 数组

    static UINT nImages[] =
    {
        IDI_ICON_SET,
        IDI_ICON_USER,
        IDI_ICON_OP_LOG,
        IDI_ICON_LOG,
        IDI_ICON_REQ,
        IDI_ICON_RE,
        IDI_ICON_REPORT,
    };

    15)导入.ico图片到项目res目录中

      一次修改ID(7个)

    16)添加背景图片

      给CFormBackground 重写onDraw函数 -->用到bmp 图片资源

      在函数内部添加代码。

      导入 background.bmp图片

      修改ID

    17)完成视图切换功能

      (1)添加消息声明  ---> MainFrm.h

        afx_msg long OnOutbarNotify(WPARAM wParam, LPARAM lParam);

      (2)注册消息映射 -->MainFrm.cpp

    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
    … …
    ON_MESSAGE(WM_OUTBAR_NOTIFY, OnOutbarNotify) // 注意不能添加分号!!!
    ……
    END_MESSAGE_MAP()

      (3)对应消息声明添加实现。-->MainFrm.cpp

        在函数内部添加代码。

    18)添加控件Dialog

      (1)在“资源视图”的“Dialog”目录上右击,添加一个新的Dialog

      修改ID、修改Dialog属性 Border --> None、修改 Style属性 Popup -->child

      给Dialog添加类CCfgView

      #include "CfgView.h" 添加到MainFrm.cpp 或 MainFrm.h

      【可选】在Dialog中添加控件

      (2)在“资源视图”的“Dialog”目录上右击,添加一个新的Dialog

      修改ID、修改Dialog属性 Border --> None、修改 Style属性 Popup -->child

      给Dialog添加类CDlgNetInfo

      #include "DlgNetInfo.h" 添加到MainFrm.cpp 或 MainFrm.h

      【可选】在Dialog中添加控件

    7、管理终端功能简析

    》“管理终端”的作用:
        新增一个网点时,服务器应通过管理终端给其分配编号、授权码(类似邮箱),并录入该网点信息到数据库。
        管理终端的管理员,应能通过管理终端配置服务器的属性,如:服务器IP、端口、最大网点个数等。

    》功能模块:
        >系统初始化
            录入配置信息,写配置文件。下次启动时直接读该配置文件。 xxx.ini
            
        >参数配置管理
            数据源参数配置
            服务器的启动参数
            根网点的配置信息
            
        >网点生命周期的管理
            网点的增、删、改、查。模糊查询、精确查询。

    8、初始化-获取配置文件路径

    》系统初始化
        第一次启动时,读配置文件
            若文件不存在,弹出对话框,让用户输入,保存到xxx.ini配置文件,同时赋值给全局变量
            若文件存在,赋值给全局变量,用于后续连接数据库。
            
    --实现读配置文件:
        1)在 SecMngAdmin.cpp的 InitInstance()中添加读配置文件的功能函数 readSecMngCfg:
        int ret = readSecMngCfg();


        2)在 SecMngAdmin.cpp中添加 readSecMngCfg 函数定义:

    >int CSecMngAdminAPP::readSecMngCfg()代码:

    int CSecMngAdminAPP::readSecMngCfg()
    {
        //找到.exe文件所在目录位置
        //C:UsersafeiDocumentsVisual Studio 2015ProjectsSecMngAdminDebugMySecAdmin.exe
        //C:UsersafeiDocumentsVisual Studio 2015ProjectsSecMngAdminDebugsecmngadmin.ini
        char fileName[1024] = { 0 };
        
        //获取当前工作模块文件路径
        GetModuleFileName(AfxGetInstanceHandle(), fileName, sizeof(fileName));
        
        //AfxMessageBox(fileName);
        
        //拼接文件路径
        CString g_strINIPath = fileName;//定义 CString 类变量,使用 CString API
        int i = g_strINIPath.ReverseFind('\');//自右向左查找‘’
        g_strINIPath = g_strINIPath.Left(i);//根据找到的位置提取
        
        //AfxMessageBox(fileName);
        
        g_strINIPath = g_strINIPath + "\" + "secmngadmin.ini"
        
        //AfxMessageBox(fileName);
        
        //获取配置项 GetCfgItem在cfg_op.h中
        //ret = GetCfgItem(char *pFileName, char *pKey, char *pValue, int *pValueLen);
        
        return 0;
    }
    int CSecMngAdminAPP::readSecMngCfg()

        3)在 SecMngAdmin.h 中添加声明:

            public:
                int readSecMngCfg();


        4)实现 readSecMngCfg 函数:
            (1)配置文件应该存放在 exe 文件所在目录下,应先,求当前应用程序所在路径。
            (2)封装自定义函数(cfg_op.c和cfg_op.h中),读配置文件。添加对应头文件。
                将 CString 类转化成 char * 用到宏 LPCTSTR 和 LPTSTR

    》补充:

    (1)获取当前工作模块文件路径函数

    /*
    DWORD GetModuleFileName(
        HMODULE hModule,//获得 hModule 所指的文件的名字,常配合 AfxGetInstanceHandle() 使用
        LPTSTR lpFilename,//存放返回的名字的内存块的指针
        DWORD nSize //内存块的大小
    );
    */
        char strFileName[2048] = { 0 };
        
        //获取当前工作模块文件路径
        GetModuleFileName(AfxGetInstanceHandle(), strFileName, sizeof(strFileName));
        
        //拼接文件路径
        CString g_strINIPath = strFileName;//定义 CString 类变量,使用 CString API
        int i = g_strINIPath.ReverseFind('\');//自右向左查找‘’
        g_strINIPath = g_strINIPath.Left(i);//根据找到的位置提取
        
        g_strINIPath = g_strINIPath + "\" + "待补充的字符串"

    (2)获取配置项和写配置项 的函数

    >cfg_op.h

    // cfg_op.h
    
    #ifndef __CFG_OP_H__
    #define __CFG_OP_H__
    
    
    #ifdef  __cplusplus
    extern "C" {
    #endif
    
    //获取配置项
    int GetCfgItem(char *pFileName, char *pKey, char *pValue, int *pValueLen);
    
    //写配置项 
    int WriteCfgItem(char *pFileName, char *pItemName, char *pItemValue, int itemValueLen);
    
    
    #ifdef  __cplusplus
    }
    #endif
    
    
    #endif
    cfg_op.h

    >cfg_op.c

    #include "stdafx.h"  //别忘记 增加这个头文件的说明
    
    #define  _CRT_SECURE_NO_WARNINGS 
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    #include "cfg_op.h"
    #define MaxLine 2048 
    
    //获取配置项
    int GetCfgItem(char *pFileName, char *pKey, char * pValue, int * pValueLen)
    {
        int        ret = 0;
        FILE    *fp = NULL;
        char    *pTmp = NULL, *pEnd = NULL, *pBegin = NULL;
    
        char lineBuf[MaxLine];
    
        fp = fopen(pFileName, "r");
        if (fp == NULL)
        {
            ret = -1;
            return ret;
        }
    
        while (!feof(fp))
        {
            memset(lineBuf, 0, sizeof(lineBuf));
            //fgets(_Out_z_cap_(_MaxCount) char * _Buf, _In_ int _MaxCount, _Inout_ FILE * _File);
            fgets(lineBuf, MaxLine, fp);
            //printf("lineBuf:%s ",lineBuf );
    
            pTmp = strchr(lineBuf, '='); // key = value
            if (pTmp == NULL) //没有=号
            {
                continue;
            }
    
            pTmp = strstr(lineBuf, pKey);
            if (pTmp == NULL) //判断key是不是在 //所在行 是不是有key
            {
                continue;
            }
            pTmp = pTmp + strlen(pKey); //mykey1 = myvalude11111111 ==> "= myvalude1111111"
    
            pTmp = strchr(pTmp, '=');
            if (pTmp == NULL) //判断key是不是在 //所在行 是不是有key
            {
                continue;
            }
            pTmp = pTmp + 1;
    
            //获取value 起点
            while (1)
            {
                if (*pTmp == ' ')
                {
                    pTmp++;
                }
                else
                {
                    pBegin = pTmp;
                    if (*pBegin == '
    ')
                    {
                        //没有配置value
                        //printf("配置项:%s 没有配置value 
    ", pKey);
                        goto End;
                    }
                    break;
                }
            }
    
            //获取valude结束点
            while (1)
            {
                if ((*pTmp == ' ' || *pTmp == '
    '))
                {
                    break;
                }
                else
                {
                    pTmp++;
                }
            }
            pEnd = pTmp;
    
            //赋值
            *pValueLen = pEnd - pBegin;
            memcpy(pValue, pBegin, pEnd - pBegin);
        }
    
    End:
        if (fp == NULL)
        {
            fclose(fp);
        }
        return 0;
    
    }
    
    //写配置项 
    //循环读每一行,检查key配置项是否存在 若存在修改对应value值
    //若不存在,在文件末尾 添加 "key = value"
    //难点:如何修改文件流中的值
    //int WriteCfgItem(char *pFileName /*in*/, char *pKey /*in*/, char * pValue/*in*/, int ValueLen /*in*/)
    int WriteCfgItem(char *pFileName, char *pKey, char * pValue, int ValueLen)
    {
        int        rv = 0, iTag = 0, length = 0;
        FILE    *fp = NULL;
        char    lineBuf[MaxLine];
        char    *pTmp = NULL, *pBegin = NULL, *pEnd = NULL;
        char    filebuf[1024 * 8] = { 0 };
    
        if (pFileName == NULL || pKey == NULL || pValue == NULL)
        {
            rv = -1;
            printf("SetCfgItem() err. param err 
    ");
            goto End;
        }
    
        fp = fopen(pFileName, "r+");
        if (fp == NULL)
        {
            rv = -2;
            printf("fopen() err. 
    ");
            //goto End;
        }
    
        if (fp == NULL)
        {
            fp = fopen(pFileName, "w+t");
            if (fp == NULL)
            {
                rv = -3;
                printf("fopen() err. 
    ");
                goto End;
            }
            rv = 0; //bug
        }
    
        fseek(fp, 0L, SEEK_END); //把文件指针从0位置开始,移动到文件末尾
        //获取文件长度;
        length = ftell(fp);
    
        fseek(fp, 0L, SEEK_SET);
    
        if (length > 1024 * 8)
        {
            rv = -3;
            printf("文件超过1024*8, nunsupport");
            goto End;
        }
    
        while (!feof(fp))
        {
            //读每一行
            memset(lineBuf, 0, sizeof(lineBuf));
            pTmp = fgets(lineBuf, MaxLine, fp);
            if (pTmp == NULL)
            {
                break;
            }
    
            //key关键字是否在本行
            pTmp = strstr(lineBuf, pKey);
            if (pTmp == NULL) //key关键字不在本行, copy到filebuf中
            {
                strcat(filebuf, lineBuf);
                continue;
            }
            else  //key关键在在本行中,替换旧的行,再copy到filebuf中 
            {
                sprintf(lineBuf, "%s = %s
    ", pKey, pValue);
                strcat(filebuf, lineBuf);
                //若存在key
                iTag = 1;
            }
        }
    
        //若key关键字,不存在 追加
        if (iTag == 0)
        {
            fprintf(fp, "%s = %s
    ", pKey, pValue);
        }
        else //若key关键字,存在,则重新创建文件
        {
            if (fp != NULL)
            {
                fclose(fp);
                fp = NULL; //避免野指针
            }
    
            fp = fopen(pFileName, "w+t");
            if (fp == NULL)
            {
                rv = -4;
                printf("fopen() err. 
    ");
                goto End;
            }
            fputs(filebuf, fp);
            //fwrite(filebuf, sizeof(char), strlen(filebuf), fp);
        }
    
    End:
        if (fp != NULL)
        {
            fclose(fp);
        }
        return rv;
    }
    cfg_op.c

    9、创建对话框

    (1)将cfg_op.c和cfg_op.h拷贝到放入项目的文件夹(在SecMngAdmin.cpp上右键打开的文件夹),然后在项目“secmngAdmin”右键,添加“现有项”,添加这2个文件;

    (2)在 SecMngAdmin.cpp中修改 readSecMngCfg 函数实现:

    >int CSecMngAdminAPP::readSecMngCfg()

    int CSecMngAdminAPP::readSecMngCfg()
    {
        int ret = 0;
        char pValue[64] = {0};
        int pValueLen = sizeof(pValue);
        //找到.exe文件所在目录位置
        //C:UsersafeiDocumentsVisual Studio 2015ProjectsSecMngAdminDebugMySecAdmin.exe
        //C:UsersafeiDocumentsVisual Studio 2015ProjectsSecMngAdminDebugsecmngadmin.ini
        char fileName[1024] = { 0 };
        
        //获取当前工作模块文件路径
        GetModuleFileName(AfxGetInstanceHandle(), fileName, sizeof(fileName));
        
        //拼接文件路径
        CString g_strINIPath = fileName;//定义 CString 类变量,使用 CString API
        int i = g_strINIPath.ReverseFind('\');//自右向左查找‘’
        g_strINIPath = g_strINIPath.Left(i);//根据找到的位置提取
        
        g_strINIPath = g_strINIPath + "\" + "secmngadmin.ini";
        
        // 获取配置项 GetCfgItem在cfg_op.h中
        // 将 CString 类转化成 char * 用到宏 LPCTSTR 和 LPTSTR
        // 读取 DSN
        ret = GetCfgItem((LPTSTR)(LPCTSTR)g_strINIPath, "DSN", pValue, &pValueLen);
        if(ret != 0)
        {
            //AfxMessageBox("读取 DSN 失败");
            return ret;
        }
        
        // 读取 UID
        memset(pValue, 0, sizeof(pValue));
        ret = GetCfgItem((LPTSTR)(LPCTSTR)g_strINIPath, "UID", pValue, &pValueLen);
        if(ret != 0)
        {
            //AfxMessageBox("读取 UID 失败");
            return ret;
        }
        
        // 读取 PWD
        memset(pValue, 0, sizeof(pValue));
        ret = GetCfgItem((LPTSTR)(LPCTSTR)g_strINIPath, "PWD", pValue, &pValueLen);
        if(ret != 0)
        {
            //AfxMessageBox("读取 PWD 失败");
            return ret;
        }
        
        return 0;
    }
    int CSecMngAdminAPP::readSecMngCfg()

    (3)在 SecMngAdmin.h中增加头文件:

    #include "cfg_op.h"

    (4)在 SecMngAdmin.cpp的 InitInstance()中增加弹出对话框提供用户输入信息的Dialog:

    打开“资源视图”,添加“Dialog”:

    在资源视图左侧“Dialog”处右键“插入Dialog”,然后删除“确定”和“取消”按钮,修改对话框的ID(在“IDD_DIALOG6”右键“属性”进行修改ID为:IDD_DIALOG_INITDB);

    点击对话框,修改属性:修改Caption属性“:配置数据库信息;

            数据源ID:    IDC_EDIT_DSN
            用户名ID:    IDC_EDIT_USER
            密码ID:        IDC_EDIT_PASSWD

    10、弹窗供用户输入信息

    (1)点击上步创建的IDD_DIALOG_INITDB对话框,右键“添加类”(或者“双击”),然后输入类名:CDlgInitCfg,基类选择: CDialog,点击“完成”:

    (2)在IDD_DIALOG_INITDB对话框右键选择“类向导”,选择“成员变量”,选中“IDC_EDIT_DSN”,然后点击右侧的“添加变量”,依次添加(3个)成员变量:

    目的是从 Dialog 中提取数据
        将试图资源关联 类 成员变量
            CString m_dbDSN
            CString m_dbUID
            CString m_dbPWD

    添加完成,如图:

    (3)在IDD_DIALOG_INITDB对话框双击“确定”按钮,添加回调函数:

    >代码如下:

    void CDlgInitCfg::OnBnClickedOk()
    {
        // TODO:在此添加控件通知处理程序代码
        //CDialog::OnOK();
        
        UpdateData(TRUE);
        
        if(m_dbDSN.IsEmpty() || m_dbPWD.IsEmpty() || m_dbUID.IsEmpty())
        {
            AfxMessageBox("录入信息不允许为空!");
            return;
        }
    }
    void CDlgInitCfg::OnBnClickedOk()

    (4)在 SecMngAdmin.cpp的 InitInstance()中添加调用(弹出对话框供用户输入)的函数:

    >BOOL CSecMngAdminApp::InitInstance()代码如下:

    BOOL CSecMngAdminApp::InitInstance()
    {
        int ret = 0;
        CWinApp::InitInstance();
        
        EnableTaskbarInteraction(FALSE);
        
        // 使用 RichEdit 控件需要 AfxInitRichEdit2()
        //AfxInitRichEdit2();
        
        //标准初始化
        ret = readSecMngCfg();
        if(ret != 0)
        {
            AfxMessageBox("读取配置信息出错");
            //弹出对话框供用户输入信息
            CDlgInitCfg dlgInitCfg;
            dlgInitCfg.DoModal();
        }
        else
        {
            // 借助全局变量 连接数据库
            
        }
        
        ...
    
    }
    BOOL CSecMngAdminApp::InitInstance()

    在 SecMngAdmin.h中增加头文件:#include "DlgInitCfg.h"

    (5)设置 测试、确定、取消 3个按钮的ID:

    测试ID:IDC_BUTTON_LINKTEST、确定ID:IDOK、取消ID:IDCANCLE

    11、将用户录入数据保存ini文件

    (1)在DlgInitCfg.cpp中修改void CDlgInitCfg::OnBnClickedOk()代码:

    void CDlgInitCfg::OnBnClickedOk()
    {
        // TODO:在此添加控件通知处理程序代码
        //CDialog::OnOK();
        int ret = -1;
        
        UpdateData(TRUE);
        
        if(m_dbDSN.IsEmpty() || m_dbPWD.IsEmpty() || m_dbUID.IsEmpty())
        {
            AfxMessageBox("录入信息不允许为空!");
            return;
        }
        
        char fileName[1024] = { 0 };
        
        //获取当前工作模块文件路径
        GetModuleFileName(AfxGetInstanceHandle(), fileName, sizeof(fileName));
        
        //拼接文件路径
        CString g_strINIPath = fileName;//定义 CString 类变量,使用 CString API
        int i = g_strINIPath.ReverseFind('\');//自右向左查找‘’
        g_strINIPath = g_strINIPath.Left(i);//根据找到的位置提取
        
        g_strINIPath = g_strINIPath + "\" + "secmngadmin.ini";
        
        // 获取配置项 GetCfgItem在cfg_op.h中
        // 将 CString 类转化成 char * 用到宏 LPCTSTR 和 LPTSTR
        // 写入 DSN
        ret = WriteCfgItem((LPTSTR)(LPCTSTR)g_strINIPath, "DSN", (LPTSTR)(LPCTSTR)m_dbDSN, m_dbDSN.getLength);
        if(ret != 0)
        {
            //AfxMessageBox("写入 DSN 失败");
            return;
        }
        
        // 写入 UID
        ret = WriteCfgItem((LPTSTR)(LPCTSTR)g_strINIPath, "UID", (LPTSTR)(LPCTSTR)m_dbUID, m_dbUID.getLength);
        if(ret != 0)
        {
            //AfxMessageBox("写入 UID 失败");
            return;
        }
        
        // 写入 PWD
        ret = WriteCfgItem((LPTSTR)(LPCTSTR)g_strINIPath, "PWD", (LPTSTR)(LPCTSTR)m_dbPWD, m_dbPWD.getLength);
        if(ret != 0)
        {
            //AfxMessageBox("写入 PWD 失败");
            return;
        }
        
        
    }
    void CDlgInitCfg::OnBnClickedOk()

    (2)测试:

    打开工程目录的上一级目录,查看,增加了secmngadmin.ini文件:

    12、全局变量赋值及取消按钮

    (1)增加全局变量,添加文件“secmng_globvar.h”

    // secmng_globvar.h
    #ifndef SECMNG_GLOB_VAR_H_
    #define SECMNG_GLOB_VAR_H_
    
    #include "stdafx.h"
    
    //数据源全局变量
    CString    g_dbSource, g_dbUser, g_dbpwd;
    
    //连接数据全局变量
    CDatabase    myDB;
    CDatabase    *g_pDB = NULL;
    
    //配置文件全局变量
    CString    g_SecMngIniName = "secmngadmin.ini";
    
    #endif
    secmng_globvar.h

    将secmng_globvar.h拷贝到放入项目的文件夹(在SecMngAdmin.cpp上右键打开的文件夹),然后在项目“secmngAdmin”右键,添加“现有项”,添加这1个文件;

    然后在SecMngAdmin.cpp中添加头文件:#include "secmng_globvar.h"

    secmng_globvar.h中为方便调试,先注释掉:

    //连接数据全局变量
    //CDatabase    myDB;
    //CDatabase    *g_pDB = NULL;

    注意:secmng_globvar.h里面是全局变量,所以只能添加到一个文件中!!!

    在SecMngAdmin.cpp中增加调用

    >BOOL CSecMngAdminApp::InitInstance()代码如下:

    BOOL CSecMngAdminApp::InitInstance()
    {
        int ret = 0;
        CWinApp::InitInstance();
        
        EnableTaskbarInteraction(FALSE);
        
        // 使用 RichEdit 控件需要 AfxInitRichEdit2()
        //AfxInitRichEdit2();
        
        //标准初始化
        ret = readSecMngCfg();
        if(ret != 0)
        {
            AfxMessageBox("读取配置信息出错");
            //弹出对话框供用户输入信息
            CDlgInitCfg dlgInitCfg;
            dlgInitCfg.DoModal();
        }
        else
        {
            // 借助全局变量 连接数据库
            AfxMessageBox("DSN:" + g_dbSource + "|UID:" + g_dbUser + "|PWD:" + g_dbpwd );
        }
        
        ...
    
    }
    BOOL CSecMngAdminApp::InitInstance()

    运行结果如下:

    注意:void CDlgInitCfg::OnBnClickedOk()注释掉:CDialog::OnOK();后打开主界面后原界面不会退出!

    所以,应该修改为:

    void CDlgInitCfg::OnBnClickedOk()

     另外,

    (1)不论配置文件是否存在,都可以连接数据库;

    (2)取消按钮功能简单,所以不设置回调,借助于判断if(dlgInitCfg.DoModal() == "取消按钮ID");

    所以,BOOL CSecMngAdminApp::InitInstance()修改为:

    BOOL CSecMngAdminApp::InitInstance()
    {
        int ret = 0;
        CWinApp::InitInstance();
        
        EnableTaskbarInteraction(FALSE);
        
        // 使用 RichEdit 控件需要 AfxInitRichEdit2()
        //AfxInitRichEdit2();
        
        //弹出对话框供用户输入信息
        CDlgInitCfg dlgInitCfg;
        
        //标准初始化
        ret = readSecMngCfg();
        if(ret != 0)
        {
            //配置文件不不存在,弹窗输入,然后连接数据库
            AfxMessageBox("配置文件不存在,请输入!!!");
            if(dlgInitCfg.DoModal() == IDCANCLE)
            {
                return FALSE;
            }
            
            g_dbSource = dlgInitCfg.m_dbDSN;
            g_dbUser = dlgInitCfg.m_dbUID;
            g_dbpwd = dlgInitCfg.m_dbPWD;
        }
        else
        {
            // 配置文件,存在,直接读取,然后连接数据库
            AfxMessageBox("DSN:" + g_dbSource + "|UID:" + g_dbUser + "|PWD:" + g_dbpwd );
        }
        
        // 借助全局变量--连接数据库
        
        ...
    
    }
    BOOL CSecMngAdminApp::InitInstance()

    13、测试连接数据库

    连接数据库(借助ODBC)示意图:

    问题来源:当创建MFC项目的时候,数据库支持选择的“无”,但是如果选择“尽头文件”,客户端类型选择“ODBC”,会添加特别多的文件,所以自己手动增加ODBC的头文件。

    (1)secmng_globvar.h中把之前注释的代码打开

    //连接数据全局变量
    CDatabase    myDB;
    CDatabase    *g_pDB = NULL;

    然后,在stdafx.h中增加头文件:

    #include <afxdb.h>

    按“F12”跳转到定义,可以查看OpenEx函数

    (2)双击“测试”按钮,增加回调函数,

    1)使用MFC连接数据库的ODBC的调用函数OpenEx;

    2)增加try...catch...

    >void CDlgInitCfg::OnBnClickedButtonLinktest()

    void CDlgInitCfg::OnBnClickedButtonLinktest()
    {
        // TODO: 在此添加控件通知处理程序代码
        
        UpdateData(TRUE);//提取文本框
        
        CDatabase myDB;
        
        CString strCon;
        
        TRY
        {
            strCon.Format("DSN=%s;UID=%s;PWD=%s", m_dbDSN, m_dbUID, m_dbPWD);
            
            if( myDB.OpenEx(strCon, CDatabase::noOdbcDialog) == FALSE)
            {
                AfxMessageBox("创建一条到数据源的连接发生错误, 请检查数据源配置是否正确!");
                return; 
            }
            else
            {
                AfxMessageBox("连接数据库成功!");
            }
            myDB.Close();//这只是测试,所以测试完毕,需要关闭与数据库的连接
        }
        CATCH_ALL(e)
        {
            e->ReportError();
        }
        END_CATCH_ALL
        
    
        return;
    }
    void CDlgInitCfg::OnBnClickedButtonLinktest()

    》测试:

    点击“运行”,先输入错误的数据源、用户名和密码:

    点击“测试”,会捕捉到错误:

    点击“运行”,输入正确的数据源、用户名和密码:

    14、总结

    》系统初始化
        第一次启动时,读配置文件
            若文件不存在,弹出对话框,让用户输入,保存到xxx.ini配置文件,同时赋值给全局变量
            若文件存在,赋值给全局变量,用于后续连接数据库。
            
    --实现读配置文件:
        在 SecMngAdmin.cpp的 InitInstance()中添加读配置文件的功能函数 ReadSecMngCfg:
        int ret = ReadSecMngCfg();
        在 CSecMngAdminAPP.cpp中添加 ReadSecMngCfg 函数定义;
        在 CSecMngAdminAPP.h 中添加声明:
            public:
                int ReadSecMngCfg();
        实现 ReadSecMngCfg 函数:
            (1)配置文件应该存放在 exe 文件所在目录下,应先,求当前应用程序所在路径。
            (2)封装自定义函数,读配置文件(cfg_op.h和cfg_op.c)。添加对应头文件。
                将 CString 类转化成 char * 用到宏 LPCTSTR 和 LPTSTR

    --创建 Dialog,读配置文件失败,弹窗显示
        “资源视图”---“Dialog目录”右键,插入 Dialog 控件。
        设计弹窗界面,修改 Dialog 的 ID:IDD_DIALOG_INITDB
            数据源ID:    IDC_EDIT_DSN
            用户名ID:    IDC_EDIT_USER
            密码ID:        IDC_EDIT_PASSWD
        Ctrl + T 预览界面
        给 Dialog 添加类:CDlgInitCfg 包含头文件 DlgInitCfg.h
            CDlgInitCfg dlgInitCfg;
        读取失败,弹窗显示 if(dlgInitCfg.DoModal() == "取消按钮ID");
        
    --从 Dialog 中提取数据
        将试图资源关联 类 成员变量 --Dialog --类向导 --成员变量
            CString m_dbDSN
            CString m_dbUID
            CString m_dbPWD
        若用户选择“确定”按钮,UpdateData(TRUE);将界面数据保存到成员变量中。
            若变量值为空 IsEmpty(),提示用户:AfxMseesageBox("不能为空");
        若用户选择“取消”按钮,dlgInitCfg.DoModel() == IDCANCEL 直接 return FALSE;
            否则,获取成员变量,数据保存至 全局变量。

    --定义全局变量文件,统一管理  secmng_globvar.h  【注意:该头文件只能被引用一次!!!
        CDatabase 类需要引用 #include <atxdb.h> -->stdafx.h
        创建项目时,数据库支持页面中,选择“仅头文件”可以包含该头文件。也可以手动添加。
        成功读取配置文件中的数据和弹窗后,用户输入的数据,对应存储到全局变量中。
        
        TRY
        {
        
        }
        CATCH_ALL(e)
        {
            e->ReportError();
        }
        END_CATCH_ALL

    --测试按钮:
        UpdateData(TRUE),将界面数据保存到成员变量中。
        CDataBase db;
        CString strCon;
        strCon.Format("DSN=%s;UID=%s;PWD=%s", m_dbDSN, m_dbUID, m_dbPWD);
        db->OpenEx(strCon, CDatabase::noOdbcDialog);
        db.Close();

    在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

  • 相关阅读:
    巴塞尔协议
    商业银行资本充足率
    开源录屏软件Open Broadcaster Software
    简介二:操作系统和集群开源技术研究
    【Python】 零碎知识积累 II
    【Python】 用户图形界面GUI wxpython IV 菜单&对话框
    【Python】 关于import和package结构
    【Python】 魔法方法
    【Python】 闭包&装饰器
    【Python】 迭代器&生成器
  • 原文地址:https://www.cnblogs.com/Alliswell-WP/p/CPlusPlus_SecureTransmissionPlatform_Project09.html
Copyright © 2011-2022 走看看