1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsDeviceContextSpecWin.h"
43 #include "nsAutoPtr.h"
44 #include "nsIWidget.h"
46 #include "nsVoidArray.h"
47 #include "nsIPrintSettingsWin.h"
51 #include "nsIServiceManager.h"
52 #include "nsReadableUtils.h"
53 #include "nsStringEnumerator.h"
55 #include "gfxPDFSurface.h"
56 #include "gfxWindowsSurface.h"
58 #include "nsIFileStreams.h"
59 #include "nsIWindowWatcher.h"
60 #include "nsIDOMWindow.h"
62 // For NS_CopyNativeToUnicode
63 #include "nsNativeCharsetUtils.h"
66 #include "nsILocalFile.h"
68 #include "nsIFilePicker.h"
69 #include "nsIStringBundle.h"
70 #define NS_ERROR_GFX_PRINTER_BUNDLE_URL "chrome://global/locale/printing.properties"
74 PRLogModuleInfo
* kWidgetPrintingLogMod
= PR_NewLogModule("printing-widget");
75 #define PR_PL(_p1) PR_LOG(kWidgetPrintingLogMod, PR_LOG_DEBUG, _p1)
80 //----------------------------------------------------------------------------------
81 // The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
82 // The PrinterEnumerator creates the printer info
83 // but the nsDeviceContextSpecWin cleans it up
84 // If it gets created (via the Page Setup Dialog) but the user never prints anything
85 // then it will never be delete, so this class takes care of that.
86 class GlobalPrinters
{
88 static GlobalPrinters
* GetInstance() { return &mGlobalPrinters
; }
89 ~GlobalPrinters() { FreeGlobalPrinters(); }
91 void FreeGlobalPrinters();
93 PRBool
PrintersAreAllocated() { return mPrinters
!= nsnull
; }
94 LPTSTR
GetItemFromList(PRInt32 aInx
) { return mPrinters
?(LPTSTR
)mPrinters
->ElementAt(aInx
):nsnull
; }
95 nsresult
EnumeratePrinterList();
96 void GetDefaultPrinterName(LPTSTR
& aDefaultPrinterName
);
97 PRInt32
GetNumPrinters() { return mPrinters
?mPrinters
->Count():0; }
101 nsresult
EnumerateNativePrinters();
102 void ReallocatePrinters();
104 static GlobalPrinters mGlobalPrinters
;
105 static nsVoidArray
* mPrinters
;
109 GlobalPrinters
GlobalPrinters::mGlobalPrinters
;
110 nsVoidArray
* GlobalPrinters::mPrinters
= nsnull
;
113 //******************************************************
114 // Define native paper sizes
115 //******************************************************
117 short mPaperSize
; // native enum
123 // There are around 40 default print sizes defined by Windows
124 const NativePaperSizes kPaperSizes
[] = {
125 {DMPAPER_LETTER
, 8.5, 11.0, PR_TRUE
},
126 {DMPAPER_LEGAL
, 8.5, 14.0, PR_TRUE
},
127 {DMPAPER_A4
, 210.0, 297.0, PR_FALSE
},
128 {DMPAPER_B4
, 250.0, 354.0, PR_FALSE
},
129 {DMPAPER_B5
, 182.0, 257.0, PR_FALSE
},
131 {DMPAPER_TABLOID
, 11.0, 17.0, PR_TRUE
},
132 {DMPAPER_LEDGER
, 17.0, 11.0, PR_TRUE
},
133 {DMPAPER_STATEMENT
, 5.5, 8.5, PR_TRUE
},
134 {DMPAPER_EXECUTIVE
, 7.25, 10.5, PR_TRUE
},
135 {DMPAPER_A3
, 297.0, 420.0, PR_FALSE
},
136 {DMPAPER_A5
, 148.0, 210.0, PR_FALSE
},
137 {DMPAPER_CSHEET
, 17.0, 22.0, PR_TRUE
},
138 {DMPAPER_DSHEET
, 22.0, 34.0, PR_TRUE
},
139 {DMPAPER_ESHEET
, 34.0, 44.0, PR_TRUE
},
140 {DMPAPER_LETTERSMALL
, 8.5, 11.0, PR_TRUE
},
141 {DMPAPER_A4SMALL
, 210.0, 297.0, PR_FALSE
},
142 {DMPAPER_FOLIO
, 8.5, 13.0, PR_TRUE
},
143 {DMPAPER_QUARTO
, 215.0, 275.0, PR_FALSE
},
144 {DMPAPER_10X14
, 10.0, 14.0, PR_TRUE
},
145 {DMPAPER_11X17
, 11.0, 17.0, PR_TRUE
},
146 {DMPAPER_NOTE
, 8.5, 11.0, PR_TRUE
},
147 {DMPAPER_ENV_9
, 3.875, 8.875, PR_TRUE
},
148 {DMPAPER_ENV_10
, 40.125, 9.5, PR_TRUE
},
149 {DMPAPER_ENV_11
, 4.5, 10.375, PR_TRUE
},
150 {DMPAPER_ENV_12
, 4.75, 11.0, PR_TRUE
},
151 {DMPAPER_ENV_14
, 5.0, 11.5, PR_TRUE
},
152 {DMPAPER_ENV_DL
, 110.0, 220.0, PR_FALSE
},
153 {DMPAPER_ENV_C5
, 162.0, 229.0, PR_FALSE
},
154 {DMPAPER_ENV_C3
, 324.0, 458.0, PR_FALSE
},
155 {DMPAPER_ENV_C4
, 229.0, 324.0, PR_FALSE
},
156 {DMPAPER_ENV_C6
, 114.0, 162.0, PR_FALSE
},
157 {DMPAPER_ENV_C65
, 114.0, 229.0, PR_FALSE
},
158 {DMPAPER_ENV_B4
, 250.0, 353.0, PR_FALSE
},
159 {DMPAPER_ENV_B5
, 176.0, 250.0, PR_FALSE
},
160 {DMPAPER_ENV_B6
, 176.0, 125.0, PR_FALSE
},
161 {DMPAPER_ENV_ITALY
, 110.0, 230.0, PR_FALSE
},
162 {DMPAPER_ENV_MONARCH
, 3.875, 7.5, PR_TRUE
},
163 {DMPAPER_ENV_PERSONAL
, 3.625, 6.5, PR_TRUE
},
164 {DMPAPER_FANFOLD_US
, 14.875, 11.0, PR_TRUE
},
165 {DMPAPER_FANFOLD_STD_GERMAN
, 8.5, 12.0, PR_TRUE
},
166 {DMPAPER_FANFOLD_LGL_GERMAN
, 8.5, 13.0, PR_TRUE
},
169 const PRInt32 kNumPaperSizes
= 41;
171 //----------------------------------------------------------------------------------
172 nsDeviceContextSpecWin::nsDeviceContextSpecWin()
174 mDriverName
= nsnull
;
175 mDeviceName
= nsnull
;
181 //----------------------------------------------------------------------------------
183 NS_IMPL_ISUPPORTS1(nsDeviceContextSpecWin
, nsIDeviceContextSpec
)
185 nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
187 SetDeviceName(nsnull
);
188 SetDriverName(nsnull
);
191 nsCOMPtr
<nsIPrintSettingsWin
> psWin(do_QueryInterface(mPrintSettings
));
193 psWin
->SetDeviceName(nsnull
);
194 psWin
->SetDriverName(nsnull
);
195 psWin
->SetDevMode(NULL
);
198 // Free them, we won't need them for a while
199 GlobalPrinters::GetInstance()->FreeGlobalPrinters();
203 //------------------------------------------------------------------
205 static PRUnichar
* GetDefaultPrinterNameFromGlobalPrinters()
207 PRUnichar
* printerName
;
209 GlobalPrinters::GetInstance()->GetDefaultPrinterName(lpPrtName
);
211 NS_CopyNativeToUnicode(nsDependentCString((char *)lpPrtName
), str
);
212 printerName
= ToNewUnicode(str
);
217 //----------------------------------------------------------------
219 EnumerateNativePrinters(DWORD aWhichPrinters
, LPWSTR aPrinterName
, PRBool
& aIsFound
, PRBool
& aIsFile
)
224 DWORD dwSizeNeeded
= 0;
225 DWORD dwNumItems
= 0;
226 LPPRINTER_INFO_2W lpInfo
= NULL
;
229 if (::EnumPrinters ( aWhichPrinters
, NULL
, 2, NULL
, 0, &dwSizeNeeded
, &dwNumItems
)) {
230 return NS_ERROR_FAILURE
;
234 lpInfo
= (LPPRINTER_INFO_2W
)HeapAlloc ( GetProcessHeap (), HEAP_ZERO_MEMORY
, dwSizeNeeded
);
235 if ( lpInfo
== NULL
) {
236 return NS_ERROR_OUT_OF_MEMORY
;
239 if (::EnumPrinters ( PRINTER_ENUM_LOCAL
, NULL
, 2, (LPBYTE
)lpInfo
, dwSizeNeeded
, &dwSizeNeeded
, &dwNumItems
) == 0 ) {
240 ::HeapFree(GetProcessHeap (), 0, lpInfo
);
245 for (DWORD i
= 0; i
< dwNumItems
; i
++ ) {
246 if (wcscmp(lpInfo
[i
].pPrinterName
, aPrinterName
) == 0) {
248 aIsFile
= wcscmp(lpInfo
[i
].pPortName
, L
"FILE:") == 0;
253 ::HeapFree(GetProcessHeap (), 0, lpInfo
);
258 //----------------------------------------------------------------
260 CheckForPrintToFileWithName(LPWSTR aPrinterName
, PRBool
& aIsFile
)
262 PRBool isFound
= PR_FALSE
;
265 nsresult rv
= EnumerateNativePrinters(PRINTER_ENUM_LOCAL
, aPrinterName
, isFound
, aIsFile
);
268 rv
= EnumerateNativePrinters(PRINTER_ENUM_NETWORK
, aPrinterName
, isFound
, aIsFile
);
271 rv
= EnumerateNativePrinters(PRINTER_ENUM_SHARED
, aPrinterName
, isFound
, aIsFile
);
274 rv
= EnumerateNativePrinters(PRINTER_ENUM_REMOTE
, aPrinterName
, isFound
, aIsFile
);
280 GetFileNameForPrintSettings(nsIPrintSettings
* aPS
)
289 nsCOMPtr
<nsIFilePicker
> filePicker
= do_CreateInstance("@mozilla.org/filepicker;1", &rv
);
290 NS_ENSURE_SUCCESS(rv
, rv
);
292 nsCOMPtr
<nsIStringBundleService
> bundleService
= do_GetService(NS_STRINGBUNDLE_CONTRACTID
, &rv
);
293 NS_ENSURE_SUCCESS(rv
, rv
);
294 nsCOMPtr
<nsIStringBundle
> bundle
;
295 rv
= bundleService
->CreateBundle(NS_ERROR_GFX_PRINTER_BUNDLE_URL
, getter_AddRefs(bundle
));
296 NS_ENSURE_SUCCESS(rv
, rv
);
299 rv
= bundle
->GetStringFromName(NS_LITERAL_STRING("PrintToFile").get(), getter_Copies(title
));
300 NS_ENSURE_SUCCESS(rv
, rv
);
302 nsCOMPtr
<nsIWindowWatcher
> wwatch
=
303 (do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
));
304 NS_ENSURE_SUCCESS(rv
, rv
);
306 nsCOMPtr
<nsIDOMWindow
> window
;
307 wwatch
->GetActiveWindow(getter_AddRefs(window
));
309 rv
= filePicker
->Init(window
, title
, nsIFilePicker::modeSave
);
310 NS_ENSURE_SUCCESS(rv
, rv
);
312 rv
= filePicker
->AppendFilters(nsIFilePicker::filterAll
);
313 NS_ENSURE_SUCCESS(rv
, rv
);
316 aPS
->GetToFileName(&fileName
);
320 nsAutoString leafName
;
321 nsCOMPtr
<nsILocalFile
> file(do_CreateInstance("@mozilla.org/file/local;1"));
323 rv
= file
->InitWithPath(nsDependentString(fileName
));
324 if (NS_SUCCEEDED(rv
)) {
325 file
->GetLeafName(leafName
);
326 filePicker
->SetDisplayDirectory(file
);
329 if (!leafName
.IsEmpty()) {
330 rv
= filePicker
->SetDefaultString(leafName
);
332 NS_ENSURE_SUCCESS(rv
, rv
);
334 nsMemory::Free(fileName
);
337 PRInt16 dialogResult
;
338 filePicker
->Show(&dialogResult
);
340 if (dialogResult
== nsIFilePicker::returnCancel
) {
341 return NS_ERROR_ABORT
;
344 nsCOMPtr
<nsILocalFile
> localFile
;
345 rv
= filePicker
->GetFile(getter_AddRefs(localFile
));
346 NS_ENSURE_SUCCESS(rv
, rv
);
348 if (dialogResult
== nsIFilePicker::returnReplace
) {
349 // be extra safe and only delete when the file is really a file
351 rv
= localFile
->IsFile(&isFile
);
352 if (NS_SUCCEEDED(rv
) && isFile
) {
353 rv
= localFile
->Remove(PR_FALSE
/* recursive delete */);
354 NS_ENSURE_SUCCESS(rv
, rv
);
358 nsAutoString unicodePath
;
359 rv
= localFile
->GetPath(unicodePath
);
360 NS_ENSURE_SUCCESS(rv
,rv
);
362 if (unicodePath
.IsEmpty()) {
366 if (NS_SUCCEEDED(rv
)) aPS
->SetToFileName(unicodePath
.get());
371 //----------------------------------------------------------------------------------
373 CheckForPrintToFile(nsIPrintSettings
* aPS
, LPWSTR aPrinterName
, PRUnichar
* aUPrinterName
)
377 if (!aPrinterName
&& !aUPrinterName
) return rv
;
380 CheckForPrintToFileWithName(aPrinterName
?aPrinterName
:aUPrinterName
, toFile
);
381 // Since the driver wasn't a "Print To File" Driver, check to see
382 // if the name of the file has been set to the special "FILE:"
384 nsXPIDLString toFileName
;
385 aPS
->GetToFileName(getter_Copies(toFileName
));
388 if (toFileName
.EqualsLiteral("FILE:")) {
389 // this skips the setting of the "print to file" info below
390 // which we don't want to do.
396 aPS
->SetPrintToFile(toFile
);
398 rv
= GetFileNameForPrintSettings(aPS
);
403 //----------------------------------------------------------------------------------
404 NS_IMETHODIMP
nsDeviceContextSpecWin::Init(nsIWidget
* aWidget
,
405 nsIPrintSettings
* aPrintSettings
,
406 PRBool aIsPrintPreview
)
408 mPrintSettings
= aPrintSettings
;
410 nsresult rv
= aIsPrintPreview
? NS_ERROR_GFX_PRINTER_PRINTPREVIEW
:
411 NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE
;
412 if (aPrintSettings
) {
413 nsCOMPtr
<nsIPrintSettingsWin
> psWin(do_QueryInterface(aPrintSettings
));
415 PRUnichar
* deviceName
;
416 PRUnichar
* driverName
;
417 psWin
->GetDeviceName(&deviceName
); // creates new memory (makes a copy)
418 psWin
->GetDriverName(&driverName
); // creates new memory (makes a copy)
421 psWin
->GetDevMode(&devMode
); // creates new memory (makes a copy)
423 if (deviceName
&& driverName
&& devMode
) {
424 // Scaling is special, it is one of the few
425 // devMode items that we control in layout
426 if (devMode
->dmFields
& DM_SCALE
) {
427 double scale
= double(devMode
->dmScale
) / 100.0f
;
429 aPrintSettings
->SetScaling(scale
);
430 devMode
->dmScale
= 100;
434 SetDeviceName(deviceName
);
435 SetDriverName(driverName
);
438 if (!aIsPrintPreview
) {
439 rv
= CheckForPrintToFile(mPrintSettings
, deviceName
, nsnull
);
441 nsCRT::free(deviceName
);
442 nsCRT::free(driverName
);
443 return NS_ERROR_FAILURE
;
448 nsCRT::free(deviceName
);
449 nsCRT::free(driverName
);
453 PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
454 if (deviceName
) nsCRT::free(deviceName
);
455 if (driverName
) nsCRT::free(driverName
);
456 if (devMode
) ::HeapFree(::GetProcessHeap(), 0, devMode
);
460 PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
463 LPDEVMODEW pDevMode
= NULL
;
464 HGLOBAL hDevNames
= NULL
;
466 // Get the Print Name to be used
467 PRUnichar
* printerName
;
468 mPrintSettings
->GetPrinterName(&printerName
);
470 // If there is no name then use the default printer
471 if (!printerName
|| (printerName
&& !*printerName
)) {
472 printerName
= GetDefaultPrinterNameFromGlobalPrinters();
475 NS_ASSERTION(printerName
, "We have to have a printer name");
476 if (!printerName
|| !*printerName
) return rv
;
478 if (!aIsPrintPreview
) {
479 CheckForPrintToFile(mPrintSettings
, nsnull
, printerName
);
482 return GetDataFromPrinter(printerName
, mPrintSettings
);
485 //----------------------------------------------------------
486 // Helper Function - Free and reallocate the string
487 static void CleanAndCopyString(PRUnichar
*& aStr
, const PRUnichar
* aNewStr
)
489 if (aStr
!= nsnull
) {
490 if (aNewStr
!= nsnull
&& wcslen(aStr
) > wcslen(aNewStr
)) { // reuse it if we can
491 wcscpy(aStr
, aNewStr
);
499 if (nsnull
!= aNewStr
) {
500 aStr
= (PRUnichar
*)PR_Malloc(sizeof(PRUnichar
)*(wcslen(aNewStr
) + 1));
501 wcscpy(aStr
, aNewStr
);
505 NS_IMETHODIMP
nsDeviceContextSpecWin::GetSurfaceForPrinter(gfxASurface
**surface
)
507 NS_ASSERTION(mDevMode
, "DevMode can't be NULL here");
509 nsRefPtr
<gfxASurface
> newSurface
;
511 PRInt16 outputFormat
;
512 mPrintSettings
->GetOutputFormat(&outputFormat
);
514 if (outputFormat
== nsIPrintSettings::kOutputFormatPDF
) {
515 nsXPIDLString filename
;
516 mPrintSettings
->GetToFileName(getter_Copies(filename
));
518 double width
, height
;
519 mPrintSettings
->GetEffectivePageSize(&width
, &height
);
520 // convert twips to points
521 width
/= TWIPS_PER_POINT_FLOAT
;
522 height
/= TWIPS_PER_POINT_FLOAT
;
524 nsCOMPtr
<nsILocalFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
525 nsresult rv
= file
->InitWithPath(filename
);
529 nsCOMPtr
<nsIFileOutputStream
> stream
= do_CreateInstance("@mozilla.org/network/file-output-stream;1");
530 rv
= stream
->Init(file
, -1, -1, 0);
534 newSurface
= new gfxPDFSurface(stream
, gfxSize(width
, height
));
537 HDC dc
= ::CreateDCW(mDriverName
, mDeviceName
, NULL
, mDevMode
);
539 // have this surface take over ownership of this DC
540 newSurface
= new gfxWindowsSurface(dc
, gfxWindowsSurface::FLAG_TAKE_DC
| gfxWindowsSurface::FLAG_FOR_PRINTING
);
545 *surface
= newSurface
;
551 return NS_ERROR_FAILURE
;
554 //----------------------------------------------------------------------------------
555 void nsDeviceContextSpecWin::SetDeviceName(const PRUnichar
* aDeviceName
)
557 CleanAndCopyString(mDeviceName
, aDeviceName
);
560 //----------------------------------------------------------------------------------
561 void nsDeviceContextSpecWin::SetDriverName(const PRUnichar
* aDriverName
)
563 CleanAndCopyString(mDriverName
, aDriverName
);
566 //----------------------------------------------------------------------------------
567 void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode
)
570 ::HeapFree(::GetProcessHeap(), 0, mDevMode
);
576 //------------------------------------------------------------------
578 nsDeviceContextSpecWin::GetDevMode(LPDEVMODEW
&aDevMode
)
583 //----------------------------------------------------------------------------------
584 // Map an incoming size to a Windows Native enum in the DevMode
586 MapPaperSizeToNativeEnum(LPDEVMODEW aDevMode
,
593 BOOL doingOrientation
= aDevMode
->dmFields
& DM_ORIENTATION
;
594 BOOL doingPaperSize
= aDevMode
->dmFields
& DM_PAPERSIZE
;
595 BOOL doingPaperLength
= aDevMode
->dmFields
& DM_PAPERLENGTH
;
596 BOOL doingPaperWidth
= aDevMode
->dmFields
& DM_PAPERWIDTH
;
599 PRBool foundEnum
= PR_FALSE
;
600 for (PRInt32 i
=0;i
<kNumPaperSizes
;i
++) {
601 if (kPaperSizes
[i
].mWidth
== aW
&& kPaperSizes
[i
].mHeight
== aH
) {
602 aDevMode
->dmPaperSize
= kPaperSizes
[i
].mPaperSize
;
603 aDevMode
->dmFields
&= ~DM_PAPERLENGTH
;
604 aDevMode
->dmFields
&= ~DM_PAPERWIDTH
;
605 aDevMode
->dmFields
|= DM_PAPERSIZE
;
612 if (aType
== nsIPrintSettings::kPaperSizeInches
) {
613 width
= short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aW
))) / 10);
614 height
= short(NS_TWIPS_TO_MILLIMETERS(NS_INCHES_TO_TWIPS(float(aH
))) / 10);
616 } else if (aType
== nsIPrintSettings::kPaperSizeMillimeters
) {
617 width
= short(aW
/ 10.0);
618 height
= short(aH
/ 10.0);
620 return; // don't set anything
623 // width and height is in
624 aDevMode
->dmPaperSize
= 0;
625 aDevMode
->dmPaperWidth
= width
;
626 aDevMode
->dmPaperLength
= height
;
628 aDevMode
->dmFields
|= DM_PAPERSIZE
;
629 aDevMode
->dmFields
|= DM_PAPERLENGTH
;
630 aDevMode
->dmFields
|= DM_PAPERWIDTH
;
633 //----------------------------------------------------------------------------------
634 // Setup Paper Size & Orientation options into the DevMode
637 SetupDevModeFromSettings(LPDEVMODEW aDevMode
, nsIPrintSettings
* aPrintSettings
)
640 if (aPrintSettings
) {
642 aPrintSettings
->GetPaperSizeType(&type
);
643 if (type
== nsIPrintSettings::kPaperSizeNativeData
) {
645 aPrintSettings
->GetPaperData(&paperEnum
);
646 aDevMode
->dmPaperSize
= paperEnum
;
647 aDevMode
->dmFields
&= ~DM_PAPERLENGTH
;
648 aDevMode
->dmFields
&= ~DM_PAPERWIDTH
;
649 aDevMode
->dmFields
|= DM_PAPERSIZE
;
652 double width
, height
;
653 aPrintSettings
->GetPaperSizeUnit(&unit
);
654 aPrintSettings
->GetPaperWidth(&width
);
655 aPrintSettings
->GetPaperHeight(&height
);
656 MapPaperSizeToNativeEnum(aDevMode
, unit
, width
, height
);
661 aPrintSettings
->GetOrientation(&orientation
);
662 aDevMode
->dmOrientation
= orientation
== nsIPrintSettings::kPortraitOrientation
?DMORIENT_PORTRAIT
:DMORIENT_LANDSCAPE
;
663 aDevMode
->dmFields
|= DM_ORIENTATION
;
665 // Setup Number of Copies
667 aPrintSettings
->GetNumCopies(&copies
);
668 aDevMode
->dmCopies
= copies
;
669 aDevMode
->dmFields
|= DM_COPIES
;
674 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
675 static void DisplayLastError()
678 DWORD errCode
= GetLastError();
681 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
684 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), // Default language
690 // Display the string.
691 MessageBox( NULL
, (const char *)lpMsgBuf
, "GetLastError", MB_OK
|MB_ICONINFORMATION
);
693 #define DISPLAY_LAST_ERROR DisplayLastError();
695 #define DISPLAY_LAST_ERROR
698 //----------------------------------------------------------------------------------
699 // Setup the object's data member with the selected printer's data
701 nsDeviceContextSpecWin::GetDataFromPrinter(const PRUnichar
* aName
, nsIPrintSettings
* aPS
)
704 return NS_ERROR_NOT_IMPLEMENTED
;
706 nsresult rv
= NS_ERROR_FAILURE
;
708 if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
709 rv
= GlobalPrinters::GetInstance()->EnumeratePrinterList();
711 PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
714 NS_ENSURE_SUCCESS(rv
, rv
);
717 HANDLE hPrinter
= NULL
;
719 BOOL status
= ::OpenPrinterW((LPWSTR
)(aName
),
724 DWORD dwNeeded
, dwRet
;
726 // Allocate a buffer of the correct size.
727 dwNeeded
= ::DocumentPropertiesW(NULL
, hPrinter
,
728 const_cast<wchar_t*>(aName
),
731 pDevMode
= (LPDEVMODEW
)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY
, dwNeeded
);
732 if (!pDevMode
) return NS_ERROR_FAILURE
;
734 // Get the default DevMode for the printer and modify it for our needs.
735 dwRet
= DocumentPropertiesW(NULL
, hPrinter
,
736 const_cast<wchar_t*>(aName
),
737 pDevMode
, NULL
, DM_OUT_BUFFER
);
739 if (dwRet
== IDOK
&& aPS
) {
740 SetupDevModeFromSettings(pDevMode
, aPS
);
741 // Sets back the changes we made to the DevMode into the Printer Driver
742 dwRet
= ::DocumentPropertiesW(NULL
, hPrinter
,
743 const_cast<wchar_t*>(aName
),
745 DM_IN_BUFFER
| DM_OUT_BUFFER
);
749 ::HeapFree(::GetProcessHeap(), 0, pDevMode
);
750 ::ClosePrinter(hPrinter
);
751 PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", dwRet
, dwRet
));
753 return NS_ERROR_FAILURE
;
756 SetDevMode(pDevMode
); // cache the pointer and takes responsibility for the memory
758 SetDeviceName(aName
);
760 SetDriverName(L
"WINSPOOL");
762 ::ClosePrinter(hPrinter
);
765 rv
= NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND
;
766 PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", NS_ConvertUTF16toUTF8(aName
).get()));
773 //----------------------------------------------------------------------------------
774 // Setup Paper Size options into the DevMode
776 // When using a data member it may be a HGLOCAL or LPDEVMODE
777 // if it is a HGLOBAL then we need to "lock" it to get the LPDEVMODE
778 // and unlock it when we are done.
780 nsDeviceContextSpecWin::SetupPaperInfoFromSettings()
785 NS_ASSERTION(devMode
, "DevMode can't be NULL here");
787 SetupDevModeFromSettings(devMode
, mPrintSettings
);
791 //----------------------------------------------------------------------------------
792 // Helper Function - Free and reallocate the string
794 nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(nsIPrintSettings
* aPrintSettings
,
797 if (aPrintSettings
== nsnull
) {
798 return NS_ERROR_FAILURE
;
800 aPrintSettings
->SetIsInitializedFromPrinter(PR_TRUE
);
802 BOOL doingNumCopies
= aDevMode
->dmFields
& DM_COPIES
;
803 BOOL doingOrientation
= aDevMode
->dmFields
& DM_ORIENTATION
;
804 BOOL doingPaperSize
= aDevMode
->dmFields
& DM_PAPERSIZE
;
805 BOOL doingPaperLength
= aDevMode
->dmFields
& DM_PAPERLENGTH
;
806 BOOL doingPaperWidth
= aDevMode
->dmFields
& DM_PAPERWIDTH
;
808 if (doingOrientation
) {
809 PRInt32 orientation
= aDevMode
->dmOrientation
== DMORIENT_PORTRAIT
?
810 nsIPrintSettings::kPortraitOrientation
:nsIPrintSettings::kLandscapeOrientation
;
811 aPrintSettings
->SetOrientation(orientation
);
814 // Setup Number of Copies
815 if (doingNumCopies
) {
816 aPrintSettings
->SetNumCopies(PRInt32(aDevMode
->dmCopies
));
819 if (aDevMode
->dmFields
& DM_SCALE
) {
820 double scale
= double(aDevMode
->dmScale
) / 100.0f
;
822 aPrintSettings
->SetScaling(scale
);
823 aDevMode
->dmScale
= 100;
824 // To turn this on you must change where the mPrt->mShrinkToFit is being set in the DocumentViewer
825 //aPrintSettings->SetShrinkToFit(PR_FALSE);
829 if (doingPaperSize
) {
830 aPrintSettings
->SetPaperSizeType(nsIPrintSettings::kPaperSizeNativeData
);
831 aPrintSettings
->SetPaperData(aDevMode
->dmPaperSize
);
832 for (PRInt32 i
=0;i
<kNumPaperSizes
;i
++) {
833 if (kPaperSizes
[i
].mPaperSize
== aDevMode
->dmPaperSize
) {
834 aPrintSettings
->SetPaperSizeUnit(kPaperSizes
[i
].mIsInches
?nsIPrintSettings::kPaperSizeInches
:nsIPrintSettings::kPaperSizeMillimeters
);
839 } else if (doingPaperLength
&& doingPaperWidth
) {
840 PRBool found
= PR_FALSE
;
841 for (PRInt32 i
=0;i
<kNumPaperSizes
;i
++) {
842 if (kPaperSizes
[i
].mPaperSize
== aDevMode
->dmPaperSize
) {
843 aPrintSettings
->SetPaperSizeType(nsIPrintSettings::kPaperSizeDefined
);
844 aPrintSettings
->SetPaperWidth(kPaperSizes
[i
].mWidth
);
845 aPrintSettings
->SetPaperHeight(kPaperSizes
[i
].mHeight
);
846 aPrintSettings
->SetPaperSizeUnit(kPaperSizes
[i
].mIsInches
?nsIPrintSettings::kPaperSizeInches
:nsIPrintSettings::kPaperSizeMillimeters
);
852 return NS_ERROR_FAILURE
;
855 return NS_ERROR_FAILURE
;
860 //***********************************************************
861 // Printer Enumerator
862 //***********************************************************
863 nsPrinterEnumeratorWin::nsPrinterEnumeratorWin()
867 nsPrinterEnumeratorWin::~nsPrinterEnumeratorWin()
869 // Do not free printers here
870 // GlobalPrinters::GetInstance()->FreeGlobalPrinters();
873 NS_IMPL_ISUPPORTS1(nsPrinterEnumeratorWin
, nsIPrinterEnumerator
)
875 //----------------------------------------------------------------------------------
876 // Return the Default Printer name
877 /* readonly attribute wstring defaultPrinterName; */
879 nsPrinterEnumeratorWin::GetDefaultPrinterName(PRUnichar
* *aDefaultPrinterName
)
881 NS_ENSURE_ARG_POINTER(aDefaultPrinterName
);
883 *aDefaultPrinterName
= GetDefaultPrinterNameFromGlobalPrinters(); // helper
888 /* void initPrintSettingsFromPrinter (in wstring aPrinterName, in nsIPrintSettings aPrintSettings); */
890 nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const PRUnichar
*aPrinterName
, nsIPrintSettings
*aPrintSettings
)
892 NS_ENSURE_ARG_POINTER(aPrinterName
);
893 NS_ENSURE_ARG_POINTER(aPrintSettings
);
895 if (!*aPrinterName
) {
899 nsRefPtr
<nsDeviceContextSpecWin
> devSpecWin
= new nsDeviceContextSpecWin();
900 if (!devSpecWin
) return NS_ERROR_OUT_OF_MEMORY
;
902 if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
903 return NS_ERROR_FAILURE
;
906 devSpecWin
->GetDataFromPrinter(aPrinterName
);
909 devSpecWin
->GetDevMode(devmode
);
910 NS_ASSERTION(devmode
, "DevMode can't be NULL here");
912 aPrintSettings
->SetPrinterName(aPrinterName
);
913 nsDeviceContextSpecWin::SetPrintSettingsFromDevMode(aPrintSettings
, devmode
);
916 // Free them, we won't need them for a while
917 GlobalPrinters::GetInstance()->FreeGlobalPrinters();
922 //----------------------------------------------------------------------------------
923 // Enumerate all the Printers from the global array and pass their
924 // names back (usually to script)
926 nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator
**aPrinterNameList
)
928 NS_ENSURE_ARG_POINTER(aPrinterNameList
);
929 *aPrinterNameList
= nsnull
;
931 nsresult rv
= GlobalPrinters::GetInstance()->EnumeratePrinterList();
933 PR_PL(("***** nsDeviceContextSpecWin::GetPrinterNameList - Couldn't enumerate printers!\n"));
937 PRInt32 numPrinters
= GlobalPrinters::GetInstance()->GetNumPrinters();
938 nsStringArray
*printers
= new nsStringArray(numPrinters
);
940 return NS_ERROR_OUT_OF_MEMORY
;
942 PRInt32 printerInx
= 0;
943 while( printerInx
< numPrinters
) {
944 LPTSTR name
= GlobalPrinters::GetInstance()->GetItemFromList(printerInx
++);
946 nsDependentString
newName(name
);
948 nsAutoString newName
;
949 NS_CopyNativeToUnicode(nsDependentCString(name
), newName
);
951 printers
->AppendString(newName
);
954 return NS_NewAdoptingStringEnumerator(aPrinterNameList
, printers
);
957 //----------------------------------------------------------------------------------
958 // Display the AdvancedDocumentProperties for the selected Printer
959 NS_IMETHODIMP
nsPrinterEnumeratorWin::DisplayPropertiesDlg(const PRUnichar
*aPrinterName
, nsIPrintSettings
* aPrintSettings
)
961 // Implementation removed because it is unused
965 //----------------------------------------------------------------------------------
967 //----------------------------------------------------------------------------------
969 //----------------------------------------------------------------------------------
970 // THe array hold the name and port for each printer
972 GlobalPrinters::ReallocatePrinters()
974 if (PrintersAreAllocated()) {
975 FreeGlobalPrinters();
977 mPrinters
= new nsVoidArray();
978 NS_ASSERTION(mPrinters
, "Printers Array is NULL!");
981 //----------------------------------------------------------------------------------
983 GlobalPrinters::FreeGlobalPrinters()
985 if (mPrinters
!= nsnull
) {
986 for (int i
=0;i
<mPrinters
->Count();i
++) {
987 free((LPTSTR
)mPrinters
->ElementAt(i
));
994 //----------------------------------------------------------------------------------
996 GlobalPrinters::EnumerateNativePrinters()
998 nsresult rv
= NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE
;
1000 PR_PL(("-----------------------\n"));
1001 PR_PL(("EnumerateNativePrinters\n"));
1003 TCHAR szDefaultPrinterName
[1024];
1004 DWORD status
= GetProfileString("devices", 0, ",", szDefaultPrinterName
, sizeof(szDefaultPrinterName
)/sizeof(TCHAR
));
1007 LPTSTR sPtr
= (LPTSTR
)szDefaultPrinterName
;
1008 LPTSTR ePtr
= (LPTSTR
)(szDefaultPrinterName
+(status
*sizeof(TCHAR
)));
1009 LPTSTR prvPtr
= sPtr
;
1010 while (sPtr
< ePtr
) {
1011 if (*sPtr
== NULL
) {
1012 LPTSTR name
= _tcsdup(prvPtr
);
1013 mPrinters
->AppendElement(name
);
1014 PR_PL(("Printer Name: %s\n", prvPtr
));
1022 PR_PL(("-----------------------\n"));
1027 //------------------------------------------------------------------
1028 // Uses the GetProfileString to get the default printer from the registry
1030 GlobalPrinters::GetDefaultPrinterName(LPTSTR
& aDefaultPrinterName
)
1033 aDefaultPrinterName
= nsnull
;
1034 TCHAR szDefaultPrinterName
[1024];
1035 DWORD status
= GetProfileString("windows", "device", 0, szDefaultPrinterName
, sizeof(szDefaultPrinterName
)/sizeof(TCHAR
));
1037 TCHAR comma
= (TCHAR
)',';
1038 LPTSTR sPtr
= (LPTSTR
)szDefaultPrinterName
;
1039 while (*sPtr
!= comma
&& *sPtr
!= NULL
)
1041 if (*sPtr
== comma
) {
1044 aDefaultPrinterName
= _tcsdup(szDefaultPrinterName
);
1046 aDefaultPrinterName
= _tcsdup("");
1049 PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName
));
1051 aDefaultPrinterName
= TEXT("UNKNOWN");
1055 //----------------------------------------------------------------------------------
1056 // This goes and gets the list of available printers and puts
1057 // the default printer at the beginning of the list
1059 GlobalPrinters::EnumeratePrinterList()
1061 // reallocate and get a new list each time it is asked for
1062 // this deletes the list and re-allocates them
1063 ReallocatePrinters();
1065 // any of these could only fail with an OUT_MEMORY_ERROR
1066 // PRINTER_ENUM_LOCAL should get the network printers on Win95
1067 nsresult rv
= EnumerateNativePrinters();
1068 if (NS_FAILED(rv
)) return rv
;
1070 // get the name of the default printer
1071 LPTSTR defPrinterName
;
1072 GetDefaultPrinterName(defPrinterName
);
1074 // put the default printer at the beginning of list
1075 if (defPrinterName
!= nsnull
) {
1076 for (PRInt32 i
=0;i
<mPrinters
->Count();i
++) {
1077 LPTSTR name
= (LPTSTR
)mPrinters
->ElementAt(i
);
1078 if (!_tcscmp(name
, defPrinterName
)) {
1080 LPTSTR ptr
= (LPTSTR
)mPrinters
->ElementAt(0);
1081 mPrinters
->ReplaceElementAt((void*)name
, 0);
1082 mPrinters
->ReplaceElementAt((void*)ptr
, i
);
1087 free(defPrinterName
);
1090 // make sure we at least tried to get the printers
1091 if (!PrintersAreAllocated()) {
1092 PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t allocated\n"));
1093 return NS_ERROR_FAILURE
;