Implemented the return of hDevModes and hDevNames in the PRINTDLG
structure of PrintDlgA().

diff --git a/dlls/commdlg/printdlg.c b/dlls/commdlg/printdlg.c
index 6c1d972..897c24a 100644
--- a/dlls/commdlg/printdlg.c
+++ b/dlls/commdlg/printdlg.c
@@ -22,11 +22,36 @@
 #include "winproc.h"
 #include "cderr.h"
 #include "winspool.h"
+#include "winerror.h"
 
 DEFAULT_DEBUG_CHANNEL(commdlg)
 
 #include "cdlg.h"
 
+
+/* This PRINTDLGA internal structure stores
+ * pointers to several throughout useful structures.
+ * 
+ */
+typedef struct  
+{
+  LPPRINTER_INFO_2A lpPrinterInfo;
+  UINT              CurrentPrinter;  /* used as lpPrinterInfo[CurrentPrinter] */
+  UINT              DefaultPrinter;  /* used as lpPrinterInfo[DefaultPrinter] */
+  DWORD             NrOfPrinterInfoEntries;
+  LPPRINTDLGA       lpPrintDlg;
+  UINT              HelpMessageID;
+  HICON             hCollateIcon;
+  HICON             hNoCollateIcon;
+} PRINT_PTRA;
+
+
+/* prototypes */
+static BOOL PRINTDLG_ValidateAndDuplicateSettings(HWND hDlg, 
+						  PRINT_PTRA* PrintStructures);
+
+
+
 /***********************************************************************
  *           PrintDlg16   (COMMDLG.20)
  */
@@ -75,20 +100,6 @@
 }
 
 
-/* This PRINTDLGA internal structure stores
- * pointers to several throughout useful structures.
- * 
- */
-typedef struct  
-{
-  LPPRINTER_INFO_2A lpPrinterInfo;
-  DWORD             NrOfPrinterInfoEntries;
-  LPPRINTDLGA       lpPrintDlg;
-  UINT              HelpMessageID;
-  HICON             hCollateIcon;
-  HICON             hNoCollateIcon;
-} PRINT_PTRA;
-
 /***********************************************************************
  *           PrintDlgA   (COMDLG32.17)
  *
@@ -104,8 +115,6 @@
  *  zero    if the user cancelled the window or an error occurred
  *
  * BUGS
- *  The function is a stub only, returning TRUE to allow more programs
- *  to function.
  *  The Collate Icons do not display, even though they are in the code.
  */
 BOOL WINAPI PrintDlgA(
@@ -121,8 +130,8 @@
  * step 4: implement all other specs
  * step 5: allow customisation of the dialog box
  *
- * current implementation is in step 2, nearly going to 3.
-     */ 
+ * current implementation is in step 3.
+ */ 
 
     HWND      hwndDialog;
     BOOL      bRet = FALSE;
@@ -156,7 +165,7 @@
                                 LoadIconA(COMDLG32_hInstance, "PD32_NOCOLLATE");
     if (PrintStructures.hCollateIcon==0 || PrintStructures.hNoCollateIcon==0)
     {
-    puts("Error: no icon?");
+    ERR("no icon in resourcefile???");
 	COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE);
 	return FALSE;
     }
@@ -177,23 +186,6 @@
     else
     	PrintStructures.HelpMessageID=0;
 	
-	/*
-	 * if lppd->Flags PD_RETURNDEFAULT is specified, the PrintDlg function
-	 * does not display the dialog box, but returns with valid entries
-	 * for hDevMode and hDevNames .
-	 * 
-	 * Currently the flag is recognised, but we return empty hDevMode and
-	 * and hDevNames. This will be fixed when I am in step 3.
-	 */
-	if (lppd->Flags & PD_RETURNDEFAULT)
-	   {
-	    WARN(": PrintDlg was requested to return printer info only."
-					  "\n The return value currently does NOT provide these.\n");
-		COMDLG32_SetCommDlgExtendedError(PDERR_NODEVICES); 
-        								/* return TRUE, thus never checked! */
-	    return(TRUE);
-	   }
-	   
 	if (lppd->Flags & PD_PRINTSETUP)
 		{
 		 FIXME(": PrintDlg was requested to display PrintSetup box.\n");
@@ -216,10 +208,16 @@
 
     /* Find the default printer.
      * If not: display a warning message (unless PD_NOWARNING specified)
+     * and return PDERR_NODEFAULTPRN
      */
+    /* FIXME: not implemented yet!!! */
+    PrintStructures.CurrentPrinter=0; 
+    PrintStructures.DefaultPrinter=0; 
+     
     /* FIXME: Currently Unimplemented */
     if (lppd->Flags & PD_NOWARNING)	
 	   {
+	    COMDLG32_SetCommDlgExtendedError(PDERR_INITFAILURE); 
 	    WARN(": PD_NOWARNING Flag is not yet implemented.\n");
 	   }
     	
@@ -232,16 +230,39 @@
 			  PD_ENABLESETUPTEMPLATE|PD_ENABLESETUPTEMPLATEHANDLE)) 
     	FIXME(": unimplemented flag (ignored)\n");     
 	
