Windows编程之从控制台到SDK窗口

1.典型C/C++程序

2.Windows 编程的第一种方式是传统的SDK方式,Windows操作系统是由C语言编写的,故可采用C语言直接调用windowsAPI函数进行编程。

以下为Win SDK应用程序窗口程序框架示例及框架解析。

(1)建立Win32应用程序项目Win32SDK

Visual Studio 2005à文件à新建à项目àVisual C++àwin32àwin32项目àwin32应用程序à空项目(默认使用Unicode字符集)。如果运行时提示找不到mfc80d.dllmsvcr80d.dll文件,在“项目属性à配置属性à清单工具à常规”中的“使用FAT32解决办法”处选择“是”,再重新生成解决方案。

(2)添加源文件Win32SDK.cpp

 

 

3.Windows下的C/C++应用程序运行机制

1subsystem选项

VC6

Project SettingsàC/C++àPreprocessoràPreprocessor Definitions_CONSOLE_WINDOWS

Project SettingsàC/C++àProject Options/D "_CONSOLE"/D "_WINDOWS "

Project SettingsàLinkà Project Options/subsystem:console/subsystem:windows

VC2005

项目属性àC/C++à预处理器à预处理器定义:_CONSOLE_WINDOWS

项目属性àC/C++à命令行:/D "_CONSOLE"/D "_WINDOWS "

项目属性à链接器à命令行:/SUBSYSTEM:CONSOLE/SUBSYSTEM:WINDOWS

项目属性à链接器à 系统à 子系统:控制台(/SUBSYSTEM:CONSOLE)Windows (/SUBSYSTEM:WINDOWS)

2)可执行文件的Entry Point

可执行文件都有一个Entry Point(起始地址),LINK时可以用/entry指定。

缺省情况下,如果subsystem“console”Entry Point mainCRTStartup(ANSI)wmainCRTStartuup(UNICODE),即:

/subsystem:"console" /entry:"mainCRTStartup" (ANSI)

/subsystem:"console" /entry:"wmainCRTStartuup" (UNICODE)

mainCRTStartup wmainCRTStartuup 会调用用户编写的mainwmain在进入可执行文件的代码前,系统将会创建一个控制台窗口。

值得一提的是,在进入应用程序的Entry Point前,Windows的装载器已经做过C变量的初始化,有初值的全局变量拥有了它们的初值,没有初值的变量被设为0

如果subsystem“windows”Entry PointWinMain(ANSI)wWinMain(UINCODE),即:

/subsystem:"windows" /entry:"WinMainCRTStartup" (ANSI)

/sbusystem:"windows" /entry:"wWinMainCRTStartup" (UINCODE)

WinMainCRTStartup wWinMainCRTStartup 会调用 用户编写的WinMain wWinMain窗口由用户调用CreateWindow(Ex)创建

VC2005中,项目属性à链接器à高级处有入口点选项,在编写Windows Mobile ANSI控制台程序时需指定入口点为mainWCRTStartupWindowsCE (/SUBSYSTEM:WINDOWSCE))。

VC2005中,建一个简单的Console程序(main为入口函数),编译后F10将进入crtexe.c,查看调用堆栈如下:

àint main(int argc, char* argv[])

àint __tmainCRTStartup(void)

àint mainCRTStartup(void)

    <1>mainCRTStartup函数只是简单的调用__tmainCRTStartup函数,其代码如下:

#ifdef _WINMAIN_

int WinMainCRTStartup(void) // UNICODE版本:int wWinMainCRTStartup(void)

#else

int mainCRTStartup(void) // UNICODE版本:int wmainCRTStartup(void)

{

        __security_init_cookie();

 

        return __tmainCRTStartup();

}

    <2>__tmainCRTStartup函数调用main/WinMain函数,其代码如下:

int __tmainCRTStartup(void)

{

//……

#ifdef _WINMAIN_

GetStartupInfo( &StartupInfo );

……

mainret = WinMain(…) // UNICODE版本:int wWinMain(…)

#else  /* _WINMAIN_ */

mainret = main(); // UNICODE版本:int wmain(…)

    //……

    /*

    * do C++ constructors (initializers) specific to this EXE

*/

if (__native_startup_state == __initializing)

    {

          _initterm( __xc_a, __xc_z );

          __native_startup_state = __initialized;

}

    //……

 

    if ( !managedapp )

exit(mainret);

    //……

return mainret;

}

    可以推测上述_WINMAIN_宏是与subsystem相关的一个VC编译器内部宏。

(3)应用程序的启动

    程序是一连串静态的指令,而进程是一个容器,它包含了一系列运行在这个程序实例上下文中的线程使用的资源。

当我们用鼠标点击磁盘上的可执行文件App.exe后,App.exe被装载至内存后就形成了进程,因此进程是一个正在运行的程序的实例。一般我们可以同时启动多个App.exe的实例,即创建同名的多个不同ID的进程。

进程内核对象不是进程本身,仅仅是一个系统用来管理这个进程的一个小的数据结构(PCBProcess Control Block)。进程是不活泼的,程序代码的执行是线程的工作,线程是进程内执行代码的独立实体。一个进程要完成任何的事情,它必须有一个运行在其地址空间的线程。Windows操作系统调用CreateProcess函数创建一个新的进程和该进程的主线程,返回 LPPROCESS_INFORMATION信息。主线程通过执行C/C++运行期启动代码初始化C/C++运行期库,C/C++运行期启动代码又会调用main函数。主线程在运行期间,可以调用CreateThread创建辅助线程,即所谓的多线程。

App.exe进程的主线程入口函数main/WinMain返回后,启动函数mainCRTStartup__tmainCRTStartup)调用C/C++运行期退出函数exit(参数为main/WinMain返回值)

全局变量(包括内置类型和类类型)存储在全局区。exit函数会销毁所有全局的或静态的C++对象,全局C++对象的构造函数在进入应用程序的Entry Point之后,调用用户编写的main/WinMain之前调用。编译器调用atexit记录全局对象的析构函数(dynamic atexit destructor for 'x'多个函数形成多播链),在exit退出时(main/WinMain返回之后)调用。

exitF11进入crt0dat.c中的doexit,其中析构函数的调用代码片段如下:

/*

* do _onexit/atexit() terminators(if there are any)

* These terminators MUST be executed in reverse order (LIFO)!

*/

_PVFV * onexitbegin = (_PVFV *)_decode_pointer(__onexitbegin);

_PVFV * onexitend   = (_PVFV *)_decode_pointer(__onexitend);

// 依次调用atexit注册的函数(oneixtbeginàonexitend

HelloCPP2.cpp程序在VC6中,没输出"X deconstructor",在VC2005中输出"X deconstructor"

最后(/* return to OS or to caller */)调用ExitProcessdoexità__crtExitProcess)促使操作系统终止应用程序。

 

参考:

在VC中编译、运行程序的小知识点

如何屏蔽控制台应用程序的窗口?

《深入浅出MFC》第一章àWin32程序基本概念à进程与线程à一个进程的诞生与死亡

Windows核心编程 第五版》4.1编写第一个Windows应用程序。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值