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.

745 lines
17 KiB

  1. /*++
  2. Copyright (c) 1995-97 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. Monitor.c
  6. Abstract:
  7. Routines for installing monitors
  8. Author:
  9. Muhunthan Sivapragasam (MuhuntS) 30-Nov-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. //
  14. // Keys to search INF files
  15. //
  16. TCHAR cszOptions[] = TEXT("Options");
  17. TCHAR cszPortMonitorSection[] = TEXT("PortMonitors");
  18. TCHAR cszPortMonitorDllKey [] = TEXT("PortMonitorDll");
  19. TCHAR cszMonitorInf[] = TEXT("*.inf");
  20. typedef struct _MON_INFO {
  21. LPTSTR pszName;
  22. LPTSTR pszDllName;
  23. BOOL bInstalled;
  24. } MON_INFO, *PMON_INFO;
  25. typedef struct _MONITOR_SETUP_INFO {
  26. PMON_INFO *ppMonInfo;
  27. DWORD dwCount;
  28. LPTSTR pszInfFile; // Valid only for OEM disk INF
  29. LPTSTR pszServerName;
  30. } MONITOR_SETUP_INFO, *PMONITOR_SETUP_INFO;
  31. VOID
  32. FreeMonInfo(
  33. PMON_INFO pMonInfo
  34. )
  35. /*++
  36. Routine Description:
  37. Free memory for a MON_INFO structure and the strings in it
  38. Arguments:
  39. pMonInfo : MON_INFO structure pointer
  40. Return Value:
  41. Nothing
  42. --*/
  43. {
  44. if ( pMonInfo ) {
  45. LocalFreeMem(pMonInfo->pszName);
  46. LocalFreeMem(pMonInfo->pszDllName);
  47. LocalFreeMem(pMonInfo);
  48. }
  49. }
  50. PMON_INFO
  51. AllocMonInfo(
  52. IN LPTSTR pszName,
  53. IN LPTSTR pszDllName, OPTIONAL
  54. IN BOOL bInstalled,
  55. IN BOOL bAllocStrings
  56. )
  57. /*++
  58. Routine Description:
  59. Allocate memory for a MON_INFO structure and create strings
  60. Arguments:
  61. pszName : Monitor name
  62. pszDllName : Monitor DLL name
  63. bAllocStrings : TRUE if routine should allocated memory and create string
  64. copies, else just assign the pointers
  65. Return Value:
  66. Pointer to the created MON_INFO structure. NULL on error.
  67. --*/
  68. {
  69. PMON_INFO pMonInfo;
  70. pMonInfo = (PMON_INFO) LocalAllocMem(sizeof(*pMonInfo));
  71. if ( !pMonInfo )
  72. return NULL;
  73. if ( bAllocStrings ) {
  74. pMonInfo->pszName = AllocStr(pszName);
  75. pMonInfo->pszDllName = AllocStr(pszDllName);
  76. if ( !pMonInfo->pszName ||
  77. (pszDllName && !pMonInfo->pszDllName) ) {
  78. FreeMonInfo(pMonInfo);
  79. return NULL;
  80. }
  81. } else {
  82. pMonInfo->pszName = pszName;
  83. pMonInfo->pszDllName = pszDllName;
  84. }
  85. pMonInfo->bInstalled = bInstalled;
  86. return pMonInfo;
  87. }
  88. VOID
  89. PSetupDestroyMonitorInfo(
  90. IN OUT HANDLE h
  91. )
  92. /*++
  93. Routine Description:
  94. Free memory allocated to a MONITOR_SETUP_INFO structure and its contents
  95. Arguments:
  96. h : A handle got by call to PSetupCreateMonitorInfo
  97. Return Value:
  98. Nothing
  99. --*/
  100. {
  101. PMONITOR_SETUP_INFO pMonitorSetupInfo = (PMONITOR_SETUP_INFO) h;
  102. DWORD Index;
  103. if ( pMonitorSetupInfo ) {
  104. if ( pMonitorSetupInfo->ppMonInfo ) {
  105. for ( Index = 0 ; Index < pMonitorSetupInfo->dwCount ; ++Index )
  106. FreeMonInfo(pMonitorSetupInfo->ppMonInfo[Index]);
  107. LocalFreeMem(pMonitorSetupInfo->ppMonInfo);
  108. }
  109. LocalFreeMem(pMonitorSetupInfo->pszInfFile);
  110. LocalFreeMem(pMonitorSetupInfo->pszServerName);
  111. LocalFreeMem(pMonitorSetupInfo);
  112. }
  113. }
  114. BOOL
  115. IsMonitorFound(
  116. IN LPVOID pBuf,
  117. IN DWORD dwReturned,
  118. IN LPTSTR pszName
  119. )
  120. /*++
  121. Routine Description:
  122. Find out if the given monitor name is found in the buffer returned from
  123. an EnumMonitors call to spooler
  124. Arguments:
  125. pBuf : Buffer used on a succesful EnumMonitor call to spooler
  126. dwReturned : Count returned by spooler on EnumMonitor
  127. pszMonName : Monitor name we are searching for
  128. Return Value:
  129. TRUE if monitor is found, FALSE else
  130. --*/
  131. {
  132. PMONITOR_INFO_2 pMonitor2;
  133. DWORD Index;
  134. for ( Index = 0, pMonitor2 = (PMONITOR_INFO_2) pBuf ;
  135. Index < dwReturned ;
  136. ++Index, (LPBYTE)pMonitor2 += sizeof(MONITOR_INFO_2) ) {
  137. if ( !lstrcmpi(pszName, pMonitor2->pName) )
  138. return TRUE;
  139. }
  140. return FALSE;
  141. }
  142. PMONITOR_SETUP_INFO
  143. CreateMonitorInfo(
  144. LPCTSTR pszServerName
  145. )
  146. /*++
  147. Routine Description:
  148. Finds all installed and installable monitors.
  149. Arguments:
  150. pSelectedDrvInfo : Pointer to the selected driver info (optional)
  151. Return Value:
  152. A pointer to MONITOR_SETUP_INFO on success,
  153. NULL on error
  154. --*/
  155. {
  156. PMONITOR_SETUP_INFO pMonitorSetupInfo = NULL;
  157. PMON_INFO *ppMonInfo;
  158. PMONITOR_INFO_2 pMonitor2;
  159. LONG Index, Count = 0;
  160. BOOL bFail = TRUE;
  161. DWORD dwNeeded, dwReturned;
  162. LPBYTE pBuf = NULL;
  163. LPTSTR pszMonName;
  164. //
  165. // First query spooler for installed monitors. If we fail let's quit
  166. //
  167. if ( !EnumMonitors((LPTSTR)pszServerName, 2, NULL,
  168. 0, &dwNeeded, &dwReturned) ) {
  169. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  170. !(pBuf = LocalAllocMem(dwNeeded)) ||
  171. !EnumMonitors((LPTSTR)pszServerName,
  172. 2,
  173. pBuf,
  174. dwNeeded,
  175. &dwNeeded,
  176. &dwReturned) ) {
  177. goto Cleanup;
  178. }
  179. }
  180. //
  181. // We know how many monitors we have to display now
  182. //
  183. pMonitorSetupInfo = (PMONITOR_SETUP_INFO) LocalAllocMem(sizeof(*pMonitorSetupInfo));
  184. if ( !pMonitorSetupInfo )
  185. goto Cleanup;
  186. ZeroMemory(pMonitorSetupInfo, sizeof(*pMonitorSetupInfo));
  187. //
  188. // pMonitorSetupInfo->dwCount could be adjusted later not to list duplicate
  189. // entries. We are allocating max required buffer here
  190. //
  191. pMonitorSetupInfo->dwCount = dwReturned;
  192. pMonitorSetupInfo->ppMonInfo = (PMON_INFO *)
  193. LocalAllocMem(pMonitorSetupInfo->dwCount*sizeof(PMON_INFO));
  194. ppMonInfo = pMonitorSetupInfo->ppMonInfo;
  195. if ( !ppMonInfo )
  196. goto Cleanup;
  197. for ( Index = 0, pMonitor2 = (PMONITOR_INFO_2) pBuf ;
  198. Index < (LONG) dwReturned ;
  199. ++Index, (LPBYTE)pMonitor2 += sizeof(MONITOR_INFO_2) ) {
  200. *ppMonInfo++ = AllocMonInfo(pMonitor2->pName,
  201. pMonitor2->pDLLName,
  202. TRUE,
  203. TRUE);
  204. }
  205. bFail = FALSE;
  206. Cleanup:
  207. if ( pBuf )
  208. LocalFreeMem(pBuf);
  209. if ( bFail ) {
  210. PSetupDestroyMonitorInfo(pMonitorSetupInfo);
  211. pMonitorSetupInfo = NULL;
  212. }
  213. return pMonitorSetupInfo;
  214. }
  215. BOOL
  216. AddPrintMonitor(
  217. IN LPCTSTR pszName,
  218. IN LPCTSTR pszDllName
  219. )
  220. /*++
  221. Routine Description:
  222. Add a print monitor by calling AddMonitor to spooler
  223. Arguments:
  224. pszName : Name of the monitor
  225. pszDllName : Monitor dll name
  226. Return Value:
  227. TRUE if monitor was succesfully added or it is already installed,
  228. FALSE on failure
  229. --*/
  230. {
  231. MONITOR_INFO_2 MonitorInfo2;
  232. MonitorInfo2.pName = (LPTSTR) pszName;
  233. MonitorInfo2.pEnvironment = NULL;
  234. MonitorInfo2.pDLLName = (LPTSTR) pszDllName;
  235. //
  236. // Call is succesful if add returned TRUE, or monitor is already installed
  237. //
  238. if ( AddMonitor(NULL, 2, (LPBYTE) &MonitorInfo2) ||
  239. GetLastError() == ERROR_PRINT_MONITOR_ALREADY_INSTALLED ) {
  240. return TRUE;
  241. } else {
  242. return FALSE;
  243. }
  244. }
  245. PMON_INFO
  246. MonInfoFromName(
  247. IN PMONITOR_SETUP_INFO pMonitorSetupInfo,
  248. IN LPCTSTR pszMonitorName
  249. )
  250. {
  251. PMON_INFO pMonInfo;
  252. DWORD dwIndex;
  253. if ( !pMonitorSetupInfo ) {
  254. return NULL;
  255. }
  256. for ( dwIndex = 0 ; dwIndex < pMonitorSetupInfo->dwCount ; ++dwIndex ) {
  257. pMonInfo = pMonitorSetupInfo->ppMonInfo[dwIndex];
  258. if ( !lstrcmp(pszMonitorName, pMonInfo->pszName) ) {
  259. return pMonInfo;
  260. }
  261. }
  262. return NULL;
  263. }
  264. BOOL
  265. InstallOnePortMonitor(HWND hwnd,
  266. HINF hInf,
  267. LPTSTR pMonitorName,
  268. LPTSTR pSectionName,
  269. LPTSTR pSourcePath)
  270. /*++
  271. Routine Description:
  272. Install one port monitor by copying files and calling spooler to add it
  273. Arguments:
  274. hwnd : Window handle of current top-level window
  275. hInf : handle to the INF file
  276. pMonitorName : port monitor display name
  277. pSectionName : install section within the INF for the port monitor
  278. Return Value:
  279. TRUE if a port monitor was successfully installed
  280. FALSE if not
  281. --*/
  282. {
  283. DWORD NameLen;
  284. BOOL bSuccess = FALSE;
  285. HSPFILEQ InstallQueue = {0};
  286. PVOID pQueueContext = NULL;
  287. LPTSTR pMonitorDllName;
  288. NameLen = MAX_PATH;
  289. if ((pMonitorDllName = LocalAllocMem(NameLen * sizeof(TCHAR))) == NULL)
  290. {
  291. goto Cleanup;
  292. }
  293. //
  294. // Find the port monitor DLL name
  295. //
  296. if (!SetupGetLineText(NULL, hInf, pSectionName, cszPortMonitorDllKey, pMonitorDllName, NameLen, NULL))
  297. {
  298. goto Cleanup;
  299. }
  300. //
  301. // perform the installation
  302. //
  303. if ((InstallQueue = SetupOpenFileQueue()) == INVALID_HANDLE_VALUE)
  304. {
  305. goto Cleanup;
  306. }
  307. if (!SetupInstallFilesFromInfSection(hInf, NULL, InstallQueue, pSectionName, pSourcePath,
  308. SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP))
  309. {
  310. goto Cleanup;
  311. }
  312. //
  313. // Commit the file queue. This gets all files copied over.
  314. //
  315. pQueueContext = SetupInitDefaultQueueCallback(hwnd);
  316. if ( !pQueueContext )
  317. {
  318. goto Cleanup;
  319. }
  320. bSuccess = SetupCommitFileQueue(hwnd,
  321. InstallQueue,
  322. SetupDefaultQueueCallback,
  323. pQueueContext);
  324. if ( !bSuccess )
  325. goto Cleanup;
  326. bSuccess = AddPrintMonitor(pMonitorName, pMonitorDllName);
  327. Cleanup:
  328. if (pQueueContext)
  329. {
  330. SetupTermDefaultQueueCallback(pQueueContext);
  331. }
  332. if (pMonitorDllName)
  333. {
  334. LocalFreeMem(pMonitorDllName);
  335. }
  336. SetupCloseFileQueue(InstallQueue);
  337. if (!bSuccess)
  338. {
  339. LPTSTR pszFormat = NULL, pszPrompt = NULL, pszTitle = NULL;
  340. pszFormat = GetStringFromRcFile(IDS_ERROR_INST_PORT_MONITOR);
  341. pszTitle = GetStringFromRcFile(IDS_INSTALLING_PORT_MONITOR);
  342. if ( pszFormat && pszTitle)
  343. {
  344. pszPrompt = LocalAllocMem((lstrlen(pszFormat) + lstrlen(pMonitorName) + 2)
  345. * sizeof(TCHAR));
  346. if ( pszPrompt )
  347. {
  348. wsprintf(pszPrompt, pszFormat, pMonitorName);
  349. MessageBox(hwnd, pszPrompt, pszTitle, MB_OK);
  350. LocalFreeMem(pszPrompt);
  351. }
  352. }
  353. LocalFreeMem(pszFormat);
  354. LocalFreeMem(pszTitle);
  355. }
  356. return bSuccess;
  357. }
  358. BOOL
  359. InstallAllPortMonitorsFromInf(HWND hwnd,
  360. HINF hInfFile,
  361. LPTSTR pSourcePath)
  362. /*++
  363. Routine Description:
  364. Install all port monitors listed in one INF
  365. Arguments:
  366. hwnd : Window handle of current top-level window
  367. hInfFile : handle of the INF file
  368. pSourcePath : path to the INF file (without the name of the INF)
  369. Return Value:
  370. TRUE if at least one port monitor was successfully installed
  371. FALSE if not
  372. --*/
  373. {
  374. LPTSTR pMonitorName = NULL, pSectionName= NULL;
  375. DWORD NameLen;
  376. BOOL bSuccess = FALSE;
  377. INFCONTEXT Context = {0};
  378. NameLen = MAX_PATH;
  379. if (((pMonitorName = LocalAllocMem(NameLen * sizeof(TCHAR))) == NULL) ||
  380. ((pSectionName = LocalAllocMem(NameLen * sizeof(TCHAR))) == NULL))
  381. {
  382. goto Cleanup;
  383. }
  384. //
  385. // Go through the list of port monitors
  386. //
  387. if (!SetupFindFirstLine(hInfFile, cszPortMonitorSection, NULL, &Context))
  388. {
  389. goto Cleanup;
  390. }
  391. do
  392. {
  393. //
  394. // get the key name
  395. //
  396. if (!SetupGetStringField(&Context, 0, pMonitorName, NameLen, NULL))
  397. {
  398. goto Cleanup;
  399. }
  400. //
  401. // get the section name
  402. //
  403. if (!SetupGetStringField(&Context, 1, pSectionName, NameLen, NULL))
  404. {
  405. goto Cleanup;
  406. }
  407. bSuccess = InstallOnePortMonitor(hwnd, hInfFile, pMonitorName, pSectionName, pSourcePath) ||
  408. bSuccess;
  409. } while (SetupFindNextLine(&Context, &Context));
  410. Cleanup:
  411. if (pMonitorName)
  412. {
  413. LocalFreeMem(pMonitorName);
  414. }
  415. if (pSectionName)
  416. {
  417. LocalFreeMem(pSectionName);
  418. }
  419. return bSuccess;
  420. }
  421. BOOL
  422. PSetupInstallMonitor(
  423. IN HWND hwnd
  424. )
  425. /*++
  426. Routine Description:
  427. Install a print monitor by copying files, and calling spooler to add it
  428. Arguments:
  429. hwnd : Window handle of current top-level window
  430. Return Value:
  431. TRUE if at least one port monitor was successfully installed
  432. FALSE if not
  433. --*/
  434. {
  435. PMONITOR_SETUP_INFO pMonitorSetupInfo = NULL;
  436. PMON_INFO *ppMonInfo, pMonInfo;
  437. HINF hInf = INVALID_HANDLE_VALUE;
  438. INFCONTEXT InfContext;
  439. TCHAR szInfPath[MAX_PATH];
  440. LPTSTR pszTitle, pszPrintMonitorPrompt;
  441. WIN32_FIND_DATA FindData ={0};
  442. HANDLE hFind;
  443. size_t PathLen;
  444. BOOL bRet = FALSE;
  445. pszTitle = GetStringFromRcFile(IDS_INSTALLING_PORT_MONITOR);
  446. pszPrintMonitorPrompt = GetStringFromRcFile(IDS_PROMPT_PORT_MONITOR);
  447. if (!pszTitle || ! pszPrintMonitorPrompt)
  448. {
  449. goto Cleanup;
  450. }
  451. //
  452. // Ask the user where the inf file with the port monitor info resides
  453. //
  454. GetCDRomDrive(szInfPath);
  455. if ( !PSetupGetPathToSearch(hwnd,
  456. pszTitle,
  457. pszPrintMonitorPrompt,
  458. cszMonitorInf,
  459. TRUE,
  460. szInfPath) ) {
  461. goto Cleanup;
  462. }
  463. //
  464. // find the INF(s) in the path. There must be one else SetupPromptForPath would've complained
  465. //
  466. PathLen = _tcslen(szInfPath);
  467. if (PathLen > MAX_PATH - _tcslen(cszMonitorInf) - 2) // -2 for terminating zero and backslash
  468. {
  469. DBGMSG(DBG_WARN, ("PSetupInstallMonitor: Path too long\n"));
  470. SetLastError(ERROR_BUFFER_OVERFLOW);
  471. goto Cleanup;
  472. }
  473. ASSERT(PathLen);
  474. if (szInfPath[PathLen-1] != _T('\\'))
  475. {
  476. szInfPath[PathLen++] = _T('\\');
  477. szInfPath[PathLen] = 0;
  478. }
  479. _tcscat(szInfPath, cszMonitorInf);
  480. hFind = FindFirstFile(szInfPath, &FindData);
  481. if (hFind != INVALID_HANDLE_VALUE)
  482. {
  483. HANDLE hInfFile;
  484. do
  485. {
  486. if (PathLen + _tcslen(FindData.cFileName) >= MAX_PATH)
  487. {
  488. DBGMSG(DBG_WARN, ("PSetupInstallMonitor: Path for %s%s too long - file skipped\n", szInfPath, FindData.cFileName));
  489. SetLastError(ERROR_BUFFER_OVERFLOW);
  490. continue;
  491. }
  492. _tcscpy(&(szInfPath[PathLen]), FindData.cFileName);
  493. hInfFile = SetupOpenInfFile(szInfPath, _T("Printer"), INF_STYLE_WIN4, NULL);
  494. if (hInfFile != INVALID_HANDLE_VALUE)
  495. {
  496. //
  497. // if the file has a section on port monitors, install it
  498. //
  499. if ( SetupGetLineCount(hInfFile, cszPortMonitorSection) > 0 )
  500. {
  501. //
  502. // cut off the INF name from the path
  503. //
  504. szInfPath[PathLen -1] = 0;
  505. //
  506. // bRet should be TRUE if there was at least one print monitor successfully installed
  507. //
  508. bRet = InstallAllPortMonitorsFromInf(hwnd, hInfFile, szInfPath) || bRet;
  509. //
  510. // Put the trailing backslash back on
  511. //
  512. szInfPath[PathLen -1] = _T('\\');
  513. }
  514. SetupCloseInfFile(hInfFile);
  515. }
  516. } while ( FindNextFile(hFind, &FindData) );
  517. FindClose(hFind);
  518. }
  519. Cleanup:
  520. if (pszTitle)
  521. {
  522. LocalFreeMem(pszTitle);
  523. }
  524. if (pszPrintMonitorPrompt)
  525. {
  526. LocalFreeMem(pszPrintMonitorPrompt);
  527. }
  528. return bRet;
  529. }
  530. HANDLE
  531. PSetupCreateMonitorInfo(
  532. IN HWND hwnd,
  533. IN LPCTSTR pszServerName
  534. )
  535. {
  536. return (HANDLE) CreateMonitorInfo(pszServerName);
  537. }
  538. BOOL
  539. PSetupEnumMonitor(
  540. IN HANDLE h,
  541. IN DWORD dwIndex,
  542. OUT LPTSTR pMonitorName,
  543. IN OUT LPDWORD pdwSize
  544. )
  545. {
  546. PMONITOR_SETUP_INFO pMonitorSetupInfo = (PMONITOR_SETUP_INFO) h;
  547. PMON_INFO pMonInfo;
  548. DWORD dwNeeded;
  549. if ( dwIndex >= pMonitorSetupInfo->dwCount ) {
  550. SetLastError(ERROR_NO_MORE_ITEMS);
  551. return FALSE;
  552. }
  553. pMonInfo = pMonitorSetupInfo->ppMonInfo[dwIndex];
  554. dwNeeded = lstrlen(pMonInfo->pszName) + 1;
  555. if ( dwNeeded > *pdwSize ) {
  556. *pdwSize = dwNeeded;
  557. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  558. return FALSE;
  559. }
  560. lstrcpy(pMonitorName, pMonInfo->pszName);
  561. return TRUE;
  562. }