-		
+    /*
+     * if lppd->Flags PD_RETURNDEFAULT is specified, the PrintDlg function
+     * does not display the dialog box, but returns with valid entries
+     * for hDevMode and hDevNames .
+     *
+     * According to MSDN, it is required that hDevMode and hDevNames equal
+     * zero if this flag is set.
+     */
+    if (lppd->Flags & PD_RETURNDEFAULT)
+       {
+	TRACE(" PD_RETURNDEFAULT: was requested to return printer info only.\n");
+        if (lppd->hDevMode!=0 || lppd->hDevNames !=0)
+            {
+     	     COMDLG32_SetCommDlgExtendedError(PDERR_INITFAILURE); 
+             return(FALSE);
+            }
+        return(PRINTDLG_ValidateAndDuplicateSettings(0, &PrintStructures));
+       }
+	
+    /* and create & process the dialog 
+     */	
     hwndDialog= DIALOG_CreateIndirect(hInst, ptr, TRUE, lppd->hwndOwner,
             (DLGPROC16)PrintDlgProcA, (LPARAM)&PrintStructures, WIN_PROC_32A );
     if (hwndDialog) 
         bRet = DIALOG_DoDialogBox(hwndDialog, lppd->hwndOwner);  
-        
+     
+    /* free memory & resources
+     */   
     free(PrintStructures.lpPrinterInfo);
     DeleteObject(PrintStructures.hCollateIcon);
     DeleteObject(PrintStructures.hNoCollateIcon);
-        
+
+  TRACE(" exit! (%d)", bRet);        
   return bRet;            
 }
 
@@ -262,21 +283,12 @@
  */
 static void PRINTDLG_UpdatePrinterInfoTexts(HWND hDlg, PRINT_PTRA* PrintStructures)
 {
-	char   PrinterName[256];
     char   StatusMsg[256];
     char   ResourceString[256];
     int    i;
-    LPPRINTER_INFO_2A lpPi = NULL;
-	GetDlgItemTextA(hDlg, cmb4, PrinterName, 255);
-             
-    /* look the selected PrinterName up in our array Printer_Info2As*/
-    for (i=0; i < PrintStructures->NrOfPrinterInfoEntries; i++)
-    	{
-         lpPi = &PrintStructures->lpPrinterInfo[i];
-         if (strcmp(lpPi->pPrinterName, PrinterName)==0)
-         break;
-        }
-        
+    LPPRINTER_INFO_2A lpPi = &(PrintStructures->lpPrinterInfo
+                                             [PrintStructures->CurrentPrinter]);
+                                             
     /* Status Message */
     StatusMsg[0]='\0';
     for (i=0; i< 25; i++)
@@ -310,9 +322,10 @@
 static LRESULT PRINTDLG_WMInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam,
 				     PRINT_PTRA* PrintStructures)
 {
- int         i;
- LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
- LPPRINTER_INFO_2A lppi = PrintStructures->lpPrinterInfo;
+ int               i;
+ LPPRINTDLGA       lppd     = PrintStructures->lpPrintDlg;
+ LPPRINTER_INFO_2A lppi     = PrintStructures->lpPrinterInfo;
+ PDEVMODEA	   pDevMode = lppi[PrintStructures->CurrentPrinter].pDevMode; 
  
 	SetWindowLongA(hDlg, DWL_USER, lParam); 
 	TRACE("WM_INITDIALOG lParam=%08lX\n", lParam);
@@ -325,12 +338,18 @@
 */	}
 
 /* Fill Combobox according to info from PRINTER_INFO2A
- * structure inside PrintStructures and generate an
+ * structure inside PrintStructures,
+ * select the default printer and generate an
  * update-message to have the rest of the dialog box updated.
  */ 
     for (i=0; i < PrintStructures->NrOfPrinterInfoEntries; i++)
 	   SendDlgItemMessageA(hDlg, cmb4, CB_ADDSTRING, 0,
-                        (LPARAM)lppi[i].pPrinterName );  
+                        (LPARAM)lppi[i].pPrinterName );
+    i=SendDlgItemMessageA(hDlg, cmb4, CB_SELECTSTRING, 
+        (WPARAM) -1,
+        (LPARAM) lppi[PrintStructures->CurrentPrinter].pPrinterName);
+    SendDlgItemMessageA(hDlg, cmb4, CB_SETCURSEL, 
+        (WPARAM)i, (LPARAM)0);
     PRINTDLG_UpdatePrinterInfoTexts(hDlg, PrintStructures);
 
 /* Flag processing to set the according buttons on/off and
@@ -381,9 +400,8 @@
      char        result[64];
      LoadStringA(COMDLG32_hInstance, PD32_PRINT_ALL_X_PAGES, 
                 resourcestr, 49);
-     sprintf(result,resourcestr,lppd->nMaxPage-lppd->nMinPage);                
-     SendDlgItemMessageA(hDlg, rad1, WM_SETTEXT, 0, 
-                        (LPARAM) result);
+     sprintf(result,resourcestr,lppd->nMaxPage - lppd->nMinPage + 1);
+     SendDlgItemMessageA(hDlg, rad1, WM_SETTEXT, 0, (LPARAM) result);
     }
         
     /* Collate pages 
@@ -402,29 +420,120 @@
                                     (LPARAM)PrintStructures->hNoCollateIcon);
    	    CheckDlgButton(hDlg, chx2, 0);
        }
+       
+    if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE ||
+        lppd->Flags & PD_USEDEVMODECOPIES)
+	{
+	 /* if printer doesn't support it: no Collate */
+	 if (!(pDevMode->dmFields & DM_COLLATE))
+	    {
+		EnableWindow(GetDlgItem(hDlg, chx2), FALSE);    
+		EnableWindow(GetDlgItem(hDlg, ico3), FALSE);    
+	    }
+	}
         
