intmain(intargc,char*argv[]){std::cout<<"HelloCPP!/n";return0;}//HelloCPP2.cpp#includeusi" />

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

系统 1766 0

1 .典型 C/C++ 程序

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

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

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

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

(2) 添加源文件 Win32SDK.cpp

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

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

1 subsystem 选项

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 会调用用户编写的 main wmain 在进入可执行文件的代码前,系统将会创建一个控制台窗口。

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

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

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

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

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

VC2005 中, 项目属性 à 链接器 à 高级处有入口点选项,在编写 Windows Mobile ANSI 控制台程序时需指定入口点为 mainWCRTStartup WindowsCE (/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 的进程。

进程内核对象不是进程本身,仅仅是一个系统用来管理这个进程的一个小的数据结构( PCB Process 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 返回之后)调用。

exit F11 进入 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 */ )调用 ExitProcess doexit à __crtExitProcess )促使操作系统终止应用程序。

参考:

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

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

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

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

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


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论