Print orientation programmatically

Manually I display the print dialog and change the orientation to Landscape mode.

I want to achieve the same without displaying the print dialog, programmatically, using WIN 32/SDK, no MFC please.
Also prefer some code which works, the MS KB article did not solve my problem.
SrinibhatlaAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

 
Tommy HuiEngineerCommented:
When you bring up the dialog, you specify a PRINTDLG structure. In this structure is a handle to a DEVMODE structure. Initialize the structure to specify landscape orientation (DMORIENT_LANDSCAPE).
0
 
SrinibhatlaAuthor Commented:
The handle to the devmode structure gets filled only after Printdlg is called. According to what you say, I need to populate it before I call it. For now I have the code..

ZeroMemory( &pDlg, sizeof( pDlg ) );
pDlg.lStructSize = (DWORD) sizeof(PRINTDLG);
pDlg.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
// now I need to set the orientation to either DMORIENT_PORTRAIT // or DMORIENT_LANDSCAPE, and I only want that setting for only // the print jobs through my app. How to do that?
PrintDlg ( &pDlg ) );
0
 
plsbctvCommented:
PrintDlg refers to a PRINTDLG structure. This structure contains a global memory handle to a DEVMODE structure. This you know.

It is not necessary to have PrintDlg create the DEVMODE structure. You may allocate memory yourself using GlobalAlloc and set that handle into the PRINTDLG structure. Fill in a DEVMODE structure in the allocated memory using the settings you wish, then call PrintDlg.

The values you place in the DEVMODE will be used to initialize the controls in the dialog box. If you set DEVMODE->dmOrientation to landscape, the dialog box will come up with landscape checked. The user may then change it.

If you don't what the user to be able to change it, then reject this answer and I'll explain that.

0
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

 
SrinibhatlaAuthor Commented:
I can set the hDevMode member of the PRINTDLG structure, but then
I lose what I really need to do. I have to print it in portrait/landscape mode, without displaying the dialog box. In order to not display the dialog box I have to set the PRINTDLG.flags = PD_RETURNDEFAULT, but for this flag to work, the hDevMode and hDevNames should be null, else PrintDlg fails.
0
 
NickRepinCommented:
PRINTDLG pdSetup;

void GetDefPrinter() {
  memset(&pdSetup, 0, sizeof(PRINTDLG));
  pdSetup.lStructSize = sizeof(PRINTDLG);
  pdSetup.Flags = PD_RETURNDEFAULT;
  PrintDlg(&pdSetup);
}

// Fill PRINTDLG struct
GetDefPrinter();

// Obtain Printer DC
LPDEVMODE dm=LPDEVMODE(GlobalLock(pdSetup.hDevMode));
LPDEVNAMES dn=LPDEVNAMES(GlobalLock(pdSetup.hDevNames));
dm->dmOrientation=DMORIENT_LANDSCAPE;
hdcPrinter=CreateDC(LPTSTR(dn)+dn->wDriverOffset,
   LPTSTR(dn)+dn->wDeviceOffset,0,dm);
GlobalUnlock(pdSetup.hDevNames);
GlobalUnlock(pdSetup.hDevMode);


0
 
NickRepinCommented:
There are some ways to do so.
I offer you to create printer DC using CreateDC.
At first, you call PrintDlg to fill PRINTDLG struct. Do not use PD_RETURNDC.
Next, change orientation in DEVMODE struct.
Now, create printer DC.

Also you may change print orientation or other setting by using SetJob() after StartDoc();


0
 
NickRepinCommented:
If you are satisfied with my answer, please give me the grade A. I've lost about half of hour to offer you the example code.
0
 
SrinibhatlaAuthor Commented:
I can't use the printer DC, so I dont want to create it.
Maybe I should explain the problem in more detail. I am printing from a 3rd party development tool.( i.e PowerBuilder PB ). I know when I print, whether I want it to be landscape mode or portrait mode. However PB does not allow me to switch the printer orientation on the fly. So I am calling a function [ ChangePrintOrientation( BOOL bPortrait )]in an external DLL in Win 32/SDK. I do the actual printing within PowerBuilder.

If I call PrintDlg( &pDlg ) within the external function I see the dialog, and can manually change the setting to LandScape, and then the document prints fine in landscape mode. So what I need to simulate inside the dll, is to change that setting to landscape/portrait depending on bPortrait without actually displaying the dialog. It would be ok to create printer dc's etc inside the dll,  as long as I delete/free them, but I cannot use them to do the actual printing. Any help would be appreciated.
0
 
