接着Win32对话框程序(1)来写 ,解决遗留的问题,即理解函数及其调用关系。文章中有些地方是自己的推断,因此肯定有叙述不准确甚至错误的地方,请指正,感谢~

*******************************正文分割************************************

WinMain函数

Win32对话框程序(1)中说了WinMain是应用程序的入口,其输入参数有四个,根据MSDN上的叙述:

输入变量声明 说明
HINSTANCE    hInstance 此应用当前实例的句柄 
HINSTANCE    hPrevInstance 此应用上一个实例的句柄,一般都是NULL
LPSTR    lpCmdLine The command line for the application, excluding the program name
int    nCmdShow 设置窗口的显示方式,比如nCmdShow=SW_MAXIMIZE表示最大化窗口,详见MSDN

因为WinMain是应用程序的入口,即程序运行的第一个函数,所以这四个参数应该是操作系统传给WinMain的,至于操作系统是怎么把他们传进来的,现在没管~@_@~

何为句柄?何为实例?如果我们同时运行两个记事本程序,我们会发现针对它们的不同操作是互不干扰的,这两个“窗口”即使记事本的两个实例,它们被加载在内存中的不同空间,但为了实现互不干扰的操作和处理,我们需要区分彼此,便使用句柄来标识应用程序的不同实例(两个记事本的句柄不同),我们能通过句柄访问相应对象的信息,但句柄不是指针,程序不能利用句柄来直接阅读文件中的信息,它只是一个唯一的整数值。

lpCmdLine是不包含程序名的命令行,根据MSDN使用函数GetCommandLine()也可返回命令行字符串,不过会包含程序名。为了验证这个所谓的“命令行”是什么,在WinMain函数体开头加了两行代码将其显示出来

1
2
MessageBox(NULL, GetCommandLine(), TEXT("CMDLINE"), MB_OK);
MessageBox(NULL, lpCmdLine, TEXT("CMDLINE_1p"), MB_OK);

在VC6.0中运行,GetCommandLine()显示为完整路径包括程序名,lpCmdLine显示为空,如下:

于是我在命令行模式下运行,显示出所谓的The command line for the application究竟是什么,也许它可以用于向程序传递参数来进行交互式操作

此外,入口函数名并不一定是WinMain,也可以是main(),但需要在main函数体内显示的调用类似GetCommandLine()这样的函数来引入WinMain的四个参数并作为变量(后面需要使用),此外还有_tWinMain(需进一步查阅)

现在大体理解了WinMain函数了,接下来看看其他函数都在干什么

函数及程序框架理解

先贴WinMain函数

1
2
3
4
5
6
7
8
9
10
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    //Enable IPAddress、Calendar.etc
    InitCommonControls();
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, Main_Proc);
    return 0;
}
函数名 参数 说明
InitCommonControls 该函数注册并初始化通用控件窗口类,使用某些高级控件时需要调用此函数,链接器会将你的程序链接到comctl32.lib,然后在程序启动时,会加载comctl32.dll。(据MSDN,此函数已废弃,需使用InitCommonControlsEx)
DialogBox (hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, Main_Proc)

MSDN,该函数Creates a modal dialog box from a dialog box template resource,然后将控制权交给自定义的Main_Proc函数,此回调函数通过调用EndDialog函数来终结the modal dialog box。

参数说明参数1为包含The dialog box template的句柄,可以是NULL;参数2是The dialog box template,使用MAKEINTRESOURCE宏来讲对话框ID(整数)转化为resource type;参数3为A handle to the window that owns the dialog box;参数4为A pointer to the dialog box procedure,函数指针。

MainDlg.cpp中包含四个函数:

函数名

参数

功能

Main_Proc

(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

消息分流器,进行消息分流 

Main_OnInitDialog

(HWND hwnd, HWND hwndFocus, LPARAM lParam)

return

Main_OnCommand

(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)

switch(ID),case

Main_OnClose

(HWND hwnd)

EndDialog

消息分流器

1
2
3
4
5
6
7
8
9
10
11
BOOL WINAPI Main_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
        HANDLE_MSG(hWnd, WM_INITDIALOG, Main_OnInitDialog);
        HANDLE_MSG(hWnd, WM_COMMAND, Main_OnCommand);
        HANDLE_MSG(hWnd, WM_CLOSE, Main_OnClose);
    }
 
    return FALSE;
}

