1、MessageBoxA 和 MessageBoxW

1.1、代码实例

WINUSERAPI
int
WINAPI
MessageBoxA(
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType);
WINUSERAPI
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 // !UNICODE 函数讲解并例子

MessageBoxAMessageBoxWWindows API 中用于显示消息框的函数,分别用于处理 ANSI 字符集(A 表示 ANSI)和 Unicode 字符集(W 表示 Wide)。

1.2、MessageBoxA 函数

int WINAPI MessageBoxA(
    HWND hWnd,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT uType
);

  • hWnd: 指定消息框的父窗口句柄。可以为 NULL。
  • lpText: 指定消息框中显示的文本。
  • lpCaption: 指定消息框的标题栏文本。
  • uType: 指定消息框的样式和按钮,例如 MB_OK 表示只有一个确定按钮。

1.3、MessageBoxW 函数

int WINAPI MessageBoxW(
    HWND hWnd,
    LPCWSTR lpText,
    LPCWSTR lpCaption,
    UINT uType
);

  • 参数和功能同 MessageBoxA,但处理的是宽字符集(Unicode)。

1.4、条件编译

#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

这段代码通过 #ifdef UNICODE 条件编译,根据编译时是否定义了 UNICODE 宏来选择使用 MessageBoxW 还是 MessageBoxA

1.5、示例代码

#include <windows.h>

int main() {
    LPCWSTR wideText = L"Hello, this is a wide character string!";
    LPCWSTR wideCaption = L"MessageBox Example";
    
    // 使用 MessageBoxW 显示 Unicode 字符串消息框
    MessageBox(NULL, wideText, wideCaption, MB_OK);

    #ifndef UNICODE
    LPCSTR narrowText = "Hello, this is an ANSI character string!";
    LPCSTR narrowCaption = "MessageBox Example";
    
    // 使用 MessageBoxA 显示 ANSI 字符串消息框
    MessageBox(NULL, narrowText, narrowCaption, MB_OK);
    #endif

    return 0;
}

在上述示例中,根据是否定义了 UNICODE 宏,选择调用相应版本的 MessageBox 函数。在实际开发中,如果你使用宽字符字符串,建议使用 MessageBoxW 函数以支持 Unicode

2、LPCWSTR宽字符字符串(Unicode) 与 LPCSTR窄字符字符串(ANSI) 的转换

LPCWSTRLPCSTR 分别代表宽字符字符串**(Unicode)和窄字符字符串(ANSI)**。在 Windows 环境中,这两种类型的字符串使用的字符编码不同,需要谨慎处理转换。

2.1、从 LPCSTR 转换到 LPCWSTR

可以使用 MultiByteToWideChar 函数进行转换。

#include <windows.h>
#include <iostream>

int main() {
    LPCSTR narrowString = "ANSI String";
    int wideStrLen = MultiByteToWideChar(CP_ACP, 0, narrowString, -1, nullptr, 0);
    wchar_t* wideString = new wchar_t[wideStrLen];
    MultiByteToWideChar(CP_ACP, 0, narrowString, -1, wideString, wideStrLen);

    // 使用 wideString,它是 Unicode 字符串
    std::wcout << L"Converted Wide String: " << wideString << std::endl;

    delete[] wideString;

    return 0;
}

2.2、从 LPCWSTR 转换到 LPCSTR:

可以使用 WideCharToMultiByte 函数进行转换。

#include <windows.h>
#include <iostream>

int main() {
    LPCWSTR wideString = L"Unicode String";
    int narrowStrLen = WideCharToMultiByte(CP_ACP, 0, wideString, -1, nullptr, 0, nullptr, nullptr);
    char* narrowString = new char[narrowStrLen];
    WideCharToMultiByte(CP_ACP, 0, wideString, -1, narrowString, narrowStrLen, nullptr, nullptr);

    // 使用 narrowString,它是 ANSI 字符串
    std::cout << "Converted Narrow String: " << narrowString << std::endl;

    delete[] narrowString;

    return 0;
}

在上述示例中,MultiByteToWideChar 用于将窄字符字符串转换为宽字符字符串,WideCharToMultiByte 用于将宽字符字符串转换为窄字符字符串。在使用这些函数时,请确保考虑字符编码和释放动态分配的内存。

3、宽字符 窄字符 相互转换

在 C++ 中,宽字符(Wide Characters)窄字符(Narrow Characters) 之间的相互转换可以使用一些函数来完成。主要的函数有
在这里插入图片描述

3.1、窄字符到宽字符的转换

