跳转至

Windows API 中的字符串

原文: http://zetcode.com/gui/winapi/strings/

在 C 语言中,没有字符串数据类型。 程序中的字符串字面值是字符数组。 每当我们说字符串时,都是指一个字符数组。

我们有五组处理字符串的函数; 在 C 运行时库(CRT)和 Windows API 中:

  • ANSI C 标准函数
  • 安全性增强的 CRT 函数
  • Windows API 内核和用户函数
  • Windows API Shell 轻量级工具函数
  • Windows API StrSafe 函数

建议您使用安全性增强的标准函数或 Windows API 安全函数。

ANSI C 字符串函数

C 运行时(CRT)库函数的开销很小,因为它们在下面调用 Windows API 函数。 这些函数提供了可移植性,但有一些限制。 如果使用不当,可能会导致安全隐患。

这些函数失败时不会返回错误值。

ansic_functions.c

#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\Pelles C Projects\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

security_enhanced.c

#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\Pelles C Projects\strings\SecurityEnhanced>SecurityEnhanced.exe
The length of the string is 18 characters
Wuthering heights

这是SecurityEnhanced.exe示例的输出。

Windows API 内核和用户字符串函数

这些函数特定于 Windows OS。 它们在User32.libKernel32.lib中可用。 它们比 CRT 同类产品轻。

内核字符串函数起源于 Windows 内核的开发。 它们以l字母为前缀。

字符串长度

最常见的要求之一是弄清楚字符串的长度。 lstrlen()函数以字符为单位返回指定字符串的长度。 它不计算终止的空字符。

int WINAPI lstrlenA(LPCSTR lpString);
int WINAPI lstrlenW(LPCWSTR lpString);

ANSI 和 UNICODE 函数将字符串作为参数,并返回字符串中的字符数。

winapi_string_lenght.c

#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\Pelles C Projects\strings\WinapiStringLength>WinapiStringLength.exe
The length of the name string is 4
The town string length is 10

这是WinapiStringLength.exe程序的输出。

连接字符串

lstrcatW()函数将一个字符串附加到另一个字符串。

LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2);

第一个参数是缓冲区,其中应包含两个字符串。 它必须足够大以包含两个字符,包括NULL终止字符。 返回值是指向缓冲区的指针。

winapi_string_concat.c

#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\Pelles C Projects\strings\WinapiStringConcat>WinapiStringConcat.exe
ZetCode, tutorials for programmers.

这是WinapiStringConcat.exe程序的输出。

转换字符

我们有两种将字符转换为大写或小写的方法。 CharLowerW()函数将字符串或单个字符转换为小写。 CharUpperW()函数将字符串或单个字符转换为大写。 如果操作数是字符串,则该函数将就地转换字符。 换句话说,它们已被修改。

LPWSTR WINAPI CharLowerW(LPWSTR lpsz);
LPWSTR WINAPI CharUpperW(LPWSTR lpsz);

这些函数在适当位置修改字符串,并返回指向修改后的字符串的指针。

winapi_string_case.c

#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

这是UpperLower.exe程序的输出。

比较字符串

lstrcmpW()函数比较两个字符串。 如果字符串相等,则返回 0。 比较是区分大小写的。 这意味着Cupcup是两个不同的字符串。 lstrcmpiW()产生不区分大小写的字符串比较。 对于此函数,Cupcup相等。

int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2);
int WINAPI lstrcmpiW(LPCWSTR lpString1, LPCWSTR lpString2);

这些函数采用两个字符串作为参数。 返回值指示字符串的相等性。 对于相等的字符串,返回 0 值。

winapi_string_compare.c

#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()函数返回定义为 0 的STR_EQUAL,则我们向控制台显示两个字符串相等。 否则,我们打印出它们不相等。

C:\Users\Jano\Documents\Pelles C Projects\strings\WinapiStringCompare>WinapiStringCompare.exe
Strong and strong are not equal
When applying case insensitive comparison:
Strong and strong are equal

WinapiStringCompare.exe程序给出以上输出。

填充缓冲区

在 C 编程中,用格式化的数据填充缓冲区至关重要。 wsprintfW()函数将格式化的数据写入指定的缓冲区。

int __cdecl wsprintfW(LPWSTR lpOut, LPCWSTR lpFmt, ... );

该函数的第一个参数是要接收格式化输出的缓冲区。 第二个是包含格式控制规范的字符串。 然后,我们有一个或多个可选参数,它们对应于格式控制规范。

winapi_string_fillbuffer.c

#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\Pelles C Projects\strings\WinapiStringFillBuffer>WinapiStringFillBuffer.exe
Today is 11.2.2016

这是WinapiStringFillBuffer.exe示例的输出。

字符类型

字符有多种类型。 它们可以是数字,空格,字母,标点符号或控制字符。

BOOL WINAPI GetStringTypeW(DWORD dwInfoType, LPCWSTR lpSrcStr,
    int cchSrc, LPWORD lpCharType);

GetStringTypeW()函数检索指定 Unicode 字符串中字符的字符类型信息。 第一个参数是指定信息类型的标志。

标志 含义
CT_CTYPE1 检索字符类型信息。
CT_CTYPE2 检索双向布局信息。
CT_CTYPE3 检索文本处理信息。

Table: Character info types

第二个参数是要检索其字符类型的 Unicode 字符串。

第三个参数是字符串的大小。 最后一个参数是指向 16 位值数组的指针。 该数组的长度必须足够大,以便为源字符串中的每个字符接收一个 16 位值。 该数组将包含一个与源字符串中每个字符相对应的单词。

GetStringTypeW()函数返回一个值,该值是类型的组合。 我们可以使用&运算符查询特定类型。

