Windows NT 4.0 source code leak
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.

1342 lines
31 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990-1994 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. SetupDlg.c
  6. Abstract:
  7. Handles the generic setup dialogs to setup drivers and monitors.
  8. Author:
  9. AlbertT [ported from printman]
  10. Environment:
  11. User Mode -Win32
  12. Revision History:
  13. --*/
  14. #include "printman.h"
  15. #include "pmdef.h"
  16. #include <commdlg.h>
  17. #include <stdarg.h>
  18. #include <prsinf.h>
  19. //
  20. // Globals
  21. //
  22. INSTALLDRIVERDATA iddPrinter = {
  23. IDS_PRINTER_INSTALL_TITLE,
  24. IDS_PRINTER_SELECT_TITLE,
  25. IDS_PRINTER_TYPE,
  26. DLG_INSTALLDRIVER,
  27. DLG_SELECTDRIVER,
  28. TEXT("PRINTER.INF"),
  29. TEXT("PRINTER"),
  30. TEXT("OPTIONS"),
  31. CB_INSERTSTRING,
  32. CB_FINDSTRINGEXACT,
  33. CB_SETCURSEL,
  34. CB_RESETCONTENT,
  35. sizeof(DRIVER_INFO_1),
  36. (DWORD)&(((PDRIVER_INFO_1)0)->pName),
  37. (PFNGETINSTALLED)GetInstalledDrivers
  38. };
  39. INSTALLDRIVERDATA iddMonitor = {
  40. IDS_MONITOR_INSTALL_TITLE,
  41. IDS_MONITOR_SELECT_TITLE,
  42. IDS_MONITOR_TYPE,
  43. DLG_INSTALLMONITOR,
  44. DLG_SELECTMONITOR,
  45. TEXT("MONITOR.INF"),
  46. TEXT("MONITOR"),
  47. TEXT("OPTIONS"),
  48. LB_INSERTSTRING,
  49. LB_FINDSTRINGEXACT,
  50. LB_SETCURSEL,
  51. LB_RESETCONTENT,
  52. sizeof(MONITOR_INFO_1),
  53. (DWORD)&(((PMONITOR_INFO_1)0)->pName),
  54. (PFNGETINSTALLED)GetInstalledMonitors
  55. };
  56. //
  57. // structs, private
  58. //
  59. typedef struct _INF_CACHE {
  60. LPTSTR pszzDrivers;
  61. UINT uDrivers; // uninstalled driver count
  62. UINT uTotal; // total count
  63. INFDRIVER aInfDriver[1]; // sorted list of installed/uninstalled drivers
  64. } INFCACHE;
  65. //
  66. // Prototypes
  67. //
  68. VOID
  69. Insert(
  70. PINFCACHE pInfCache,
  71. LPTSTR pszDriver,
  72. BOOL bInstalled);
  73. UINT
  74. GetDriverCount(
  75. LPTSTR pszzDriver,
  76. PINFCACHE pInfCache);
  77. HANDLE
  78. OpenInfFileW(
  79. PWCHAR szFileName,
  80. PWCHAR szInfType);
  81. PWCHAR
  82. GetOptionListW(
  83. HANDLE hndInf,
  84. PWCHAR szOptionSection);
  85. PTCHAR
  86. GetOptionFromListSelection(
  87. INT Selection,
  88. PTCHAR pOption );
  89. TCHAR LastChar(TCHAR *string);
  90. void AppendChar(TCHAR *string, TCHAR ch);
  91. //
  92. // Procedures
  93. //
  94. VOID
  95. DestroyInfParms(
  96. PINFPARMS pInfParms)
  97. /*++
  98. Routine Description:
  99. Frees information in pInfParms, BUT NOT pInfParms!
  100. Arguments:
  101. Return Value:
  102. --*/
  103. {
  104. if (pInfParms->pInstalled)
  105. FreeSplMem(pInfParms->pInstalled);
  106. pInfParms->pInstalled = NULL;
  107. pInfParms->cbInstalled = 0;
  108. DestroyInfCache(pInfParms->pInfCache);
  109. pInfParms->pInfCache = NULL;
  110. }
  111. VOID
  112. DestroyInfCache(
  113. PINFCACHE pInfCache)
  114. {
  115. if (pInfCache && pInfCache->pszzDrivers) {
  116. LocalFree(pInfCache->pszzDrivers);
  117. FreeSplMem(pInfCache);
  118. }
  119. }
  120. BOOL
  121. HandleSelChange(
  122. HWND hwnd,
  123. PINFPARMS pInfParms,
  124. UINT uAddSel)
  125. {
  126. PINSTALLDRIVERDATA pInstallDriverData = pInfParms->pInstallDriverData;
  127. PTCHAR pInstalledDriverOption;
  128. BOOL OK;
  129. DWORD cInstalledDrivers;
  130. BOOL bReturnValue = FALSE;
  131. //
  132. // pInfParms->pOptions must be cleared since this dialog box
  133. // may fail, and we want to know if pOptions is valid.
  134. //
  135. pInfParms->pOptions = NULL;
  136. OK = DialogBoxParam(hInst,
  137. MAKEINTRESOURCE(DLG_INSTALLDRIVER),
  138. hwnd,
  139. (DLGPROC)InstallDriverDlg,
  140. (LONG)pInfParms);
  141. //
  142. // Remember, we are responsible for freeing
  143. // pOptions since pOptionSelected points into it.
  144. //
  145. pInstalledDriverOption = pInfParms->pOptionSelected;
  146. if( OK && pInstalledDriverOption )
  147. {
  148. //
  149. // Refresh our list of things.
  150. //
  151. cInstalledDrivers = (*pInstallDriverData->pfnGetInstalled)(pInfParms);
  152. /* Check whether the number of installed drivers has actually increased.
  153. * This may not be the case if a driver was installed to update an
  154. * already installed driver.
  155. */
  156. if( cInstalledDrivers > pInfParms->cInstalled )
  157. {
  158. DBGMSG( DBG_INFO, ( "Total of %d installed drivers. Updating list.\n",
  159. cInstalledDrivers ) );
  160. //
  161. // If so, we need to update the list of merged drivers too:
  162. //
  163. pInfParms->cInstalled = cInstalledDrivers;
  164. SetupInfDlg(pInfParms);
  165. }
  166. else
  167. {
  168. DBGMSG( DBG_INFO, ( "A driver was updated. No new drivers installed.\n" ) );
  169. }
  170. //
  171. // Select the new driver
  172. //
  173. pInfParms->uCurSel = SendMessage(pInfParms->hwnd,
  174. pInstallDriverData->uFindMsg,
  175. (WPARAM)-1,
  176. (LPARAM)pInstalledDriverOption);
  177. if (pInfParms->uCurSel == (UINT)-1) {
  178. pInfParms->uCurSel = 0;
  179. goto RestorePrevious;
  180. }
  181. SendMessage(pInfParms->hwnd,
  182. pInstallDriverData->uSelectMsg,
  183. pInfParms->uCurSel,
  184. 0L);
  185. }
  186. else
  187. {
  188. RestorePrevious:
  189. DBGMSG( DBG_WARNING, ( "Driver was not installed or failed to find.\n" ) );
  190. //
  191. // If we didn't install a new driver, don't keep the "Other..."
  192. // selection in the list box; return it to the previous one:
  193. //
  194. SendMessage(pInfParms->hwnd,
  195. pInstallDriverData->uSelectMsg,
  196. pInfParms->uCurSel,
  197. 0L);
  198. /* Ensure that we do actually have a driver now.
  199. * This is a fix for bug #16383, which happened
  200. * when there were no drivers installed and PRINTER.INF
  201. * was missing. The Create Printer dialog prompted
  202. * for a source path, and the user canceled out,
  203. * then typed a printer name and clicked OK.
  204. * Only "Other..." was in the Drivers list, but the
  205. * code assumed there was a driver.
  206. */
  207. if (pInfParms->uCurSel == uAddSel)
  208. {
  209. Message( hwnd, MSG_ERROR, IDS_PRINTMANAGER,
  210. IDS_NO_DRIVERS_INSTALLED, pInstallDriverData->pszInfFile );
  211. goto Done;
  212. }
  213. }
  214. bReturnValue = TRUE;
  215. Done:
  216. //
  217. // Must be local free'd since allocated by inf code rather than
  218. // spooler (Don't use FreeSplMem).
  219. //
  220. if (pInfParms->pOptions)
  221. LocalFree(pInfParms->pOptions);
  222. return TRUE;
  223. }
  224. PINFCACHE
  225. SetupInfDlg(
  226. PINFPARMS pInfParms)
  227. /*++
  228. Routine Description:
  229. Sets up the window with the installed and installable drivers.
  230. Arguments:
  231. Return Value:
  232. pInfCacheNew buffer must be freed by callee or used in pInfCache
  233. on the next call. If cache used, then the return value is the cache.
  234. NULL = Error, use GetLastError()
  235. --*/
  236. {
  237. PINSTALLDRIVERDATA pInstallDriverData = pInfParms->pInstallDriverData;
  238. LPTSTR pszzDrivers = NULL;
  239. UINT uDrivers = 0;
  240. HANDLE hInfFile;
  241. TCHAR string[128];
  242. PINFCACHE pInfCache = pInfParms->pInfCache;
  243. HWND hwnd = pInfParms->hwnd;
  244. UINT uInsertMsg = pInstallDriverData->uInsertMsg;
  245. UINT uFindMsg = pInstallDriverData->uFindMsg;
  246. UINT uSelectMsg = pInstallDriverData->uSelectMsg;
  247. PBYTE pInstalled = pInfParms->pInstalled;
  248. UINT uInstalled = pInfParms->cInstalled;
  249. DWORD cbSize = pInstallDriverData->cbSize;
  250. DWORD cbOffset = pInstallDriverData->cbOffset;
  251. LPTSTR pszCurrentDriver = pInfParms->pszCurrentDriver;
  252. UINT i;
  253. //
  254. // If pInfCache valid but hInfFile isn't, then we won't read
  255. // in inf file until pInfCache is invalid.
  256. //
  257. if (!pInfCache) {
  258. hInfFile = OpenInfFileW(pInstallDriverData->pszInfFile,
  259. pInstallDriverData->pszInfType);
  260. if (hInfFile != INVALID_HANDLE_VALUE) {
  261. pszzDrivers = GetOptionListW(hInfFile, pInstallDriverData->pszSection);
  262. CloseInfFile(hInfFile);
  263. if (pszzDrivers) {
  264. uDrivers = GetDriverCount(pszzDrivers, NULL);
  265. }
  266. }
  267. } else {
  268. uDrivers = pInfCache->uDrivers;
  269. pszzDrivers = pInfCache->pszzDrivers;
  270. FreeSplMem(pInfCache);
  271. }
  272. pInfCache = AllocSplMem(sizeof(INFCACHE) +
  273. (uDrivers+uInstalled) * sizeof(INFDRIVER));
  274. pInfParms->pInfCache = pInfCache;
  275. if (!pInfCache) {
  276. LocalFree(pszzDrivers);
  277. return NULL;
  278. }
  279. //
  280. // pInfCache->uTotal = 0;
  281. //
  282. pInfCache->uDrivers = uDrivers;
  283. pInfCache->pszzDrivers = pszzDrivers;
  284. //
  285. // Reset the box
  286. //
  287. SendMessage(hwnd,
  288. pInstallDriverData->uResetMsg,
  289. 0,
  290. 0L);
  291. //
  292. // Add in uninstalled drivers
  293. //
  294. GetDriverCount(pszzDrivers, pInfCache);
  295. //
  296. // Add in installed drivers
  297. //
  298. if (pInstalled) {
  299. for(i=0, ((PBYTE)pInstalled) += cbOffset;
  300. i<uInstalled;
  301. i++, ((PBYTE)pInstalled) += cbSize) {
  302. Insert(pInfCache, *((LPTSTR*)pInstalled), TRUE);
  303. }
  304. }
  305. //
  306. // pInstalled is now garbage
  307. //
  308. //
  309. // Now everything is sorted and added (Insert removes dups)
  310. // Do Insert!
  311. //
  312. for(i = 0; i < pInfCache->uTotal; i++) {
  313. SendMessage(hwnd,
  314. uInsertMsg,
  315. i,
  316. (LPARAM)pInfCache->aInfDriver[i].pszDriver);
  317. }
  318. if (pszCurrentDriver) {
  319. pInfParms->uCurSel = SendMessage(hwnd,
  320. uFindMsg,
  321. 0,
  322. (LPARAM)pszCurrentDriver);
  323. if (pInfParms->uCurSel == (DWORD)-1)
  324. pInfParms->uCurSel = 0;
  325. } else {
  326. pInfParms->uCurSel = 0;
  327. }
  328. SendMessage(hwnd, uSelectMsg, pInfParms->uCurSel, 0L);
  329. LoadString( hInst, IDS_OTHER, string,
  330. sizeof( string ) / sizeof( *string ) );
  331. i = SendMessage(hwnd,
  332. uInsertMsg,
  333. (WPARAM)-1,
  334. (LPARAM)string );
  335. //
  336. // Use the combo box reserved user long to store the unlisted index:
  337. //
  338. SetWindowLong(hwnd, GWL_USERDATA, i);
  339. return pInfCache;
  340. }
  341. VOID
  342. Insert(
  343. PINFCACHE pInfCache,
  344. LPTSTR pszDriver,
  345. BOOL bInstalled)
  346. /*++
  347. Routine Description:
  348. Inserts a string and bInstalled option into pInfCache. Assume
  349. string compares slow, moving items fast (true since NLS sorting
  350. is enabled).
  351. This does a binary sort in place, which causes a lot of item movement
  352. (not pointers, but actual objects), so if INFDRIVER gets big,
  353. rewrite this code.
  354. Duplicates disallowed; bInstalled turned on if duplicate has it on.
  355. Arguments:
  356. pInfCache -- Structure to insert item into. Assumes uTotal is
  357. accurate and there is enough space for the new item.
  358. pszDriver -- Driver string to insert. Must not be freed until pInfCache
  359. is no longer needed.
  360. bInstalled -- Extra param for INFDRIVER.
  361. Return Value:
  362. --*/
  363. {
  364. INT iMax, iMin, iMid, j, iCompare;
  365. PINFDRIVER pInfDriver = pInfCache->aInfDriver;
  366. UINT uTotal = pInfCache->uTotal;
  367. //
  368. // Check if iMax is != 0. If so, must sort insert.
  369. //
  370. if (iMax = uTotal) {
  371. iMin = 0;
  372. //
  373. // Quick hack for presorted lists
  374. //
  375. // Since they sort already (excepting strange chars/localization)
  376. // do a quick check if it goes at the end of the list.
  377. //
  378. // Check if it DOESN'T, then insert
  379. //
  380. iCompare = lstrcmpi(pInfDriver[iMax-1].pszDriver, pszDriver);
  381. if (!iCompare) {
  382. //
  383. // On match, just turn on bInstalled bit.
  384. //
  385. pInfDriver[iMax-1].bInstalled |= bInstalled;
  386. return;
  387. } else if (iCompare > 0) {
  388. //
  389. // do a binary insert
  390. //
  391. do {
  392. iMid = (iMax + iMin) / 2;
  393. iCompare = lstrcmpi(pInfDriver[iMid].pszDriver, pszDriver);
  394. if (iCompare < 0)
  395. iMin = iMid + 1;
  396. else if (iCompare > 0)
  397. iMax = iMid - 1;
  398. else {
  399. iMin = iMax = iMid;
  400. }
  401. } while (iMax > iMin);
  402. if (iMax < 0)
  403. iMax = 0;
  404. //
  405. // Insert after this item.
  406. //
  407. if ((iCompare=lstrcmpi(pInfDriver[iMax].pszDriver, pszDriver)) < 0) {
  408. iMax++;
  409. }
  410. //
  411. // If if not a duplicate
  412. //
  413. if (iCompare) {
  414. if (iMax != (INT)uTotal) {
  415. for (j = uTotal; j > iMax; j--)
  416. pInfDriver[j] = pInfDriver[j-1];
  417. }
  418. }
  419. }
  420. //
  421. // If its a duplicate, don't install it, just make sure
  422. // to update the bInstalled flag.
  423. //
  424. if (!iCompare) {
  425. pInfDriver[iMax].bInstalled |= bInstalled;
  426. return;
  427. }
  428. }
  429. //
  430. // New driver, add it to the list
  431. //
  432. pInfDriver[iMax].pszDriver = pszDriver;
  433. pInfDriver[iMax].bInstalled = bInstalled;
  434. pInfCache->uTotal++;
  435. }
  436. UINT
  437. GetDriverCount(
  438. LPTSTR pszzDriver,
  439. PINFCACHE pInfCache)
  440. /*++
  441. Routine Description:
  442. Gets the number of strings in a list of strings (null term).
  443. If ppszDriver is != NULL, fills it with pointers into the array.
  444. Arguments:
  445. pszzDriver -- List of strings, NULL terminated
  446. Can be NULL.
  447. pInfCache -- [OPTIONAL] pInfCache struct to update
  448. These drivers are added to the structure as NOT_INSTALLED!
  449. Return Value:
  450. Number of strings in pOptions
  451. --*/
  452. {
  453. UINT uCount = 0;
  454. if (!pszzDriver)
  455. return 0;
  456. while( *pszzDriver ) {
  457. if (pInfCache) {
  458. Insert(pInfCache, pszzDriver, FALSE);
  459. }
  460. uCount++;
  461. //
  462. // Scan to the end of this option:
  463. //
  464. while( *pszzDriver )
  465. pszzDriver++;
  466. //
  467. // Step over the null-terminator:
  468. //
  469. pszzDriver++;
  470. }
  471. return uCount;
  472. }
  473. PWCHAR
  474. GetOptionListW(
  475. HANDLE hndInf,
  476. PWCHAR szOptionSection)
  477. {
  478. PCHAR szos;
  479. PCHAR szList;
  480. PCHAR p;
  481. int cchos;
  482. PWCHAR szReturn;
  483. PWCHAR szPtr;
  484. int size;
  485. cchos = (lstrlenW(szOptionSection)+1)*sizeof(TCHAR);
  486. szos = AllocSplMem(cchos);
  487. WideCharToMultiByte( CP_ACP, 0,
  488. szOptionSection, lstrlenW(szOptionSection)+1,
  489. szos, cchos,
  490. NULL, NULL );
  491. szList = p = GetOptionList(hndInf, szos);
  492. szReturn = AllocSplMem( LocalSize(szList) *sizeof(TCHAR) );
  493. szPtr = szReturn;
  494. while( *p ) {
  495. size = lstrlenA(p)+1;
  496. MultiByteToWideChar(CP_ACP,
  497. MB_PRECOMPOSED,
  498. p,
  499. size,
  500. szPtr,
  501. size*sizeof(TCHAR) );
  502. p += size;
  503. szPtr += (lstrlenW(szPtr)+1);
  504. }
  505. LocalFree(szList);
  506. FreeSplMem(szos);
  507. return szReturn;
  508. }
  509. HANDLE
  510. OpenInfFileW(
  511. PWCHAR szFileName,
  512. PWCHAR szInfType)
  513. {
  514. PCHAR szfn;
  515. PCHAR szit;
  516. int cchfn;
  517. int cchit;
  518. HANDLE h;
  519. cchfn = (lstrlenW(szFileName)+1)*sizeof(TCHAR);
  520. cchit = (lstrlenW(szInfType)+1)*sizeof(TCHAR);
  521. szfn = AllocSplMem(cchfn);
  522. szit = AllocSplMem(cchit);
  523. WideCharToMultiByte( CP_ACP, 0,
  524. szFileName, lstrlenW(szFileName)+1,
  525. szfn, cchfn,
  526. NULL, NULL );
  527. WideCharToMultiByte( CP_ACP, 0,
  528. szInfType, lstrlenW(szInfType)+1,
  529. szit, cchit,
  530. NULL, NULL );
  531. h = OpenInfFile(szfn, szit);
  532. FreeSplMem(szfn);
  533. FreeSplMem(szit);
  534. return h;
  535. }
  536. PINFDRIVER
  537. GetInfDriver(
  538. PINFCACHE pInfCache,
  539. UINT uIndex)
  540. {
  541. return &pInfCache->aInfDriver[uIndex];
  542. }
  543. BOOL APIENTRY
  544. SelectDriverDlg(
  545. HWND hwnd,
  546. UINT msg,
  547. WPARAM wparam,
  548. LPARAM lparam)
  549. {
  550. PINFPARMS pInfParms;
  551. switch(msg)
  552. {
  553. case WM_INITDIALOG:
  554. return SelectDriverInitDialog(hwnd, (PINFPARMS)lparam);
  555. case WM_COMMAND:
  556. switch (LOWORD(wparam))
  557. {
  558. case IDOK:
  559. return SelectDriverCommandOK(hwnd);
  560. case IDCANCEL:
  561. return SelectDriverCommandCancel(hwnd);
  562. case IDD_SD_LB_PRINTERDRIVERS:
  563. switch (HIWORD(wparam))
  564. {
  565. case CBN_DBLCLK:
  566. return SelectDriverCommandOK(hwnd);
  567. }
  568. break;
  569. case IDD_SD_PB_HELP:
  570. goto DoHelp;
  571. }
  572. }
  573. if( msg == WM_Help ) {
  574. DoHelp:
  575. pInfParms = (PINFPARMS)GetWindowLong(hwnd,
  576. GWL_USERDATA);
  577. ShowHelp(hwnd,
  578. HELP_CONTEXT,
  579. pInfParms->pInstallDriverData->dlgSelectHelp);
  580. }
  581. return FALSE;
  582. }
  583. BOOL
  584. SelectDriverInitDialog(
  585. HWND hwnd,
  586. PINFPARMS pInfParms)
  587. {
  588. PINSTALLDRIVERDATA pInstallDriverData = pInfParms->pInstallDriverData;
  589. PTCHAR pOptions;
  590. LPTSTR pszTitle;
  591. SetWindowLong(hwnd, GWL_USERDATA, (LONG)pInfParms);
  592. // #ifndef JAPAN
  593. if (!bJapan) {
  594. SETDLGITEMFONT(hwnd, IDD_SD_EF_SOURCEDIRECTORY, hfontHelv);
  595. SETDLGITEMFONT(hwnd, IDD_SD_LB_PRINTERDRIVERS, hfontHelv);
  596. }
  597. // #endif
  598. SetDlgItemText(hwnd,
  599. IDD_SD_EF_SOURCEDIRECTORY,
  600. pInfParms->pInfDirectory);
  601. SendDlgItemMessage(hwnd, IDD_SD_EF_SOURCEDIRECTORY, EM_LIMITTEXT, MAX_PATH, 0);
  602. SendDlgItemMessage(hwnd, IDD_SD_EF_SOURCEDIRECTORY, WM_KEYDOWN, (WPARAM)VK_END, 0);
  603. pOptions = pInfParms->pOptions;
  604. pszTitle = GetString(pInstallDriverData->idsSelectTitle);
  605. if (pszTitle) {
  606. SetWindowText(hwnd, pszTitle);
  607. FreeSplStr(pszTitle);
  608. }
  609. pszTitle = GetString(pInstallDriverData->idsType);
  610. if (pszTitle) {
  611. SetDlgItemText(hwnd, IDD_SD_TX_TYPE, pszTitle);
  612. FreeSplStr(pszTitle);
  613. }
  614. /* Only continue as long as we get a valid option text.
  615. * If GetOptionTextW returns NULL, we've probably got
  616. * a corrupted INF file.
  617. */
  618. while( *pOptions /*&& pOptionText*/ )
  619. {
  620. /* !!! What do we do with the language here ???
  621. * IGNORE IT!
  622. */
  623. SendDlgItemMessage( hwnd, IDD_SD_LB_PRINTERDRIVERS, LB_INSERTSTRING,
  624. (UINT)-1, (LONG)(LPTSTR)pOptions);
  625. while(*pOptions++);
  626. }
  627. SetFocus( GetDlgItem( hwnd, IDD_SD_LB_PRINTERDRIVERS ) );
  628. SendMessage( GetDlgItem( hwnd, IDD_SD_LB_PRINTERDRIVERS ),
  629. LB_SETCURSEL, 0, 0 );
  630. return FALSE;
  631. }
  632. /*
  633. *
  634. */
  635. BOOL SelectDriverCommandOK(HWND hwnd)
  636. {
  637. PINFPARMS pInfParms;
  638. TCHAR string[MAX_PATH];
  639. PTCHAR pOptions;
  640. int Selection;
  641. pInfParms = (PINFPARMS)GetWindowLong( hwnd, GWL_USERDATA );
  642. GetDlgItemText(hwnd,
  643. IDD_SD_EF_SOURCEDIRECTORY,
  644. string,
  645. sizeof (string)/sizeof(TCHAR) );
  646. // if(LastChar(string) != BACKSLASH)
  647. // AppendChar(string, BACKSLASH);
  648. ReallocSplStr( &pInfParms->pSetupDirectory, string );
  649. Selection = GETLISTSELECT( hwnd, IDD_SD_LB_PRINTERDRIVERS );
  650. GETLISTTEXT( hwnd, IDD_SD_LB_PRINTERDRIVERS, Selection, string );
  651. pOptions = pInfParms->pOptions;
  652. pInfParms->pOptionSelected = GetOptionFromListSelection( Selection,
  653. pOptions );
  654. EndDialog( hwnd, TRUE );
  655. return TRUE;
  656. }
  657. /*
  658. *
  659. */
  660. BOOL SelectDriverCommandCancel(HWND hwnd)
  661. {
  662. EndDialog(hwnd, FALSE);
  663. return TRUE;
  664. }
  665. /*
  666. *
  667. */
  668. PTCHAR
  669. GetOptionFromListSelection(
  670. INT Selection,
  671. PTCHAR pOption)
  672. {
  673. int i = 0;
  674. while( i < Selection )
  675. {
  676. while( *pOption ) /* Increment to null terminator */
  677. pOption++;
  678. pOption++; /* Increment to beginning of next option */
  679. i++;
  680. }
  681. return pOption;
  682. }
  683. BOOL APIENTRY
  684. InstallDriverDlg(
  685. HWND hwnd,
  686. UINT msg,
  687. WPARAM wparam,
  688. LPARAM lparam)
  689. /*++
  690. Routine Description:
  691. Dialog for user to type in a path for the in file. This dialog
  692. then creates the select dialog to choose a new driver.
  693. ** NOTE ** Callee must free pOptions, since pOptionSelected
  694. points into this buffer.
  695. Arguments:
  696. Return Value:
  697. --*/
  698. {
  699. PINFPARMS pInfParms;
  700. switch(msg)
  701. {
  702. case WM_INITDIALOG:
  703. return InstallDriverInitDialog(hwnd, (PINFPARMS)lparam);
  704. case WM_COMMAND:
  705. switch (LOWORD(wparam))
  706. {
  707. case IDOK:
  708. return InstallDriverCommandOK(hwnd);
  709. case IDCANCEL:
  710. return InstallDriverCommandCancel(hwnd);
  711. case IDD_ID_HELP:
  712. goto DoHelp;
  713. }
  714. }
  715. if( msg == WM_Help ) {
  716. DoHelp:
  717. pInfParms = (PINFPARMS)GetWindowLong(hwnd,
  718. GWL_USERDATA);
  719. ShowHelp(hwnd,
  720. HELP_CONTEXT,
  721. pInfParms->pInstallDriverData->dlgInstallHelp);
  722. }
  723. return FALSE;
  724. }
  725. /*
  726. *
  727. */
  728. BOOL
  729. InstallDriverInitDialog(
  730. HWND hwnd,
  731. PINFPARMS pInfParms)
  732. {
  733. LPTSTR pszTitle;
  734. PINSTALLDRIVERDATA pInstallDriverData = pInfParms->pInstallDriverData;
  735. SetWindowLong(hwnd, GWL_USERDATA, (LONG)pInfParms);
  736. // #ifndef JAPAN
  737. if (!bJapan) {
  738. SETDLGITEMFONT(hwnd, IDD_ID_EF_DRIVERPATH, hfontHelv);
  739. }
  740. // #endif
  741. pszTitle = GetString(pInstallDriverData->idsInstallTitle);
  742. if (pszTitle) {
  743. SetWindowText(hwnd, pszTitle);
  744. FreeSplStr(pszTitle);
  745. }
  746. SendDlgItemMessage(hwnd, IDD_ID_EF_DRIVERPATH, EM_LIMITTEXT, MAX_PATH, 0);
  747. SetDlgItemText(hwnd, IDD_ID_EF_DRIVERPATH, TEXT("A:\\"));
  748. return TRUE;
  749. }
  750. /*
  751. *
  752. */
  753. BOOL InstallDriverCommandOK(HWND hwnd)
  754. {
  755. TCHAR FileName[MAX_PATH+1+1+11];
  756. // Note maximum possible characters retrievable from
  757. // the dialog box MAX_PATH + 1 char for the '\\' +
  758. // 11 chars for the szSetupInf + 1 char null terminator
  759. HANDLE hInfFile;
  760. PTCHAR pOptions;
  761. BOOL SetupOK;
  762. DWORD ExitCode;
  763. PINSTALLDRIVERDATA pInstallDriverData;
  764. PINFPARMS pInfParms;
  765. TCHAR FullPath[MAX_PATH+1+1+11];
  766. BOOL OK = FALSE;
  767. PTCHAR pFilePart;
  768. pInfParms = (PINFPARMS)GetWindowLong( hwnd, GWL_USERDATA );
  769. pInstallDriverData =pInfParms->pInstallDriverData;
  770. //
  771. // Get the path, which may or may not have been modified by the user:
  772. //
  773. memset(FileName, 0, MAX_PATH+13);
  774. GetDlgItemText(hwnd, IDD_ID_EF_DRIVERPATH, FileName, MAX_PATH);
  775. if(LastChar(FileName) != BACKSLASH) /* Ensure it's terminated with backslash */
  776. AppendChar(FileName, BACKSLASH);
  777. /* Append the setup filename to the path:
  778. */
  779. _tcscat(FileName, pInstallDriverData->pszInfFile);
  780. hInfFile = OpenInfFileW(FileName, pInstallDriverData->pszInfType);
  781. if(hInfFile == INVALID_HANDLE_VALUE)
  782. {
  783. Message(hwnd, MSG_ERROR, IDS_PRINTMANAGER,
  784. IDS_COULDNOTFINDINFFILE, FileName);
  785. OK = FALSE;
  786. }
  787. else
  788. {
  789. GetDlgItemText(hwnd, IDD_ID_EF_DRIVERPATH, FileName, sizeof FileName/sizeof(TCHAR));
  790. /* Now get a full path name which will be passed on to SETUP.
  791. * We will give SETUP the full path name in case the user typed in
  792. * a relative path. In this instance, SETUP will assume that the
  793. * default directory is System32, but this might just possibly
  794. * not correspond to Print Manager's default.
  795. * We just found the .INF file in the directory, so it's safe to
  796. * assume that GetFullPathname will succeed.
  797. */
  798. if( GetFullPathName( FileName, sizeof FullPath/sizeof(TCHAR), FullPath, &pFilePart ) )
  799. {
  800. pOptions = GetOptionListW(hInfFile, pInstallDriverData->pszSection);
  801. /* Assume the drivers are in the same directory as the INF file;
  802. * this can be overridden by the user:
  803. */
  804. pInfParms->pSetupDirectory = AllocSplStr(FullPath);
  805. pInfParms->pInfDirectory = AllocSplStr(FullPath);
  806. if(pOptions && pInfParms->pSetupDirectory
  807. && pInfParms->pInfDirectory)
  808. {
  809. pInfParms->pOptions = pOptions;
  810. SetCursor( hcursorWait );
  811. if( DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_SELECTDRIVER),
  812. hwnd, (DLGPROC)SelectDriverDlg,
  813. (DWORD)pInfParms) == IDOK )
  814. {
  815. SetupOK = InvokeSetup( hwnd,
  816. pInstallDriverData->pszInfFile,
  817. pInfParms->pSetupDirectory,
  818. pInfParms->pInfDirectory,
  819. pInfParms->pOptionSelected,
  820. pInfParms->pServerName,
  821. &ExitCode );
  822. if( SetupOK && ( ExitCode == 0 ) )
  823. {
  824. DBGMSG( DBG_INFO, ( "%s was installed.\n",
  825. pInfParms->pOptionSelected ) );
  826. OK = TRUE;
  827. }
  828. else
  829. {
  830. DBGMSG( DBG_WARNING, ( "Setup failed: return code %d; exit code %d\n",
  831. SetupOK, ExitCode ) );
  832. }
  833. }
  834. FreeSplStr( pInfParms->pSetupDirectory );
  835. FreeSplStr( pInfParms->pInfDirectory );
  836. //
  837. // Callee is responsible for LocalFree(pOptions);
  838. // since pOptionSelected points into the buffer.
  839. //
  840. }
  841. }
  842. else
  843. {
  844. /* This should not happen.
  845. */
  846. DBGMSG( DBG_WARNING, ("GetFullPathName( %s ) failed: Error %d\n",
  847. FileName, GetLastError( ) ) );
  848. }
  849. CloseInfFile(hInfFile);
  850. }
  851. if( OK )
  852. EndDialog(hwnd, TRUE);
  853. return TRUE;
  854. }
  855. /*
  856. *
  857. */
  858. BOOL InstallDriverCommandCancel(HWND hwnd)
  859. {
  860. EndDialog(hwnd, FALSE);
  861. return TRUE;
  862. }
  863. /*
  864. *
  865. */
  866. TCHAR LastChar(TCHAR *string)
  867. {
  868. while(*string) /* Increment to the null terminator */
  869. string++;
  870. return *(--string);
  871. }
  872. /*
  873. *
  874. */
  875. void AppendChar(TCHAR *string, TCHAR ch)
  876. {
  877. while(*string) /* Increment to the null terminator */
  878. string++;
  879. *string++ = ch;
  880. *string = NULLC;
  881. }
  882. //
  883. // InvokeSetup
  884. //
  885. // Call the SETUP.EXE program to install an option listed in an .INF file.
  886. // The SETUP program will make the correct registry entries for this option
  887. // under both HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER. It will set the
  888. // new default value for the USER (i.e. a new locale or keyboard layout).
  889. //
  890. BOOL InvokeSetup (HWND hwnd, LPTSTR pszInfFile, LPTSTR pszSetupDirectory,
  891. LPTSTR pszInfDirectory, LPTSTR pszOption, LPTSTR pszServerName,
  892. PDWORD pExitCode)
  893. {
  894. TCHAR *pszSetupString = TEXT("\\SETUP.EXE -f -s %s -i %s\\%s -c ExternalInstallOption \
  895. /t STF_LANGUAGE = ENG /t OPTION = \"%s\" /t STF_PRINTSERVER = \"%s\" /t ADDCOPY = YES \
  896. /t DOCOPY = YES /t DOCONFIG = YES /w %d");
  897. int CmdSetupLength;
  898. TCHAR pszSetup[200+MAX_PATH];
  899. TCHAR *pszCmdSetup;
  900. MSG Msg;
  901. STARTUPINFO StartupInfo;
  902. PROCESS_INFORMATION ProcessInformation;
  903. BOOL b;
  904. // Create command line to invoke SETUP program
  905. *pszSetup = NULLC;
  906. GetSystemDirectory( pszSetup, sizeof pszSetup/sizeof(TCHAR) );
  907. _tcscat( pszSetup, pszSetupString );
  908. /* SLIGHT HACK:
  909. *
  910. * Currently we specify both setup and inf directories, or neither:
  911. * We'll need to get more sophisticated if other combinations are needed.
  912. */
  913. if( !pszSetupDirectory && !pszInfDirectory )
  914. {
  915. DeleteSubstring( pszSetup, TEXT("-s %s ") );
  916. DeleteSubstring( pszSetup, TEXT("%s\\") );
  917. }
  918. /* Find out how much buffer we need for the command.
  919. * Theoretically this could be enormous.
  920. *
  921. * The 20 is for the window handle passed in ascii.
  922. *
  923. */
  924. CmdSetupLength = ( _tcslen( pszSetup )+1
  925. + ( pszSetupDirectory ? _tcslen( pszSetupDirectory )+1 : 0 )
  926. + ( pszInfDirectory ? _tcslen( pszInfDirectory )+1 : 0 )
  927. + ( pszServerName ? _tcslen( pszServerName )+1 : 0 )
  928. + _tcslen( pszOption )+1
  929. + _tcslen( pszInfFile )+1 ) * sizeof(TCHAR)
  930. + 20;
  931. if( !( pszCmdSetup = AllocSplMem( CmdSetupLength ) ) )
  932. return FALSE;
  933. if( !pszServerName )
  934. pszServerName = TEXT("");
  935. if( !pszSetupDirectory && !pszInfDirectory )
  936. {
  937. wsprintf (pszCmdSetup,
  938. pszSetup,
  939. pszInfFile,
  940. pszOption,
  941. pszServerName,
  942. hwnd);
  943. }
  944. else
  945. {
  946. wsprintf (pszCmdSetup,
  947. pszSetup,
  948. pszSetupDirectory,
  949. pszInfDirectory,
  950. pszInfFile,
  951. pszOption,
  952. pszServerName,
  953. hwnd);
  954. }
  955. // Create screen saver process
  956. ZERO_OUT( &StartupInfo );
  957. StartupInfo.cb = sizeof(StartupInfo);
  958. StartupInfo.wShowWindow = SW_SHOW;
  959. b = CreateProcess ( NULL,
  960. pszCmdSetup,
  961. NULL,
  962. NULL,
  963. FALSE,
  964. 0,
  965. NULL,
  966. NULL,
  967. &StartupInfo,
  968. &ProcessInformation
  969. );
  970. // If process creation successful, wait for it to
  971. // complete before continuing
  972. if ( b )
  973. {
  974. EnableWindow (hwnd, FALSE);
  975. while (MsgWaitForMultipleObjects (
  976. 1,
  977. &ProcessInformation.hProcess,
  978. FALSE,
  979. (DWORD)-1,
  980. QS_ALLINPUT) != 0)
  981. {
  982. // This message loop is a duplicate of main
  983. // message loop with the exception of using
  984. // PeekMessage instead of waiting inside of
  985. // GetMessage. Process wait will actually
  986. // be done in MsgWaitForMultipleObjects api.
  987. //
  988. while (PeekMessage (&Msg, NULL, 0, 0, PM_REMOVE))
  989. {
  990. TranslateMessage (&Msg);
  991. DispatchMessage (&Msg);
  992. }
  993. }
  994. GetExitCodeProcess (ProcessInformation.hProcess, pExitCode);
  995. CloseHandle (ProcessInformation.hProcess);
  996. CloseHandle (ProcessInformation.hThread);
  997. EnableWindow (hwnd, TRUE);
  998. SetForegroundWindow (hwnd);
  999. }
  1000. else
  1001. {
  1002. ReportFailure( hwnd, 0, IDS_ERRORRUNNINGSETUP );
  1003. }
  1004. FreeSplMem( pszCmdSetup );
  1005. return b;
  1006. }