文章

滴水-day38-WIN32-宽字符

宽字符

在编程中通常会遇到多语言的问题,也就是每个国家都有不同的语言,如果没有一个统一的表就无法直接表示各个国家的语言。

在WIN32中有两个码表,分别是ASCII和UNICODE。

ASCII码表通常是只表示一个字符或者一个字节,这个在使用英文语言下是使用最多的一个码表,还有一个是UNICODE码表,这个码表很大,几乎包括了这个世界上各个国家常用的文字。

例如中文:

在WIN32中,一个中文无法使用ASCII码表进行表示,所以中国大佬就创建了一个规则,一个中文字符使用两个字节进行表示,再查表组合成一个中文。

在不同的码表中所表示的字节也不不一样的。

在ASCII中:

中国表示为:

//d6 d0 b9 fa 00

在UNICODE中:

//2d 4e fd 56 00 00

可以发现UNICODE中是以两个00为结束标志的。

也就是说不管是任何字符,只要使用了UNICODE都是以两个字节进行表示。

Unicode中的每个字符都是16位宽而不是8位宽

在C语言中使用wchar_t表示宽字符,但是无法直接给这个宽字符进行赋值,因为编译器默认使用了ASCII码表,我们需要手动告述编译器使他使用UNICODE码表。在字符串前加一个L

wchar_t temp[] = L"中国";

这样就不会报错了。

  wchar_t temp[] = L"中国";
	wchar_t data[30];
	wprintf(L"%s\\n", temp);

	cout << wcslen(temp) << endl; // 2;
	wcscpy_s(data, temp);
	wprintf(L"%s", data);

	wchar_t aa[] = L"AAAA";
	wcscat_s(data, aa);
	wprintf(L"%s\\n", data);
	
	cout << wcscmp(temp, data) << endl;

	WCHAR *sss = wcsstr(temp, data);

	wprintf(L"%s\\n", sss);

在以上使用中,不知道什么时候使用ASCII和UNICODE码表,这个时候我们可是使用TEXT来指定字符串的格式,当当前项目使用ASII的时候,就相当于“AAA”,当项目使用了UNICODE的时候就相当于使用了L”AAA”

WIN32入口程序

在WIN32中,有很多的宏,这些宏无非就是给C语言中的一些关键字什么的起了一个新的名字。

在win32中多字节与宽字符的区别

MessageBoxA(0,"内容多字节","标题",MB_OK);

MessageBoxW(0,L"内容宽字节",L"标题",MB_OK);

MessageBox(0,TEXT("根据项目字符集决定"),TEXT("标题"),MB_OK);

Windows提供的API 凡是需要传递字符串参数的函数,都会提供两个版本和一个宏.

这就是是为什么有的API会有A版和W版。其实就是ASCII和UNICODE的区别。

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)

这是一个WIN32应用程序的入口点也就是main函数,他与控制台程序的main函数不同,首先是参数的个数不一样。

APIENTRY:__stdcall

这个宏就是调用约定中的_stdcall,与控制台函数一样。

wWinMain参数解释

hInstance:应用程序的当前实例的句柄,也是当前程序的ImageBase hPrevInstance:此参数始终 NULL lpCmdLine:应用程序的命令行,不包括程序名称 nShowCmd:控制窗口的显示方式,参考 ShowWindow 函数

返回值:

如果函数成功,在收到 WM_QUIT 消息时终止,它应返回该消息 wParam 参数中包含的退出值。 如果函数在输入消息循环之前终止,则应返回零。

格式化输出

因为原有的OutputDebugString并不支持%d%s什么的,所以需要重写一个函数用来支持这样的功能

void __cdecl OutputDebugStringF(const char* format, ...)
{
	char strBuffer[4096];  // 使用栈上缓冲区
	va_list vlArgs;

	va_start(vlArgs, format);
	vsnprintf(strBuffer, sizeof(strBuffer), format, vlArgs);  // 更安全的格式化函数
	va_end(vlArgs);

	// 添加换行符
	strcat_s(strBuffer, sizeof(strBuffer), "\\n");

	// 输出到调试窗口
	OutputDebugStringA(strBuffer);
}

在WIN32中,如果有一些运行中的错误,他是不会报出来的,需要我们手动获取到错误去查错误表

使用**GetLastError函数,**该函数返回一个DWORD的值,根据这个值去微软提供的错误表查找相应的错误。

WNDCLASSEXW类参数

cbSize:此结构的大小(以字节为单位)。 将此成员设置为 sizeof(WNDCLASSEX) style:类样式 () 。 此成员可以是 类样式的任意组合 lpfnWndProc:此窗口的消息处理函数 cbClsExtra:0 cbWndExtra:0 ****hInstance:实例的句柄,该实例包含类的窗口过程 hIcon:窗口图标 hCursor:窗口光标 hbrBackground:窗口背景色 lpszMenuName:菜单资源名称 lpszClassName:类名 hIconSm:小图标资源

WNDCLASSEXW参数填写完毕后使用RegisterClassExW完成注册。

InitInstance自定义函数,显示窗口

CreateWindowW函数创建窗口

ShowWindow函数显示窗口

License:  CC BY 4.0