`
film
  • 浏览: 225297 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

[转自木目]Visual C++学习历程

 
阅读更多
科班出身,C语言学而致用近五年,几欲跨入神圣的Win32殿堂,终因天资愚钝每每跌出门外。近来终于下定决心利用开学前这段时间再学学VC,本月 5日,买了一本侯俊杰先生的《深入浅出MFC》,打算认真学一学可视化Win32编程,这样一段经历或许可以为本人和他人的学习提供些许借鉴。

我和大多初学者一样,对于VC与MFC之间的区别并不甚在意,相信这个问题将随着学习的深入不攻自解。

单就Win32的SDK或MFC编程来讲,理解其所谓的事件驱动、消息传递模式对于我这样一个了解OOP(Object Oriented Pragramming)的编程者并不是一项太艰巨的任务,但这也并不意味着拥有C++基础就能够轻易征服复杂庞大的MFC,我之所以三过其门而不入,很大程度上是因为MFC中有太多的%26ldquo;稀奇古怪%26rdquo;的东西,比如大量的宏、大量的虚函数%26hellip;% 26hellip;

下面我就把我的学习历程呈现给你,希望可以让你从中得到点什么。

一、五年来抵制VC的三个理由:

1、对于用了五年Borland的TC2.0的我来说,我对main的感情犹如滔滔江水,又如黄河泛滥,而自以为是的MS偏偏要加个win,此为其一;

2、你MS为了显摆Windows加个win也就罢了,换了我,或许也会加个fox啊什么的,毕竟这年头%26ldquo;好酒也怕巷子深% 26rdquo;,%26ldquo;人不出名死也羞%26rdquo;,但自有C以来,我所见所用的变量和函数多用小写,可到了OOP这儿又是另立异端,什么%26ldquo;匈牙利命名法%26rdquo;一会大写、一会小写,欺侮我打字慢可以试试别的方法吧?此为其二;

3、这些大大小小的名字似乎日久觉得也很舒服,意义也一目了然,可是你MS用那么多的宏干什么?当一个人有太多的名字,你叫我怎么去想她?此为其三。

显而易见,这些都是不成其为理由的,于是,终于开始了我的Win32之旅,第一站当然从Win32 Application程序入手,毕竟,这儿和曾经的Win32 Console最相似!

二、再也找不到main函数,看看WinMain吧!

int WINAPI WinMain(

HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nShowCmd

)

在这里,WinMain是Windows程序的入口,函数返回类型为int,WINAPI(宏名:实际上是__stdcall)是Windows程序函数调用习惯,异于DOS C的_cdecl方式。

一个最简单的单文档SDK程序执行顺序如下:

1、系统调用:WinMain;

2、设计窗口:WNDCLASS wndcls(并对其10个参数进行赋值);

3、注册窗口:RegisterClass(%26amp;wndcls);

4、创建窗口:hWnd = CreateWindow(”YuleFox”,”Yule Fox 2006″,WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);

5、显示窗口:ShowWindow(hWnd,SW_NORMAL);

6、更新窗口:UpdateWindow(hWnd);

7、消息循环:while(GetMessage(%26amp;msg,hWnd,0,0))

{

TranslateMessage(%26amp;msg);

DispatchMessage(%26amp;msg);

}

8、窗口函数:LRESULT CALLBACK WndProc(

HWND hWnd,

UINT uMsg,

WPARAM wParam,

LPARAM lParam

)

整个程序如下,比较简单:

// 如果你不知道自己需要哪些头文件,不妨用用下面这一个,我就属于不知道的那一种%26hellip;%26hellip;

#include

// 下一个因为是C的标准输入输出头文件,这个我最熟悉%26hellip;%26hellip;

#include

// 这就是传说中的Windows Procession!一般的函数先声明再使用,看来这一点C/C++是通行惯例了!

LRESULT CALLBACK WndProc(

HWND hWnd,

UINT uMsg,

WPARAM wParam,

LPARAM lParam

);

// 终于看到main函数了,噢,我错了,是WinMain%26hellip;%26hellip;

int WINAPI WinMain(

HINSTANCE hInstance, // 当前实例句柄,句柄?孙鑫说%26ldquo;句柄就是资源%26rdquo;,孙鑫?%26hellip;%26hellip;

HINSTANCE hPrevInstance, // Win32令之永远为0,糊涂中

LPSTR lpCmdLine, // 指向命令行参数的指针

int nShowCmd) // 窗口显示方式

{

// 设计窗口类

WNDCLASS wndcls;

wndcls.style = CS_HREDRAW | CS_VREDRAW;

wndcls.lpfnWndProc = (WNDPROC)WndProc;

wndcls.cbClsExtra = 0;

wndcls.cbWndExtra = 0;

wndcls.hInstance = hInstance;

wndcls.hIcon = LoadIcon(NULL,IDI_ERROR);

wndcls.hCursor = LoadCursor(NULL,IDC_CROSS);

wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

wndcls.lpszMenuName = NULL;

wndcls.lpszClassName = “YuleFox”;

// 注册窗口类

RegisterClass(%26amp;wndcls);

// 创建窗口

HWND hWnd;

hWnd = CreateWindow(”YuleFox”,”Yule Fox 2006″,WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);

// 显示窗口

ShowWindow(hWnd,SW_NORMAL);

// 更新窗口

UpdateWindow(hWnd);

// 消息循环

MSG msg;

while(GetMessage(%26amp;msg,hWnd,0,0)) // 从消息队列中取出消息,永真,除非%26hellip;%26hellip;

{

TranslateMessage(%26amp;msg); // 转换消息

DispatchMessage(%26amp;msg); // 分发消息给需要的窗口处理

}

return 0;

}

// 实现窗口函数

LRESULT CALLBACK WndProc(

HWND hWnd, // 窗口句柄

UINT uMsg, // 消息名称

WPARAM wParam, // 消息附加信息,比如当键盘按下,获得消息WM_KEYDOWN,具体是哪个键呢?HERE!

LPARAM lParam // 消息附加信息

)

{

// 下面处理消息,可简可繁,这几个嘛,比较EASY吧?

switch(uMsg)

{

case WM_PAINT:

HDC hDc;

PAINTSTRUCT ps;

hDc = BeginPaint(hWnd,%26amp;ps);

TextOut(hDc,0,0,”Hello!”,strlen(”Hello!”));

EndPaint(hWnd,%26amp;ps);

ReleaseDC(hWnd,hDc);

break;

case WM_CHAR:

char szChar[20];

sprintf(szChar,”The char is %c”, wParam);

MessageBox(hWnd,szChar,”Keyboard Input”,MB_OK);

break;

case WM_LBUTTONDOWN:

HDC hDC;

hDC = GetDC(hWnd);

TextOut(hDC,0,50,”Left Button Clicked Down!”,strlen(”Left Button Clicked Down!”));

ReleaseDC(hWnd,hDC);

break;

case WM_CLOSE:

if(IDYES == MessageBox(hWnd,”Realy to CLOSE the Application?”,”Close”,MB_YESNO))

{

DestroyWindow(hWnd);

}

break;

case WM_DESTROY:

PostQuitMessage(0);

default:

return DefWindowProc(hWnd,uMsg,wParam,lParam);

}

return 0;

}

搞清楚Win32 SDK程序的脉络,似乎可以开始动手创建MFC程序了。

二、当我在MFC连WinMain也找不到的时候,我又一次胆怯了。

直接出来5个类:

CAboutDlg : public CDialog

CMainFrame : public CFrameWnd // 框架窗口,派生自CWnd

CFOXApp : public CWinApp

CFOXDoc : public CDocument

CFOXView : public CView // 子窗口,派生自CWnd

还有一个全局变量:CFOXApp theApp

都没有见过!我好不容易搞明白的SDK脉络怎么一下全没了?突然蹦出这些东西,这对我的自信心真是一个严重伤害!我最早就是让theApp吓倒的,所以这一次我也是从theApp开始的:

1、:CWinApp::CWinApp(LPCTSTR lpszAppName)

当对象被实例化的时候,首先被调用的是其对应类中的构造函数,CFOXApp派生自CWinApp,所以我们先到了这儿。当我们看到:

pThreadState->m_pCurrentWinThread = this;

这意味着当前执行线程为this,即theApp,很有道理,然后呢?

2、:extern “C” int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

// call shared/exported WinMain

return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

这么长?易水三千,我只取一瓢饮:_tWinMain,又改名了?是的,也不是,看看前面提到%26ldquo;五年来抵制VC的三个理由%26rdquo;;

3、:#define _tWinMain WinMain

现在提起的心又稍稍下放了。可是%26hellip;%26hellip;,调用一个_tWinMain,居然只是为了return AfxWinMain?我实在无语!

4、:int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

仅仅为了一个WinMain,要绕这么大圈子,到现在才看到一个做正事的,这让我对MS感到失望,这是不是也算一个理由呢?好了,不怨天,不尤人,继续吧,看看这个AfxWinMain有什么东西:

CWinThread* pThread = AfxGetThread();

CWinApp* pApp = AfxGetApp(); // CwinApp派生自CWinThread,可见pThread和pApp均指向theApp

AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)

pApp->InitApplication() // 内部初始化管理

pThread->InitInstance() // 虚函数,须重写覆盖之,应该去注册窗口类了%26hellip;%26hellip;

pThread->Run() // 控制消息循环

5、:BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)

wndcls.lpfnWndProc = DefWindowProc; // 窗口过程处理函数

:BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass)

MFC已定义好若干窗口类,在此只需根据fToRegister去注册即可。

6、:BOOL CMainFrame::PreCreateWindow(CREATESTRUCT%26amp; cs)

:BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT%26amp; cs)

创建窗口之前,注册窗口,一般在PreCreateWindow中注册,对于单/多文档等程序,在处理InitInstance中 ProcessShellCommand时已注册窗口,而后调用PreCreateWindow,在PreCreateWindow中调用 AfxDeferRegisterClass(即AfxEndDeferRegisterClass)。

7、:BOOL CFrameWnd::Create(LPCTSTR lpszClassName,

LPCTSTR lpszWindowName,

DWORD dwStyle,

const RECT%26amp; rect,

CWnd* pParentWnd,

LPCTSTR lpszMenuName,

DWORD dwExStyle,

CCreateContext* pContext)

: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)

在CreateEx中再次调用PreCreateWindow

CREATESTRUCT%26amp; cs

typedef struct tagCREATESTRUCTW {

LPVOID lpCreateParams;

HINSTANCE hInstance;

HMENU hMenu;

HWND hwndParent;

int cy;

int cx;

int y;

int x;

LONG style;

LPCWSTR lpszName;

LPCWSTR lpszClass;

DWORD dwExStyle;

} CREATESTRUCTW, *LPCREATESTRUCTW;

typedef CREATESTRUCTW CREATESTRUCT;

WINUSERAPI

HWND

WINAPI

CreateWindowExW(

DWORD dwExStyle,

LPCWSTR lpClassName,

LPCWSTR lpWindowName,

DWORD dwStyle,

int X,

int Y,

int nWidth,

int nHeight,

HWND hWndParent ,

HMENU hMenu,

HINSTANCE hInstance,

LPVOID lpParam);

#define CreateWindowEx CreateWindowExW

仔细观察不难发现,CREATESTRUCT的成员与CreateWindowEx的参数一一对应,至于为什么会是相反顺序,这是由于C/C++中函数参数入栈顺序(FILO)决定的。以引用方式调用cs,以使我们可以在创建窗口之前自行定义窗口形式。

8、BOOL CNFXApp::InitInstance()

m_pMainWnd->ShowWindow(SW_SHOW); // 显示窗口

m_pMainWnd->UpdateWindow(); // 更新窗口

9、:int CWinThread::Run() // 重新回到WinMain函数:pThread->Run()

:int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

PeekMessage(%26amp;m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)

OnIdle(lIdleCount++)

PumpMessage() // BOOL CWinThread::PumpMessage()

::TranslateMessage(%26amp;m_msgCur);

::DispatchMessage(%26amp;m_msgCur);

10、再来看一下这5个类:

CAboutDlg : public CDialog // ABOUT对话框,窗口的一种

CMainFrame : public CFrameWnd // 框架窗口,派生自CWnd,用以生成程序所定制的主框架窗口,可看作CView的父窗口

CFOXApp : public CWinApp // 产生应用程序实例theApp,有且只有一个

CFOXDoc : public CDocument // 文档类负责数据I/O

CFOXView : public CView // 子窗口,派生自CWnd,覆盖在CMainFrame窗口之上,负责数据显示

经典的Frame/Document/View结构凭借不同类型的模板结合在一起

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CNFXDoc),

RUNTIME_CLASS(CMainFrame), // main SDI frame window

RUNTIME_CLASS(CNFXView));

AddDocTemplate(pDocTemplate);

这样,一个SDK程序的执行过程就被从MFC程序代码中活生生的挖了出来,心情也略微改善了一些,剩下的工作就是如何做好一个程序员应该做的了。今天有点收获,也有点累了!

分享到:
评论

相关推荐

    Visual C++ + SQL Server数据库开发与实例(随书光盘)

    Visual C++是Microsoft Visual Studio开发组件中最为强大的编程工具。在数据库领域,其表现也异常突出,它不仅提供了多种数据库开发技术,支持几乎所有的数据库系统,如SQL Server,DB2,Sybase,FoxPro,Access等,...

    Visual C++实践与提高-COM和COM+篇『PDF』

    5.4 在Visual C++中使用代码组件 5.4.1 利用OLE/COM Object Viewer查看组件信息 5.4.2 利用COM库函数使用代码组件——例程VCAuotCom 5.4.3 通过ClassWizard使用代码组件——例程VCAuotClw 5.4.4 利用#import指令...

    Visual C++与Delphi之比较

    "Visual C++与Delphi之比较"最近在CSDN的论坛上的讨论非常火热,本文将以一个程序员的角度,从技术水平、功能、性能、易用性、稳定性、发展历程和前景等方面,以Visual C++6和Delphi5为代表,尽可能客观地比较介绍...

    C与C++程序设计学习与实验系统.rar

    新增读书笔记功能有利用户 记录教程中的重点、难点、学习心得体会,同时,为了便于C语言学习,加入C语言学习指导、入门程序实例、典型源程序、典型的函数算法,课程设计指导、课程设计源程序、Visual C++6.0中英文...

    C与C++程序设计学习与实验系统 2011.2

    Visual C++6.0中英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、2004...

    c/c++程序设计学习与实验系统

    量身定制的一个简单易用的 C/C++程序设计学习与实验软件(支持TC2/TC3、VC6三种编译器,没有使用日期限制,重新集成在VISTA、WINDOWS 7系统下正常运行的Visual C++6.0简化版)。与软件配套的《 C/C++程序设计教程(配...

    C/C++程序设计学习与实验系统 V2008.13.part1

    原名《Turbo C/C++ for Windows 集成实验与学习环境》,现已更名为《C/C++程序设计学习与实验系统》,现在已全面支持最新操作系统VISTA,它由从事一线教学的大学教师根据C/C++初学者的特点,量身定制的一个简单易用的...

    精通Visual.C++指纹模式识别系统算法及实现 (完整版+中文版)pdf 格式

    3.3.2 自建VisualC++指纹模式识别演示系统 38 3.3.3 VisualC++指纹模式识别开发环境详细说明 40 3.3.4 指纹图像BMP位图的读取 42 3.3.5 指纹图像的灰度模型 49 3.4 编制可移植VisualC++指纹识别源代码的要点 51 第二...

    C_C++程序设计学习与实验系统 2010 part1

    Visual C++6.0中英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、2004...

    C_C++集成实验与学习环境

    现在已支持最新操作系统WINDOWS 7,它是从事一线教学的大学教师根据多媒体教学演示和C语言初学者的特点,量身打造的一个简单易用的C/C++程序设计教学演示、学习与实验软件(支持TC2/TC3、VC6三种编译器,没有使用日期...

    C/C++程序设计学习与实验系统 2010.part1

    Visual C++6.0中英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、二级 ...

    C与C++程序设计学习与实验系统

    原名《Turbo C/C++ for Windows 集成实验与学习环境》,支持32位与64位的WINDOWS 7,它是从事一线教学的大学教师根据多媒体教学演示和C语言初学者的特点,量身打造的一个简单易用的C/C++程序设计教学演示、学习与实验...

    C/C++程序设计学习与实验系统

    现在已支持最新操作系统WINDOWS 7,它是从事一线教学的大学教师根据多媒体教学演示和C语言初学者的特点,量身打造的一个简单易用的C/C++程序设计教学演示、学习与实验软件(支持TC2/TC3、VC6三种编译器,没有使用日期...

    C/C++程序设计学习与实验系统 2010.part2

    Visual C++6.0中英文编译错误信息同步显示功能(并配有60多种同步的语法错误程序实例、修改方法等)、 Turbo C2.0 中英文编译错误信息同步显示功能、Turbo C++3.0常见编译错误信息、C语言专业词汇的中英文对照、二级 ...

    c++与c程序设计学习与实验系统(2014)

    原名《Turbo C/C++ for Windows 集成实验与学习环境》,支持32位与64位的WINDOWS 7,它是从事一线教学的大学教师根据多媒体教学演示和C语言初学者的特点,量身打造的一个简单易用的C/C++程序设计教学演示、学习与实验...

    C_C++程序设计学习与实验系统 V2008

    Visual C++6.0 常见编译错误信息、Turbo C++3.0常见编译错误信息、 Turbo C2.0 常见编译错误信息、C语言专业词汇的中英文对照、2004年到2006年全部二级 C 语言的真题笔试试卷及答案与分析和10套上机模拟试题和详尽的...

    Turbo C&C++ for Windows 集成实验与学习环境

    Visual C++6.0 常见编译错误信息、Turbo C++3.0常见编译错误信息、 Turbo C2.0 常见编译错误信息、C语言专业词汇的中英文对照、2004年到2006年全部二级 C 语言的真题笔试试卷及答案与分析和上机模拟试题和详尽的答案...

    Turbo C&C++ for Windows 集成实验与学习环境.part16

    Visual C++6.0 常见编译错误信息、Turbo C++3.0常见编译错误信息、 Turbo C2.0 常见编译错误信息、C语言专业词汇的中英文对照、2004年到2006年全部二级 C 语言的真题笔试试卷及答案与分析和上机模拟试题和详尽的答案...

    Turbo C&C++ for Windows 集成实验与学习环境.part08

    Visual C++6.0 常见编译错误信息、Turbo C++3.0常见编译错误信息、 Turbo C2.0 常见编译错误信息、C语言专业词汇的中英文对照、2004年到2006年全部二级 C 语言的真题笔试试卷及答案与分析和上机模拟试题和详尽的答案...

Global site tag (gtag.js) - Google Analytics