2015-07-21 98 views
0

我一直在使用本机Unity插件,该插件允许用户在Windows上打印某些内容(此刻为文本)。尝试打印时堆损坏

我(编辑: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; 
} 
+1

混合'char'和'TCHAR'问题。沟通两者,并在整个过程中使用'wchar_t',以及显式的Unicode版本的Windows API(例如'GetDefaultPrinterW')。 – IInspectable

+1

当内存管理器发现它们时,会显示有关堆损坏的消息,而这些消息并不一定就近。 – molbdnilo

+0

@IInspectable,我同意混合'char'和'TCHAR'是一个坏主意,但硬编码Unicode API也是一个好主意。只要将所有东西都做成'TCHAR',它就可以在32位和64位构建中完美编译和工作。 –

回答

1

我居然看不到这可能导致堆损坏任何直接的问题。

然而,有一对夫妇的其他问题,在上面的代码:

  1. 的CreateDC的第三个参数应为NULL。
  2. CreateDC的第二个参数不应该转换为LPSTR! (这里没有问题,因为该方法无论如何都会忽略LPCSTR,但仍然是:只有在非常罕见的写入不正确的库时才需要抛出const ......使用它总是存在未定义行为的风险)。
  3. 一般:只有在必要时才施放。 (在大多数情况下,在你的代码中,它实际上并不是)
  4. 永远不要在堆栈上分配16k内存(BYTE pdBuffer[16384]):基本上你应该调用GetPrinter()两次:一次不提供缓冲区。这个调用会失败,但它会返回实际需要的缓冲区的大小。然后为此大小分配一个缓冲区并将其提供给第二个调用。

编辑: 4实际上应该看起来有点像这样:

GetPrinter(hPrinter, 2, NULL, 0, &cbNeeded); 
BYTE* pBuffer = new BYTE[cbNeeded]; //allocate buffer 
bReturn = GetPrinter(hPrinter, 2, pBuffer, cbNeeded, &cbActual); 

// do something with pBuffer 

delete[] pBuffer; //free buffer 

编辑2: 基本上有三件事情可能出错:

  • 您尝试以释放内存已被释放

    delete pObject; //some code delete pObject;

  • 您尝试使用已经被释放

    delete pObject; pObject->use();

  • 您在堆上有一个缓冲区溢出的地方

    pBuffer = new BYTES[3] memcpy(pBuffer, pSomeMemory, 100); //copy 100 bytes into a 3 byte buffer delete[] pBuffer;

内存几率非常高实际的错误是在你的代码的其他部分。

+0

请原谅我的无知,但对于第4点。我将如何重组我的代码来做到这一点?我只是将所有'NULL'传递给第一个GetPrinter()调用? 我该如何声明并将大小传递给我的'pdBuffer'? – ChappieZ

+0

感谢您的解释。我仍然在OpenPrinter调用周围发生堆损坏(有时会在此之前或之后发生)。仍然不完全确定发生了什么事。我的类型是否可以? – ChappieZ