1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "nsDeviceContextSpecWin.h"
7 
8 #include "mozilla/ArrayUtils.h"
9 #include "mozilla/gfx/PrintTargetPDF.h"
10 #include "mozilla/gfx/PrintTargetWindows.h"
11 #include "mozilla/Logging.h"
12 #include "mozilla/Preferences.h"
13 #include "mozilla/RefPtr.h"
14 
15 #include "prmem.h"
16 
17 #include <winspool.h>
18 
19 #include "nsIWidget.h"
20 
21 #include "nsTArray.h"
22 #include "nsIPrintSettingsWin.h"
23 
24 #include "nsString.h"
25 #include "nsIServiceManager.h"
26 #include "nsReadableUtils.h"
27 #include "nsStringEnumerator.h"
28 
29 #include "gfxWindowsSurface.h"
30 
31 #include "nsIFileStreams.h"
32 #include "nsIWindowWatcher.h"
33 #include "nsIDOMWindow.h"
34 #include "mozilla/Services.h"
35 #include "nsWindowsHelpers.h"
36 
37 #include "mozilla/gfx/Logging.h"
38 
39 #include "mozilla/Logging.h"
40 static mozilla::LazyLogModule kWidgetPrintingLogMod("printing-widget");
41 #define PR_PL(_p1)  MOZ_LOG(kWidgetPrintingLogMod, mozilla::LogLevel::Debug, _p1)
42 
43 using namespace mozilla;
44 using namespace mozilla::gfx;
45 
46 static const wchar_t kDriverName[] =  L"WINSPOOL";
47 
48 //----------------------------------------------------------------------------------
49 // The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
50 // The PrinterEnumerator creates the printer info
51 // but the nsDeviceContextSpecWin cleans it up
52 // If it gets created (via the Page Setup Dialog) but the user never prints anything
53 // then it will never be delete, so this class takes care of that.
54 class GlobalPrinters {
55 public:
GetInstance()56   static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
~GlobalPrinters()57   ~GlobalPrinters() { FreeGlobalPrinters(); }
58 
59   void FreeGlobalPrinters();
60 
PrintersAreAllocated()61   bool         PrintersAreAllocated() { return mPrinters != nullptr; }
GetItemFromList(int32_t aInx)62   LPWSTR       GetItemFromList(int32_t aInx) { return mPrinters?mPrinters->ElementAt(aInx):nullptr; }
63   nsresult     EnumeratePrinterList();
64   void         GetDefaultPrinterName(nsString& aDefaultPrinterName);
GetNumPrinters()65   uint32_t     GetNumPrinters() { return mPrinters?mPrinters->Length():0; }
66 
67 protected:
GlobalPrinters()68   GlobalPrinters() {}
69   nsresult EnumerateNativePrinters();
70   void     ReallocatePrinters();
71 
72   static GlobalPrinters    mGlobalPrinters;
73   static nsTArray<LPWSTR>* mPrinters;
74 };
75 //---------------
76 // static members
77 GlobalPrinters    GlobalPrinters::mGlobalPrinters;
78 nsTArray<LPWSTR>* GlobalPrinters::mPrinters = nullptr;
79 
80 struct AutoFreeGlobalPrinters
81 {
~AutoFreeGlobalPrintersAutoFreeGlobalPrinters82   ~AutoFreeGlobalPrinters() {
83     GlobalPrinters::GetInstance()->FreeGlobalPrinters();
84   }
85 };
86 
87 //----------------------------------------------------------------------------------
nsDeviceContextSpecWin()88 nsDeviceContextSpecWin::nsDeviceContextSpecWin()
89 {
90   mDriverName    = nullptr;
91   mDeviceName    = nullptr;
92   mDevMode       = nullptr;
93 
94 }
95 
96 
97 //----------------------------------------------------------------------------------
98 
NS_IMPL_ISUPPORTS(nsDeviceContextSpecWin,nsIDeviceContextSpec)99 NS_IMPL_ISUPPORTS(nsDeviceContextSpecWin, nsIDeviceContextSpec)
100 
101 nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
102 {
103   SetDeviceName(nullptr);
104   SetDriverName(nullptr);
105   SetDevMode(nullptr);
106 
107   nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
108   if (psWin) {
109     psWin->SetDeviceName(nullptr);
110     psWin->SetDriverName(nullptr);
111     psWin->SetDevMode(nullptr);
112   }
113 
114   // Free them, we won't need them for a while
115   GlobalPrinters::GetInstance()->FreeGlobalPrinters();
116 }
117 
118 
119 //------------------------------------------------------------------
120 // helper
GetDefaultPrinterNameFromGlobalPrinters()121 static char16_t * GetDefaultPrinterNameFromGlobalPrinters()
122 {
123   nsAutoString printerName;
124   GlobalPrinters::GetInstance()->GetDefaultPrinterName(printerName);
125   return ToNewUnicode(printerName);
126 }
127 
128 //----------------------------------------------------------------------------------
Init(nsIWidget * aWidget,nsIPrintSettings * aPrintSettings,bool aIsPrintPreview)129 NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
130                                            nsIPrintSettings* aPrintSettings,
131                                            bool aIsPrintPreview)
132 {
133   mPrintSettings = aPrintSettings;
134 
135   nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
136   if (aPrintSettings) {
137     // If we're in the child and printing via the parent or we're printing to
138     // PDF we only need information from the print settings.
139     mPrintSettings->GetOutputFormat(&mOutputFormat);
140     if ((XRE_IsContentProcess() &&
141          Preferences::GetBool("print.print_via_parent")) ||
142         mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
143       return NS_OK;
144     }
145 
146     nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
147     if (psWin) {
148       char16_t* deviceName;
149       char16_t* driverName;
150       psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
151       psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
152 
153       LPDEVMODEW devMode;
154       psWin->GetDevMode(&devMode);       // creates new memory (makes a copy)
155 
156       if (deviceName && driverName && devMode) {
157         // Scaling is special, it is one of the few
158         // devMode items that we control in layout
159         if (devMode->dmFields & DM_SCALE) {
160           double scale = double(devMode->dmScale) / 100.0f;
161           if (scale != 1.0) {
162             aPrintSettings->SetScaling(scale);
163             devMode->dmScale = 100;
164           }
165         }
166 
167         SetDeviceName(deviceName);
168         SetDriverName(driverName);
169         SetDevMode(devMode);
170 
171         // clean up
172         free(deviceName);
173         free(driverName);
174 
175         return NS_OK;
176       } else {
177         PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
178         if (deviceName) free(deviceName);
179         if (driverName) free(driverName);
180         if (devMode) ::HeapFree(::GetProcessHeap(), 0, devMode);
181       }
182     }
183   } else {
184     PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
185   }
186 
187   // Get the Printer Name to be used and output format.
188   char16_t * printerName = nullptr;
189   if (mPrintSettings) {
190     mPrintSettings->GetPrinterName(&printerName);
191   }
192 
193   // If there is no name then use the default printer
194   if (!printerName || (printerName && !*printerName)) {
195     printerName = GetDefaultPrinterNameFromGlobalPrinters();
196   }
197 
198   NS_ASSERTION(printerName, "We have to have a printer name");
199   if (!printerName || !*printerName) return rv;
200 
201   return GetDataFromPrinter(printerName, mPrintSettings);
202 }
203 
204 //----------------------------------------------------------
205 // Helper Function - Free and reallocate the string
CleanAndCopyString(wchar_t * & aStr,const wchar_t * aNewStr)206 static void CleanAndCopyString(wchar_t*& aStr, const wchar_t* aNewStr)
207 {
208   if (aStr != nullptr) {
209     if (aNewStr != nullptr && wcslen(aStr) > wcslen(aNewStr)) { // reuse it if we can
210       wcscpy(aStr, aNewStr);
211       return;
212     } else {
213       PR_Free(aStr);
214       aStr = nullptr;
215     }
216   }
217 
218   if (nullptr != aNewStr) {
219     aStr = (wchar_t *)PR_Malloc(sizeof(wchar_t)*(wcslen(aNewStr) + 1));
220     wcscpy(aStr, aNewStr);
221   }
222 }
223 
MakePrintTarget()224 already_AddRefed<PrintTarget> nsDeviceContextSpecWin::MakePrintTarget()
225 {
226   NS_ASSERTION(mDevMode, "DevMode can't be NULL here");
227 
228   if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
229     nsXPIDLString filename;
230     mPrintSettings->GetToFileName(getter_Copies(filename));
231 
232     double width, height;
233     mPrintSettings->GetEffectivePageSize(&width, &height);
234     if (width <= 0 || height <= 0) {
235       return nullptr;
236     }
237 
238     // convert twips to points
239     width  /= TWIPS_PER_POINT_FLOAT;
240     height /= TWIPS_PER_POINT_FLOAT;
241 
242     nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
243     nsresult rv = file->InitWithPath(filename);
244     if (NS_FAILED(rv)) {
245       return nullptr;
246     }
247 
248     nsCOMPtr<nsIFileOutputStream> stream = do_CreateInstance("@mozilla.org/network/file-output-stream;1");
249     rv = stream->Init(file, -1, -1, 0);
250     if (NS_FAILED(rv)) {
251       return nullptr;
252     }
253 
254     return PrintTargetPDF::CreateOrNull(stream, IntSize::Truncate(width, height));
255   }
256 
257   if (mDevMode) {
258     NS_WARNING_ASSERTION(mDriverName, "No driver!");
259     HDC dc = ::CreateDCW(mDriverName, mDeviceName, nullptr, mDevMode);
260     if (!dc) {
261       gfxCriticalError(gfxCriticalError::DefaultOptions(false))
262         << "Failed to create device context in GetSurfaceForPrinter";
263       return nullptr;
264     }
265 
266     // The PrintTargetWindows takes over ownership of this DC
267     return PrintTargetWindows::CreateOrNull(dc);
268   }
269 
270   return nullptr;
271 }
272 
273 float
GetDPI()274 nsDeviceContextSpecWin::GetDPI()
275 {
276   // To match the previous printing code we need to return 72 when printing to
277   // PDF and 144 when printing to a Windows surface.
278   return mOutputFormat == nsIPrintSettings::kOutputFormatPDF ? 72.0f : 144.0f;
279 }
280 
281 float
GetPrintingScale()282 nsDeviceContextSpecWin::GetPrintingScale()
283 {
284   MOZ_ASSERT(mPrintSettings);
285 
286   // To match the previous printing code there is no scaling for PDF.
287   if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
288     return 1.0f;
289   }
290 
291   // The print settings will have the resolution stored from the real device.
292   int32_t resolution;
293   mPrintSettings->GetResolution(&resolution);
294   return float(resolution) / GetDPI();
295 }
296 
297 //----------------------------------------------------------------------------------
SetDeviceName(char16ptr_t aDeviceName)298 void nsDeviceContextSpecWin::SetDeviceName(char16ptr_t aDeviceName)
299 {
300   CleanAndCopyString(mDeviceName, aDeviceName);
301 }
302 
303 //----------------------------------------------------------------------------------
SetDriverName(char16ptr_t aDriverName)304 void nsDeviceContextSpecWin::SetDriverName(char16ptr_t aDriverName)
305 {
306   CleanAndCopyString(mDriverName, aDriverName);
307 }
308 
309 //----------------------------------------------------------------------------------
SetDevMode(LPDEVMODEW aDevMode)310 void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode)
311 {
312   if (mDevMode) {
313     ::HeapFree(::GetProcessHeap(), 0, mDevMode);
314   }
315 
316   mDevMode = aDevMode;
317 }
318 
319 //------------------------------------------------------------------
320 void
GetDevMode(LPDEVMODEW & aDevMode)321 nsDeviceContextSpecWin::GetDevMode(LPDEVMODEW &aDevMode)
322 {
323   aDevMode = mDevMode;
324 }
325 
326 #define DISPLAY_LAST_ERROR
327 
328 //----------------------------------------------------------------------------------
329 // Setup the object's data member with the selected printer's data
330 nsresult
GetDataFromPrinter(char16ptr_t aName,nsIPrintSettings * aPS)331 nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS)
332 {
333   nsresult rv = NS_ERROR_FAILURE;
334 
335   if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
336     rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
337     if (NS_FAILED(rv)) {
338       PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
339       DISPLAY_LAST_ERROR
340     }
341     NS_ENSURE_SUCCESS(rv, rv);
342   }
343 
344   nsHPRINTER hPrinter = nullptr;
345   wchar_t *name = (wchar_t*)aName; // Windows APIs use non-const name argument
346 
347   BOOL status = ::OpenPrinterW(name, &hPrinter, nullptr);
348   if (status) {
349     nsAutoPrinter autoPrinter(hPrinter);
350 
351     LPDEVMODEW   pDevMode;
352 
353     // Allocate a buffer of the correct size.
354     LONG needed = ::DocumentPropertiesW(nullptr, hPrinter, name, nullptr,
355                                         nullptr, 0);
356     if (needed < 0) {
357       PR_PL(("**** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't get "
358              "size of DEVMODE using DocumentPropertiesW(pDeviceName = \"%s\"). "
359              "GetLastEror() = %08x\n",
360              aName ? NS_ConvertUTF16toUTF8(aName).get() : "", GetLastError()));
361       return NS_ERROR_FAILURE;
362     }
363 
364     pDevMode = (LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
365                                        needed);
366     if (!pDevMode) return NS_ERROR_FAILURE;
367 
368     // Get the default DevMode for the printer and modify it for our needs.
369     LONG ret = ::DocumentPropertiesW(nullptr, hPrinter, name,
370                                      pDevMode, nullptr, DM_OUT_BUFFER);
371 
372     if (ret == IDOK && aPS) {
373       nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
374       MOZ_ASSERT(psWin);
375       psWin->CopyToNative(pDevMode);
376       // Sets back the changes we made to the DevMode into the Printer Driver
377       ret = ::DocumentPropertiesW(nullptr, hPrinter, name,
378                                   pDevMode, pDevMode,
379                                   DM_IN_BUFFER | DM_OUT_BUFFER);
380 
381       // We need to copy the final DEVMODE settings back to our print settings,
382       // because they may have been set from invalid prefs.
383       if (ret == IDOK) {
384         // We need to get information from the device as well.
385         nsAutoHDC printerDC(::CreateICW(kDriverName, aName, nullptr, pDevMode));
386         if (NS_WARN_IF(!printerDC)) {
387           ::HeapFree(::GetProcessHeap(), 0, pDevMode);
388           return NS_ERROR_FAILURE;
389         }
390 
391         psWin->CopyFromNative(printerDC, pDevMode);
392       }
393     }
394 
395     if (ret != IDOK) {
396       ::HeapFree(::GetProcessHeap(), 0, pDevMode);
397       PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", ret, ret));
398       DISPLAY_LAST_ERROR
399       return NS_ERROR_FAILURE;
400     }
401 
402     SetDevMode(pDevMode); // cache the pointer and takes responsibility for the memory
403 
404     SetDeviceName(aName);
405 
406     SetDriverName(kDriverName);
407 
408     rv = NS_OK;
409   } else {
410     rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
411     PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", NS_ConvertUTF16toUTF8(aName).get()));
412     DISPLAY_LAST_ERROR
413   }
414   return rv;
415 }
416 
417 //***********************************************************
418 //  Printer Enumerator
419 //***********************************************************
nsPrinterEnumeratorWin()420 nsPrinterEnumeratorWin::nsPrinterEnumeratorWin()
421 {
422 }
423 
~nsPrinterEnumeratorWin()424 nsPrinterEnumeratorWin::~nsPrinterEnumeratorWin()
425 {
426   // Do not free printers here
427   // GlobalPrinters::GetInstance()->FreeGlobalPrinters();
428 }
429 
NS_IMPL_ISUPPORTS(nsPrinterEnumeratorWin,nsIPrinterEnumerator)430 NS_IMPL_ISUPPORTS(nsPrinterEnumeratorWin, nsIPrinterEnumerator)
431 
432 //----------------------------------------------------------------------------------
433 // Return the Default Printer name
434 NS_IMETHODIMP
435 nsPrinterEnumeratorWin::GetDefaultPrinterName(char16_t * *aDefaultPrinterName)
436 {
437   NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
438 
439   *aDefaultPrinterName = GetDefaultPrinterNameFromGlobalPrinters(); // helper
440 
441   return NS_OK;
442 }
443 
444 NS_IMETHODIMP
InitPrintSettingsFromPrinter(const char16_t * aPrinterName,nsIPrintSettings * aPrintSettings)445 nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, nsIPrintSettings *aPrintSettings)
446 {
447   NS_ENSURE_ARG_POINTER(aPrinterName);
448   NS_ENSURE_ARG_POINTER(aPrintSettings);
449 
450   if (!*aPrinterName) {
451     return NS_OK;
452   }
453 
454   // When printing to PDF on Windows there is no associated printer driver.
455   int16_t outputFormat;
456   aPrintSettings->GetOutputFormat(&outputFormat);
457   if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
458     return NS_OK;
459   }
460 
461   RefPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
462   if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
463 
464   if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
465     return NS_ERROR_FAILURE;
466   }
467 
468   AutoFreeGlobalPrinters autoFreeGlobalPrinters;
469 
470   // If the settings have already been initialized from prefs then pass these to
471   // GetDataFromPrinter, so that they are saved to the printer.
472   bool initializedFromPrefs;
473   nsresult rv =
474     aPrintSettings->GetIsInitializedFromPrefs(&initializedFromPrefs);
475   if (NS_WARN_IF(NS_FAILED(rv))) {
476     return rv;
477   }
478   if (initializedFromPrefs) {
479     // If we pass in print settings to GetDataFromPrinter it already copies
480     // things back to the settings, so we can return here.
481     return devSpecWin->GetDataFromPrinter(aPrinterName, aPrintSettings);
482   }
483 
484   devSpecWin->GetDataFromPrinter(aPrinterName);
485 
486   LPDEVMODEW devmode;
487   devSpecWin->GetDevMode(devmode);
488   if (NS_WARN_IF(!devmode)) {
489     return NS_ERROR_FAILURE;
490   }
491 
492   aPrintSettings->SetPrinterName(aPrinterName);
493 
494   // We need to get information from the device as well.
495   char16ptr_t printerName = aPrinterName;
496   HDC dc = ::CreateICW(kDriverName, printerName, nullptr, devmode);
497   if (NS_WARN_IF(!dc)) {
498     return NS_ERROR_FAILURE;
499   }
500 
501   nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPrintSettings);
502   MOZ_ASSERT(psWin);
503   psWin->CopyFromNative(dc, devmode);
504   ::DeleteDC(dc);
505 
506   return NS_OK;
507 }
508 
509 
510 //----------------------------------------------------------------------------------
511 // Enumerate all the Printers from the global array and pass their
512 // names back (usually to script)
513 NS_IMETHODIMP
GetPrinterNameList(nsIStringEnumerator ** aPrinterNameList)514 nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator **aPrinterNameList)
515 {
516   NS_ENSURE_ARG_POINTER(aPrinterNameList);
517   *aPrinterNameList = nullptr;
518 
519   nsresult rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
520   if (NS_FAILED(rv)) {
521     PR_PL(("***** nsDeviceContextSpecWin::GetPrinterNameList - Couldn't enumerate printers!\n"));
522     return rv;
523   }
524 
525   uint32_t numPrinters = GlobalPrinters::GetInstance()->GetNumPrinters();
526   nsTArray<nsString> *printers = new nsTArray<nsString>(numPrinters);
527   if (!printers)
528     return NS_ERROR_OUT_OF_MEMORY;
529 
530   nsString* names = printers->AppendElements(numPrinters);
531   for (uint32_t printerInx = 0; printerInx < numPrinters; ++printerInx) {
532     LPWSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx);
533     names[printerInx].Assign(name);
534   }
535 
536   return NS_NewAdoptingStringEnumerator(aPrinterNameList, printers);
537 }
538 
539 //----------------------------------------------------------------------------------
540 //-- Global Printers
541 //----------------------------------------------------------------------------------
542 
543 //----------------------------------------------------------------------------------
544 // THe array hold the name and port for each printer
545 void
ReallocatePrinters()546 GlobalPrinters::ReallocatePrinters()
547 {
548   if (PrintersAreAllocated()) {
549     FreeGlobalPrinters();
550   }
551   mPrinters = new nsTArray<LPWSTR>();
552   NS_ASSERTION(mPrinters, "Printers Array is NULL!");
553 }
554 
555 //----------------------------------------------------------------------------------
556 void
FreeGlobalPrinters()557 GlobalPrinters::FreeGlobalPrinters()
558 {
559   if (mPrinters != nullptr) {
560     for (uint32_t i=0;i<mPrinters->Length();i++) {
561       free(mPrinters->ElementAt(i));
562     }
563     delete mPrinters;
564     mPrinters = nullptr;
565   }
566 }
567 
568 //----------------------------------------------------------------------------------
569 nsresult
EnumerateNativePrinters()570 GlobalPrinters::EnumerateNativePrinters()
571 {
572   nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
573   PR_PL(("-----------------------\n"));
574   PR_PL(("EnumerateNativePrinters\n"));
575 
576   WCHAR szDefaultPrinterName[1024];
577   DWORD status = GetProfileStringW(L"devices", 0, L",",
578                                    szDefaultPrinterName,
579                                    ArrayLength(szDefaultPrinterName));
580   if (status > 0) {
581     DWORD count = 0;
582     LPWSTR sPtr   = szDefaultPrinterName;
583     LPWSTR ePtr   = szDefaultPrinterName + status;
584     LPWSTR prvPtr = sPtr;
585     while (sPtr < ePtr) {
586       if (*sPtr == 0) {
587         LPWSTR name = wcsdup(prvPtr);
588         mPrinters->AppendElement(name);
589         PR_PL(("Printer Name:    %s\n", prvPtr));
590         prvPtr = sPtr+1;
591         count++;
592       }
593       sPtr++;
594     }
595     rv = NS_OK;
596   }
597   PR_PL(("-----------------------\n"));
598   return rv;
599 }
600 
601 //------------------------------------------------------------------
602 // Uses the GetProfileString to get the default printer from the registry
603 void
GetDefaultPrinterName(nsString & aDefaultPrinterName)604 GlobalPrinters::GetDefaultPrinterName(nsString& aDefaultPrinterName)
605 {
606   aDefaultPrinterName.Truncate();
607   WCHAR szDefaultPrinterName[1024];
608   DWORD status = GetProfileStringW(L"windows", L"device", 0,
609                                    szDefaultPrinterName,
610                                    ArrayLength(szDefaultPrinterName));
611   if (status > 0) {
612     WCHAR comma = ',';
613     LPWSTR sPtr = szDefaultPrinterName;
614     while (*sPtr != comma && *sPtr != 0)
615       sPtr++;
616     if (*sPtr == comma) {
617       *sPtr = 0;
618     }
619     aDefaultPrinterName = szDefaultPrinterName;
620   } else {
621     aDefaultPrinterName = EmptyString();
622   }
623 
624   PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName.get()));
625 }
626 
627 //----------------------------------------------------------------------------------
628 // This goes and gets the list of available printers and puts
629 // the default printer at the beginning of the list
630 nsresult
EnumeratePrinterList()631 GlobalPrinters::EnumeratePrinterList()
632 {
633   // reallocate and get a new list each time it is asked for
634   // this deletes the list and re-allocates them
635   ReallocatePrinters();
636 
637   // any of these could only fail with an OUT_MEMORY_ERROR
638   // PRINTER_ENUM_LOCAL should get the network printers on Win95
639   nsresult rv = EnumerateNativePrinters();
640   if (NS_FAILED(rv)) return rv;
641 
642   // get the name of the default printer
643   nsAutoString defPrinterName;
644   GetDefaultPrinterName(defPrinterName);
645 
646   // put the default printer at the beginning of list
647   if (!defPrinterName.IsEmpty()) {
648     for (uint32_t i=0;i<mPrinters->Length();i++) {
649       LPWSTR name = mPrinters->ElementAt(i);
650       if (defPrinterName.Equals(name)) {
651         if (i > 0) {
652           LPWSTR ptr = mPrinters->ElementAt(0);
653           mPrinters->ElementAt(0) = name;
654           mPrinters->ElementAt(i) = ptr;
655         }
656         break;
657       }
658     }
659   }
660 
661   // make sure we at least tried to get the printers
662   if (!PrintersAreAllocated()) {
663     PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t allocated\n"));
664     return NS_ERROR_FAILURE;
665   }
666 
667   return NS_OK;
668 }
669 
670