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.

892 lines
19 KiB

  1. /* File: progcm.c */
  2. /**************************************************************************/
  3. /* Install: Program Manager commands.
  4. /* Uses DDE to communicate with ProgMan
  5. /* Can create groups, delete groups, add items to groups
  6. /* Originally written 3/9/89 by toddla (the stuff that looks terrible)
  7. /* Munged greatly for STUFF 4/15/91 by chrispi (the stuff that doesn't work)
  8. /**************************************************************************/
  9. #include <nt.h>
  10. #include <ntrtl.h>
  11. #include <nturtl.h>
  12. #include <cmnds.h>
  13. #include <dde.h>
  14. #include "install.h"
  15. #include "uilstf.h"
  16. #define BIG_ENUF 1024
  17. _dt_system(Install)
  18. _dt_subsystem(ProgMan Operations)
  19. HANDLE
  20. ExecuteApplication(
  21. LPSTR lpApp,
  22. WORD nCmdShow
  23. );
  24. HWND hwndFrame;
  25. HWND hwndProgressGizmo;
  26. CHAR szProgMan[] = "PROGMAN";
  27. HWND hwndDde = NULL; // dummy window to handle DDE messages
  28. HWND hwndProgMan = NULL; // global handle of progman window
  29. BOOL fInitiate = fFalse; // are we initializing?
  30. BOOL fAck = fFalse;
  31. BOOL fProgManExeced = fFalse;
  32. HANDLE hInstCur = NULL;
  33. /*
  34. ** Purpose:
  35. ** Arguments:
  36. ** Returns:
  37. **
  38. **************************************************************************/
  39. _dt_private
  40. BOOL
  41. APIENTRY
  42. FDdeTerminate(VOID)
  43. {
  44. PreCondition(hwndProgMan != NULL, fFalse);
  45. PreCondition(hwndDde != NULL, fFalse);
  46. SetForegroundWindow(hwndFrame);
  47. UpdateWindow(hwndFrame);
  48. MPostWM_DDE_TERMINATE( hwndProgMan, hwndDde );
  49. hwndProgMan = NULL;
  50. return(fTrue);
  51. }
  52. /*
  53. ** Purpose:
  54. ** Arguments:
  55. ** Returns:
  56. **
  57. **************************************************************************/
  58. _dt_private
  59. LONG_PTR
  60. APIENTRY
  61. WndProcDde(
  62. HWND hwnd,
  63. UINT uiMessage,
  64. WPARAM wParam,
  65. LPARAM lParam
  66. )
  67. {
  68. AssertDataSeg();
  69. switch (uiMessage) {
  70. case WM_DDE_TERMINATE:
  71. if(hwndProgMan == NULL) {
  72. DestroyWindow(hwnd);
  73. hwndDde = NULL;
  74. }
  75. else {
  76. EvalAssert(FDdeTerminate());
  77. }
  78. DDEFREE( uiMessage, lParam );
  79. return(0L);
  80. case WM_DDE_ACK:
  81. if (fInitiate) {
  82. ATOM aApp = LOWORD(lParam);
  83. ATOM aTopic = HIWORD(lParam);
  84. hwndProgMan = (HWND)wParam; //conversation established 1632
  85. GlobalDeleteAtom (aApp);
  86. GlobalDeleteAtom (aTopic);
  87. }
  88. else {
  89. WORD wStatus = GET_WM_DDE_EXECACK_STATUS(wParam, lParam);
  90. HANDLE hCommands = GET_WM_DDE_EXECACK_HDATA(wParam, lParam);
  91. if (hCommands) {
  92. fAck = ((DDEACK *)(&wStatus))->fAck;
  93. GlobalFree(hCommands);
  94. }
  95. DDEFREE( uiMessage, lParam );
  96. }
  97. return(0L);
  98. default:
  99. break;
  100. }
  101. return(DefWindowProc(hwnd, uiMessage, wParam, lParam));
  102. }
  103. /*
  104. ** Purpose:
  105. ** Arguments:
  106. ** Returns:
  107. **
  108. **************************************************************************/
  109. _dt_private
  110. BOOL
  111. APIENTRY
  112. FDdeInit(
  113. HANDLE hInst
  114. )
  115. {
  116. if (hInst == NULL) {
  117. /* try to re-init with hInst from last FDdeInit call */
  118. if (hInstCur == NULL) {
  119. return(fFalse);
  120. }
  121. hInst = hInstCur;
  122. }
  123. else {
  124. hInstCur = hInst;
  125. }
  126. if (hwndDde == NULL) {
  127. static CHP szClassName[] = "ddeClass";
  128. WNDCLASS rClass;
  129. Assert(hwndProgMan == NULL);
  130. if (!GetClassInfo(hInst, szClassName, &rClass)) {
  131. rClass.hCursor = NULL;
  132. rClass.hIcon = NULL;
  133. rClass.lpszMenuName = NULL;
  134. rClass.lpszClassName = szClassName;
  135. rClass.hbrBackground = NULL;
  136. rClass.hInstance = hInst;
  137. rClass.style = 0;
  138. rClass.lpfnWndProc = WndProcDde;
  139. rClass.cbClsExtra = 0;
  140. rClass.cbWndExtra = 0;
  141. if (!RegisterClass(&rClass)) {
  142. return(fFalse);
  143. }
  144. }
  145. hwndDde = CreateWindow(
  146. szClassName,
  147. NULL,
  148. 0L,
  149. 0, 0, 0, 0,
  150. (HWND)NULL,
  151. (HMENU)NULL,
  152. (HANDLE)hInst,
  153. (LPSTR)NULL
  154. );
  155. }
  156. return(hwndDde != NULL);
  157. }
  158. /*
  159. ** Purpose:
  160. ** Arguments:
  161. ** Returns:
  162. **
  163. **************************************************************************/
  164. _dt_private
  165. VOID
  166. APIENTRY
  167. DdeSendConnect(
  168. ATOM aApp,
  169. ATOM aTopic
  170. )
  171. {
  172. fInitiate = fTrue;
  173. SendMessage(
  174. (HWND)-1,
  175. WM_DDE_INITIATE,
  176. (WPARAM)hwndDde,
  177. MAKELONG(aApp, aTopic)
  178. );
  179. fInitiate = fFalse;
  180. }
  181. /*
  182. ** Purpose:
  183. ** Arguments:
  184. ** Returns:
  185. **
  186. **************************************************************************/
  187. _dt_private
  188. BOOL
  189. APIENTRY
  190. FDdeConnect(
  191. SZ szApp,
  192. SZ szTopic
  193. )
  194. {
  195. BOOL fStatus = fTrue;
  196. MSG rMsg;
  197. HANDLE hProcess = NULL;
  198. //
  199. // Form the Global Atoms used to indicate the app and topic
  200. //
  201. ATOM aApp = GlobalAddAtom(szApp);
  202. ATOM aTopic = GlobalAddAtom(szTopic);
  203. //
  204. // Connect to the progman dde server
  205. //
  206. DdeSendConnect(aApp, aTopic);
  207. if (hwndProgMan == NULL) {
  208. //
  209. // If the connect failed then try to run progman.
  210. //
  211. if ((hProcess = ExecuteApplication("PROGMAN /NTSETUP", SW_SHOWNORMAL)) == NULL ) {
  212. fStatus = fFalse;
  213. }
  214. else {
  215. INT i;
  216. DWORD dw;
  217. #define TIMEOUT_INTERVAL 120000
  218. //
  219. // Indicate that Progman has been execed
  220. //
  221. fProgManExeced = fTrue;
  222. //
  223. // exec was successful, first wait for input idle
  224. //
  225. if( (dw = WaitForInputIdle( hProcess, TIMEOUT_INTERVAL )) != 0 ) {
  226. CloseHandle( hProcess );
  227. fStatus = fFalse;
  228. }
  229. else {
  230. CloseHandle( hProcess );
  231. //
  232. // Empty the message queue till no messages
  233. // are left in the queue or till WM_ACTIVATEAPP is processed. Then
  234. // try connecting to progman. I am using PeekMessage followed
  235. // by GetMessage because PeekMessage doesn't remove some messages
  236. // ( WM_PAINT for one ).
  237. //
  238. while ( PeekMessage( &rMsg, hwndFrame, 0, 0, PM_NOREMOVE ) &&
  239. GetMessage(&rMsg, NULL, 0, 0) ) {
  240. if (TRUE
  241. && (hwndProgressGizmo == NULL
  242. || !IsDialogMessage(hwndProgressGizmo, &rMsg))) {
  243. TranslateMessage(&rMsg);
  244. DispatchMessage(&rMsg);
  245. }
  246. if ( rMsg.message == WM_ACTIVATEAPP ) {
  247. break;
  248. }
  249. }
  250. DdeSendConnect(aApp, aTopic);
  251. }
  252. }
  253. }
  254. //
  255. // Delete the atom resources
  256. //
  257. GlobalDeleteAtom(aApp);
  258. GlobalDeleteAtom(aTopic);
  259. return ( fStatus );
  260. }
  261. /*
  262. ** Purpose:
  263. ** Arguments:
  264. ** Returns:
  265. **
  266. **************************************************************************/
  267. _dt_private
  268. BOOL
  269. APIENTRY
  270. FDdeWait(VOID)
  271. {
  272. MSG rMsg;
  273. BOOL fResult = fTrue;
  274. DWORD dwTimeOut, dwTickDelta, dwLastTick, dwCurrentTick;
  275. Assert(hwndProgMan != NULL);
  276. Assert(hwndDde != NULL);
  277. //
  278. // Set timeout for 30 seconds from now. This assumes that it will
  279. // take less than 30 seconds for Progman to respond.
  280. //
  281. dwTimeOut = 30000L;
  282. dwLastTick = GetTickCount();
  283. while (TRUE) {
  284. //
  285. // While there is a connection established to progman and there
  286. // are DDE messages we can fetch, fetch the messages dispatch them
  287. // and try to find out if they are terminators (data, ack or terminate)
  288. //
  289. while (
  290. hwndProgMan != NULL &&
  291. PeekMessage(&rMsg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE)
  292. ) {
  293. TranslateMessage(&rMsg);
  294. DispatchMessage(&rMsg);
  295. if (rMsg.wParam == (WPARAM)hwndProgMan) {
  296. switch (rMsg.message) {
  297. case WM_DDE_ACK:
  298. return ( fAck );
  299. case WM_DDE_DATA:
  300. return (fTrue);
  301. default:
  302. break;
  303. }
  304. }
  305. }
  306. //
  307. // If connection to progman has been broken, this may be resulting
  308. // from a terminate, so return true
  309. //
  310. if (hwndProgMan == NULL) {
  311. return (fTrue);
  312. }
  313. //
  314. // Check to see if timeout hasn't been reached. If the timeout is
  315. // reached we will assume that our command succeeded (for want of
  316. // a better verification scheme
  317. //
  318. dwTickDelta = ((dwCurrentTick = GetTickCount()) < dwLastTick) ?
  319. dwCurrentTick : (dwCurrentTick - dwLastTick);
  320. if (dwTimeOut < dwTickDelta) {
  321. return (fTrue);
  322. }
  323. dwTimeOut = dwTimeOut - dwTickDelta;
  324. dwLastTick = dwCurrentTick;
  325. //
  326. // Lastly, since user doesn't have idle detection, we will be
  327. // sitting in a tight loop here. To prevent this just do a
  328. // sleep for 250 milliseconds.
  329. //
  330. Sleep( 250 );
  331. }
  332. return(fTrue);
  333. }
  334. /*
  335. ** Purpose:
  336. ** Arguments:
  337. ** Returns:
  338. **
  339. **************************************************************************/
  340. _dt_private
  341. BOOL
  342. APIENTRY
  343. FDdeExec(
  344. SZ szCmd
  345. )
  346. {
  347. BOOL bResult = fFalse;
  348. HANDLE hCmd;
  349. Assert(hwndProgMan != NULL);
  350. Assert(hwndDde != NULL);
  351. hCmd = GlobalAlloc(GMEM_DDESHARE, (LONG)CchpStrLen(szCmd) + 1);
  352. if (hCmd != NULL) {
  353. LPSTR lpCmd = GlobalLock(hCmd);
  354. if (lpCmd != NULL) {
  355. lstrcpy(lpCmd, szCmd);
  356. GlobalUnlock(hCmd);
  357. MPostWM_DDE_EXECUTE(hwndProgMan, hwndDde, hCmd);
  358. bResult = FDdeWait();
  359. }
  360. else {
  361. GlobalFree(hCmd);
  362. }
  363. }
  364. return(bResult);
  365. }
  366. /*
  367. ** Purpose:
  368. ** Arguments:
  369. ** Returns:
  370. **
  371. **************************************************************************/
  372. _dt_private
  373. BOOL
  374. APIENTRY
  375. FActivateProgMan(VOID)
  376. {
  377. //
  378. // Find out if the dde client window has been started, if not start it
  379. //
  380. if (hwndDde == NULL) {
  381. if (!FDdeInit(NULL)) {
  382. return(fFalse);
  383. }
  384. Assert(hwndDde != NULL);
  385. }
  386. //
  387. // Find out if the connection has been established with the progman
  388. // server, if not try to connect
  389. //
  390. if (hwndProgMan == NULL) {
  391. //
  392. // Try to conncect and then see if we were successful
  393. //
  394. if ( (!FDdeConnect(szProgMan, szProgMan)) ||
  395. (hwndProgMan == NULL)
  396. ) {
  397. return(fFalse);
  398. }
  399. }
  400. //
  401. // Bring progman to the foreground
  402. //
  403. SetForegroundWindow(hwndProgMan);
  404. //
  405. // If progman is iconic restore it
  406. //
  407. if (GetWindowLong(hwndProgMan, GWL_STYLE) & WS_ICONIC) {
  408. ShowWindow(hwndProgMan, SW_RESTORE);
  409. }
  410. return(fTrue);
  411. }
  412. /*
  413. ** Purpose:
  414. ** Creates a new Program Manager group.
  415. ** Arguments:
  416. ** Valid command options:
  417. ** cmoVital
  418. ** Notes:
  419. ** Initializes and activates the DDE communication if it is not
  420. ** currently open.
  421. ** Returns:
  422. ** fTrue if group was created, or already existed
  423. ** fFalse otherwise.
  424. **
  425. **************************************************************************/
  426. _dt_private
  427. BOOL
  428. APIENTRY
  429. FCreateProgManGroup(
  430. SZ szGroup,
  431. SZ szPath,
  432. CMO cmo,
  433. BOOL CommonGroup
  434. )
  435. {
  436. static CHP szCmdBase[] = "[CreateGroup(%s%s%s,%s)]";
  437. CCHP cchp;
  438. char szBuf[BIG_ENUF];
  439. BOOL fVital = cmo & cmoVital;
  440. EERC eerc;
  441. if (szPath == NULL) {
  442. szPath = "";
  443. }
  444. FActivateProgMan();
  445. wsprintf(szBuf, szCmdBase, szGroup, (*szPath ? "," : szPath), szPath, CommonGroup ? "1" : "0");
  446. FDdeExec(szBuf);
  447. return(fTrue);
  448. }
  449. /*
  450. ** Purpose:
  451. ** Removes a Program Manager group.
  452. ** Arguments:
  453. ** Valid command options:
  454. ** cmoVital
  455. ** Notes:
  456. ** Initializes and activates the DDE communication if it is not
  457. ** currently open.
  458. ** Returns:
  459. ** fTrue if successful if removed, or didn't exist
  460. ** fFalse otherwise.
  461. **
  462. **************************************************************************/
  463. _dt_private
  464. BOOL
  465. APIENTRY
  466. FRemoveProgManGroup(
  467. SZ szGroup,
  468. CMO cmo,
  469. BOOL CommonGroup
  470. )
  471. {
  472. static CHP szCmdBase[] = "[DeleteGroup(%s,%s)]";
  473. CCHP cchp;
  474. char szBuf[BIG_ENUF];
  475. BOOL fVital = cmo & cmoVital;
  476. EERC eerc;
  477. FActivateProgMan();
  478. wsprintf(szBuf, szCmdBase, szGroup, CommonGroup ? "1" : "0");
  479. FDdeExec(szBuf);
  480. return(fTrue);
  481. }
  482. /*
  483. ** Purpose:
  484. ** Shows a program manager group in one of several different ways
  485. ** based upon the parameter szCommand.
  486. ** Arguments:
  487. ** szGroup: non-NULL, non-empty group to show.
  488. ** szCommand: non-NULL, non-empty command to exec.
  489. ** cmo: Valid command options - cmoVital and cmoNone.
  490. ** Notes:
  491. ** Initializes and activates the DDE communication if it is not
  492. ** currently open.
  493. ** Returns:
  494. ** Returns fTrue if successful, fFalse otherwise.
  495. **
  496. **************************************************************************/
  497. _dt_private
  498. BOOL
  499. APIENTRY
  500. FShowProgManGroup(
  501. SZ szGroup,
  502. SZ szCommand,
  503. CMO cmo,
  504. BOOL CommonGroup
  505. )
  506. {
  507. static CHP szCmdBase[] = "[ShowGroup(%s, %s,%s)]";
  508. CCHP cchp;
  509. CHP szBuf[BIG_ENUF];
  510. BOOL fVital = cmo & cmoVital;
  511. EERC eerc;
  512. ChkArg((szGroup != (SZ)NULL) && (*szGroup != '\0'), 1, fFalse);
  513. ChkArg((szCommand != (SZ)NULL) && (*szCommand != '\0'), 2, fFalse);
  514. FActivateProgMan();
  515. wsprintf(szBuf, szCmdBase, szGroup, szCommand, CommonGroup ? "1" : "0");
  516. FDdeExec(szBuf);
  517. return(fTrue);
  518. }
  519. /*
  520. ** Purpose:
  521. ** Creates a new Program Manager item.
  522. ** Always attempts to create the group if it doesn't exist.
  523. ** Arguments:
  524. ** Valid command options:
  525. ** cmoVital
  526. ** cmoOverwrite
  527. ** Notes:
  528. ** Initializes and activates the DDE communication if it is not
  529. ** currently open.
  530. ** Returns:
  531. ** Returns fTrue if successful, fFalse otherwise.
  532. **
  533. **************************************************************************/
  534. _dt_private BOOL APIENTRY
  535. FCreateProgManItem(
  536. SZ szGroup,
  537. SZ szItem,
  538. SZ szCmd,
  539. SZ szIconFile,
  540. INT nIconNum,
  541. CMO cmo,
  542. BOOL CommonGroup
  543. )
  544. {
  545. static CHP szCmdBase[] = "[AddItem(%s, %s, %s, %d)]";
  546. CCHP cchp;
  547. char szBuf[BIG_ENUF];
  548. BOOL fVital = cmo & cmoVital;
  549. EERC eerc;
  550. BOOL bStatus;
  551. FActivateProgMan();
  552. wsprintf(szBuf, szCmdBase, szCmd, szItem, szIconFile, nIconNum+666);
  553. bStatus = FDdeExec(szBuf);
  554. return(bStatus);
  555. }
  556. /*
  557. ** Purpose:
  558. ** Removes a program manager item.
  559. ** Arguments:
  560. ** Valid command options:
  561. ** cmoVital
  562. ** Returns:
  563. ** Returns fTrue if successful, fFalse otherwise.
  564. **
  565. **************************************************************************/
  566. _dt_private
  567. BOOL
  568. APIENTRY
  569. FRemoveProgManItem(
  570. SZ szGroup,
  571. SZ szItem,
  572. CMO cmo,
  573. BOOL CommonGroup
  574. )
  575. {
  576. static CHP szCmdBase[] = "[DeleteItem(%s)]";
  577. CCHP cchp;
  578. char szBuf[BIG_ENUF];
  579. BOOL fVital = cmo & cmoVital;
  580. EERC eerc;
  581. BOOL bStatus;
  582. FActivateProgMan();
  583. FCreateProgManGroup(szGroup, NULL, cmoVital, CommonGroup);
  584. wsprintf(szBuf, szCmdBase, szItem);
  585. bStatus = FDdeExec(szBuf);
  586. return(bStatus);
  587. }
  588. /*
  589. ** Purpose:
  590. ** Initializes the DDE window for communication with ProgMan
  591. ** Does not actually initiate a conversation with ProgMan
  592. ** Arguments:
  593. ** hInst instance handle for the setup application
  594. ** Returns:
  595. ** Returns fTrue if successful, fFalse otherwise.
  596. **
  597. **************************************************************************/
  598. _dt_private
  599. BOOL
  600. APIENTRY
  601. FInitProgManDde(
  602. HANDLE hInst
  603. )
  604. {
  605. if (hwndDde == NULL) {
  606. return(FDdeInit(hInst));
  607. }
  608. return(fTrue);
  609. }
  610. /*
  611. ** Purpose:
  612. ** Closes conversation with ProgMan (if any) and destroys
  613. ** the DDE communication window (if any)
  614. ** Arguments:
  615. ** (none)
  616. ** Returns:
  617. ** Returns fTrue if successful, fFalse otherwise.
  618. **
  619. **************************************************************************/
  620. _dt_private
  621. BOOL
  622. APIENTRY
  623. FEndProgManDde(VOID)
  624. {
  625. //
  626. // if we execed progman then we should try to close it down. When we
  627. // send a close message it will post us a WM_DDE_TERMINATE message
  628. // eventaully. else we haven't started progman so we just need to
  629. // terminate the connection.
  630. //
  631. if (fProgManExeced) {
  632. fProgManExeced = fFalse;
  633. //
  634. // Clean up connection to progman
  635. //
  636. if (hwndProgMan) {
  637. SetForegroundWindow(hwndFrame);
  638. UpdateWindow(hwndFrame);
  639. FDdeExec("[exitprogman(1)]"); // close save state
  640. hwndProgMan = NULL;
  641. }
  642. //
  643. // Destroy the DDE Window if need be
  644. //
  645. if (hwndDde) {
  646. DestroyWindow(hwndDde);
  647. hwndDde = NULL;
  648. }
  649. }
  650. else if (hwndProgMan != NULL) {
  651. EvalAssert( FDdeTerminate() );
  652. }
  653. else if (hwndDde != NULL) {
  654. DestroyWindow (hwndDde);
  655. hwndDde = NULL;
  656. }
  657. return (fTrue);
  658. }
  659. /*
  660. ** Purpose:
  661. ** Arguments:
  662. ** Returns:
  663. **
  664. **************************************************************************/
  665. HANDLE
  666. ExecuteApplication(
  667. LPSTR lpApp,
  668. WORD nCmdShow
  669. )
  670. {
  671. BOOL fStatus;
  672. STARTUPINFO si;
  673. PROCESS_INFORMATION pi;
  674. #if DBG
  675. DWORD dwLastError;
  676. #endif
  677. //
  678. // Initialise Startup info
  679. //
  680. si.cb = sizeof(STARTUPINFO);
  681. si.lpReserved = NULL;
  682. si.lpDesktop = NULL;
  683. si.lpTitle = NULL;
  684. si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
  685. si.dwFlags = STARTF_USESHOWWINDOW;
  686. si.wShowWindow = nCmdShow;
  687. si.lpReserved2 = NULL;
  688. si.cbReserved2 = 0;
  689. //
  690. // Execute using Create Process
  691. //
  692. fStatus = CreateProcess(
  693. (LPSTR)NULL, // lpApplicationName
  694. lpApp, // lpCommandLine
  695. (LPSECURITY_ATTRIBUTES)NULL, // lpProcessAttributes
  696. (LPSECURITY_ATTRIBUTES)NULL, // lpThreadAttributes
  697. DETACHED_PROCESS, // dwCreationFlags
  698. FALSE, // bInheritHandles
  699. (LPVOID)NULL, // lpEnvironment
  700. (LPSTR)NULL, // lpCurrentDirectory
  701. (LPSTARTUPINFO)&si, // lpStartupInfo
  702. (LPPROCESS_INFORMATION)&pi // lpProcessInformation
  703. );
  704. //
  705. // Since we are execing a detached process we don't care about when it
  706. // exits. To do proper book keeping, we should close the handles to
  707. // the process handle and thread handle
  708. //
  709. if (fStatus) {
  710. CloseHandle( pi.hThread );
  711. return( pi.hProcess );
  712. }
  713. #if DBG
  714. else {
  715. dwLastError = GetLastError();
  716. }
  717. #endif
  718. //
  719. // Return the status of this operation
  720. return ( (HANDLE)NULL );
  721. }