Windows API 中的字符串
最后修改于 2023 年 10 月 18 日
在 C 语言中,没有字符串数据类型。程序中的字符串字面量是一个字符数组。每当我们说字符串时,我们指的是一个字符数组。
我们有五组用于处理字符串的函数;分别在 C 运行时库 (CRT) 和 Windows API 中
- ANSI C 标准函数
- 安全增强 CRT 函数
- Windows API 内核和用户函数
- Windows API Shell 轻量级实用程序函数
- Windows API StrSafe 函数
建议优先使用安全增强的标准函数或 Windows API 安全函数。
ANSI C 字符串函数
C 运行时 (CRT) 库函数有一些小的开销,因为它们在底层调用 Windows API 函数。这些函数提供了可移植性,但也有一些限制。如果使用不当,它们可能会导致安全风险。
这些函数在失败时不会返回值错误。
#include <windows.h> #include <wchar.h> #define STR_EQUAL 0 int wmain(void) { wchar_t str1[] = L"There are 15 pines"; wprintf(L"The length of the string is %lld characters\n", wcslen(str1)); wchar_t buf[20]; wcscpy(buf, L"Wuthering"); wcscat(buf, L" heights\n"); wprintf(buf); if (wcscmp(L"rain", L"rainy")== STR_EQUAL) { wprintf(L"rain and rainy are equal strings\n"); } else { wprintf(L"rain and rainy are not equal strings\n"); } return 0; }
在示例中,我们展示了 CRT 库中的一些字符串函数。
wprintf(L"The length of the string is %lld characters\n", wcslen(str1));
wcslen
返回字符串中宽字符的数量。
wcscpy(buf, L"Wuthering");
wcscpy
将字符串复制到字符串缓冲区。
wcscat(buf, L" heights\n");
wcscat
函数将字符串附加到字符串缓冲区。
if (wcscmp(L"rain", L"rainy")== STR_EQUAL) { wprintf(L"rain and rainy are equal strings\n"); } else { wprintf(L"rain and rainy are not equal strings\n"); }
wcscmp
比较两个字符串。
C:\Users\Jano\Documents\WinApi\strings\ANSICFunctions>ANSICFunctions.exe The length of the string is 18 characters Wuthering heights rain and rainy are not equal strings
安全增强 CRT 函数
安全 CRT 函数为 CRT 函数增加了额外的安全性。(它们不是标准函数,而是 MS 扩展。)这些函数验证参数,获取大小缓冲区,检查字符串是否以 NULL 结尾,并提供增强的错误报告。
安全 CRT 函数有一个 _s
后缀。
#include <windows.h> #include <wchar.h> #define BUF_LEN 25 int wmain(void) { wchar_t str1[] = L"There are 15 pines"; const int MAX_CHARS = 50; size_t count = wcsnlen_s(str1, MAX_CHARS); wprintf(L"The length of the string is %ld characters\n", count); wchar_t buf[BUF_LEN] = {0}; int r = wcscpy_s(buf, BUF_LEN, L"Wuthering"); if (r != 0) { wprintf(L"wcscpy_s() failed %ld", r); } r = wcscat_s(buf, BUF_LEN, L" heights\n"); if (r != 0) { wcscat_s(L"wcscat_s() failed %ld", r); } wprintf_s(buf); return 0; }
在示例中,我们展示了四个函数:wcsnlen_s
, wcscpy_s
, wcscat_s
, 和 wprintf_s
。
const int MAX_CHARS = 50; size_t count = wcsnlen_s(str1, MAX_CHARS);
wcsnlen_s
计算宽字符串的长度。该函数仅检查前 MAX_CHARS
个字符。
int r = wcscpy_s(buf, BUF_LEN, L"Wuthering");
使用 wcscpy_s
函数,我们将字符串 L"Wuthering"
复制到缓冲区中。该函数获取缓冲区中字符的最大数量,如果失败,则返回错误代码。该函数在成功时返回 0。
r = wcscat_s(buf, BUF_LEN, L" heights\n");
wcscat_s
是 wcscat
函数的安全扩展。
wprintf_s(buf);
甚至还有一个安全增强的 wprintf
函数;它有一些运行时约束。
C:\Users\Jano\Documents\WinApi\strings\SecurityEnhanced>SecurityEnhanced.exe The length of the string is 18 characters Wuthering heights
Windows API 内核和用户字符串函数
这些函数特定于 Windows 操作系统;它们在 User32.lib
和 Kernel32.lib
中可用。它们比 CRT 对应的函数更轻量级。
内核字符串函数源于 Windows 内核的开发。它们以字母 l
为前缀。
字符串长度
最常见的需求之一是计算字符串的长度。 lstrlen
函数返回指定字符串的字符长度。它不计算终止的空字符。
int WINAPI lstrlenA(LPCSTR lpString); int WINAPI lstrlenW(LPCWSTR lpString);
ANSI 和 UNICODE 函数将字符串作为参数,并返回字符串中的字符数。
#include <windows.h> #include <wchar.h> int wmain(void) { char *name = "Jane"; wchar_t *town = L"Bratislava"; wprintf(L"The length of the name string is %d\n", lstrlenA(name)); wprintf(L"The town string length is %d\n", lstrlenW(town)); return 0; }
我们计算两个字符串的长度。lstrlen
函数实际上是一个宏,可以是 lstrlenA
或 lstrlenW
。第一个用于 ANSI 字符串,第二个用于宽字符串。
wprintf(L"The town string length is %d\n", lstrlenW(town));
我们使用 lstrlenW
函数打印字符串 L"Bratislava"
的长度。
C:\Users\Jano\Documents\WinApi\strings\WinapiStringLength>WinapiStringLength.exe The length of the name string is 4 The town string length is 10
连接字符串
lstrcatW
函数将一个字符串附加到另一个字符串。
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2);
第一个参数是应该包含两个字符串的缓冲区。它必须足够大,以包含它们,包括 NULL
终止字符。返回值是指向缓冲区的指针。
#include <windows.h> #include <wchar.h> int main(void) { wchar_t *s1 = L"ZetCode, "; wchar_t *s2 = L"tutorials "; wchar_t *s3 = L"for "; wchar_t *s4 = L"programmers.\n"; int len = lstrlenW(s1) + lstrlenW(s2) + lstrlenW(s3) + lstrlenW(s4); wchar_t buf[len+1]; lstrcpyW(buf, s1); lstrcatW(buf, s2); lstrcatW(buf, s3); lstrcatW(buf, s4); wprintf(buf); return 0; }
在示例中,我们连接了四个字符串。
wchar_t *s1 = L"ZetCode, "; wchar_t *s2 = L"tutorials "; wchar_t *s3 = L"for "; wchar_t *s4 = L"programmers.\n";
这些是我们即将连接的字符串。
int len = lstrlenW(s1) + lstrlenW(s2) + lstrlenW(s3) + lstrlenW(s4);
我们使用 lstrlenW
函数计算四个字符串的长度。
wchar_t buf[len+1];
我们创建一个缓冲区来保存最终的字符串。请注意,我们加 1 以包含 NULL
字符。
lstrcpyW(buf, s1);
我们使用 lstrcpyW
函数将第一个字符串复制到缓冲区。
lstrcatW(buf, s2); lstrcatW(buf, s3); lstrcatW(buf, s4);
我们使用 lstrcatW
函数附加其余字符串。
C:\Users\Jano\Documents\WinApi\strings\WinapiStringConcat>WinapiStringConcat.exe ZetCode, tutorials for programmers.
转换字符
我们有两种将字符转换为大写或小写的方法。CharLowerW
函数将字符串或单个字符转换为小写。 CharUpperW
函数将字符串或单个字符转换为大写。如果操作数是字符串,则该函数将就地转换字符。换句话说,它们被修改了。
LPWSTR WINAPI CharLowerW(LPWSTR lpsz); LPWSTR WINAPI CharUpperW(LPWSTR lpsz);
这些函数就地修改字符串,并返回指向修改后字符串的指针。
#include <windows.h> #include <wchar.h> #pragma comment(lib, "User32.lib") int wmain(void) { wchar_t str[] = L"Europa"; CharLowerW(str); wprintf(L"%ls\n", str); CharUpperW(str); wprintf(L"%ls\n", str); return 0; }
我们有一个字符串,我们将其转换为小写和大写。
CharLowerW(str); wprintf(L"%ls\n", str);
我们使用 CharLowerW
方法将 str
字符串转换为小写。字符串被就地修改。
C:\winapi\examples2\strings\UpperLower>UpperLower.exe europa EUROPA
比较字符串
lstrcmpW
函数比较两个字符串。如果字符串相等,则返回 0。比较区分大小写。这意味着 "Cup" 和 "cup" 是两个不同的字符串。 lstrcmpiW
产生不区分大小写的字符串比较。对于此函数,"Cup" 和 "cup" 是相等的。
int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2); int WINAPI lstrcmpiW(LPCWSTR lpString1, LPCWSTR lpString2);
这些函数将两个字符串作为参数。返回值表示字符串的相等性。对于相等的字符串,返回值为 0。
#include <windows.h> #include <wchar.h> #define STR_EQUAL 0 int wmain(void) { wchar_t *s1 = L"Strong"; wchar_t *s2 = L"strong"; if (lstrcmpW(s1, s2) == STR_EQUAL) { wprintf(L"%ls and %ls are equal\n", s1, s2); } else { wprintf(L"%ls and %ls are not equal\n", s1, s2); } wprintf(L"When applying case insensitive comparison:\n"); if (lstrcmpiW(s1, s2) == STR_EQUAL) { wprintf(L"%ls and %ls are equal\n", s1, s2); } else { wprintf(L"%ls and %ls are not equal\n", s1, s2); } return 0; }
我们有两个字符串。我们使用区分大小写和不区分大小写的字符串比较来比较它们。
if (lstrcmpW(s1, s2) == STR_EQUAL) { wprintf(L"%ls and %ls are equal\n", s1, s2); } else { wprintf(L"%ls and %ls are not equal\n", s1, s2); }
如果 lstrcmpW
函数返回 STR_EQUAL
,它被定义为 0,然后我们在控制台中打印这两个字符串相等。否则,我们打印它们不相等。
C:\Users\Jano\Documents\WinApi\strings\WinapiStringCompare>WinapiStringCompare.exe Strong and strong are not equal When applying case insensitive comparison: Strong and strong are equal
填充缓冲区
用格式化数据填充缓冲区是 C 编程中必不可少的操作。wsprintfW
函数将格式化数据写入指定的缓冲区。
int __cdecl wsprintfW(LPWSTR lpOut, LPCWSTR lpFmt, ... );
函数的第一个参数是要接收格式化输出的缓冲区。第二个参数是包含格式控制规范的字符串。然后,我们有一个或多个可选参数,它们对应于格式控制规范。
#include <windows.h> #include <wchar.h> #pragma comment(lib, "User32.lib") int wmain(void) { SYSTEMTIME st = {0}; wchar_t buf[128] = {0}; GetLocalTime(&st); wsprintfW(buf, L"Today is %lu.%lu.%lu\n", st.wDay, st.wMonth, st.wYear); wprintf(buf); return 0; }
我们构建一个字符串,该字符串填充了当前日期。
wchar_t buf[128] = {0};
在这种特殊情况下,我们可以安全地假设字符串不会超过 128 个字符。
GetLocalTime(&st);
GetLocalTime
函数检索当前本地日期和时间。
wsprintfW(buf, L"Today is %lu.%lu.%lu\n", st.wDay, st.wMonth, st.wYear);
wsprintfW
使用宽字符串填充缓冲区。根据格式说明符,参数被复制到字符串中。
wprintf(buf);
缓冲区的内容被打印到控制台。
C:\Users\Jano\Documents\WinApi\strings\WinapiStringFillBuffer>WinapiStringFillBuffer.exe Today is 11.2.2016
字符类型
字符有各种类型。它们可以是数字、空格、字母、标点符号或控制字符。
BOOL WINAPI GetStringTypeW(DWORD dwInfoType, LPCWSTR lpSrcStr, int cchSrc, LPWORD lpCharType);
GetStringTypeW
函数检索指定 Unicode 字符串中字符的字符类型信息。第一个参数是一个标志,用于指定信息类型。
标志 | 含义 |
---|---|
CT_CTYPE1 | 检索字符类型信息。 |
CT_CTYPE2 | 检索双向布局信息。 |
CT_CTYPE3 | 检索文本处理信息。 |
第二个参数是要检索其字符类型的 Unicode 字符串。
第三个参数是字符串的大小。最后一个参数是指向 16 位值数组的指针。此数组的长度必须足够大,以接收源字符串中每个字符的一个 16 位值。该数组将包含对应于源字符串中每个字符的一个字。
GetStringTypeW
函数返回一个值,该值是类型的组合。我们可以使用 & 运算符查询特定类型。
值 | 含义 |
---|---|
C1_DIGIT | 十进制数字 |
C1_SPACE | 空格字符 |
C1_PUNCT | 标点符号 |
C1_CNTRL | 控制字符 |
C1_ALPHA | 任何语言字符 |
该函数在失败时返回 0。
#include <windows.h> #include <wchar.h> #include <stdbool.h> int wmain(void) { wchar_t str[] = L"7 white, 3 red roses.\n"; int alphas = 0; int digits = 0; int spaces = 0; int puncts = 0; int contrs = 0; int size = lstrlenW(str); WORD types[size]; ZeroMemory(types, size); bool rv = GetStringTypeW(CT_CTYPE1, str, size, types); if (!rv) { wprintf(L"Could not get character types (%ld)", GetLastError()); return EXIT_FAILURE; } for (int i=0; i<size; i++) { if (types[i] & C1_ALPHA) { alphas++; } if (types[i] & C1_DIGIT) { digits++; } if (types[i] & C1_SPACE) { spaces++; } if (types[i] & C1_PUNCT) { puncts++; } if (types[i] & C1_CNTRL) { contrs++; } } wprintf(L"There are %ld letter(s), %ld digit(s), " L"%ld space(s), %ld punctuation character(s), " L"and %ld control character(s)\n", alphas, digits, spaces, puncts, contrs); return 0; }
我们有一个短句。 GetStringTypeW
函数用于确定字符串的字符类型。
wchar_t str[] = L"7 white, 3 red roses.\n";
这是一个由各种宽字符组成的短句。
int alphas = 0; int digits = 0; int spaces = 0; int puncts = 0; int contrs = 0;
这些变量将用于计算字母、数字、空格、标点符号和控制字符。
int size = lstrlenW(str); WORD types[size]; ZeroMemory(types, size);
我们获取字符串的大小,并创建和数组的值。大小不包括 NULL
终止字符。我们可以加 1 来包含它。它将被计为控制字符。
bool rv = GetStringTypeW(CT_CTYPE1, str, size, types);
我们获取句子的字符类型。类型数组填充了字符类型值。
if (types[i] & C1_DIGIT) { digits++; }
如果该值包含 C1_DIGIT
标志,则增加数字计数器。
C:\Users\Jano\Documents\WinApi\strings\WinapiStringTypes>WinapiStringTypes.exe There are 13 letter(s), 2 digit(s), 5 space(s), 2 punctuation character(s), and 1 control character(s)
Windows API Shell 轻量级实用程序函数
这些函数特定于 Windows 操作系统;它们在 Shlwapi.lib
中可用。
修剪字符串
StrTrimW
函数从字符串中删除指定的起始和结尾字符。如果删除了任何字符,则返回 true;否则,返回 false。
BOOL WINAPI StrTrimW(LPWSTR psz, LPCWSTR pszTrimChars);
第一个参数是指向要修剪的字符串的指针。当此函数成功返回时,psz
接收修剪后的字符串。第二个参数是指向包含要从 psz
中修剪的字符的字符串的指针。
#include <windows.h> #include <wchar.h> #include <stdbool.h> #include "Shlwapi.h" #pragma comment(lib, "Shlwapi.lib") int wmain(void) { wchar_t buf[] = L"23tennis74"; wchar_t trim[] = L"0123456789"; wprintf(L"Original string: %ls\n", buf); bool r = StrTrimW(buf, trim); if (r == true) { wprintf(L"The StrTrim() trimmed some characters\n", buf); } else { wprintf(L"No characters were trimmed\n", buf); } wprintf(L"Trimmed string: %ls\n", buf); return 0; }
在示例中,我们从字符串中删除任何数字。
wchar_t buf[] = L"23tennis74";
我们从这个字符串中删除所有数字。
wchar_t trim[] = L"0123456789";
此字符串包含要删除的所有字符。
bool r = StrTrimW(buf, trim);
使用 StrTrimW
函数,我们从缓冲区中修剪数字。
C:\Users\Jano\Documents\WinApi\strings\ShellTrimString>ShellTrimString.exe Original string: 23tennis74 The StrTrim() trimmed some characters Trimmed string: tennis
将字符串转换为整数
StrToIntExW
将表示十进制或十六进制数字的字符串转换为整数。该函数在成功时返回 true。
BOOL WINAPI StrToIntExW(LPCWSTR pszString, DWORD dwFlags, int *piRet);
第一个参数是指向要转换的字符串的指针。第二个参数是指定如何解析 pszString
以将其转换为整数的标志之一。第三个参数是指向接收转换后字符串的整数的指针。
#include <windows.h> #include <wchar.h> #include <stdbool.h> #include "Shlwapi.h" #pragma comment(lib, "Shlwapi.lib") int wmain(void) { wchar_t str1[] = L"512"; wchar_t str2[] = L"0xAB12"; int n = 0; bool r = StrToIntExW(str1, STIF_DEFAULT, &n); if (r == true) { wprintf(L"The value is %d\n", n); } else { wprintf(L"The first conversion failed\n"); return 1; } r = StrToIntExW(str2, STIF_SUPPORT_HEX, &n); if (r == true) { wprintf(L"The value is %d\n", n); } else { wprintf(L"The second conversion failed\n"); return 1; } return 0; }
在示例中,我们转换两个字符串;一个表示十进制值,另一个表示十六进制值。
wchar_t str1[] = L"512"; wchar_t str2[] = L"0xAB12";
第一个字符串表示一个十进制数字;第二个字符串表示一个十六进制数字。
bool r = StrToIntExW(str1, STIF_DEFAULT, &n);
使用 StrToIntExW
函数,我们将第一个字符串转换为整数。 STIF_DEFAULT
标志告诉该函数转换十进制值。
r = StrToIntExW(str2, STIF_SUPPORT_HEX, &n);
使用 STIF_SUPPORT_HEX
标志,我们告诉该函数转换十六进制值。
C:\Users\Jano\Documents\WinApi\strings\ShellConvertString>ShellConvertString.exe The value is 512 The value is 43794
搜索字符串
StrStrW
函数在字符串中查找子字符串的第一次出现。比较区分大小写。
LPWSTR WINAPI StrStrW(LPCWSTR pszFirst, LPCWSTR pszSrch);
第一个参数是指向要搜索的字符串的指针。第二个参数是指向要搜索的子字符串的指针。如果成功,该函数将返回匹配子字符串的第一个出现的地址,否则返回 NULL
。
#include <windows.h> #include <wchar.h> #include "Shlwapi.h" #pragma comment(lib, "Shlwapi.lib") int wmain(void) { wchar_t buf[] = L"Today is a rainy day."; wchar_t *search_word = L"rainy"; int len = wcslen(search_word); LPWSTR pr = StrStrW(buf, search_word); if (pr == NULL) { wprintf(L"No match\n", buf); } else { wprintf(L"%.*ls is found\n", len, pr); } return 0; }
在代码示例中,我们在句子中搜索一个单词。
wchar_t buf[] = L"Today is a rainy day.";
我们从这个句子中搜索一个单词。
wchar_t *search_word = L"rainy";
这是我们搜索的单词。
LPWSTR pr = StrStrW(buf, search_word);
StrStrW
函数在句子中搜索一个单词。如果成功,它将返回指向匹配子字符串的指针。
C:\Users\Jano\Documents\WinApi\strings\ShellSearchString>ShellSearchString.exe rainy is found
Windows API StrSafe 函数
为了提高应用程序安全性,发布了 StrSafe 函数。这些函数需要目标缓冲区的大小作为输入。保证缓冲区以 null 结尾。这些函数返回错误代码;这使得可以进行适当的错误处理。
每个函数都可以在相应的字符计数 Cch
或字节计数 Cb
版本中使用。
字符串长度
StringCchLengthW
和 StringCbLengthW
函数可以确定字符串的字符和字节长度。
HRESULT StringCchLengthW(LPCWSTR psz, size_t cchMax, size_t *pcch); HRESULT StringCbLengthW(LPCWSTR psz, size_t cbMax, size_t *pcb);
函数的第一个参数是要检查其长度的字符串。第二个参数是 psz
参数中允许的最大字符数(字节数)。此值不能超过 STRSAFE_MAX_CCH
。第三个参数是 psz
中的字符数(字节数),不包括终止的空字符。
如果成功,这些函数返回 S_OK
,如果失败,则返回 STRSAFE_E_INVALID_PARAMETER
。如果 psz
中的值为 NULL
,cchMax
大于 STRSAFE_MAX_CCH
,或者 psz
的长度大于 cchMax
,则这些函数会失败。可以使用 SUCCEEDED
和 FAILED
宏来检查这些函数的返回值。
#include <windows.h> #include <strsafe.h> #include <wchar.h> int wmain(void) { wchar_t str[] = L"ZetCode"; size_t target_size = 0; size_t size = sizeof(str); HRESULT r = StringCbLengthW(str, size, &target_size); if (SUCCEEDED(r)) { wprintf(L"The string has %lld bytes\n", target_size); } else { wprintf(L"StringCbLengthW() failed\n"); return 1; } size = sizeof(str)/sizeof(wchar_t); r = StringCchLengthW(str, size, &target_size); if (SUCCEEDED(r)) { wprintf(L"The string has %lld characters\n", target_size); } else { wprintf(L"StringCchLengthW() failed\n"); return 1; } return 0; }
代码示例确定给定字符串的字符和字节长度。
wchar_t str[] = L"ZetCode";
我们将确定此字符串的长度。
size_t target_size = 0;
当函数返回时,使用计数的值填充 target_size
变量。
size_t size = sizeof(str);
使用 sizeof
运算符,我们获取字符数组的大小(以字节为单位)。该值用作 StringCbLengthW
函数中字符串的最大允许字符数。
HRESULT r = StringCbLengthW(str, size, &target_size);
使用 StringCbLengthW
函数,我们确定字符串的字节长度。该长度存储在 target_size
变量中。
if (SUCCEEDED(r)) { wprintf(L"The string has %lld bytes\n", target_size); } else { wprintf(L"StringCbLengthW() failed\n"); return 1; }
我们使用 SUCCEEDED
宏检查返回的值。如果成功,我们打印字符串中的字节数;如果出错,我们打印错误消息。
size = sizeof(str)/sizeof(wchar_t);
在这里,我们确定字符串中允许的最大字符数。wchar_t
是宽字符的类型;它的 size 取决于编译器。
r = StringCchLengthW(str, size, &target_size);
使用 StringCchLengthW
函数,我们获取字符串的字符数大小。
if (SUCCEEDED(r)) { wprintf(L"The string has %lld characters\n", target_size); } else { wprintf(L"StringCchLengthW() failed\n"); return 1; }
如果成功,我们在控制台中打印字符串中的字符数。如果出错,我们打印错误消息。
C:\Users\Jano\Documents\WinApi\strsafe\SafeLength>SafeLength.exe The string has 14 bytes The string has 7 characters
该字符串由 14 个字节或 7 个字符组成。
读取标准输入
StringCchGetsW
从标准输入读取一行,包括换行符。
HRESULT StringCchGetsW(LPWSTR pszDest, size_t cchDest);
第一个参数是目标缓冲区,它接收复制的字符。第二个参数是目标缓冲区的大小,以字符为单位。
#include <windows.h> #include <strsafe.h> #include <wchar.h> #define BUF_LEN 8191 int wmain(void) { wchar_t buf[BUF_LEN] = {0}; HRESULT r = StringCchGetsW(buf, ARRAYSIZE(buf)); if (SUCCEEDED(r)) { wprintf(L"You have entered: %ls\n", buf); } else { wprintf(L"StringCchGets() failed\n"); return 1; } return 0; }
在示例中,我们从标准输入读取一行。该行被打印回控制台。
#define BUF_LEN 8191
根据 MSDN 文档,命令行提示符的最大输入不能超过 8191 个字符。
wchar_t buf[BUF_LEN] = {0};
我们为输入字符串创建一个缓冲区。
HRESULT r = StringCchGetsW(buf, ARRAYSIZE(buf));
StringCchGetsW
从 stdin
读取一行。
C:\Users\Jano\Documents\WinApi\strsafe\SafeGets>SafeGets.exe Today is a rainy day. You have entered: Today is a rainy day.
复制字符串
StringCchCopyW
将一个字符串复制到另一个字符串。
HRESULT StringCchCopyW(LPTSTR pszDest, size_t cchDest, LPCWSTR pszSrc);
第一个参数是目标缓冲区,它接收复制的字符串。第二个参数是目标缓冲区的大小,以字符为单位。第三个参数是源字符串。
#include <windows.h> #include <strsafe.h> #include <wchar.h> int wmain(void) { wchar_t *sentence = L"Today is a rainy day."; size_t size = wcslen(sentence) + 1; wchar_t buf[size]; ZeroMemory(buf, size); HRESULT r = StringCchCopyW(buf, size, sentence); if (SUCCEEDED(r)) { wprintf(L"%ls\n", buf); } else { wprintf(L"StringCchCopyW() failed\n"); return 1; } return 0; }
在代码示例中,我们使用 StringCchCopyW
函数复制一个字符串。
wchar_t *sentence = L"Today is a rainy day.";
这是要复制的字符串。
size_t size = wcslen(sentence) + 1;
我们使用 wcslen
函数确定其长度;一个字符用于换行符。
wchar_t buf[size]; ZeroMemory(buf, size);
我们创建一个缓冲区,并使用 ZeroMemory
函数用零填充它。
HRESULT r = StringCchCopyW(buf, size, sentence);
使用 StringCchCopyW
,我们将字符串复制到缓冲区中。提供了目标缓冲区的大小,以确保它不会写入超出此缓冲区的末尾。
C:\Users\Jano\Documents\WinApi\strsafe\SafeCopy>SafeCopy.exe Today is a rainy day.
连接字符串
StringCchCatW
将一个字符串连接到另一个字符串。
HRESULT StringCchCatW(LPWSTR pszDest, size_t cchDest, LPCWSTR pszSrc);
第一个参数是目标缓冲区。第二个参数是目标缓冲区的大小,以字符为单位。第三个参数是要连接到目标缓冲区末尾的源字符串。
#include <windows.h> #include <strsafe.h> #include <wchar.h> #define BUF_LEN 256 int wmain(void) { wchar_t buf[BUF_LEN] = {0}; HRESULT r = StringCchCatW(buf, BUF_LEN, L"Hello "); if (FAILED(r)) { wprintf(L"StringCchCatW() failed\n"); return 1; } r = StringCchCatW(buf, BUF_LEN, L"there"); if (FAILED(r)) { wprintf(L"StringCchCatW() failed\n"); return 1; } wprintf(L"%ls\n", buf); return 0; }
在代码示例中,我们使用 StringCchCatW
函数连接两个字符串。
HRESULT r = StringCchCatW(buf, BUF_LEN, L"Hello ");
StringCchCatW
函数将 L"Hello "
字符串添加到 buf 数组中。
r = StringCchCatW(buf, BUF_LEN, L"there");
稍后,第二个字符串被添加到缓冲区中。
C:\Users\Jano\Documents\WinApi\strsafe\SafeConcat>SafeConcat.exe Hello there
格式化字符串
StringCchPrintfW
函数将格式化数据写入目标缓冲区。
HRESULT StringCchPrintfW(LPWSTR pszDest, size_t cchDest, LPCWSTR pszFormat, ...);
第一个参数是目标缓冲区,它接收从 pszFormat
及其参数创建的格式化字符串。第二个参数是目标缓冲区,以字符为单位。第三个参数是格式字符串。以下参数被插入到 pszFormat
字符串中。
#include <windows.h> #include <strsafe.h> #include <wchar.h> #define BUF_LEN 256 int wmain(void) { wchar_t *word = L"table"; int count = 6; wchar_t buf[BUF_LEN] = {0}; wchar_t *line = L"There are %d %lss"; HRESULT r = StringCchPrintfW(buf, ARRAYSIZE(buf), line, count, word); if (SUCCEEDED(r)) { wprintf(L"%ls\n", buf); } else { wprintf(L"StringCchPrintfW() failed\n"); return 1; } return 0; }
在代码示例中,我们使用 StringCchPrintfW
函数创建一个格式化字符串。
wchar_t *line = L"There are %d %lss";
这是格式字符串;它有两个格式说明符:%d
和 %ls
。
HRESULT r = StringCchPrintfW(buf, ARRAYSIZE(buf), line, count, word);
使用 StringCchPrintfW
函数,我们将两个值插入到目标缓冲区中。
C:\Users\Jano\Documents\WinApi\strsafe\SafeFormat>SafeFormat.exe There are 6 tables
在本 Windows API 教程中,我们使用字符串进行了工作。