Partager via


How to use DEVMODE

I received a question about how to use DEVMODE. Below is some sample code that retrieves the screen’s current width/height screen resolution and rotates it for a few seconds if supported by your machine (mostly on Tablet PCs)

The user’s question continues:

The printer properties you can control start with DM_ORIENTATION and go through DM_DITHERTYPE. Each constant represents the bit in DM_FIELDS for that property, but there's a gap in the sequence between DM_SCALE and DM_COPIES. Why aren't the bits for 32, 64 and 128 used?

There is no rule saying that all values in a bitfield must be used. An API can define bit 1 to mean A, bit 4 to mean B, but bits 2 and 3 do not have to be defined. Also, APIs evolve as the OS version changes to support newer hardware/software. However, the #define’s below show that 32, 64 and 128 are used for DM_POSITION, DM_NUP, DM_DISPLAYORIENTATION

DEVMODE is defined in C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include\wingdi.h

It’s a little bit complex with some #ifdefs and macros. WINVER is 0x0501 for Windows XP

typedef struct _devicemodeA {

    BYTE dmDeviceName[CCHDEVICENAME];

    WORD dmSpecVersion;

    WORD dmDriverVersion;

    WORD dmSize;

    WORD dmDriverExtra;

    DWORD dmFields;

    union {

      /* printer only fields */

      struct {

        short dmOrientation;

        short dmPaperSize;

        short dmPaperLength;

        short dmPaperWidth;

        short dmScale;

        short dmCopies;

        short dmDefaultSource;

        short dmPrintQuality;

      };

      /* display only fields */

      struct {

        POINTL dmPosition;

        DWORD dmDisplayOrientation;

        DWORD dmDisplayFixedOutput;

      };

    };

    short dmColor;

    short dmDuplex;

    short dmYResolution;

    short dmTTOption;

    short dmCollate;

    BYTE dmFormName[CCHFORMNAME];

    WORD dmLogPixels;

    DWORD dmBitsPerPel;

    DWORD dmPelsWidth;

    DWORD dmPelsHeight;

    union {

        DWORD dmDisplayFlags;

        DWORD dmNup;

    };

    DWORD dmDisplayFrequency;

#if(WINVER >= 0x0400)

    DWORD dmICMMethod;

    DWORD dmICMIntent;

    DWORD dmMediaType;

    DWORD dmDitherType;

    DWORD dmReserved1;

    DWORD dmReserved2;

#if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400)

    DWORD dmPanningWidth;

    DWORD dmPanningHeight;

#endif

#endif /* WINVER >= 0x0400 */

} DEVMODEA, *PDEVMODEA, *NPDEVMODEA, *LPDEVMODEA;

From that same file:

/* field selection bits */

#define DM_ORIENTATION 0x00000001L

#define DM_PAPERSIZE 0x00000002L

#define DM_PAPERLENGTH 0x00000004L

#define DM_PAPERWIDTH 0x00000008L

#define DM_SCALE 0x00000010L

#if(WINVER >= 0x0500)

#define DM_POSITION 0x00000020L

#define DM_NUP 0x00000040L

#endif /* WINVER >= 0x0500 */

#if(WINVER >= 0x0501)

#define DM_DISPLAYORIENTATION 0x00000080L

#endif /* WINVER >= 0x0501 */

#define DM_COPIES 0x00000100L

#define DM_DEFAULTSOURCE 0x00000200L

#define DM_PRINTQUALITY 0x00000400L

#define DM_COLOR 0x00000800L

#define DM_DUPLEX 0x00001000L

#define DM_YRESOLUTION 0x00002000L

#define DM_TTOPTION 0x00004000L

#define DM_COLLATE 0x00008000L

#define DM_FORMNAME 0x00010000L

#define DM_LOGPIXELS 0x00020000L

#define DM_BITSPERPEL 0x00040000L

#define DM_PELSWIDTH 0x00080000L

#define DM_PELSHEIGHT 0x00100000L

#define DM_DISPLAYFLAGS 0x00200000L

#define DM_DISPLAYFREQUENCY 0x00400000L

#if(WINVER >= 0x0400)

#define DM_ICMMETHOD 0x00800000L

#define DM_ICMINTENT 0x01000000L

#define DM_MEDIATYPE 0x02000000L

#define DM_DITHERTYPE 0x04000000L

#define DM_PANNINGWIDTH 0x08000000L

#define DM_PANNINGHEIGHT 0x10000000L

#endif /* WINVER >= 0x0400 */

#if(WINVER >= 0x0501)

#define DM_DISPLAYFIXEDOUTPUT 0x20000000L

#endif /* WINVER >= 0x0501 */