NickRepinCommented:
Ok, here is the code you need.

HDC SetDefPrinterOrient(bool isprt) {
  memset(&pdSetup, 0, sizeof(PRINTDLG));
  pdSetup.lStructSize = sizeof(PRINTDLG);
  pdSetup.Flags = PD_RETURNDEFAULT;
  PrintDlg(&pdSetup);
    LPDEVMODE dm=LPDEVMODE(GlobalLock(pdSetup.hDevMode));
    LPDEVNAMES dn=LPDEVNAMES(GlobalLock(pdSetup.hDevNames));
    HANDLE hPrinter;
    PRINTER_DEFAULTS pd;
    pd.pDatatype=0;
    pd.pDevMode=dm;
    pd.DesiredAccess=PRINTER_ALL_ACCESS;
    OpenPrinter(LPTSTR(dn)+dn->wDeviceOffset,&hPrinter,&pd);
    LPPRINTER_INFO_2 pi=0;
    DWORD need;
    GetPrinter(hPrinter,2,0,0,&need);
    pi=LPPRINTER_INFO_2(new char[need]);
    GetPrinter(hPrinter,2,LPBYTE(pi),need,&need);
    pi->pDevMode->dmOrientation=isprt ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE;
    SetPrinter(hPrinter,2,LPBYTE(pi),0);
    delete[] pi;
    GlobalUnlock(HGLOBAL(pdSetup.hDevMode));
    GlobalUnlock(HGLOBAL(pdSetup.hDevNames));

}

0
 
NickRepinCommented:
Next time if you ask Q in experts-echange, please clarify what exactly you need.
0
 
NickRepinCommented:
Add ClosePrinter(hPrinter) at the end of the function.
0
 
SrinibhatlaAuthor Commented:
Hi,

I tried your code, but it does not work. I wonder if it is related to modifying the private part ( device independent )of the DEVMODE structure(?).  I even put error checks for all the functions, they all are successful but it does not print in landscape. If instead I just show the dialog from within the dll, and manually choose Landscape it prints fine. Could you point me as to where the flaw is? Btw if it matters I am using a HP5Si Laser jet printer. Thanks very much.
0
 
SrinibhatlaAuthor Commented:
Just some additional info if it helps. It is a network printer
and I am using Win 95. Thanks
0
 
NickRepinCommented:
This code works, I've tested it.
It doesn't work in your case because it seems you have not the administrative privileges to operate the printer.
I'm sorry, but I have no more time to spend for you.
0
 
SrinibhatlaAuthor Commented:
Ok, thanks for your help nick. I'll still explore it, and will post what the problem is..
0
 
SrinibhatlaAuthor Commented:
The reason it fails is because SetPrinter is not supported in Win95, when printing to a network printer using the UNC name.
Does anyone know of way to bypass this, or to achieve the same result in any other way?. Thanks a lot.
0
 
amitc011599Commented:
Did you try the API DocumentProperties() from winspool.h. It can be used to get and set a DEVMODE structure for a printer.

Change the dmOrientation member to DMORIENT_LANDSCAPE before setting.
0
 
SrinibhatlaAuthor Commented:
Hi,

Yes I did. It was succesful, but after the DEVMODE structure was modified, and I tried to reset it with SetPrinter(), the call failed but GetLastError returned 0. Here's the code I tried.

