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.

606 lines
15 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. extern HWND hwndFrame;
  4. extern HANDLE hinstShell;
  5. extern BOOL FYield(VOID);
  6. BOOL WaitingOnChild = FALSE;
  7. /*
  8. Code to support RunExternalProgram, InvokeLibraryProcedure install commands
  9. LoadLibrary <diskname>,<libraryname>,<INFvar-for-handle>
  10. FreeLibrary <libhandle>
  11. LibraryProcedure <infvar>,<libhandle>,<entrypoint>[,<arg>]*
  12. RunProgram <var>,<diskname>,<libhandle>,<programfile>[,<arg>]*
  13. StartDetachedProcess <var>,<diskname>,<libhandle>,<programfile>[,<arg>]*
  14. InvokeApplet <libraryname>
  15. */
  16. #define NO_RETURN_VALUE (-1)
  17. #define HANDLER_ENTRY "RegHandler"
  18. typedef enum {
  19. PRESENT,
  20. NOT_PRESENT,
  21. NOT_PRESENT_IGNORE
  22. } PRESENCE;
  23. typedef BOOL (*PFNICMD)(DWORD, RGSZ, LPSTR*);
  24. /*
  25. * MakeSureDiskIsAvailable
  26. *
  27. * Given a fully qualified pathname, prompt the user to put the named
  28. * disk into the drive specified in the pathname. If the disk is not
  29. * removable, instead flash an error to let the user retry.
  30. *
  31. * Arguments:
  32. *
  33. * Diskname - name of disk to prompt for (literal string)
  34. * File - fully qualified filename of file to make present
  35. * fVital - whether non-presence of file is critical
  36. *
  37. * returns: PRESENT if File is now accessible
  38. * NOT_PRESENT if not (ie, user CANCELed at error popup)
  39. * NOT_PRESENT_IGNORE if user IGNOREd error
  40. *
  41. */
  42. PRESENCE MakeSureFileIsAvailable(SZ DiskName,SZ File,BOOL fVital)
  43. {
  44. UINT DriveType;
  45. EERC eerc;
  46. char disk[4];
  47. disk[0] = *File;
  48. disk[1] = ':';
  49. disk[2] = '\\';
  50. disk[3] = 0;
  51. DriveType = GetDriveType(disk);
  52. disk[2] = 0;
  53. while(!FFileFound(File)) {
  54. if((DriveType == DRIVE_REMOVABLE) || (DriveType == DRIVE_CDROM)) {
  55. if(!FPromptForDisk(hinstShell,DiskName,disk)) {
  56. return(NOT_PRESENT); // user canceled
  57. }
  58. } else if((eerc = EercErrorHandler(hwndFrame,grcOpenFileErr,fVital,File))
  59. != eercRetry)
  60. {
  61. return((eerc == eercIgnore)
  62. ? NOT_PRESENT_IGNORE
  63. : NOT_PRESENT);
  64. }
  65. }
  66. return(PRESENT);
  67. }
  68. /*
  69. * FLoadLibrary
  70. *
  71. * Load a fully-qualified library and place the handle in an INF var.
  72. *
  73. * Arguments:
  74. *
  75. * DiskName - name of disk to prompt for
  76. * File - fully qualified filename of dll to load
  77. * LibHandle - INF var that gets library's handle
  78. *
  79. * returns: TRUE/FALSE. If FALSE, user ABORTED from an error dialog.
  80. * If TRUE, library is loaded.
  81. */
  82. BOOL FLoadLibrary(SZ DiskName,SZ File,SZ INFVar)
  83. {
  84. HANDLE LibraryHandle;
  85. char LibraryHandleSTR[25];
  86. if(!DiskName || !File) {
  87. return(FALSE);
  88. }
  89. if(MakeSureFileIsAvailable(DiskName,File,TRUE) != PRESENT) {
  90. return(FALSE); // not possible to ignore
  91. }
  92. while((LibraryHandle = LoadLibrary(File)) == NULL)
  93. {
  94. switch(EercErrorHandler(hwndFrame,grcLibraryLoadErr,fTrue,File)) {
  95. case eercRetry:
  96. break;
  97. case eercAbort:
  98. return(FALSE);
  99. #if DBG
  100. case eercIgnore: // illegal because error is critical
  101. default: // bogus return value
  102. Assert(0);
  103. #endif
  104. }
  105. }
  106. LibraryHandleSTR[0] = '|';
  107. if (!LibraryHandle) {
  108. return(FALSE);
  109. }
  110. #if defined(_WIN64)
  111. _ui64toa((DWORD_PTR)LibraryHandle,LibraryHandleSTR+1,20);
  112. #else
  113. _ultoa((DWORD)LibraryHandle,LibraryHandleSTR+1,10);
  114. #endif
  115. if(INFVar) {
  116. while(!FAddSymbolValueToSymTab(INFVar,LibraryHandleSTR)) {
  117. if(!FHandleOOM(hwndFrame)) {
  118. FreeLibrary(LibraryHandle);
  119. return(FALSE);
  120. }
  121. }
  122. }
  123. return(TRUE);
  124. }
  125. /*
  126. * FFreeLibrary
  127. *
  128. * Free a library given its handle.
  129. *
  130. * Arguments:
  131. *
  132. * Hnadle - dle
  133. *
  134. * returns: TRUE
  135. *
  136. */
  137. BOOL FFreeLibrary(SZ Handle)
  138. {
  139. char buff1[100],buff2[100],buff3[500];
  140. HANDLE hMod;
  141. Assert(Handle);
  142. //
  143. // Prevent an INF from errantly unloading the interpreter!
  144. //
  145. hMod = LongToHandle(atol(Handle+1));
  146. if(hMod == MyDllModuleHandle) {
  147. return(TRUE);
  148. }
  149. if(!FreeLibrary(hMod)) {
  150. LoadString(hinstShell,IDS_SETUP_WARNING,buff1,sizeof(buff1)-1);
  151. LoadString(hinstShell,IDS_BAD_LIB_HANDLE,buff2,sizeof(buff2)-1);
  152. wsprintf(buff3,buff2,Handle+1);
  153. MessBoxSzSz(buff1,buff3);
  154. }
  155. return(TRUE);
  156. }
  157. /*
  158. * FLibraryProcedure
  159. *
  160. * Arguments: INFVar - variable to get string result of callout
  161. *
  162. * HandleVar - library's handle
  163. *
  164. * EntryPoint - name of routine in library to be called
  165. *
  166. * Args - argv to be passed to the routine. The vector must
  167. * be terminated with a NULL entry.
  168. *
  169. */
  170. BOOL APIENTRY FLibraryProcedure(SZ INFVar,SZ Handle,SZ EntryPoint,RGSZ Args)
  171. {
  172. DWORD cArgs;
  173. HANDLE LibraryHandle;
  174. PFNICMD Proc;
  175. LPSTR TextOut;
  176. BOOL rc = FALSE;
  177. EERC eerc;
  178. SZ szErrCtl ;
  179. LibraryHandle = LongToHandle(atol(Handle+1));
  180. while((Proc = (PFNICMD)GetProcAddress(LibraryHandle,EntryPoint)) == NULL) {
  181. if((eerc = EercErrorHandler(hwndFrame,grcBadLibEntry,FALSE,EntryPoint))
  182. == eercAbort)
  183. {
  184. return(FALSE);
  185. } else if(eerc == eercIgnore) {
  186. goto FLP;
  187. }
  188. Assert(eerc == eercRetry);
  189. }
  190. for(cArgs = 0; Args[cArgs]; cArgs++); // count arguments
  191. while(!(rc = Proc(cArgs,Args,&TextOut))) {
  192. // If the symbol "FLibraryErrCtl" is found and its value is non-zero,
  193. // the INF file will handle all error conditions.
  194. if ( (szErrCtl = SzFindSymbolValueInSymTab("FLibraryErrCtl"))
  195. && atoi(szErrCtl) > 0 )
  196. {
  197. rc = 1 ;
  198. break ;
  199. }
  200. if((eerc = EercErrorHandler(hwndFrame,grcExternal,FALSE,EntryPoint,TextOut)) == eercAbort) {
  201. return(FALSE);
  202. } else if(eerc == eercIgnore) {
  203. break;
  204. }
  205. Assert(eerc == eercRetry);
  206. }
  207. FLP:
  208. if((INFVar != NULL) && (*INFVar != '\0')) {
  209. FAddSymbolValueToSymTab(INFVar,rc ? TextOut : "ERROR");
  210. }
  211. return(TRUE);
  212. }
  213. /*
  214. * FRunProgram
  215. *
  216. * Arguments: INFVar - an INF variable which will get the rc of the
  217. * exec'ed program.
  218. *
  219. * DiskName - string used in prompting the user to insert
  220. * a disk
  221. *
  222. * ProgramFile - qualified name of program to be run
  223. *
  224. * Args - argv to be passed directly to spawn (so must
  225. * include argv[0] filled in).
  226. *
  227. */
  228. BOOL APIENTRY FRunProgram(SZ INFVar,
  229. SZ DiskName,
  230. SZ LibHand,
  231. SZ ProgramFile,
  232. RGSZ Args)
  233. {
  234. char Number[15];
  235. DWORD rc;
  236. HANDLE ProcID = NULL;
  237. EERC eerc;
  238. MSG msg;
  239. int iWaitState = P_NOWAIT;
  240. SZ szWaitState;
  241. switch(MakeSureFileIsAvailable(DiskName,ProgramFile,FALSE)) {
  242. case PRESENT:
  243. break;
  244. case NOT_PRESENT:
  245. return(fFalse);
  246. case NOT_PRESENT_IGNORE:
  247. goto FRP;
  248. #if DBG
  249. default:
  250. Assert(0); // illegal PRESENCE value
  251. #endif
  252. }
  253. if((LibHand != NULL) && (*LibHand != '\0')) {
  254. SetSupportLibHandle(LongToHandle(atol(LibHand+1))); // skip the leading |
  255. }
  256. WaitingOnChild = TRUE;
  257. if ( (szWaitState = SzFindSymbolValueInSymTab("FWaitForProcess"))
  258. && atoi(szWaitState) > 0 )
  259. {
  260. iWaitState = P_WAIT;
  261. rc=(DWORD)_spawnv(iWaitState,ProgramFile,Args);
  262. } else
  263. {
  264. while((ProcID=(HANDLE)_spawnv(iWaitState,ProgramFile,Args)) == (HANDLE)(-1)) {
  265. if((eerc = EercErrorHandler(hwndFrame,
  266. grcSpawn,
  267. FALSE,
  268. ProgramFile)
  269. ) == eercAbort
  270. )
  271. {
  272. WaitingOnChild = FALSE;
  273. return(FALSE);
  274. } else if(eerc == eercIgnore) {
  275. goto FRP;
  276. }
  277. Assert(eerc == eercRetry);
  278. }
  279. while(WaitForSingleObject(ProcID,350)) {
  280. FYield();
  281. }
  282. }
  283. //
  284. // Process any pending messages so the user can do stuff like move the
  285. // gauge around the screen if he wants to.
  286. //
  287. while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  288. DispatchMessage(&msg);
  289. }
  290. FRP:
  291. WaitingOnChild = FALSE;
  292. if((INFVar != NULL) && (*INFVar != '\0')) {
  293. FAddSymbolValueToSymTab(INFVar,
  294. ((szWaitState != NULL ) && (atoi(szWaitState)>0)) ? _itoa(rc,Number,10):
  295. (GetExitCodeProcess(ProcID,&rc) ? _itoa(rc,
  296. Number,
  297. 10
  298. )
  299. : "ERROR")
  300. );
  301. }
  302. CloseHandle(ProcID);
  303. SetForegroundWindow(hwndFrame); // reactivate ourselves
  304. return(fTrue);
  305. }
  306. /*
  307. * FStartDetachedProcess
  308. *
  309. * Arguments: INFVar - an INF variable which will get the rc of the
  310. * exec'ed program.
  311. *
  312. * DiskName - string used in prompting the user to insert
  313. * a disk
  314. *
  315. * ProgramFile - qualified name of program to be run
  316. *
  317. * Args - argv to be passed directly to spawn (so must
  318. * include argv[0] filled in).
  319. *
  320. */
  321. BOOL APIENTRY
  322. FStartDetachedProcess(
  323. SZ INFVar,
  324. SZ DiskName,
  325. SZ LibHand,
  326. SZ ProgramFile,
  327. RGSZ Args
  328. )
  329. {
  330. CHAR Number[15];
  331. CHAR App[MAX_PATH];
  332. DWORD rc;
  333. HANDLE ProcID = NULL;
  334. EERC eerc;
  335. BOOL Status = FALSE;
  336. STARTUPINFO si;
  337. PROCESS_INFORMATION pi;
  338. INT i;
  339. //
  340. // Make sure the file is available, prompt the user if necessary
  341. //
  342. switch(MakeSureFileIsAvailable(DiskName,ProgramFile,FALSE)) {
  343. case PRESENT:
  344. break;
  345. case NOT_PRESENT:
  346. return(fFalse);
  347. case NOT_PRESENT_IGNORE:
  348. goto FRP;
  349. #if DBG
  350. default:
  351. Assert(0); // illegal PRESENCE value
  352. #endif
  353. }
  354. if((LibHand != NULL) && (*LibHand != '\0')) {
  355. SetSupportLibHandle(LongToHandle(atol(LibHand+1))); // skip the leading |
  356. }
  357. //
  358. // Initialise Startup info
  359. //
  360. si.cb = sizeof(STARTUPINFO);
  361. si.lpReserved = NULL;
  362. si.lpDesktop = NULL;
  363. si.lpDesktop = NULL;
  364. si.lpTitle = NULL;
  365. si.dwX = si.dwY = si.dwXSize = si.dwYSize = si.dwFlags = 0L;
  366. si.wShowWindow = 0;
  367. si.lpReserved2 = NULL;
  368. si.cbReserved2 = 0;
  369. //
  370. // Create the app command line
  371. //
  372. *App = '\0';
  373. for(i = 0; Args[i]; i++){
  374. lstrcat( App, Args[i] );
  375. lstrcat( App, " " );
  376. }
  377. //
  378. // Use Create Process to create a detached process
  379. //
  380. while (!CreateProcess(
  381. (LPSTR)NULL, // lpApplicationName
  382. App, // lpCommandLine
  383. (LPSECURITY_ATTRIBUTES)NULL, // lpProcessAttributes
  384. (LPSECURITY_ATTRIBUTES)NULL, // lpThreadAttributes
  385. FALSE, // bInheritHandles
  386. DETACHED_PROCESS, // dwCreationFlags
  387. (LPVOID)NULL, // lpEnvironment
  388. (LPSTR)NULL, // lpCurrentDirectory
  389. (LPSTARTUPINFO)&si, // lpStartupInfo
  390. (LPPROCESS_INFORMATION)&pi // lpProcessInformation
  391. )) {
  392. if((eerc = EercErrorHandler(hwndFrame,grcSpawn,FALSE,ProgramFile)
  393. ) == eercAbort){
  394. return(FALSE);
  395. } else if(eerc == eercIgnore) {
  396. goto FRP;
  397. }
  398. Assert(eerc == eercRetry);
  399. }
  400. Status = TRUE;
  401. //
  402. // Since we are execing a detached process we don't care about when it
  403. // exits. To do proper book keeping, we should close the handles to
  404. // the process handle and thread handle
  405. //
  406. CloseHandle( pi.hThread );
  407. CloseHandle( pi.hProcess );
  408. FRP:
  409. if((INFVar != NULL) && (*INFVar != '\0')) {
  410. FAddSymbolValueToSymTab(
  411. INFVar,
  412. Status ? _itoa(0, Number, 10) : "ERROR"
  413. );
  414. }
  415. CloseHandle(ProcID);
  416. return(fTrue);
  417. }
  418. PRESENCE SendMessageToApplet(PROC Proc,HWND hwnd,DWORD msg,LONG p1,LONG p2,LONG rcDesired,SZ Libname)
  419. {
  420. #if 0
  421. LONG rcActual;
  422. rcActual = Proc(hwnd,msg,p1,p2);
  423. if((rcDesired == NO_RETURN_VALUE) || (rcActual == rcDesired)) {
  424. return(PRESENT);
  425. }
  426. while(Proc(hwnd,msg,p1,p2) != rcDesired) {
  427. switch(EercErrorHandler(hwndFrame, grcApplet,fFalse,Libname,NULL,NULL)) {
  428. case eercRetry:
  429. break;
  430. case eercIgnore:
  431. return(NOT_PRESENT_IGNORE);
  432. case eercAbort:
  433. return(NOT_PRESENT);
  434. #if DBG
  435. default:
  436. Assert(0); // illegal case
  437. #endif
  438. }
  439. }
  440. return(PRESENT);
  441. #else
  442. Unused(Proc);
  443. Unused(hwnd);
  444. Unused(msg);
  445. Unused(p1);
  446. Unused(p2);
  447. Unused(rcDesired);
  448. Unused(Libname);
  449. return(NOT_PRESENT);
  450. #endif
  451. }
  452. /*
  453. * FInvokeApplet
  454. *
  455. * Arguments: LibraryFile - qualified name of library to load
  456. *
  457. * Args - argv to be passed to the routine. The vector must
  458. * be terminated with a NULL entry.
  459. *
  460. */
  461. // BUGBUG -- also need some way to specify the sub-handler
  462. BOOL APIENTRY FInvokeApplet(SZ LibraryFile)
  463. {
  464. #if 0
  465. HANDLE LibraryHandle;
  466. PROC Proc;
  467. CFGINFO cfginfo;
  468. PRESENCE p;
  469. switch(FLoadLibrary(LibraryFile,HANDLER_ENTRY,&LibraryHandle,&Proc)) {
  470. case PRESENT:
  471. break;
  472. case NOT_PRESENT:
  473. return(fFalse); // user wants to exit setup
  474. case NOT_PRESENT_IGNORE:
  475. return(fTrue);
  476. #if DBG
  477. default:
  478. Assert(0); // illegal PRESENCE value
  479. #endif
  480. }
  481. if((p = SendMessageToApplet(Proc,hwndFrame,CFG_INIT,0,0,TRUE)) == PRESENT) {
  482. if((p = SendMessageToApplet(Proc,
  483. hwndFrame,
  484. CFG_INQUIRE,
  485. subhandler#,
  486. &cfginfo,
  487. TRUE,
  488. LibraryFile)) == PRESENT)
  489. {
  490. SendMessageToApplet(Proc,
  491. hwndFrame,
  492. CFG_DBLCLK,
  493. registry handle,
  494. cfginfo.lData,
  495. -1,
  496. LibraryFile);
  497. // it's activated -- now what?
  498. SendMessageToApplet(Proc,
  499. hwndFrame,
  500. CFG_STOP,
  501. subhandler#,
  502. cfginfo.lData,
  503. -1,
  504. LibraryFile);
  505. SendMessageToApplet(Proc,hwndFrame,CFG_EXIT,0,0,-1,LibraryFile);
  506. }
  507. }
  508. FreeLibrary(LibraryHandle);
  509. return(p != NOT_PRESENT);
  510. #else
  511. Unused(LibraryFile);
  512. MessBoxSzSz("Stub","InvokeApplet called");
  513. return(fTrue);
  514. #endif
  515. }