Solved

Select Printer Programmatically Problem

Posted on 2006-11-10
6
788 Views
Last Modified: 2013-11-20
Hello.

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.

http://support.microsoft.com/kb/166129

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,
        dwBytesNeeded);
    if (GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded,
       &dwBytesReturned) == 0) {
       GlobalFree(p2);
       ClosePrinter(hPrinter);
       return FALSE;
    }
    ClosePrinter(hPrinter);

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

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

    // 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));
    ASSERT(hDevNames);
    DEVNAMES* pDevNames = (DEVNAMES*)GlobalLock(hDevNames);
    ASSERT(pDevNames);

    // 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,
        drvNameLen*sizeof(TCHAR));
    tcOffset += drvNameLen;

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

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

    GlobalUnlock(hDevNames);
    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;
}
0
Comment
Question by:wdhough
  • 3
  • 2
6 Comments
 
LVL 22

Accepted Solution

by:
mahesh1402 earned 500 total points
ID: 17916053
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 :
http://support.microsoft.com/kb/193103 <=====================

-MAHESH
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 17918833
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
0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 17925104
wdhough,
 So how you solved your problem ? above kb article helped you ??

-MAHESH
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:wdhough
ID: 17928609
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

Will
0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 17928874
well then if it solved with above then why grade 'B' for ?
0
 

Author Comment

by:wdhough
ID: 17928929
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?
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now