Select Printer Programmatically Problem


I would like to programtically change the printer i print to.  The way i was going to do this was simple by changing the default printer for the application before calling the print operation.  Eventually i want to allow my users to do this through automation but i am just testing it out now.  After reading stuff on the internet and here i decided that this was the best implementation.

the code for it is below.  I Get a problem at this point towards the bottom;
"// set the new hDevMode and hDevNames
    *phDevMode = hDevMode;
    *phDevNames = hDevNames;
    return TRUE;
The error message returned is "Unhandled exception at 0x0040f714 in MyApp.exe: 0xC0000005: Access violation writing location 0x0040515c."

I have no idea why it is doing this please help.

BOOL MyApp::ChangePrinter()
      BOOL ret = TRUE;
      LPTSTR str = _T("Acrobat Distiller");
      ret = GetPrinterDevice(str,&m_hDevNames,&m_hDevMode);

BOOL MyApp::GetPrinterDevice(LPTSTR pszPrinterName, HGLOBAL* phDevNames, HGLOBAL* phDevMode)
    // if NULL is passed, then assume we are setting app object's
    // devmode and devnames
    if (phDevMode == NULL || phDevNames == NULL)
        return FALSE;

    // Open printer
    HANDLE hPrinter;
    if (OpenPrinter(pszPrinterName, &hPrinter, NULL) == FALSE)
        return FALSE;

    // obtain PRINTER_INFO_2 structure and close printer
    DWORD dwBytesReturned, dwBytesNeeded;
    GetPrinter(hPrinter, 2, NULL, 0, &dwBytesNeeded);
    PRINTER_INFO_2* p2 = (PRINTER_INFO_2*)GlobalAlloc(GPTR,
    if (GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded,
       &dwBytesReturned) == 0) {
       return FALSE;

    // Allocate a global handle for DEVMODE
    HGLOBAL  hDevMode = GlobalAlloc(GHND, sizeof(*p2->pDevMode) +
    DEVMODE* pDevMode = (DEVMODE*)GlobalLock(hDevMode);

    // copy DEVMODE data from PRINTER_INFO_2::pDevMode
    memcpy(pDevMode, p2->pDevMode, sizeof(*p2->pDevMode) +

    // Compute size of DEVNAMES structure from PRINTER_INFO_2's data
    DWORD drvNameLen = lstrlen(p2->pDriverName)+1;  // driver name
    DWORD ptrNameLen = lstrlen(p2->pPrinterName)+1; // printer name
    DWORD porNameLen = lstrlen(p2->pPortName)+1;    // port name

    // Allocate a global handle big enough to hold DEVNAMES.
    HGLOBAL hDevNames = GlobalAlloc(GHND,
        sizeof(DEVNAMES) +
        (drvNameLen + ptrNameLen + porNameLen)*sizeof(TCHAR));
    DEVNAMES* pDevNames = (DEVNAMES*)GlobalLock(hDevNames);

    // Copy the DEVNAMES information from PRINTER_INFO_2
    // tcOffset = TCHAR Offset into structure
    int tcOffset = sizeof(DEVNAMES)/sizeof(TCHAR);
    ASSERT(sizeof(DEVNAMES) == tcOffset*sizeof(TCHAR));

    pDevNames->wDriverOffset = tcOffset;
    memcpy((LPTSTR)pDevNames + tcOffset, p2->pDriverName,
    tcOffset += drvNameLen;

    pDevNames->wDeviceOffset = tcOffset;
    memcpy((LPTSTR)pDevNames + tcOffset, p2->pPrinterName,
    tcOffset += ptrNameLen;

    pDevNames->wOutputOffset = tcOffset;
    memcpy((LPTSTR)pDevNames + tcOffset, p2->pPortName,
    pDevNames->wDefault = 0;

    GlobalFree(p2);   // free PRINTER_INFO_2

    // set the new hDevMode and hDevNames
   //problem happens on these next two lines of code
    *phDevMode = hDevMode;
    *phDevNames = hDevNames;
    return TRUE;
Who is Participating?
How you are passing parameters to  GetPrinterDevice() function ?

It should be like :

 HANDLE m_hDevMode;
 HANDLE m_hDevNames;

GetPrinterDevice(_T("HP LaserJet III"), &m_hDevNames, &m_hDevMode);


Correct usage is shown on following KB article. follow this :

How to modify the "default" printer for your Microsoft Foundation Classes (MFC) application to be other than the actual system-defined default printer : <=====================

The most likely reason for that error is that, during the preceding code, the on-stack values of one or more of the pointer variables has been inadvertantly modified.  To test that, place a breakpoint on the first line of the GetPrinterDevice function.  At that point, examine and write down that values of the two pointer variables.  Single-step the function and see where the values get overwritten.  It's probably during one of the memcpy calls.

-- Dan
 So how you solved your problem ? above kb article helped you ??

Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

wdhoughAuthor Commented:
Yeah the above article solved it, i was using that approach all along i just couldnt get it to work and its because i was passing the wrong HANDLE objects.

Hope this helps

well then if it solved with above then why grade 'B' for ?
wdhoughAuthor Commented:
sorry i am new to the site, the code supplied didnt completely solve the problem but rather showed me the error so i had to find some other HANLDE objects in my application and pass them.  Anyway b said "Very good" i think which i though your answer was.  does a b grade mean something else then?
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.