Here’s the VFP code to change the screen orientation. Check out the uses of BINTOC and CTOBIN (see also Tools->Task Pane->Solution Samples->New in VFP9->BINTOC Binary Conversion and Floating Point calculations: comparing with zero). The string offsets are offsets into the DEVMODE structure. They are easy to figure out in a debugger, especially with the macros, unions and nested structures. Just put &(*(DEVMODE *)0).dmDisplayOrientation in the watch window and 0x00000034 (52 base 10) is displayed. (That says interpret the address at 0 as a DEVMODE structure and give the address of the dmDisplayOrientation member.) The SUBSTR function is 1 based, so the SUBSTR offset of dmDisplayOrientation is 53.

#define ENUM_CURRENT_SETTINGS 0xffffffff

#define ENUM_REGISTRY_SETTINGS 0xfffffffe

#define DMDO_DEFAULT 0

#define DMDO_90 1

#define DMDO_180 2

#define DMDO_270 3

#define DM_DISPLAYORIENTATION 0x00000080

CLEAR

*SetDisplay(DMDO_180)

SetDisplay(DMDO_90)

INKEY(3)

SetDisplay(DMDO_DEFAULT)

PROCEDURE SetDisplay(nOrientation as Integer)

      *sizeof(DEVMODE)=156

      cDevmode=REPLICATE(CHR(0),36)+BINTOC(156,"2sr")+REPLICATE(CHR(0),118)

      DECLARE integer EnumDisplaySettings IN WIN32API integer,integer,string @

      DECLARE integer ChangeDisplaySettings IN WIN32API string @, integer

      IF EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,@cDevmode)=0

            ?"Error"

            RETURN

      ENDIF

      nWidth=CTOBIN(SUBSTR(cDevmode,109,4),"4sr")

      nHeight=CTOBIN(SUBSTR(cDevmode,113,4),"4sr")

      ?"Screen dimensions are ",nWidth,"X",nHeight

      dmFields=CTOBIN(SUBSTR(cDevmode,41,4),"4sr")

      ?TRANSFORM(dmFields,"@0x")

      IF BITAND(dmFields,DM_DISPLAYORIENTATION)>0

            fSwap=.f.

            nDisplay = CTOBIN(SUBSTR(cDevmode,53,4),"4sr")

            ?"Current DisplayOrientation=",nDisplay

            IF nOrientation != nDisplay && if different

                  fLandscape=nWidth>nHeight

                  DO CASE

                  CASE INLIST(nOrientation,DMDO_DEFAULT,DMDO_180)

                        fSwap = !fLandscape && if it wasn't lasndscape, we need to swap x,y pixels

                  CASE INLIST(nOrientation,DMDO_90,DMDO_270)

                        fSwap = fLandscape

                  ENDCASE

                  IF fSwap

                        nTemp=nWidth

                        nWidth=nHeight

                        nHeight=nTemp

                  ENDIF

            cDevmode=LEFT(cDevmode,108)+BINTOC(nWidth,"4sr")+BINTOC(nHeight,"4sr")+SUBSTR(cDevmode,117)

                  cDevmode=LEFT(cDevmode,52)+BINTOC(nOrientation,"4sr")+SUBSTR(cDevmode,57)

                  n= ChangeDisplaySettings(@cDevmode,0)

                  IF n=0

                        ?"Success"

                  ELSE

                        ?"Failed",n

                  ENDIF

            ENDIF

      ELSE

            ?"Can't get Display Orientation"

      ENDIF

RETURN

Comments

  • Anonymous
    August 31, 2005
    Thanks for answering my question. I hadn't thought about those bits being used for some other purpose than printer properties. (Just focused too narrowly on printing at the moment.) Thanks too for pointing out BINTOC and CTOBIN. I had been using other UDFs to do that were much more cumbersome.

    See you in Phoenix!

    -BP

  • Anonymous
    August 31, 2005
    Very interesting, thanks.

    Hmm... looks like a great tool addition to VFP to increase interoperability: feed the class method a struct definition as a text string, get back an object that has the offsets built-in for getting/setting values given an initial address.

  • Anonymous
    August 31, 2005
    Hank, I've been working on something sort of like this. I have a class that accepts the constants (or value) for the property you want to change and the setting and returns the modified DEVMODE structure to you. Right now it only works for the printer properties. And I need to switch it to using the BINTOC and CTOBIN functions, but you can download a version of this now from http://www.peisch.com/downloads.html. The file is SetPrtProps.zip.

  • Anonymous
    April 17, 2006
    Input devmode is always NULL in DrvDocumentPropertySheet

  • Anonymous
    October 26, 2006
    i need to know how to get the amounth of copies of acopies of a report in order to save in a file this is done in Oracle.                                                                                                                                                                                          

  • Anonymous
    October 27, 2006
    I need to get the dm_copies from the file devmode,  how may I get it?

  • Anonymous
    October 24, 2007
    it should be: #define DMDO_270        4 // not 3 check the microsoft include files...

  • Anonymous
    May 29, 2009
    PingBack from http://paidsurveyshub.info/story.php?title=calvin-hsia-s-weblog-how-to-use-devmode