diff --git a/CHANGES.md b/CHANGES.md
index 349702b4eb..7b1f958f27 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -7,6 +7,7 @@ Next Release (5.12.0)
 
 Features
 --------
+* [#1429](https://github.com/java-native-access/jna/pull/1429): Add missing `Winspool.PRINTER_INFO_X` structs [@tresf](https://github.com/tresf).
 
 Bug Fixes
 ---------
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/User32.java b/contrib/platform/src/com/sun/jna/platform/win32/User32.java
index a1e43aada1..85416bbc4e 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/User32.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/User32.java
@@ -1857,6 +1857,35 @@ HWND CreateWindowEx(int dwExStyle, String lpClassName,
      */
     BOOL EnumDisplayMonitors(HDC hdc, RECT lprcClip, MONITORENUMPROC lpfnEnum, LPARAM dwData);
 
+    /**
+     * retrieves information about one of the graphics modes for a display device. To retrieve information for
+     * all the graphics modes of a display device, make a series of calls to this function.
+     *
+     * @param lpszDeviceName A pointer to a null-terminated string that specifies the display device about
+     *        whose graphics mode the function will obtain information. This parameter is either NULL or a
+     *        DISPLAY_DEVICE.DeviceName returned from EnumDisplayDevices. A NULL value specifies the current
+     *        display device on the computer on which the calling thread is running.
+     *
+     * @param iModeNum Graphics mode indexes start at zero. To obtain information for all of a display device's
+     *        graphics modes, make a series of calls to EnumDisplaySettings, as follows: Set iModeNum to zero
+     *        for the first call, and increment iModeNum by one for each subsequent call. Continue calling the
+     *        function until the return value is zero.
+     *        When you call EnumDisplaySettings with iModeNum set to zero, the operating system initializes and
+     *        caches information about the display device. When you call EnumDisplaySettings with iModeNum set
+     *        to a nonzero value, the function returns the information that was cached the last time the function
+     *        was called with iModeNum set to zero.
+     *
+     * @param lpDevMode A pointer to a DEVMODE structure into which the function stores information about the
+     *        specified graphics mode. Before calling EnumDisplaySettings, set the dmSize member to
+     *        sizeof(DEVMODE), and set the dmDriverExtra member to indicate the size, in bytes, of the additional
+     *        space available to receive private driver data.
+     *
+     * @return If the function succeeds, the return value is nonzero. If the function fails, the return value
+     *        is zero.
+     * @see <a href="https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaysettingsa">MSDN</a>
+     */
+    BOOL EnumDisplaySettings(String lpszDeviceName, int iModeNum, Pointer lpDevMode);
+
     /**
      * Retrieves the show state and the restored, minimized, and maximized
      * positions of the specified window.
@@ -2437,7 +2466,7 @@ HANDLE SetWinEventHook(int eventMin, int eventMax, HMODULE hmodWinEventProc, Win
      *         duplicate icon. <br>
      *         If the function fails, the return value is NULL. To get extended
      *         error information, call GetLastError.
-     * @see <a href="https://msdn.microsoft.com/en-us/library/ms648058(S.85).aspx">MSDN</a>
+     * @see <a href="https://msdn.microsoft.com/en-us/library/ms648058(S.85).aspx">MSDN</a>*
      */
     HICON CopyIcon(HICON hIcon);
 
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinGDI.java b/contrib/platform/src/com/sun/jna/platform/win32/WinGDI.java
index 671e6f49ca..a12b540aa4 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/WinGDI.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WinGDI.java
@@ -23,23 +23,481 @@
  */
 package com.sun.jna.platform.win32;
 
-import com.sun.jna.NativeLong;
-import com.sun.jna.Pointer;
-import com.sun.jna.Structure;
+import com.sun.jna.*;
 import com.sun.jna.Structure.FieldOrder;
 import com.sun.jna.platform.win32.WinNT.HANDLE;
-import com.sun.jna.platform.win32.WinDef.HBITMAP;
-import com.sun.jna.platform.win32.WinDef.RECT;
+
+import static com.sun.jna.platform.win32.WinDef.*;
+import java.nio.charset.StandardCharsets;
 
 /**
  * Ported from WinGDI.h.
  * Microsoft Windows SDK 6.0A.
  * @author dblock[at]dblock.org
  * @author Andreas "PAX" L&uuml;ck, onkelpax-git[at]yahoo.de
+ * @author SSHTOOLS Limited, support@sshtools.com
  */
 public interface WinGDI {
     int RDH_RECTANGLES = 1;
 
+    int DM_ORIENTATION = 0x00000001;
+    int DM_PAPERSIZE = 0x00000002;
+    int DM_PAPERLENGTH = 0x00000004;
+    int DM_PAPERWIDTH = 0x00000008;
+    int DM_SCALE = 0x00000010;
+    int DM_POSITION = 0x00000020;
+    int DM_NUP = 0x00000040;
+    int DM_DISPLAYORIENTATION = 0x00000080;
+    int DM_COPIES = 0x00000100;
+    int DM_DEFAULTSOURCE = 0x00000200;
+    int DM_PRINTQUALITY = 0x00000400;
+    int DM_COLOR = 0x00000800;
+    int DM_DUPLEX = 0x00001000;
+    int DM_YRESOLUTION = 0x00002000;
+    int DM_TTOPTION = 0x00004000;
+    int DM_COLLATE = 0x00008000;
+    int DM_FORMNAME = 0x00010000;
+    int DM_LOGPIXELS = 0x00020000;
+    int DM_BITSPERPEL = 0x00040000;
+    int DM_PELSWIDTH = 0x00080000;
+    int DM_PELSHEIGHT = 0x00100000;
+    int DM_DISPLAYFLAGS = 0x00200000;
+    int DM_DISPLAYFREQUENCY = 0x00400000;
+    int DM_ICMMETHOD = 0x00800000;
+    int DM_ICMINTENT = 0x01000000;
+    int DM_MEDIATYPE = 0x02000000;
+    int DM_DITHERTYPE = 0x04000000;
+    int DM_PANNINGWIDTH = 0x08000000;
+    int DM_PANNINGHEIGHT = 0x10000000;
+    int DM_DISPLAYFIXEDOUTPUT = 0x20000000;
+
+    @FieldOrder({ "dmDeviceName", "dmSpecVersion", "dmDriverVersion", "dmSize", "dmDriverExtra", "dmFields", "dmUnion1", "dmColor",
+            "dmDuplex", "dmYResolution", "dmTTOption", "dmCollate", "dmFormName", "dmLogPixels", "dmBitsPerPel", "dmPelsWidth",
+            "dmPelsHeight", "dummyunionname2", "dmDisplayFrequency", "dmICMMethod", "dmICMIntent", "dmMediaType", "dmDitherType",
+            "dmReserved1", "dmReserved2", "dmPanningWidth", "dmPanningHeight" })
+    /**
+     * The size of the "public" <code>DEVMODE</code> data can vary for different versions of the structure.
+     * <p>
+     * - The <code>dmSize</code> member specifies the number of bytes of "public" data
+     * - The <code>dmDriverExtra</code> member specifies the number of bytes of "private" data.
+     *
+     * A device driver's "private" data follows the public portion of the <code>DEVMODE</code> structure.
+     *
+     * @see <a href=
+     *      "https://docs.microsoft.com/ewindows/win32/api/wingdi/ns-wingdi-devmodew">
+     * DEVMODEW structure</a>
+     */
+    public static class DEVMODE extends Structure {
+        public static class ByReference extends DEVMODE implements Structure.ByReference {}
+        private static final int CHAR_WIDTH = Boolean.getBoolean("w32.ascii") ? 1 : 2;
+        private static final int DUMMYSTRUCTNAME_MASK = DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH
+                | DM_SCALE | DM_COPIES | DM_DEFAULTSOURCE | DM_PRINTQUALITY;
+        private static final int DUMMYSTRUCTNAME2_MASK = DM_POSITION | DM_DISPLAYORIENTATION | DM_DISPLAYFIXEDOUTPUT;
+
+        @Override
+        public void read() {
+            super.read();
+            if ((dmFields & DUMMYSTRUCTNAME_MASK) > 0) {
+                dmUnion1.setType(DUMMYUNIONNAME.DUMMYSTRUCTNAME.class);
+                dmUnion1.read();
+            } else if ((dmFields & DUMMYSTRUCTNAME2_MASK) > 0) {
+                dmUnion1.setType(DUMMYUNIONNAME.DUMMYSTRUCTNAME2.class);
+                dmUnion1.read();
+            } else if ((dmFields & DM_POSITION) > 0) {
+                dmUnion1.setType(POINT.class);
+                dmUnion1.read();
+            }
+        }
+
+        /**
+         * A zero-terminated character array that specifies the "friendly" name of the printer or display
+         * <p>
+         * For a printer: "PCL/HP LaserJet" in the case of PCL/HP LaserJet.
+         *
+         * For a display: "perm3dd" in the case of the 3Dlabs Permedia3 display driver.
+         *
+         * This string is unique among device driverers.  Note that this name may be truncated to fit in the
+         * <code>dmDeviceName</code> array.
+         */
+        public byte[] dmDeviceName = new byte[Winspool.CCHDEVICENAME * CHAR_WIDTH];
+
+        /**
+         * The version number of the initialization data specification on which the structure is based. To ensure the
+         * correct version is used for any operating system, use <code>DM_SPECVERSION</code> constant in <code>wingdi.h</code>
+         */
+        public short dmSpecVersion;
+
+        /**
+         * For a printer: Specifies the printer driver version number assigned by the printer driver developer.
+         *
+         * For a display: Drivers can set this member to <code>DM_SPECVERSION</code> constant in <code>wingdi.h</code>.
+         */
+        public short dmDriverVersion;
+
+        /**
+         * Specifies the size in bytes of the public <code>DEVMODE</code> structure, not including any private
+         * driver-specified members identified by the <code>dmDriverExtra</code> member.
+         */
+        public short dmSize;
+
+        /**
+         * Contains the number of bytes of private driver-data that follow this structure. If a device driver
+         * does not use device-specific information, set this member to zero.
+         *
+         * Since the size and format of this data is driver-specific, applications needing it
+         * must read the data into a separate one-off struct to match.
+         */
+        public short dmDriverExtra;
+
+        /**
+         * Specifies bit flags identifying which of the following <code>DEVMODE</code> members are in use.
+         *
+         * For example, the <code>DM_ORIENTATION</<code> flag is set when the <code>dmOrientation</code> member
+         * contains valid data. The <code>DM_XXX</code> flags are defined in <code>wingdi.h.</code>
+         */
+        public int dmFields;
+
+        public DUMMYUNIONNAME dmUnion1;
+
+        /**
+         * For printers: Specifies whether a color printer should print color or monochrome. This member can be one of
+         * <code>DMCOLOR_COLOR</code> or <code>DMCOLOR_MONOCHROME</code>.
+         *
+         * For displays: This member is not used for displays.
+         */
+        public short dmColor;
+
+        /**
+         * For printers: Specifies duplex (double-sided) printing for duplex-capable printers. This member can be
+         * <code>DMCOLOR_COLOR</code> or <code>DMCOLOR_MONOCHROME</code>.
+         *
+         * For displays: This member is not used for displays.
+         */
+        public short dmDuplex;
+
+        /**
+         * For printers: Specifies the y resolution of the printer, in DPI. If this member is used, the
+         * <code>dmPrintQuality</code> member specifies the x resolution.
+         *
+         * For displays: This member is not used for displays.
+         */
+        public short dmYResolution;
+
+        /**
+         * For printers: Specifies how TrueType fonts should be printed. This member must be one of the
+         * <code>DMTT_XXX</code> constants defined in <code>wingdi.h</code>.
+         *
+         * For displays: This member is not used for displays.
+         */
+        public short dmTTOption;
+
+        /**
+         * For printers: Specifies whether multiple copies should be collated. This member can be one of
+         * <code>DMCOLLATE_TRUE</code>, <code>DMCOLLATE_FALSE</code>.
+         *
+         * For displays: This member is not used for displays.
+         */
+        public short dmCollate;
+
+        /**
+         * For printers: Specifies the name of the form to use; such as "Letter" or "Legal". This must be a name that
+         * can be obtained by calling the Win32 <code>EnumForms</code> function (described in the Microsoft Window SDK
+         * documentation).
+         *
+         * For displays: This member is not used for displays.
+         */
+        public byte[] dmFormName = new byte[Winspool.CCHFORMNAME * CHAR_WIDTH];
+
+        /**
+         * For displays: Specifies the number of logical pixels per inch of a display device and should be equal to the
+         * <code>ulLogPixels</code> member of the <code>GDIINFO</code> structure.
+         *
+         * For printers: This member is not used for printers.
+         */
+        public short dmLogPixels;
+
+        /**
+         * For displays: Specifies the color resolution, in bits per pixel, of a display device.
+         *
+         * For printers: This member is not used for printers.
+         */
+        public int dmBitsPerPel;
+
+        /**
+         * For displays: Specifies the width, in pixels, of the visible device surface.
+         *
+         * For printers: This member is not used for printers.
+         */
+        public int dmPelsWidth;
+
+        /**
+         * For displays: Specifies the height, in pixels, of the visible device surface.
+         *
+         * For printers: This member is not used for printers.
+         */
+        public int dmPelsHeight;
+
+        public DUMMYUNIONNAME2 dummyunionname2;
+
+        /**
+         * For displays: Specifies the frequency, in hertz (cycles per second), of the display device in a particular
+         * mode. This value is also known as the display device's vertical refresh rate. Display drivers use this
+         * member. It is used, for example, in the <code>ChangeDisplaySettings</code> function.
+         *
+         * When you call the <code>EnumDisplaySettings</code> function, the <code>dmDisplayFrequency</code> member may
+         * return with the value 0 or 1. These values represent the display hardware's default refresh rate. This
+         * default rate is typically set by switches on a display card or computer motherboard, or by a configuration
+         * program that does not use display functions such as <code>ChangeDisplaySettings</code>.
+         *
+         * For printers: This member is not used for printers.
+         */
+        public int dmDisplayFrequency;
+
+        /**
+         * For printers: Specifies how ICM (image color management) is handled. For a non-ICM application, this member determines
+         * if ICM is enabled or disabled. For ICM applications, the system examines this member to determine how to
+         * handle ICM support. This member can be one of the predefined <code>DMICMMETHOD_XXX</code>values, or a driver-defined value
+         * greater than or equal to the value of <code>DMICMMETHOD_USER</code>.
+         *
+         * The printer driver must provide a user interface for setting this member. Most printer drivers support only
+         * the <code>DMICMMETHOD_SYSTEM</code> or <code>DMICMMETHOD_NONE</code> value. Drivers for PostScript printers
+         * support all <code>DCMICMMETHOD_XXX</code>values.
+         *
+         * For displays: This member is not used for displays.
+         */
+        public int dmICMMethod;
+
+        /**
+         * For printers: Specifies which color matching method, or intent, should be used by default. This member is primarily for
+         * non-ICM applications. ICM applications can establish intents by using the ICM functions. This member can be
+         * one of the following predefined values, or a driver defined value greater than or equal to the value of
+         * <code>DMICM_USER</code>.
+         *
+         * For displays: This member is not used for displays.
+         */
+        public int dmICMIntent;
+
+        /**
+         * For printers: Specifies the type of media being printed on. The member can be one of the predefined
+         * <code>DMMEDIA_XXX</code> values, or a driver-defined value greater than or equal to the value of <code>DMMEDIA_USER</code>.
+         *
+         * To retrieve a list of the available media types for a printer, use the <code>DeviceCapabilities</code>
+         * function with the <code>DC_MEDIATYPES</code> flag.
+         *
+         * For displays: This member is not used for displays.
+         */
+        public int dmMediaType;
+
+        /**
+         * For printers: Specifies how dithering is to be done. The member can be one of the predefined
+         * <code>DMDITHER_XXX</code> values, or a driver-defined value greater than or equal to the value of
+         * <code>DMDITHER_USER</code>.
+         *
+         * For displays: This member is not used for displays.
+         */
+        public int dmDitherType;
+
+        /**
+         * Not used; must be zero.
+         */
+        public int dmReserved1;
+
+        /**
+         * Not used; must be zero.
+         */
+        public int dmReserved2;
+
+        /**
+         * This member must be zero.
+         */
+        public int dmPanningWidth;
+
+        /**
+         * This member must be zero.
+         */
+        public int dmPanningHeight;
+
+        /**
+         * Converts dmDeviceName from raw byte[] to String
+         */
+        public String getDmDeviceName() {
+            long offset = fieldOffset("dmDeviceName");
+            if(CHAR_WIDTH == 1) {
+                //todo: this can overrun if there is no null, perhaps we should add overrun protection to getString
+                return this.getPointer().getString(offset);
+            } else {
+                return this.getPointer().getWideString(offset);
+            }
+        }
+
+        /**
+         * Converts dmFormName from raw byte[] to String
+         */
+        public String getDmFormName() {
+            long offset = fieldOffset("dmFormName");
+            if(CHAR_WIDTH == 1) {
+                return this.getPointer().getString(offset);
+            } else {
+                return this.getPointer().getWideString(offset);
+            }
+        }
+
+        public static class DUMMYUNIONNAME extends Union {
+            public DUMMYSTRUCTNAME dummystructname;
+            public POINT dmPosition;
+            public DUMMYSTRUCTNAME2 dummystructname2;
+
+            @FieldOrder({ "dmOrientation", "dmPaperSize", "dmPaperLength", "dmPaperWidth", "dmScale", "dmCopies", "dmDefaultSource",
+                    "dmPrintQuality" })
+            public static class DUMMYSTRUCTNAME extends Structure {
+                /**
+                 * For printers: Specifies the paper orientation. This member can be either DMORIENT_PORTRAIT or DMORIENT_LANDSCAPE.
+                 *
+                 * For displays: This member is not used for displays.
+                 */
+                public short dmOrientation;
+
+                /**
+                 * For printers, specifies the size of the paper to be printed on. This member must be zero if the
+                 * length and width of the paper are specified by the dmPaperLength and
+                 * <code>dmPaperWidth</code> members. Otherwise, the <code>dmPaperSize</code> member must be one of the
+                 * <code>DMPAPER_XXX</code> constants defined in <code>wingdi.h</code>.
+                 *
+                 * For displays: This member is not used for displays.
+                 */
+                public short dmPaperSize;
+
+                /**
+                 * For printers: Specifies the length of the paper, in units of 1/10 of a millimeter. This value
+                 * overrides the length of the paper specified by the <code>dmPaperSize</code> member, and is used if
+                 * the paper is of a custom size, or if the device is a dot matrix printer, which can print a page of
+                 * arbitrary length.
+                 *
+                 * For displays: This member is not used for displays.
+                 */
+                public short dmPaperLength;
+
+                /**
+                 * For printers: Specifies the width of the paper, in units of 1/10 of a millimeter. This value
+                 * overrides the width of the paper specified by the <code>dmPaperSize</code> member. This member must
+                 * be used if <code>dmPaperLength</code> is used.
+                 *
+                 * For displays: This member is not used for displays.
+                 */
+                public short dmPaperWidth;
+
+                /**
+                 * For printers: Specifies the percentage by which the image is to be scaled for printing.
+                 * The image's page size is scaled to the physical page by a factor of <code>dmScale</code>/100.
+                 *
+                 * For example, a 17-inch by 22-inch image with a scale value of 100 requires 17x22-inch paper, while
+                 * the same image with a scale value of 50 should print as half-sized and fit on letter-sized paper.
+                 *
+                 * For displays: This member is not used for displays.
+                 */
+                public short dmScale;
+
+                /**
+                 * For printers: Specifies the number of copies to be printed, if the device supports multiple copies.
+                 *
+                 * For displays: This member is not used for displays.
+                 */
+                public short dmCopies;
+
+                /**
+                 * For printers: Specifies the printer's default input bin (paper source). This must be one of the
+                 * <code>DMBIN_XXX</code> constants defined in <code>wingdi.h</code>. If the specified constant is
+                 * <code>DMBIN_FORMSOURCE</code>, the input bin should be selected automatically.
+                 *
+                 * To retrieve a list of the available paper sources for a printer, use the
+                 * <code>DeviceCapabilities</code> function with the <code>DC_BINS</code> flag.
+                 *
+                 * This member can be one of the <code>DMBIN_XXX</code>> values, or it can be a device-specific value greater than or
+                 * equal to <code>DMBIN_USER</code>.
+                 *
+                 * For displays: This member is not used for displays.
+                 */
+                public short dmDefaultSource;
+
+                /**
+                 * For printers: Specifies the printer resolution. The following negative constant values are defined in
+                 * <code>wingdi.h</code>:
+                 *
+                 * <code>DMRES_HIGH</code>
+                 * <code>DMRES_MEDIUM</code>
+                 * <code>DMRES_LOW</code>
+                 * <code>DMRES_DRAFT</code>
+                 *
+                 * For displays: This member is not used for displays.
+                 */
+                public short dmPrintQuality;
+            }
+
+            @FieldOrder({ "dmPosition", "dmDisplayOrientation", "dmDisplayFixedOutput" })
+            public static class DUMMYSTRUCTNAME2 extends Structure {
+
+                /**
+                 * For displays: Specifies a <code>POINTL</code> structure containing the x- and y-coordinates of
+                 * upper-left corner of the display, in desktop coordinates. This member is used to determine the
+                 * relative position of monitors in a multiple monitor environment.
+                 *
+                 * For printers: This member is not used for printers.
+                 *
+                 * Note: This member is defined only for Windows XP and later.
+                 */
+                public POINT dmPosition;
+
+                /**
+                 * For displays: Specifies the orientation at which images should be presented. When the
+                 * <code>DM_DISPLAYORIENTATION</code> bit is not set in the <code>dmFields</code> member, this member
+                 * must be set to zero. When the <code>DM_DISPLAYORIENTATION</code> bit is set in the
+                 * <code>dmFields</code> member, this member must be set to one of the <code>DMDO_XXX</code> values
+                 *
+                 * For printers: This member is not used for printers.
+                 *
+                 * Note: This member is defined only for Windows XP and later.
+                 */
+                public int dmDisplayOrientation;
+
+                /**
+                 * For displays: For fixed-resolution displays, specifies how the device can present a lower-resolution
+                 * mode on a higher-resolution display. For example, if a display device's resolution is fixed at
+                 * <code>1024 X 768</code>, and its mode is set to <code>640 x 480</code>, the device can either
+                 * display a <code>640 X 480</code> image within the <code>1024 X 768</code> screen space, or stretch
+                 * the <code>640 X 480</code> image to fill the larger screen space.
+                 *
+                 * When the <code>DM_DISPLAYFIXEDOUTPUT</code> bit is not set in the <code>dmFields</code> member,
+                 * this member must be set to zero. When the <code>DM_DISPLAYFIXEDOUTPUT</code> bit is set in the
+                 * <code>dmFields</code> member, this member must be set to one of the <code>DMDFO_XXX</code> values.
+                 *
+                 * For printers: This member is not used for printers.
+                 *
+                 * Note: This member is defined only for Windows XP and later.
+                 */
+                public int dmDisplayFixedOutput;
+            }
+        }
+
+        public static class DUMMYUNIONNAME2 extends Union {
+            /**
+             * For displays: Specifies a display device's display mode. This member can be
+             * <code>DM_GRAYSCALE</code>, <code>DM_INTERLACED</code> or <code>DMDISPLAYFLAGS_TEXTMODE</code>,
+             * however values other than <code>DM_INTERLACED</code> are invalid for newer systems.
+             *
+             * For printers: This member is not used for printers.
+             */
+            public int dmDisplayFlags;
+
+            /**
+             * For printers: Specifies where the N-UP (pages per sheet) is done. It can be <code>DMNUP_SYSTEM</code> or
+             * <code>DMNUP_ONEUP</code> being controlled by the spooler or the application, respectively.
+             *
+             * For displays: This member is not used for displays.
+             */
+            public int dmNup;
+        }
+    }
+
     @FieldOrder({"dwSize", "iType", "nCount", "nRgnSize", "rcBound"})
     class RGNDATAHEADER extends Structure {
         public int dwSize = size();
@@ -65,6 +523,163 @@ public RGNDATA(int bufferSize) {
 
     HANDLE HGDI_ERROR = new HANDLE(Pointer.createConstant(0xFFFFFFFF));
 
+    int DMCOLOR_MONOCHROME = 1;
+    int DMCOLOR_COLOR = 2;
+
+    /* TrueType options */
+    /** print TT fonts as graphics **/
+    int DMTT_BITMAP = 1;
+    /** download TT fonts as soft fonts **/
+    int DMTT_DOWNLOAD = 2;
+    /** substitute device fonts for TT fonts **/
+    int DMTT_SUBDEV = 3;
+    /** download TT fonts as outline soft fonts **/
+    int DMTT_DOWNLOAD_OUTLINE = 4;
+
+
+    int DMORIENT_PORTRAIT = 1;
+    int DMORIENT_LANDSCAPE = 2;
+
+    /* device capabilities indices */
+    int DC_FIELDS =1;
+    int DC_PAPERS = 2;
+    int DC_PAPERSIZE = 3;
+    int DC_MINEXTENT = 4;
+    int DC_MAXEXTENT = 5;
+    int DC_BINS = 6;
+    int DC_DUPLEX = 7;
+    int DC_SIZE = 8;
+    int DC_EXTRA = 9;
+    int DC_VERSION = 10;
+    int DC_DRIVER = 11;
+    int DC_BINNAMES = 12;
+    int DC_ENUMRESOLUTIONS = 13;
+    int DC_FILEDEPENDENCIES = 14;
+    int DC_TRUETYPE = 15;
+    int DC_PAPERNAMES = 16;
+    int DC_ORIENTATION = 17;
+    int DC_COPIES = 18;
+    int DC_BINADJUST = 19;
+    int DC_EMF_COMPLIANT = 20;
+    int DC_DATATYPE_PRODUCED = 21;
+    int DC_COLLATE = 22;
+    int DC_MANUFACTURER = 23;
+    int DC_MODEL = 24;
+    int DC_PERSONALITY = 25;
+    int DC_PRINTRATE = 26;
+    int DC_PRINTRATEUNIT = 27;
+    int PRINTRATEUNIT_PPM = 1;
+    int PRINTRATEUNIT_CPS = 2;
+    int PRINTRATEUNIT_LPM = 3;
+    int PRINTRATEUNIT_IPM = 4;
+    int DC_PRINTERMEM = 28;
+    int DC_MEDIAREADY = 29;
+    int DC_STAPLE = 30;
+    int DC_PRINTRATEPPM = 31;
+    int DC_COLORDEVICE = 32;
+    int DC_NUP = 33;
+    int DC_MEDIATYPENAMES = 34;
+    int DC_MEDIATYPES = 35;
+
+    /* print qualities */
+    int DMRES_DRAFT = -1;
+    int DMRES_LOW = -2;
+    int DMRES_MEDIUM = -3;
+    int DMRES_HIGH = -4;
+
+    /* bin selections */
+    int DMBIN_UPPER = 0x0001;
+    int DMBIN_LOWER = 0x0002;
+    int DMBIN_MIDDLE = 0x0003;
+    int DMBIN_MANUAL = 0x0004;
+    int DMBIN_ENVELOPE = 0x0005;
+    int DMBIN_ENVMANUAL = 0x0006;
+    int DMBIN_AUTO = 0x0007;
+    int DMBIN_TRACTOR = 0x0008;
+    int DMBIN_SMALLFMT = 0x0009;
+    int DMBIN_LARGEFMT = 0x000A;
+    int DMBIN_LARGECAPACITY = 0x000B;
+    int DMBIN_CASSETTE = 0x000E;
+    int DMBIN_FORMSOURCE = 0x000F;
+
+    /* DEVMODE dmDisplayOrientation specifiations */
+    int DMDO_DEFAULT = 0;
+    int DMDO_90 = 1;
+    int DMDO_180 = 2;
+    int DMDO_270 = 3;
+
+    /* DEVMODE dmDisplayFixedOutput specifiations */
+    int DMDFO_DEFAULT = 0;
+    int DMDFO_STRETCH = 1;
+    int DMDFO_CENTER = 2;
+
+    /* DEVMODE dmDisplayFlags flags */
+    int DM_GRAYSCALE = 0x00000001;
+    int DM_INTERLACED = 0x00000002;
+    int DMDISPLAYFLAGS_TEXTMODE = 0x00000004;
+
+    /* DEVMODE dmNup: multiple logical page per physical page options */
+    /** The print spooler does the NUP (pages per sheet) **/
+    int DMNUP_SYSTEM = 1;
+    /** The application does the NUP (pages per sheet) **/
+    int DMNUP_ONEUP = 2;
+
+    /* ICM methods */
+    /** ICM disabled **/
+    int DMICMMETHOD_NONE = 1;
+    /** ICM handled by system **/
+    int DMICMMETHOD_SYSTEM = 2;
+    /** ICM handled by driver **/
+    int DMICMMETHOD_DRIVER = 3;
+    /** ICM handled by device **/
+    int DMICMMETHOD_DEVICE = 4;
+
+    /* ICM Intents */
+    /** Maximize color saturation **/
+    int DMICM_SATURATE = 1;
+    /** Maximize color contrast **/
+    int DMICM_CONTRAST = 2;
+    /** Use specific color metric **/
+    int DMICM_COLORIMETRIC  = 3;
+    /** Use specific color metric **/
+    int DMICM_ABS_COLORIMETRIC =  4;
+    /** Device-specific intents start here **/
+    int DMICM_USER = 256;
+
+    /* Media types */
+    /** Standard paper **/
+    int DMMEDIA_STANDARD = 1;
+    /** Transparency **/
+    int DMMEDIA_TRANSPARENCY = 2;
+    /** Glossy paper **/
+    int DMMEDIA_GLOSSY = 3;
+    /** Device-specific media start here */
+    int DMMEDIA_USER = 256;
+
+    /* Dither types */
+    /** No dithering **/
+    int DMDITHER_NONE= 1;
+    /** Dither with a coarse brush **/
+    int DMDITHER_COARSE     = 2;
+    /** Dither with a fine brush **/
+    int DMDITHER_FINE= 3;
+    /** LineArt dithering **/
+    int DMDITHER_LINEART   = 4;
+    /** LineArt dithering **/
+    int DMDITHER_ERRORDIFFUSION = 5;
+    /** LineArt dithering **/
+    int DMDITHER_RESERVED6 = 6;
+    /** LineArt dithering **/
+    int DMDITHER_RESERVED7 = 7;
+    /** LineArt dithering **/
+    int DMDITHER_RESERVED8 = 8;
+    /** LineArt dithering **/
+    int DMDITHER_RESERVED9 = 9;
+    /** Device does grayscaling **/
+    int DMDITHER_GRAYSCALE  = 10;
+    /** Device-specific dithers start here **/
+    int DMDITHER_USER = 256;
+
     int RGN_AND = 1;
     int RGN_OR = 2;
     int RGN_XOR = 3;
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Winspool.java b/contrib/platform/src/com/sun/jna/platform/win32/Winspool.java
index 7dcdac4cb4..d330c96ca9 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Winspool.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Winspool.java
@@ -29,6 +29,7 @@
 import com.sun.jna.Structure;
 import com.sun.jna.Structure.FieldOrder;
 import com.sun.jna.Union;
+import com.sun.jna.platform.win32.WinGDI.DEVMODE;
 import com.sun.jna.platform.win32.WinBase.SYSTEMTIME;
 import com.sun.jna.platform.win32.WinDef.DWORD;
 import com.sun.jna.platform.win32.WinDef.DWORDByReference;
@@ -41,6 +42,8 @@
 import com.sun.jna.win32.StdCallLibrary;
 import com.sun.jna.win32.W32APIOptions;
 
+import static com.sun.jna.platform.win32.WinDef.*;
+
 /**
  * Ported from Winspool.h. Windows SDK 6.0a
  *
@@ -51,6 +54,13 @@ public interface Winspool extends StdCallLibrary {
     Winspool INSTANCE = Native.load("Winspool.drv", Winspool.class, W32APIOptions.DEFAULT_OPTIONS);
 
     public static final int CCHDEVICENAME = 32;
+    public static final int CCHFORMNAME = 32;
+
+    public static final int DSPRINT_PUBLISH = 0x00000001;
+    public static final int DSPRINT_UPDATE = 0x00000002;
+    public static final int DSPRINT_UNPUBLISH = 0x00000004;
+    public static final int DSPRINT_REPUBLISH = 0x00000008;
+    public static final int DSPRINT_PENDING = 0x80000000;
 
     public static final int PRINTER_STATUS_PAUSED = 0x00000001;
     public static final int PRINTER_STATUS_ERROR = 0x00000002;
@@ -281,7 +291,7 @@ public interface Winspool extends StdCallLibrary {
      *         the function fails, the return value is zero.
      *
      * @see <a href=
-     *      "https://msdn.microsoft.com/en-us/library/windows/desktop/dd162692(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/enumprinters">
      *      EnumPrinters function</a>
      */
     boolean EnumPrinters(int Flags, String Name, int Level,
@@ -318,7 +328,7 @@ boolean EnumPrinters(int Flags, String Name, int Level,
      *         the function fails, the return value is zero.
      *
      * @see <a href=
-     *      "https://msdn.microsoft.com/en-us/library/windows/desktop/dd144911(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/getprinter">
      * GetPrinter function</a>
      */
     boolean GetPrinter(HANDLE hPrinter, int Level, Pointer pPrinter, int cbBuf, IntByReference pcbNeeded);
@@ -327,7 +337,7 @@ boolean EnumPrinters(int Flags, String Name, int Level,
      * The PRINTER_INFO_1 structure specifies general printer information.
      *
      * @see <a href=
-     *      "https://msdn.microsoft.com/en-us/library/windows/desktop/dd162844(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/printer-info-1">
      * PRINTER_INFO_1 structure</a>
      */
     @FieldOrder({"Flags", "pDescription", "pName", "pComment"})
@@ -368,7 +378,7 @@ public PRINTER_INFO_1(int size) {
      *
      * @author Ivan Ridao Freitas, Padrus
      * @see <a href=
-     *      "https://msdn.microsoft.com/en-us/library/windows/desktop/dd162845(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/printer-info-2">
      * PRINTER_INFO_2 structure</a>
      */
     @FieldOrder({"pServerName", "pPrinterName", "pShareName",
@@ -508,6 +518,34 @@ public boolean hasAttribute(int value) {
         }
     }
 
+    /**
+     * The PRINTER_INFO_3 structure specifies printer security information.
+     * <p>
+     * The structure lets an application get and set a printer's security descriptor.
+     * The caller may do so even if it lacks specific printer permissions, as long
+     * as it has the standard rights described in SetPrinter and GetPrinter. Thus,
+     * an application may temporarily deny all access to a printer, while allowing
+     * the owner of the printer to have access to the printer's discretionary ACL.
+     *
+     * @see <a href=
+     *      "https://docs.microsoft.com/windows/win32/printdocs/printer-info-3">
+     * PRINTER_INFO_3 structure</a>
+     */
+    @FieldOrder({"pSecurityDescriptor"})
+    public static class PRINTER_INFO_3 extends Structure {
+
+        /**
+         * Pointer to a SECURITY_DESCRIPTOR structure that specifies a printer's security information.
+         */
+        public WinNT.SECURITY_DESCRIPTOR_RELATIVE pSecurityDescriptor;
+
+        public PRINTER_INFO_3() {}
+
+        public PRINTER_INFO_3(int size) {
+            super(new Memory((long)size));
+        }
+    }
+
     /**
      * The PRINTER_INFO_4 structure specifies general printer information.
      * <p>
@@ -517,7 +555,7 @@ public boolean hasAttribute(int value) {
      * all remote printer connections that a user has established.
      *
      * @see <a href=
-     *      "https://msdn.microsoft.com/en-us/library/windows/desktop/dd162847(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/printer-info-4">
      * PRINTER_INFO_4 structure</a>
      */
     @FieldOrder({"pPrinterName", "pServerName", "Attributes"})
@@ -535,7 +573,7 @@ public static class PRINTER_INFO_4 extends Structure {
         /**
          * Specifies information about the returned data.
          */
-        public DWORD Attributes;
+        public int Attributes;
 
         public PRINTER_INFO_4() {
             super();
@@ -546,11 +584,172 @@ public PRINTER_INFO_4(int size) {
         }
     }
 
+    /**
+     * The PRINTER_INFO_5 structure specifies detailed printer information.
+     *
+     * @see <a href=
+     *      "https://docs.microsoft.com/windows/win32/printdocs/printer-info-4">
+     * PRINTER_INFO_5 structure</a>
+     */
+    @FieldOrder({"pPrinterName", "pPortName", "Attributes", "DeviceNotSelectedTimeout",
+            "TransmissionRetryTimeout"})
+    public static class PRINTER_INFO_5 extends Structure {
+
+        /**
+         * Pointer to a null-terminated string that specifies the name of the
+         * printer (local or remote).
+         */
+        public String pPrinterName;
+
+        /**
+         * A pointer to a null-terminated string that identifies the port(s)
+         * used to transmit data to the printer. If a printer is connected
+         * to more than one port, the names of each port must be separated
+         * by commas (for example, "LPT1:,LPT2:,LPT3:").
+         */
+        public String pPortName;
+
+        /**
+         * The printer attributes. This member can be any reasonable combination
+         * of <code>PRINTER_ATTRIBUTE_XXX</code> values
+         *
+         */
+        public int Attributes;
+
+        /**
+         * This value is not used.
+         */
+        public int DeviceNotSelectedTimeout;
+
+        /**
+         * This value is not used.
+         */
+        public int TransmissionRetryTimeout;
+
+        public PRINTER_INFO_5() {}
+
+        public PRINTER_INFO_5(int size) {
+            super(new Memory((long)size));
+        }
+    }
+
+    /**
+     * The PRINTER_INFO_6 structure specifies the status value of a printer.
+     *
+     * @see <a href=
+     *      "https://docs.microsoft.com/windows/win32/printdocs/printer-info-4">
+     * PRINTER_INFO_6 structure</a>
+     */
+    @FieldOrder({"dwStatus"})
+    public static class PRINTER_INFO_6 extends Structure {
+        /**
+         * The printer status. This member can be any reasonable combination
+         * of <code>PRINTER_STATUS_XXX</code> values.
+         */
+        public int dwStatus;
+
+        public PRINTER_INFO_6() {}
+
+        public PRINTER_INFO_6(int size) {
+            super(new Memory((long)size));
+        }
+    }
+
+    /**
+     * The PRINTER_INFO_7 structure specifies directory services printer information.
+     * <p>
+     * The structure specifies directory services printer information.  Use this
+     * structure with the <code>SetPrinter</code> function to publish a printer's
+     * data in the directory service (DS), or to update or remove a printer's
+     * published data from the DS. Use this structure with the <code>GetPrinter</code>
+     * function to determine whether a printer is published in the DS.
+     *
+     * @see <a href=
+     *      "https://docs.microsoft.com/windows/win32/printdocs/printer-info-4">
+     * PRINTER_INFO_7 structure</a>
+     */
+    @FieldOrder({"pszObjectGUID", "dwAction"})
+    public static class PRINTER_INFO_7 extends Structure {
+
+        /**
+         * A pointer to a null-terminated string containing the GUID of the directory
+         * service print queue object associated with a published printer. Use the
+         * <code>GetPrinter</code> function to retrieve this GUID.
+         *
+         * Before calling <code>SetPrinter</code>, set <code>pszObjectGUID</code> to NULL.
+         */
+        public String pszObjectGUID;
+
+        /**
+         * Indicates the action for the <code>SetPrinter</code> function to perform. For the
+         * <code>GetPrinter</code> function, this member indicates whether the specified
+         * printer is published. This member can be a combination of <code>DSPRINT_XXX</code>
+         * values.
+         */
+        public int dwAction;
+
+        public PRINTER_INFO_7() {}
+
+        public PRINTER_INFO_7(int size) {
+            super(new Memory((long)size));
+        }
+    }
+
+    /**
+     * The PRINTER_INFO_8 structure specifies the global default printer settings.
+     * <p>
+     * The global defaults are set by the administrator of a printer that can be
+     * used by anyone. In contrast, the per-user defaults will affect a particular
+     * user or anyone else who uses the profile. For per-user defaults,
+     * use <code>PRINTER_INFO_9</code>.
+     *
+     * @see <a href=
+     *      "https://docs.microsoft.com/windows/win32/printdocs/printer-info-4">
+     * PRINTER_INFO_8 structure</a>
+     */
+    @FieldOrder({"pDevMode"})
+    public static class PRINTER_INFO_8 extends Structure {
+        /**
+         * A pointer to a <code>DEVMODE</code> structure that defines the global
+         * default printer data such as the paper orientation and the resolution.
+         */
+        public DEVMODE.ByReference pDevMode;
+
+        public PRINTER_INFO_8() {}
+
+        public PRINTER_INFO_8(int size) {
+            super(new Memory((long)size));
+        }
+    }
+
+    /**
+     * The PRINTER_INFO_9 structure specifies the per-user default printer settings.
+     * <p>
+     * The per-user defaults will affect only a particular user or anyone who uses the
+     * profile. In contrast, the global defaults are set by the administrator of a printer
+     * that can be used by anyone. For global defaults, use <code>PRINTER_INFO_8</code>.
+     *
+     * @see <a href=
+     *      "https://docs.microsoft.com/windows/win32/printdocs/printer-info-4">
+     * PRINTER_INFO_9 structure</a>
+     */
+    @FieldOrder({"pDevMode"})
+    public static class PRINTER_INFO_9 extends Structure {
+        public DEVMODE.ByReference pDevMode;
+
+        public PRINTER_INFO_9() {}
+
+        public PRINTER_INFO_9(int size) {
+            super(new Memory((long)size));
+        }
+    }
+
     /**
      * The PRINTER_DEFAULTS structure specifies the default data type,
      * environment, initialization data, and access rights for a printer.
      *
-     * @see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd162839(v=vs.85).aspx">PRINTER_DEFAULTS structure</a>
+     * @see <a href="https://docs.microsoft.com/windows/win32/printdocs/printer-defaults">
+     *     PRINTER_DEFAULTS structure</a>
      */
     @FieldOrder({"pDatatype", "pDevMode", "DesiredAccess"})
     public class LPPRINTER_DEFAULTS extends Structure {
@@ -597,7 +796,8 @@ public class LPPRINTER_DEFAULTS extends Structure {
      * @return If the function succeeds, the return value is a nonzero value. If
      *         the function fails, the return value is zero.
      *
-     * @see <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd162751(v=vs.85).aspx">OpenPrinter function</a>
+     * @see <a href="https://docs.microsoft.com/windows/win32/printdocs/openprinter">
+     *     OpenPrinter function</a>
      */
     boolean OpenPrinter(
             // _In_
@@ -628,7 +828,7 @@ boolean OpenPrinter(
      *         the function fails, the return value is zero.
      *
      * @see <a href=
-     *      "http://msdn.microsoft.com/en-us/library/windows/desktop/dd162751(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/closeprinter">
      * ClosePrinter function</a>
      */
     boolean ClosePrinter(HANDLE hPrinter);
@@ -638,7 +838,7 @@ boolean OpenPrinter(
      * notification object that monitors a printer or print server.
      *
      * @see
-     * <a href="https://docs.microsoft.com/en-us/windows/win32/printdocs/printer-notify-options">
+     * <a href="https://docs.microsoft.com/windows/win32/printdocs/printer-notify-options">
      *     PRINTER_NOTIFY_OPTIONS structure
      * </a>
      */
@@ -681,7 +881,7 @@ public class PRINTER_NOTIFY_OPTIONS extends Structure {
      * notification object.
      *
      * @see
-     * <a href="https://docs.microsoft.com/en-us/windows/win32/printdocs/printer-notify-options-type">
+     * <a href="https://docs.microsoft.com/windows/win32/printdocs/printer-notify-options-type">
      *     PRINTER_NOTIFY_OPTIONS_TYPE structure
      * </a>
      */
@@ -744,7 +944,7 @@ public short[] getFields() {
      * object has been satisfied.
      *
      * @see
-     * <a href="https://docs.microsoft.com/en-us/windows/win32/printdocs/printer-notify-info">
+     * <a href="https://docs.microsoft.com/windows/win32/printdocs/printer-notify-info">
      *     PRINTER_NOTIFY_INFO structure
      * </a>
      */
@@ -836,7 +1036,7 @@ public class NOTIFY_DATA extends Union {
      * information field and provides the current data for that field.
      *
      * @see
-     * <a href="https://docs.microsoft.com/en-us/windows/win32/printdocs/printer-notify-info-data">
+     * <a href="https://docs.microsoft.com/windows/win32/printdocs/printer-notify-info-data">
      *     PRINTER_NOTIFY_INFO_DATA structure
      * </a>
      */
@@ -984,7 +1184,7 @@ HANDLE FindFirstPrinterChangeNotification(
      *         INVALID_HANDLE_VALUE.
      *
      * @see <a href=
-     *      "http://msdn.microsoft.com/en-us/library/windows/desktop/dd162722(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/findfirstprinterchangenotification">
      * FindFirstPrinterChangeNotification function</a>
      */
     HANDLE FindFirstPrinterChangeNotification(
@@ -1068,7 +1268,7 @@ boolean FindNextPrinterChangeNotification(
      *         the function fails, the return value is zero.
      *
      * @see <a href=
-     *      "http://msdn.microsoft.com/en-us/library/windows/desktop/dd162721(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/findnextprinterchangenotification">
      * FindClosePrinterChangeNotification function</a>
      */
     boolean FindNextPrinterChangeNotification(
@@ -1097,7 +1297,7 @@ boolean FindNextPrinterChangeNotification(
      *         the function fails, the return value is zero.
      *
      * @see <a href=
-     *      "http://msdn.microsoft.com/en-us/library/windows/desktop/dd162721(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/findcloseprinterchangenotification">
      * FindClosePrinterChangeNotification function</a>
      */
     boolean FindClosePrinterChangeNotification(
@@ -1117,7 +1317,7 @@ boolean FindClosePrinterChangeNotification(
      *         the function fails, the return value is zero.
      *
      * @see
-     * <a href="https://docs.microsoft.com/en-us/windows/win32/printdocs/freeprinternotifyinfo">
+     * <a href="https://docs.microsoft.com/windows/win32/printdocs/freeprinternotifyinfo">
      *     FreePrinterNotifyInfo function
      * </a>
      */
@@ -1158,7 +1358,7 @@ boolean FreePrinterNotifyInfo(
      *         the function fails, the return value is zero.
      *
      * @see <a href=
-     *      "https://msdn.microsoft.com/en-us/library/windows/desktop/dd162625(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/enumjobs">
      * EnumJobs function</a>
      */
     boolean EnumJobs(
@@ -1186,7 +1386,7 @@ boolean EnumJobs(
      * the user that owns the print job, and so on.
      *
      * @see <a href=
-     *      "https://msdn.microsoft.com/en-us/library/windows/desktop/dd145019(v=vs.85).aspx">
+     *      "https://docs.microsoft.com/windows/win32/printdocs/job-info-1">
      * JOB_INFO_1 structure</a>
      */
     @FieldOrder({"JobId", "pPrinterName", "pMachineName", "pUserName",
@@ -1275,4 +1475,8 @@ public JOB_INFO_1(int size) {
             super(new Memory(size));
         }
     }
+
+    int DocumentProperties(
+            WinDef.HWND hWnd, HANDLE hPrinter, String pDeviceName,
+            Pointer pDevModeOutput, Pointer pDevModeInput, int fMode);
 }
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java b/contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java
index 34da367183..5700df380e 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java
@@ -25,104 +25,57 @@
 
 import static com.sun.jna.platform.win32.WinError.ERROR_INSUFFICIENT_BUFFER;
 import static com.sun.jna.platform.win32.WinError.ERROR_SUCCESS;
+import static com.sun.jna.platform.win32.Winspool.*;
 
 import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
-import com.sun.jna.platform.win32.Winspool.JOB_INFO_1;
-import com.sun.jna.platform.win32.Winspool.PRINTER_INFO_1;
-import com.sun.jna.platform.win32.Winspool.PRINTER_INFO_2;
-import com.sun.jna.platform.win32.Winspool.PRINTER_INFO_4;
+import com.sun.jna.platform.win32.Winspool;
 import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.Structure;
 
 /**
  * Winspool Utility API.
  *
  * @author dblock[at]dblock.org, Ivan Ridao Freitas, Padrus, Artem Vozhdayenko
+ * @author Tres Finocchiaro, tres.finocchiaro@gmail.com
  */
 public abstract class WinspoolUtil {
 
-    public static PRINTER_INFO_1[] getPrinterInfo1() {
-        IntByReference pcbNeeded = new IntByReference();
-        IntByReference pcReturned = new IntByReference();
-        Winspool.INSTANCE.EnumPrinters(Winspool.PRINTER_ENUM_LOCAL, null, 1,
-                null, 0, pcbNeeded, pcReturned);
-        if (pcbNeeded.getValue() <= 0) {
-            return new PRINTER_INFO_1[0];
-        }
-
-        PRINTER_INFO_1 pPrinterEnum = new PRINTER_INFO_1(pcbNeeded.getValue());
-        if (!Winspool.INSTANCE.EnumPrinters(Winspool.PRINTER_ENUM_LOCAL, null,
-                1, pPrinterEnum.getPointer(), pcbNeeded.getValue(), pcbNeeded,
-                pcReturned)) {
-            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
-        }
-
-        pPrinterEnum.read();
-
-        return (PRINTER_INFO_1[]) pPrinterEnum.toArray(pcReturned.getValue());
-    }
-
-    public static PRINTER_INFO_2[] getPrinterInfo2() {
-        return getPrinterInfo2(Winspool.PRINTER_ENUM_LOCAL);
-    }
-
     /**
-     * Returns printers that are physically attached to the local machine as
-     * well as remote printers to which it has a network connection.
+     * Helper for getting printer info struct by number, e.g. PRINTER_INFO_1 = 1, etc.
      */
-    public static PRINTER_INFO_2[] getAllPrinterInfo2() {
-        // When Name is NULL, setting Flags to PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS
-        // enumerates printers that are installed on the local machine.
-        // These printers include those that are physically attached to the local machine
-        // as well as remote printers to which it has a network connection.
-        // See https://msdn.microsoft.com/en-us/library/windows/desktop/dd162692(v=vs.85).aspx
-        return getPrinterInfo2(Winspool.PRINTER_ENUM_LOCAL | Winspool.PRINTER_ENUM_CONNECTIONS);
-    }
-
-    private static PRINTER_INFO_2[] getPrinterInfo2(int flags) {
-        IntByReference pcbNeeded = new IntByReference();
-        IntByReference pcReturned = new IntByReference();
-        Winspool.INSTANCE.EnumPrinters(flags, null, 2, null, 0, pcbNeeded, pcReturned);
-        if (pcbNeeded.getValue() <= 0) {
-            return new PRINTER_INFO_2[0];
-        }
-
-        PRINTER_INFO_2 pPrinterEnum = new PRINTER_INFO_2(pcbNeeded.getValue());
-        if (!Winspool.INSTANCE.EnumPrinters(flags, null, 2, pPrinterEnum.getPointer(), pcbNeeded.getValue(), pcbNeeded,
-                pcReturned)) {
-            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
-        }
-
-        pPrinterEnum.read();
-        return (PRINTER_INFO_2[]) pPrinterEnum.toArray(pcReturned.getValue());
-    }
-
-    public static PRINTER_INFO_2 getPrinterInfo2(String printerName) {
+    static Structure getPrinterInfoByStruct(String printerName, int structType) {
         IntByReference pcbNeeded = new IntByReference();
         IntByReference pcReturned = new IntByReference();
         HANDLEByReference pHandle = new HANDLEByReference();
 
+        // Get printer handle
         if (!Winspool.INSTANCE.OpenPrinter(printerName, pHandle, null)) {
             throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
         }
 
         Win32Exception we = null;
-        PRINTER_INFO_2 pinfo2 = null;
+        Structure struct = null;
 
         try {
-            Winspool.INSTANCE.GetPrinter(pHandle.getValue(), 2, null, 0, pcbNeeded);
+            // First pass: Get page size
+            Winspool.INSTANCE.GetPrinter(pHandle.getValue(), structType, null, 0, pcbNeeded);
+
+            struct = initStructByType(structType, pcbNeeded.getValue());
             if (pcbNeeded.getValue() <= 0) {
-                return new PRINTER_INFO_2();
+                return struct;
             }
 
-            pinfo2 = new PRINTER_INFO_2(pcbNeeded.getValue());
-            if (!Winspool.INSTANCE.GetPrinter(pHandle.getValue(), 2, pinfo2.getPointer(), pcbNeeded.getValue(), pcReturned)) {
+            // Second pass: Get printer information
+            if (!Winspool.INSTANCE.GetPrinter(pHandle.getValue(), structType, struct.getPointer(), pcbNeeded.getValue(), pcReturned)) {
                 throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
             }
 
-            pinfo2.read();
-        } catch (Win32Exception e) {
+            struct.read();
+        }
+        catch(Win32Exception e) {
             we = e;
-        } finally {
+        }
+        finally {
             if (!Winspool.INSTANCE.ClosePrinter(pHandle.getValue())) {
                 Win32Exception ex = new Win32Exception(Kernel32.INSTANCE.GetLastError());
                 if (we != null) {
@@ -135,28 +88,83 @@ public static PRINTER_INFO_2 getPrinterInfo2(String printerName) {
             throw we;
         }
 
-        return pinfo2;
+        return struct;
     }
 
-    public static PRINTER_INFO_4[] getPrinterInfo4() {
+    /**
+     * Helper for getting array of printer info
+     * PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS
+     */
+    static Structure[] getPrinterInfoByStruct(int flags, int structType) {
         IntByReference pcbNeeded = new IntByReference();
         IntByReference pcReturned = new IntByReference();
-        Winspool.INSTANCE.EnumPrinters(Winspool.PRINTER_ENUM_LOCAL, null, 4,
-                null, 0, pcbNeeded, pcReturned);
+        // When Name is NULL, setting Flags to PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS
+        // enumerates printers that are installed on the local machine.
+        // These printers include those that are physically attached to the local machine
+        // as well as remote printers to which it has a network connection.
+        // See https://msdn.microsoft.com/en-us/library/windows/desktop/dd162692(v=vs.85).aspx
+        Winspool.INSTANCE.EnumPrinters(flags, null, structType, null, 0, pcbNeeded, pcReturned);
+        Structure struct = initStructByType(structType, pcbNeeded.getValue());
         if (pcbNeeded.getValue() <= 0) {
-            return new PRINTER_INFO_4[0];
+            return emptyStructArrayByType(structType);
         }
-
-        PRINTER_INFO_4 pPrinterEnum = new PRINTER_INFO_4(pcbNeeded.getValue());
-        if (!Winspool.INSTANCE.EnumPrinters(Winspool.PRINTER_ENUM_LOCAL, null,
-                4, pPrinterEnum.getPointer(), pcbNeeded.getValue(), pcbNeeded,
+        if (!Winspool.INSTANCE.EnumPrinters(flags, null, structType, struct.getPointer(), pcbNeeded.getValue(), pcbNeeded,
                 pcReturned)) {
             throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
         }
 
-        pPrinterEnum.read();
+        struct.read();
+        return struct.toArray(pcReturned.getValue());
+    }
+
+    private static Structure[] emptyStructArrayByType(int structType) {
+        switch(structType) {
+            case 1:
+                return new PRINTER_INFO_1[0];
+            case 2:
+                return new PRINTER_INFO_2[0];
+            case 3:
+                return new PRINTER_INFO_3[0];
+            case 4:
+                return new PRINTER_INFO_4[0];
+            case 5:
+                return new PRINTER_INFO_5[0];
+            case 6:
+                return new PRINTER_INFO_6[0];
+            case 7:
+                return new PRINTER_INFO_7[0];
+            case 8:
+                return new PRINTER_INFO_8[0];
+            case 9:
+                return new PRINTER_INFO_9[0];
+            default:
+                throw new UnsupportedOperationException("PRINTER_INFO_" + structType + " doesn't exist or has not been implemented");
+        }
+    }
 
-        return (PRINTER_INFO_4[]) pPrinterEnum.toArray(pcReturned.getValue());
+    private static Structure initStructByType(int structType, int size) {
+        switch(structType) {
+            case 1:
+                return size <= 0 ? new PRINTER_INFO_1() : new PRINTER_INFO_1(size);
+            case 2:
+                return size <= 0 ? new PRINTER_INFO_2() : new PRINTER_INFO_2(size);
+            case 3:
+                return size <= 0 ? new PRINTER_INFO_3() : new PRINTER_INFO_3(size);
+            case 4:
+                return size <= 0 ? new PRINTER_INFO_4() : new PRINTER_INFO_4(size);
+            case 5:
+                return size <= 0 ? new PRINTER_INFO_5() : new PRINTER_INFO_5(size);
+            case 6:
+                return size <= 0 ? new PRINTER_INFO_6() : new PRINTER_INFO_6(size);
+            case 7:
+                return size <= 0 ? new PRINTER_INFO_7() : new PRINTER_INFO_7(size);
+            case 8:
+                return size <= 0 ? new PRINTER_INFO_8() : new PRINTER_INFO_8(size);
+            case 9:
+                return size <= 0 ? new PRINTER_INFO_9() : new PRINTER_INFO_9(size);
+            default:
+                throw new UnsupportedOperationException("PRINTER_INFO_" + structType + " doesn't exist or has not been implemented");
+        }
     }
 
     public static JOB_INFO_1[] getJobInfo1(HANDLEByReference phPrinter) {
@@ -190,4 +198,228 @@ public static JOB_INFO_1[] getJobInfo1(HANDLEByReference phPrinter) {
         return (JOB_INFO_1[]) pJobEnum.toArray(pcReturned.getValue());
     }
 
+    public static PRINTER_INFO_1[] getAllPrinterInfo1() {
+        return getPrinterInfo1(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+    }
+
+    public static PRINTER_INFO_2[] getAllPrinterInfo2() {
+        return getPrinterInfo2(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+    }
+
+    public static PRINTER_INFO_3[] getAllPrinterInfo3() {
+        return getPrinterInfo3(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+    }
+
+    public static PRINTER_INFO_4[] getAllPrinterInfo4() {
+        return getPrinterInfo4(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+    }
+
+    public static PRINTER_INFO_5[] getAllPrinterInfo5() {
+        return getPrinterInfo5(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+    }
+
+    public static PRINTER_INFO_6[] getAllPrinterInfo6() {
+        return getPrinterInfo6(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+    }
+
+    public static PRINTER_INFO_7[] getAllPrinterInfo7() {
+        return getPrinterInfo7(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+    }
+
+    public static PRINTER_INFO_8[] getAllPrinterInfo8() {
+        return getPrinterInfo8(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+    }
+
+    public static PRINTER_INFO_9[] getAllPrinterInfo9() {
+        return getPrinterInfo9(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+    }
+
+    /**
+     * The PRINTER_INFO_1 structure specifies general printer information.
+     */
+    public static PRINTER_INFO_1[] getPrinterInfo1() {
+        return getPrinterInfo1(PRINTER_ENUM_LOCAL);
+    }
+
+    /**
+     * The PRINTER_INFO_1 structure specifies general printer information.
+     */
+    public static PRINTER_INFO_1 getPrinterInfo1(String printerName) {
+        return (PRINTER_INFO_1)getPrinterInfoByStruct(printerName, 1);
+    }
+
+    /**
+     * The PRINTER_INFO_1 structure specifies general printer information.
+     */
+    public static PRINTER_INFO_1[] getPrinterInfo1(int flags) {
+        return (PRINTER_INFO_1[])getPrinterInfoByStruct(flags, 1);
+    }
+
+    /**
+     * The PRINTER_INFO_2 structure specifies general printer information.
+     */
+    public static PRINTER_INFO_2 getPrinterInfo2(String printerName) {
+        return (PRINTER_INFO_2)getPrinterInfoByStruct(printerName, 2);
+    }
+
+    /**
+     * The PRINTER_INFO_2 structure specifies general printer information.
+     */
+    public static PRINTER_INFO_2[] getPrinterInfo2(int flags) {
+        return (PRINTER_INFO_2[])getPrinterInfoByStruct(flags, 2);
+    }
+
+    /**
+     * The PRINTER_INFO_2 structure specifies general printer information.
+     */
+    public static PRINTER_INFO_2[] getPrinterInfo2() {
+        return getPrinterInfo2(PRINTER_ENUM_LOCAL);
+    }
+
+    /**
+     * The PRINTER_INFO_3 structure specifies printer security information.
+     */
+    public static PRINTER_INFO_3 getPrinterInfo3(String printerName) {
+        return (PRINTER_INFO_3)getPrinterInfoByStruct(printerName, 3);
+    }
+
+    /**
+     * The PRINTER_INFO_3 structure specifies printer security information.
+     */
+    public static PRINTER_INFO_3[] getPrinterInfo3(int flags) {
+        return (PRINTER_INFO_3[])getPrinterInfoByStruct(flags, 3);
+    }
+
+    /**
+     * The PRINTER_INFO_3 structure specifies printer security information.
+     */
+    public static PRINTER_INFO_3[] getPrinterInfo3() {
+        return getPrinterInfo3(PRINTER_ENUM_LOCAL);
+    }
+
+    /**
+     * The PRINTER_INFO_4 structure specifies general printer information.
+     */
+    public static PRINTER_INFO_4 getPrinterInfo4(String printerName) {
+        return (PRINTER_INFO_4)getPrinterInfoByStruct(printerName, 4);
+    }
+
+    /**
+     * The PRINTER_INFO_4 structure specifies general printer information.
+     */
+    public static PRINTER_INFO_4[] getPrinterInfo4(int flags) {
+        return (PRINTER_INFO_4[])getPrinterInfoByStruct(flags, 4);
+    }
+
+    /**
+     * The PRINTER_INFO_4 structure specifies general printer information.
+     */
+    public static PRINTER_INFO_4[] getPrinterInfo4() {
+        return getPrinterInfo4(PRINTER_ENUM_LOCAL);
+    }
+
+    /**
+     * The PRINTER_INFO_5 structure specifies detailed printer information.
+     */
+    public static PRINTER_INFO_5 getPrinterInfo5(String printerName) {
+        return (PRINTER_INFO_5)getPrinterInfoByStruct(printerName, 5);
+    }
+
+    /**
+     * The PRINTER_INFO_5 structure specifies detailed printer information.
+     */
+    public static PRINTER_INFO_5[] getPrinterInfo5(int flags) {
+        return (PRINTER_INFO_5[])getPrinterInfoByStruct(flags, 5);
+    }
+
+    /**
+     * The PRINTER_INFO_5 structure specifies detailed printer information.
+     */
+    public static PRINTER_INFO_5[] getPrinterInfo5() {
+        return getPrinterInfo5(PRINTER_ENUM_LOCAL);
+    }
+
+    /**
+     * The PRINTER_INFO_6 specifies the status value of a printer.
+     */
+    public static PRINTER_INFO_6 getPrinterInfo6(String printerName) {
+        return (PRINTER_INFO_6)getPrinterInfoByStruct(printerName, 6);
+    }
+
+    /**
+     * The PRINTER_INFO_6 specifies the status value of a printer.
+     */
+    public static PRINTER_INFO_6[] getPrinterInfo6(int flags) {
+        return (PRINTER_INFO_6[])getPrinterInfoByStruct(flags, 6);
+    }
+
+    /**
+     * The PRINTER_INFO_6 specifies the status value of a printer.
+     */
+    public static PRINTER_INFO_6[] getPrinterInfo6() {
+        return getPrinterInfo6(PRINTER_ENUM_LOCAL);
+    }
+
+    /**
+     * The PRINTER_INFO_7 structure specifies directory services printer information.
+     */
+    public static PRINTER_INFO_7 getPrinterInfo7(String printerName) {
+        return (PRINTER_INFO_7)getPrinterInfoByStruct(printerName, 7);
+    }
+
+    /**
+     * The PRINTER_INFO_7 structure specifies directory services printer information.
+     */
+    public static PRINTER_INFO_7[] getPrinterInfo7(int flags) {
+        return (PRINTER_INFO_7[])getPrinterInfoByStruct(flags, 7);
+    }
+
+    /**
+     * The PRINTER_INFO_7 structure specifies directory services printer information.
+     */
+    public static PRINTER_INFO_7[] getPrinterInfo7() {
+        return getPrinterInfo7(PRINTER_ENUM_LOCAL);
+    }
+
+    /**
+     * The PRINTER_INFO_8 structure specifies the global default printer settings.
+     */
+    public static PRINTER_INFO_8 getPrinterInfo8(String printerName) {
+        return (PRINTER_INFO_8)getPrinterInfoByStruct(printerName, 8);
+    }
+
+    /**
+     * The PRINTER_INFO_8 structure specifies the global default printer settings.
+     */
+    public static PRINTER_INFO_8[] getPrinterInfo8(int flags) {
+        return (PRINTER_INFO_8[])getPrinterInfoByStruct(flags, 8);
+    }
+
+    /**
+     * The PRINTER_INFO_8 structure specifies the global default printer settings.
+     */
+    public static PRINTER_INFO_8[] getPrinterInfo8() {
+        return getPrinterInfo8(PRINTER_ENUM_LOCAL);
+    }
+
+    /**
+     * The PRINTER_INFO_9 Structure specifies the per-user default printer settings.
+     */
+    public static PRINTER_INFO_9 getPrinterInfo9(String printerName) {
+        return (PRINTER_INFO_9)getPrinterInfoByStruct(printerName, 9);
+    }
+
+    /**
+     * The PRINTER_INFO_9 Structure specifies the per-user default printer settings.
+     */
+    public static PRINTER_INFO_9[] getPrinterInfo9(int flags) {
+        return (PRINTER_INFO_9[])getPrinterInfoByStruct(flags, 9);
+    }
+
+    /**
+     * The PRINTER_INFO_9 Structure specifies the per-user default printer settings.
+     */
+    public static PRINTER_INFO_9[] getPrinterInfo9() {
+        return getPrinterInfo9(PRINTER_ENUM_LOCAL);
+    }
 }
\ No newline at end of file
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/WinspoolDummyTest.java b/contrib/platform/test/com/sun/jna/platform/win32/WinspoolDummyTest.java
new file mode 100644
index 0000000000..db64be320d
--- /dev/null
+++ b/contrib/platform/test/com/sun/jna/platform/win32/WinspoolDummyTest.java
@@ -0,0 +1,126 @@
+/* Copyright (c) 2010 Daniel Doubrovkine, All Rights Reserved
+ *
+ * The contents of this file is dual-licensed under 2
+ * alternative Open Source/Free licenses: LGPL 2.1 or later and
+ * Apache License 2.0. (starting with JNA version 4.0.0).
+ *
+ * You can freely decide which license you want to apply to
+ * the project.
+ *
+ * You may obtain a copy of the LGPL License at:
+ *
+ * http://www.gnu.org/licenses/licenses.html
+ *
+ * A copy is also included in the downloadable source code package
+ * containing JNA, in file "LGPL2.1".
+ *
+ * You may obtain a copy of the Apache License at:
+ *
+ * http://www.apache.org/licenses/
+ *
+ * A copy is also included in the downloadable source code package
+ * containing JNA, in file "AL2.0".
+ */
+package com.sun.jna.platform.win32;
+
+import com.sun.jna.Memory;
+import com.sun.jna.Native;
+import com.sun.jna.Structure;
+import java.nio.charset.StandardCharsets;
+import org.junit.Test;
+
+
+/**
+ * @author dblock[at]dblock[dot]org
+ */
+public class WinspoolDummyTest {
+
+    private static final String EVERYONE = "S-1-1-0";
+
+    @Test
+    public void testNoDuplicateMethodsNames() {
+        // Get a printer name from Java to use
+        //String printer = PrintServiceLookup.lookupDefaultPrintService().getName();
+        String printer = "Microsoft Print to PDF";
+
+        // Get custom Winspool2 instance
+        Winspool winspool = Winspool.INSTANCE;
+
+        // Get printer handle from Winspool
+        WinNT.HANDLEByReference hPrinter = new WinNT.HANDLEByReference();
+        boolean success = winspool.OpenPrinter(printer, hPrinter, null);
+        System.out.println("OpenPrinter status: " + success);
+        if (getLastError() || !success) {
+            System.err.println("Can't open printer, stopping");
+            return;
+        }
+
+        // Get DEVMODE size
+        int bufferSize = winspool.DocumentProperties(null, hPrinter.getValue(), printer, null, null, 0);
+
+        if (getLastError() || bufferSize == 0) {
+            System.err.println("Problem calling DocumentProperties");
+        } else {
+            System.out.println("The DEVMODE size must be " + bufferSize);
+            Memory devmodeBuffer = new Memory(bufferSize);
+            int status = winspool.DocumentProperties(null, hPrinter.getValue(), printer, devmodeBuffer, null, 6 /* DM_OUT_BUFFER | DM_PROMPT */);
+
+            WinGDI.DEVMODE dm = Structure.newInstance(WinGDI.DEVMODE.class, devmodeBuffer);
+            dm.read();
+
+            System.out.println(dm);
+            System.out.printf("Device:           %s%n", dm.getDmDeviceName());
+            System.out.printf("Formname:         %s%n", dm.getDmFormName());
+            if ((dm.dmFields & WinGDI.DM_ORIENTATION) == WinGDI.DM_ORIENTATION
+                    || (dm.dmFields & WinGDI.DM_PAPERSIZE) == WinGDI.DM_PAPERSIZE
+                    || (dm.dmFields & WinGDI.DM_PAPERLENGTH) == WinGDI.DM_PAPERLENGTH
+                    || (dm.dmFields & WinGDI.DM_PAPERWIDTH) == WinGDI.DM_PAPERWIDTH
+                    || (dm.dmFields & WinGDI.DM_COPIES) == WinGDI.DM_COPIES) {
+                dm.dmUnion1.setType("dummystructname");
+                dm.dmUnion1.read();
+                if((dm.dmFields & WinGDI.DM_ORIENTATION) == WinGDI.DM_ORIENTATION) {
+                    System.out.printf("Orientientation:  %d%n", dm.dmUnion1.dummystructname.dmOrientation);
+                }
+                if((dm.dmFields & WinGDI.DM_PAPERSIZE) == WinGDI.DM_PAPERSIZE) {
+                    System.out.printf("Paper size:       %d%n", dm.dmUnion1.dummystructname.dmPaperSize);
+                }
+                if((dm.dmFields & WinGDI.DM_PAPERLENGTH) == WinGDI.DM_PAPERLENGTH) {
+                    System.out.printf("Paper length:     %d%n", dm.dmUnion1.dummystructname.dmPaperLength);
+                }
+                if((dm.dmFields & WinGDI.DM_PAPERWIDTH) == WinGDI.DM_PAPERWIDTH) {
+                    System.out.printf("Paper width:      %d%n", dm.dmUnion1.dummystructname.dmPaperWidth);
+                }
+                if((dm.dmFields & WinGDI.DM_COPIES) == WinGDI.DM_COPIES) {
+                    System.out.printf("Copies:           %d%n", dm.dmUnion1.dummystructname.dmCopies);
+                }
+            }
+
+            // TODO: This may throw false error
+            long IDOK = 1;
+            if (getLastError()) {
+                System.err.println("Problem calling DocumentProperties");
+            }
+
+            if (status == IDOK) {
+                System.out.println("The call to DocumentProperties returned IDOK");
+            } else {
+                // API states a negative value is equivalent to an error
+                System.err.println("The call to DocumentProperties returned " + status);
+            }
+        }
+
+        // Close printer handle
+        winspool.INSTANCE.ClosePrinter(hPrinter.getValue());
+    }
+
+    private static boolean getLastError() {
+        int error = Native.getLastError();
+        if (error == 0) {
+            System.out.println("  OK");
+            return false;
+        } else {
+            System.out.println("  ERROR: " + error);
+        }
+        return true;
+    }
+}