3

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

我认为这是一个相对简单的事情,我过于复杂了。该应用程序有一个std::string包含当前打印机名称的名称。该脚本首先检查它是否未设置(如果它使用GetDefaultPrinter了哪个输出 a LPTSTR)。最后,脚本采用 thanstd::string或 theLPTSTR并将其转换为LPCTSTRfor 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 研究,但还没有提出具体的解决方案。

任何帮助是极大的赞赏!

4

2 回答 2

2

首先,正如评论中提到的,正确的方法是制作一个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\0", PrinterHandle, NULL, NULL);
于 2013-01-25T22:30:12.037 回答
2

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

例如,对于大多数 Windows API,例如CreateDC,实际上并没有具有该名称的函数。相反,有一个名为的宏CreateDC扩展为CreateDCAor 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);
于 2013-01-26T00:16:40.467 回答