My StartDoc() fails in Windows 7, runs well in Windows XP

风格不统一 提交于 2019-12-11 11:22:33

问题


My code is in 32 bit Visual C++ 2010. It is the usual print-using-default-printer one, which goes like this (this is the exact code minus error handlers):

// Get the length of the printer name.
GetDefaultPrinter(NULL, &size);
lpcPrinterName = new char[size];

// Get the printer name.
if(!GetDefaultPrinter(lpcPrinterName, &size)) {
    // handle error
    return false;
}

// Get a device context for the printer.
hdcPrint = CreateDC(NULL, lpcPrinterName, NULL, NULL);

// get printer parameters
iPrinterDPIX = GetDeviceCaps(hdcPrint, LOGPIXELSX);      // x dpi
iPrinterDPIY = GetDeviceCaps(hdcPrint, LOGPIXELSY);      // y dpi
iPrinterBPP  = GetDeviceCaps(hdcPrint, BITSPIXEL);       // bit per pixel
iPrinterHRes = GetDeviceCaps(hdcPrint, HORZRES);         // x printable area in pixels. 0 maps to 0 here
iPrinterVRes = GetDeviceCaps(hdcPrint, VERTRES);         // y printable area in pixels. 0 maps to 0 here

if (!OpenPrinter(lpcPrinterName, &printerHandle, NULL)) {
    // handle error
    return false;
}

// initialize docInfo
ZeroMemory(&docInfo, sizeof(docInfo));
docInfo.cbSize = sizeof(docInfo);
docInfo.lpszDocName = lpcstrDocName;

// ---> this is where it fails when run standalone on Windows 7, return value == -1
iPrintJobID = StartDoc(hdcPrint, &docInfo); // this starts a print job

if (iPrintJobID <= 0) {
    // handle error
    return false;
}

if (StartPage(hdcPrint) <= 0) { // this starts a new page
    // handle error
    return false;
}

{ // enclose in an inner scope to get graphics destroyed before deleting dc
    Gdiplus::Graphics graphics(hdcPrint, printerHandle);
    if (graphics.DrawImage(&bmp,x,y) != Ok)
        // handle error
        return false;
    }
}

if (EndPage(hdcPrint) <= 0) { // ends the page (eject paper)
    // handle error
    return false;
}

if (EndDoc(hdcPrint) <= 0) {  // end the print job (actually starts printing)
    // handle error
    return false;
}

ClosePrinter(printerHandle);
DeleteDC(hdcPrint);
delete[] lpcPrinterName;

I have done some trial and errors with these results:

  • The code runs well in Windows XP (administrator and normal user)

  • When run under Windows 7, StartDoc fails (returns -1) with GetLastError() returning 'Access is denied' error, under any user (Administrator, normal user, elevated user using run-as administrator, all fails)

  • The code runs well under Windows 7 only when:

    • run from Visual C++, either started with debugging or without debugging
    • and only when Visual C++ is run elevated (run-as administrator) or logged in as Administrator

In order to see the difference between those conditions seen from the programs's security context, I took a peek into both user and group SID's, compared them and found out that although they're run under the same user and group SID, the StartDoc still failed.

I've used Canon iP3680 in practice and bullZip PDF printer for easier code debugging which react exactly the same.

Can anyone help me find a way to get StartDoc to succeed under Windows 7? Does anyone ever experience the same or related problems?

Added:

I've also tried taking ownership of Spool/PRINTERS folder with no luck. It seems like the problem revolves around Windows 7's security. Some other printing cases I've found here manage to solve that way that's why I tried that

I forgot to add that the problem's gone when I set the printer to 'Print directly to the printer' instead of using printer spool. This hints that the problem is with the spooler.

Solved:

I was using a method of preventing my application from being killed by implementing an empty DACL, something like this:

dwErr = SetSecurityInfo(hProcess, SE_KERNEL_OBJECT, 
        DACL_SECURITY_INFORMATION, NULL/*ownerpsid*/, NULL, pEmptyDacl, NULL);

Removing that snippet clears all the problems.


回答1:


We had the same problem a few months ago in only one of our customers (over more than 15.000) using Windows 10.

After a long investigation, we discover the problem was the printer HDC obtained previously using general parameters. It worked well for all operations until we need to call StartDoc().

And the solution was to do the current StartDoc() call using the HDC we already had and, in case of error, create a new printer DC specifying the concrete pDeviceMode parameter:

newPrinterDC = CreateDC(NULL, PrinterName, NULL, pDeviceMode); 

After that, we can do the StartDoc() call again using the newPrinterDC.

This solved the problem and ran correctly in the 100% of the cases.

I hope it help you.



来源:https://stackoverflow.com/questions/20276193/my-startdoc-fails-in-windows-7-runs-well-in-windows-xp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!