本帖最后由 天上飞来一只 于 2020-10-22 15:36 编辑
前言:在windows应用程序下,不包含windows.h和window.h内的任何头文件,弹框 “Hello, world!”,本文主要基于 vs2015 生成的windows应用程序的空工程进行研究,以提高对基础知识的理解。
一、VS基础配置1.打开VS2015,新建项目----win32控制台应用程序----windows应用程序,附加选项,空项目
二、windows应用程序的主入口函数wWinMain写任何一个函数应该有一个该函数的入口了。我们知道控制台的入口函数是main()函数,那么在写Windows应用程序也是main()吗?
回答当然不是了。我们用的是SDK中的WinMain()函数参考MSDN的说明
[C] 纯文本查看 复制代码 int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
);
Requirements
Windows NT/2000/XP: Included in Windows NT 3.1 and later.
Windows 95/98/Me: Included in Windows 95 and later.
Header: Declared in Winbase.h; include Windows.h.
MSDN上已经说明需要包含 Winbase.h或者Windows.h. 那我们需要的挑战就是不使用任何头文件,也能正常弹出提示框MessageBox
三、具体流程1、先写主函数内的内容int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow){ //MessageBox(NULL, TEXT("hello world"), TEXT("标题"), MB_OK); return 0;}2、如果直接选择编译以上问题,相信大家看VS提示输出窗口是一大堆,莫名其妙的错误提示
这么多语法错误、未声明的标识符 为啥???现在我会一点一点的挽回那失去的耐心!优先解决掉未声明的标识符
3、解决提示“_In_”: 未声明的标识符的问题
_in 输入参数 _out 输出参数
_opt 参数是可选的,就是可以为NULL
_ecount 所指向的缓存的元素个素 也就是括号里的数字
这些宏都被定义为空,只是让程序更容易理解!
解放方法:
宏定义
#define _In_
#define _In_opt_
4、C语言语法基础知识:在使用函数之前应该先声明,那么WinMain函数,同样也需要声明,OK,加上
[Asm] 纯文本查看 复制代码 //宏定义
#define _In_
#define _In_opt_
//函数声明
int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine, _In_ int nShowCmd);
//入口函数
int APIENTRY WinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
//MessageBox(NULL, TEXT("hello world"), TEXT("标题"), MB_OK);
return 0;
}
5、继续F7编译,还是提示很多报错,不要放弃,继续解决错误
大家可以新的提示“HINSTANCE”: 未声明的标识符,依次解决掉WinMain函数的所有类型
解决方法:
HINSTANCE是“句柄型”数据类型HWND 是一个基本类型,一般指窗口句柄
LPSTR一种字符串数据类型
LPCSTR一种常量字符串数据类型
LPWSTR是wchar_t字符串数据类型
LPCWSTR 是常量wchar_t字符串数据类型
UINT是无符号整型数据类型
依次自定义类型
[C] 纯文本查看 复制代码 typedef void *HINSTANCE;
typedef void *HWND;
typedef char *LPSTR;
typedef const char *LPCSTR;
typedef wchar_t *LPWSTR;
typedef const wchar_t *LPCWSTR;
typedef unsigned int UINT;
6、继续F7编译,提示报错
看到这么多错误,还能坚持下来的同学,是最棒的! 可以看到提示“WinMain”: 必须是“__stdcall”
解决:
__stdcall是函数调用约定的一种,函数调用约定主要约束了两件事:1.参数传递顺序2.调用堆栈由谁(调用函数或被调用函数)清理
那么可以得出APIENTRY就是表示__stdcall,定义#define APIENTRY __stdcall
[C++] 纯文本查看 复制代码 //宏定义
#define _In_
#define _In_opt_
#define APIENTRY __stdcall
//自定义数据类型
typedef void *HINSTANCE;
typedef void *HWND;
typedef char *LPSTR;
typedef const char *LPCSTR;
typedef wchar_t *LPWSTR;
typedef const wchar_t *LPCWSTR;
typedef unsigned int UINT;
//函数声明
int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine, _In_ int nShowCmd);
//函数入口
int APIENTRY WinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
//MessageBox(NULL, TEXT("hello world"), TEXT("标题"), MB_OK);
return 0;
}
7、添加代码继续编译F7,无错误
8、终于到了MessageBox阶段,取消注释,编译F7等待报错。
MessageBox找不到标识符,MessageBox是函数,同样也需要声明,这里需要注意MessageBox实际分为2个版本:
[Asm] 纯文本查看 复制代码 int WINAPI MessageBoxA(_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType);
int WINAPI MessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType);
需要进行宏定义
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif
[Asm] 纯文本查看 复制代码 解决:NULL TEXT,MB_OK未知标识符,宏定义走起
#define __TEXT(quote) L##quote
#define TEXT(quote) __TEXT(quote)
#define MB_OK 0x00000000L
#define NULL 0
[/size][/font]
[font=宋体][size=12.0000pt]#define WINAPI __stdcall
9、编译,报错
解决:
小知识点,MessageBoxA很古老,为了能够正确实现C++代码调用其他C语言代码,在MessageBoxA和MessageBoxW上必须声明C,即extern "C"
10、完整代码,求爱心!
WindowsMain.rar
(622 Bytes, 下载次数: 14)
|