+    /* nCopies */
+    if (lppd->hDevMode == 0)
+    	{
+         SetDlgItemInt(hDlg, edt3, lppd->nCopies, FALSE);
+	}
+    else
+        {
+         SetDlgItemInt(hDlg, edt1, pDevMode->dmCopies, FALSE);
+	}
+    if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE ||
+        lppd->Flags & PD_USEDEVMODECOPIES)
+	{
+	 /* if printer doesn't support it: no nCopies */
+	 if (!(pDevMode->dmFields & DM_COPIES))
+	    {
+		EnableWindow(GetDlgItem(hDlg, edt3), FALSE);    
+		EnableWindow(GetDlgItem(hDlg, stc5), FALSE);    
+	    }
+	}
+
     /* print to file */
    	CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0);
     if (lppd->Flags & PD_DISABLEPRINTTOFILE)
 		EnableWindow(GetDlgItem(hDlg, chx1), FALSE);    
     if (lppd->Flags & PD_HIDEPRINTTOFILE)
 		ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE);
-    
+
     /* help button */
 	if ((lppd->Flags & PD_SHOWHELP)==0)
     	{	/* hide if PD_SHOWHELP not specified */
 		 ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE);         
         }
 
+  GlobalUnlock(lppd->hDevMode);
   return TRUE;
 }
 
 
