?windows桌面應用分為兩種類型: 基于文檔視圖類型 和 基于對話框類型。 通常具有復雜交互控件的程序即為基于對話框類型,相對而言比較復雜,而基于文檔視圖類的應用交互形式比較單一,相對簡單。下面給出基于mfc框架的最基本的桌面程序示例:
// 1. 創建控制臺空項目
// 2. 項目屬性--> 高級-->MFC的應用:[使用標準 Windows 庫] 改成 [在共享 DLL 中使用 MFC]
// 3. 項目屬性-->鏈接器-->系統-->子系統:[控制臺 (/SUBSYSTEM:CONSOLE)] 改成 [窗口 (/SUBSYSTEM:WINDOWS)]#include <afxwin.h>
class BaseWinApp:public CWinApp
{
public:BaseWinApp();virtual BOOL InitInstance() override;
};class BaseMainFrame:public CFrameWnd
{
public:BaseMainFrame();
};BaseMainFrame::BaseMainFrame()
{}BaseWinApp::BaseWinApp()
{}BOOL BaseWinApp::InitInstance()
{BaseMainFrame* pFrame = new BaseMainFrame();pFrame->Create(NULL, "BaseFrame");m_pMainWnd = pFrame;pFrame->ShowWindow(SW_SHOW);pFrame->UpdateWindow();return TRUE;
}BaseWinApp theApp;//全局唯一// 主線程啟動順序(最終進入一個事件循環):
// WinMain: appmodul.cpp
// AfxWinMain: winmain.cpp
// (CWinApp*)(&theApp)->InitApplication 應用資源初始化,是虛函數,可以在子類中重寫,做一些特殊資源的初始化
// (CWinThread*)(&theApp)->InitInstance 用戶重寫的InitInstance
// (CWinThread*)(&theApp)->Run: appcore.cpp
// (CWinThread*)(&theApp)->CWinThread::Run(): thrdcore.cpp 進入事件循環,處理消息// 當消息產生后會在消息循環中偵測到,并在DispatchMessage內部調用對應窗口的處理回調(如AfxWndProc: wincore.cpp)進行消息處理// MFC 中創建線程的兩種方法:
// 1. CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, ...); 調用該接口,傳入線程函數,生成一個CWinThread線程管理對象
// 2. CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass,...); 繼承CWinThread實現新的Thread類,并聲明Runtime信息, 傳入新類的RuntimeClass,生成一個線程管理對象。(即CWinApp的做法)// 通過這兩種方法創建的新線程,與當前線程公用同一個消息隊列,以便在兩個線程之間完成通信
?基于對話框的應用,可以先看win32 框架下的示例,對程序的運行框架有一個大致的理解:
#include <windows.h>
#include <iostream>
#include "resource.h"//要給項目添加資源文件//本例需要在資源文件中添加一個Dialog控件(ID為IDD_DIALOG1)和一個Menu控件(ID為IDR_MENU1,MENU中要增加菜單欄和菜單項)HINSTANCE g_hInstance = NULL;
HWND hddd = NULL;INT_PTR CALLBACK DlgProc(HWND hwndlg,UINT msgID,WPARAM wParam, LPARAM lParam)
{switch (msgID){case WM_SYSCOMMAND:if (wParam == SC_CLOSE){HWND pHwnd = GetParent(hwndlg);DestroyWindow(hwndlg);EnableWindow(pHwnd, TRUE);}else//不知道如何處理的消息,則讓框架處理return FALSE;break;case WM_DESTROY:MessageBox(NULL,L"Dialog Destroyed",L"Notify",MB_OK);break;case WM_COMMAND:if(wParam == IDOK)MessageBox(NULL, L"User Confirmed",L"Dialog Result", MB_OK);else if(wParam == IDCANCEL)MessageBox(NULL, L"User Denied", L"Dialog Result",MB_OK);break;default:return FALSE;break;}return TRUE;
}void OnNoModel(HWND hWnd)
{HWND pHwnd = GetParent(hWnd);EnableWindow(pHwnd,FALSE);//HWND hDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_DIALOG1),hWnd,DlgProc);// 等效步驟①②③④⑤⑥//創建對話窗對象,并和對話框控件(資源中創建,ID為IDD_DIALOG1)綁定HRSRC hRs = FindResource(g_hInstance,MAKEINTRESOURCE(IDD_DIALOG1),RT_DIALOG);//①HGLOBAL hGl = LoadResource(g_hInstance,hRs);//②LPDLGTEMPLATE pTemplate = (LPDLGTEMPLATE)LockResource(hGl);//③HWND hDlg = CreateDialogIndirect(g_hInstance,pTemplate,hWnd, DlgProc);//④UnlockResource(hGl);//⑤FreeResource(hGl);//⑥hddd = hDlg;ShowWindow(hDlg, SW_SHOW);//立即返回不阻塞
}void OnCommand(HWND hWnd,WPARAM wParam )
{WORD ID = LOWORD(wParam);//控件IDWORD Code = HIWORD(wParam);//通知類型switch (ID){case ID_FFF:// 資源文件中定義菜單欄下拉的菜單選項對應的資源ID,點擊該菜單項將創建一個對話框出來OnNoModel(hWnd);break;default:break;}
}LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{LRESULT lRet = 0;switch (msgID){case WM_DESTROY:PostQuitMessage(0);break;case WM_COMMAND:OnCommand(hWnd,wParam);break;default:lRet = DefWindowProc(hWnd, msgID, wParam, lParam);break;}return lRet;
}int CALLBACK WinMain(HINSTANCE hIns,HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{g_hInstance = hIns;WNDCLASS wc = {};wc.cbClsExtra = 0;wc.cbWndExtra = 0;wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wc.hCursor = NULL;wc.hIcon = NULL;wc.hInstance = hIns;wc.lpfnWndProc = WndProc;wc.lpszClassName =L"Main";//wc.lpszMenuName = NULL;// IDR_MENU1 在資源文件中添加一個菜單資源,資源ID為IDR_MENU1wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);wc.style = CS_HREDRAW | CS_VREDRAW;RegisterClass(&wc);HWND hWnd = CreateWindowEx(0,L"Main",L"window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);ShowWindow(hWnd,SW_SHOW);UpdateWindow(hWnd);MSG nMsg = {};// AllocConsole();//打日志用// FILE* f = NULL;// freopen_s(&f,"CONOUT$", "w", stdout);while (GetMessage(&nMsg, NULL, 0, 0)){TranslateMessage(&nMsg);DispatchMessage(&nMsg);//將消息交給窗口處理函數處理}//fclose(f);return 0;
}
對話框程序示例
#include <afxwin.h>
#include <afxcmn.h>
#include "resource.h"//本例需要在資源文件中添加一個Dialog控件(ID為IDD_DIALOG1) class MainDialog : public CDialog
{DECLARE_MESSAGE_MAP()enum { IDD = IDD_DIALOG1 };
public:MainDialog():CDialog(IDD){}void OnIdle(){}//可在此處理低優先級任務
protected:BOOL OnInitDialog() override{return CDialog::OnInitDialog();}void OnClosed(void){::DestroyWindow(this->m_hWnd);}void AFX_MSG_CALL OnSysCommand(UINT msgID, LPARAM lParam){DWORD cmdType = msgID & 0xFFF0;switch (cmdType){case SC_CLOSE://處理標題欄的關閉事件OnClosed();break;default:CDialog::OnSysCommand(msgID, lParam);break;}}void DoDataExchange(CDataExchange* pDX) override{}
};
BEGIN_MESSAGE_MAP(MainDialog, CDialog)ON_WM_SYSCOMMAND()
END_MESSAGE_MAP()class BaseWinApp :public CWinApp
{
public:BaseWinApp();virtual BOOL InitInstance() override;virtual BOOL OnIdle(LONG lCount) override;
};BaseWinApp::BaseWinApp()
{InitApplication();
}BOOL BaseWinApp::InitInstance()
{MainDialog* pFrame = new MainDialog();pFrame->Create(IDD_DIALOG1,NULL);m_pMainWnd = pFrame;pFrame->ShowWindow(SW_SHOW);//LONG wProc = GetWindowLongPtr(pFrame->m_hWnd, GWLP_WNDPROC);//that should be AfxWndProc//WNDPROC fun = AfxWndProc;//BOOL bRet = fun == (WNDPROC)wProc;//delete pFrame;return TRUE;
}BOOL BaseWinApp::OnIdle(LONG lCount)
{if (m_pMainWnd != NULL)((MainDialog*)m_pMainWnd)->OnIdle();return CWinThread::OnIdle(lCount);
}BaseWinApp theApp;
單文檔程序示例
#include <afxwin.h>
#include <afxext.h>
#include "resource.h"//本例需要在資源文件中添加一個Menu控件(ID為IDR_MENU1) 和一個String Table(添加字符串資源:ID=AFX_IDS_UNTITLED, Value=61443,Caption=自定義)class CMyDoc :public CDocument
{DECLARE_DYNCREATE(CMyDoc)
};
IMPLEMENT_DYNCREATE(CMyDoc,CDocument)class CMyView :public CView
{DECLARE_DYNCREATE(CMyView)
public:virtual void OnDraw(CDC* pDC);
};
void CMyView::OnDraw(CDC* pDC)
{pDC->TextOut(100,100,"this is a view wnd");
}
IMPLEMENT_DYNCREATE(CMyView, CView)class CMyFrameWnd : public CFrameWnd
{DECLARE_DYNCREATE(CMyFrameWnd)
};
IMPLEMENT_DYNCREATE(CMyFrameWnd, CFrameWnd)class CMyWinApp : public CWinApp
{
public:virtual BOOL InitInstance();
};BOOL CMyWinApp::InitInstance()
{/************ 方式一 Begin************************************///CSingleDocTemplate* pTemplate = new CSingleDocTemplate(IDR_MENU1,// RUNTIME_CLASS(CMyDoc),// RUNTIME_CLASS(CMyFrameWnd), // RUNTIME_CLASS(CMyView));//AddDocTemplate(pTemplate);//OnFileNew();/************ 方式一 End************************************/ /**********************方式二 Begin: **************************/ CMyFrameWnd* pFrame = new CMyFrameWnd;CMyDoc* pDoc = new CMyDoc;CCreateContext cct;cct.m_pCurrentDoc = pDoc;cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);pFrame->LoadFrame(IDR_MENU1,WS_OVERLAPPEDWINDOW,NULL,&cct);m_pMainWnd = pFrame;/**********************方式二 End **************************/m_pMainWnd->ShowWindow(SW_SHOW);m_pMainWnd->UpdateWindow();return TRUE;
}CMyWinApp theApp;
多文檔程序示例
#include <afxwin.h>
#include <afxext.h>
#include "resource.h"
//本例需要在資源文件中添加兩個Menu控件(ID為IDR_MENU1和IDR_MENU2) 和一個String Table(添加字符串資源:ID=AFX_IDS_UNTITLED, Value=61443,Caption=自定義)class CMyDoc :public CDocument
{DECLARE_DYNCREATE(CMyDoc)
};
IMPLEMENT_DYNCREATE(CMyDoc, CDocument)class CMyView :public CView
{DECLARE_DYNCREATE(CMyView)
public:virtual void OnDraw(CDC* pDC);
};
void CMyView::OnDraw(CDC* pDC)
{pDC->TextOut(100, 100, "I am a view wnd");
}
IMPLEMENT_DYNCREATE(CMyView, CView)class CMyChild :public CMDIChildWnd
{DECLARE_DYNCREATE(CMyChild)
};
IMPLEMENT_DYNCREATE(CMyChild, CMDIChildWnd)class CMyFrameWnd : public CMDIFrameWnd
{
public:CMyFrameWnd() :CMDIFrameWnd() {}BOOL PreCreateWindow(CREATESTRUCT& cs) override{m_strTitle = "MasterWnd";//修改主窗口標題return CMDIFrameWnd::PreCreateWindow(cs);}
public:DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CMDIFrameWnd)
END_MESSAGE_MAP()class CMyWinApp : public CWinApp
{
public:virtual BOOL InitInstance();
};BOOL CMyWinApp::InitInstance()
{CMyFrameWnd* pFrame = new CMyFrameWnd();pFrame->LoadFrame(IDR_MENU1);//MENU1為主框架窗口的菜單(MENU1至少需要兩個菜單欄)m_pMainWnd = pFrame;CMultiDocTemplate* pTemplate = new CMultiDocTemplate(IDR_MENU2,//MENU2為子框架窗口的菜單RUNTIME_CLASS(CMyDoc),RUNTIME_CLASS(CMyChild),RUNTIME_CLASS(CMyView));AddDocTemplate(pTemplate);OnFileNew();//創建三個子窗口OnFileNew();OnFileNew();m_pMainWnd->ShowWindow(SW_SHOW);m_pMainWnd->UpdateWindow();return TRUE;
}CMyWinApp theApp;