2015-07-21 4 views
0

Я работаю над собственным плагином 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++ и неуправляемых языков вообще так любые указатели (ха!) Будут оценены :)

EDIT: Людей на работе помогли выявить проблемы. Голый минимум кода для печати текста на принтер:

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 для API Windows (например,' GetDefaultPrinterW'). – IInspectable

+1

Сообщения о кучевом повреждении появляются, когда диспетчер памяти обнаруживает их, что не обязательно находится где-то рядом, где они были вызваны. – molbdnilo

+0

@ Я не согласен с тем, что смешивание 'char' и' TCHAR' - плохая идея, но так жестко кодирует Unicode API. Просто сделайте все 'TCHAR', и он все будет компилироваться и отлично работать как в 32-, так и в 64-битных сборках. –

ответ

1

Я на самом деле не вижу никаких прямых вопросов, которые могут привести к куче коррупции.

Однако есть несколько других вопросов, в приведенном выше коде:

  1. Третий параметр CreateDC должен быть NULL.
  2. второй параметр для CreateDC не должен быть передан в LPSTR !!! (здесь проблема не проблема, так как метод все равно проверяет LPCSTR, но все же: отбрасывание константы необходимо только в очень редких случаях неправильно написанных библиотек ... Использование этого всегда имеет риск неопределенного поведения).
  3. Общие сведения: При необходимости выполнять только приведения. (в большинстве случаев в вашем коде это фактически не так)
  4. Никогда не выделяйте 16k памяти в стеке (BYTE pdBuffer[16384]): В принципе вы должны дважды позвонить GetPrinter(): один раз без предоставления буфера. Этот вызов завершится с ошибкой, но он вернет размер требуемого буфера. Затем выделите буфер для этого размера и предоставьте его второму вызову.

Edit: 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 

Edit 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

 Смежные вопросы

  • Нет связанных вопросов^_^