上节编写的程序,仍然带着”黑屏“,而我们常用的软件是没有的,怎么把”黑屏“去掉呢?
其实,上节编写的程序是DOS程序和Windows程序的混合体,”黑屏“是典型的DOS程序,对话框是典型的Windows程序。
DOS程序以 main() 为入口函数,Windows程序以 WinMain() 为入口函数,动态链接库(DLL)以 DllMain() 为入口函数(请查看 动态链接库DLL教程 ),不同的入口函数决定了不同类型的程序。
WinMain() 函数的原型为:
先不要急于理解这些参数的含义,我先给大家写一个简单的不带”黑屏“的Windows程序:
编译并运行,会弹出一个不带“黑屏”的对话框,如下所示:
大家可以亲自运行一下,会有真实的体验。
原来没有main()函数,没有 #include <stdio.h> 的C语言程序也是可以运行的^_^
在C程序中,其入口函数都是main(),但在Windows程序中,这个入口函数由WinMain()来代替。该函数是在winbase.h中声明的,其原型已在上面给出。
可以看出,WinMain() 函数除了形参名、个数与main()函数不同外,类型名也有了新的变化。下面就来分析:
① WinMain函数被声明成为返回一个int值,同时WinMain函数名前还有WINAPI标识符的修饰。WINAPI是一种“调用约定”宏,它在windef.h中有如下定义:
#define WINAPI _ _stdcall
所谓“调用约定”,就是指程序生成机器码后,函数调用的多个参数是按怎样的次 序来传递,同时函数调用结束后堆栈由谁来恢复,以及编译器对函数名的修饰约定等的 协议。
函数调用约定“协议”有许多,其中由WINAPI宏指定的_ _stdcall是一个常见的协议,内容包括:参数从右向左压入堆栈;函数自身修改堆栈;机器码中的函数名前面自动加下划线,而函数后面接@符号和参数的字节数。
特别地,Visual C++的MFC方式却采用了_ _cdecl调用约定:参数从右向左压入堆栈;传递参数的内存栈由调用者来维护(正因为如此可实现变参函数);机器码中的函数名只在前面自动加下划线。
② WinMain函数的第一个和第二个参数都是HINSTANCE(实例句柄)类型。HINSTANCE中,H表示Handle,是“句柄”的意思。在Windows编程中,句柄是一个应用程序用来识别某些资源、状态、模块等的数字。由于句柄唯一标识着对应的资源、状态、模块等,因而使用句柄就是使(调)用相应的资源、状态、模块。
当应用程序运行多次时,每一次都是应用程序的“实例”。由于同一个应用程序的所有实例都共享着应用程序的资源,因而程序通过检查hPrevInstance参数就可确定自身的其他实例是否正在运行。
③ WinMain函数的第三个参数lpCmdLine用来指定程序的命令行,其参数类型为LPSTR。但在HelloMsg.c中,却将其改为PSTR。这两种数据类型都是合法的,也都是指向字符串的指针类型。其中的STR是“STRING,字符串”的含义,是指以\0结尾的字符串,LP前缀表示“长指针”,在Win32中它与“P”前缀表示的“指针”含义相同。
其实,上节编写的程序是DOS程序和Windows程序的混合体,”黑屏“是典型的DOS程序,对话框是典型的Windows程序。
DOS程序以 main() 为入口函数,Windows程序以 WinMain() 为入口函数,动态链接库(DLL)以 DllMain() 为入口函数(请查看 动态链接库DLL教程 ),不同的入口函数决定了不同类型的程序。
WinMain() 函数的原型为:
- int WINAPI WinMain(
- HINSTANCE hInstance, // 当前窗口句柄
- HINSTANCE hPrevInstance, // 前一个窗口句柄,Win32下为NULL(Win16留下的废物,目前已弃用)
- LPSTR lpCmdLine, // 命令行参数
- int nCmdShow // 窗口显示方式
- );
- #include <windows.h>
- int WINAPI WinMain(
- HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow
- ){
- int nSelect = MessageBox(NULL, "确认要删除吗?删除后不可恢复!", "警告", MB_OKCANCEL | MB_ICONEXCLAMATION);
- if(nSelect == IDOK){
- MessageBox(NULL, "您已成功删除", "提示", MB_OK | MB_ICONINFORMATION);
- }else{
- MessageBox(NULL, "已取消删除操作", "提示", MB_OK | MB_ICONINFORMATION);
- }
- return 0;
- }
大家可以亲自运行一下,会有真实的体验。
原来没有main()函数,没有 #include <stdio.h> 的C语言程序也是可以运行的^_^
在C程序中,其入口函数都是main(),但在Windows程序中,这个入口函数由WinMain()来代替。该函数是在winbase.h中声明的,其原型已在上面给出。
可以看出,WinMain() 函数除了形参名、个数与main()函数不同外,类型名也有了新的变化。下面就来分析:
① WinMain函数被声明成为返回一个int值,同时WinMain函数名前还有WINAPI标识符的修饰。WINAPI是一种“调用约定”宏,它在windef.h中有如下定义:
#define WINAPI _ _stdcall
所谓“调用约定”,就是指程序生成机器码后,函数调用的多个参数是按怎样的次 序来传递,同时函数调用结束后堆栈由谁来恢复,以及编译器对函数名的修饰约定等的 协议。
函数调用约定“协议”有许多,其中由WINAPI宏指定的_ _stdcall是一个常见的协议,内容包括:参数从右向左压入堆栈;函数自身修改堆栈;机器码中的函数名前面自动加下划线,而函数后面接@符号和参数的字节数。
特别地,Visual C++的MFC方式却采用了_ _cdecl调用约定:参数从右向左压入堆栈;传递参数的内存栈由调用者来维护(正因为如此可实现变参函数);机器码中的函数名只在前面自动加下划线。
② WinMain函数的第一个和第二个参数都是HINSTANCE(实例句柄)类型。HINSTANCE中,H表示Handle,是“句柄”的意思。在Windows编程中,句柄是一个应用程序用来识别某些资源、状态、模块等的数字。由于句柄唯一标识着对应的资源、状态、模块等,因而使用句柄就是使(调)用相应的资源、状态、模块。
当应用程序运行多次时,每一次都是应用程序的“实例”。由于同一个应用程序的所有实例都共享着应用程序的资源,因而程序通过检查hPrevInstance参数就可确定自身的其他实例是否正在运行。
③ WinMain函数的第三个参数lpCmdLine用来指定程序的命令行,其参数类型为LPSTR。但在HelloMsg.c中,却将其改为PSTR。这两种数据类型都是合法的,也都是指向字符串的指针类型。其中的STR是“STRING,字符串”的含义,是指以\0结尾的字符串,LP前缀表示“长指针”,在Win32中它与“P”前缀表示的“指针”含义相同。
④ WinMain函数的第四个参数nShowCmd用来指定程序最初显示的方式,它可以是正常、最大化或最小化来显示程序窗口。
http://c.biancheng.net/cpp/windows/