【发布时间】:2015-10-10 21:03:18
【问题描述】:
我一直在开发一个原生 Unity 插件,它允许用户在 Windows 上的默认打印机上打印一些东西(目前是文本)。
我的 (EDIT: OLD) 代码如下,用于打印文本:
bool PrintText(const char* pText, int pTextWidth, int pTextHeight, const char* pPrinterName) {
LPCSTR szDriver = (LPCSTR)"WINSPOOL";
TCHAR szPrinter[256];
DWORD cchBuffer = 255;
HDC hdcPrint = NULL;
HDC hdcPrintImg = NULL;
HANDLE hPrinter = NULL;
PRINTER_INFO_2 *pPrinterData;
BYTE pdBuffer[16384];
BOOL bReturn = FALSE;
LPCSTR documentFilename = "PrintTest";
LPCSTR documentText = (LPCSTR)pText;
DWORD cbBuf = sizeof(pdBuffer);
DWORD cbNeeded = 0;
pPrinterData = (PRINTER_INFO_2 *)&pdBuffer[0];
bReturn = GetDefaultPrinter(szPrinter, &cchBuffer);
if (bReturn) {
bReturn = OpenPrinter((LPSTR)pPrinterName, &hPrinter, NULL);
}
if (bReturn) {
bReturn = GetPrinter(hPrinter, 2, &pdBuffer[0], cbBuf, &cbNeeded);
ClosePrinter(hPrinter);
}
if (bReturn) {
hdcPrint = CreateDC(szDriver, (LPSTR)pPrinterName, pPrinterData->pPortName, NULL);
}
if (hdcPrint) {
Escape(hdcPrint, STARTDOC, 8, documentFilename, NULL);
TextOut(hdcPrint, pTextWidth, pTextHeight, documentText, strlen((const char*)documentText));
Escape(hdcPrint, NEWFRAME, 0, NULL, NULL);
Escape(hdcPrint, ENDDOC, 0, NULL, NULL);
DeleteDC(hdcPrint);
}
return bReturn;
}
这会将文档发送到打印后台处理程序并成功打印,但是,我在 VS 中触发了一个断点,说堆已损坏。
我对 C++ 和非托管语言非常陌生,所以任何指针(哈!)将不胜感激 :)
编辑: 一位工作人员帮助查明了问题。 将文本打印到打印机的最少代码:
bool PrintText(char* inputText, int positionX, int positionY, char* printerName)
{
HDC printerDeviceContext = NULL;
HANDLE printerHandle = NULL;
BOOL bReturn = FALSE;
LPCSTR documentFilename = "PrintTest";
LPCSTR documentText = (LPCSTR)inputText;
DWORD buffer;
DWORD bytesRequired;
bReturn = OpenPrinter((LPSTR)printerName, &printerHandle, NULL);
GetPrinter(printerHandle, 2, NULL, 0, &buffer);
BYTE* printerBuffer = new BYTE[buffer]; //allocate buffer
bReturn = GetPrinter(printerHandle, 2, printerBuffer, buffer, &bytesRequired);
ClosePrinter(printerHandle);
printerDeviceContext = CreateDC(NULL, printerName, NULL, NULL);
if (printerDeviceContext)
{
Escape(printerDeviceContext, STARTDOC, 8, documentFilename, NULL);
TextOut(printerDeviceContext, positionX, positionY, documentText, strlen((char*)documentText));
Escape(printerDeviceContext, NEWFRAME, 0, NULL, NULL);
Escape(printerDeviceContext, ENDDOC, 0, NULL, NULL);
DeleteDC(printerDeviceContext);
}
delete[] printerBuffer; //free buffer
return bReturn;
}
【问题讨论】:
-
混合
char和TCHAR是自找麻烦。放弃两者,并在整个过程中使用wchar_t,以及Windows API 的显式Unicode 版本(例如GetDefaultPrinterW)。 -
有关堆损坏的消息会在内存管理器发现它们时显示出来,而这些消息不一定在它们引起的位置附近。
-
@IInspectable,我同意混合使用
char和TCHAR是一个坏主意,但硬编码 Unicode API 也是如此。只需制作TCHAR的所有内容,它就会在 32 位和 64 位版本中编译并完美运行。 -
@CareyGregory:基于什么原理,硬编码您将使用的唯一 API(即 Unicode)是一个“坏主意”?相反,它会从您的测试矩阵中删除一个参数。这与 32/64 位完全无关。
-
@IInspectable 我没有看到 OP 说他永远不想支持 ASCII,所以当免费提供为 ASCII 或 Unicode 构建的能力时,为什么要将自己锁定在仅限 Unicode 的构建中?如果您真的不打算使用其中一个,那么它可能会从测试矩阵中消失。同时,您正在使用所有“正常”的 Win32 函数名称,并保留将来改变主意的能力。 (显然我的意思是说 ASCII 和 Unicode,而不是我之前的评论中的 32 位和 64 位。)
标签: c++ winapi memory-management printing gdi