分享
 
 
 

生死MFC程序

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

MFC将大部分函数都进行了封装,程序员只要改写部分重要的virtual函数即可,这往往使初学者摸不着头脑,连个WinMain函数都看不到,程序从哪开始从哪结束?基本的条理搞不清,永远也不会有提高。下面简单讲下基运行过程.

1,CMyWinApp theApp 程序从这里开始

2,_tWinMain() 在APPMODUL.CPP 它实际上只调用AfxWinMain函数

3,AfxWinMain() WINAMIN.CPP,去掉一些次要信息,它作的事就是:

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

int nReturnCode = -1;

CWinThread* pThread = AfxGetThread();

CWinApp* pApp = AfxGetApp(); ->实际上就是取得CMyWinApp对象指针

AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)

pApp->InitApplication()

pThread->InitInstance()

pThread->Run();

AfxWinTerm();

return nReturnCode;

}

其中:

AfxGetApp(); AFXWIN.CPP中

InitApplication() AFXWIN.CPP中

InitInstance() AFXWIN.CPP中

实际上AfxWinMainy就是调用:

CWinApp::InitApplication 因为我们程序没有改写它

CMyWinApp::InitInstance 我们改写了它且必须改写它,为什么?看源码就能证明一切

BOOL CWinApp::InitInstance() APPCORE.CPP中

{

return TRUE;

}

看到了吧,它什么也没干,直接return TRUE;

CWinApp::Run();

4:AfxWinInit() AFX内部初始化操作,APPINIT.CPP中,贴下源码,如下:

BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

..,去掉部分

pModuleState->m_hCurrentInstanceHandle = hInstance;

pModuleState->m_hCurrentResourceHandle = hInstance;

CWinApp* pApp = AfxGetApp();

if (pApp != NULL)

{

// Windows specific initialization (not done if no CWinApp)

pApp->m_hInstance = hInstance;

pApp->m_hPrevInstance = hPrevInstance;

pApp->m_lpCmdLine = lpCmdLine;

pApp->m_nCmdShow = nCmdShow;

pApp->SetCurrentHandles();

}

if (!afxContextIsDLL)

AfxInitThread();

return TRUE;

}

可以看到。它主要进行一些初始化工作.其中:

AfxInitThread() 在THRDCORE.CPP中

5:CWinApp::InitApplication() APPCORE.CPP中,

BOOL CWinApp::InitApplication()

{

if (CDocManager::pStaticDocManager != NULL)

{

if (m_pDocManager == NULL)

m_pDocManager = CDocManager::pStaticDocManager;

CDocManager::pStaticDocManager = NULL;

}

if (m_pDocManager != NULL)

m_pDocManager->AddDocTemplate(NULL);

else

CDocManager::bStaticInit = FALSE;

return TRUE;

}

5:CMyWinApp::InitInstance() 继InitApplication后就是InitInstance调用了。在我们改写的InitStance函数中,将是我们的主窗口的生命,在这里我们会有这样的操作:

m_pMainWnd=new CMyFrameWnd();开始我们的主窗口,创建主窗口,MDI程序采取的是LoadFrame,大家可以看CFrameWnd::LoadFrame()(WNDFRM.CPP中),实际还是做了一样的事,大家不防看下源码。

6:CFrameWnd::Create()

BOOL CFrameWnd::Create(LPCTSTR lpszClassName, 类名

LPCTSTR lpszWindowName, 窗口名

DWORD dwStyle, 样式

const RECT& rect, 区域,默认:rectDefault

CWnd* pParentWnd, 父窗口

LPCTSTR lpszMenuName, 菜单

DWORD dwExStyle, 扩展样式

CCreateContext* pContext)

{

HMENU hMenu = NULL;

if (lpszMenuName != NULL)

{

HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);

if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)

{

TRACE0("Warning: failed to load menu for CFrameWnd.\n");

PostNcDestroy(); // perhaps delete the C++ object

return FALSE;

}

}

m_strTitle = lpszWindowName; // save title for later

if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,

rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,

pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))

{

TRACE0("Warning: failed to create CFrameWnd.\n");

if (hMenu != NULL)

DestroyMenu(hMenu);

return FALSE;

}

return TRUE;

}

7:CWnd::CreateEx() 可以看到CFrameWnd::Create,只是调用了CreateEx 函数,CFrameWnd没有改字CreateEx 函数,所以它调用的是CWnd 类的函数.

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

LPCTSTR lpszWindowName, DWORD dwStyle,

int x, int y, int nWidth, int nHeight,

HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

{

// allow modification of several common create parameters

CREATESTRUCT cs; 用过SDK写程序的朋友一定知道这是想做什么

cs.dwExStyle = dwExStyle;

cs.lpszClass = lpszClassName;

cs.lpszName = lpszWindowName;

cs.style = dwStyle;

cs.x = x;

cs.y = y;

cs.cx = nWidth;

cs.cy = nHeight;

cs.hwndParent = hWndParent;

cs.hMenu = nIDorHMenu;

cs.hInstance = AfxGetInstanceHandle();

cs.lpCreateParams = lpParam;

if (!PreCreateWindow(cs))

{

PostNcDestroy();

return FALSE;

}

AfxHookWindowCreate(this);

HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,

cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,

cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);

