Win32開發MFC程序

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




















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章