開發MFC程式一般是利用MFC程式向導,建立工程開發項目。如果你細心會發現,根本找不到程式入口 ANSI版本的WinMain() 或者 _tWinMain();
(注實際MFC程式此時為wWinMain(),
#ifdef _UNICODE
#define _tWinMain wWinMain
#else
#define _tWinMain WinMain
#endif
不久後,通過查找資料和在目錄中查找還是見到了WinMain身在何處appmodul.cpp
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "sal.h"
/
// export WinMain to force linkage to this module
extern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow);
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
/
// initialize app state such that it points to this module's core state
BOOL AFXAPI AfxInitialize(BOOL bDLL, DWORD dwVersion)
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
pModuleState->m_bDLL = (BYTE)bDLL;
ASSERT(dwVersion <= _MFC_VER);
UNUSED(dwVersion); // not used in release build
#ifdef _AFXDLL
pModuleState->m_dwVersion = dwVersion;
#endif
#ifdef _MBCS
// set correct multi-byte code-page for Win32 apps
if (!bDLL)
_setmbcp(_MB_CP_ANSI);
#endif //_MBCS
return TRUE;
}
// force initialization early
#pragma warning(disable: 4074)
#pragma init_seg(lib)
#ifndef _AFXDLL
void AFX_CDECL _AfxTermAppState()
{
// terminate local data and critical sections
AfxTermLocalData(NULL, TRUE);
AfxCriticalTerm();
// release the reference to thread local storage data
AfxTlsRelease();
}
#endif
#ifndef _AFXDLL
char _afxInitAppState = (char)(AfxInitialize(FALSE, _MFC_VER), atexit(&_AfxTermAppState));
#else
char _afxInitAppState = (char)(AfxInitialize(FALSE, _MFC_VER));
#endif
/
MFC程式WinMain()還要調用AfxWinMain(),這個函數負責建立一個CWinApp類的對象,并初始化對象運作,CWinApp中建立CDialog/CDialogEx或CFrame的對象并初始化運作。AfxWinMain()的定義在winmain.cpp這個檔案裡面。
[winmain.cpp]
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "sal.h"
/
// Standard WinMain implementation
// Can be replaced as long as 'AfxWinInit' is called first
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;
// Perform specific initializations
if (!pThread->InitInstance())
{
if (pThread->m_pMainWnd != NULL)
{
TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}
/
[winmain.cpp]
既然知道了MFC程式的運作原理,代碼原則,我們就能夠使用Win32建立MFC程式,當然也可以用控制台建立MFC程式,這個複雜一點。有時間可以嘗試。控制台程式入口為main(),參數有要注意一下 一個是HINSTANCE,視窗句柄,要用 HINSTANCE hThisInstance =::GetModuleHandle(NULL);還有int nCmdShow,這個可以自己定義SW_SHOW,HINSTANCE hPreInstance,LPTSTR lpCmdLine并不是那麼好搞了,hPreInstance是圖形視窗共享記憶體的,新的Win32系統中直接NULL,完全OK,而lpCmdLine和main(int argc,char* argv[])兩個參數對應,需要複雜的轉換,自己去實踐吧。
繼續講主題,我們利用Visual Studio建立Win32程式,一般而言除了Visual Studio,還沒有什麼可以開發MFC程式吧。那就用Visual Studio吧,注意建立的Win32為空項目!非空就會自動建立一個Frame程式,基于Win32API的程式,這個就和我們的原則背離了。
建立一個stdafx.h,Visual Studio 中有模闆。
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
// STDAFX.H is the header that includes the standard includes that are used
// for most of the project. These are compiled into a pre-compiled header
#pragma once
#include <winsdkver.h>
#undef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_MAXVER
#include <sdkddkver.h>
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#endif
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdisp.h> // MFC Automation classes
#if defined(_M_CEE)
#include <afxwinforms.h>
#endif
一個stdafx.cpp
#include "stdafx.h"
建立程式入口源檔案mian.cpp
#include "stdafx.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)//Win32-MFC初始化函數!
{
ASSERT(hPrevInstance == NULL);
// Win32應用程式隻有一個執行個體,是以hPrevInstance肯定是NULL,
// 如果不是,則肯定是出了問題。
int nReturnCode = -1;
// 預設傳回值為-1。這個傳回值是用來與父程序通信的。不過并沒有這個值的标準
// 使用方法。
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// CWinApp是CWinThread的派生類,上兩行代碼分别初始化了一個指向CWinThread對象的
// 指針和一個CWinApp對象。它們的初始化是通過調用AfxGetThread()和AfxGetApp()得到
// 的,也就是說,它們分别被初始化為指向目前應用程式的唯一全局線程/應用程式對象的
// 指針。
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// AfxWinInit()函數初始化MFC程式,處理很多難以預料的問題。該函數和後面的
// AfxWinTerm()對應。
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;
// 調用pApp->InitApplication(),初始化應用程式。不過這還不夠。
// Perform specific initializations
if (!pThread->InitInstance())
// 調用pThread->InitInstance()函數,進行線程初始化。注意,InitInstance()通常
// 是你的MFC代碼中唯一必須重載的函數。
// 下面的語句塊是當初始化不成功時的處理。
{
if (pThread->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
// ExitInstance()也是一個值得注意的函數
goto InitFailure;
}
nReturnCode = pThread->Run();
// pThread->Run()是重要函數,它使得MFC進入消息循環。其細節待另文介紹。
// 以下代碼處理各種初始化失敗情形
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}
這裡省略了AfxWinMain(),theApp執行個體的初始化直接放在了WinMain()中,不過,正式開發一定要注意不能這樣,這不是很安全的選擇。然後就是建立一個CWinApp的類,如果要CWinAppEx類,pApp->InitApplication() 初始化要換一下。上述編譯通不過
如我的CWinApp類為:BuilderEx.h
#pragma once
#include "stdafx.h"
#include <afxwinappex.h>
#ifndef __AFXWIN_H__
#error "在包含此檔案之前包含“stdafx.h”以生成 PCH 檔案"
#endif
#include "resource.h" // 主符号
class BuilderEx : public CWinApp
{
public:
BuilderEx();
// 重寫
public:
virtual BOOL InitInstance();
// 實作
DECLARE_MESSAGE_MAP()
};
extern BuilderEx theApp;
BuilderEx.cpp:
// BuilderEx.cpp : 定義應用程式的類行為。
//
#include "stdafx.h"
#include "BuilderEx.h"
#include "Builderdlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// BuilderEx
BEGIN_MESSAGE_MAP(BuilderEx, CWinAppEx)
//ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
// BuilderEx 構造
BuilderEx::BuilderEx()
{
// 支援重新啟動管理器
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
// TODO: 在此處添加構造代碼,
// 将所有重要的初始化放置在 InitInstance 中
}
// 唯一的一個 BuilderEx 對象
BuilderEx theApp;
// BuilderEx 初始化
BOOL BuilderEx::InitInstance()
{
// 如果一個運作在 Windows XP 上的應用程式清單指定要
// 使用 ComCtl32.dll 版本 6 或更高版本來啟用可視化方式,
//則需要 InitCommonControlsEx()。否則,将無法建立視窗。
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// 将它設定為包括所有要在應用程式中使用的
// 公共控件類。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinApp::InitInstance();
AfxEnableControlContainer();
// 建立 shell 管理器,以防對話框包含
// 任何 shell 樹視圖控件或 shell 清單視圖控件。
CShellManager *pShellManager = new CShellManager;
// 标準初始化
// 如果未使用這些功能并希望減小
// 最終可執行檔案的大小,則應移除下列
// 不需要的特定初始化例程
// 更改用于存儲設定的系統資料庫項
// TODO: 應适當修改該字元串,
// 例如修改為公司或組織名
SetRegistryKey(_T("應用程式向導生成的本地應用程式"));
BuilderDlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: 在此放置處理何時用
// “确定”來關閉對話框的代碼
}
else if (nResponse == IDCANCEL)
{
// TODO: 在此放置處理何時用
// “取消”來關閉對話框的代碼
}
// 删除上面建立的 shell 管理器。
if (pShellManager != NULL)
{
delete pShellManager;
}
// 由于對話框已關閉,是以将傳回 FALSE 以便退出應用程式,
// 而不是啟動應用程式的消息泵。
return FALSE;
}
這就是CWinApp的實作,這是一個對話框,你也可以設定其他的,這裡我們還要建立一個對話框,直接在資源中建立即可,建立後使用類向導建立一個類,在CWinApp中會實作的
我直接貼代碼
.h
#include "resource.h"
//#include <Windows.h>
//#include <afx.h>
#pragma once
// BuilderDlg 對話框
class BuilderDlg : public CDialogEx
{
DECLARE_DYNAMIC(BuilderDlg)
public:
BuilderDlg(CWnd* pParent = NULL); // 标準構造函數
virtual ~BuilderDlg();
// 對話框資料
enum { IDD = IDD_DIALOG_WINM };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支援
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
virtual BOOL InitInstance();
void OnPaint();
HICON m_hIcon;
void BuilderDlg::OnSize(UINT nType,int cx,int cy);
};
.cpp
//#include "BuilderDlg.h"
// BuilderDlg.cpp : 實作檔案
//
#include "stdafx.h"
//#include "Builder.h"
#include "BuilderDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// BuilderDlg 對話框
IMPLEMENT_DYNAMIC(BuilderDlg, CDialogEx)
BuilderDlg::BuilderDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(BuilderDlg::IDD, pParent)
{
EnableActiveAccessibility();
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON_MAIN);
//m_pAutoProxy = NULL;
}
BuilderDlg::~BuilderDlg()
{
}
void BuilderDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(BuilderDlg, CDialogEx)
ON_WM_SIZE()
END_MESSAGE_MAP()
// BuilderDlg 消息處理程式
BOOL BuilderDlg::InitInstance()
{
CDialogEx::OnInitDialog();
SetIcon(m_hIcon, TRUE); // 設定大圖示
SetIcon(m_hIcon, FALSE);
return TRUE;
}
void BuilderDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于繪制的裝置上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使圖示在工作區矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 繪制圖示
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
HCURSOR BuilderDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void BuilderDlg::OnSize(UINT nType,int cx,int cy)
{
CDialogEx::OnSize(nType, cx, cy);
//MessageBox(_T("Hello"));
CRect rect;
CRichEditCtrl * wnd;
GetClientRect(rect); //擷取客戶區大小
wnd=(CRichEditCtrl *)GetDlgItem(IDC_EDIT1); //擷取其上控件的指針,是個編輯框
if(wnd)wnd->MoveWindow(rect);
}
資源自己準備把,這裡就不多說了,項目設定一定要使用MFC庫,無論是靜态還是共享!
這個程式還有一個Edit控件,現在和MFC程式的做法是一樣的了,你自己想怎麼搞就怎麼搞!