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