mbstowcs_s: 将多字节字符串(窄字符)转换为宽字符字符串。

mbstowcs: 与 mbstowcs_s 类似,但在某些环境中可能不是线程安全的。

示例代码:

#include <iostream>
#include <cstring>

int main() {
    const char narrowStr[] = "Narrow String";
    const size_t bufferSize = 100;
    wchar_t wideStr[bufferSize];

    size_t convertedChars = 0;
    mbstowcs_s(&convertedChars, wideStr, narrowStr, _TRUNCATE);

    std::wcout << L"Wide String: " << wideStr << std::endl;

    return 0;
}

3.1.1、mbstowcs: 与 mbstowcs_s 区别

mbstowcs 和 mbstowcs_s 函数都用于将多字节字符串(char)转换为宽字符字符串(wchar_t),但它们之间有一些关键的区别,主要涉及到安全性和错误处理。**

  • 安全性和错误处理:

    • mbstowcs 函数不提供安全性检查,因此在进行转换时,需要确保目标缓冲区足够大以容纳转换后的字符串。如果目标缓冲区不足以容纳字符串,可能导致缓冲区溢出。
    • mbstowcs_s 是 C11 标准引入的函数,提供了安全性检查。它接受目标缓冲区的大小作为参数,以及用于指示溢出的处理方式。如果目标缓冲区不足,mbstowcs_s 会截断字符串,避免缓冲区溢出。
  • 函数原型:

    • mbstowcs 的原型是:
    • size_t mbstowcs(wchar_t *wcstr, const char *mbstr, size_t count);
    • 其中 count 表示要转换的多字节字符数。
    • mbstowcs_s 的原型是:
    • errno_t mbstowcs_s(size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count);
    • 其中 sizeInWords 表示目标缓冲区的大小(以字为单位),pReturnValue 用于返回转换后的字符数。
  • 返回值:

    • mbstowcs 返回转换后的字符数,如果出错则返回 size_t(-1)。
    • mbstowcs_s 的返回值是一个错误码 errno_t,成功返回 0,失败返回错误码。
  • 以下是一个简单的示例,演示了如何使用 mbstowcsmbstowcs_s 进行多字节到宽字符的转换:

#include <iostream>
#include <cstdlib>

int main() {
    const char* narrowString = "Hello, this is a narrow character string!";

    // 使用 mbstowcs
    size_t bufferSize = mbstowcs(nullptr, narrowString, 0);
    wchar_t* wideString = new wchar_t[bufferSize + 1];  // 加上 null 终止符的位置
    size_t convertedChars = mbstowcs(wideString, narrowString, bufferSize);

    std::wcout << L"Converted Wide String (mbstowcs): " << wideString << std::endl;

    delete[] wideString;

    // 使用 mbstowcs_s
    size_t convertedChars_s = 0;
    errno_t err = mbstowcs_s(&convertedChars_s, nullptr, 0, narrowString, 0);
    wchar_t* wideString_s = new wchar_t[convertedChars_s + 1];  // 加上 null 终止符的位置
    err = mbstowcs_s(&convertedChars_s, wideString_s, convertedChars_s + 1, narrowString, _TRUNCATE);

    std::wcout << L"Converted Wide String (mbstowcs_s): " << wideString_s << std::endl;

    delete[] wideString_s;

    return 0;
}

  • 在这个例子中,mbstowcsmbstowcs_s 都被用于将多字节字符串转换为宽字符字符串,并输出转换结果。

3.2、宽字符到窄字符的转换:

wcstombs_s: 将宽字符字符串转换为多字节字符串。

wcstombs: 与 wcstombs_s 类似,但在某些环境中可能不是线程安全的。

  • wcstombs_s 函数是用于将宽字符字符串(wchar_t*)转换为多字节字符串(char*)的安全版本。这个函数是 C11 标准引入的,并且在 Microsoft Visual Studio 中提供了对该函数的支持。
  • 以下是 wcstombs_s 函数的原型:
errno_t wcstombs_s(
   size_t *pReturnValue,
   char *mbstr,
   size_t sizeInBytes,
   const wchar_t *wcstr,
   size_t count
);

  • 其中:

    • pReturnValue:指向存储转换后的字符数的变量的指针。
    • mbstr:指向目标多字节字符串缓冲区的指针。
    • sizeInBytes:目标缓冲区的大小(以字节为单位)。
    • wcstr:指向源宽字符字符串的指针。
    • count:要转换的宽字符的最大数量。
  • 这个函数的目标是将 wcstr 中的宽字符字符串转换为多字节字符串,并将结果存储在 mbstr 中。函数会计算转换后的字符数,存储在 pReturnValue 中,以便检查缓冲区是否足够大以容纳转换后的字符串。

