2 * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: PrinterSetupWizardSheet.cpp,v $
26 Revision 1.17 2004/10/12 18:02:53 shersche
27 <rdar://problem/3764873> Escape '/', '@', '"' characters in printui command.
30 Revision 1.16 2004/09/13 21:27:22 shersche
31 <rdar://problem/3796483> Pass the moreComing flag to OnAddPrinter and OnRemovePrinter callbacks
34 Revision 1.15 2004/09/11 05:59:06 shersche
35 <rdar://problem/3785766> Fix code that generates unique printer names based on currently installed printers
38 Revision 1.14 2004/09/02 01:57:58 cheshire
39 <rdar://problem/3783611> Fix incorrect testing of MoreComing flag
41 Revision 1.13 2004/07/26 21:06:29 shersche
42 <rdar://problem/3739200> Removing trailing '.' in hostname
45 Revision 1.12 2004/07/13 21:24:23 rpantos
46 Fix for <rdar://problem/3701120>.
48 Revision 1.11 2004/06/28 00:51:47 shersche
49 Move call to EnumPrinters out of browse callback into standalone function
51 Revision 1.10 2004/06/27 23:06:47 shersche
52 code cleanup, make sure EnumPrinters returns non-zero value
54 Revision 1.9 2004/06/27 15:49:31 shersche
55 clean up some cruft in the printer browsing code
57 Revision 1.8 2004/06/27 08:04:51 shersche
58 copy selected printer to prevent printer being deleted out from under
60 Revision 1.7 2004/06/26 23:27:12 shersche
61 support for installing multiple printers of the same name
63 Revision 1.6 2004/06/26 21:22:39 shersche
64 handle spaces in file names
66 Revision 1.5 2004/06/26 03:19:57 shersche
67 clean up warning messages
69 Submitted by: herscher
71 Revision 1.4 2004/06/25 02:26:52 shersche
72 Normalize key fields in text record entries
73 Submitted by: herscher
75 Revision 1.3 2004/06/24 20:12:07 shersche
77 Submitted by: herscher
79 Revision 1.2 2004/06/23 17:58:21 shersche
80 <rdar://problem/3701837> eliminated memory leaks on exit
81 <rdar://problem/3701926> installation of a printer that is already installed results in a no-op
82 Bug #: 3701837, 3701926
83 Submitted by: herscher
85 Revision 1.1 2004/06/18 04:36:57 rpantos
92 #include "PrinterSetupWizardApp.h"
93 #include "PrinterSetupWizardSheet.h"
94 #include "CommonServices.h"
95 #include "DebugServices.h"
96 #include "WinServices.h"
103 #pragma warning(disable:4702)
106 #if( !TARGET_OS_WINDOWS_CE )
107 # include <mswsock.h>
108 # include <process.h>
113 #define WM_SERVICE_EVENT ( WM_USER + 0x100 )
114 #define WM_PROCESS_EVENT ( WM_USER + 0x101 )
118 #define kPDLDataStreamServiceType "_pdl-datastream._tcp"
119 #define kLPRServiceType "_printer._tcp"
120 #define kIPPServiceType "_ipp._tcp"
123 // CPrinterSetupWizardSheet
125 IMPLEMENT_DYNAMIC(CPrinterSetupWizardSheet
, CPropertySheet
)
126 CPrinterSetupWizardSheet::CPrinterSetupWizardSheet(UINT nIDCaption
, CWnd
* pParentWnd
, UINT iSelectPage
)
127 :CPropertySheet(nIDCaption
, pParentWnd
, iSelectPage
),
128 m_selectedPrinter(NULL
)
130 m_arrow
= LoadCursor(0, IDC_ARROW
);
131 m_wait
= LoadCursor(0, IDC_APPSTARTING
);
138 CPrinterSetupWizardSheet::~CPrinterSetupWizardSheet()
141 // rdar://problem/3701837 memory leaks
143 // Clean up the ServiceRef and printer list on exit
145 if (m_pdlBrowser
!= NULL
)
147 DNSServiceRefDeallocate(m_pdlBrowser
);
151 while (m_printerList
.size() > 0)
153 Printer
* printer
= m_printerList
.front();
155 m_printerList
.pop_front();
160 if (m_selectedPrinter
!= NULL
)
162 delete m_selectedPrinter
;
167 // ------------------------------------------------------
168 // InstallEventHandler
170 // Installs an event handler for DNSService events.
173 CPrinterSetupWizardSheet::InstallEventHandler(EventHandler
* handler
)
175 PrinterList::iterator iter
;
177 m_eventHandlerList
.push_back(handler
);
179 iter
= m_printerList
.begin();
181 while (iter
!= m_printerList
.end())
183 Printer
* printer
= *iter
++;
185 handler
->OnAddPrinter(printer
, iter
!= m_printerList
.end());
192 // ------------------------------------------------------
193 // RemoveEventHandler
195 // Removes an event handler for DNSService events.
198 CPrinterSetupWizardSheet::RemoveEventHandler(EventHandler
* handler
)
200 m_eventHandlerList
.remove(handler
);
207 // ------------------------------------------------------
208 // SetSelectedPrinter
210 // Manages setting a printer as the printer to install. Stops
211 // any pending resolves.
214 CPrinterSetupWizardSheet::SetSelectedPrinter(Printer
* printer
)
219 // we only want one resolve going on at a time, so we check
220 // state of the m_selectedPrinter
222 if (m_selectedPrinter
!= NULL
)
225 // if we're currently resolving, then stop the resolve
227 if (m_selectedPrinter
->serviceRef
)
229 err
= StopResolve(m_selectedPrinter
);
230 require_noerr(err
, exit
);
233 delete m_selectedPrinter
;
234 m_selectedPrinter
= NULL
;
237 check( m_selectedPrinter
== NULL
);
241 m_selectedPrinter
= new Printer
;
245 m_selectedPrinter
= NULL
;
248 require_action( m_selectedPrinter
, exit
, err
= E_OUTOFMEMORY
);
250 m_selectedPrinter
->window
= printer
->window
;
251 m_selectedPrinter
->serviceRef
= NULL
;
252 m_selectedPrinter
->item
= NULL
;
253 m_selectedPrinter
->ifi
= printer
->ifi
;
254 m_selectedPrinter
->name
= printer
->name
;
255 m_selectedPrinter
->displayName
= printer
->displayName
;
256 m_selectedPrinter
->actualName
= printer
->actualName
;
257 m_selectedPrinter
->type
= printer
->type
;
258 m_selectedPrinter
->domain
= printer
->domain
;
259 m_selectedPrinter
->installed
= printer
->installed
;
260 m_selectedPrinter
->deflt
= printer
->deflt
;
261 m_selectedPrinter
->refs
= 1;
263 err
= StartResolve(m_selectedPrinter
);
264 require_noerr(err
, exit
);
272 // ------------------------------------------------------
275 // Installs a printer with Windows.
277 // NOTE: this works one of two ways, depending on whether
278 // there are drivers already installed for this printer.
279 // If there are, then we can just create a port with XcvData,
280 // and then call AddPrinter. If not, we use the printui.dll
281 // to install the printer. Actually installing drivers that
282 // are not currently installed is painful, and it's much
283 // easier and less error prone to just let printui.dll do
284 // the hard work for us.
288 CPrinterSetupWizardSheet::InstallPrinter(Printer
* printer
)
290 PRINTER_DEFAULTS printerDefaults
= { NULL
, NULL
, SERVER_ACCESS_ADMINISTER
};
292 DWORD cbInputData
= 100;
293 PBYTE pOutputData
= NULL
;
294 DWORD cbOutputNeeded
= 0;
295 PORT_DATA_1 portData
;
297 HANDLE hPrinter
= NULL
;
301 check(printer
!= NULL
);
302 check(printer
->installed
== false);
304 ok
= OpenPrinter(L
",XcvMonitor Standard TCP/IP Port", &hXcv
, &printerDefaults
);
305 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
306 require_noerr( err
, exit
);
309 // BUGBUG: MSDN said this is not required, but my experience shows it is required
313 pOutputData
= new BYTE
[cbInputData
];
320 require_action( pOutputData
, exit
, err
= kNoMemoryErr
);
325 ZeroMemory(&portData
, sizeof(PORT_DATA_1
));
326 wcscpy(portData
.sztPortName
, printer
->portName
);
328 portData
.dwPortNumber
= printer
->portNumber
;
329 portData
.dwVersion
= 1;
331 portData
.dwProtocol
= PROTOCOL_RAWTCP_TYPE
;
332 portData
.cbSize
= sizeof PORT_DATA_1
;
333 portData
.dwReserved
= 0L;
335 wcscpy(portData
.sztQueue
, printer
->hostname
);
336 wcscpy(portData
.sztIPAddress
, printer
->hostname
);
337 wcscpy(portData
.sztHostAddress
, printer
->hostname
);
339 ok
= XcvData(hXcv
, L
"AddPort", (PBYTE
) &portData
, sizeof(PORT_DATA_1
), pOutputData
, cbInputData
, &cbOutputNeeded
, &dwStatus
);
340 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
341 require_noerr( err
, exit
);
343 if (printer
->driverInstalled
)
345 PRINTER_INFO_2 pInfo
;
347 ZeroMemory(&pInfo
, sizeof(pInfo
));
349 pInfo
.pPrinterName
= printer
->actualName
.GetBuffer();
350 pInfo
.pServerName
= NULL
;
351 pInfo
.pShareName
= NULL
;
352 pInfo
.pPortName
= printer
->portName
.GetBuffer();
353 pInfo
.pDriverName
= printer
->model
.GetBuffer();
354 pInfo
.pComment
= printer
->model
.GetBuffer();
355 pInfo
.pLocation
= L
"";
356 pInfo
.pDevMode
= NULL
;
357 pInfo
.pDevMode
= NULL
;
358 pInfo
.pSepFile
= L
"";
359 pInfo
.pPrintProcessor
= L
"winprint";
360 pInfo
.pDatatype
= L
"RAW";
361 pInfo
.pParameters
= L
"";
362 pInfo
.pSecurityDescriptor
= NULL
;
363 pInfo
.Attributes
= PRINTER_ATTRIBUTE_QUEUED
;
365 pInfo
.DefaultPriority
= 0;
369 hPrinter
= AddPrinter(NULL
, 2, (LPBYTE
) &pInfo
);
370 err
= translate_errno( hPrinter
, errno_compat(), kUnknownErr
);
371 require_noerr( err
, exit
);
380 m_processFinished
= false;
385 hThread
= (HANDLE
) _beginthreadex_compat( NULL
, 0, InstallPrinterThread
, printer
, 0, &threadID
);
386 err
= translate_errno( hThread
, (OSStatus
) GetLastError(), kUnknownErr
);
387 require_noerr( err
, exit
);
392 while (!m_processFinished
)
396 GetMessage( &msg
, m_hWnd
, 0, 0 );
397 TranslateMessage(&msg
);
398 DispatchMessage(&msg
);
402 // Wait until child process exits.
404 dwResult
= WaitForSingleObject( hThread
, INFINITE
);
405 err
= translate_errno( dwResult
== WAIT_OBJECT_0
, errno_compat(), err
= kUnknownErr
);
406 require_noerr( err
, exit
);
409 printer
->installed
= true;
412 // if the user specified a default printer, set it
416 ok
= SetDefaultPrinter(printer
->actualName
);
417 err
= translate_errno( ok
, errno_compat(), err
= kUnknownErr
);
418 require_noerr( err
, exit
);
423 if (hPrinter
!= NULL
)
425 ClosePrinter(hPrinter
);
433 if (pOutputData
!= NULL
)
435 delete [] pOutputData
;
442 BEGIN_MESSAGE_MAP(CPrinterSetupWizardSheet
, CPropertySheet
)
443 ON_MESSAGE( WM_SERVICE_EVENT
, OnServiceEvent
)
444 ON_MESSAGE( WM_PROCESS_EVENT
, OnProcessEvent
)
449 // ------------------------------------------------------
452 // Traps when the user hits Finish
454 BOOL
CPrinterSetupWizardSheet::OnCommand(WPARAM wParam
, LPARAM lParam
)
457 // Check if this is OK
459 if (wParam
== ID_WIZFINISH
) // If OK is hit...
464 return CPropertySheet::OnCommand(wParam
, lParam
);
468 // ------------------------------------------------------
471 // Initializes this Dialog object. We start the browse here,
472 // so that printers show up instantly when the user clicks
475 BOOL
CPrinterSetupWizardSheet::OnInitDialog()
479 CPropertySheet::OnInitDialog();
482 // setup the DNS-SD browsing
484 err
= DNSServiceBrowse( &m_pdlBrowser
, 0, 0, kPDLDataStreamServiceType
, NULL
, OnBrowse
, this );
485 require_noerr( err
, exit
);
487 m_serviceRefList
.push_back(m_pdlBrowser
);
489 err
= WSAAsyncSelect((SOCKET
) DNSServiceRefSockFD(m_pdlBrowser
), m_hWnd
, WM_SERVICE_EVENT
, FD_READ
|FD_CLOSE
);
490 require_noerr( err
, exit
);
500 exc
.text
.LoadString(IDS_NO_MDNSRESPONDER_SERVICE_TEXT
);
501 exc
.caption
.LoadString(IDS_NO_MDNSRESPONDER_SERVICE_CAPTION
);
510 // ------------------------------------------------------
513 // This is called when Windows wants to know what cursor
514 // to display. So we tell it.
517 CPrinterSetupWizardSheet::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
520 DEBUG_UNUSED(nHitTest
);
521 DEBUG_UNUSED(message
);
528 // ------------------------------------------------------
531 // This is not fully implemented yet.
535 CPrinterSetupWizardSheet::OnContextMenu(CWnd
* pWnd
, CPoint pos
)
546 // ------------------------------------------------------
549 // This is called when the user hits the "Finish" button
552 CPrinterSetupWizardSheet::OnOK()
554 check ( m_selectedPrinter
!= NULL
);
556 SetWizardButtons( PSWIZB_DISABLEDFINISH
);
558 if ( InstallPrinter( m_selectedPrinter
) != kNoErr
)
563 caption
.LoadString(IDS_INSTALL_ERROR_CAPTION
);
564 message
.LoadString(IDS_INSTALL_ERROR_MESSAGE
);
566 MessageBox(message
, caption
, MB_OK
|MB_ICONEXCLAMATION
);
571 // CPrinterSetupWizardSheet message handlers
573 void CPrinterSetupWizardSheet::Init(void)
576 AddPage(&m_pgSecond
);
578 AddPage(&m_pgFourth
);
580 m_psh
.dwFlags
&= (~PSH_HASHELP
);
582 m_psh
.dwFlags
|= PSH_WIZARD97
|PSH_WATERMARK
|PSH_HEADER
;
583 m_psh
.pszbmWatermark
= MAKEINTRESOURCE(IDB_WATERMARK
);
584 m_psh
.pszbmHeader
= MAKEINTRESOURCE(IDB_BANNER_ICON
);
586 m_psh
.hInstance
= AfxGetInstanceHandle();
593 CPrinterSetupWizardSheet::OnServiceEvent(WPARAM inWParam
, LPARAM inLParam
)
595 if (WSAGETSELECTERROR(inLParam
) && !(HIWORD(inLParam
)))
597 dlog( kDebugLevelError
, "OnServiceEvent: window error\n" );
601 SOCKET sock
= (SOCKET
) inWParam
;
604 ServiceRefList::iterator begin
= m_serviceRefList
.begin();
605 ServiceRefList::iterator end
= m_serviceRefList
.end();
609 DNSServiceRef ref
= *begin
++;
613 if ((SOCKET
) DNSServiceRefSockFD(ref
) == sock
)
615 DNSServiceProcessResult(ref
);
626 CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam
, LPARAM inLParam
)
628 DEBUG_UNUSED(inWParam
);
629 DEBUG_UNUSED(inLParam
);
631 m_processFinished
= true;
638 CPrinterSetupWizardSheet::OnBrowse(
640 DNSServiceFlags inFlags
,
641 uint32_t inInterfaceIndex
,
642 DNSServiceErrorType inErrorCode
,
645 const char * inDomain
,
650 CPrinterSetupWizardSheet
* self
;
652 EventHandlerList::iterator it
;
653 DWORD printerNameCount
;
654 bool moreComing
= (bool) (inFlags
& kDNSServiceFlagsMoreComing
);
656 require_noerr( inErrorCode
, exit
);
658 self
= reinterpret_cast <CPrinterSetupWizardSheet
*>( inContext
);
659 require_quiet( self
, exit
);
661 printer
= self
->LookUp(inName
);
663 if (inFlags
& kDNSServiceFlagsAdd
)
675 printer
= new Printer
;
682 require_action( printer
, exit
, err
= E_OUTOFMEMORY
);
684 printer
->window
= self
;
685 printer
->ifi
= inInterfaceIndex
;
686 printer
->name
= inName
;
687 err
= UTF8StringToStringObject(inName
, printer
->displayName
);
689 printer
->actualName
= printer
->displayName
;
692 // Compare this name against printers that are already installed
693 // to avoid name clashes. Rename as necessary
694 // to come up with a unique name.
696 printerNameCount
= 2;
700 PrinterNameMap::iterator it
;
702 it
= self
->m_printerNames
.find(printer
->actualName
);
704 if (it
!= self
->m_printerNames
.end())
706 printer
->actualName
.Format(L
"%s (%d)", printer
->displayName
, printerNameCount
);
716 printer
->type
= inType
;
717 printer
->domain
= inDomain
;
718 printer
->installed
= false;
719 printer
->deflt
= false;
722 self
->m_printerList
.push_back( printer
);
725 // now invoke event handlers for AddPrinter event
727 for (it
= self
->m_eventHandlerList
.begin(); it
!= self
->m_eventHandlerList
.end(); it
++)
729 EventHandler
* handler
= *it
;
731 handler
->OnAddPrinter(printer
, moreComing
);
737 if ((printer
!= NULL
) && (--printer
->refs
== 0))
740 // now invoke event handlers for RemovePrinter event
742 for (it
= self
->m_eventHandlerList
.begin(); it
!= self
->m_eventHandlerList
.end(); it
++)
744 EventHandler
* handler
= *it
;
746 handler
->OnRemovePrinter(printer
, moreComing
);
749 self
->m_printerList
.remove(printer
);
752 // check to see if we've selected this printer
754 if (self
->m_selectedPrinter
== printer
)
757 // this guy is being removed while we're resolving it...so let's
760 if (printer
->serviceRef
!= NULL
)
762 self
->StopResolve(printer
);
765 self
->m_selectedPrinter
= NULL
;
779 CPrinterSetupWizardSheet::OnResolve(
781 DNSServiceFlags inFlags
,
782 uint32_t inInterfaceIndex
,
783 DNSServiceErrorType inErrorCode
,
784 const char * inFullName
,
785 const char * inHostName
,
791 DEBUG_UNUSED(inFullName
);
792 DEBUG_UNUSED(inInterfaceIndex
);
793 DEBUG_UNUSED(inFlags
);
797 CPrinterSetupWizardSheet
* self
;
798 EventHandlerList::iterator it1
;
799 EventHandlerList::iterator it2
;
803 require_noerr( inErrorCode
, exit
);
805 printer
= reinterpret_cast<Printer
*>( inContext
);
806 require_quiet( printer
, exit
);
808 self
= printer
->window
;
809 require_quiet( self
, exit
);
811 err
= self
->StopResolve(printer
);
812 require_noerr(err
, exit
);
815 // hold on to the hostname...
817 err
= UTF8StringToStringObject( inHostName
, printer
->hostname
);
818 require_noerr( err
, exit
);
821 // <rdar://problem/3739200> remove the trailing dot on hostname
823 idx
= printer
->hostname
.ReverseFind('.');
825 if ((idx
> 1) && ((printer
->hostname
.GetLength() - 1) == idx
))
827 printer
->hostname
.Delete(idx
, 1);
831 // hold on to the port
833 printer
->portNumber
= ntohs(inPort
);
836 // parse the text record. we create a stringlist of text record
837 // entries that can be interrogated later
843 unsigned char num
= *inTXT
;
844 check( (int) num
< inTXTSize
);
846 memset(buf
, 0, sizeof(buf
));
847 memcpy(buf
, inTXT
+ 1, num
);
849 inTXTSize
-= (num
+ 1);
854 err
= UTF8StringToStringObject( buf
, elem
);
855 require_noerr( err
, exit
);
859 CString key
= elem
.Tokenize(L
"=", curPos
);
860 CString val
= elem
.Tokenize(L
"=", curPos
);
864 if ((key
== L
"usb_mfg") || (key
== L
"usb_manufacturer"))
866 printer
->usb_MFG
= val
;
868 else if ((key
== L
"usb_mdl") || (key
== L
"usb_model"))
870 printer
->usb_MDL
= val
;
872 else if (key
== L
"description")
874 printer
->description
= val
;
876 else if (key
== L
"product")
878 printer
->product
= val
;
883 // now invoke event handlers for Resolve event
885 it1
= self
->m_eventHandlerList
.begin();
886 it2
= self
->m_eventHandlerList
.end();
890 EventHandler
* handler
= *it1
++;
892 handler
->OnResolvePrinter(printer
);
902 CPrinterSetupWizardSheet::LoadPrinterNames()
908 // rdar://problem/3701926 - Printer can't be installed twice
910 // First thing we want to do is make sure the printer isn't already installed.
911 // If the printer name is found, we'll try and rename it until we
912 // find a unique name
914 DWORD dwNeeded
= 0, dwNumPrinters
= 0;
916 BOOL ok
= EnumPrinters(PRINTER_ENUM_LOCAL
, NULL
, 4, NULL
, 0, &dwNeeded
, &dwNumPrinters
);
917 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
919 if ((err
== ERROR_INSUFFICIENT_BUFFER
) && (dwNeeded
> 0))
923 buffer
= new unsigned char[dwNeeded
];
930 require_action( buffer
, exit
, kNoMemoryErr
);
931 ok
= EnumPrinters(PRINTER_ENUM_LOCAL
, NULL
, 4, buffer
, dwNeeded
, &dwNeeded
, &dwNumPrinters
);
932 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
933 require_noerr( err
, exit
);
935 for (DWORD index
= 0; index
< dwNumPrinters
; index
++)
937 PRINTER_INFO_4
* lppi4
= (PRINTER_INFO_4
*) (buffer
+ index
* sizeof(PRINTER_INFO_4
));
939 m_printerNames
[lppi4
->pPrinterName
] = lppi4
->pPrinterName
;
955 CPrinterSetupWizardSheet::StartResolve(Printer
* printer
)
961 err
= DNSServiceResolve( &printer
->serviceRef
, 0, 0, printer
->name
.c_str(), printer
->type
.c_str(), printer
->domain
.c_str(), (DNSServiceResolveReply
) OnResolve
, printer
);
962 require_noerr( err
, exit
);
964 m_serviceRefList
.push_back(printer
->serviceRef
);
966 err
= WSAAsyncSelect((SOCKET
) DNSServiceRefSockFD(printer
->serviceRef
), m_hWnd
, WM_SERVICE_EVENT
, FD_READ
|FD_CLOSE
);
967 require_noerr( err
, exit
);
970 // set the cursor to arrow+hourglass
982 CPrinterSetupWizardSheet::StopResolve(Printer
* printer
)
987 check( printer
->serviceRef
);
989 m_serviceRefList
.remove( printer
->serviceRef
);
991 err
= WSAAsyncSelect((SOCKET
) DNSServiceRefSockFD(printer
->serviceRef
), m_hWnd
, 0, 0);
994 DNSServiceRefDeallocate( printer
->serviceRef
);
996 printer
->serviceRef
= NULL
;
999 // set the cursor back to normal
1002 SetCursor(m_active
);
1009 CPrinterSetupWizardSheet::LookUp(const char * inName
)
1011 PrinterList::iterator it1
= m_printerList
.begin();
1012 PrinterList::iterator it2
= m_printerList
.end();
1016 Printer
* printer
= *it1
++;
1018 if (printer
->name
== inName
)
1029 CPrinterSetupWizardSheet::InstallPrinterThread( LPVOID inParam
)
1033 Printer
* printer
= (Printer
*) inParam
;
1040 PROCESS_INFORMATION pi
;
1043 ZeroMemory( &si
, sizeof(si
) );
1045 ZeroMemory( &pi
, sizeof(pi
) );
1048 // <rdar://problem/3764873> Escape '\', '@', '"' characters which seem to cause problems for printui
1051 actualName
= printer
->actualName
;
1053 actualName
.Replace(L
"\\", L
"\\\\");
1054 actualName
.Replace(L
"@", L
"\\@");
1055 actualName
.Replace(L
"\"", L
"\\\"");
1057 command
.Format(L
"rundll32.exe printui.dll,PrintUIEntry /if /b \"%s\" /f \"%s\" /r \"%s\" /m \"%s\"", (LPCTSTR
) actualName
, (LPCTSTR
) printer
->infFileName
, (LPCTSTR
) printer
->portName
, (LPCTSTR
) printer
->model
);
1059 ok
= CreateProcess(NULL
, command
.GetBuffer(), NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1060 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
1061 require_noerr( err
, exit
);
1063 dwResult
= WaitForSingleObject( pi
.hProcess
, INFINITE
);
1064 translate_errno( dwResult
== WAIT_OBJECT_0
, errno_compat(), err
= kUnknownErr
);
1065 require_noerr( err
, exit
);
1067 ok
= GetExitCodeProcess( pi
.hProcess
, &exitCode
);
1068 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
1069 require_noerr( err
, exit
);
1072 // Close process and thread handles.
1074 CloseHandle( pi
.hProcess
);
1075 CloseHandle( pi
.hThread
);
1080 // alert the main thread
1082 printer
->window
->PostMessage( WM_PROCESS_EVENT
, err
, exitCode
);