Solved

Print orientation programmatically

Posted on 1998-12-09
25
662 Views
Last Modified: 2013-12-03
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.
0
Comment
Question by:Srinibhatla
  • 12
  • 7
  • 4
  • +2
25 Comments
 
LVL 15

Expert Comment

by:Tommy Hui
ID: 1416972
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
 

Author Comment

by:Srinibhatla
ID: 1416973
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
 

Expert Comment

by:plsbctv
ID: 1416974
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
 

Author Comment

by:Srinibhatla
ID: 1416975
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
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416976
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
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416977
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
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416978
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
 

Author Comment

by:Srinibhatla
ID: 1416979
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
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416980
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
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416981
Next time if you ask Q in experts-echange, please clarify what exactly you need.
0
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416982
Add ClosePrinter(hPrinter) at the end of the function.
0
 

Author Comment

by:Srinibhatla
ID: 1416983
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
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 

Author Comment

by:Srinibhatla
ID: 1416984
Just some additional info if it helps. It is a network printer
and I am using Win 95. Thanks
0
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416985
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
 

Author Comment

by:Srinibhatla
ID: 1416986
Ok, thanks for your help nick. I'll still explore it, and will post what the problem is..
0
 

Author Comment

by:Srinibhatla
ID: 1416987
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
 
LVL 2

Expert Comment

by:amitc011599
ID: 1416988
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
 

Author Comment

by:Srinibhatla
ID: 1416989
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
 

Author Comment

by:Srinibhatla
ID: 1416990
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
 
LVL 2

Expert Comment

by:amitc011599
ID: 1416991
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
 

Author Comment

by:Srinibhatla
ID: 1416992
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
 
LVL 2

Accepted Solution

by:
amitc011599 earned 100 total points
ID: 1416993
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
 

Author Comment

by:Srinibhatla
ID: 1416994
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
 
LVL 2

Expert Comment

by:amitc011599
ID: 1416995
Sure, do that.

I got it working from NT to NT.
0
 

Author Comment

by:Srinibhatla
ID: 1416996
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

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
This article surveys and compares options for encoding and decoding base64 data.  It includes source code in C++ as well as examples of how to use standard Windows API functions for these tasks. We'll look at the algorithms — how encoding and decodi…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

705 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

20 Experts available now in Live!

Get 1:1 Help Now