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.

871 lines
30 KiB

  1. // Created 07-Jan-1993 11:20am by Jeff Parsons
  2. #include "shellprv.h"
  3. #pragma hdrstop
  4. #include <setupapi.h>
  5. const CHAR szIpOpen []= "SetupOpenInfFileW";
  6. const CHAR szIpFindFirstLine []= "SetupFindFirstLineW";
  7. const CHAR szIpFindNextLine []= "SetupFindNextLine";
  8. const CHAR szIpGetStringField[]= "SetupGetStringFieldW";
  9. const CHAR szIpGetIntField []= "SetupGetIntField";
  10. const CHAR szIpClose []= "SetupCloseInfFile";
  11. const TCHAR szOne []= TEXT("1");
  12. //
  13. // WARNING: Do not change the format of this structure (BPSTR followed by
  14. // FARPROC) unless you also plan on the changing the code below that fills
  15. // the structure in. The sole purpose of this structure is and should
  16. // remain to obtain various exported procedure addresses from SETUPX.DLL!
  17. //
  18. typedef const CHAR *BPSTR;
  19. struct {
  20. BPSTR pszIpOpen;
  21. HINF (WINAPI *lpIpOpen)(LPCTSTR pszFileSpec, LPCTSTR InfClass, DWORD InfStyle, UINT *ErrorLine);
  22. BPSTR pszIpFindFirstLine;
  23. BOOL (WINAPI *lpIpFindFirstLine)(HINF hInf, LPCTSTR lpszSect, LPCTSTR lpszKey, PINFCONTEXT Context);
  24. BPSTR pszIpFindNextLine;
  25. BOOL (WINAPI *lpIpFindNextLine)(PINFCONTEXT ContextIn, PINFCONTEXT ContextOut);
  26. BPSTR pszIpGetStringField;
  27. BOOL (WINAPI *lpIpGetStringField)(PINFCONTEXT Context, DWORD FieldIndex, LPTSTR ReturnBuffer, DWORD ReturnBufferSize, DWORD * RequiredSize);
  28. BPSTR pszIpGetIntField;
  29. BOOL (WINAPI *lpIpGetIntField)(PINFCONTEXT Context, DWORD FieldIndex, INT * IntegerValue);
  30. BPSTR pszIpClose;
  31. VOID (WINAPI *lpIpClose)(HINF hInf);
  32. } sfnIp = {
  33. szIpOpen ,NULL,
  34. szIpFindFirstLine ,NULL,
  35. szIpFindNextLine ,NULL,
  36. szIpGetStringField,NULL,
  37. szIpGetIntField ,NULL,
  38. szIpClose ,NULL,
  39. };
  40. #define NUM_FUNCTIONS 6
  41. static UINT g_SXUseCount = 0;
  42. static HINSTANCE g_hSetupDLL = NULL;
  43. const TCHAR szRegKeyMSDOSApps[] = REGSTR_PATH_NEWDOSBOX;
  44. const TCHAR szParams[] = KEY_PARAMS;
  45. const TCHAR szBatchFile[] = KEY_BATCHFILE;
  46. const TCHAR szLowMem[] = KEY_LOWMEM;
  47. const TCHAR szEmsMem[] = KEY_EMSMEM;
  48. const TCHAR szXmsMem[] = KEY_XMSMEM;
  49. const TCHAR szDpmiMem[] = KEY_DPMIMEM;
  50. const TCHAR szEnable[] = KEY_ENABLE;
  51. const TCHAR szDisable[] = KEY_DISABLE;
  52. const TCHAR szWindowed[] = KEYVAL_WINDOWED;
  53. const TCHAR szBackground[] = KEYVAL_BACKGROUND;
  54. const TCHAR szExclusive[] = KEYVAL_EXCLUSIVE;
  55. const TCHAR szDetectIdle[] = KEYVAL_DETECTIDLE;
  56. const TCHAR szLowLocked[] = KEYVAL_LOWLOCKED;
  57. const TCHAR szEMSLocked[] = KEYVAL_EMSLOCKED;
  58. const TCHAR szXMSLocked[] = KEYVAL_XMSLOCKED;
  59. const TCHAR szUseHMA[] = KEYVAL_USEHMA;
  60. const TCHAR szEmulateROM[] = KEYVAL_EMULATEROM;
  61. const TCHAR szRetainVRAM[] = KEYVAL_RETAINVRAM;
  62. const TCHAR szFastPaste[] = KEYVAL_FASTPASTE;
  63. const TCHAR szALTTAB[] = KEYVAL_ALTTAB;
  64. const TCHAR szALTESC[] = KEYVAL_ALTESC;
  65. const TCHAR szCTRLESC[] = KEYVAL_CTRLESC;
  66. const TCHAR szPRTSCRN[] = KEYVAL_PRTSCRN;
  67. const TCHAR szALTPRTSCRN[] = KEYVAL_ALTPRTSCRN;
  68. const TCHAR szALTSPACE[] = KEYVAL_ALTSPACE;
  69. const TCHAR szALTENTER[] = KEYVAL_ALTENTER;
  70. const TCHAR szWinLie[] = KEYVAL_WINLIE;
  71. const TCHAR szGlobalMem[] = KEYVAL_GLOBALMEM;
  72. const TCHAR szRealMode[] = KEYVAL_REALMODE;
  73. const TCHAR szMouse[] = KEYVAL_MOUSE;
  74. const TCHAR szEMS[] = KEYVAL_EMS;
  75. const TCHAR szCDROM[] = KEYVAL_CDROM;
  76. const TCHAR szNetwork[] = KEYVAL_NETWORK;
  77. const TCHAR szDiskLock[] = KEYVAL_DISKLOCK;
  78. const TCHAR szPrivateCFG[] = KEYVAL_PRIVATECFG;
  79. const TCHAR szCloseOnExit[] = KEYVAL_CLOSEONEXIT;
  80. const TCHAR szAllowSSaver[] = KEYVAL_ALLOWSSAVER;
  81. const TCHAR szUniqueSettings[] = KEYVAL_UNIQUESETTINGS;
  82. const LPCTSTR apszKey[] = {
  83. szParams,
  84. szBatchFile,
  85. szLowMem,
  86. szEmsMem,
  87. szXmsMem,
  88. szDpmiMem,
  89. szEnable,
  90. szDisable,
  91. };
  92. const LPCTSTR apszKeyVal[] = {
  93. szWindowed, // abKeyValIDBits[0]
  94. szBackground, // abKeyValIDBits[1]
  95. szExclusive, // abKeyValIDBits[2]
  96. szDetectIdle, // abKeyValIDBits[3]
  97. szLowLocked, // abKeyValIDBits[4]
  98. szEMSLocked, // abKeyValIDBits[5]
  99. szXMSLocked, // abKeyValIDBits[6]
  100. szUseHMA, // abKeyValIDBits[7]
  101. szEmulateROM, // abKeyValIDBits[8]
  102. szRetainVRAM, // abKeyValIDBits[9]
  103. szFastPaste, // abKeyValIDBits[10]
  104. szALTTAB, // abKeyValIDBits[11]
  105. szALTESC, // abKeyValIDBits[12]
  106. szCTRLESC, // abKeyValIDBits[13]
  107. szPRTSCRN, // abKeyValIDBits[14]
  108. szALTPRTSCRN, // abKeyValIDBits[15]
  109. szALTSPACE, // abKeyValIDBits[16]
  110. szALTENTER, // abKeyValIDBits[17]
  111. szWinLie, // abKeyValIDBits[18]
  112. szGlobalMem, // abKeyValIDBits[19]
  113. szRealMode, // abKeyValIDBits[20]
  114. szMouse, // abRMKeyValIDBits[0]
  115. szEMS, // abRMKeyValIDBits[1]
  116. szCDROM, // abRMKeyValIDBits[2]
  117. szNetwork, // abRMKeyValIDBits[3]
  118. szDiskLock, // abRMKeyValIDBits[4]
  119. szPrivateCFG, // abRMKeyValIDBits[5]
  120. szCloseOnExit, // special case 0 (see "special case 0" below)
  121. szAllowSSaver, // special case 1 (see "special case 1" below)
  122. szUniqueSettings, // Never transferred to PIF - Used to populate registry
  123. };
  124. // Array of bit numbers that must be kept in sync with KEYVALIDs
  125. //
  126. // 0x80 means bit must be inverted
  127. // 0x40 means bit must be set in PfW386Flags2 instead of PfW386Flags
  128. const BYTE abKeyValIDBits[] = {
  129. BITNUM(fFullScreen) | 0x80,
  130. BITNUM(fBackground),
  131. BITNUM(fExclusive),
  132. BITNUM(fPollingDetect),
  133. BITNUM(fVMLocked),
  134. BITNUM(fEMSLocked),
  135. BITNUM(fXMSLocked),
  136. BITNUM(fNoHMA) | 0x80,
  137. BITNUM(fVidTxtEmulate) | 0x40,
  138. BITNUM(fVidRetainAllo) | 0x40,
  139. BITNUM(fINT16Paste),
  140. BITNUM(fALTTABdis) | 0x80,
  141. BITNUM(fALTESCdis) | 0x80,
  142. BITNUM(fCTRLESCdis) | 0x80,
  143. BITNUM(fPRTSCdis) | 0x80,
  144. BITNUM(fALTPRTSCdis) | 0x80,
  145. BITNUM(fALTSPACEdis) | 0x80,
  146. BITNUM(fALTENTERdis) | 0x80,
  147. BITNUM(fWinLie),
  148. BITNUM(fGlobalProtect),
  149. BITNUM(fRealMode),
  150. };
  151. const BYTE abRMKeyValIDBits[] = {
  152. BITNUM(RMOPT_MOUSE),
  153. BITNUM(RMOPT_EMS),
  154. BITNUM(RMOPT_CDROM),
  155. BITNUM(RMOPT_NETWORK),
  156. BITNUM(RMOPT_DISKLOCK),
  157. BITNUM(RMOPT_PRIVATECFG),
  158. BITNUM(RMOPT_VESA),
  159. };
  160. // FEATURE: other bits to be supported (maybe):
  161. // WIN_TOOLBAR,
  162. // WIN_SAVESETTINGS,
  163. // MSE_WINDOWENABLE | 0x80,
  164. // MSE_EXCLUSIVE,
  165. // TSK_NOWARNTERMINATE | 0x80,
  166. //
  167. // Load setupx.dll and get proc address for all entry points in table
  168. //
  169. BOOL InitSetupxDll(void)
  170. {
  171. BOOL fSuccess = TRUE; // Assume it works
  172. if (g_SXUseCount == 0) {
  173. //
  174. // Dynamically load SETUPX.DLL
  175. //
  176. UINT uOldMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  177. g_hSetupDLL = LoadLibrary(TEXT("SETUPAPI.DLL"));
  178. SetErrorMode(uOldMode);
  179. fSuccess = (g_hSetupDLL != NULL);
  180. if (fSuccess)
  181. {
  182. int i;
  183. BPSTR *ppsz;
  184. FARPROC *plpfn;
  185. ppsz = (BPSTR *)&sfnIp;
  186. for (i=0; i<NUM_FUNCTIONS; i++)
  187. {
  188. plpfn = (FARPROC *)(ppsz+1);
  189. *plpfn = GetProcAddress(g_hSetupDLL, *ppsz);
  190. if (*plpfn == NULL)
  191. {
  192. FreeLibrary(g_hSetupDLL);
  193. g_hSetupDLL = NULL;
  194. fSuccess = FALSE;
  195. break;
  196. }
  197. ppsz = (BPSTR *)(plpfn+1);
  198. }
  199. }
  200. }
  201. if (fSuccess) {
  202. g_SXUseCount++;
  203. }
  204. return(fSuccess);
  205. }
  206. //
  207. // When the last user of setupx.dll calls this function, the library is freed.
  208. //
  209. void FreeSetupxDll(void)
  210. {
  211. g_SXUseCount--;
  212. if (g_SXUseCount == 0) {
  213. FreeLibrary(g_hSetupDLL);
  214. g_hSetupDLL = NULL;
  215. }
  216. }
  217. void InitWorkDir(PPROPLINK ppl, LPPROPPRG lpPrg, LPPROPNT40 lpnt40)
  218. {
  219. int i;
  220. if (lpnt40)
  221. {
  222. lstrcpyn((LPTSTR)lpnt40->awchWorkDir,
  223. ppl->szPathName,
  224. min(ARRAYSIZE(lpnt40->awchWorkDir),ppl->iFileName+1));
  225. // Working directories like C:\ are ok, but C:\FOO\ are not,
  226. // so remove trailing '\' in that case
  227. i = lstrlen((LPTSTR)lpnt40->awchWorkDir)-1;
  228. if (i > 2 && lpnt40->awchWorkDir[i] == TEXT('\\'))
  229. lpnt40->awchWorkDir[i] = TEXT('\0');
  230. WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchWorkDir, -1, lpPrg->achWorkDir, ARRAYSIZE(lpPrg->achWorkDir), NULL, NULL );
  231. }
  232. else
  233. {
  234. WideCharToMultiByte( CP_ACP, 0,
  235. ppl->szPathName,
  236. min(ARRAYSIZE(lpPrg->achWorkDir),ppl->iFileName+1),
  237. (LPSTR)lpPrg->achWorkDir,
  238. ARRAYSIZE(lpPrg->achWorkDir),
  239. NULL,
  240. NULL
  241. );
  242. // Working directories like C:\ are ok, but C:\FOO\ are not,
  243. // so remove trailing '\' in that case
  244. i = lstrlenA(lpPrg->achWorkDir)-1;
  245. if (i > 2 && lpPrg->achWorkDir[i] == '\\')
  246. lpPrg->achWorkDir[i] = '\0';
  247. }
  248. }
  249. BOOL FAR GetAppsInfData(PPROPLINK ppl, LPPROPPRG lpPrg, LPPROPNT40 lpnt40, HINF hInf, LPCTSTR lpszApp, BOOL fNotAmbiguous, int flOpt)
  250. {
  251. HINF hinfApps;
  252. int id, i;
  253. TCHAR szTmp[MAX_PATH];
  254. TCHAR szPIFSection[MAX_KEY_SIZE];
  255. BOOL fSuccess = FALSE;
  256. INFCONTEXT InfContext;
  257. DWORD dwSize;
  258. FunctionName(GetAppsInfData);
  259. //
  260. // Although not strictly part of INF processing, it's most
  261. // convenient here to search for any ICO file that might exist
  262. // in the same directory as the app, and select it for our default icon.
  263. //
  264. lstrcpyn(szTmp, ppl->szPathName, ppl->iFileExt+1);
  265. lstrcpy(szTmp + ppl->iFileExt, TEXT(".ICO"));
  266. if ((int)GetFileAttributes(szTmp) != -1) {
  267. lstrcpyn((LPTSTR)lpnt40->awchIconFile, szTmp, ARRAYSIZE(lpnt40->awchIconFile));
  268. WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchIconFile, -1, lpPrg->achIconFile, ARRAYSIZE(lpPrg->achIconFile), NULL, NULL );
  269. lpPrg->wIconIndex = 0;
  270. PifMgr_SetProperties(ppl, MAKELP(0,GROUP_PRG),
  271. lpPrg, SIZEOF(*lpPrg), SETPROPS_CACHE);
  272. PifMgr_SetProperties(ppl, MAKELP(0,GROUP_NT40),
  273. lpnt40, SIZEOF(*lpnt40), SETPROPS_CACHE);
  274. }
  275. //
  276. // Dynamically load SETUPX.DLL
  277. //
  278. if (!InitSetupxDll())
  279. goto DllLoadFalied;
  280. if (hInf)
  281. hinfApps = hInf;
  282. else
  283. hinfApps = (*sfnIp.lpIpOpen)(LoadStringSafe(NULL,
  284. IDS_APPSINF,
  285. szTmp,
  286. ARRAYSIZE(szTmp)),
  287. 0, INF_STYLE_WIN4, NULL );
  288. if (hinfApps==INVALID_HANDLE_VALUE) {
  289. id = IDS_CANTOPENAPPSINF;
  290. if (GetLastError()==ERROR_FILE_NOT_FOUND)
  291. id = IDS_NOAPPSINF;
  292. Warning((HWND)ppl, (WORD)id, MB_ICONEXCLAMATION | MB_OK | MB_NOFOCUS);
  293. goto CloseDLL;
  294. }
  295. // OK, now we have APPS.INF open, so let's bounce around the [pif95]
  296. // section and try to find the app of interest.
  297. if (!(*sfnIp.lpIpFindFirstLine)(hinfApps, TEXT("pif95"), NULL, &InfContext)) {
  298. Warning((HWND)ppl, IDS_APPSINFERROR, MB_ICONEXCLAMATION | MB_OK | MB_NOFOCUS);
  299. goto CloseInf;
  300. }
  301. // OK, we've found the [pif95] section, so let's go to it
  302. do {
  303. if (!(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_FILENAME, szTmp, ARRAYSIZE(szTmp), &dwSize))
  304. continue;
  305. // We need to read the rest of the fields now, before we do any
  306. // more processing, because otherwise we lose our place in the file
  307. if (lstrcmpi(szTmp, ppl->szPathName+ppl->iFileName) == 0) {
  308. // See if Other File was specified, and then make sure it
  309. // exists. If it doesn't, then we need to continue the search.
  310. // Initialize szTmp with only the path portion of the app's
  311. // fully-qualified name. Giving lstrcpyn a length of iFileName+1
  312. // insures that szTmp[ppl->iFileName] will be NULL.
  313. lstrcpyn(szTmp, ppl->szPathName, ppl->iFileName+1);
  314. (*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_OTHERFILE,
  315. &szTmp[ppl->iFileName], ARRAYSIZE(lpPrg->achOtherFile), &dwSize);
  316. // If szTmp[ppl->iFileName] is no longer NULL, then
  317. // GetStringField filled it in. See if the file exists.
  318. if (szTmp[ppl->iFileName]) {
  319. if ((int)GetFileAttributes(szTmp) == -1)
  320. continue; // Other File didn't exist, continue search
  321. }
  322. // If the PIF data we have is ambiguous, and it has already
  323. // been initialized with data from this APPS.INF entry, then just
  324. // leave the PIF data alone and LEAVE.
  325. if (lpPrg->flPrgInit & PRGINIT_AMBIGUOUSPIF) {
  326. if (lstrcmpi((LPWSTR)lpnt40->awchOtherFile, szTmp+ppl->iFileName) == 0) {
  327. if (!szTmp[ppl->iFileName]) {
  328. // The comparison was inconclusive; both filenames
  329. // are blank. See if the filename contained in
  330. // lpPrg->achCmdLine matches lpszApp; if not, again
  331. // we should fail the search.
  332. //
  333. // It's ok to whack lpPrg->achCmdLine with a null;
  334. // OpenProperties (our only caller) doesn't depend on
  335. // that data in lpPrg.
  336. lpnt40->awchCmdLine[lstrskipfnameA(lpPrg->achCmdLine)] = L'\0';
  337. if (lstrcmpi((LPWSTR)lpnt40->awchCmdLine, lpszApp) != 0)
  338. goto CloseInf; // unsuccessful search
  339. }
  340. fSuccess++; // successful search
  341. }
  342. // Otherwise, this APPS.INF entry isn't a match, implying
  343. // some of the PIF's settings don't really apply. We need
  344. // to fail this search, get back to OpenProperties, look ONLY
  345. // for _DEFAULT.PIF, and let it try to call GetAppsInfData
  346. // one more time.
  347. goto CloseInf;
  348. }
  349. // Otherwise, update Other File. THIS is the APPS.INF entry
  350. // we're going to use!
  351. lstrcpyn((LPWSTR)lpnt40->awchOtherFile, szTmp + ppl->iFileName, ARRAYSIZE(lpnt40->awchOtherFile));
  352. WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchOtherFile, -1, lpPrg->achOtherFile, ARRAYSIZE( lpPrg->achOtherFile ), NULL, NULL );
  353. (*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_TITLE, (LPWSTR)lpnt40->awchTitle, ARRAYSIZE(lpnt40->awchTitle), &dwSize);
  354. WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchTitle, -1, lpPrg->achTitle, ARRAYSIZE( lpPrg->achTitle ), NULL, NULL );
  355. lstrcpyn((LPWSTR)lpnt40->awchCmdLine, lpszApp, ARRAYSIZE(lpnt40->awchCmdLine));
  356. WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchCmdLine, -1, lpPrg->achCmdLine, ARRAYSIZE( lpPrg->achCmdLine ), NULL, NULL );
  357. i = 0;
  358. (*sfnIp.lpIpGetIntField)(&InfContext, APPSINF_NOWORKDIR, &i);
  359. // Only set the working directory if "NoWorkDir" in the INF
  360. // is FALSE and no working directory was supplied by the caller.
  361. if (i == 0 && !lpnt40->awchWorkDir[0]) {
  362. // No hard-coded working directory, so let's provide one
  363. InitWorkDir(ppl, lpPrg, lpnt40);
  364. }
  365. szTmp[0] = 0;
  366. sfnIp.lpIpGetStringField(&InfContext, APPSINF_ICONFILE, szTmp, ARRAYSIZE(szTmp), &dwSize);
  367. if (!szTmp[0])
  368. lstrcpy(szTmp, TEXT("SHELL32.DLL"));
  369. i = 0;
  370. sfnIp.lpIpGetIntField(&InfContext, APPSINF_ICONINDEX, &i);
  371. // Update the icon info now, if it's valid
  372. if (i != 0) {
  373. lstrcpy((LPWSTR)lpnt40->awchIconFile, szTmp);
  374. WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchIconFile, -1, lpPrg->achIconFile, ARRAYSIZE( lpPrg->achIconFile ), NULL, NULL );
  375. lpPrg->wIconIndex = (WORD) i;
  376. }
  377. (*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_SECTIONID,
  378. szPIFSection, ARRAYSIZE(szPIFSection), &dwSize);
  379. szTmp[0] = TEXT('\0');
  380. (*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_NOPIF,
  381. szTmp, ARRAYSIZE(szTmp), &dwSize);
  382. // This code used to set INHBITPIF if the app was NOT on a
  383. // fixed disk, knowing that we would otherwise try to create
  384. // a PIF in the PIF directory instead of the app's directory;
  385. // in other words, NOPIF really meant "no PIF in the PIF
  386. // directory please, because this app is ambiguously named".
  387. // Now, we want to always allow PIF creation, so the user
  388. // always has a place to save properties for an app. But we
  389. // also need to propagate the old NOPIF flag to AMBIGUOUSPIF,
  390. // so that we'll always check to see if the PIF should be
  391. // regenerated (based on the presence of a NEW Other File).
  392. lpPrg->flPrgInit &= ~PRGINIT_AMBIGUOUSPIF;
  393. if (!fNotAmbiguous && szTmp[0] == TEXT('1'))
  394. lpPrg->flPrgInit |= PRGINIT_AMBIGUOUSPIF;
  395. if (flOpt & OPENPROPS_FORCEREALMODE)
  396. lpPrg->flPrgInit |= PRGINIT_REALMODE;
  397. // Time to dirty those properties!
  398. PifMgr_SetProperties(ppl, MAKELP(0,GROUP_PRG),
  399. lpPrg, SIZEOF(*lpPrg), SETPROPS_CACHE);
  400. PifMgr_SetProperties(ppl, MAKELP(0,GROUP_NT40),
  401. lpnt40, SIZEOF(*lpnt40), SETPROPS_CACHE);
  402. GetAppsInfSectionData(&InfContext, APPSINF_DEFAULT_SECTION, ppl);
  403. if (*szPIFSection)
  404. GetAppsInfSectionData(&InfContext, szPIFSection, ppl);
  405. // Make a note that we found INF settings (appwiz cares)
  406. ppl->flProp |= PROP_INFSETTINGS;
  407. // GetAppsInfSectionData affects program props, so get fresh copy
  408. PifMgr_GetProperties(ppl, MAKELP(0,GROUP_PRG),
  409. lpPrg, SIZEOF(*lpPrg), GETPROPS_NONE);
  410. // Now call appwiz in "silent configuration mode", to create the
  411. // per-app config and autoexec images, if app runs in real mode;
  412. // BUT don't do this if the caller (NOT the INF) specified no PIF,
  413. // to avoid unwanted dialog boxes popping up from appwiz. Yes, I'm
  414. // telling appwiz to be quiet, but sometimes he just can't contain
  415. // himself (ie, silent configuration may not be possible given the
  416. // the real-mode configuration required).
  417. if (!(ppl->flProp & PROP_INHIBITPIF)) {
  418. if (lpPrg->flPrgInit & PRGINIT_REALMODE)
  419. AppWizard(NULL, ppl, WIZACTION_SILENTCONFIGPROP);
  420. }
  421. FlushPIFData(ppl, FALSE);
  422. fSuccess++; // successful search
  423. goto CloseInf;
  424. }
  425. } while ((*sfnIp.lpIpFindNextLine)(&InfContext, &InfContext));
  426. CloseInf:
  427. if (!hInf)
  428. (*sfnIp.lpIpClose)(hinfApps);
  429. CloseDLL:
  430. FreeSetupxDll();
  431. DllLoadFalied:
  432. return fSuccess;
  433. }
  434. void GetAppsInfSectionData(PINFCONTEXT pInfContext, LPCTSTR lpszSection, PPROPLINK ppl)
  435. {
  436. int i, j, idKey;
  437. LPSTDPIF lpstd;
  438. LPW386PIF30 lp386;
  439. LPWENHPIF40 lpenh;
  440. TCHAR szVal[MAX_KEYVAL_SIZE];
  441. TCHAR szVal2[MAX_KEYVAL_SIZE];
  442. FunctionName(GetAppsInfSectionData);
  443. if (!(*sfnIp.lpIpFindFirstLine)(pInfContext, lpszSection, NULL, NULL))
  444. return;
  445. ppl->cLocks++;
  446. lpstd = (LPSTDPIF)ppl->lpPIFData;
  447. // lp386 may or may not exist, but we'll create if not
  448. lp386 = GetGroupData(ppl, szW386HDRSIG30, NULL, NULL);
  449. if (!lp386) {
  450. if (AddGroupData(ppl, szW386HDRSIG30, NULL, SIZEOF(W386PIF30))) {
  451. lp386 = GetGroupData(ppl, szW386HDRSIG30, NULL, NULL);
  452. if (!lp386)
  453. goto UnlockPIF;
  454. }
  455. }
  456. // lpenh may or may not exist, but we'll create if not
  457. lpenh = GetGroupData(ppl, szWENHHDRSIG40, NULL, NULL);
  458. if (!lpenh) {
  459. if (AddGroupData(ppl, szWENHHDRSIG40, NULL, SIZEOF(WENHPIF40))) {
  460. lpenh = GetGroupData(ppl, szWENHHDRSIG40, NULL, NULL);
  461. if (!lpenh)
  462. goto UnlockPIF;
  463. }
  464. }
  465. do {
  466. BYTE bInvert;
  467. DWORD dwSize;
  468. idKey = GetKeyID(pInfContext);
  469. if (!(*sfnIp.lpIpGetStringField)(pInfContext, APPSINF_KEYVAL, szVal, ARRAYSIZE(szVal), &dwSize))
  470. continue;
  471. szVal2[0] = TEXT('\0');
  472. if (idKey >= KEYID_LOWMEM && idKey <= KEYID_DPMIMEM)
  473. (*sfnIp.lpIpGetStringField)(pInfContext, APPSINF_KEYVAL2, szVal2, ARRAYSIZE(szVal2), &dwSize);
  474. bInvert = 0;
  475. switch (idKey)
  476. {
  477. case KEYID_UNKNOWN:
  478. ASSERTFAIL();
  479. break;
  480. case KEYID_NONE:
  481. break;
  482. case KEYID_PARAMS:
  483. {
  484. WCHAR szTmp[ ARRAYSIZE(lp386->PfW386params) ];
  485. MultiByteToWideChar( CP_ACP, 0, (LPSTR)lp386->PfW386params, -1, szTmp, ARRAYSIZE(szTmp) );
  486. (*sfnIp.lpIpGetStringField)(pInfContext, APPSINF_KEYVAL, szTmp, SIZEOF(lp386->PfW386params), &dwSize);
  487. }
  488. break;
  489. case KEYID_BATCHFILE:
  490. break;
  491. case KEYID_LOWMEM:
  492. if (!lstrcmpi(szVal, g_szAuto))
  493. lp386->PfW386minmem = 0xFFFF;
  494. else
  495. lp386->PfW386minmem = (WORD) StrToInt(szVal);
  496. if (!szVal2[0])
  497. lp386->PfW386maxmem = 0xFFFF;
  498. else
  499. lp386->PfW386maxmem = (WORD) StrToInt(szVal2);
  500. break;
  501. case KEYID_EMSMEM:
  502. if (!lstrcmpi(szVal, g_szNone)) {
  503. lp386->PfMaxEMMK = lp386->PfMinEMMK = 0;
  504. }
  505. if (!lstrcmpi(szVal, g_szAuto)) {
  506. lp386->PfMinEMMK = 0;
  507. lp386->PfMaxEMMK = 0xFFFF;
  508. }
  509. else
  510. lp386->PfMaxEMMK = lp386->PfMinEMMK = (WORD) StrToInt(szVal);
  511. if (szVal2[0])
  512. lp386->PfMaxEMMK = (WORD) StrToInt(szVal2);
  513. break;
  514. case KEYID_XMSMEM:
  515. if (!lstrcmpi(szVal, g_szNone)) {
  516. lp386->PfMaxXmsK = lp386->PfMinXmsK = 0;
  517. }
  518. if (!lstrcmpi(szVal, g_szAuto)) {
  519. lp386->PfMinXmsK = 0;
  520. lp386->PfMaxXmsK = 0xFFFF;
  521. }
  522. else
  523. lp386->PfMaxXmsK = lp386->PfMinXmsK = (WORD) StrToInt(szVal);
  524. if (szVal2[0])
  525. lp386->PfMaxXmsK = (WORD) StrToInt(szVal2);
  526. break;
  527. case KEYID_DPMIMEM:
  528. if (!lstrcmpi(szVal, g_szAuto))
  529. lpenh->envProp.wMaxDPMI = 0;
  530. else
  531. lpenh->envProp.wMaxDPMI = (WORD) StrToInt(szVal);
  532. break;
  533. case KEYID_DISABLE:
  534. bInvert = 0x80;
  535. // fall into KEYID_ENABLE...
  536. case KEYID_ENABLE:
  537. for (i=1; 0 != (j = GetKeyValID(pInfContext, i)); i++)
  538. {
  539. int s;
  540. BYTE b;
  541. if (j == KEYVAL_ID_UNKNOWN) {
  542. ASSERTFAIL();
  543. continue;
  544. }
  545. if (j == KEYVAL_ID_UNIQUESETTINGS) {
  546. continue;
  547. }
  548. j--;
  549. if (j < ARRAYSIZE(abKeyValIDBits)) {
  550. b = abKeyValIDBits[j];
  551. s = b & 0x3F;
  552. b ^= bInvert;
  553. if (!(b & 0x80)) {
  554. if (!(b & 0x40)) {
  555. lp386->PfW386Flags |= 1L << s;
  556. }
  557. else
  558. lp386->PfW386Flags2 |= 1L << s;
  559. }
  560. else {
  561. if (!(b & 0x40))
  562. lp386->PfW386Flags &= ~(1L << s);
  563. else
  564. lp386->PfW386Flags2 &= ~(1L << s);
  565. }
  566. }
  567. else {
  568. j -= ARRAYSIZE(abKeyValIDBits);
  569. if (j < ARRAYSIZE(abRMKeyValIDBits)) {
  570. b = abRMKeyValIDBits[j];
  571. s = b & 0x3F;
  572. b ^= bInvert;
  573. if (!(b & 0x80))
  574. lpenh->dwRealModeFlagsProp |= 1L << s;
  575. else
  576. lpenh->dwRealModeFlagsProp &= ~(1L << s);
  577. }
  578. else {
  579. j -= ARRAYSIZE(abRMKeyValIDBits);
  580. switch(j) {
  581. case 0: // special case 0
  582. if (!bInvert)
  583. lpstd->MSflags |= EXITMASK;
  584. else
  585. lpstd->MSflags &= ~EXITMASK;
  586. break;
  587. case 1: // special case 1
  588. if (bInvert)
  589. lpenh->tskProp.flTsk |= TSK_NOSCREENSAVER;
  590. else
  591. lpenh->tskProp.flTsk &= ~TSK_NOSCREENSAVER;
  592. break;
  593. default:
  594. ASSERTFAIL();
  595. break;
  596. }
  597. }
  598. }
  599. }
  600. break;
  601. }
  602. } while ((*sfnIp.lpIpFindNextLine)(pInfContext, pInfContext));
  603. UnlockPIF:
  604. ppl->cLocks--;
  605. }
  606. int GetKeyID(PINFCONTEXT pInfContext)
  607. {
  608. int i;
  609. TCHAR szCurKey[MAX_KEY_SIZE];
  610. DWORD dwSize;
  611. FunctionName(GetKeyID);
  612. if ((*sfnIp.lpIpGetStringField)(pInfContext, APPSINF_KEY, szCurKey, ARRAYSIZE(szCurKey), &dwSize)) {
  613. for (i=0; i<ARRAYSIZE(apszKey); i++) {
  614. if (!lstrcmpi(szCurKey, apszKey[i]))
  615. return i+1;
  616. }
  617. return KEYID_UNKNOWN;
  618. }
  619. return KEYID_NONE;
  620. }
  621. int GetKeyValID(PINFCONTEXT pInfContext, int i)
  622. {
  623. TCHAR szCurKeyVal[MAX_KEYVAL_SIZE];
  624. DWORD dwSize;
  625. FunctionName(GetKeyValID);
  626. if ((*sfnIp.lpIpGetStringField)(pInfContext, i, szCurKeyVal, ARRAYSIZE(szCurKeyVal), &dwSize)) {
  627. for (i=0; i<ARRAYSIZE(apszKeyVal); i++) {
  628. if (!lstrcmpi(szCurKeyVal, apszKeyVal[i]))
  629. return i+1;
  630. }
  631. return KEYVAL_ID_UNKNOWN;
  632. }
  633. return KEYVAL_ID_NONE;
  634. }
  635. DWORD GetSettingsFlags(PINFCONTEXT pInfContext, LPCTSTR lpszSection)
  636. {
  637. return(0);
  638. }
  639. BOOL Initialize1AppReg(HWND hwndParent)
  640. {
  641. BOOL fSuccess = FALSE; // Assume failure
  642. TCHAR szTmp[MAX_PATH];
  643. HINF hinfApps;
  644. HKEY hk1App;
  645. INFCONTEXT InfContext;
  646. if (!InitSetupxDll()) {
  647. goto DllLoadFailed;
  648. }
  649. hinfApps = (*sfnIp.lpIpOpen)(LoadStringSafe(NULL,
  650. IDS_APPSINF,
  651. szTmp,
  652. ARRAYSIZE(szTmp)),
  653. 0, INF_STYLE_WIN4, NULL );
  654. if (hinfApps==INVALID_HANDLE_VALUE) {
  655. int id = IDS_CANTOPENAPPSINF;
  656. if (GetLastError()==ERROR_FILE_NOT_FOUND)
  657. id = IDS_NOAPPSINF;
  658. Warning(hwndParent, (WORD)id, MB_ICONEXCLAMATION | MB_OK | MB_NOFOCUS);
  659. goto CloseDLL;
  660. }
  661. // OK, now we have APPS.INF open, so let's find [PIF95]
  662. if (!(*sfnIp.lpIpFindFirstLine)(hinfApps, TEXT("pif95"), NULL, &InfContext)) {
  663. Warning(hwndParent, IDS_APPSINFERROR, MB_ICONEXCLAMATION | MB_OK | MB_NOFOCUS);
  664. goto CloseInf;
  665. }
  666. // OK, we've found the [pif95] section, so now we'll create the reg branch
  667. //
  668. // Always start with a clean slate!
  669. //
  670. RegDeleteKey(HKEY_LOCAL_MACHINE, szRegKeyMSDOSApps);
  671. if (RegCreateKey(HKEY_LOCAL_MACHINE, szRegKeyMSDOSApps, &hk1App) !=
  672. ERROR_SUCCESS) {
  673. goto CloseInf;
  674. }
  675. do {
  676. DWORD dwSettings;
  677. DWORD dwSize;
  678. TCHAR szSectionName[MAX_KEY_SIZE];
  679. if (!(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_FILENAME,
  680. szTmp, ARRAYSIZE(szTmp), &dwSize)) {
  681. continue;
  682. }
  683. (*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_SECTIONID,
  684. szSectionName, ARRAYSIZE(szSectionName), &dwSize);
  685. dwSettings = GetSettingsFlags(&InfContext, szSectionName);
  686. if (dwSettings) {
  687. HKEY hkThisApp;
  688. if (RegCreateKey(hk1App, szTmp, &hkThisApp) == ERROR_SUCCESS) {
  689. (*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_OTHERFILE,
  690. szTmp, ARRAYSIZE(szTmp), &dwSize);
  691. if (szTmp[0] == 0) {
  692. (*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_FILENAME,
  693. szTmp, ARRAYSIZE(szTmp), &dwSize);
  694. }
  695. RegSetValueEx(hkThisApp, szTmp, 0, REG_BINARY, (LPSTR)&dwSettings, sizeof(dwSettings));
  696. RegCloseKey(hkThisApp);
  697. }
  698. }
  699. } while ((*sfnIp.lpIpFindNextLine)(&InfContext, &InfContext));
  700. fSuccess = TRUE;
  701. RegCloseKey(hk1App);
  702. CloseInf:
  703. (*sfnIp.lpIpClose)(hinfApps);
  704. CloseDLL:
  705. FreeSetupxDll();
  706. DllLoadFailed:
  707. return(fSuccess);
  708. }
  709. //
  710. // A RUNDLL entry point that is called at boot time to initialize the registry.
  711. //
  712. void WINAPI InitPIFRegEntries(HWND hwnd, HINSTANCE hAppInstance, LPSTR lpszCmdLine, int nCmdShow)
  713. {
  714. Initialize1AppReg(hwnd);
  715. }