在 Unicode 中转换变量

Converting variables in Unicode

本文关键字:变量 转换 Unicode      更新时间:2023-10-16

我是一个Javascript开发人员,所以请放轻松!我正在尝试编写一个C++补丁以在框架上启用打印。我正在使用Unicode进行编译,根据我的研究,这就是让我搞砸的原因。

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

这是我的代码:

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", PrinterHandle, NULL, NULL);

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

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

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

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

任何帮助将不胜感激!

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

例如,对于大多数Windows API(如CreateDC),实际上没有具有该名称的函数。 相反,有一个名为 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);

首先,正如评论中提到的,正确的方法是做一个DWORD并传递地址:

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

为什么这样是这样,以便它可以使用和更改一个数字:

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

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


其次,由于window->getPrinter()返回一个窄字符串,并且您使用的是UNICODE,这使得函数采用宽字符串,因此您应该从窄字符串转换为宽字符串。有几种方法可以做到这一点(例如ildjarn评论中提到的非常简单的方法),甚至这个方法在C++11中也稍微好一点,尽管前面提到的注释更适用于它,但我将使用MultiByteToWideChar和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", PrinterHandle, NULL, NULL);