EXPORT long CALLBACK ChangePrintOrientation( bool bPortrait )
{      
      
      PRINTDLG      pdSetup;
      memset(&pdSetup, 0, sizeof(PRINTDLG));
      pdSetup.lStructSize = sizeof(PRINTDLG);
      pdSetup.Flags = PD_RETURNDEFAULT | PD_ENABLESETUPHOOK;
      pdSetup.lpfnSetupHook = PrintHookProc;
      PrintDlg(&pdSetup);
      
    LPDEVMODE dm=LPDEVMODE(GlobalLock(pdSetup.hDevMode));
    LPDEVNAMES dn=LPDEVNAMES(GlobalLock(pdSetup.hDevNames));
   
      HANDLE                        hPrinter;
    PRINTER_DEFAULTS      pd;
      LONG                        lFlag;
   
      memset(&pd, 0, sizeof(PRINTER_DEFAULTS));
      pd.pDatatype=0;
    pd.pDevMode=dm;
    pd.DesiredAccess=PRINTER_ALL_ACCESS;

    LPTSTR pName;
      pName = (LPTSTR)dn + dn->wDeviceOffset;
      
      if ( OpenPrinter(pName,&hPrinter,&pd) == 0 )
            return -1;

    LPPRINTER_INFO_2 pi = 0;
    DWORD      need;
      HANDLE hMem;

    GetPrinter(hPrinter,2,0,0,&need);
   
      hMem = GlobalAlloc( GHND, need );
      pi = LPPRINTER_INFO_2(GlobalLock( hMem ));
   
      if ( GetPrinter(hPrinter,2,LPBYTE(pi),need,&need) == 0 )
            return -2;

      if ( !pi->pDevMode->dmFields & DM_ORIENTATION )
            return -3;

      if (bPortrait)
            pi->pDevMode->dmOrientation= DMORIENT_PORTRAIT;
      else
            pi->pDevMode->dmOrientation= DMORIENT_LANDSCAPE;

      lFlag = DocumentProperties(NULL, hPrinter, LPTSTR(dn)+dn->wDeviceOffset,
                        pi->pDevMode, pi->pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER );
   
      if ( SetPrinter(hPrinter,2,LPBYTE(pi),0) == 0 )
            return -4;

      GlobalUnlock( HGLOBAL( hMem ) );
      GlobalFree( HGLOBAL( hMem ) );
      GlobalUnlock( HGLOBAL( pdSetup.hDevMode ) );
      GlobalUnlock( HGLOBAL( pdSetup.hDevNames ) );

      ClosePrinter( hPrinter );
      
      return 0;
}

Thanks for responding.
0
 
SrinibhatlaAuthor Commented:
Oops, Please ignore the above code in message. I posted some different code by 'cut & paste' the wrong code. Some of the code esp. the part about the DocumentProperties is valid. This code was a result of my frustration with the problem that I was trying some 'new' stuff to make it work.
0
 
amitc011599Commented:
Sorry Srini,

After trying for some 3/4 hours, even I just gave up. DocumentProperties does not work. I did find a few things, here they are just incase it helps.

1. The flag DM_OUT_DEFAULT or DM_UPDATE should be specified as mode, if the setting are to be done for the printer and not just the current application.

2. There is a article in the MS KB(Microsoft KnowledgeBase) numbered Q112641 which talks about a sample to change orientation. This sample just hung when I tried it. But maybe it will work for you.

That's all then. Do tell me if you get it to work.

Regards



0
 
SrinibhatlaAuthor Commented:
Hi Amit,

Sorry it took me a long while to reply here. I still havent found a solution, so for now am displaying the Dialog to the users, and letting them pick the setting. One day when I find the solution, I'll definitely post it here. :-)

Thanks for your time and effort - Srini
0
 
amitc011599Commented:
Srinibhatla,

If you increase the points, I will answer it. Cause finally I found the answer. :))
Actually is how it is done,
1. Open a printer will PRINTER_ALL_ACCESS access.
2. Get the PRINTER_INFO_2 structure using GetPrinter at level 2.
3. The stucture has a pDevMode structure, Change the orientation field to 1(Potrait) or 2 (Landscape)
4. Call SetPrinter with this modified structure and it works. That simple.

Nothing to do with DocumentProperties at all.

I am upload the code, if required. Will need to clean it up.

0

Experts Exchange Solution brought to you by ConnectWise

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
 
SrinibhatlaAuthor Commented:
Hi Amit,

Sorry took so long to respond. I've not been checking here lately.  Your answer is similar to Nick Repin's answer, and I had already tried it, but it didnt work for me. Did you try to print from Win 95 to a network printer ? Thats when it failed for me. Let me know if you did it and it worked. Anyways this is getting to be a old question and I plan on closing it soon.

Thanks
0
 
amitc011599Commented:
Sure, do that.

I got it working from NT to NT.
0
 
SrinibhatlaAuthor Commented:
I got it working on NT to NT too, needed it to work from 95 to NT. If you have access to a 95 machine ( thats why my comments above about how SetPrinter does not seem to work in Win 95 ), can you try it?

Thanks.
0
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.