windows游戏编程 (一) 了解WinMain函数,创建一个信息框

参考《Windows游戏编程大师技巧》 2.5节

1.创建工程2

对于Vs2019, VS2017

1)桌面向导

2)选择桌面应用程序,空项目

 

2.代码如下:

 

#define WIN32_LEAN_AND_MEAN //预编译指令 指示编译器不要包含MFC的内容

#include <Windows.h>
#include <windowsx.h>
/*
#define WINAPI __stdcall
#define CALLBACK __stdcall
__stdcall: 函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。
__cdecl: C/C++和MFC程序默认使用的调用约定,也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。
WINAPI声明符: 一般用于修饰动态链接库中导出函数 3. CALLBACK仅用于修饰回调函数
*/
int WINAPI WinMain(HINSTANCE hinstance, /*windows为应用程序生成的实例句柄。实例是一个指针或一个数。 本例中hinstance用来跟踪应用程序*/
	HINSTANCE hprevinstance,/*用来跟踪应用程序以前的实例,目前不再使用,微软要去除它*/
	LPSTR lpcmdline,//空值终止字符串
	int ncmdshow) {//启动过程中被传递给应用程序,带有如何打开主应用程序窗口的信息。这样用户可以有些控制程序如何启动的能力,可以在函数ShowWindow()中使用
	MessageBox(NULL, "Hello",
		"My First Windows Program", MB_OK | MB_ICONEXCLAMATION);
	MessageBeep(MB_OK);//点击按钮后有声音
	/*
	函数返回一个值通知我们发生了什么事,比如IDABORT, IDCANCEL
	int MessageBox(
    _In_opt_ HWND hWnd, 窗口句柄,设置为null,Windows桌面被用作父窗口
    _In_opt_ LPCSTR lpText, 包含显示文本的空值终止字符串
    _In_opt_ LPCSTR lpCaption, 包含显示文本框标题的空值终止字符串
    _In_ UINT uType); 决定显示的是哪种信息框
	*/
	return 0;
}

 

 

 

 

WINAPI与CALLBACK:

本质上是

#define WINAPI __stdcall

#define CALLBACK __stdcall

 

与书上写的WINAPI等同于PASCAL不同,这里是

具体见:

http://www.cppblog.com/winmain/archive/2010/03/07/109128.html 

__cdecl

 

 

__stdcall

 

C 和 C++ 程序的缺省调用规范

 

为了使用这种调用规范,需要你明确的加上 __stdcall(或 WINAPI )文字。即 return-type __stdcallfunction-name[(argument-list)]

 

 

调用函数 (Callee) 返回,由调用方 (Caller) 调整堆栈。

 

1. 调用方的函数调用

                                         

2. 被调用函数的执行

 

3. 被调用函数的结果返回

 

4. 调用方清除调整堆栈

                                                                

 

调用函数 (Callee) 返回,由调用函数 (Callee)调整堆栈。图示:

 

1. 调用方的函数调用

 

2. 被调用函数的执行

 

3. 被调用函数清除调整堆栈

 

4. 被调用函数的结果返回                                                           

 

因为每个调用的地方都需要生成一段调整堆栈的代码,所以最后生成的文件较大。

 

 

因为调整堆栈的代码只存在在一个地方(被调用函数的代码内),所以最后生成的文件较小。

 

函数的参数个数可变(就像 printf 函数一样),因为只有调用者才知道它传给被调用函数几个参数,才能在调用结束时适当地调整堆栈。

 

 

函数的参数个数不能是可变的。

 

对于定义在 C 程序文件中的输出函数,函数名会保持原样,不会被修饰。

对于定义在 C++ 程序文件中的输出函数,函数名会被修饰, MSDN 说 Underscore character (_) is prefixed to names . 我实际测试( VC4 和 VC6 )下来发现好像不是那么简单。

可通过在前面加上 extern “C” 以去除函数名修饰。也可通过 .def 文件去除函数名修饰。

 

不论是 C 程序文件中的输出函数还是 C++ 程序文件中的输出函数,函数名都会被修饰。

对于定义在 C 程序文件中的输出函数, An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list.

对于定义在 C++ 程序文件中的输出函数,好像更复杂,和 __cdecl 的情况类似。

好像只能通过 .def 文件去除函数名修饰。

 

 

_beginthread 需要 __cdecl 的线程函数地址

 

 

_beginthreadex 和 CreateThread 需要 __stdcall 的线程函数地址

 

 

两者的参数传递顺序都是从右向左。

为了让 VB 可以调用,需要用 __stdcall 调用规范来定义 C/C++ 函数。请参看Microsoft KB153586 文章:How To Call C Functions That Use the _cdecl Calling Convention

当你 LoadLibrary 一个 DLL 文件后, 把 GetProcAddress 取得的函数地址传给上面三个线程生成函数时,请务必确认实际定义在 DLL 文件的输出函数符合调用规范要求。否则,编译成 Release 版后运行,可能会破坏堆栈,程序行为不可预测。

VC 中的相关编译开关:/Gd /Gr /Gz。另外,VC6中新增加的 /GZ 编译开关可以帮你检查堆栈问题。

我也是初学者,若有不对的地方、可以补充的地方,请指教。谢谢。

注意上面代码MessageBox(),如果选用的Uniocde编码,

 

MessageBox(NULL, L"Hello",
		L"My First Windows Program", MB_OK | MB_ICONEXCLAMATION);

这里使用的是宽字符集:

相互转换方法:
LPWSTR->LPTSTR: W2T();
LPTSTR->LPWSTR: T2W();
LPCWSTR->LPCSTR: W2CT();
LPCSTR->LPCWSTR: T2CW();

ANSI->UNICODE: A2W();
UNICODE->ANSI: W2A();
————————————————

参考:

https://blog.csdn.net/luoweifu/article/details/49382969

http://www.cppblog.com/winmain/archive/2010/03/07/109128.html 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值