+
+/***********************************************************************
+ *             PRINTDLG_CreateDevNames          [internal]
+ *
+ *
+ *   creates a DevNames structure.
+ * RETURNS
+ *   HGLOBAL to DevNames memory object on success or
+ *   zero on faillure
+ */
+HGLOBAL PRINTDLG_CreateDevNames(
+                    char* DeviceDriverName, 
+                    char* DeviceName, 
+                    char* OutputPort, 
+                    WORD  Flags)
+{
+    long size;
+    HGLOBAL hDevNames;
+    void*   pDevNamesSpace;
+    void*   pTempPtr;
+    LPDEVNAMES lpDevNames;
+    
+    size = strlen(DeviceDriverName) +1
+            + strlen(DeviceName) + 1
+            + strlen(OutputPort) + 1
+            + sizeof(DEVNAMES);
+            
+    hDevNames = GlobalAlloc(GMEM_MOVEABLE, size*sizeof(char));
+    if (hDevNames != 0)
+    {
+        pDevNamesSpace = GlobalLock(hDevNames);
+        lpDevNames = (LPDEVNAMES) pDevNamesSpace;
+        
+        pTempPtr = pDevNamesSpace + sizeof(DEVNAMES);
+        strcpy(pTempPtr, DeviceDriverName);
+        lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace;
+        
+        pTempPtr += strlen(DeviceDriverName) + 1;
+        strcpy(pTempPtr, DeviceName);
+        lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace;
+        
+        pTempPtr += strlen(DeviceName) + 1;
+        strcpy(pTempPtr, OutputPort);
+        lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace;
+        
+        lpDevNames->wDefault = Flags;
+        
+        GlobalUnlock(hDevNames);
+    }
+    return(hDevNames);
+}
+            
+    
+           
+    
 /***********************************************************************
  *             PRINTDLG_ValidateAndDuplicateSettings          [internal]
  *
  *
  *   updates the PrintDlg structure for returnvalues.
+ *   (yep, the name was chosen a bit stupid...)
+ *
+ *   if hDlg equals zero, only hDevModes and hDevNames are adapted.
+ *      
  * RETURNS
  *   FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values)
  *   TRUE  if succesful.
@@ -432,8 +541,13 @@
 static BOOL PRINTDLG_ValidateAndDuplicateSettings(HWND hDlg, 
 						  PRINT_PTRA* PrintStructures)
 {
- LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
+ LPPRINTER_INFO_2A lpPi = &(PrintStructures->lpPrinterInfo
+                                             [PrintStructures->CurrentPrinter]);
+ LPPRINTDLGA       lppd = PrintStructures->lpPrintDlg;
+ PDEVMODEA         pDevMode;
  
+ if (hDlg!=0)
+ {
     /* check whether nFromPage and nToPage are within range defined by
      * nMinPage and nMaxPage
      */
@@ -460,16 +574,92 @@
         lppd->nToPage   = nToPage;
     }
      
+    
     if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED)
        {
         lppd->Flags |= PD_PRINTTOFILE;
-        /* FIXME: insert code to set "FILE:" in DEVNAMES structure */
+        lpPi->pPortName = "FILE:";
        }
-       
+
     if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
        {
         FIXME("Collate lppd not yet implemented as output\n");
        }
+ } /* end-of-if(hDlg!=0) */
+
+    /* 
+     * create or modify hDevMode 
+     */     
+    if (lppd->hDevMode == 0)
+       {
+        TRACE(" No hDevMode yet... Need to create my own\n");
+        /* FIXME: possible memory leak? Memory never freed again! */
+        lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, lpPi->pDevMode->dmSize);
+        pDevMode    = GlobalLock(lppd->hDevMode);
+        memcpy(pDevMode, lpPi->pDevMode, lpPi->pDevMode->dmSize);
+       }
+    else
+       {
+        FIXME(" already hDevMode... must adjust it... Not implemented yet\n");
+        pDevMode    = GlobalLock(lppd->hDevMode);
+       }
+              
+    /* If hDevNames already exists, trash it.
+     * But create a new one anyway
+     */
+    if (lppd->hDevNames != 0)
+       {
+        if ( (GlobalFlags(lppd->hDevNames)&0xFF) != 0)
+	    ERR(" Tried to free hDevNames, but your application still has a"
+	    	" lock on hDevNames. Possible program crash...");
+        GlobalFree(lppd->hDevNames);
+       }
+    /* FIXME: The first entry  of DevNames is fixed to "winspool", 
+     * because I don't know of any printerdriver which doesn't return 
+     * winspool there. But I guess they do exist... 
+     */
+    lppd->hDevNames = PRINTDLG_CreateDevNames("winspool",
+                      lpPi->pDriverName, lpPi->pPortName, 
+		      (PrintStructures->DefaultPrinter ==
+		                PrintStructures->CurrentPrinter)?1:0);
+
+    /* set PD_Collate and nCopies */
+    if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE ||
+        lppd->Flags & PD_USEDEVMODECOPIES)
+        {
+	 /* if one of the above flags was set, the application doesn't
+	   * (want to) support multiple copies or collate...
+	   */
+	 lppd->Flags &= ~PD_COLLATE;
+	 lppd->nCopies = 1;
+	  /* if the printer driver supports it... store info there
+	   * otherwise no collate & multiple copies !
+	   */
+         if (pDevMode->dmFields & DM_COLLATE)
+	   {
+	    if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
+	    	pDevMode->dmCollate = 1;	 
+	    else
+	    	pDevMode->dmCollate = 0;
+	   }
+         if (pDevMode->dmFields & DM_COPIES)
+	    {
+	     WORD nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
+	     pDevMode->dmCopies = nCopies; 	 
+	    }
+	}
+    else
+        {
+	 /* set Collate & nCopies according to dialog */
+         if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED)
+	    lppd->Flags |= PD_COLLATE;
+	 else
+	    lppd->Flags &= ~PD_COLLATE;
+	 lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE);
+	}
+
+
+    GlobalUnlock(lppd->hDevMode);
 
  return(TRUE);   
 }