含义
C1_DIGIT 小数位数
C1_SPACE 空格字符
C1_PUNCT 标点
C1_CNTRL 控制字符
C1_ALPHA 任何语言特征

Table: Partial list of character types

如果失败,该函数将返回 0。

winapi_string_types.c

#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);

我们得到句子的字符类型。 types数组填充有字符类型值。

if (types[i] & C1_DIGIT) {
  digits++;
}

如果该值包含C1_DIGIT标志,我们将增加数字计数器。

C:\Users\Jano\Documents\Pelles C Projects\strings\WinapiStringTypes>WinapiStringTypes.exe
There are 13 letter(s), 2 digit(s), 5 space(s), 2 punctuation character(s), 
and 1 control character(s)

这是WinapiStringTypes.exe示例的输出。

Windows API Shell 轻量级工具函数

这些函数特定于 Windows OS。 它们在Shlwapi.lib中可用。

修剪字符串

StrTrimW()函数从字符串中删除指定的开头和结尾字符。 如果删除了任何字符,则返回true;否则返回false。 否则为假。

BOOL WINAPI StrTrimW(LPWSTR psz, LPCWSTR pszTrimChars);

第一个参数是指向要修剪的字符串的指针。 当此函数成功返回时,psz接收到修剪后的字符串。 第二个参数是一个指向字符串的指针,该字符串包含要从psz中修剪的字符。

winapi_shell_trim.c

#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\Pelles C Projects\strings\ShellTrimString>ShellTrimString.exe
Original string: 23tennis74
The StrTrim() trimmed some characters
Trimmed string: tennis

这是ShellTrimString.exe示例的输出。

将字符串转换为整数

StrToIntExW()将代表十进制或十六进制数字的字符串转换为整数。 成功时该函数返回true

BOOL WINAPI StrToIntExW(LPCWSTR pszString, DWORD dwFlags, int *piRet);

第一个参数是指向要转换的字符串的指针。 第二个参数是标志之一,用于指定应如何解析pszString以将其转换为整数。 第三个参数是指向接收转换后的字符串的int的指针。

winapi_shell_convert.c

#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\Pelles C Projects\strings\ShellConvertString>ShellConvertString.exe
The value is 512
The value is 43794

这是ShellConvertString.exe程序的输出。

搜索字符串

StrStrW()函数查找字符串中子字符串的首次出现。 比较是区分大小写的。

LPWSTR WINAPI StrStrW(LPCWSTR pszFirst, LPCWSTR pszSrch);

第一个参数是指向要搜索的字符串的指针。 第二个参数是指向要搜索的子字符串的指针。 如果成功,该函数将返回匹配子字符串的第一个匹配项的地址,否则返回NULL

winapi_shell_search.c

#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\Pelles C Projects\strings\ShellSearchString>ShellSearchString.exe
rainy is found

这是ShellSearchString.exe程序的输出。

Windows API StrSafe 函数

为了提高应用的安全性,发布了 StrSafe 函数。 这些函数需要目标缓冲区的大小作为输入。 保证缓冲区为空终止。 该函数返回错误代码。 这样可以进行正确的错误处理。

每个函数都有相应的字符计数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中的值为NULLcchMax大于STRSAFE_MAX_CCHpsz大于cchMax,则函数将失败。 SUCCEEDEDFAILED宏可用于检查函数的返回值。

safe_length.c

#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是一种宽字符类型; 它的大小取决于编译器。

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\Pelles C Projects\strsafe\SafeLength>SafeLength.exe
The string has 14 bytes
The string has 7 characters

该字符串包含 14 个字节或 7 个字符。

读取标准输入

StringCchGetsW()从标准输入读取一行,包括换行符。

HRESULT StringCchGetsW(LPWSTR pszDest, size_t cchDest);

第一个参数是目标缓冲区,它接收复制的字符。 第二个参数是目标缓冲区的大小(以字符为单位)。

safe_gets.c

#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\Pelles C Projects\strsafe\SafeGets>SafeGets.exe
Today is a rainy day.
You have entered: Today is a rainy day.

这是SafeGets.exe程序的示例运行。

复制字符串

StringCchCopyW()将一个字符串复制到另一个。

HRESULT StringCchCopyW(LPTSTR pszDest, size_t cchDest, LPCWSTR pszSrc);

第一个参数是目标缓冲区,它接收复制的字符串。 第二个参数是目标缓冲区的大小(以字符为单位)。 第三个参数是源字符串。

safe_copy.c

#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\Pelles C Projects\strsafe\SafeCopy>SafeCopy.exe
Today is a rainy day.

这是SafeCopy.exe程序的输出。

连接字符串

StringCchCatW()将一个字符串连接到另一个字符串。

HRESULT StringCchCatW(LPWSTR pszDest, size_t cchDest, LPCWSTR pszSrc);

第一个参数是目标缓冲区。 第二个参数是目标缓冲区的大小(以字符为单位)。 第三个参数是要连接到目标缓冲区末尾的源字符串。

safe_concat.c

#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\Pelles C Projects\strsafe\SafeConcat>SafeConcat.exe
Hello there

这是SafeConcat.exe程序的输出。

格式化字符串

StringCchPrintfW()函数将格式化的数据写入目标缓冲区。

HRESULT StringCchPrintfW(LPWSTR pszDest, size_t cchDest, LPCWSTR pszFormat, ...);

第一个参数是目标缓冲区,它接收从pszFormat及其参数创建的格式化字符串。 第二个参数是目标缓冲区,以字符为单位。 第三个参数是格式字符串。 将以下参数插入pszFormat字符串中。

safe_format.c

#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\Pelles C Projects\strsafe\SafeFormat>SafeFormat.exe
There are 6 tables

这是SafeFormat.exe程序的输出。

在 Windows API 教程的这一部分中,我们使用了字符串。



回到顶部