...

}

此函数又调用了PreCreateWindow,CreateWindowEx,

8:CFrameWnd::PreCreateWindow(), PreCreateWindow是个virtual,由于this 指针的原故,这里是调用CFrameWnd的PreCreateWindow.一般我们的程序都会改写些函数,在此设定窗口的一些样式。

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) --->WINFRM.CPP

{

if (cs.lpszClass == NULL)

{

VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background

}

...

}

#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)

AfxEndDeferRegisterClass() --->WINCORE.CPP,在这个函数中,调用RegisterWithIcon(实际上还是要调用AfxRegisterClass),和AfxRegisterClass,会我们注五个窗口类.在non-Unicode下使用MFC动态链接版和谳试版,五个类为:

"AfxWnd42d"

"AfxControlBar42d"

"AfxMDIFrame42d"

"AfxFrameOrView42d"

"AfxOleControl42d"

在Uncode中使用静态和调试版,是:

"AfxWnd42sud"

"AfxControlBar42sud"

"AfxMDIFrame42sud"

"AfxFrameOrView42sud"

"AfxOleControl42sud"

大家可以看到了。PreCreateWindow是在窗口产生前被调用,用来注册窗口类,如果我们指定的窗口类为NULL,则会用系统默认的。可以来看下不同功能的窗口使用的窗口类:

BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs) -->WINCORE.CPP

{

if (cs.lpszClass == NULL)

{

...

cs.lpszClass = _afxWnd; file://使用_afxWnd窗口类

}

}

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs) -->WINFRM.CPP

{

if (cs.lpszClass == NULL)

{

...

cs.lpszClass = _afxWndFrameOrView; // COLOR_WINDOW background

}

}

BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs) -->WINMDI.CPP

{

if (cs.lpszClass == NULL)

{

...

cs.lpszClass = _afxWndMDIFrame; file://使用_afxWndMDIFrame 窗口类

}

return TRUE;

}

...

9:CWinApp::Run() 程序到这里,窗口类注册好了。并显示出来了。UpDateWindow函数将会调用,并产生一个WM_PAINTIITH,等待处理。便进入了RUN函数,

file://APPCORE.CPP

int CWinApp::Run()

{

if (m_pMainWnd == NULL && AfxOleGetUserCtrl())

{

// Not launched /Embedding or /Automation, but has no main window!

TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.\n");

AfxPostQuitMessage(0);

}

return CWinThread::Run(); // 调用CWinThread::Run()

}

file://THRDCORE.CPP

int CWinThread::Run()

{

ASSERT_VALID(this);

// for tracking the idle time state

BOOL bIdle = TRUE;

LONG lIdleCount = 0;

// acquire and dispatch messages until a WM_QUIT message is received.

for (;;)

{

// phase1: check to see if we can do idle work

while (bIdle &&

!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))

{

// call OnIdle while in bIdle state

if (!OnIdle(lIdleCount++))

bIdle = FALSE; // assume "no idle" state

}

// phase2: pump messages while available

do

{

// pump message, but quit on WM_QUIT

if (!PumpMessage())

return ExitInstance();

// reset "no idle" state after pumping "normal" message

if (IsIdleMessage(&m_msgCur))

{

bIdle = TRUE;

lIdleCount = 0;

}

} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));

}

ASSERT(FALSE); // not reachable

}

如果没有消息,则调用OnIdle(),空闲处理,否则PumpMessage(),看下它做了什么?

BOOL CWinThread::PumpMessage()

{

ASSERT_VALID(this);

if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))

{

#ifdef _DEBUG

if (afxTraceFlags & traceAppMsg)

TRACE0("CWinThread::PumpMessage - Received WM_QUIT.\n");

m_nDisablePumpCount++; // application must die

// Note: prevents calling message loop things in 'ExitInstance'

// will never be decremented

#endif

return FALSE;

}

#ifdef _DEBUG

if (m_nDisablePumpCount != 0)

{

TRACE0("Error: CWinThread::PumpMessage called when not permitted.\n");

ASSERT(FALSE);

}

#endif

#ifdef _DEBUG

if (afxTraceFlags & traceAppMsg)

_AfxTraceMsg(_T("PumpMessage"), &m_msgCur);

#endif

// process this message

if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))

{

::TranslateMessage(&m_msgCur);

::DispatchMessage(&m_msgCur);

}

return TRUE;

}

呵,和SDK程序做法一样,GetMessage,TranslateMessage(),DisptchMessage()

好了。进入到Run ()这里,程序就活动起来了。它会对一系列的消息进行处理。并在收到WM_CLOSE 消息时退出.默认函数对WM_CLOSE的处理是是调用::DestroyWindow(),关因而发出WM_DESTROY消息,默认的的WM_DESTROY处理方式是调用::PostQuitMessage(),因此发出WM_QUIT,Run收到WM_QUIT时,就结束消息循环,调用ExitInstance,最后在AfxWinMain中执行AfxWinTerm结束程序.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有