如何使用 Unicode 集将 std::string 传递给 CreateDirectory

Posted

技术标签:

【中文标题】如何使用 Unicode 集将 std::string 传递给 CreateDirectory【英文标题】:How to pass std::string to CreateDirectory with Unicode set 【发布时间】:2015-02-28 07:43:14 【问题描述】:

我在使用 CreateDirectory 函数时遇到了困难。在下面的代码中,我得到一个 “无法将参数 1 从 'const char *' 转换为 'LPCWSTR'” CreateDirectory 调用的编译错误。

// make path to folder in program data
char szPath[MAX_PATH];
if ( ! SUCCEEDED( SHGetFolderPathA( NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath ) ) )

    std::cout << "ERROR: Could not open server log - no common data folder " << std::endl;
    exit(1);

std::string fname = szPath;
fname +="/Point";
CreateDirectory( fname.c_str(), NULL);

我正在使用 Visual Studio 2015 并且有“字符集 = 使用 Unicode 字符集”。

在fileapi.h中定义如下:

#ifdef UNICODE
    #define CreateDirectory  CreateDirectoryW
#else
    #define CreateDirectory  CreateDirectoryA
#endif // !UNICODE

所以我认为正在使用 CreateDirectoryW 函数

我需要做什么才能正确编译?

【问题讨论】:

【参考方案1】:

您需要使用std::wstring 而不是std::string 才能使用宽字符串。

int main()

    // make path to folder in program data
    wchar_t szPath[MAX_PATH];
    if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath)))
    
        std::cout << "ERROR: Could not open server log - no common data folder " << std::endl;
        exit(1);
    
    std::wstring fname = szPath;
    fname += L"/Point";
    CreateDirectory(fname.c_str(), NULL);

如果您不想使用宽字符串,则需要显式调用窄字符版本的 Windows API 函数,例如 CreateDirectoryA 而不是 CreateDirectory

【讨论】:

【参考方案2】:

使用CreateDirectoryA

也就是说,您最好在应用程序中更改为 Unicode,宽文本。


原代码有一些问题:

// make path to folder in program data

↑ 此评论具有误导性:代码是关于寻找路径,而不是创建路径。

char szPath[MAX_PATH];

↑ 这个缓冲区是不必要的,相反,对于这段代码,你应该在这里声明后面的变量std::string fname,并指定缓冲区大小。

if ( ! SUCCEEDED( SHGetFolderPathA( NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath ) ) )

!SUCCEEEDED 是对惯用 FAILED 的误导性重写。 SHGetFolderPath 已被弃用。相反,您应该使用SHGetKnownFolderPath


    std::cout << "ERROR: Could not open server log - no common data folder " << std::endl;
    exit(1);

↑ 控制台输出使得这种故障处理在 GUI 程序中几乎没有价值。无论如何,您应该使用cerrclog 而不是cout(默认情况下它们都映射到标准错误流)。在exit 调用中,您应该使用诸如EXIT_FAILURE 之类的标准值,或者提供您得到的HRESULT(这是Windows 约定,特别是对于崩溃程序),或者对于某些函数,该值你来自GetLastError。无论如何exit 太激烈了。您应该要么抛出异常,要么返回一个可选项。

std::string fname = szPath;
fname +="/Point";

↑ 通常支持正斜杠,但 Windows 约定仍将反斜杠作为项目分隔符。

CreateDirectory( fname.c_str(), NULL);

↑ 在包含windows.h 之前定义的UNICODE 无法编译的唯一问题。使用CreateDirectoryA。或者更好的是,切换到 Unicode。

【讨论】:

Hej Alf.您能否详细说明您的评论“切换到 Unicode”?我正在寻找的是最佳实践。程序的其余部分是为在多个平台上工作而编写的,即 OS X 和 64 位。 @user2235373:对于纯 Windows 应用程序切换到 Unicode 就像在包含 windows.h 之前定义 UNICODE 并使用宽文本一样简单,即基于 wchar_t 类型,加上一点支持控制台输出。对于具有宽文本方法的可移植代码,您需要在 Unix 领域提供不同的控制台输出支持(基本上只是调用 setlocale)。但是,使用第 3 方 Unix-land 库,仅使用宽文本的方法不一定可行。相反,我建议使用抽象层,以便相同的代码在 Windows 中使用宽文本 (UTF-16),在 *nix 中使用窄文本 (UTF-8)

以上是关于如何使用 Unicode 集将 std::string 传递给 CreateDirectory的主要内容,如果未能解决你的问题,请参考以下文章

如何从构造中寻址变量以用于同一类的方法?

NASM 程序集将输入转换为整数?

MASM 程序集将 8 位寄存器移动到 16 位寄存器(即 mov cx,ch)[重复]

使用表单集将许多文件上传到记录,它不是很有效

使用 .NET 中的类型化数据集将 SQL 参数传递给 IN() 子句

计数不使用 iris 数据集将字符串转换为浮点数