在 Unicode 中转换变量
Posted
技术标签:
【中文标题】在 Unicode 中转换变量【英文标题】:Converting variables in Unicode 【发布时间】:2013-01-25 21:22:10 【问题描述】:我是一名 javascript 开发人员,所以请放轻松!我正在尝试只编写一个 C++ 补丁来启用在框架上的打印。我正在使用 Unicode 进行编译,根据我的研究,这让我很困惑。
我认为这是一件相对简单的事情,但我过于复杂了。该应用程序有一个包含当前打印机名称的std::string
。该脚本首先检查它是否未设置(如果是,则使用GetDefaultPrinter
输出LPTSTR
)。最后,该脚本采用std::string
或LPTSTR
并将其转换为LPCTSTR
为CreateDC
。
这是我的代码:
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
的宏扩展为CreateDCA
或CreateDCW
,它们是实际的函数名称。当您为“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 中转换变量的主要内容,如果未能解决你的问题,请参考以下文章