開發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程序的做法是一樣的了,你自己想怎麼搞就怎麼搞!