本文已参与「新人创作礼」活动,一起开启掘金创作之路。
@TOC
前言
windows核心编程
一、错误处理
strerror(errno)
string.h 解析全局errno变量的含义 转成字符串
_set_errno(0)
string.h 字面意思 设置全局错误码
GetLastError
windows.h GetLastError() 获取错误码
FormatMessage()
windows.h 将GetLastError获得的错误码转化为字符串信息
从系统中获取错误码
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, 0, NULL, str, 200, NULL);
从模块中获取错误码
HMOUDLE hMoudle = LoadLibrary(L"user32.dll");
FormatMessage(
FORMAT_MESSAGE_FROM_MODULE | FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER,
hModule, 0, NULL, str, 200, NULL);
// FORMAT_MESSAGE_ALLOCATE_BUFFER 自动分配内存
LocalLock/LocalFree
锁定本地内存与销毁内存,一般用于函数自动分配的内存。
二、Windows函数常见返回值的意义
VOID:这个函数不可能失败! BOOL:FALSE失败;TRUE成功。 HANDLE:失败返回NULL,否则返回非零句柄。如果有特殊说明,则可能为特殊值例如:INVALID_HANDLE_VALUE。 PVOID:返回一个内存地址,失败为NULL LONG/DWORD:应该根据SDK说明来确定函数状况。
三、字符和字符串处理
3.1字符编码
3.1.1 ASCII字符集(多字节字符集)
ASCII 字符集在 0x00 - 0x7F 范围内定义字符。 还有许多其他字符集(主要是欧洲字符集),它们在 0x00 - 0x7F 范围内定义与 ASCII 字符集相同的字符,还在 0x80 - 0xFF. 范围内定义扩展字符集。 (SBCS) 的8位单字节字符集足以表示 ASCII 字符集以及许多欧洲语言的字符集,这一点非常好。 但是,一些非欧洲字符集(如日本汉字)包含的字符数多于单字节编码方案可表示的字符数,因此需要多字节字符集 (MBCS) 编码。 多字节字符集可以包含单字节和双字节字符。 多字节字符字符串可以包含单字节字符和双字节字符的组合。 两字节多字节字符具有一个前导字节和一个尾字节。 在特定的多字节字符集中,前导字节位于某个范围内,尾字节也是如此。 当这些范围重叠时,可能需要计算上下文,以确定给定的字节是用作前导字节还是尾字节。
3.1.2 UNICODE字符集
有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字表示的,这是一种所有符号的编码。
unicode是抽象合集,它的具体实现却有很多种,UTF-8、UTF-16、UTF-32等
字符编码
UTF-8: 一个字节一个字符,有些字符是2个字节,有的字符是3个字节,还有的字符是4个字节。
UTF-16 大部分字符都是2个字节,一般UNICODE就是指utf-16, Windows的Unicode编码一般指utf-16,然后Java的String一般也是Utf-16编码。
UTF-32 所有字符都是4个字节。一般非Windows平台。
常见关于字符编码的宏
TEXT() _T() TCHAR 字符类型 UNICODE 判断是否UNICODE编码的宏
WIN32 表示32位WindowsOs _WIN64 表示64WindowsOs _WIN32 表示32/64 WindowsOs
字符串处理
字符串函数
1.<tchar.h> 包含宽字符和窄字符处理 例如_tcslen(), 定义多字节宏 _MBCS 则使用strlen() 定义Unicode宏_UNICODE 则使用wcslen()
2.StringSafe.h包含安全字符串处理 我们编程的时候,尽量使用安全字符串, strcpy(dst,src)->strcpy_s(dst,srcLen,src)
而StringSafe.h中包含不少可以安全处理字符串的函数
HRESULT StringCchCat(
__inout LPTSTR pszDest,
__in size_t cchDest,
__in LPCTSTR pszSrc
);
pszDest:目标字符串;
cchDest:目标字符串内存大小;
pszSrc: 源字符串。
这是一个字符串拷贝函数,在strsafe.h中。
HRESULT StringCchPrintf(
__out LPTSTR pszDest,
__in size_t cchDest,//目标内存大小
__in LPCTSTR pszFormat,
__in ...
);
这个函数和printf函数用法类似,只是将字符写入了pszDest内存块中,而不是屏幕上!
Windows.h中 字符串比较函数
int CompareString(
__in LCID Locale,
__in DWORD dwCmpFlags,
__in LPCTSTR lpString1,
__in int cchCount1,
__in LPCTSTR lpString2,
__in int cchCount2
);
int CompareStringOrdinal(
__in LPCWSTR lpString1,
__in int cchCount1,
__in LPCWSTR lpString2,
__in int cchCount2,
__in BOOL bIgnoreCase
);
第二个和语言无关,速度更快!!!建议使用!!!
3.ASCII 和 UNICODE 之间的字符转换
int MultiByteToWideChar(
__in UINT CodePage,
__in DWORD dwFlags,
__in LPCSTR lpMultiByteStr,
__in int cbMultiByte,
__out LPWSTR lpWideCharStr,
__in int cchWideChar
);
int WideCharToMultiByte(
__in UINT CodePage,
__in DWORD dwFlags,
__in LPCWSTR lpWideCharStr,
__in int cchWideChar,
__out LPSTR lpMultiByteStr,
__in int cbMultiByte,
__in LPCSTR lpDefaultChar,
__out LPBOOL lpUsedDefaultChar
);
BOOL IsTextUnicode(
__in const VOID *lpv,
__in int iSize,
__inout LPINT lpiResult
);
代码实战
1.vs下使用printf/wsprintf 打印中文的宽字符%S和窄字符%s
#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
void main() {
setlocale(LC_ALL, "");
wchar_t wszName[] = L"WCHAR中文TEST";
char szName[] = "CHAR汉语测试TEST";
printf("szWchar = %S, length = %d\n", wszName, wcslen(wszName));
printf("szChar = %s, length = %d\n", szName, strlen(szName));
wprintf(L"wprintf szWchar = %s\n", wszName);
wprintf(L"wprintf szChar = %S\n", szName);
}
2.使用StringCchPrintf/StringCchCat/StringCchCopy
char mem[1000] = {0};
StringCchPrintf(mem, 1000, "%d,%s", 10, "helloworld");
StringCchCat(mem, 1000, "你好");//追加
StringCchCopy(mem, 1000, "您好");//拷贝
3.使用CompareString/CompareStringOriginal
TCHAR szBuffer[10] = {
TEXT('A'),TEXT('A'),TEXT('A'),TEXT('A'),TEXT('A'),
TEXT('A'),TEXT('A'),TEXT('A'),TEXT('B'),'\0'
};
LCID local = GetThreadLocale();
//int result = CompareString(local/*LOCALE_SYSTEM_DEFAULT*/, NORM_IGNORECASE, szBuffer, _countof(szBuffer), TEXT("AAAAAAAAA"), 10);
int result = CompareStringOrdinal(L"AAAAAAAAB", 10, L"AAAAAAAAA", 10, TRUE);
switch (result)
{
case 0:
cout << "Error" << endl;
break;
case CSTR_LESS_THAN:
cout << "Str1 《 Str2" << endl;
break;
case CSTR_GREATER_THAN:
cout << "Str1 》 Str2" << endl;
break;
case CSTR_EQUAL:
cout << "Str1 = Str2" << endl;
break;
default:
cout << "Don't goto there" << endl;
break;
}
4.使用IsTextUnicode判断
if (IsTextUnicode(L"abc", 4, NULL)) {
printf("is unicode");
}
else {
printf("is ascii code");
}
5.多字节和UNICODE转换
void main2() {
char sBuf[25] = { 0 };
strcpy_s(sBuf,25, "我最棒");
//获取输入缓存大小
int sBufSize = strlen(sBuf);
//获取输出缓存大小
//VC++ 默认使用ANSI,故取第一个参数为CP_ACP
DWORD dBufSize = MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, NULL, 0);
printf("需要wchar_t%u个\n", dBufSize);
wchar_t* dBuf = new wchar_t[dBufSize];
wmemset(dBuf, 0, dBufSize);
//进行转换
int nRet = MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, dBuf, dBufSize);
if (nRet <= 0)
{
cout << "转换失败" << endl;
DWORD dwErr = GetLastError();
switch (dwErr)
{
case ERROR_INSUFFICIENT_BUFFER:
printf("ERROR_INSUFFICIENT_BUFFER\n");
break;
case ERROR_INVALID_FLAGS:
printf("ERROR_INVALID_FLAGS\n");
break;
case ERROR_INVALID_PARAMETER:
printf("ERROR_INVALID_PARAMETER\n");
break;
case ERROR_NO_UNICODE_TRANSLATION:
printf("ERROR_NO_UNICODE_TRANSLATION\n");
break;
}
}
else
{
cout << "转换成功" << endl;
cout << dBuf;
}
delete(dBuf);
}
void main(){
//从宽字符串转换窄字符串
wchar_t sBuf[25] = { 0 };
wcscpy_s(sBuf,100, L"我最棒");
//获取转换所需的目标缓存大小
DWORD dBufSize = WideCharToMultiByte(CP_OEMCP, 0, sBuf, -1, NULL, 0, NULL, FALSE);
//分配目标缓存
char* dBuf = new char[dBufSize];
memset(dBuf, 0, dBufSize);
//转换
int nRet = WideCharToMultiByte(CP_OEMCP, 0, sBuf, -1, dBuf, dBufSize, NULL, FALSE);
if (nRet <= 0)
{
printf("转换失败\n");
}
else
{
printf("转换成功\nAfter Convert: %s\n", dBuf);
}
delete[]dBuf;
}
四、代码页
代码页通常和软件本地化 多语言支持有关。
总结
小技巧
1.vs 选中函数 按下f1 可进入msdn网页 函数具体详情 2.vs F5运行,Cirl+F5 无调试运行,F7编译, 3.工具栏-》错误查找 工具可以查找错误码对应的错误含义