#include <iostream>
#include <locale>
#include <cstdlib>

int main() {
    const wchar_t* wideString = L"Hello, this is a wide character string!";
    size_t convertedChars = 0;

    // 计算需要的缓冲区大小
    size_t bufferSize = 0;
    wcstombs_s(&convertedChars, nullptr, 0, wideString, 0);
    bufferSize = convertedChars + 1; // 加上 null 终止符的位置

    // 分配缓冲区
    char* narrowString = new char[bufferSize];

    // 进行转换
    wcstombs_s(&convertedChars, narrowString, bufferSize, wideString, _TRUNCATE);

    // 输出结果
    std::cout << "Converted Narrow String: " << narrowString << std::endl;

    // 释放内存
    delete[] narrowString;

    return 0;
}

以下是一个简单的示例:

示例代码:

#include <iostream>
#include <cstring>

int main() {
    const wchar_t wideStr[] = L"Wide String";
    const size_t bufferSize = 100;
    char narrowStr[bufferSize];

    size_t convertedChars = 0;
    wcstombs_s(&convertedChars, narrowStr, wideStr, _TRUNCATE);

    std::cout << "Narrow String: " << narrowStr << std::endl;

    return 0;
}

这些函数通常在编写涉及多字节字符集和宽字符集的代码时很有用。请注意,宽字符集一般用于 Unicode 字符,而多字节字符集则是传统的 ASCII 或其他字符编码。使用这些函数时要注意字符编码的问题。

3.2.1、wcstombs 和wcstombs_s区别
  • wcstombs 和 wcstombs_s 都是用于将宽字符字符串(wchar_t*)转换为多字节字符串(char*)的函数,但它们有一些关键的区别,主要体现在安全性和错误处理方面。
    • 安全性和错误处理:

      • wcstombs 函数不提供安全性检查,因此在进行转换时,需要确保目标缓冲区足够大以容纳转换后的字符串。如果目标缓冲区不足以容纳字符串,可能导致缓冲区溢出。
      • wcstombs_sC11 标准引入的函数,提供了安全性检查。它接受目标缓冲区的大小作为参数,以及用于指示溢出的处理方式。如果目标缓冲区不足,wcstombs_s 会截断字符串,避免缓冲区溢出。
    • 函数原型:

      • wcstombs 的原型是:
      • size_t wcstombs(char *mbstr, const wchar_t *wcstr, size_t count);
      • 其中 count 表示要转换的宽字符数。
      • wcstombs_s 的原型是:
      • errno_t wcstombs_s(size_t *pReturnValue, char *mbstr, size_t sizeInBytes, const wchar_t *wcstr, size_t count);
      • 其中 sizeInBytes 表示目标缓冲区的大小,pReturnValue 用于返回转换后的字符数。
    • 返回值:

      • wcstombs 返回转换后的字符数,如果出错则返回 size_t(-1)。
      • wcstombs_s 的返回值是一个错误码 errno_t,成功返回 0,失败返回错误码。
    • 下面是一个简单的示例,演示了如何使用 wcstombs 和 wcstombs_s 进行宽字符到多字节的转换:

#include <iostream>
#include <cstdlib>

int main() {
    const wchar_t* wideString = L"Hello, this is a wide character string!";

    // 使用 wcstombs
    size_t bufferSize = wcstombs(nullptr, wideString, 0);
    char* narrowString = new char[bufferSize + 1];  // 加上 null 终止符的位置
    size_t convertedChars = wcstombs(narrowString, wideString, bufferSize);

    std::cout << "Converted Narrow String (wcstombs): " << narrowString << std::endl;

    delete[] narrowString;

    // 使用 wcstombs_s
    size_t convertedChars_s = 0;
    errno_t err = wcstombs_s(&convertedChars_s, nullptr, 0, wideString, 0);
    char* narrowString_s = new char[convertedChars_s + 1];  // 加上 null 终止符的位置
    err = wcstombs_s(&convertedChars_s, narrowString_s, convertedChars_s + 1, wideString, _TRUNCATE);

    std::cout << "Converted Narrow String (wcstombs_s): " << narrowString_s << std::endl;

    delete[] narrowString_s;

    return 0;
}

在这个例子中,wcstombswcstombs_s 都被用于将宽字符字符串转换为多字节字符串,并输出转换结果。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