HANDLE_MSG也是一个宏,它在windowsx.h中定义,如下:

1
#define HANDLE_MSG(hwnd, message, fn) case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))

比如代码

HANDLE_MSG(hWnd, WM_INITDIALOG, Main_OnInitDialog);

实际被替换为

case (WM_INITDIALOG): return HANDLE_WM_CREATE((hwnd), (wParam), (lParam), (Main_OnInitDialog))

可见,可见消息分流器的作用就是当消息出现时将控制权交给不同的程序,一些相关的参数也会同时传给相应程序。

如WM_INITDIALOG等为消息,由操作系统传递给程序,根据MSDN,WM_INITDIALOG消息是在对话框马上要显示前(即对话框内存中已经准备好了,但还没有显示在屏幕上)发给程序的,程序可以在此时执行一些初始化操作;同理,WM_COMMAND消息和WM_CLOSE消息从字面就基本可以理解。

接下来把其他三个函数的代码都贴在下面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
BOOL Main_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
    return TRUE;
}
 
void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
    switch(id)
    {
        case IDC_OK:
        {          
            MessageBox(hwnd,TEXT("欢迎"),TEXT("问好"),MB_OK);
        }
        break;
        default:
        break;
    }
}
 
void Main_OnClose(HWND hwnd)
{
    EndDialog(hwnd, 0);
}

可见,Main_Proc函数是一直在执行中的,时刻等待操作系统传递消息进来,根据不同消息将控制权交予不同的函数,包括初始化和关闭函数,当然实现功能最主要的在函数Main_OnCommand中,对话框中有菜单和不同的控件,通过ID对他们进行标示,如果用户对他们进行了某种操作(比如单击),则在Main_OnCommand函数体内进入相应的case,执行其中的代码,如上,当点击“确定”按钮是会弹出“欢迎”对话框。

**********************************************************************************************

以上就是《C语言也能干大事》中介绍的对话框程序的基本框架,当然,对话框程序应该是Windows编程中很简单的,还有很多其他的内容需要学习,此外,学习windows编程很重要的一部分就是掌握尽可能多的API,万丈高楼平地起,一步步来~

遗留问题

操作系统是如何向程序传递参数的(不急迫),即更深入的理解Windows的消息传递机制;其他……

参考

  1. C语言也能干大事http://rupeng.com/forum/forum-52-1.html

  2. WinMain和main http://blog.163.com/hanyinlong@126/blog/static/99751486201212345130881/

  3. 消息分流器http://www.cnblogs.com/ifaithu/articles/2478841.html

Win32对话框程序(2)的更多相关文章

  1. Win32对话框程序(1)

    之前学C语言是一直都是在控制台下面操作的,面对的都是黑框框,严重的打击了学习的兴趣.后来在TC下进行C语言课程设计,做了图形界面编程,但都是点线面画的…… 中间隔了好长一段时间没有碰过C语言,最近才开 ...

  2. 如何让win32对话框居中显示

    在编写win32对话框程序,如果是用visual studio建的win32对话框程序,默认是不居中显示的,about 对话框也是这样的,用资源编辑器打开,可以在属性里面设置居中center 为tur ...

  3. (转载)用VS2012或VS2013在win7下编写的程序在XP下运行就出现“不是有效的win32应用程序“

    原文地址:http://www.vcerror.com/?p=1483 问题描述: 用VC2013编译了一个程序,在Windows 8.Windows 7(64位.32位)下都能正常运行.但在Win ...

  4. 给Win32 GUI程序增加控制台窗口的方法

    给Win32 GUI程序增加控制台窗口的方法 2008年10月11日 星期六 下午 04:43 在Win32的GUI程序中,没有控制台窗口,我们输出调试信息时有些不方便,以往我的做法是使用Messag ...

  5. java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 应用程序。

    JNA 调用 dll 库时,保错: ///////////////// 通过 JNA 引入 DLL 库 //////////// /** * ID_FprCap.dll 负责指纹的采集, 指纹仪的初始 ...

  6. VC++ 对话框程序响应键盘消息的处理方法的说明(非常重要)

    基于MFC对话框的应用程序在响应按键消息和热键方面都力不从心,CDialog类的消息循环中去掉了TranslateAccelerator函数,因此不能响应热键:同时由于对话框上可能有很多控件,且默认情 ...

  7. python ImportError: DLL load failed: %1 不是有效的 Win32 应用程序

    导入的时候报出了 ImportError 在windows上安装python 的模块后,导入模块时报 python ImportError: DLL load failed: %1 不是有效的 Win ...

  8. 【转】WIN32 控制台程序

    http://blog.csdn.net/houmin0036/article/details/7702236 win32控制台项目指在32位Windows命令提示符(即所谓的dos)环境下运行的应用 ...

  9. 【转】VS2012编译出来的程序,在XP上运行,出现“.exe 不是有效的 win32 应用程序” “not a valid win32 application”

    原文网址:http://www.cnblogs.com/Dageking/archive/2013/05/15/3079394.html VS2012编译出来的程序,在XP上运行,出现“.exe 不是 ...

