windows桌面应用分为两种类型: 基于文档视图类型 和 基于对话框类型。 通常具有复杂交互控件的程序即为基于对话框类型,相对而言比较复杂,而基于文档视图类的应用交互形式比较单一,相对简单。下面给出基于mfc框架的最基本的桌面程序示例:
cpp
// 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 框架下的示例,对程序的运行框架有一个大致的理解:
cpp
#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);//控件ID
WORD 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_MENU1
wc.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;
}
对话框程序示例
cpp
#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;
单文档程序示例
cpp
#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;
多文档程序示例
cpp
#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;