@@ -482,6 +672,9 @@
 			LPARAM lParam, PRINT_PTRA* PrintStructures)
 {
     LPPRINTDLGA lppd = PrintStructures->lpPrintDlg;
+    LPPRINTER_INFO_2A lppi = &(PrintStructures->lpPrinterInfo
+                                        [PrintStructures->CurrentPrinter]);
+    
 
     switch (LOWORD(wParam)) 
     {
@@ -536,12 +729,54 @@
         }
      case cmb4:                         /* Printer combobox */
         if (HIWORD(wParam)==CBN_SELCHANGE)
-			PRINTDLG_UpdatePrinterInfoTexts(hDlg, PrintStructures);
+           {
+            int i;
+        	char   PrinterName[256];
+
+            /* look the newly selected Printer up in 
+             * our array Printer_Info2As
+             */
+        	GetDlgItemTextA(hDlg, cmb4, PrinterName, 255);
+            for (i=0; i < PrintStructures->NrOfPrinterInfoEntries; i++)
+           	   {
+                if (strcmp(PrintStructures->lpPrinterInfo[i].pPrinterName, 
+                           PrinterName)==0)
+                     break;
+               }
+            PrintStructures->CurrentPrinter = i;   
+	    PRINTDLG_UpdatePrinterInfoTexts(hDlg, PrintStructures);
+	    lppi = &(PrintStructures->lpPrinterInfo
+                                       [PrintStructures->CurrentPrinter]);
+            if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE ||
+                lppd->Flags & PD_USEDEVMODECOPIES)
+        	{
+	         /* if printer doesn't support it: no nCopies */
+	 	 if (!(lppi->pDevMode->dmFields & DM_COPIES))
+		    {
+			EnableWindow(GetDlgItem(hDlg, edt3), FALSE);    
+			EnableWindow(GetDlgItem(hDlg, stc5), FALSE);    
+		    }
+		 else
+		    {
+			EnableWindow(GetDlgItem(hDlg, edt3), TRUE);    
+			EnableWindow(GetDlgItem(hDlg, stc5), TRUE);    
+		    }
+	         /* if printer doesn't support it: no Collate */
+	 	 if (!(lppi->pDevMode->dmFields & DM_COPIES))
+		    {
+			EnableWindow(GetDlgItem(hDlg, ico3), FALSE);    
+			EnableWindow(GetDlgItem(hDlg, chx2), FALSE);    
+		    }
+		 else
+		    {
+			EnableWindow(GetDlgItem(hDlg, ico3), TRUE);
+			EnableWindow(GetDlgItem(hDlg, chx2), TRUE);
+		    }
+		}
+
+           }
         break;
-/*     default:
-        printf("wParam: 0x%x  ",wParam);
-        break;
-*/    }
+    }
     return FALSE;
 }    
 
@@ -569,8 +804,6 @@
       TRACE("PRINTDLG_WMInitDialog returned FALSE\n");
       return FALSE;
     }  
-    MessageBoxA(hDlg,"Warning: this dialog has no functionality yet!", 
-    			NULL, MB_OK);
   }
   switch (uMsg)
   {
diff --git a/include/commdlg.h b/include/commdlg.h
index 2b6f3d8..37c655e 100644
--- a/include/commdlg.h
+++ b/include/commdlg.h
@@ -506,6 +506,7 @@
 #define PD_ENABLEPRINTTEMPLATEHANDLE 0x00010000
 #define PD_ENABLESETUPTEMPLATEHANDLE 0x00020000
 #define PD_USEDEVMODECOPIES          0x00040000
+#define PD_USEDEVMODECOPIESANDCOLLATE 0x00040000
 #define PD_DISABLEPRINTTOFILE        0x00080000
 #define PD_HIDEPRINTTOFILE           0x00100000