随机推荐

  1. 在本地没有安装Oracle的情况下,使用plsql远程连接数据库

    远程连接数据库的方式不止一种.这里主要写在本地没有安装Oracle的情况下,使用plsql可视化工具远程连接数据库的方式. 一.前提 首先你本地得安装有plsql工具.具体的安装步骤就不多说了. 二. ...

  2. BZOJ3629(JLOI2014)聪明的燕姿

    (⊙﹏⊙)我交了好久,有坑啊...(如果没有匹配的话,即输出0种情况要记得换行...) 就是搜索,加上一点数论,并不太难... #include<cstdio> #include<c ...

  3. springboot+redis分布式锁-模拟抢单

    本篇内容主要讲解的是redis分布式锁,这个在各大厂面试几乎都是必备的,下面结合模拟抢单的场景来使用她:本篇不涉及到的redis环境搭建,快速搭建个人测试环境,这里建议使用docker:本篇内容节点如 ...

  4. 跟我一起学opencv 第四课之图像的基本操作

    1.图像是由像素组成的,所以修改了像素就可以实现图像的改变. 2先看灰度图像(单通道): *****2.获取灰度图像的像素值使用:  int gray = gray_src.at<uchar&g ...

  5. 前端笔记之NodeJS(一)初识NodeJS&内置模块&特点

    一.NodeJS简介 NodeJS是开发服务器后台的东西,和PHP.JavaEE.python类似,和传统的浏览器的关注DOM的JS完全不同,将JavaScript触角伸到了服务器端.内核是Chrom ...

  6. 介绍几款 Python 类型检查工具

    近日,微软在 Github 上开源了一个 Python 静态类型检查工具:pyright ,引起了社区内的多方关注. 微软在开源项目上的参与力度是越来越大了,不说收购 Github 这种大的战略野心, ...

  7. 一个小实例理解js 原型和继承

    导语1:一个构造函数的原型对象,其实就是这个构造函数的一个属性而已,属性名叫prototype,值是一个对象,对象中有一些属性和方法,所以每个构造函数的实例对象都拥有这些属性和方法的使用权. 导语2: ...

  8. 从spring框架中的事件驱动模型出发,优化实际应用开发代码

    一.事件起源 相信很多人在使用spring框架进行开发时,都会遇到这样的需求:在spring启动后,立即加载部分资源(例如:spring启动后立刻加载资源初始化到redis中).当我去解决这个问题时发 ...

  9. 微服务容错限流Hystrix入门

    为什么需要容错限流 复杂分布式系统通常有很多依赖,如果一个应用不能对来自依赖 故障进行隔离,那么应用本身就处在被拖垮的风险中.在一个高流量的网站中,某个单一后端一旦发生延迟,将会在数秒内导致 所有应用 ...

  10. 动态路由协议(RIP)

    虽然静态路由在某些时刻很有用,但是必须手工配置每条路由条目,对于大中型的网络或拓补经常发生变化的清空,配置和维护静态路由的工作量就变得非常繁重,而且不小心还容易出错,因此就需要一种不需要手工配置的路由 ...