Back to index

lightning-sunbird  0.9+nobinonly
nsDeviceContextSpecWin.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsDeviceContextSpecWin.h"
00039 #include "prmem.h"
00040 #include <winspool.h>
00041 #include <tchar.h>
00042 
00043 #include "nsVoidArray.h"
00044 #include "nsIPrintSettingsWin.h"
00045 
00046 #include "nsString.h"
00047 #include "nsCRT.h"
00048 #include "nsIServiceManager.h"
00049 #include "nsReadableUtils.h"
00050 #include "nsGfxCIID.h"
00051 
00052 #include "nsIWindowWatcher.h"
00053 #include "nsIDOMWindow.h"
00054 
00055 // For NS_CopyNativeToUnicode
00056 #include "nsNativeCharsetUtils.h"
00057 
00058 // File Picker
00059 #include "nsILocalFile.h"
00060 #include "nsIFile.h"
00061 #include "nsIFilePicker.h"
00062 #include "nsIStringBundle.h"
00063 #define NS_ERROR_GFX_PRINTER_BUNDLE_URL "chrome://global/locale/printing.properties"
00064 
00065 #include "prlog.h"
00066 #ifdef PR_LOGGING 
00067 extern PRLogModuleInfo * kGfxPrintingLogMod;
00068 #define PR_PL(_p1)  PR_LOG(kGfxPrintingLogMod, PR_LOG_DEBUG, _p1)
00069 #else
00070 #define PR_PL(_p1)
00071 #endif
00072 
00073 //-----------------------------------------------
00074 // Global Data
00075 //-----------------------------------------------
00076 static HWND gParentWnd = NULL;
00077 
00078 //----------------------------------------------------------------------------------
00079 // The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
00080 // The PrinterEnumerator creates the printer info
00081 // but the nsDeviceContextSpecWin cleans it up
00082 // If it gets created (via the Page Setup Dialog) but the user never prints anything
00083 // then it will never be delete, so this class takes care of that.
00084 class GlobalPrinters {
00085 public:
00086   static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
00087   ~GlobalPrinters() { FreeGlobalPrinters(); }
00088 
00089   void FreeGlobalPrinters();
00090 
00091   PRBool       PrintersAreAllocated() { return mPrinters != nsnull; }
00092   LPTSTR       GetItemFromList(PRInt32 aInx) { return mPrinters?(LPTSTR)mPrinters->ElementAt(aInx):nsnull; }
00093   nsresult     EnumeratePrinterList();
00094   void         GetDefaultPrinterName(LPTSTR& aDefaultPrinterName);
00095   PRInt32      GetNumPrinters() { return mPrinters?mPrinters->Count():0; }
00096 
00097 protected:
00098   GlobalPrinters() {}
00099   nsresult EnumerateNativePrinters();
00100   void     ReallocatePrinters();
00101 
00102   static GlobalPrinters mGlobalPrinters;
00103   static nsVoidArray*   mPrinters;
00104 };
00105 //---------------
00106 // static members
00107 GlobalPrinters GlobalPrinters::mGlobalPrinters;
00108 nsVoidArray*   GlobalPrinters::mPrinters = nsnull;
00109 
00110 
00111 //******************************************************
00112 // Define native paper sizes
00113 //******************************************************
00114 typedef struct {
00115   short  mPaperSize; // native enum
00116   double mWidth;
00117   double mHeight;
00118   PRBool mIsInches;
00119 } NativePaperSizes;
00120 
00121 // There are around 40 default print sizes defined by Windows
00122 const NativePaperSizes kPaperSizes[] = {
00123   {DMPAPER_LETTER,    8.5,   11.0,  PR_TRUE},
00124   {DMPAPER_LEGAL,     8.5,   14.0,  PR_TRUE},
00125   {DMPAPER_A4,        210.0, 297.0, PR_FALSE},
00126   {DMPAPER_B4,        250.0, 354.0, PR_FALSE}, 
00127   {DMPAPER_B5,        182.0, 257.0, PR_FALSE},
00128 #ifndef WINCE
00129   {DMPAPER_TABLOID,   11.0,  17.0,  PR_TRUE},
00130   {DMPAPER_LEDGER,    17.0,  11.0,  PR_TRUE},
00131   {DMPAPER_STATEMENT, 5.5,   8.5,   PR_TRUE},
00132   {DMPAPER_EXECUTIVE, 7.25,  10.5,  PR_TRUE},
00133   {DMPAPER_A3,        297.0, 420.0, PR_FALSE},
00134   {DMPAPER_A5,        148.0, 210.0, PR_FALSE},
00135   {DMPAPER_CSHEET,    17.0,  22.0,  PR_TRUE},  
00136   {DMPAPER_DSHEET,    22.0,  34.0,  PR_TRUE},  
00137   {DMPAPER_ESHEET,    34.0,  44.0,  PR_TRUE},  
00138   {DMPAPER_LETTERSMALL, 8.5, 11.0,  PR_TRUE},  
00139   {DMPAPER_A4SMALL,   210.0, 297.0, PR_FALSE}, 
00140   {DMPAPER_FOLIO,     8.5,   13.0,  PR_TRUE},
00141   {DMPAPER_QUARTO,    215.0, 275.0, PR_FALSE},
00142   {DMPAPER_10X14,     10.0,  14.0,  PR_TRUE},
00143   {DMPAPER_11X17,     11.0,  17.0,  PR_TRUE},
00144   {DMPAPER_NOTE,      8.5,   11.0,  PR_TRUE},  
00145   {DMPAPER_ENV_9,     3.875, 8.875, PR_TRUE},  
00146   {DMPAPER_ENV_10,    40.125, 9.5,  PR_TRUE},  
00147   {DMPAPER_ENV_11,    4.5,   10.375, PR_TRUE},  
00148   {DMPAPER_ENV_12,    4.75,  11.0,  PR_TRUE},  
00149   {DMPAPER_ENV_14,    5.0,   11.5,  PR_TRUE},  
00150   {DMPAPER_ENV_DL,    110.0, 220.0, PR_FALSE}, 
00151   {DMPAPER_ENV_C5,    162.0, 229.0, PR_FALSE}, 
00152   {DMPAPER_ENV_C3,    324.0, 458.0, PR_FALSE}, 
00153   {DMPAPER_ENV_C4,    229.0, 324.0, PR_FALSE}, 
00154   {DMPAPER_ENV_C6,    114.0, 162.0, PR_FALSE}, 
00155   {DMPAPER_ENV_C65,   114.0, 229.0, PR_FALSE}, 
00156   {DMPAPER_ENV_B4,    250.0, 353.0, PR_FALSE}, 
00157   {DMPAPER_ENV_B5,    176.0, 250.0, PR_FALSE}, 
00158   {DMPAPER_ENV_B6,    176.0, 125.0, PR_FALSE}, 
00159   {DMPAPER_ENV_ITALY, 110.0, 230.0, PR_FALSE}, 
00160   {DMPAPER_ENV_MONARCH,  3.875,  7.5, PR_TRUE},  
00161   {DMPAPER_ENV_PERSONAL, 3.625,  6.5, PR_TRUE},  
00162   {DMPAPER_FANFOLD_US,   14.875, 11.0, PR_TRUE},  
00163   {DMPAPER_FANFOLD_STD_GERMAN, 8.5, 12.0, PR_TRUE},  
00164   {DMPAPER_FANFOLD_LGL_GERMAN, 8.5, 13.0, PR_TRUE},  
00165 #endif // WINCE
00166 };
00167 const PRInt32 kNumPaperSizes = 41;
00168 
00169 //----------------------------------------------------------------------------------
00170 nsDeviceContextSpecWin::nsDeviceContextSpecWin()
00171 {
00172   mDriverName    = nsnull;
00173   mDeviceName    = nsnull;
00174   mDevMode       = NULL;
00175 
00176 }
00177 
00178 
00179 //----------------------------------------------------------------------------------
00180 NS_IMPL_ISUPPORTS1(nsDeviceContextSpecWin, nsIDeviceContextSpec)
00181 
00182 nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
00183 {
00184   SetDeviceName(nsnull);
00185   SetDriverName(nsnull);
00186   SetDevMode(NULL);
00187 
00188   nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
00189   if (psWin) {
00190     psWin->SetDeviceName(nsnull);
00191     psWin->SetDriverName(nsnull);
00192     psWin->SetDevMode(NULL);
00193   }
00194 
00195   // Free them, we won't need them for a while
00196   GlobalPrinters::GetInstance()->FreeGlobalPrinters();
00197 }
00198 
00199 
00200 //------------------------------------------------------------------
00201 // helper
00202 static PRUnichar * GetDefaultPrinterNameFromGlobalPrinters()
00203 {
00204   PRUnichar * printerName;
00205   LPTSTR lpPrtName;
00206   GlobalPrinters::GetInstance()->GetDefaultPrinterName(lpPrtName);
00207   nsAutoString str;
00208   NS_CopyNativeToUnicode(nsDependentCString((char *)lpPrtName), str);
00209   printerName = ToNewUnicode(str);
00210   free(lpPrtName);
00211   return printerName;
00212 }
00213 
00214 //----------------------------------------------------------------
00215 static nsresult 
00216 EnumerateNativePrinters(DWORD aWhichPrinters, LPTSTR aPrinterName, PRBool& aIsFound, PRBool& aIsFile)
00217 {
00218 #ifdef WINCE
00219   aIsFound = PR_FALSE;
00220 #else
00221   DWORD             dwSizeNeeded = 0;
00222   DWORD             dwNumItems   = 0;
00223   LPPRINTER_INFO_2  lpInfo        = NULL;
00224 
00225   // Get buffer size
00226   if (::EnumPrinters ( aWhichPrinters, NULL, 2, NULL, 0, &dwSizeNeeded, &dwNumItems )) {
00227     return NS_ERROR_FAILURE;
00228   }
00229 
00230   // allocate memory
00231   lpInfo = (LPPRINTER_INFO_2)HeapAlloc ( GetProcessHeap (), HEAP_ZERO_MEMORY, dwSizeNeeded );
00232   if ( lpInfo == NULL ) {
00233     return NS_ERROR_OUT_OF_MEMORY;
00234   }
00235 
00236   if (::EnumPrinters ( PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)lpInfo, dwSizeNeeded, &dwSizeNeeded, &dwNumItems) == 0 ) {
00237     ::HeapFree(GetProcessHeap (), 0, lpInfo);
00238     return NS_OK;
00239   }
00240 
00241 
00242   for (DWORD i = 0; i < dwNumItems; i++ ) {
00243     if (_tcscmp(lpInfo[i].pPrinterName, aPrinterName) == 0) {
00244       aIsFound = PR_TRUE;
00245       aIsFile  = _tcscmp(lpInfo[i].pPortName, _T("FILE:")) == 0;
00246       break;
00247     }
00248   }
00249 
00250   ::HeapFree(GetProcessHeap (), 0, lpInfo);
00251 #endif
00252   return NS_OK;
00253 }
00254 
00255 //----------------------------------------------------------------
00256 static void 
00257 CheckForPrintToFileWithName(LPTSTR aPrinterName, PRBool& aIsFile)
00258 {
00259   PRBool isFound = PR_FALSE;
00260   aIsFile = PR_FALSE;
00261 #ifndef WINCE
00262   nsresult rv = EnumerateNativePrinters(PRINTER_ENUM_LOCAL, aPrinterName, isFound, aIsFile);
00263   if (isFound) return;
00264 
00265   rv = EnumerateNativePrinters(PRINTER_ENUM_NETWORK, aPrinterName, isFound, aIsFile);
00266   if (isFound) return;
00267 
00268   rv = EnumerateNativePrinters(PRINTER_ENUM_SHARED, aPrinterName, isFound, aIsFile);
00269   if (isFound) return;
00270 
00271   rv = EnumerateNativePrinters(PRINTER_ENUM_REMOTE, aPrinterName, isFound, aIsFile);
00272   if (isFound) return;
00273 #endif
00274 }
00275 
00276 static nsresult 
00277 GetFileNameForPrintSettings(nsIPrintSettings* aPS)
00278 {
00279   // for testing
00280 #ifdef DEBUG_rods
00281   return NS_OK;
00282 #endif
00283 
00284   nsresult rv;
00285 
00286   nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1", &rv);
00287   NS_ENSURE_SUCCESS(rv, rv);
00288 
00289   nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00290   NS_ENSURE_SUCCESS(rv, rv);
00291   nsCOMPtr<nsIStringBundle> bundle;
00292   rv = bundleService->CreateBundle(NS_ERROR_GFX_PRINTER_BUNDLE_URL, getter_AddRefs(bundle));
00293   NS_ENSURE_SUCCESS(rv, rv);
00294 
00295   nsXPIDLString title;
00296   rv = bundle->GetStringFromName(NS_LITERAL_STRING("PrintToFile").get(), getter_Copies(title));
00297   NS_ENSURE_SUCCESS(rv, rv);
00298 
00299   nsCOMPtr<nsIWindowWatcher> wwatch =
00300     (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
00301   NS_ENSURE_SUCCESS(rv, rv);
00302 
00303   nsCOMPtr<nsIDOMWindow> window;
00304   wwatch->GetActiveWindow(getter_AddRefs(window));
00305 
00306   rv = filePicker->Init(window, title, nsIFilePicker::modeSave);
00307   NS_ENSURE_SUCCESS(rv, rv);
00308  
00309   rv = filePicker->AppendFilters(nsIFilePicker::filterAll);
00310   NS_ENSURE_SUCCESS(rv, rv);
00311 
00312   PRUnichar* fileName;
00313   aPS->GetToFileName(&fileName);
00314 
00315   if (fileName) {
00316     if (*fileName) {
00317       nsAutoString leafName;
00318       nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
00319       if (file) {
00320         rv = file->InitWithPath(nsDependentString(fileName));
00321         if (NS_SUCCEEDED(rv)) {
00322           file->GetLeafName(leafName);
00323           filePicker->SetDisplayDirectory(file);
00324         }
00325       }
00326       if (!leafName.IsEmpty()) {
00327         rv = filePicker->SetDefaultString(leafName);
00328       }
00329       NS_ENSURE_SUCCESS(rv, rv);
00330     }
00331     nsMemory::Free(fileName);
00332   }
00333 
00334   PRInt16 dialogResult;
00335   filePicker->Show(&dialogResult);
00336 
00337   if (dialogResult == nsIFilePicker::returnCancel) {
00338     return NS_ERROR_ABORT;
00339   }
00340 
00341   nsCOMPtr<nsILocalFile> localFile;
00342   rv = filePicker->GetFile(getter_AddRefs(localFile));
00343   NS_ENSURE_SUCCESS(rv, rv);
00344   
00345   if (dialogResult == nsIFilePicker::returnReplace) {
00346     // be extra safe and only delete when the file is really a file
00347     PRBool isFile;
00348     rv = localFile->IsFile(&isFile);
00349     if (NS_SUCCEEDED(rv) && isFile) {
00350       rv = localFile->Remove(PR_FALSE /* recursive delete */);
00351       NS_ENSURE_SUCCESS(rv, rv);
00352     }
00353   }
00354 
00355   nsAutoString unicodePath;
00356   rv = localFile->GetPath(unicodePath);
00357   NS_ENSURE_SUCCESS(rv,rv);
00358 
00359   if (unicodePath.IsEmpty()) {
00360     rv = NS_ERROR_ABORT;
00361   }
00362 
00363   if (NS_SUCCEEDED(rv)) aPS->SetToFileName(unicodePath.get());
00364 
00365   return rv;
00366 }
00367 
00368 //----------------------------------------------------------------------------------
00369 static nsresult
00370 CheckForPrintToFile(nsIPrintSettings* aPS, LPTSTR aPrinterName, PRUnichar* aUPrinterName)
00371 {
00372   nsresult rv = NS_OK;
00373 
00374   if (!aPrinterName && !aUPrinterName) return rv;
00375 
00376   PRBool toFile;
00377 #ifdef UNICODE
00378   CheckForPrintToFileWithName(aPrinterName?aPrinterName:aUPrinterName, toFile);
00379 #else
00380   if (aPrinterName) {
00381     CheckForPrintToFileWithName(aPrinterName, toFile);
00382   } else {
00383     nsCAutoString nativeName;
00384     NS_CopyUnicodeToNative(nsDependentString(aUPrinterName), nativeName);
00385     CheckForPrintToFileWithName(NS_CONST_CAST(char*, nativeName.get()), toFile);
00386   }
00387 #endif
00388   // Since the driver wasn't a "Print To File" Driver, check to see
00389   // if the name of the file has been set to the special "FILE:"
00390   if (!toFile) {
00391     nsXPIDLString toFileName;
00392     aPS->GetToFileName(getter_Copies(toFileName));
00393     if (toFileName) {
00394       if (*toFileName) {
00395         if (toFileName.EqualsLiteral("FILE:")) {
00396           // this skips the setting of the "print to file" info below
00397           // which we don't want to do.
00398           return NS_OK; 
00399         }
00400       }
00401     }
00402   }
00403   aPS->SetPrintToFile(toFile);
00404   if (toFile) {
00405     rv = GetFileNameForPrintSettings(aPS);
00406   }
00407   return rv;
00408 }
00409 
00410 //----------------------------------------------------------------------------------
00411 NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget, 
00412                                            nsIPrintSettings* aPrintSettings,
00413                                            PRBool aIsPrintPreview)
00414 {
00415   mPrintSettings = aPrintSettings;
00416 
00417   gParentWnd = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
00418 
00419   nsresult rv = NS_ERROR_FAILURE;
00420   if (aPrintSettings) {
00421     nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
00422     if (psWin) {
00423       char* deviceName;
00424       char* driverName;
00425       psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
00426       psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
00427 
00428       LPDEVMODE devMode;
00429       psWin->GetDevMode(&devMode);       // creates new memory (makes a copy)
00430 
00431       if (deviceName && driverName && devMode) {
00432         // Scaling is special, it is one of the few
00433         // devMode items that we control in layout
00434         if (devMode->dmFields & DM_SCALE) {
00435           double scale = double(devMode->dmScale) / 100.0f;
00436           if (scale != 1.0) {
00437             aPrintSettings->SetScaling(scale);
00438             devMode->dmScale = 100;
00439           }
00440         }
00441 
00442         SetDeviceName(deviceName);
00443         SetDriverName(driverName);
00444         SetDevMode(devMode);
00445 
00446         if (!aIsPrintPreview) {
00447           rv = CheckForPrintToFile(mPrintSettings, deviceName, nsnull);
00448           if (NS_FAILED(rv)) {
00449             nsCRT::free(deviceName);
00450             nsCRT::free(driverName);
00451             return NS_ERROR_FAILURE;
00452           }
00453         }
00454 
00455         // clean up
00456         nsCRT::free(deviceName);
00457         nsCRT::free(driverName);
00458 
00459         return NS_OK;
00460       } else {
00461         PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
00462         if (deviceName) nsCRT::free(deviceName);
00463         if (driverName) nsCRT::free(driverName);
00464         if (devMode) ::HeapFree(::GetProcessHeap(), 0, devMode);
00465       }
00466     }
00467   } else {
00468     PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
00469   }
00470 
00471   LPDEVMODE pDevMode  = NULL;
00472   HGLOBAL   hDevNames = NULL;
00473 
00474   // Get the Print Name to be used
00475   PRUnichar * printerName;
00476   mPrintSettings->GetPrinterName(&printerName);
00477 
00478   // If there is no name then use the default printer
00479   if (!printerName || (printerName && !*printerName)) {
00480     printerName = GetDefaultPrinterNameFromGlobalPrinters();
00481   }
00482 
00483   NS_ASSERTION(printerName, "We have to have a printer name");
00484   if (!printerName || !*printerName) return NS_ERROR_FAILURE;
00485 
00486   if (!aIsPrintPreview) {
00487     CheckForPrintToFile(mPrintSettings, nsnull, printerName);
00488   }
00489  
00490   return GetDataFromPrinter(printerName, mPrintSettings);
00491 }
00492 
00493 //----------------------------------------------------------
00494 // Helper Function - Free and reallocate the string
00495 static void CleanAndCopyString(char*& aStr, char* aNewStr)
00496 {
00497   if (aStr != nsnull) {
00498     if (aNewStr != nsnull && strlen(aStr) > strlen(aNewStr)) { // reuse it if we can
00499       PL_strcpy(aStr, aNewStr);
00500       return;
00501     } else {
00502       PR_Free(aStr);
00503       aStr = nsnull;
00504     }
00505   }
00506 
00507   if (nsnull != aNewStr) {
00508     aStr = (char *)PR_Malloc(PL_strlen(aNewStr) + 1);
00509     PL_strcpy(aStr, aNewStr);
00510   }
00511 }
00512 
00513 //----------------------------------------------------------------------------------
00514 void nsDeviceContextSpecWin::SetDeviceName(char* aDeviceName)
00515 {
00516   CleanAndCopyString(mDeviceName, aDeviceName);
00517 }
00518 
00519 //----------------------------------------------------------------------------------
00520 void nsDeviceContextSpecWin::SetDriverName(char* aDriverName)
00521 {
00522   CleanAndCopyString(mDriverName, aDriverName);
00523 }
00524 
00525 //----------------------------------------------------------------------------------
00526 void nsDeviceContextSpecWin::SetDevMode(LPDEVMODE aDevMode)
00527 {
00528   if (mDevMode) {
00529     ::HeapFree(::GetProcessHeap(), 0, mDevMode);
00530   }
00531 
00532   mDevMode = aDevMode;
00533 }
00534 
00535 //------------------------------------------------------------------
00536 void 
00537 nsDeviceContextSpecWin::GetDevMode(LPDEVMODE &aDevMode)
00538 {
00539   aDevMode = mDevMode;
00540 }
00541 
00542 //----------------------------------------------------------------------------------
00543 // Map an incoming size to a Windows Native enum in the DevMode
00544 static void 
00545 MapPaperSizeToNativeEnum(LPDEVMODE aDevMode,
00546                          PRInt16   aType, 
00547                          double    aW, 
00548                          double    aH)
00549 {
00550 
00551 #ifdef DEBUG_rods
00552   BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
00553   BOOL doingPaperSize   = aDevMode->dmFields & DM_PAPERSIZE;
00554   BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
00555   BOOL doingPaperWidth  = aDevMode->dmFields & DM_PAPERWIDTH;
00556 #endif
00557 
00558   PRBool foundEnum = PR_FALSE;
00559   for (PRInt32 i=0;i<kNumPaperSizes;i++) {
00560     if (kPaperSizes[i].mWidth == aW && kPaperSizes[i].mHeight == aH) {
00561       aDevMode->dmPaperSize = kPaperSizes[i].mPaperSize;
00562       aDevMode->dmFields &= ~DM_PAPERLENGTH;
00563       aDevMode->dmFields &= ~DM_PAPERWIDTH;
00564       aDevMode->dmFields |= DM_PAPERSIZE;
00565       return;
00566     }
00567   }
00568 
00569   short width  = 0;
00570   short height = 0;
00571   if (aType == nsIPrintSettings::kPaperSizeInches) {
00572     width  = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW))) / 10);
00573     height = short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH))) / 10);
00574 
00575   } else if (aType == nsIPrintSettings::kPaperSizeMillimeters) {
00576     width  = short(aW / 10.0);
00577     height = short(aH / 10.0);
00578   } else {
00579     return; // don't set anything
00580   }
00581 
00582   // width and height is in 
00583   aDevMode->dmPaperSize   = 0;
00584   aDevMode->dmPaperWidth  = width;
00585   aDevMode->dmPaperLength = height;
00586 
00587   aDevMode->dmFields |= DM_PAPERSIZE;
00588   aDevMode->dmFields |= DM_PAPERLENGTH;
00589   aDevMode->dmFields |= DM_PAPERWIDTH;
00590 }
00591 
00592 //----------------------------------------------------------------------------------
00593 // Setup Paper Size & Orientation options into the DevMode
00594 // 
00595 static void 
00596 SetupDevModeFromSettings(LPDEVMODE aDevMode, nsIPrintSettings* aPrintSettings)
00597 {
00598   // Setup paper size
00599   if (aPrintSettings) {
00600     PRInt16 type;
00601     aPrintSettings->GetPaperSizeType(&type);
00602     if (type == nsIPrintSettings::kPaperSizeNativeData) {
00603       PRInt16 paperEnum;
00604       aPrintSettings->GetPaperData(&paperEnum);
00605       aDevMode->dmPaperSize = paperEnum;
00606       aDevMode->dmFields &= ~DM_PAPERLENGTH;
00607       aDevMode->dmFields &= ~DM_PAPERWIDTH;
00608       aDevMode->dmFields |= DM_PAPERSIZE;
00609     } else {
00610       PRInt16 unit;
00611       double width, height;
00612       aPrintSettings->GetPaperSizeUnit(&unit);
00613       aPrintSettings->GetPaperWidth(&width);
00614       aPrintSettings->GetPaperHeight(&height);
00615       MapPaperSizeToNativeEnum(aDevMode, unit, width, height);
00616     }
00617 
00618     // Setup Orientation
00619     PRInt32 orientation;
00620     aPrintSettings->GetOrientation(&orientation);
00621     aDevMode->dmOrientation = orientation == nsIPrintSettings::kPortraitOrientation?DMORIENT_PORTRAIT:DMORIENT_LANDSCAPE;
00622     aDevMode->dmFields |= DM_ORIENTATION;
00623 
00624     // Setup Number of Copies
00625     PRInt32 copies;
00626     aPrintSettings->GetNumCopies(&copies);
00627     aDevMode->dmCopies = copies;
00628     aDevMode->dmFields |= DM_COPIES;
00629   }
00630 
00631 }
00632 
00633 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
00634 static void DisplayLastError()
00635 {
00636   LPVOID lpMsgBuf;
00637   DWORD errCode = GetLastError();
00638 
00639   FormatMessage( 
00640       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00641       NULL,
00642       GetLastError(),
00643       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00644       (LPTSTR) &lpMsgBuf,
00645       0,
00646       NULL 
00647   );
00648 
00649   // Display the string.
00650   MessageBox( NULL, (const char *)lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
00651 }
00652 #define DISPLAY_LAST_ERROR DisplayLastError();
00653 #else
00654 #define DISPLAY_LAST_ERROR 
00655 #endif
00656 
00657 //----------------------------------------------------------------------------------
00658 // Setup the object's data member with the selected printer's data
00659 nsresult
00660 nsDeviceContextSpecWin::GetDataFromPrinter(const PRUnichar * aName, nsIPrintSettings* aPS)
00661 {
00662 #ifdef WINCE 
00663   return NS_ERROR_NOT_IMPLEMENTED;
00664 #else
00665   nsresult rv = NS_ERROR_FAILURE;
00666 
00667   if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
00668     rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
00669     if (NS_FAILED(rv)) {
00670       PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
00671       DISPLAY_LAST_ERROR
00672     }
00673     NS_ENSURE_SUCCESS(rv, rv);
00674   }
00675 
00676   HANDLE hPrinter = NULL;
00677   nsCAutoString nativeName;
00678   NS_CopyUnicodeToNative(nsDependentString(aName), nativeName);
00679   BOOL status = ::OpenPrinter(NS_CONST_CAST(char*, nativeName.get()),
00680                               &hPrinter, NULL);
00681   if (status) {
00682 
00683     LPDEVMODE   pDevMode;
00684     DWORD       dwNeeded, dwRet;
00685 
00686     // Allocate a buffer of the correct size.
00687     dwNeeded = ::DocumentProperties(gParentWnd, hPrinter,
00688                                     NS_CONST_CAST(char*, nativeName.get()),
00689                                     NULL, NULL, 0);
00690 
00691     pDevMode = (LPDEVMODE)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
00692     if (!pDevMode) return NS_ERROR_FAILURE;
00693 
00694     // Get the default DevMode for the printer and modify it for our needs.
00695     dwRet = DocumentProperties(gParentWnd, hPrinter, 
00696                                NS_CONST_CAST(char*, nativeName.get()),
00697                                pDevMode, NULL, DM_OUT_BUFFER);
00698 
00699     if (dwRet == IDOK && aPS) {
00700       SetupDevModeFromSettings(pDevMode, aPS);
00701       // Sets back the changes we made to the DevMode into the Printer Driver
00702       dwRet = ::DocumentProperties(gParentWnd, hPrinter,
00703                                    NS_CONST_CAST(char*, nativeName.get()),
00704                                    pDevMode, pDevMode,
00705                                    DM_IN_BUFFER | DM_OUT_BUFFER);
00706     }
00707 
00708     if (dwRet != IDOK) {
00709       ::HeapFree(::GetProcessHeap(), 0, pDevMode);
00710       ::ClosePrinter(hPrinter);
00711       PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", dwRet, dwRet));
00712       DISPLAY_LAST_ERROR
00713       return NS_ERROR_FAILURE;
00714     }
00715 
00716     SetDevMode(pDevMode); // cache the pointer and takes responsibility for the memory
00717 
00718     SetDeviceName(NS_CONST_CAST(char*, nativeName.get()));
00719   
00720     // The driver should be NULL for Win95/Win98
00721     OSVERSIONINFO os;
00722     os.dwOSVersionInfoSize = sizeof(os);
00723     ::GetVersionEx(&os);
00724     if (VER_PLATFORM_WIN32_NT == os.dwPlatformId) {
00725       SetDriverName("WINSPOOL");
00726     } else {
00727       SetDriverName(NULL);
00728     }
00729     ::ClosePrinter(hPrinter);
00730     rv = NS_OK;
00731   } else {
00732     rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
00733     PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", nativeName.get()));
00734     DISPLAY_LAST_ERROR
00735   }
00736   return rv;
00737 #endif // WINCE
00738 }
00739 
00740 //----------------------------------------------------------------------------------
00741 // Setup Paper Size options into the DevMode
00742 // 
00743 // When using a data member it may be a HGLOCAL or LPDEVMODE
00744 // if it is a HGLOBAL then we need to "lock" it to get the LPDEVMODE
00745 // and unlock it when we are done.
00746 void 
00747 nsDeviceContextSpecWin::SetupPaperInfoFromSettings()
00748 {
00749   LPDEVMODE devMode;
00750 
00751   GetDevMode(devMode);
00752   NS_ASSERTION(devMode, "DevMode can't be NULL here");
00753   if (devMode) {
00754     SetupDevModeFromSettings(devMode, mPrintSettings);
00755   }
00756 }
00757 
00758 //----------------------------------------------------------------------------------
00759 // Helper Function - Free and reallocate the string
00760 nsresult 
00761 nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(nsIPrintSettings* aPrintSettings, 
00762                                                     LPDEVMODE         aDevMode)
00763 {
00764   if (aPrintSettings == nsnull) {
00765     return NS_ERROR_FAILURE;
00766   }
00767   aPrintSettings->SetIsInitializedFromPrinter(PR_TRUE);
00768 
00769   BOOL doingNumCopies   = aDevMode->dmFields & DM_COPIES;
00770   BOOL doingOrientation = aDevMode->dmFields & DM_ORIENTATION;
00771   BOOL doingPaperSize   = aDevMode->dmFields & DM_PAPERSIZE;
00772   BOOL doingPaperLength = aDevMode->dmFields & DM_PAPERLENGTH;
00773   BOOL doingPaperWidth  = aDevMode->dmFields & DM_PAPERWIDTH;
00774 
00775   if (doingOrientation) {
00776     PRInt32 orientation  = aDevMode->dmOrientation == DMORIENT_PORTRAIT?
00777       nsIPrintSettings::kPortraitOrientation:nsIPrintSettings::kLandscapeOrientation;
00778     aPrintSettings->SetOrientation(orientation);
00779   }
00780 
00781   // Setup Number of Copies
00782   if (doingNumCopies) {
00783     aPrintSettings->SetNumCopies(PRInt32(aDevMode->dmCopies));
00784   }
00785 
00786   if (aDevMode->dmFields & DM_SCALE) {
00787     double scale = double(aDevMode->dmScale) / 100.0f;
00788     if (scale != 1.0) {
00789       aPrintSettings->SetScaling(scale);
00790       aDevMode->dmScale = 100;
00791       // To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer
00792       //aPrintSettings->SetShrinkToFit(PR_FALSE);
00793     }
00794   }
00795 
00796   if (doingPaperSize) {
00797     aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData);
00798     aPrintSettings->SetPaperData(aDevMode->dmPaperSize);
00799     for (PRInt32 i=0;i<kNumPaperSizes;i++) {
00800       if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
00801         aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters);
00802         break;
00803       }
00804     }
00805 
00806   } else if (doingPaperLength && doingPaperWidth) {
00807     PRBool found = PR_FALSE;
00808     for (PRInt32 i=0;i<kNumPaperSizes;i++) {
00809       if (kPaperSizes[i].mPaperSize == aDevMode->dmPaperSize) {
00810         aPrintSettings->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined);
00811         aPrintSettings->SetPaperWidth(kPaperSizes[i].mWidth);
00812         aPrintSettings->SetPaperHeight(kPaperSizes[i].mHeight);
00813         aPrintSettings->SetPaperSizeUnit(kPaperSizes[i].mIsInches?nsIPrintSettings::kPaperSizeInches:nsIPrintSettings::kPaperSizeMillimeters);
00814         found = PR_TRUE;
00815         break;
00816       }
00817     }
00818     if (!found) {
00819       return NS_ERROR_FAILURE;
00820     }
00821   } else {
00822     return NS_ERROR_FAILURE;
00823   }
00824   return NS_OK;
00825 }
00826 
00827 //***********************************************************
00828 //  Printer Enumerator
00829 //***********************************************************
00830 nsPrinterEnumeratorWin::nsPrinterEnumeratorWin()
00831 {
00832 }
00833 
00834 nsPrinterEnumeratorWin::~nsPrinterEnumeratorWin()
00835 {
00836   // Do not free printers here
00837   // GlobalPrinters::GetInstance()->FreeGlobalPrinters();
00838 }
00839 
00840 NS_IMPL_ISUPPORTS1(nsPrinterEnumeratorWin, nsIPrinterEnumerator)
00841 
00842 
00843 static void CleanupArray(PRUnichar**& aArray, PRInt32& aCount)
00844 {
00845   for (PRInt32 i = aCount - 1; i >= 0; i--) {
00846     nsMemory::Free(aArray[i]);
00847   }
00848   nsMemory::Free(aArray);
00849   aArray = NULL;
00850   aCount = 0;
00851 }
00852 
00853  //----------------------------------------------------------------------------------
00854 // Return the Default Printer name
00855 /* readonly attribute wstring defaultPrinterName; */
00856 NS_IMETHODIMP 
00857 nsPrinterEnumeratorWin::GetDefaultPrinterName(PRUnichar * *aDefaultPrinterName)
00858 {
00859   NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
00860 
00861   *aDefaultPrinterName = GetDefaultPrinterNameFromGlobalPrinters(); // helper
00862 
00863   return NS_OK;
00864 }
00865 
00866 /* void initPrintSettingsFromPrinter (in wstring aPrinterName, in nsIPrintSettings aPrintSettings); */
00867 NS_IMETHODIMP 
00868 nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const PRUnichar *aPrinterName, nsIPrintSettings *aPrintSettings)
00869 {
00870   NS_ENSURE_ARG_POINTER(aPrinterName);
00871   NS_ENSURE_ARG_POINTER(aPrintSettings);
00872 
00873   if (!*aPrinterName) {
00874     return NS_OK;
00875   }
00876 
00877   nsCOMPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
00878   if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
00879 
00880   if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
00881     return NS_ERROR_FAILURE;
00882   }
00883 
00884   devSpecWin->GetDataFromPrinter(aPrinterName);
00885 
00886   LPDEVMODE devmode;
00887   devSpecWin->GetDevMode(devmode);
00888   NS_ASSERTION(devmode, "DevMode can't be NULL here");
00889   if (devmode) {
00890     aPrintSettings->SetPrinterName(aPrinterName);
00891     nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(aPrintSettings, devmode);
00892   }
00893 
00894   // Free them, we won't need them for a while
00895   GlobalPrinters::GetInstance()->FreeGlobalPrinters();
00896   return NS_OK;
00897 }
00898 
00899 
00900 //----------------------------------------------------------------------------------
00901 // Enumerate all the Printers from the global array and pass their
00902 // names back (usually to script)
00903 NS_IMETHODIMP 
00904 nsPrinterEnumeratorWin::EnumeratePrinters(PRUint32* aCount, PRUnichar*** aResult)
00905 {
00906   NS_ENSURE_ARG(aCount);
00907   NS_ENSURE_ARG_POINTER(aResult);
00908 
00909   nsresult rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
00910   if (NS_FAILED(rv)) {
00911     PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinters - Couldn't enumerate printers!\n"));
00912     return rv;
00913   }
00914 
00915   if (aCount) 
00916     *aCount = 0;
00917   else 
00918     return NS_ERROR_NULL_POINTER;
00919   
00920   if (aResult) 
00921     *aResult = nsnull;
00922   else 
00923     return NS_ERROR_NULL_POINTER;
00924   
00925   PRInt32 numPrinters = GlobalPrinters::GetInstance()->GetNumPrinters();
00926   PRInt32 numItems    = numPrinters;
00927 
00928   PRUnichar** array = (PRUnichar**) nsMemory::Alloc(numItems * sizeof(PRUnichar*));
00929   if (!array) 
00930     return NS_ERROR_OUT_OF_MEMORY;
00931   
00932   PRInt32 count      = 0;
00933   PRInt32 printerInx = 0;
00934   while( count < numItems ) {
00935     LPTSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx++);
00936     nsAutoString newName; 
00937     NS_CopyNativeToUnicode(nsDependentCString(name), newName);
00938     PRUnichar *str = ToNewUnicode(newName);
00939     if (!str) {
00940       CleanupArray(array, count);
00941       return NS_ERROR_OUT_OF_MEMORY;
00942     }
00943     array[count++] = str;
00944   }
00945   *aCount  = count;
00946   *aResult = array;
00947 
00948   return NS_OK;
00949 
00950 }
00951 
00952 //----------------------------------------------------------------------------------
00953 // Display the AdvancedDocumentProperties for the selected Printer
00954 NS_IMETHODIMP nsPrinterEnumeratorWin::DisplayPropertiesDlg(const PRUnichar *aPrinterName, nsIPrintSettings* aPrintSettings)
00955 {
00956 #ifdef WINCE
00957   return NS_ERROR_NOT_IMPLEMENTED;
00958 #else
00959   nsresult rv = NS_ERROR_FAILURE;
00960   HANDLE hPrinter = NULL;
00961   nsCAutoString nativeName;
00962   NS_CopyUnicodeToNative(nsDependentString(aPrinterName), nativeName);
00963   BOOL status = ::OpenPrinter(NS_CONST_CAST(char*, nativeName.get()),
00964                               &hPrinter, NULL);
00965   if (status) {
00966 
00967     LPDEVMODE   pDevMode;
00968     LPDEVMODE   pNewDevMode;
00969     DWORD       dwNeeded, dwRet;
00970 
00971     // Get the buffer correct buffer size
00972     dwNeeded = ::DocumentProperties(gParentWnd, hPrinter,
00973                                    NS_CONST_CAST(char*, nativeName.get()),
00974                                    NULL, NULL, 0);
00975 
00976     // Allocate a buffer of the correct size.
00977     pNewDevMode = (LPDEVMODE)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
00978     if (!pNewDevMode) return NS_ERROR_FAILURE;
00979 
00980     dwRet = ::DocumentProperties(gParentWnd, hPrinter,
00981                                  NS_CONST_CAST(char*, nativeName.get()),
00982                                  pNewDevMode, NULL, DM_OUT_BUFFER);
00983 
00984     if (dwRet != IDOK) {
00985        ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
00986        ::ClosePrinter(hPrinter);
00987        PR_PL(("***** nsDeviceContextSpecWin::DisplayPropertiesDlg - Couldn't get DocumentProperties (pNewDevMode) for [%s]\n", nativeName.get()));
00988        return NS_ERROR_FAILURE;
00989     }
00990 
00991     pDevMode = (LPDEVMODE)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
00992     if (!pDevMode) return NS_ERROR_FAILURE;
00993 
00994     dwRet = ::DocumentProperties(gParentWnd, hPrinter,
00995                                  NS_CONST_CAST(char*, nativeName.get()),
00996                                  pDevMode, NULL, DM_OUT_BUFFER);
00997 
00998     if (dwRet != IDOK) {
00999        ::HeapFree(::GetProcessHeap(), 0, pDevMode);
01000        ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
01001        ::ClosePrinter(hPrinter);
01002        PR_PL(("***** nsDeviceContextSpecWin::DisplayPropertiesDlg - Couldn't get DocumentProperties (pDevMode) for [%s]\n", nativeName.get()));
01003        return NS_ERROR_FAILURE;
01004     }
01005 
01006 
01007     if (pDevMode && pNewDevMode) {
01008       SetupDevModeFromSettings(pDevMode, aPrintSettings);
01009 
01010       // Display the Dialog and get the new DevMode
01011 #if 0 // need more to do more work to see why AdvancedDocumentProperties fails 
01012       // when cancel is pressed
01013       LONG stat = ::AdvancedDocumentProperties(gParentWnd, hPrinter,
01014                                                NS_CONST_CAST(char*, nativeName.get()),
01015                                                pNewDevMode, pDevMode);
01016 #else
01017       LONG stat = ::DocumentProperties(gParentWnd, hPrinter,
01018                                        NS_CONST_CAST(char*, nativeName.get()),
01019                                        pDevMode, NULL,
01020                                        DM_IN_PROMPT|DM_OUT_BUFFER);
01021 #endif
01022       if (stat == IDOK) {
01023         // Now set the print options from the native Page Setup
01024         nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(aPrintSettings, pDevMode);
01025       }
01026       ::HeapFree(::GetProcessHeap(), 0, pDevMode);
01027       ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
01028       rv = NS_OK;
01029     } else {
01030       rv = NS_ERROR_OUT_OF_MEMORY;
01031     }
01032 
01033     ::ClosePrinter(hPrinter);
01034 
01035   } else {
01036     rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
01037     PR_PL(("***** nsDeviceContextSpecWin::DisplayPropertiesDlg - Couldn't open printer [%s]\n", nativeName.get()));
01038     DISPLAY_LAST_ERROR
01039   }
01040 
01041   return rv;
01042 #endif //WINCE
01043 }
01044 
01045 //----------------------------------------------------------------------------------
01046 //-- Global Printers
01047 //----------------------------------------------------------------------------------
01048 
01049 //----------------------------------------------------------------------------------
01050 // THe array hold the name and port for each printer
01051 void 
01052 GlobalPrinters::ReallocatePrinters()
01053 {
01054   if (PrintersAreAllocated()) {
01055     FreeGlobalPrinters();
01056   }
01057   mPrinters = new nsVoidArray();
01058   NS_ASSERTION(mPrinters, "Printers Array is NULL!");
01059 }
01060 
01061 //----------------------------------------------------------------------------------
01062 void 
01063 GlobalPrinters::FreeGlobalPrinters()
01064 {
01065   if (mPrinters != nsnull) {
01066     for (int i=0;i<mPrinters->Count();i++) {
01067       free((LPTSTR)mPrinters->ElementAt(i));
01068     }
01069     delete mPrinters;
01070     mPrinters = nsnull;
01071   }
01072 }
01073 
01074 //----------------------------------------------------------------------------------
01075 nsresult 
01076 GlobalPrinters::EnumerateNativePrinters()
01077 {
01078   nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
01079 #ifndef WINCE
01080   PR_PL(("-----------------------\n"));
01081   PR_PL(("EnumerateNativePrinters\n"));
01082 
01083   TCHAR szDefaultPrinterName[1024];    
01084   DWORD status = GetProfileString("devices", 0, ",", szDefaultPrinterName, sizeof(szDefaultPrinterName)/sizeof(TCHAR));
01085   if (status > 0) {
01086     DWORD count = 0;
01087     LPTSTR sPtr   = (LPTSTR)szDefaultPrinterName;
01088     LPTSTR ePtr   = (LPTSTR)(szDefaultPrinterName+(status*sizeof(TCHAR)));
01089     LPTSTR prvPtr = sPtr;
01090     while (sPtr < ePtr) {
01091       if (*sPtr == NULL) {
01092         LPTSTR name = _tcsdup(prvPtr);
01093         mPrinters->AppendElement(name);
01094         PR_PL(("Printer Name:    %s\n", prvPtr));
01095         prvPtr = sPtr+1;
01096         count++;
01097       }
01098       sPtr++;
01099     }
01100     rv = NS_OK;
01101   }
01102   PR_PL(("-----------------------\n"));
01103 #endif
01104   return rv;
01105 }
01106 
01107 //------------------------------------------------------------------
01108 // Uses the GetProfileString to get the default printer from the registry
01109 void 
01110 GlobalPrinters::GetDefaultPrinterName(LPTSTR& aDefaultPrinterName)
01111 {
01112 #ifndef WINCE
01113   aDefaultPrinterName = nsnull;
01114   TCHAR szDefaultPrinterName[1024];    
01115   DWORD status = GetProfileString("windows", "device", 0, szDefaultPrinterName, sizeof(szDefaultPrinterName)/sizeof(TCHAR));
01116   if (status > 0) {
01117     TCHAR comma = (TCHAR)',';
01118     LPTSTR sPtr = (LPTSTR)szDefaultPrinterName;
01119     while (*sPtr != comma && *sPtr != NULL) 
01120       sPtr++;
01121     if (*sPtr == comma) {
01122       *sPtr = NULL;
01123     }
01124     aDefaultPrinterName = _tcsdup(szDefaultPrinterName);
01125   } else {
01126     aDefaultPrinterName = _tcsdup("");
01127   }
01128 
01129   PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName));
01130 #else
01131   aDefaultPrinterName = "UNKNOWN";
01132 #endif
01133 }
01134 
01135 //----------------------------------------------------------------------------------
01136 // This goes and gets the list of available printers and puts
01137 // the default printer at the beginning of the list
01138 nsresult 
01139 GlobalPrinters::EnumeratePrinterList()
01140 {
01141   // reallocate and get a new list each time it is asked for
01142   // this deletes the list and re-allocates them
01143   ReallocatePrinters();
01144 
01145   // any of these could only fail with an OUT_MEMORY_ERROR
01146   // PRINTER_ENUM_LOCAL should get the network printers on Win95
01147   nsresult rv = EnumerateNativePrinters();
01148   if (NS_FAILED(rv)) return rv;
01149 
01150   // get the name of the default printer
01151   LPTSTR defPrinterName;
01152   GetDefaultPrinterName(defPrinterName);
01153 
01154   // put the default printer at the beginning of list
01155   if (defPrinterName != nsnull) {
01156     for (PRInt32 i=0;i<mPrinters->Count();i++) {
01157       LPTSTR name = (LPTSTR)mPrinters->ElementAt(i);
01158       if (!_tcscmp(name, defPrinterName)) {
01159         if (i > 0) {
01160           LPTSTR ptr = (LPTSTR)mPrinters->ElementAt(0);
01161           mPrinters->ReplaceElementAt((void*)name, 0);
01162           mPrinters->ReplaceElementAt((void*)ptr, i);
01163         }
01164         break;
01165       }
01166     }
01167     free(defPrinterName);
01168   }
01169 
01170   // make sure we at least tried to get the printers
01171   if (!PrintersAreAllocated()) {
01172     PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t allocated\n"));
01173     return NS_ERROR_FAILURE;
01174   }
01175 
01176   return NS_OK;
01177 }
01178