Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

728 lines
17 KiB

  1. /*++
  2. Copyright (c) 1995-97 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. SrvInst.c
  6. Purpose:
  7. Server side install code. This code will be called from a process created by the spooler to do a
  8. "server" side install of a printer driver.
  9. Author:
  10. Patrick Vine (pvine) - 22 March 2000
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "srvinst.hxx"
  16. const TCHAR gcszNTPrint[] = _TEXT("inf\\ntprint.inf");
  17. const TCHAR gcszPrintKey[] = _TEXT("SYSTEM\\CurrentControlSet\\Control\\Print");
  18. const TCHAR gcszTimeOut[] = _TEXT("ServerInstallTimeOut");
  19. const TCHAR gcSpace = _TEXT(' ');
  20. #define DEFAULT_MAX_TIMEOUT 300000 // 5 minute timeout.
  21. /*++
  22. Routine Name:
  23. ServerInstall
  24. Routine Description:
  25. Server side install code to be called by a process created by spooler.
  26. Arguments:
  27. hwnd - Window handle of stub window.
  28. hInstance, - Rundll instance handle.
  29. pszCmdLine - Pointer to command line.
  30. nCmdShow - Show command value always TRUE.
  31. Return Value:
  32. Returns the last error code. This can be read by the spooler by getting the return code from the process.
  33. --*/
  34. DWORD
  35. ServerInstallW(
  36. IN HWND hwnd,
  37. IN HINSTANCE hInstance,
  38. IN LPCTSTR pszCmdLine,
  39. IN UINT nCmdShow
  40. )
  41. {
  42. CServerInstall Installer;
  43. if( Installer.ParseCommand( (LPTSTR)pszCmdLine) && Installer.OpenPipe())
  44. {
  45. if( Installer.GetInstallParameters() )
  46. Installer.InstallDriver();
  47. Installer.SendError();
  48. Installer.ClosePipe();
  49. }
  50. return Installer.GetLastError();
  51. }
  52. ////////////////////////////////////////////////////////////////////////////////
  53. //
  54. // Method definitions for CServerInstall Class.
  55. //
  56. ////////////////////////////////////////////////////////////////////////////////
  57. CServerInstall::
  58. CServerInstall() : _dwLastError(ERROR_SUCCESS),
  59. _tsDriverName(),
  60. _tsInf(),
  61. _tsSource(),
  62. _tsFlags(),
  63. _tsPipeName(),
  64. _hPipe(INVALID_HANDLE_VALUE)
  65. {
  66. SetMaxTimeOut();
  67. }
  68. CServerInstall::
  69. ~CServerInstall()
  70. {
  71. ClosePipe();
  72. }
  73. void
  74. CServerInstall::
  75. SetMaxTimeOut()
  76. {
  77. HKEY hKey;
  78. DWORD dwDummy;
  79. DWORD dwSize = sizeof(_dwMaxTimeOut);
  80. _dwMaxTimeOut = DEFAULT_MAX_TIMEOUT;
  81. if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, gcszPrintKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS )
  82. {
  83. if(RegQueryValueEx( hKey, gcszTimeOut, 0, &dwDummy, (LPBYTE)&_dwMaxTimeOut, &dwSize ) != ERROR_SUCCESS)
  84. {
  85. _dwMaxTimeOut = DEFAULT_MAX_TIMEOUT;
  86. }
  87. RegCloseKey( hKey );
  88. }
  89. }
  90. BOOL
  91. CServerInstall::
  92. InstallDriver()
  93. {
  94. if( SetInfDir() &&
  95. bValidateSourcePath() &&
  96. DriverNotInstalled() )
  97. {
  98. _dwLastError = ::InstallDriverSilently(_tsInf, _tsDriverName, _tsSource);
  99. }
  100. return (_dwLastError == ERROR_SUCCESS);
  101. }
  102. /*++
  103. Parameter structure:
  104. 1st word : Flags = default == 0 for now
  105. if flags = 0
  106. 2nd word : Pipe name to open
  107. --*/
  108. BOOL
  109. CServerInstall::
  110. ParseCommand( LPTSTR pszCommandStr )
  111. {
  112. TCHAR * pTemp;
  113. DWORD dwCount = 0;
  114. //
  115. // If we don't have a valid command string
  116. //
  117. if( !pszCommandStr || !*pszCommandStr )
  118. {
  119. _dwLastError = ERROR_INVALID_PARAMETER;
  120. goto Cleanup;
  121. }
  122. //
  123. // Lets grab the flags field
  124. //
  125. pTemp = _tcschr( pszCommandStr, gcSpace );
  126. if( !pTemp )
  127. {
  128. //
  129. // No flags field, fail.
  130. //
  131. _dwLastError = ERROR_INVALID_PARAMETER;
  132. goto Cleanup;
  133. }
  134. *(pTemp++) = 0;
  135. if( !_tsFlags.bUpdate( pszCommandStr ))
  136. {
  137. _dwLastError = ::GetLastError();
  138. goto Cleanup;
  139. }
  140. //
  141. // Currently we only have one case - so we don't need to worry about the
  142. // flags nor branch on them. however we may want to in the future.
  143. //
  144. //
  145. // The rest of the command line is the pipe's name.
  146. //
  147. if( !_tsPipeName.bUpdate( pTemp ))
  148. _dwLastError = ::GetLastError();
  149. Cleanup:
  150. return (_dwLastError == ERROR_SUCCESS);
  151. }
  152. BOOL
  153. CServerInstall::
  154. GetInstallParameters()
  155. {
  156. if(!GetOneParam( &_tsDriverName ))
  157. goto Done;
  158. if( _tsDriverName.bEmpty() )
  159. {
  160. _dwLastError = ERROR_INVALID_PARAMETER;
  161. goto Done;
  162. }
  163. if(!GetOneParam( &_tsInf ))
  164. goto Done;
  165. GetOneParam( &_tsSource );
  166. Done:
  167. return (_dwLastError == ERROR_SUCCESS);
  168. }
  169. //
  170. // Read the size of the string to follow from the pipe.
  171. // Then reads the string and places it in the TString passed.
  172. //
  173. BOOL
  174. CServerInstall::
  175. GetOneParam( TString * tString )
  176. {
  177. DWORD dwSize = 0;
  178. DWORD dwRet = 0;
  179. LPTSTR pszString = NULL;
  180. LPVOID pData = NULL;
  181. if( !ReadOverlapped( _hPipe, &dwSize, sizeof(dwSize), &dwRet ))
  182. goto Done;
  183. if( dwSize == 0 )
  184. goto Done;
  185. //
  186. // The data that we're receiving will be WCHARs as spooler only works with UNICODE.
  187. //
  188. if(!(pData = LocalAllocMem((dwSize + 1)*sizeof(WCHAR))))
  189. {
  190. _dwLastError = ::GetLastError();
  191. goto Done;
  192. }
  193. if( !ReadOverlapped( _hPipe, pData, dwSize*sizeof(WCHAR), &dwRet ) )
  194. goto Done;
  195. if( dwRet != dwSize*sizeof(WCHAR) )
  196. _dwLastError = ERROR_INVALID_PARAMETER;
  197. //
  198. // Because ntprint compiles to both unicode and ansi we need to do this conversion.
  199. // The string coming in will be unicode as it comes from spooler which only
  200. // uses wchars.
  201. //
  202. #ifdef UNICODE
  203. pszString = (LPTSTR)pData;
  204. pData = NULL;
  205. #else
  206. //Get the length of the unicode string
  207. dwSize = WideCharToMultiByte( CP_ACP, 0, (LPWSTR)pData, -1, NULL, 0, NULL, NULL );
  208. //Create the TCHAR string of the same length
  209. if( !(pszString = (LPTSTR)LocalAllocMem((dwSize + 1)*sizeof(TCHAR))))
  210. goto Done;
  211. //Convert the string from unicode to ansi.
  212. if( !WideCharToMultiByte( CP_ACP, 0, (LPWSTR)pData, -1, pszString, dwSize, NULL, NULL ) )
  213. {
  214. _dwLastError = ::GetLastError();
  215. }
  216. #endif
  217. Done:
  218. if( !tString->bUpdate( pszString ))
  219. _dwLastError = ::GetLastError();
  220. if( pData )
  221. LocalFreeMem( pData );
  222. if( pszString )
  223. LocalFreeMem( pszString );
  224. return (_dwLastError == ERROR_SUCCESS);
  225. }
  226. DWORD
  227. CServerInstall::
  228. GetLastError()
  229. {
  230. SetLastError(_dwLastError);
  231. return _dwLastError;
  232. }
  233. BOOL
  234. CServerInstall::
  235. SetInfDir()
  236. {
  237. if( _tsInf.bEmpty() )
  238. {
  239. SetInfToNTPRINTDir();
  240. }
  241. else
  242. {
  243. //
  244. // The inf name must be fully qualified.
  245. //
  246. TCHAR szFullInfName[MAX_PATH];
  247. LPTSTR pszDummy;
  248. DWORD dwLength = GetFullPathName( _tsInf, COUNTOF( szFullInfName ), szFullInfName, &pszDummy );
  249. if( !dwLength || !_tsInf.bUpdate( szFullInfName ))
  250. _dwLastError = ::GetLastError();
  251. }
  252. return (_dwLastError == ERROR_SUCCESS);
  253. }
  254. //
  255. // Returns: TRUE if SUCCESS, FALSE otherwise
  256. //
  257. // Sets the _stInf string to contain %windir%\inf\ntprint.inf
  258. //
  259. BOOL
  260. CServerInstall::
  261. SetInfToNTPRINTDir()
  262. {
  263. UINT uiSize = 0;
  264. UINT uiAllocSize = 0;
  265. PTCHAR pData = NULL;
  266. TCHAR szNTPrintInf[MAX_PATH];
  267. _dwLastError = ERROR_INVALID_DATA;
  268. //
  269. // Get %windir%
  270. // If the return is 0 - the call failed.
  271. // If the return is greater than MAX_PATH we want to fail as something has managed to change
  272. // the system dir to longer than MAX_PATH which is invalid.
  273. //
  274. uiSize = GetSystemWindowsDirectory( szNTPrintInf, COUNTOF(szNTPrintInf) );
  275. if( !uiSize || uiSize > COUNTOF(szNTPrintInf) )
  276. goto Cleanup;
  277. //
  278. // If we don't end in a \ then add one.
  279. //
  280. pData = &szNTPrintInf[ _tcslen(szNTPrintInf) ];
  281. if( *pData != _TEXT('\\') )
  282. *(pData++) = _TEXT('\\');
  283. *(pData) = 0;
  284. uiSize = _tcslen( szNTPrintInf ) + _tcslen( gcszNTPrint ) + 1;
  285. //
  286. // If what we've got sums up to a longer string than the allowable length MAX_PATH - fail
  287. //
  288. if( uiSize > COUNTOF(szNTPrintInf) )
  289. goto Cleanup;
  290. //
  291. // Copy the inf\ntprint.inf string onto the end of the %windir%\ string.
  292. //
  293. _tcscpy( pData, gcszNTPrint );
  294. _dwLastError = ERROR_SUCCESS;
  295. Cleanup:
  296. if( _dwLastError != ERROR_SUCCESS && szNTPrintInf )
  297. {
  298. //
  299. // Got here due to some error. Get what the called function set the last error to.
  300. // If the function set a success, set some error code.
  301. //
  302. if( (_dwLastError = ::GetLastError()) == ERROR_SUCCESS )
  303. _dwLastError = ERROR_INVALID_DATA;
  304. szNTPrintInf[0] = 0;
  305. }
  306. if( !_tsInf.bUpdate( szNTPrintInf ) )
  307. _dwLastError = ::GetLastError();
  308. return (_dwLastError == ERROR_SUCCESS);
  309. }
  310. BOOL
  311. CServerInstall::
  312. bValidateSourcePath(
  313. )
  314. {
  315. if( !_tsSource.bEmpty() &&
  316. !(GetFileAttributes( (LPCTSTR)_tsSource ) & FILE_ATTRIBUTE_DIRECTORY) )
  317. {
  318. _dwLastError = ERROR_DIRECTORY;
  319. }
  320. return (_dwLastError == ERROR_SUCCESS);
  321. }
  322. BOOL
  323. CServerInstall::
  324. OpenPipe()
  325. {
  326. if( !_tsPipeName.bEmpty() )
  327. {
  328. _hPipe = CreateFile( _tsPipeName,
  329. GENERIC_WRITE | GENERIC_READ,
  330. 0,
  331. NULL,
  332. OPEN_EXISTING,
  333. FILE_FLAG_OVERLAPPED,
  334. NULL );
  335. if( _hPipe == INVALID_HANDLE_VALUE )
  336. _dwLastError = ::GetLastError();
  337. }
  338. else
  339. _dwLastError = ERROR_INVALID_HANDLE;
  340. return (_dwLastError == ERROR_SUCCESS);
  341. }
  342. BOOL
  343. CServerInstall::
  344. SendError()
  345. {
  346. DWORD dwDontCare;
  347. return (WriteOverlapped( _hPipe, &_dwLastError, sizeof(_dwLastError), &dwDontCare ));
  348. }
  349. BOOL
  350. CServerInstall::
  351. ClosePipe()
  352. {
  353. BOOL bRet = TRUE;
  354. if( _hPipe != INVALID_HANDLE_VALUE )
  355. {
  356. bRet = CloseHandle( _hPipe );
  357. _hPipe = INVALID_HANDLE_VALUE;
  358. }
  359. return bRet;
  360. }
  361. BOOL
  362. CServerInstall::
  363. ReadOverlapped( HANDLE hFile,
  364. LPVOID lpBuffer,
  365. DWORD nNumberOfBytesToRead,
  366. LPDWORD lpNumberOfBytesRead )
  367. {
  368. if( hFile != INVALID_HANDLE_VALUE )
  369. {
  370. OVERLAPPED Ov;
  371. ZeroMemory( &Ov,sizeof(Ov));
  372. if ( !(Ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) )
  373. {
  374. _dwLastError = ::GetLastError();
  375. goto Cleanup;
  376. }
  377. if( !ReadFile( hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, &Ov ) &&
  378. ::GetLastError() != ERROR_IO_PENDING )
  379. {
  380. _dwLastError = ::GetLastError();
  381. goto Cleanup;
  382. }
  383. if( WaitForSingleObject(Ov.hEvent, _dwMaxTimeOut) == WAIT_TIMEOUT )
  384. {
  385. CancelIo(hFile);
  386. WaitForSingleObject(Ov.hEvent, INFINITE);
  387. }
  388. if( !GetOverlappedResult(hFile, &Ov, lpNumberOfBytesRead, FALSE) )
  389. _dwLastError = ::GetLastError();
  390. Cleanup:
  391. if ( Ov.hEvent )
  392. CloseHandle(Ov.hEvent);
  393. }
  394. else
  395. _dwLastError = ERROR_INVALID_HANDLE;
  396. return (_dwLastError == ERROR_SUCCESS);
  397. }
  398. BOOL
  399. CServerInstall::
  400. WriteOverlapped( HANDLE hFile,
  401. LPVOID lpBuffer,
  402. DWORD nNumberOfBytesToRead,
  403. LPDWORD lpNumberOfBytesRead )
  404. {
  405. if( hFile != INVALID_HANDLE_VALUE )
  406. {
  407. OVERLAPPED Ov;
  408. ZeroMemory( &Ov,sizeof(Ov));
  409. if ( !(Ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) )
  410. {
  411. _dwLastError = ::GetLastError();
  412. goto Cleanup;
  413. }
  414. if( !WriteFile( hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, &Ov ) &&
  415. ::GetLastError() != ERROR_IO_PENDING )
  416. {
  417. _dwLastError = ::GetLastError();
  418. goto Cleanup;
  419. }
  420. if( WaitForSingleObject(Ov.hEvent, _dwMaxTimeOut) == WAIT_TIMEOUT )
  421. {
  422. CancelIo(hFile);
  423. WaitForSingleObject(Ov.hEvent, INFINITE);
  424. }
  425. if( !GetOverlappedResult(hFile, &Ov, lpNumberOfBytesRead, FALSE) )
  426. _dwLastError = ::GetLastError();
  427. Cleanup:
  428. if ( Ov.hEvent )
  429. CloseHandle(Ov.hEvent);
  430. }
  431. else
  432. _dwLastError = ERROR_INVALID_HANDLE;
  433. return (_dwLastError == ERROR_SUCCESS);
  434. }
  435. /*+
  436. This function enumerates the drivers and finds if there is one of the same name currently installed.
  437. If there is then open the inf to install with and verify that the inf's version date is newer than the
  438. already installed driver.
  439. Returns: TRUE - if anything fails or the installed date isn't newer than the inf date.
  440. FALSE - only if the driver is installed AND it's date is newer than the inf's date.
  441. -*/
  442. BOOL
  443. CServerInstall::
  444. DriverNotInstalled()
  445. {
  446. LPCTSTR pszKey = _TEXT("DriverVer");
  447. LPTSTR pszEntry = NULL;
  448. LPDRIVER_INFO_6 pDriverInfo6 = NULL;
  449. LPBYTE pBuf = NULL;
  450. PSP_INF_INFORMATION pInfo = NULL;
  451. SYSTEMTIME Time = {0};
  452. BOOL bRet = TRUE;
  453. DWORD dwLength,
  454. dwRet,
  455. dwIndex;
  456. TCHAR *pTemp,
  457. *pTemp2;
  458. if(!EnumPrinterDrivers( NULL, PlatformEnv[MyPlatform].pszName, 6, pBuf, 0, &dwLength, &dwRet ))
  459. {
  460. if( ::GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  461. return TRUE;
  462. if( (pBuf = (LPBYTE) AllocMem( dwLength )) == NULL ||
  463. !EnumPrinterDrivers( NULL, PlatformEnv[MyPlatform].pszName, 6, pBuf, dwLength, &dwLength, &dwRet ))
  464. {
  465. _dwLastError = ::GetLastError();
  466. goto Cleanup;
  467. }
  468. }
  469. else
  470. {
  471. //
  472. // Only way this could succeed is if no drivers installed.
  473. //
  474. _dwLastError = ERROR_UNKNOWN_PRINTER_DRIVER;
  475. return TRUE;
  476. }
  477. for( dwIndex = 0, pDriverInfo6 = (LPDRIVER_INFO_6)pBuf; dwIndex < dwRet; dwIndex++, pDriverInfo6++ )
  478. {
  479. if( _tcscmp( pDriverInfo6->pName, (LPCTSTR)_tsDriverName ) == 0 )
  480. break;
  481. }
  482. if(dwIndex >= dwRet)
  483. {
  484. //
  485. // Driver not found
  486. //
  487. _dwLastError = ERROR_UNKNOWN_PRINTER_DRIVER;
  488. goto Cleanup;
  489. }
  490. //
  491. // The driver has been found... Open up inf and look at it's date.
  492. //
  493. //
  494. // Firstly get the size that will be needed for pInfo.
  495. //
  496. if( !SetupGetInfInformation( (LPCTSTR)_tsInf, INFINFO_INF_NAME_IS_ABSOLUTE, pInfo, 0, &dwLength ) )
  497. {
  498. _dwLastError = ::GetLastError();
  499. goto Cleanup;
  500. }
  501. //
  502. // Alloc pInfo and fill it.
  503. //
  504. if( (pInfo = (PSP_INF_INFORMATION) AllocMem( dwLength )) != NULL &&
  505. SetupGetInfInformation( (LPCTSTR)_tsInf, INFINFO_INF_NAME_IS_ABSOLUTE, pInfo, dwLength, &dwLength ) )
  506. {
  507. //
  508. // Get the size of the date string
  509. //
  510. if( SetupQueryInfVersionInformation( pInfo, 0, pszKey, pszEntry, 0, &dwLength ))
  511. {
  512. //
  513. // Alloc pszEntry and fill it.
  514. //
  515. if( (pszEntry = (LPTSTR) AllocMem( dwLength*sizeof(TCHAR) )) != NULL &&
  516. SetupQueryInfVersionInformation( pInfo, 0, pszKey, pszEntry, dwLength, &dwLength ))
  517. {
  518. //
  519. // Now convert the date string into a SYSTEMTIME
  520. // Date is of the form 03/22/2000
  521. //
  522. // Get the month - 03 part
  523. //
  524. if( (pTemp = _tcschr( pszEntry, _TEXT('/'))) != NULL )
  525. {
  526. *pTemp++ = 0;
  527. Time.wMonth = (WORD)_ttoi( pszEntry );
  528. pTemp2 = pTemp;
  529. //
  530. // Get the day - 22 part
  531. //
  532. if( (pTemp = _tcschr( pTemp2, _TEXT('/'))) != NULL )
  533. {
  534. *pTemp++ = 0;
  535. Time.wDay = (WORD)_ttoi( pTemp2 );
  536. pTemp2 = pTemp;
  537. //
  538. // Get the year - 2000 part
  539. //
  540. pTemp = _tcschr( pTemp2, _TEXT('/'));
  541. if( pTemp )
  542. *pTemp = 0;
  543. Time.wYear = (WORD)_ttoi( pTemp2 );
  544. }
  545. else
  546. _dwLastError = ERROR_INVALID_PARAMETER;
  547. }
  548. else
  549. _dwLastError = ERROR_INVALID_PARAMETER;
  550. }
  551. else
  552. _dwLastError = ::GetLastError();
  553. }
  554. else
  555. _dwLastError = ::GetLastError();
  556. }
  557. else
  558. _dwLastError = ::GetLastError();
  559. //
  560. // If we got all the way to filling in the year, we may have something useful...
  561. //
  562. if( Time.wYear )
  563. {
  564. FILETIME ftTime = {0};
  565. if(SystemTimeToFileTime( &Time, &ftTime ))
  566. {
  567. //
  568. // If the inf time is more recent than what is installed,
  569. // reinstall, otherwise don't
  570. //
  571. if( CompareFileTime(&ftTime, &pDriverInfo6->ftDriverDate) < 1 )
  572. {
  573. bRet = FALSE;
  574. }
  575. }
  576. //
  577. // Getting here and return TRUE or FALSE is still a successful call.
  578. //
  579. _dwLastError = ERROR_SUCCESS;
  580. }
  581. else
  582. _dwLastError = ERROR_INVALID_PARAMETER;
  583. Cleanup:
  584. if( pBuf )
  585. FreeMem( pBuf );
  586. if( pInfo )
  587. FreeMem( pInfo );
  588. if( pszEntry )
  589. FreeMem( pszEntry );
  590. return bRet;
  591. }