在 Unicode 中转换变量

Posted

技术标签:

【中文标题】在 Unicode 中转换变量【英文标题】:Converting variables in Unicode 【发布时间】:2013-01-25 21:22:10 【问题描述】:

我是一名 javascript 开发人员,所以请放轻松!我正在尝试只编写一个 C++ 补丁来启用在框架上的打印。我正在使用 Unicode 进行编译,根据我的研究,这让我很困惑。

我认为这是一件相对简单的事情,但我过于复杂了。该应用程序有一个包含当前打印机名称的std::string。该脚本首先检查它是否未设置(如果是,则使用GetDefaultPrinter 输出LPTSTR)。最后,该脚本采用std::stringLPTSTR 并将其转换为LPCTSTRCreateDC

这是我的代码:

std::string PrinterName = window->getPrinter();
LPDWORD lPrinterNameLength;
LPWSTR szPrinterName;
LPCTSTR PrinterHandle;

if (PrinterName == "unset") 
    GetDefaultPrinter( szPrinterName, &lPrinterNameLength );
    PrinterHandle = szPrinterName; //Note sure the best way to convert here
 else 
    PrinterHandle = PrinterName.c_str();

HDC hdc = CreateDC( L"WINSPOOL\0", PrinterHandle, NULL, NULL);

编译时,我只会收到转换错误。比如

无法将参数 2 从 LPDWORD * 转换为 LPDWORD (GetDefaultPrinter)

无法从“const char *”转换为“LPCTSTR”(在 PrinterHandle = PrinterName.c_str() 行)

我对此进行了相当多的 SO 研究,但还没有提出具体的解决方案。

非常感谢任何帮助!

【问题讨论】:

我希望szPrinterName 在函数中获得分配给它的内存。哦,没关系,它没有。你会想要解决这个问题并传递你拥有的内存。 @chris 确实如此-我只是将其省略了,因为它实际上不在问题的范围内。 :) @hmjd 轰隆隆!完成了一个。谢谢! window->getPrinter() 有没有办法返回一个宽字符串而不是它现在返回的窄字符串?如果是这样,那么有一个比转换更有意义的解决方案。 使用std::wstring 而不是std::string 【参考方案1】:

即使您是为“Unicode”(宽字符串)编译的,您也可以调用 API 函数的“ANSI”(窄字符串)版本。 Windows 将为您进行转换,并在后台调用宽字符版本。

例如,对于像 CreateDC 这样的大多数 Windows API,实际上并没有具有该名称的函数。相反,有一个名为CreateDC 的宏扩展为CreateDCACreateDCW,它们是实际的函数名称。当您为“Unicode”编译时,宏扩展为 -W 版本(这是所有现代版本的操作系统中的原生版本。没有什么能阻止您显式调用任一版本,无论您是否编译为Unicode。在大多数情况下,-A 版本会简单地将窄字符串转换为宽字符串,然后调用相应的-W 版本。(这里有一些与创建窗口相关的注意事项,但我不认为他们适用于 DC。)

std::string PrinterName = window->getPrinter();
if (PrinterName == "unset") 
  char szPrinterName[MAX_PATH];  // simplified for illustration
  DWORD cchPrinterNameLength = ARRAYSIZE(szPrinterName);
  GetDefaultPrinterA(szPrinterName, &cchPrinterNameLength);
  PrinterName = szPrinterName;


HDC hdc = CreateDCA("WINSPOOL", PrinterName.c_str(), NULL, NULL);

【讨论】:

刚刚重新编译了这个 - 更好的解决方案。谢谢。【参考方案2】:

首先,如cmets中所说,正确的做法是打一个DWORD并传递地址:

DWORD lpPrinterNameLength;
...
GetDefaultPrinter(..., &lpPrinterNameLength);

为什么会这样,它可以使用和更改数字:

在输入时,指定 pszBuffer 缓冲区的大小(以字符为单位)。在输出时,接收打印机名称字符串的大小(以字符为单位),包括终止空字符。

它只需要一个DWORD,但函数会更改传入的变量中的数字,因此函数需要更改变量的地址,以便这些更改反映给调用者。


其次,由于window->getPrinter() 返回一个窄字符串,而您使用的是UNICODE,这使得函数采用宽字符串,您应该将窄字符串转换为宽字符串。有几种方法可以做到这一点(例如在 ildjarn 的评论中提到的非常简单的一种),即使是这个在 C++11 上也稍微好一些,尽管前面提到的注释更适用于此,但我将使用 @987654326 @ 和 C++03:

std::wstring narrowToWide(const std::string &narrow) 
    std::vector<wchar_t> wide;

    int length = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, narrow.c_str(), -1, NULL, 0);
    if (!length) 
        //error
    

    wide.resize(length);
    if (!MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, narrow.c_str(), -1, &wide[0], length)) 
        //error, should probably check that the number of characters written is consistent as well
    

    return std::wstring(wide.begin(), wide.end());


...

std::wstring PrinterName = narrowToWide(window->getPrinter());
//rest is same, but should be L"unset"
CreateDC( L"WINSPOOL\0", PrinterHandle, NULL, NULL);

【讨论】:

如果 OP 使用的是 VC++ 2012,他们可以将 narrowToWide 替换为 std::wstring_convert::from_bytes() @ildjarn,我不确定您的评论到底是什么意思,但我认为它会像那样简单。如果您知道将使用 VS2012,这将非常有用。 或任何 C++11 工具链。 :-] @ildjarn,哦,那不是 VS 扩展?惊人的! :) @JesseGood,我错过了什么吗?从我提取的内容来看,它与std::string 进行比较,所以没关系,而且它是一个未知函数,因此在这种情况下,返回值不能轻易被证明是不同的东西。还是您在谈论我在评论中提到将其更改为L"unset" 的事实?

以上是关于在 Unicode 中转换变量的主要内容,如果未能解决你的问题,请参考以下文章

C++ 将 wstring 转换为 Unicode

Java 经典实例: Unicode字符和String之间的转换

unicode16与unicode32之间是啥转换关系

如何将unicode转换成汉字

python中怎样将unicode转换成原来的中文?

怎样将unicode编码转换为中文