Leaked source code of windows server 2003
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.

2728 lines
96 KiB

  1. /*
  2. * Microsoft Confidential
  3. * Copyright (C) Microsoft Corporation 1991
  4. * All Rights Reserved.
  5. *
  6. *
  7. * PIFMGR.C
  8. * Main module for PIFMGR.DLL
  9. *
  10. * History:
  11. * Created 31-Jul-1992 3:30pm by Jeff Parsons
  12. *
  13. * Exported Program Information File (PIF) Manager services:
  14. *
  15. * PifMgr_OpenProperties()
  16. * Give it the name of an DOS application (com, exe, or bat),
  17. * and it will open the PIF associated with that application
  18. * and return a "handle" to the app's "properties". Use this
  19. * handle when calling any of the other "properties" services (ie,
  20. * Get, Set, and Close).
  21. *
  22. * If no PIF exists, it will still allocate a PIF data block
  23. * in memory and initialize it, either with data from _DEFAULT.PIF
  24. * or its internal defaults. It will also construct the PIF name
  25. * it was looking for but couldn')t find and save that in its internal
  26. * PIF data structure, so that if PifMgr_SetProperties is ever called, the
  27. * data can be saved to disk.
  28. *
  29. * PifMgr_GetProperties()
  30. * Returns the specified block of data from the associated PIF.
  31. * If it is a "named" block, it must be the name of a linked
  32. * extension inside the PIF, which can be any predefined name
  33. * (eg, "WINDOWS 386 3.0") or the name of your own block. You can
  34. * create your own named data blocks using the PifMgr_SetProperties()
  35. * service. "Named" data can also be thought of as "raw" data,
  36. * because it is returned to the caller as-is -- without translation.
  37. *
  38. * The size of a named block can be determined by calling
  39. * PifMgr_GetProperties with a size of zero; no data is copied, but the size
  40. * of the requested block is returned (0 if not found).
  41. *
  42. * All named blocks can be enumerated by passing NULL for the name,
  43. * a pointer to a 16-byte buffer for the requested block name, and a
  44. * 0-based block index in the size parameter. The size returned
  45. * is the size of the block (0 if none).
  46. *
  47. * If an unnamed property block is requested (ie, the selector of
  48. * the name parameter is NULL, and the offset is a property group
  49. * ordinal), then the associated structure is returned. For example,
  50. * PifMgr_GetProperties(GROUP_TSK) returns a predefined structure (see
  51. * PROPTSK in PIF.H) containing all the tasking-related information,
  52. * in a format that is PIF-independent. This is a valuable service,
  53. * because it relieves callers from having to cope with PIFs
  54. * containing a wide variety of sections (known as PIF extensions),
  55. * only one of which is required. Think of this as "cooked" data.
  56. *
  57. * A third variation is raw read/write of the entire PIF data block,
  58. * if lpszGroup is NULL. This must be used with extreme caution, and
  59. * will only be allowed if the properties were opened with the
  60. * OPENPROPS_RAWIO flag specified.
  61. *
  62. * PifMgr_SetProperties()
  63. * This is pretty much the opposite of PifMgr_GetProperties, except that it
  64. * also takes a flags parameter that can specify that the changes
  65. * be made immediately, or deferred to PifMgr_CloseProperties.
  66. *
  67. * PifMgr_CloseProperties()
  68. * Flushes any dirty PIF data in memory, and frees the local heap
  69. * storage.
  70. *
  71. */
  72. #include "shellprv.h"
  73. #pragma hdrstop
  74. #ifdef _X86_
  75. /* Global R/W DLL data
  76. */
  77. PPROPLINK g_pplHead; // pointer to first prop entry
  78. HANDLE g_offHighestPropLink; // highest offset of a prop thus far recorded
  79. TCHAR g_szNone[16]; // initialized by LibMainP,
  80. TCHAR g_szAuto[16]; // and 16 chars to allow for localization
  81. char g_szMSDOSSTSFile[] = "C:\\MSDOSSYS.STS";
  82. TCHAR g_szConfigFile[] = TEXT("C:") CONFIGFILE;
  83. TCHAR g_szAutoexecFile[] = TEXT("C:") AUTOEXECFILE;
  84. TCHAR g_szMConfigFile[] = TEXT("C:") MCONFIGFILE;
  85. TCHAR g_szMAutoexecFile[] = TEXT("C:") MAUTOEXECFILE;
  86. TCHAR g_szWConfigFile[] = TEXT("C:") WCONFIGFILE;
  87. TCHAR g_szWAutoexecFile[] = TEXT("C:") WAUTOEXECFILE;
  88. #ifdef DBCS
  89. char ImeBatchFile[] = "DOSIME\0";
  90. #endif
  91. #define NT_CONFIG_FILE "%SystemRoot%\\SYSTEM32\\CONFIG.NT"
  92. #define NT_AUTOEXEC_FILE "%SystemRoot%\\SYSTEM32\\AUTOEXEC.NT"
  93. #define LPPH_OFF(off) ((LPBYTE)lpph + off)
  94. #define LPPIF_FIELDOFF(off) ((LPBYTE)ppl->lpPIFData + FIELD_OFFSET(PIFDATA,off))
  95. #define LPPIF_OFF(off) ((LPBYTE)ppl->lpPIFData + off)
  96. //
  97. // g_szDefaultPIF can be in one of three states:
  98. //
  99. // 1. "_DEFAULT.PIF", which means that we have never needed to search
  100. // for a _default.pif yet. The next time we need to locate
  101. // _default.pif, we must perform a full search. On success,
  102. // move to state 2. On failure, move to state 3.
  103. //
  104. // 2. A fully-qualified path to _default.pif, which means that we have
  105. // searched for a _default.pif and found it in the specified
  106. // location. The next time we need to locate _default.pif, we
  107. // will look here. If found, remain in state 2, else move to
  108. // state 3.
  109. //
  110. // 3. The null string, which means that we searched for a _default.pif
  111. // and didn't find one. The next time we need to locate
  112. // _default.pif, we just fail without even looking on the disk.
  113. // (This is the common case for a clean install.)
  114. //
  115. // Note that all the cases are "sticky"; once you reach a state, you
  116. // can never move back to a previous state. This sacrifices flexibility
  117. // for performance.
  118. //
  119. // The macro fTryDefaultPif() returns nonzero if we are in cases
  120. // 1 or 2.
  121. //
  122. // The macro fDefaultPifFound() returns nonzero if we are in case 2.
  123. //
  124. // WARNING! WARNING! WARNING! WARNING!
  125. //
  126. // Evil hack relies on the fact that the three states can be
  127. // distinguished by the first character of g_szDefaultPIF, which
  128. // in turn relies on the fact that `_' cannot be the first character
  129. // of a fully-qualified path. (It is not a valid drive letter,
  130. // and it cannot start a UNC.)
  131. //
  132. //
  133. #define INIT_INIDATA 0x01
  134. #define INIT_PIFDIR 0x02
  135. CHAR fbInit = 0; // see INIT_* flags
  136. INT iPIFName = (12*sizeof(TCHAR)); // strlen(g_szPIFDir)
  137. INT iWinName = (12*sizeof(TCHAR)); // strlen(g_szPIFDir)
  138. TCHAR g_szPIFDir[MAXPATHNAME] = TEXT("\\WINDOWS\\PIF");
  139. TCHAR g_szDefaultPIF[MAXPATHNAME] = TEXT("_DEFAULT.PIF");
  140. #define fTryDefaultPif() g_szDefaultPIF[0]
  141. #define fDefaultPifFound() (g_szDefaultPIF[0] != TEXT('_'))
  142. //
  143. // szComspec is the name of the COMSPEC program, usually "COMMAND.COM"
  144. // or "CMD.EXE".
  145. //
  146. TCHAR szComspec[8+1+3+1];
  147. /* Global R/O DLL data
  148. */
  149. extern const TCHAR c_szNULL[]; // A string so nice...
  150. const TCHAR szZero[] = TEXT("0");
  151. const int acbData[] = {
  152. sizeof(PROPPRG),
  153. sizeof(PROPTSK),
  154. sizeof(PROPVID),
  155. sizeof(PROPMEM),
  156. sizeof(PROPKBD),
  157. sizeof(PROPMSE),
  158. sizeof(PROPSND),
  159. sizeof(PROPFNT),
  160. sizeof(PROPWIN),
  161. sizeof(PROPENV),
  162. sizeof(PROPNT31),
  163. sizeof(PROPNT40),
  164. };
  165. /*
  166. * The casts are used because we intentionally mis-prototyped the GetXxxData
  167. * and SetXxxData functions to receive their third argument as a LPXXX instead
  168. * of a LPVOID.
  169. */
  170. const DATAGETFN afnGetData[] = {
  171. (DATAGETFN)GetPrgData,
  172. (DATAGETFN)GetTskData,
  173. (DATAGETFN)GetVidData,
  174. (DATAGETFN)GetMemData,
  175. (DATAGETFN)GetKbdData,
  176. (DATAGETFN)GetMseData,
  177. (DATAGETFN)GetSndData,
  178. (DATAGETFN)GetFntData,
  179. (DATAGETFN)GetWinData,
  180. (DATAGETFN)GetEnvData,
  181. (DATAGETFN)GetNt31Data,
  182. (DATAGETFN)GetNt40Data,
  183. };
  184. const DATASETFN afnSetData[] = {
  185. (DATASETFN)SetPrgData,
  186. (DATASETFN)SetTskData,
  187. (DATASETFN)SetVidData,
  188. (DATASETFN)SetMemData,
  189. (DATASETFN)SetKbdData,
  190. (DATASETFN)SetMseData,
  191. (DATASETFN)SetSndData,
  192. (DATASETFN)SetFntData,
  193. (DATASETFN)SetWinData,
  194. (DATASETFN)SetEnvData,
  195. (DATASETFN)SetNt31Data,
  196. (DATASETFN)SetNt40Data,
  197. };
  198. // WIN.INI things of interest
  199. // Note: some of these NEED to be ANSI strings, and other TCHAR
  200. // strings. Please do not arbitrarily change the type casts of
  201. // these strings!!!! (RickTu)
  202. const TCHAR szMemory[] = TEXT("MEMORY");
  203. const TCHAR szComp[] = TEXT("COMPATIBLE");
  204. CHAR szSingle[] = "DOS=SINGLE\r\n";
  205. CHAR szCRLF[] = "\r\n";
  206. CHAR szEcho[] = "ECHO ";
  207. CHAR szPause[] = "\r\nPAUSE\r\n";
  208. CHAR szCall[] = "CALL ";
  209. CHAR szCD[] = "CD ";
  210. CHAR szWin[] = "WIN";
  211. // SYSTEM.INI things of interest
  212. const TCHAR szSystemINI[] = TEXT("SYSTEM.INI");
  213. const TCHAR sz386EnhSection[] = TEXT("386Enh");
  214. const TCHAR szWOAFontKey[] = TEXT("WOAFont");
  215. const TCHAR szWOADBCSFontKey[] = TEXT("WOADBCSFont");
  216. const TCHAR szNonWinSection[] = TEXT("NonWindowsApp");
  217. const TCHAR szTTInitialSizes[] = TEXT("TTInitialSizes");
  218. #ifdef CUSTOMIZABLE_HEURISTICS
  219. const TCHAR szTTHeuristics[] = TEXT("TTHeuristics");
  220. const TCHAR szTTNonAspectMin[] = TEXT("TTNonAspectMin");
  221. #endif
  222. TCHAR szTTCacheSection[2][32] = {TEXT("TTFontDimenCache"), TEXT("TTFontDimenCacheDBCS")};
  223. //
  224. // These are because they are accessed only when we need to create
  225. // a new PIF file or convert a 3.1 PIF file into a 4.0 PIF file.
  226. //
  227. const TCHAR szDOSAPPINI[] = TEXT("DOSAPP.INI");
  228. const TCHAR szDOSAPPSection[] = TEXT("DOS Applications");
  229. const TCHAR szDOSAPPDefault[] = TEXT("Default");
  230. const TCHAR szDisplay[] = TEXT("DISPLAY");
  231. const TCHAR szDefIconFile[] = ICONFILE_DEFAULT;
  232. const TCHAR szDotExe[] = TEXT(".EXE");
  233. const TCHAR szDotCom[] = TEXT(".COM");
  234. const TCHAR szDotBat[] = TEXT(".BAT");
  235. const TCHAR szDotPif[] = TEXT(".PIF");
  236. const TCHAR szDotCmd[] = TEXT(".CMD");
  237. const TCHAR * apszAppType[] = {
  238. szDotExe, szDotCom, szDotBat, szDotCmd, szDotPif
  239. };
  240. CHAR szSTDHDRSIG[] = STDHDRSIG;
  241. CHAR szW286HDRSIG30[] = W286HDRSIG30;
  242. CHAR szW386HDRSIG30[] = W386HDRSIG30;
  243. CHAR szWENHHDRSIG40[] = WENHHDRSIG40;
  244. CHAR szWNTHDRSIG31[] = WNTHDRSIG31;
  245. CHAR szWNTHDRSIG40[] = WNTHDRSIG40;
  246. CHAR szCONFIGHDRSIG40[] = CONFIGHDRSIG40;
  247. CHAR szAUTOEXECHDRSIG40[] = AUTOEXECHDRSIG40;
  248. const TCHAR szRunOnceKey[] = REGSTR_PATH_RUNONCE;
  249. const TCHAR szPIFConvert[] = TEXT("PIFConvert");
  250. const TCHAR szPIFConvertExe[] = TEXT("RUNDLL.EXE PIFMGR.DLL,ProcessStartupProperties");
  251. const TCHAR szPIFConvertKey[] = REGSTR_PATH_PIFCONVERT;
  252. const TCHAR szMSDOSMode[] = REGSTR_VAL_MSDOSMODE;
  253. const TCHAR szMSDOSModeDiscard[] = REGSTR_VAL_MSDOSMODEDISCARD;
  254. // wsprintf formatting strings
  255. const TCHAR szDotPercent03d[] = TEXT(".%03d");
  256. // miscellaneous hack-o-ramas
  257. const TCHAR szPP4[] = TEXT("PP4"); // MS Powerpoint 4.0
  258. PROPTSK tskDefault ={TSK_DEFAULT,
  259. TSKINIT_DEFAULT,
  260. TSKFGNDBOOST_DEFAULT,
  261. TSKBGNDBOOST_DEFAULT,
  262. 0,
  263. 0,
  264. TSKIDLESENS_DEFAULT,
  265. };
  266. PROPVID vidDefault ={VID_DEFAULT,
  267. VIDINIT_DEFAULT,
  268. 0,
  269. 0,
  270. 0,
  271. };
  272. PROPMEM memDefault ={MEM_DEFAULT,
  273. MEMINIT_DEFAULT,
  274. MEMLOW_DEFAULT, // ignore stdpifdata.minmem?
  275. MEMLOW_MAX, // ignore stdpifdata.maxmem?
  276. MEMEMS_DEFAULT,
  277. MEMEMS_MAX,
  278. MEMXMS_DEFAULT,
  279. MEMXMS_MAX,
  280. };
  281. PROPKBD kbdDefault ={KBD_DEFAULT,
  282. KBDINIT_DEFAULT,
  283. KBDALTDELAY_DEFAULT,
  284. KBDALTPASTEDELAY_DEFAULT,
  285. KBDPASTEDELAY_DEFAULT,
  286. KBDPASTEFULLDELAY_DEFAULT,
  287. KBDPASTETIMEOUT_DEFAULT,
  288. KBDPASTESKIP_DEFAULT,
  289. KBDPASTECRSKIP_DEFAULT,
  290. };
  291. PROPMSE mseDefault ={MSE_DEFAULT,
  292. MSEINIT_DEFAULT,
  293. };
  294. PROPENV envDefault ={ENV_DEFAULT,
  295. ENVINIT_DEFAULT,
  296. "",
  297. ENVSIZE_DEFAULT,
  298. ENVDPMI_DEFAULT,
  299. };
  300. WORD flWinDefault = WIN_DEFAULT;
  301. /*
  302. * Default face name to use for Raster fonts. Currently, this is
  303. * just a hard-coded value (ie, not maintained in any INI file).
  304. */
  305. CHAR szRasterFaceName[LF_FACESIZE] = "Terminal";
  306. /*
  307. * Default face name to use for TrueType fonts. It must be a monospace
  308. * font, and it must be a font that everyone is guaranteed to have. Currently,
  309. * this can be changed by setting TTFont in [NonWindowsApp] in SYSTEM.INI.
  310. */
  311. // now this is initialized with string resource. The 2nd element will get
  312. // the native typeface for the bilingual dos prompt
  313. CHAR szTTFaceName[2][LF_FACESIZE] = {"Lucida Console", "Courier New"};
  314. const TCHAR szAltKeyDelay [] = TEXT("AltKeyDelay");
  315. const TCHAR szAltPasteDelay [] = TEXT("AltPasteDelay");
  316. const TCHAR szKeyPasteDelay [] = TEXT("KeyPasteDelay");
  317. const TCHAR szKeyBufferDelay [] = TEXT("KeyBufferDelay");
  318. const TCHAR szKeyPasteTimeout [] = TEXT("KeyPasteTimeout");
  319. const TCHAR szKeyPasteSkipCount [] = TEXT("KeyPasteSkipCount");
  320. const TCHAR szKeyPasteCRSkipCount[] = TEXT("KeyPasteCRSkipCount");
  321. const TCHAR szMouseInDosBox [] = TEXT("MouseInDosBox");
  322. const TCHAR szDisablePositionSave[] = TEXT("DisablePositionSave");
  323. const TCHAR szDOSPromptExitInst [] = TEXT("DOSPromptExitInstruc");
  324. const TCHAR szCommandEnvSize [] = TEXT("CommandEnvSize");
  325. const TCHAR szScreenLines [] = TEXT("ScreenLines");
  326. const INIDATA aINIData[] = {
  327. {sz386EnhSection, szAltKeyDelay, &kbdDefault.msAltDelay, INIDATA_FIXEDPOINT},
  328. {sz386EnhSection, szAltPasteDelay, &kbdDefault.msAltPasteDelay, INIDATA_FIXEDPOINT},
  329. {sz386EnhSection, szKeyPasteDelay, &kbdDefault.msPasteDelay, INIDATA_FIXEDPOINT},
  330. {sz386EnhSection, szKeyBufferDelay, &kbdDefault.msPasteFullDelay,INIDATA_FIXEDPOINT},
  331. {sz386EnhSection, szKeyPasteTimeout, &kbdDefault.msPasteTimeout, INIDATA_FIXEDPOINT},
  332. {sz386EnhSection, szKeyPasteSkipCount, &kbdDefault.cPasteSkip, INIDATA_DECINT},
  333. {sz386EnhSection, szKeyPasteCRSkipCount, &kbdDefault.cPasteCRSkip, INIDATA_DECINT},
  334. {szNonWinSection, szMouseInDosBox, &mseDefault.flMse, INIDATA_BOOLEAN, MSE_WINDOWENABLE},
  335. {szNonWinSection, szDisablePositionSave, &flWinDefault, INIDATA_BOOLEAN | INIDATA_INVERT, WIN_SAVESETTINGS},
  336. #ifdef ENVINIT_INSTRUCTIONS
  337. {sz386EnhSection, szDOSPromptExitInst, &envDefault.flEnvInit, INIDATA_BOOLEAN, ENVINIT_INSTRUCTIONS},
  338. #endif
  339. {szNonWinSection, szCommandEnvSize, &envDefault.cbEnvironment, INIDATA_DECINT},
  340. {szNonWinSection, szScreenLines, &vidDefault.cScreenLines, INIDATA_DECINT},
  341. };
  342. /**************************************************************************
  343. *
  344. * OVERVIEW OF INI FILE USAGE
  345. *
  346. *
  347. * SYSTEM.INI
  348. *
  349. * [386Enh]
  350. *
  351. * WOAFont=<fon filename>
  352. *
  353. * Status: Public
  354. * Default: dosapp.fon
  355. * Purpose:
  356. *
  357. * This setting allows the user to specify which Terminal font
  358. * file should be loaded when DOS box is started.
  359. *
  360. * To change:
  361. *
  362. * Use Notepad to edit the SYSTEM.INI file.
  363. *
  364. *
  365. * [NonWindowsApp]
  366. *
  367. * DisablePositionSave=<Boolean>
  368. *
  369. * Status: Public
  370. * Default: 0 (FALSE)
  371. * Purpose:
  372. *
  373. * When FALSE, the position and font used in a non-Windows
  374. * application is saved in the application's PIF file when
  375. * you exit the application. When TRUE, the position, fonts, and
  376. * toolbar state of a non-Windows application whose settings
  377. * have not been previously saved in the DOSAPP.INI file will
  378. * not be saved.
  379. *
  380. * If enabled, the setting can be overridden for each
  381. * non-Windows application by selecting the Save Settings On
  382. * Exit check box in the Font dialog box.
  383. *
  384. * To change:
  385. *
  386. * Use Notepad to edit the SYSTEM.INI file.
  387. *
  388. * Compatibility notes:
  389. *
  390. * In Windows 3.x, the "position save" (and font) information was
  391. * saved in DOSAPP.INI, and although we will still read DOSAPP.INI
  392. * in the absence of any information in the PIF file, we only *write*
  393. * settings back to the PIF file. DOSAPP.INI should be considered
  394. * obsolete.
  395. *
  396. *
  397. * TTFont=<fontname>
  398. *
  399. * Status: ?
  400. * Default: Courier New // FEATURE -- this should be a TT OEM font
  401. * Purpose:
  402. *
  403. * This setting allows the user to specify which TrueType font
  404. * will be used in a DOS box. It must be an OEM font.
  405. *
  406. * To change:
  407. *
  408. * Use Notepad to edit the SYSTEM.INI file.
  409. *
  410. *
  411. * TTInitialSizes=<i1 i2 i3 i4 ... i16>
  412. *
  413. * Status: ?
  414. * Default: 4 5 6 7 8 9 10 11 12 14 16 18 20 22 36 72
  415. * Purpose:
  416. *
  417. * This setting allows the user to specify which font sizes
  418. * WinOldAp initially builds for the TrueType fonts in a DOS
  419. * application window.
  420. *
  421. * At most 16 font sizes can be requested.
  422. *
  423. * Note that this INI entry is consulted only the first time
  424. * Windows is restarted after changing video drivers or fonts.
  425. *
  426. * To change:
  427. *
  428. * Use Notepad to edit the SYSTEM.INI file.
  429. *
  430. *
  431. * TTHeuristics=<i1 i2 i3 i4 i5 i6 i7 i8 i9>
  432. *
  433. * Status: Public
  434. * Default: 5000 1000 0 1000 5000 1000 0 1000 1
  435. * Purpose:
  436. *
  437. * These integers control the way Windows chooses the font to
  438. * display for DOS applications running inside a window if you
  439. * have chosen "Auto" as the font size.
  440. *
  441. * The parameters are named as follows:
  442. *
  443. * i1=XOvershootInitial
  444. * i2=XOvershootScale
  445. * i3=XShortfallInitial
  446. * i4=XShortfallScale
  447. * i5=YOvershootInitial
  448. * i6=YOvershootScale
  449. * i7=YShortfallInitial
  450. * i8=YShortfallScale
  451. * i9=TrueTypePenalty
  452. *
  453. * Each penalty value may not exceed 5000.
  454. *
  455. * When Windows needs to select a font for use in a DOS
  456. * application's window, it goes through the list of font
  457. * sizes available and computes the "penalty" associated
  458. * with using that font. Windows then selects the font with
  459. * the smallest penalty.
  460. *
  461. * The horizontal penalty is computed as follows:
  462. *
  463. * Let dxActual = <actual window width>
  464. * Let dxDesired = <font width> * <characters per line>
  465. *
  466. * If dxActual = dxDesired:
  467. * xPenalty = 0
  468. * If dxActual < dxDesired:
  469. * Let Ratio = 1 - dxDesired / dxActual
  470. * xPenalty = XOvershootInitial + Ratio * XOvershootScale
  471. * If dxActual > dxDesired:
  472. * Let Ratio = 1 - dxActual / dxDesired
  473. * xPenalty = XShortfallInitial + Ratio * XShortfallScale
  474. *
  475. * The vertical penalty is computed similarly.
  476. *
  477. * Note that the Ratio is always a fraction between 0 and 1.
  478. *
  479. * The penalty associated with a font is the sum of the vertical
  480. * and horizontal penalties, plus the TrueTypePenalty if the font
  481. * is a TrueType font.
  482. *
  483. * The default value of 1 for the TrueTypePenalty means that,
  484. * all other things being equal, Windows will select a raster
  485. * font in preference to a TrueType font. You can set this
  486. * value to -1 if you wish the opposite preference.
  487. *
  488. * To change:
  489. *
  490. * Use Notepad to edit the SYSTEM.INI file.
  491. *
  492. * Internals:
  493. *
  494. * Even though floating point appears in the computations,
  495. * everything is really done in integer arithmetic.
  496. *
  497. * Pixels are NEVER MENTIONED anywhere in the penalty computations.
  498. * (All pixel values are divided by other pixel values, so that
  499. * we get a dimensionless number as a result.)
  500. * This keeps us independent of the display resolution as well
  501. * as the display aspect ratio.
  502. *
  503. * Since the stretch and shrink are taken as fractions of the
  504. * larger dimension, this keeps us from penalizing large
  505. * differences by too much. This is important because there
  506. * isn't much visible difference between being ten times too
  507. * big and being eleven times too big, but there is a big
  508. * difference between being just right and being twice as big.
  509. *
  510. * We must be careful not to let the maximum possible penalty
  511. * exceed 32767. This is done by making sure that each
  512. * dimension cannot produce a penalty of greater than 10000
  513. * (5000+5000), and that the TrueTypePenalty is at most 5000.
  514. * This makes the maximum possible penalty 25000.
  515. * This range checking is done by FontSelInit.
  516. *
  517. *
  518. * TTNonAspectMin=<x y>
  519. *
  520. * Status: Public
  521. * Default: 3 3
  522. * Purpose:
  523. *
  524. * These integers control the minimum width and height font that
  525. * Windows will attempt to create automatically in response to a
  526. * resize operation when TrueType fonts in DOS boxes are enabled
  527. * and the "Auto" font size is selected.
  528. *
  529. * These values prevent Windows from creating visually useless
  530. * fonts like 10 x 1 or 1 x 10. The default values prevent Windows
  531. * from trying to create X x Y fonts if X < 3 or Y < 3.
  532. *
  533. * TTNonAspectMin is not consulted if the font is being created at
  534. * its default aspect ratio. In other words, Windows will create,
  535. * for example, a 1 x 3 font, if 1 x 3 is the standard aspect ratio
  536. * for a 3-pixel-high font.
  537. *
  538. * To permit all aspect ratios, set the values to "0 0".
  539. *
  540. * To forbid all aspect ratios except for the standard aspect ratio,
  541. * set the values to "-1 -1".
  542. *
  543. * [TTFontDimenCache]
  544. *
  545. * dxWidthRequested dyHeightRequested=dxWidthActual dyWidthActual
  546. *
  547. * Status: Private
  548. * Default: Null
  549. * Purpose:
  550. *
  551. * The [FontDimenCache] section contains information about
  552. * TrueType font sizes that have been created. Each entry
  553. * has as the keyname the width and height that were passed
  554. * to CreateFont and has as the value the width and height of
  555. * the font that was actually created.
  556. *
  557. * Internals:
  558. *
  559. * Inspected by AddTrueTypeFontsToFontList.
  560. * Set by AddOneNewTrueTypeFontToFontList.
  561. *
  562. *
  563. **************************************************************************
  564. *
  565. * DOSAPP.INI (obsolete, supported on a read-only basis)
  566. *
  567. * [Dos Applications]
  568. *
  569. * C:\FULL\PATH\TO\EXE\COM\BAT\OR.PIF=<wFlags wFontWidth wFontHeight
  570. * wWinWidth wWinHeight length flags showCmd ptMinPositionX
  571. * ptMinPositionY ptMaxPositionX ptMaxPositionY
  572. * rcNormalLeft rcNormalTop rcNormalRight rcNormalBottom>
  573. *
  574. * Status: Private
  575. * Purpose:
  576. *
  577. * These values are used to restore a DOS application's window
  578. * to the state it was in when the DOS app last exited normally.
  579. *
  580. * The values are taken directly from the INIINFO structure, qv.
  581. *
  582. * The values of ptMinPositionX and ptMinPositionY are always -1,
  583. * since we do not try to preserve the icon position.
  584. *
  585. * If wFontHeight has the high bit set, then the font that
  586. * should be used is a TrueType font.
  587. *
  588. * If wFontWidth = 1 and wFontHeight = -1, then
  589. * Auto-font-selection is active.
  590. *
  591. * Compatibility notes:
  592. *
  593. * In Windows 3.x, the "position save" (and font) information was
  594. * saved in DOSAPP.INI, and although we will still read DOSAPP.INI
  595. * in the absence of any information in the PIF file, we only *write*
  596. * settings back to the PIF file. DOSAPP.INI should be considered
  597. * obsolete.
  598. *
  599. *
  600. **************************************************************************
  601. *
  602. * THE NEXT INI VAR IS NOT IMPLEMENTED BUT SHOULD BE
  603. *
  604. **************************************************************************
  605. *
  606. * SYSTEM.INI
  607. *
  608. * [NonWindowsApp]
  609. *
  610. * TTFontTolerance=<i>
  611. *
  612. * Status: Public
  613. * Default: 200
  614. * Purpose:
  615. *
  616. * This setting indicates how large a penalty (see TTHeuristics)
  617. * Windows should tolerate before trying to synthesize new font
  618. * sizes from TrueType fonts.
  619. *
  620. * Decreasing this value will result in a tighter fit of the
  621. * Windows-selected font to the actual window size, but at a
  622. * cost in speed and memory.
  623. *
  624. * To change:
  625. *
  626. * Use Notepad to edit the SYSTEM.INI file.
  627. *
  628. *
  629. * Internals:
  630. *
  631. * Inspected by ChooseBestFont, if implemented.
  632. *
  633. **************************************************************************/
  634. void PifMgrDLL_Init()
  635. {
  636. static BOOL fInit = FALSE;
  637. if (!fInit)
  638. {
  639. LoadString(g_hinst, IDS_PIF_NONE, g_szNone, ARRAYSIZE(g_szNone));
  640. LoadString(g_hinst, IDS_AUTONORMAL, g_szAuto, ARRAYSIZE(g_szAuto));
  641. LoadGlobalFontData();
  642. fInit = TRUE;
  643. }
  644. }
  645. /** GetPIFDir - Form default PIF directory name + name of given file
  646. *
  647. * INPUT
  648. * None
  649. *
  650. * OUTPUT
  651. * None
  652. */
  653. void GetPIFDir(LPTSTR pszName)
  654. {
  655. int i;
  656. static const TCHAR szBackslashPIF[] = TEXT("\\PIF");
  657. FunctionName(GetPIFDir);
  658. if (!(fbInit & INIT_PIFDIR)) {
  659. // Set up g_szPIFDir, less space for a filename, less space for \PIF
  660. i = ARRAYSIZE(g_szPIFDir)-lstrlen(pszName)-ARRAYSIZE(szBackslashPIF);
  661. if (i <= 0) // sanity check
  662. return;
  663. GetWindowsDirectory(g_szPIFDir, i);
  664. iPIFName = lstrlen(g_szPIFDir);
  665. if (StrRChr(g_szPIFDir, NULL, TEXT('\\')) == &g_szPIFDir[iPIFName-1])
  666. iPIFName--;
  667. iWinName = iPIFName;
  668. StringCchCopy(g_szPIFDir+iPIFName, ARRAYSIZE(g_szPIFDir)-iPIFName, szBackslashPIF);
  669. iPIFName += ARRAYSIZE(szBackslashPIF)-1;
  670. i = (int)GetFileAttributes(g_szPIFDir);
  671. if (i == -1) {
  672. // It didn't exist, so try to create it (returns TRUE if success)
  673. i = CreateDirectory(g_szPIFDir, NULL);
  674. if (i)
  675. SetFileAttributes(g_szPIFDir, FILE_ATTRIBUTE_HIDDEN);
  676. }
  677. else if (i & FILE_ATTRIBUTE_DIRECTORY)
  678. i = TRUE; // directory already exists, cool!
  679. else
  680. i = FALSE; // some sort of file is in the way...
  681. if (i) {
  682. g_szPIFDir[iPIFName++] = TEXT('\\'); // append the slash we'll need
  683. // to separate future filenames (the
  684. // space after is already zero-init'ed)
  685. }
  686. else // we'll just have to use the Windows dir
  687. iPIFName -= ARRAYSIZE(szBackslashPIF)-2;
  688. fbInit |= INIT_PIFDIR;
  689. }
  690. // Now initialize g_szPIFDir with the name of the file we're processing
  691. if (pszName)
  692. StringCchCopy(g_szPIFDir+iPIFName, ARRAYSIZE(g_szPIFDir)-iPIFName, pszName);
  693. }
  694. /** GetINIData - Read WIN.INI/SYSTEM.INI/DOSAPP.INI for default settings
  695. *
  696. * INPUT
  697. * Nothing
  698. *
  699. * OUTPUT
  700. * Nothing; global defaults (re)set
  701. *
  702. * NOTES
  703. * We only do this work now if GetPIFData couldn't open a PIF file, or
  704. * could but it contained no enhanced section. And we never do it more than
  705. * once per fresh load of this DLL.
  706. */
  707. void GetINIData()
  708. {
  709. int t;
  710. const INIDATA *pid;
  711. LPCTSTR lpsz;
  712. DWORD dwRet;
  713. TCHAR szTemp[MAX_PATH];
  714. FunctionName(GetINIData);
  715. if (fbInit & INIT_INIDATA) // if already done
  716. return; // then go away
  717. for (pid=aINIData; pid-aINIData < ARRAYSIZE(aINIData); pid++) {
  718. t = *(INT UNALIGNED *)pid->pValue;
  719. if (pid->iFlags & (INIDATA_DECINT | INIDATA_BOOLEAN)) {
  720. if (pid->iFlags & INIDATA_BOOLEAN) {
  721. t &= pid->iMask;
  722. if (pid->iFlags & INIDATA_INVERT)
  723. t ^= pid->iMask;
  724. }
  725. t = GetPrivateProfileInt(pid->pszSection,
  726. pid->pszKey,
  727. t,
  728. szSystemINI);
  729. if (pid->iFlags & INIDATA_BOOLEAN) {
  730. if (t)
  731. t = pid->iMask;
  732. if (pid->iFlags & INIDATA_INVERT)
  733. t ^= pid->iMask;
  734. t |= *(INT UNALIGNED *)pid->pValue & ~pid->iMask;
  735. }
  736. *(INT UNALIGNED *)pid->pValue = t;
  737. }
  738. else
  739. if (pid->iFlags & INIDATA_FIXEDPOINT) {
  740. StringCchPrintf(szTemp, ARRAYSIZE(szTemp), szDotPercent03d, t);
  741. GetPrivateProfileString(pid->pszSection,
  742. pid->pszKey,
  743. szTemp,
  744. szTemp,
  745. ARRAYSIZE(szTemp),
  746. szSystemINI);
  747. *(INT UNALIGNED *)pid->pValue = StrToInt(szTemp+1);
  748. }
  749. else
  750. ASSERTFAIL();
  751. }
  752. //
  753. // Locate COMSPEC once and for all.
  754. //
  755. dwRet = GetEnvironmentVariable(TEXT("COMSPEC"), szTemp, ARRAYSIZE(szTemp));
  756. if (dwRet < ARRAYSIZE(szTemp) && dwRet > 0)
  757. {
  758. lpsz = StrRChr(szTemp, NULL, TEXT('\\'));
  759. if (lpsz) {
  760. StringCchCopy(szComspec, ARRAYSIZE(szComspec), lpsz+1);
  761. }
  762. }
  763. fbInit |= INIT_INIDATA;
  764. }
  765. /** InitProperties - initialize new property structure
  766. *
  767. * INPUT
  768. * ppl -> property
  769. * fLocked == TRUE to return data locked, FALSE unlocked
  770. *
  771. * OUTPUT
  772. * Nothing (if successful, ppl->hPIFData will become non-zero)
  773. */
  774. void InitProperties(PPROPLINK ppl, BOOL fLocked)
  775. {
  776. LPSTDPIF lpstd;
  777. LPW386PIF30 lp386 = NULL;
  778. CHAR achPathName[ARRAYSIZE(ppl->szPathName)];
  779. BYTE behavior = 0;
  780. FunctionName(InitProperties);
  781. GetINIData(); // make sure we have all the right defaults
  782. if (ResizePIFData(ppl, sizeof(STDPIF)) != -1) {
  783. // We're no longer called *only* after a fresh ZERO'd HeapAlloc
  784. // by ResizePIFData. We could be getting called because PifMgr_OpenProperties
  785. // was told to punt on an ambiguous PIF and create new settings.
  786. // Hence, we always zero-init the buffer ourselves now.
  787. BZero(ppl->lpPIFData, ppl->cbPIFData);
  788. lpstd = (LPSTDPIF)ppl->lpPIFData;
  789. lpstd->id = 0x78;
  790. PifMgr_WCtoMBPath( ppl->szPathName, achPathName, ARRAYSIZE(achPathName) );
  791. lstrcpyncharA(lpstd->appname, achPathName+ppl->iFileName, ARRAYSIZE(lpstd->appname), '.');
  792. CharToOemBuffA(lpstd->appname, lpstd->appname, ARRAYSIZE(lpstd->appname));
  793. // NOTE: When 3.x Setup creates PIF files, it sets maxmem to 640;
  794. // that's typically what memDefault.wMaxLow will be too....
  795. lpstd->minmem = memDefault.wMinLow;
  796. lpstd->maxmem = (WORD) GetProfileInt(apszAppType[APPTYPE_PIF]+1, szMemory, memDefault.wMaxLow);
  797. StringCchCopyA(lpstd->startfile, ARRAYSIZE(lpstd->startfile), achPathName);
  798. CharToOemBuffA(lpstd->startfile, lpstd->startfile, ARRAYSIZE(lpstd->startfile));
  799. //
  800. // New for 4.0: fDestroy (close on exit) is disabled by default
  801. // for most apps, but is enabled by default for COMSPEC.
  802. //
  803. lpstd->MSflags = 0;
  804. if (!lstrcmpi(ppl->szPathName+ppl->iFileName, szComspec)) {
  805. lpstd->MSflags = fDestroy;
  806. }
  807. // Initialize various goofy non-zero stuff just to make it
  808. // look like a backward-compatible PIF file -- not that we use
  809. // or particularly care about any of it
  810. // NOTE: When 3.x Setup creates PIF files, it sets screen to 0x7F
  811. lpstd->cPages = 1;
  812. lpstd->highVector = 0xFF;
  813. lpstd->rows = 25;
  814. lpstd->cols = 80;
  815. lpstd->sysmem = 0x0007;
  816. // fFullScreen is no longer default, so only if an explicit
  817. // COMPATIBLE=FALSE exists in the PIF section of WIN.INI will
  818. // we set fScreen in behavior and fFullScreen in PfW386Flags
  819. // Similarly, fDestroy is no longer default, but we'll go
  820. // back to the old way if the switch tells us to.
  821. if (!GetProfileInt(apszAppType[APPTYPE_PIF]+1, szComp, TRUE)) {
  822. lpstd->behavior = behavior = fScreen;
  823. lpstd->MSflags = fDestroy;
  824. }
  825. if (ppl->ckbMem != -1 && ppl->ckbMem != 1)
  826. lpstd->minmem = lpstd->maxmem = (WORD) ppl->ckbMem;
  827. if (AddGroupData(ppl, szW386HDRSIG30, NULL, sizeof(W386PIF30))) {
  828. if (NULL != (lp386 = GetGroupData(ppl, szW386HDRSIG30, NULL, NULL))) {
  829. lp386->PfW386minmem = lpstd->minmem;
  830. lp386->PfW386maxmem = lpstd->maxmem;
  831. lp386->PfFPriority = TSKFGND_OLD_DEFAULT;
  832. lp386->PfBPriority = TSKBGND_OLD_DEFAULT;
  833. lp386->PfMinEMMK = memDefault.wMinEMS;
  834. lp386->PfMaxEMMK = memDefault.wMaxEMS;
  835. lp386->PfMinXmsK = memDefault.wMinXMS;
  836. lp386->PfMaxXmsK = memDefault.wMaxXMS;
  837. lp386->PfW386Flags = fBackground + fPollingDetect + fINT16Paste;
  838. if (behavior & fScreen)
  839. lp386->PfW386Flags |= fFullScreen;
  840. lp386->PfW386Flags2 = fVidTxtEmulate + fVidNoTrpTxt + fVidNoTrpLRGrfx + fVidNoTrpHRGrfx + fVidTextMd;
  841. }
  842. }
  843. VERIFYTRUE(AddEnhancedData(ppl, lp386));
  844. if (AddGroupData(ppl, szWNTHDRSIG31, NULL, sizeof(WNTPIF31))) {
  845. LPWNTPIF31 lpnt31;
  846. if (NULL != (lpnt31 = GetGroupData(ppl, szWNTHDRSIG31, NULL, NULL))) {
  847. StringCchCopyA( lpnt31->nt31Prop.achConfigFile, ARRAYSIZE(lpnt31->nt31Prop.achConfigFile), NT_CONFIG_FILE );
  848. StringCchCopyA( lpnt31->nt31Prop.achAutoexecFile, ARRAYSIZE(lpnt31->nt31Prop.achAutoexecFile), NT_AUTOEXEC_FILE );
  849. }
  850. }
  851. VERIFYTRUE(AddGroupData(ppl, szWNTHDRSIG40, NULL, sizeof(WNTPIF40)));
  852. // Can't be dirty anymore, 'cause we just set everything to defaults
  853. ppl->flProp &= ~PROP_DIRTY;
  854. if (!fLocked)
  855. ppl->cLocks--;
  856. }
  857. else
  858. ASSERTFAIL();
  859. }
  860. /** OpenPIFFile - Wrapper around CreateFile for opening PIF files
  861. *
  862. * The wrapper handles the following things:
  863. *
  864. * Passing the proper access and sharing flags to CreateFile.
  865. * Setting pof->nErrCode = 0 on success.
  866. * Converting ERROR_PATH_NOT_FOUND to ERROR_FILE_NOT_FOUND.
  867. *
  868. * INPUT
  869. *
  870. * pszFile -> name of file to attempt to open
  871. * pof -> PIFOFSTRUCT to fill in
  872. *
  873. * OUTPUT
  874. *
  875. * Same return code as CreateFile.
  876. *
  877. */
  878. HANDLE OpenPIFFile(LPCTSTR pszFile, LPPIFOFSTRUCT pof)
  879. {
  880. HANDLE hf;
  881. TCHAR pszFullFile[ MAX_PATH ];
  882. LPTSTR pszTheFile;
  883. DWORD dwRet;
  884. //
  885. // CreateFile does not search the path, so do that first, then
  886. // give CreateFile a fully qualified file name to open...
  887. //
  888. dwRet = SearchPath( NULL,
  889. pszFile,
  890. NULL,
  891. ARRAYSIZE(pszFullFile),
  892. pszFullFile,
  893. &pszTheFile
  894. );
  895. if ((dwRet==0) || (dwRet > ARRAYSIZE(pszFullFile)))
  896. {
  897. pszTheFile = (LPTSTR)pszFile;
  898. }
  899. else
  900. {
  901. pszTheFile = pszFullFile;
  902. }
  903. hf = CreateFile( pszTheFile,
  904. GENERIC_READ,
  905. FILE_SHARE_READ,
  906. NULL,
  907. OPEN_EXISTING,
  908. FILE_ATTRIBUTE_NORMAL,
  909. NULL );
  910. if (hf == INVALID_HANDLE_VALUE)
  911. {
  912. pof->nErrCode = GetLastError();
  913. if (pof->nErrCode == ERROR_PATH_NOT_FOUND)
  914. pof->nErrCode = ERROR_FILE_NOT_FOUND;
  915. }
  916. else
  917. {
  918. LPTSTR lpDummy;
  919. //
  920. // NOTE: Special hack for creating shortcuts. If the PIF file
  921. // that we find is 0 bytes long, pretend we did not find one at all.
  922. // This is because appwiz renames a 0 length file from "New shortcut.lnk"
  923. // to "appname.pif" and we end up finding it. We'll ignore this file.
  924. //
  925. if (SetFilePointer( hf, 0, NULL, FILE_END) == 0)
  926. {
  927. CloseHandle( hf );
  928. hf = INVALID_HANDLE_VALUE;
  929. pof->nErrCode = ERROR_FILE_NOT_FOUND;
  930. }
  931. else
  932. {
  933. LPCTSTR pszNewFile;
  934. TCHAR szTemp[ ARRAYSIZE(pof->szPathName) ];
  935. SetFilePointer( hf, 0, NULL, FILE_BEGIN );
  936. pof->nErrCode = ERROR_SUCCESS;
  937. // In some cases, people pass in two pointers to the same
  938. // buffer. This will hose GetFullPathName, so if they
  939. // are the same, then make a copy before calling GetFullPathName.
  940. if (pszTheFile==pof->szPathName) {
  941. FillMemory( szTemp, sizeof(szTemp), 0 );
  942. StringCchCopy( szTemp, ARRAYSIZE(szTemp), pszTheFile );
  943. pszNewFile = szTemp;
  944. }
  945. else
  946. {
  947. pszNewFile = pszTheFile;
  948. }
  949. GetFullPathName( pszNewFile, ARRAYSIZE(pof->szPathName),
  950. pof->szPathName, &lpDummy );
  951. }
  952. }
  953. return hf;
  954. }
  955. /** PifMgr_OpenProperties - return handle to property info for application
  956. *
  957. * INPUT
  958. * lpszApp -> name of application
  959. * lpszPIF -> name of PIF file to use/create
  960. * hInf = Inf handle, 0 if none, -1 to inhibit Inf processing
  961. * flOpt = OPENPROPS_RAWIO to allow raw file updates; otherwise, 0
  962. *
  963. * OUTPUT
  964. * handle to properties, FALSE if could not be opened, or out of memory
  965. *
  966. * REMARKS
  967. * This should not be thought of as a function that opens a file somewhere
  968. * on the disk (although that's usually the effect), but rather as an
  969. * property structure allocator that is optionally initialized by disk data
  970. * (currently, the file does not even remain open after this call). So the
  971. * main reason for failure in this function will be either a low memory
  972. * condition *or* inability to open a specific PIF file.
  973. *
  974. * The rules for PIF file searching are as follows:
  975. *
  976. * If not a .PIF file:
  977. * Search in current directory.
  978. * Endif.
  979. *
  980. * If path components were specified:
  981. * Search in specified directory.
  982. * Endif.
  983. *
  984. * Search in PIF directory.
  985. * Search the path.
  986. *
  987. * Note that this differs from the Windows 3.1 PIF search algorithm, which
  988. * was...
  989. *
  990. * Search current directory.
  991. * Search the path.
  992. * Search in application directory.
  993. *
  994. * This was a really bogus search order. Fortunately, it seems that
  995. * very few people relied on it.
  996. *
  997. * Things to watch out for when dorking the PIF file search order:
  998. *
  999. * Make sure editing PIF properties from the shell works. (I.e.,
  1000. * if a full path to a PIF is given, then use it; don't search.)
  1001. *
  1002. * Extra special thing to watch out for when dorking the PIF file
  1003. * search order:
  1004. *
  1005. * MS Delta execs its child process as follows:
  1006. *
  1007. * CreatePif("C:\DELTA\DELTABAT.PIF");
  1008. * SetCurrentDirectory("C:\RANDOM\PLACE");
  1009. * WinExec("C:\TMP\DELTABAT.BAT", SW_HIDE);
  1010. *
  1011. * It expects the PIF search to pick up C:\DELTA\DELTABAT.PIF
  1012. * from the path, even though the WinExec supplied a full path.
  1013. *
  1014. */
  1015. HANDLE WINAPI PifMgr_OpenProperties(LPCTSTR lpszApp, LPCTSTR lpszPIF, UINT hInf, UINT flOpt)
  1016. {
  1017. PPROPLINK ppl;
  1018. LPTSTR pszExt;
  1019. BOOL fError = FALSE;
  1020. BOOL fFixedDisk = FALSE;
  1021. BOOL fSearchInf = FALSE;
  1022. BOOL fExplicitPIF = FALSE;
  1023. PROPPRG prg;
  1024. PROPNT40 nt40;
  1025. LPTSTR pszName, pszFullName;
  1026. #ifdef DBCS
  1027. PROPENV env;
  1028. #endif
  1029. FunctionName(PifMgr_OpenProperties);
  1030. // Allocate new prop
  1031. if (!(ppl = (PPROPLINK)LocalAlloc(LPTR, sizeof(PROPLINK))))
  1032. return 0;
  1033. if (!(pszFullName = (LPTSTR)LocalAlloc(LPTR, MAXPATHNAME*sizeof(TCHAR)))) {
  1034. EVAL(LocalFree(ppl) == NULL);
  1035. return 0;
  1036. }
  1037. if ((HANDLE)ppl > g_offHighestPropLink) {
  1038. g_offHighestPropLink = (HANDLE)ppl;
  1039. }
  1040. // Initialize the new prop
  1041. ppl->ppl = ppl;
  1042. ppl->ckbMem = -1;
  1043. ppl->iSig = PROP_SIG;
  1044. ppl->hPIF = INVALID_HANDLE_VALUE;
  1045. if (flOpt & OPENPROPS_RAWIO)
  1046. ppl->flProp |= PROP_RAWIO;
  1047. #if (PRGINIT_INHIBITPIF != PROP_INHIBITPIF)
  1048. #error PRGINIT_INIHIBITPIF and PROP_INHIBITPIF out of sync!
  1049. #endif
  1050. ppl->flProp |= (flOpt & PROP_INHIBITPIF);
  1051. // Link into the global list
  1052. if (NULL != (ppl->pplNext = g_pplHead))
  1053. g_pplHead->pplPrev = ppl;
  1054. g_pplHead = ppl;
  1055. // Copy app name to both temp and perm buffers, and record location
  1056. // of base filename, and extension if any, within the buffer
  1057. StringCchCopy(pszFullName,MAXPATHNAME-4, lpszApp);
  1058. StringCchCopy(ppl->szPathName, ARRAYSIZE(ppl->szPathName), pszFullName);
  1059. if (NULL != (pszName = StrRChr(pszFullName, NULL, TEXT('\\'))) ||
  1060. NULL != (pszName = StrRChr(pszFullName, NULL, TEXT(':'))))
  1061. pszName++;
  1062. else
  1063. pszName = pszFullName;
  1064. if (!(pszExt = StrRChr(pszName, NULL, TEXT('.'))))
  1065. pszExt = pszFullName + lstrlen(pszFullName);
  1066. ppl->iFileName = (UINT) (pszName - pszFullName);
  1067. ppl->iFileExt = (UINT) (pszExt - pszFullName);
  1068. // Check the application's file extension
  1069. if (!*pszExt) {
  1070. StringCchCat(pszFullName, MAXPATHNAME, apszAppType[APPTYPE_PIF]);
  1071. }
  1072. else if (!lstrcmpi(pszExt, apszAppType[APPTYPE_EXE]) ||
  1073. !lstrcmpi(pszExt, apszAppType[APPTYPE_COM]) ||
  1074. !lstrcmpi(pszExt, apszAppType[APPTYPE_BAT])) {
  1075. // !lstrcmpi(pszExt, apszAppType[APPTYPE_CMD])) {
  1076. StringCchCopy(pszExt, MAXPATHNAME-(pszExt-pszFullName), apszAppType[APPTYPE_PIF]);
  1077. }
  1078. else if (!lstrcmpi(pszExt, apszAppType[APPTYPE_PIF]))
  1079. fExplicitPIF = TRUE;
  1080. else {
  1081. // Let's disallow random file extensions, since WinOldAp never
  1082. // allowed them either
  1083. goto Error;
  1084. }
  1085. // INFONLY means the caller just wants to search the INF, so ignore
  1086. // any WIN.INI garbage and any PIFs laying around. We still look for
  1087. // _DEFAULT.PIF, since that code takes care of other important
  1088. // initialization that needs to happen when no PIF was found at all.
  1089. if (flOpt & OPENPROPS_INFONLY)
  1090. goto FindDefault;
  1091. // Backward compatibility requires that if the app is not a PIF,
  1092. // then we must check the PIF section of WIN.INI for an entry matching
  1093. // the base name of the app. If the entry exists, then we have to skip
  1094. // the PIF search, and pass the value of the entry to InitProperties,
  1095. // which it uses to establish default memory requirements
  1096. //
  1097. // Also note that if IGNOREPIF is set, then ofPIF.szPathName is nothing
  1098. // more than the name of the app that was given to PifMgr_OpenProperties; this
  1099. // may give us the opportunity to do something more intelligent later...
  1100. if (!fExplicitPIF) {
  1101. ppl->ckbMem = GetProfileInt(apszAppType[APPTYPE_PIF]+1, ppl->szPathName+ppl->iFileName, -1);
  1102. if (ppl->ckbMem != -1) {
  1103. ppl->flProp |= PROP_IGNOREPIF | PROP_SKIPPIF;
  1104. StringCchCopy(ppl->ofPIF.szPathName, ARRAYSIZE(ppl->ofPIF.szPathName), lpszApp);
  1105. goto IgnorePIF; // entry exists, skip PIF file search
  1106. }
  1107. }
  1108. //
  1109. // Initialize default error return code. Once we get a successful
  1110. // open, it will be set to zero.
  1111. //
  1112. ppl->flProp |= PROP_NOCREATEPIF;
  1113. ppl->ofPIF.nErrCode = ERROR_FILE_NOT_FOUND;
  1114. //
  1115. // We must search in the current directory if not given a path to a PIF.
  1116. // We need to prefix `.\' to the filename so that OpenFile will not do
  1117. // a path search.
  1118. //
  1119. if (!fExplicitPIF || pszName == pszFullName) {
  1120. //
  1121. // This relies on a feature of OpenFile, that it copies the input
  1122. // buffer to a private buffer before stomping the output buffer,
  1123. // thus permitting precisely the stunt we are pulling here, namely,
  1124. // passing an input buffer equal to the output buffer.
  1125. //
  1126. *(LPDWORD)(ppl->ofPIF.szPathName) = 0x005C002E; /*dot backslash prefix */
  1127. StringCchCopy( &ppl->ofPIF.szPathName[2], ARRAYSIZE(ppl->ofPIF.szPathName) - 2,
  1128. pszName);
  1129. ppl->hPIF = OpenPIFFile(ppl->ofPIF.szPathName, &ppl->ofPIF);
  1130. }
  1131. //
  1132. // If we were given a path component, then look in that directory.
  1133. // (The fact that we have a backslash or drive letter will suppress
  1134. // the path search.)
  1135. //
  1136. if (pszName != pszFullName && ppl->ofPIF.nErrCode == ERROR_FILE_NOT_FOUND) {
  1137. ppl->hPIF = OpenPIFFile(pszFullName, &ppl->ofPIF);
  1138. // If we didn't find a PIF there, we'd probably still like to create
  1139. // one there if the media is a fixed disk. Network shares, CD-ROM
  1140. // drives, and floppies are not good targets for PIF files in general.
  1141. //
  1142. // So, if the media is a fixed disk, set the fFixedDisk flag so that
  1143. // we'll leave pszFullName alone.
  1144. if (ppl->hPIF == INVALID_HANDLE_VALUE && pszFullName[1] == TEXT(':')) {
  1145. TCHAR szTemp[4];
  1146. StringCchCopy(szTemp, ARRAYSIZE(szTemp), pszFullName);
  1147. if (GetDriveType(szTemp) == DRIVE_FIXED)
  1148. fFixedDisk++;
  1149. }
  1150. }
  1151. // PERF: replace this PIF dir search with a registry search -JTP
  1152. //
  1153. // Failing that, let's look in the PIF directory. Again, since we're
  1154. // supplying a full pathname, OpenFile won't try to search the PATH again.
  1155. if (ppl->ofPIF.nErrCode == ERROR_FILE_NOT_FOUND) {
  1156. GetPIFDir(pszName);
  1157. ppl->hPIF = OpenPIFFile(g_szPIFDir, &ppl->ofPIF);
  1158. if (ppl->hPIF != INVALID_HANDLE_VALUE)
  1159. ppl->flProp |= PROP_PIFDIR;
  1160. }
  1161. // If we're still in trouble, our last chance is to do a path
  1162. // search. This is an unconditional search, thanks to the
  1163. // wonders of MS-Delta.
  1164. if (ppl->ofPIF.nErrCode == ERROR_FILE_NOT_FOUND) {
  1165. ppl->hPIF = OpenPIFFile(pszName, &ppl->ofPIF);
  1166. }
  1167. if (ppl->hPIF == INVALID_HANDLE_VALUE) {
  1168. if (ppl->ofPIF.nErrCode != ERROR_FILE_NOT_FOUND || fExplicitPIF) {
  1169. // Hmmm, file *may* exist, but it cannot be opened; if it's a
  1170. // strange error, or we were specifically told to open that file,
  1171. // then return error
  1172. goto Error;
  1173. }
  1174. FindDefault:
  1175. fSearchInf = TRUE;
  1176. ppl->flProp &= ~PROP_NOCREATEPIF;
  1177. // Any files we find now are NOT really what we wanted, so save
  1178. // the name we'd like to use in the future, in case we need to save
  1179. // updated properties later.
  1180. //
  1181. // We must save the name now because we might stomp g_szPIFDir while
  1182. // searching for the _default.pif. Furthermore, we must save it in
  1183. // the buffer we HeapAlloc'ed (pszFullName) temporarily, because
  1184. // the following calls to OpenPIFFile can still stomp on szPathName
  1185. // in our OpenFile structure (ofPIF.szPathName).
  1186. GetPIFDir(pszName);
  1187. if (!fFixedDisk) // save desired name in
  1188. StringCchCopy(pszFullName, MAXPATHNAME, g_szPIFDir); // temp buffer (pszFullName)
  1189. //
  1190. // Try to locate the _default.pif.
  1191. //
  1192. if (fTryDefaultPif()) {
  1193. if (!fDefaultPifFound()) { // Must search for it
  1194. // First try PIFDir
  1195. StringCchCopy(g_szPIFDir+iPIFName, ARRAYSIZE(g_szPIFDir)-iPIFName, g_szDefaultPIF);
  1196. ppl->hPIF = OpenPIFFile(g_szPIFDir, &ppl->ofPIF);
  1197. if (ppl->ofPIF.nErrCode == ERROR_FILE_NOT_FOUND) { // try PATH
  1198. ppl->hPIF = OpenPIFFile(g_szDefaultPIF, &ppl->ofPIF);
  1199. }
  1200. } else { // Look in cached path
  1201. // We've already found it once, so just open it
  1202. ppl->hPIF = OpenPIFFile(g_szDefaultPIF, &ppl->ofPIF);
  1203. }
  1204. }
  1205. if (ppl->hPIF != INVALID_HANDLE_VALUE) {
  1206. ppl->flProp |= PROP_DEFAULTPIF;
  1207. // Save the fully-qualified pathname of the default PIF file,
  1208. // so that subsequent OpenFile() calls will be faster (note that
  1209. // we don't specify OF_SEARCH on that particular call)
  1210. StringCchCopy(g_szDefaultPIF, ARRAYSIZE(g_szDefaultPIF), ppl->ofPIF.szPathName);
  1211. }
  1212. else {
  1213. // Not only could we not open any sort of PIF, we also need to
  1214. // tell GetPIFData to not bother trying to open the file itself
  1215. // (since it is unlikely someone created one in this short time)
  1216. ppl->flProp |= PROP_NOPIF | PROP_SKIPPIF;
  1217. if (ppl->ofPIF.nErrCode == ERROR_FILE_NOT_FOUND)
  1218. g_szDefaultPIF[0] = 0; // Invalidate cache.
  1219. }
  1220. // NOW we can set ppl->ofPIF.szPathName to the filename we REALLY
  1221. // wanted, since we're done with all the calls to OpenPIFFile.
  1222. StringCchCopy(ppl->ofPIF.szPathName, ARRAYSIZE(ppl->ofPIF.szPathName), pszFullName);
  1223. }
  1224. // Initialize the properties by PIF if we have one, by hand if not
  1225. IgnorePIF:
  1226. // We don't need to check the return code from GetPIFData() here,
  1227. // because we validate hPIFData below anyway. Please also note that
  1228. // this GetPIFData call uses the handle we supplied (if any), and closes
  1229. // it for us when it's done. Furthermore, if we didn't supply a handle,
  1230. // then we should have set PROP_SKIPPIF, so that GetPIFData won't try to
  1231. // open anything (since we just tried!)
  1232. GetPIFData(ppl, FALSE);
  1233. // Now that the original file from which we obtained settings (if any) is
  1234. // closed, we need to see if the caller wants us to create a new PIF file
  1235. // using a specific name. If so, force it to be created now.
  1236. if (lpszPIF) {
  1237. StringCchCopy(ppl->ofPIF.szPathName, ARRAYSIZE(ppl->ofPIF.szPathName), lpszPIF);
  1238. ppl->flProp |= PROP_DIRTY;
  1239. ppl->flProp &= ~PROP_NOCREATEPIF;
  1240. fError = !FlushPIFData(ppl, FALSE);
  1241. }
  1242. // Apply INF data to the PIF data we just retrieved, as appropriate,
  1243. // as long as it's an app file and not a PIF file (and if, in the case of
  1244. // creating a specific PIF, we were actually able to create one).
  1245. if (!fError && !fExplicitPIF && (hInf != -1)) {
  1246. if (PifMgr_GetProperties(ppl, MAKELP(0,GROUP_PRG),
  1247. &prg, sizeof(prg), GETPROPS_NONE)) {
  1248. // In the PRGINIT_AMBIGUOUSPIF case, GetAppsInfData must
  1249. // again look for a matching entry; however, if the entry it
  1250. // finds is the same as what we've already got (based on Other
  1251. // File), then it will leave the PIF data alone (ie, it doesn't
  1252. // reinitialize it, it doesn't call AppWiz to silently
  1253. // reconfigure it, etc).
  1254. if (fSearchInf || (prg.flPrgInit & PRGINIT_AMBIGUOUSPIF)) {
  1255. if (PifMgr_GetProperties(ppl, MAKELP(0,GROUP_NT40),
  1256. &nt40, sizeof(nt40), GETPROPS_NONE)) {
  1257. if (!GetAppsInfData(ppl, &prg, &nt40, (HINF)IntToPtr( hInf ), lpszApp, fFixedDisk, flOpt)) {
  1258. // When GetAppsInfData fails and the PIF is ambiguous, then
  1259. // we need to restart the PIF search process at the point where
  1260. // it searches for _DEFAULT.PIF, so that the ambiguous PIF is
  1261. // effectively ignored now.
  1262. // Also, we avoid the ugly possibility of getting to this
  1263. // point again and infinitely jumping back FindDefault, by
  1264. // only jumping if fSearchInf was FALSE. FindDefault sets
  1265. // it to TRUE.
  1266. if (!fSearchInf && (prg.flPrgInit & PRGINIT_AMBIGUOUSPIF)) {
  1267. goto FindDefault;
  1268. }
  1269. #ifdef DBCS
  1270. if (GetSystemDefaultLangID() == 0x0411) {
  1271. ZeroMemory(&env, sizeof(env));
  1272. StringCchCopyA(env.achBatchFile, ARRAYSIZE(env.achBatchFile), ImeBatchFile);
  1273. PifMgr_SetProperties(ppl, MAKELP(0,GROUP_ENV),
  1274. &env, sizeof(env), SETPROPS_NONE);
  1275. }
  1276. #endif
  1277. }
  1278. }
  1279. }
  1280. }
  1281. }
  1282. Error:
  1283. LocalFree(pszFullName);
  1284. if (fError || !ppl->lpPIFData) {
  1285. PifMgr_CloseProperties(ppl, 0);
  1286. return 0;
  1287. }
  1288. // We should never leave PIFMGR with outstanding locks
  1289. ASSERTTRUE(!ppl->cLocks);
  1290. return ppl;
  1291. }
  1292. /** PifMgr_GetProperties - get property info by name
  1293. *
  1294. * INPUT
  1295. * hProps = handle to properties
  1296. * lpszGroup -> property group; may be one of the following:
  1297. * "WINDOWS 286 3.0"
  1298. * "WINDOWS 386 3.0"
  1299. * "WINDOWS VMM 4.0"
  1300. * "WINDOWS NT 3.1"
  1301. * "WINDOWS NT 4.0"
  1302. * or any other group name that is the name of a valid PIF extension;
  1303. * if NULL, then cbProps is a 0-based index of a named group, and lpProps
  1304. * must point to a 16-byte buffer to receive the name of the group (this
  1305. * enables the caller to enumerate the names of all the named groups)
  1306. * lpProps -> property group record to receive the data
  1307. * cbProps = size of property group record to get; if cbProps is zero
  1308. * and a named group is requested, lpProps is ignored, no data is copied,
  1309. * and the size of the group record is returned (this enables the caller
  1310. * to determine the size of a named group)
  1311. * flOpt = GETPROPS_RAWIO to perform raw file read (lpszGroup ignored)
  1312. *
  1313. * Alternatively, if the high word (selector) of lpszGroup is 0, the low
  1314. * word must be a group ordinal (eg, GROUP_PRG, GROUP_TSK, etc)
  1315. *
  1316. * OUTPUT
  1317. * If the group is not found, or an error occurs, 0 is returned.
  1318. * Otherwise, the size of the group info transferred in bytes is returned.
  1319. */
  1320. int WINAPI PifMgr_GetProperties(HANDLE hProps, LPCSTR lpszGroup, void *lpProps, int cbProps, UINT flOpt)
  1321. {
  1322. int cb, i;
  1323. void *lp;
  1324. LPW386PIF30 lp386;
  1325. LPWENHPIF40 lpenh;
  1326. LPWNTPIF40 lpnt40;
  1327. LPWNTPIF31 lpnt31;
  1328. PPROPLINK ppl;
  1329. FunctionName(PifMgr_GetProperties);
  1330. cb = 0;
  1331. if (!(ppl = ValidPropHandle(hProps)))
  1332. return cb;
  1333. // We should never enter PIFMGR with outstanding locks (we also call
  1334. // here from *inside* PIFMGR, but none of those cases should require a
  1335. // lock either)
  1336. ASSERTTRUE(!ppl->cLocks);
  1337. ppl->cLocks++;
  1338. if (flOpt & GETPROPS_RAWIO) {
  1339. if (ppl->flProp & PROP_RAWIO) {
  1340. cb = min(ppl->cbPIFData, cbProps);
  1341. hmemcpy(lpProps, ppl->lpPIFData, cb);
  1342. }
  1343. ppl->cLocks--;
  1344. return cb;
  1345. }
  1346. if (!lpszGroup) {
  1347. if (lpProps) {
  1348. lp = GetGroupData(ppl, NULL, &cbProps, NULL);
  1349. if (lp) {
  1350. cb = cbProps;
  1351. hmemcpy(lpProps, lp, PIFEXTSIGSIZE);
  1352. }
  1353. }
  1354. }
  1355. else if (IS_INTRESOURCE(lpszGroup) && lpProps) {
  1356. // Special case: if GROUP_ICON, then do a nested call to
  1357. // PifMgr_GetProperties to get GROUP_PRG data, then feed it to load
  1358. // LoadPIFIcon, and finally return the hIcon, if any, to the user.
  1359. if (LOWORD((DWORD_PTR) lpszGroup) == GROUP_ICON) {
  1360. PPROPPRG pprg;
  1361. PPROPNT40 pnt40 = (void *)LocalAlloc(LPTR, sizeof(PROPNT40));
  1362. if ( pnt40 ) {
  1363. pprg = (void *)LocalAlloc(LPTR, sizeof(PROPPRG));
  1364. if (pprg) {
  1365. if ( PifMgr_GetProperties(ppl, MAKELP(0,GROUP_PRG), pprg, sizeof(PROPPRG), GETPROPS_NONE)
  1366. && PifMgr_GetProperties(ppl, MAKELP(0,GROUP_NT40), pnt40, sizeof(PROPNT40), GETPROPS_NONE) ) {
  1367. *(HICON *)lpProps = LoadPIFIcon(pprg, pnt40);
  1368. cb = 2;
  1369. }
  1370. EVAL(LocalFree(pprg) == NULL);
  1371. }
  1372. EVAL(LocalFree(pnt40) == NULL);
  1373. }
  1374. }
  1375. else {
  1376. lp386 = GetGroupData(ppl, szW386HDRSIG30, NULL, NULL);
  1377. lpenh = GetGroupData(ppl, szWENHHDRSIG40, NULL, NULL);
  1378. lpnt40 = GetGroupData(ppl, szWNTHDRSIG40, NULL, NULL);
  1379. lpnt31 = GetGroupData(ppl, szWNTHDRSIG31, NULL, NULL);
  1380. //
  1381. // Fix anything from down-level PIF files. Since this
  1382. // is the first revision of the WENHPIF40 format, we
  1383. // don't have anything to worry about (yet).
  1384. //
  1385. // Don't muck with PIF files from the future!
  1386. //
  1387. if (lpenh && lpenh->wInternalRevision != WENHPIF40_VERSION) {
  1388. lpenh->wInternalRevision = WENHPIF40_VERSION;
  1389. ppl->flProp |= PROP_DIRTY;
  1390. //
  1391. // Old (pre-M7) PIFs did not zero-initialize the reserved
  1392. // fields of PIF files, so zero them out now.
  1393. //
  1394. lpenh->tskProp.wReserved1 = 0;
  1395. lpenh->tskProp.wReserved2 = 0;
  1396. lpenh->tskProp.wReserved3 = 0;
  1397. lpenh->tskProp.wReserved4 = 0;
  1398. lpenh->vidProp.wReserved1 = 0;
  1399. lpenh->vidProp.wReserved2 = 0;
  1400. lpenh->vidProp.wReserved3 = 0;
  1401. lpenh->envProp.wMaxDPMI = 0;
  1402. // Turn off bits that have been deleted during the development
  1403. // cycle.
  1404. lpenh->envProp.flEnv = 0;
  1405. lpenh->envProp.flEnvInit = 0;
  1406. if (lp386)
  1407. lp386->PfW386Flags &= ~0x00400000;
  1408. }
  1409. // End of "Remove this after M8"
  1410. // Zero the input buffer first, so that the Get* functions
  1411. // need not initialize every byte to obtain consistent results
  1412. BZero(lpProps, cbProps);
  1413. // The GetData functions CANNOT rely on either lp386 or lpenh
  1414. i = LOWORD((DWORD_PTR) lpszGroup)-1;
  1415. if (i >= 0 && i < ARRAYSIZE(afnGetData) && cbProps >= acbData[i]) {
  1416. void *aDataPtrs[NUM_DATA_PTRS];
  1417. aDataPtrs[ LP386_INDEX ] = (LPVOID)lp386;
  1418. aDataPtrs[ LPENH_INDEX ] = (LPVOID)lpenh;
  1419. aDataPtrs[ LPNT40_INDEX ] = (LPVOID)lpnt40;
  1420. aDataPtrs[ LPNT31_INDEX ] = (LPVOID)lpnt31;
  1421. cb = (afnGetData[i])(ppl, aDataPtrs, lpProps, cbProps, flOpt );
  1422. }
  1423. }
  1424. }
  1425. else if (NULL != (lp = GetGroupData(ppl, lpszGroup, &cb, NULL))) {
  1426. if (lpProps && cbProps != 0) {
  1427. cb = min(cb, cbProps);
  1428. hmemcpy(lpProps, lp, cb);
  1429. }
  1430. }
  1431. ppl->cLocks--;
  1432. #ifdef EXTENDED_DATA_SUPPORT
  1433. // Note that for GETPROPS_EXTENDED, both the normal and extended
  1434. // sections are returned, and that the return code reflects the success
  1435. // or failure of reading the normal portion only. We return both because
  1436. // that's the most convenient thing to do for the caller.
  1437. if (flOpt & GETPROPS_EXTENDED) {
  1438. if (ppl->hVM) {
  1439. WORD wGroup = EXT_GROUP_QUERY;
  1440. if (!HIWORD(lpszGroup) && LOWORD(lpszGroup) <= MAX_GROUP)
  1441. wGroup |= LOWORD(lpszGroup);
  1442. GetSetExtendedData(ppl->hVM, wGroup, lpszGroup, lpProps);
  1443. }
  1444. }
  1445. #endif
  1446. // We should never leave PIFMGR with outstanding locks (we also call
  1447. // here from *inside* PIFMGR, but none of those cases should require a
  1448. // lock either)
  1449. ASSERTTRUE(!ppl->cLocks);
  1450. return cb;
  1451. }
  1452. /** PifMgr_SetProperties - set property info by name
  1453. *
  1454. * INPUT
  1455. * hProps = handle to properties
  1456. * lpszGroup -> property group; may be one of the following:
  1457. * "WINDOWS 286 3.0"
  1458. * "WINDOWS 386 3.0"
  1459. * "WINDOWS PIF.400"
  1460. * or any other group name that is the name of a valid PIF extension
  1461. * lpProps -> property group record to copy the data from
  1462. * cbProps = size of property group record to set; if cbProps is
  1463. * zero and lpszGroup is a group name, the group will be removed
  1464. * flOpt = SETPROPS_RAWIO to perform raw file write (lpszGroup ignored)
  1465. * SETPROPS_CACHE to cache changes until properties are closed
  1466. *
  1467. * Alternatively, if the high word (selector) of lpszGroup is 0, the low
  1468. * word must be a group ordinal (eg, GROUP_PRG, GROUP_TSK, etc)
  1469. *
  1470. * OUTPUT
  1471. * If the group is not found, or an error occurs, 0 is returned.
  1472. * Otherwise, the size of the group info transferred in bytes is returned.
  1473. */
  1474. int WINAPI PifMgr_SetProperties(HANDLE hProps, LPCSTR lpszGroup, void *lpProps, int cbProps, UINT flOpt)
  1475. {
  1476. void *p = NULL;
  1477. void *lp = NULL;
  1478. LPW386PIF30 lp386;
  1479. LPWENHPIF40 lpenh;
  1480. LPWNTPIF40 lpnt40;
  1481. LPWNTPIF31 lpnt31;
  1482. int i, cb = 0;
  1483. PPROPLINK ppl;
  1484. FunctionName(PifMgr_SetProperties);
  1485. // Can't set a NULL name (nor set-by-index)--causes squirlly behavior in RemoveGroupData
  1486. if (!lpProps || !lpszGroup)
  1487. return 0;
  1488. ppl = ValidPropHandle(hProps);
  1489. if (!ppl)
  1490. return 0;
  1491. // We should never enter PIFMGR with outstanding locks (we also call
  1492. // here from *inside* PIFMGR, but none of those cases should require a
  1493. // lock either)
  1494. ASSERTTRUE(!ppl->cLocks);
  1495. if (flOpt & SETPROPS_RAWIO) {
  1496. if (ppl->flProp & PROP_RAWIO) {
  1497. ppl->cLocks++;
  1498. cb = min(ppl->cbPIFData, cbProps);
  1499. if (IsBufferDifferent(ppl->lpPIFData, lpProps, cb)) {
  1500. hmemcpy(ppl->lpPIFData, lpProps, cb);
  1501. ppl->flProp |= PROP_DIRTY;
  1502. }
  1503. if (cb < ppl->cbPIFData)
  1504. ppl->flProp |= PROP_DIRTY | PROP_TRUNCATE;
  1505. ppl->cbPIFData = cb;
  1506. ppl->cLocks--;
  1507. }
  1508. return cb;
  1509. }
  1510. #ifdef EXTENDED_DATA_SUPPORT
  1511. // Note that, unlike GETPROPS_EXTENDED, SETPROPS_EXTENDED only updates
  1512. // the extended section, and that the return code reflects the existence
  1513. // of a VM only. This is because there's a performance hit associated
  1514. // with setting the normal portion, and because the caller generally only
  1515. // wants to set one or the other.
  1516. if (flOpt & SETPROPS_EXTENDED) {
  1517. if (ppl->hVM) {
  1518. WORD wGroup = EXT_GROUP_UPDATE;
  1519. cb = cbProps;
  1520. if (!HIWORD(lpszGroup) && LOWORD(lpszGroup) <= MAX_GROUP)
  1521. wGroup |= LOWORD(lpszGroup);
  1522. GetSetExtendedData(ppl->hVM, wGroup, lpszGroup, lpProps);
  1523. }
  1524. return cb;
  1525. }
  1526. #endif
  1527. // For named groups, if the group does NOT exist, or DOES but is
  1528. // a different size, then we have to remove the old data, if any, and
  1529. // then add the new.
  1530. if (!IS_INTRESOURCE(lpszGroup)) {
  1531. cb = PifMgr_GetProperties(hProps, lpszGroup, NULL, 0, GETPROPS_NONE);
  1532. if (cb == 0 || cb != cbProps) {
  1533. if (cb) {
  1534. RemoveGroupData(ppl, lpszGroup);
  1535. cb = 0;
  1536. }
  1537. if (cbProps) {
  1538. if (AddGroupData(ppl, lpszGroup, lpProps, cbProps))
  1539. cb = cbProps;
  1540. }
  1541. goto done;
  1542. }
  1543. }
  1544. if (cbProps) {
  1545. if (!lpszGroup)
  1546. return cb;
  1547. p = (void *)LocalAlloc(LPTR, cbProps);
  1548. if (!p)
  1549. return cb;
  1550. }
  1551. cb = PifMgr_GetProperties(hProps, lpszGroup, p, cbProps, GETPROPS_NONE);
  1552. // If the group to set DOES exist, and if the data given is
  1553. // different, copy into the appropriate group(s) in the PIF data
  1554. if (cb != 0) {
  1555. cbProps = min(cb, cbProps);
  1556. if (IsBufferDifferent(p, lpProps, cbProps)) {
  1557. cb = 0;
  1558. ppl->cLocks++;
  1559. i = LOWORD((DWORD_PTR) lpszGroup)-1;
  1560. if (!IS_INTRESOURCE(lpszGroup)) {
  1561. lp = GetGroupData(ppl, lpszGroup, NULL, NULL);
  1562. if (lp) {
  1563. cb = cbProps;
  1564. hmemcpy(lp, lpProps, cbProps);
  1565. ppl->flProp |= PROP_DIRTY;
  1566. }
  1567. }
  1568. else if (i >= 0 && i < ARRAYSIZE(afnSetData) && cbProps >= acbData[i]) {
  1569. // Insure that both 386 and enhanced sections of PIF
  1570. // file are present. There are some exceptions: all
  1571. // groups from GROUP_MSE on up do not use the 386 section,
  1572. // and GROUP_MEM does not need the enh section....
  1573. lp386 = GetGroupData(ppl, szW386HDRSIG30, NULL, NULL);
  1574. if (i < GROUP_MSE-1 && !lp386) {
  1575. if (AddGroupData(ppl, szW386HDRSIG30, NULL, sizeof(W386PIF30))) {
  1576. lp386 = GetGroupData(ppl, szW386HDRSIG30, NULL, NULL);
  1577. if (!lp386) {
  1578. ASSERTFAIL();
  1579. cbProps = 0; // indicate error
  1580. }
  1581. }
  1582. }
  1583. if (cbProps) {
  1584. lpenh = GetGroupData(ppl, szWENHHDRSIG40, NULL, NULL);
  1585. if (i != GROUP_MEM-1 && !lpenh) {
  1586. if (!(lpenh = AddEnhancedData(ppl, lp386))) {
  1587. ASSERTFAIL();
  1588. cbProps = 0; // indicate error
  1589. }
  1590. }
  1591. lpnt40 = GetGroupData(ppl, szWNTHDRSIG40, NULL, NULL);
  1592. if (!lpnt40)
  1593. {
  1594. if (AddGroupData(ppl, szWNTHDRSIG40, NULL, sizeof(WNTPIF40)))
  1595. {
  1596. lpnt40 = GetGroupData(ppl, szWNTHDRSIG40, NULL, NULL);
  1597. }
  1598. }
  1599. ASSERT(lpnt40);
  1600. lpnt31 = GetGroupData(ppl, szWNTHDRSIG31, NULL, NULL);
  1601. if (!lpnt31)
  1602. {
  1603. if (AddGroupData(ppl, szWNTHDRSIG31, NULL, sizeof(WNTPIF31)))
  1604. {
  1605. if (NULL != (lpnt31 = GetGroupData(ppl, szWNTHDRSIG31, NULL, NULL))) {
  1606. StringCchCopyA( lpnt31->nt31Prop.achConfigFile, ARRAYSIZE(lpnt31->nt31Prop.achConfigFile), NT_CONFIG_FILE );
  1607. StringCchCopyA( lpnt31->nt31Prop.achAutoexecFile, ARRAYSIZE(lpnt31->nt31Prop.achAutoexecFile), NT_AUTOEXEC_FILE );
  1608. }
  1609. }
  1610. }
  1611. ASSERT(lpnt31);
  1612. }
  1613. if (cbProps)
  1614. {
  1615. void *aDataPtrs[NUM_DATA_PTRS];
  1616. //
  1617. // We need to re-establish the pointers because any of
  1618. // the AddGroupData's could have moved the block (via
  1619. // a HeapReAlloc call), so do that now...
  1620. //
  1621. lp386 = GetGroupData( ppl, szW386HDRSIG30, NULL, NULL );
  1622. lpenh = GetGroupData( ppl, szWENHHDRSIG40, NULL, NULL );
  1623. lpnt40 = GetGroupData( ppl, szWNTHDRSIG40, NULL, NULL );
  1624. lpnt31 = GetGroupData( ppl, szWNTHDRSIG31, NULL, NULL );
  1625. aDataPtrs[ LP386_INDEX ] = (LPVOID)lp386;
  1626. aDataPtrs[ LPENH_INDEX ] = (LPVOID)lpenh;
  1627. aDataPtrs[ LPNT40_INDEX ] = (LPVOID)lpnt40;
  1628. aDataPtrs[ LPNT31_INDEX ] = (LPVOID)lpnt31;
  1629. cb = (afnSetData[i])(ppl, aDataPtrs, lpProps, cbProps, flOpt );
  1630. }
  1631. }
  1632. ppl->cLocks--;
  1633. }
  1634. }
  1635. EVAL(LocalFree(p) == NULL);
  1636. done:
  1637. if (!(flOpt & SETPROPS_CACHE))
  1638. if (!FlushPIFData(ppl, FALSE))
  1639. cb = 0;
  1640. // We should never leave PIFMGR with outstanding locks (we also call
  1641. // here from *inside* PIFMGR, but none of those cases should require a
  1642. // lock either)
  1643. ASSERTTRUE(!ppl->cLocks);
  1644. return cb;
  1645. }
  1646. /** EnumProperties - enumerate open properties
  1647. *
  1648. * INPUT
  1649. * hProps = handle to previous properties (NULL to start)
  1650. *
  1651. * OUTPUT
  1652. * next property handle, 0 if none
  1653. */
  1654. HANDLE WINAPI EnumProperties(HANDLE hProps)
  1655. {
  1656. PPROPLINK ppl;
  1657. FunctionName(EnumProperties);
  1658. if (!hProps)
  1659. return g_pplHead;
  1660. if (!(ppl = ValidPropHandle(hProps)))
  1661. return NULL;
  1662. return ppl->pplNext;
  1663. }
  1664. /** PifMgr_CloseProperties - close property info for application
  1665. *
  1666. * INPUT
  1667. * hProps = handle to properties
  1668. * flOpt = CLOSEPROPS_DISCARD to abandon cached PIF data, otherwise save it
  1669. *
  1670. * OUTPUT
  1671. * NULL if successful, otherwise hProps is returned as given
  1672. */
  1673. HANDLE WINAPI PifMgr_CloseProperties(HANDLE hProps, UINT flOpt)
  1674. {
  1675. PPROPLINK ppl;
  1676. FunctionName(PifMgr_CloseProperties);
  1677. if (!(ppl = ValidPropHandle(hProps)))
  1678. return hProps;
  1679. // When discarding on a close, set the SKIPPIF flag, so that the
  1680. // flush code won't say "oh, not only should I throw away my current
  1681. // set of data, but I should read in clean data" -- new data is no use
  1682. // since the caller is closing.
  1683. if (flOpt & CLOSEPROPS_DISCARD)
  1684. ppl->flProp |= PROP_SKIPPIF;
  1685. if (ppl->flProp & PROP_DIRTY) { // this redundant check added
  1686. // to avoid making FlushPIFData PRELOAD -JTP
  1687. // Note that we avoid calling FlushPIFData if INHIBITPIF is set,
  1688. // since FlushPIFData will just return a fake TRUE result anyway.
  1689. // But we don't want to be fooled, we want to make sure the block
  1690. // gets unlocked now.
  1691. if ((ppl->flProp & PROP_INHIBITPIF) || !FlushPIFData(ppl, (flOpt & CLOSEPROPS_DISCARD))) {
  1692. // If FlushPIFData failed, then if we still have an outstanding
  1693. // dirty lock, force the data to become unlocked, by clearing the
  1694. // dirty flag in the middle of a pair otherwise pointless lock/unlock
  1695. // calls (because that's the nice, clean way to do it!)
  1696. if (ppl->flProp & PROP_DIRTYLOCK) {
  1697. ppl->cLocks++;
  1698. ppl->flProp &= ~PROP_DIRTY;
  1699. ppl->cLocks--;
  1700. }
  1701. }
  1702. }
  1703. if (ppl->lpPIFData) {
  1704. LocalFree(ppl->lpPIFData);
  1705. ppl->lpPIFData = NULL;
  1706. }
  1707. if (ppl->hPIF != INVALID_HANDLE_VALUE)
  1708. CloseHandle(ppl->hPIF);
  1709. // Unlink from the global list
  1710. if (ppl->pplPrev)
  1711. ppl->pplPrev->pplNext = ppl->pplNext;
  1712. else
  1713. g_pplHead = ppl->pplNext;
  1714. if (ppl->pplNext)
  1715. ppl->pplNext->pplPrev = ppl->pplPrev;
  1716. LocalFree(ppl);
  1717. return NULL;
  1718. }
  1719. /** ValidPropHandle - verify handle
  1720. *
  1721. * INPUT
  1722. * hProps = handle to properties
  1723. *
  1724. * OUTPUT
  1725. * pointer to prop, NULL otherwise
  1726. */
  1727. PPROPLINK ValidPropHandle(HANDLE hProps)
  1728. {
  1729. FunctionName(ValidPropHandle);
  1730. if (!hProps ||
  1731. (HANDLE)hProps > g_offHighestPropLink ||
  1732. ((PPROPLINK)hProps)->iSig != PROP_SIG) {
  1733. ASSERTFAIL();
  1734. return NULL;
  1735. }
  1736. return (PPROPLINK)hProps;
  1737. }
  1738. /** ResizePIFData - verify handle and resize PIF data
  1739. *
  1740. * INPUT
  1741. * ppl -> property
  1742. * cbResize = bytes to resize PIF data by
  1743. *
  1744. * OUTPUT
  1745. * previous size of PIF data if successful, -1 if not
  1746. *
  1747. * on success, the PIF data is returned LOCKED, so successful
  1748. * ResizePIFData calls should be matched with UnlockPIFData calls.
  1749. */
  1750. int ResizePIFData(PPROPLINK ppl, INT cbResize)
  1751. {
  1752. INT cbOld, cbNew;
  1753. void *lpNew;
  1754. BOOL fInitStdHdr = FALSE;
  1755. FunctionName(ResizePIFData);
  1756. ASSERTTRUE(cbResize != 0);
  1757. // Cope with empty or old PIF files
  1758. cbOld = ppl->cbPIFData;
  1759. cbNew = ppl->cbPIFData + cbResize;
  1760. if ((cbNew < cbOld) == (cbResize > 0))
  1761. return -1; // underflow/overflow
  1762. if (!ppl->lpPIFData && cbOld == 0) {
  1763. if (cbNew >= sizeof(STDPIF) + sizeof(PIFEXTHDR))
  1764. fInitStdHdr = TRUE;
  1765. lpNew = LocalAlloc(LPTR, cbNew);
  1766. }
  1767. else
  1768. {
  1769. if (cbOld == sizeof(STDPIF))
  1770. {
  1771. fInitStdHdr = TRUE;
  1772. cbOld += sizeof(PIFEXTHDR);
  1773. cbNew += sizeof(PIFEXTHDR);
  1774. }
  1775. lpNew = LocalReAlloc( ppl->lpPIFData, cbNew, LMEM_MOVEABLE|LMEM_ZEROINIT);
  1776. }
  1777. if (lpNew) {
  1778. ppl->cbPIFData = cbNew;
  1779. ppl->lpPIFData = (LPPIFDATA)lpNew;
  1780. ppl->cLocks++;
  1781. if (fInitStdHdr) {
  1782. StringCchCopyA(ppl->lpPIFData->stdpifext.extsig, ARRAYSIZE(ppl->lpPIFData->stdpifext.extsig), szSTDHDRSIG);
  1783. ppl->lpPIFData->stdpifext.extnxthdrfloff = LASTHDRPTR;
  1784. ppl->lpPIFData->stdpifext.extfileoffset = 0x0000;
  1785. ppl->lpPIFData->stdpifext.extsizebytes = sizeof(STDPIF);
  1786. }
  1787. return cbOld;
  1788. }
  1789. return -1;
  1790. }
  1791. /** GetPIFData - read PIF data back from PIF
  1792. *
  1793. * INPUT
  1794. * ppl -> property
  1795. * fLocked == TRUE to return data locked, FALSE unlocked
  1796. *
  1797. * OUTPUT
  1798. * TRUE if succeeded, FALSE if not
  1799. */
  1800. BOOL GetPIFData(PPROPLINK ppl, BOOL fLocked)
  1801. {
  1802. DWORD dwOff;
  1803. LPTSTR pszOpen;
  1804. BOOL fSuccess = FALSE;
  1805. FunctionName(GetPIFData);
  1806. // Since we're going to (re)load the property data now, reset
  1807. // the current size, so that ResizePIFData will resize it from zero
  1808. ppl->cbPIFData = 0;
  1809. // If SKIPPIF is set (eg, by PifMgr_OpenProperties), then don't
  1810. // try to open anything (since PifMgr_OpenProperties already tried!),
  1811. if (ppl->hPIF == INVALID_HANDLE_VALUE && !(ppl->flProp & PROP_SKIPPIF)) {
  1812. pszOpen = g_szDefaultPIF;
  1813. if (!(ppl->flProp & PROP_DEFAULTPIF))
  1814. pszOpen = ppl->ofPIF.szPathName;
  1815. ppl->hPIF = CreateFile( pszOpen,
  1816. GENERIC_READ | GENERIC_WRITE,
  1817. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1818. NULL,
  1819. OPEN_EXISTING,
  1820. FILE_ATTRIBUTE_NORMAL,
  1821. NULL );
  1822. }
  1823. if (ppl->hPIF == INVALID_HANDLE_VALUE) {
  1824. // The following warning is disabled because the presence of
  1825. // the dialog box got WINOLDAP stuck in an infinite message loop -JTP
  1826. InitProperties(ppl, fLocked);
  1827. goto Exit;
  1828. }
  1829. dwOff = SetFilePointer(ppl->hPIF, 0, NULL, FILE_END);
  1830. if (dwOff >= sizeof(STDPIF)) {
  1831. ppl->flProp |= PROP_REGEN;
  1832. if (ResizePIFData(ppl, dwOff) != -1) {
  1833. SetFilePointer(ppl->hPIF, 0, NULL, FILE_BEGIN);
  1834. if (ReadFile( ppl->hPIF, ppl->lpPIFData,
  1835. ppl->cbPIFData, &ppl->cbPIFData, NULL ))
  1836. {
  1837. // Can't be dirty anymore, 'cause we just read the PIF back in
  1838. ppl->flProp &= ~PROP_DIRTY;
  1839. if (ppl->flProp & PROP_DEFAULTPIF) {
  1840. WideCharToMultiByte( CP_ACP, 0,
  1841. ppl->szPathName+ppl->iFileName,
  1842. -1,
  1843. ppl->lpPIFData->stdpifdata.appname,
  1844. ARRAYSIZE(ppl->lpPIFData->stdpifdata.appname),
  1845. NULL, NULL
  1846. );
  1847. PifMgr_WCtoMBPath( ppl->szPathName,
  1848. ppl->lpPIFData->stdpifdata.startfile,
  1849. ARRAYSIZE(ppl->lpPIFData->stdpifdata.startfile)
  1850. );
  1851. // I don't think this is generally worth dirtying the
  1852. // property info for, because otherwise every app that used
  1853. // _DEFAULT.PIF initially would get its own PIF file created
  1854. // later; PIF file creation should only take place when
  1855. // substantive changes have been made
  1856. // ppl->flProp |= PROP_DIRTY;
  1857. }
  1858. // If we're not dealing with an enhanced PIF, then we
  1859. // go to the various INI files to retrieve DOS app defaults
  1860. if (!GetGroupData(ppl, szWENHHDRSIG40, NULL, NULL)) {
  1861. GetINIData();
  1862. }
  1863. // If we're not dealing with a new NT/UNICODE PIF, then
  1864. // we add a new section so it's ALWAYS there when we're
  1865. // UNICODE enabled.
  1866. if (!GetGroupData(ppl, szWNTHDRSIG40, NULL, NULL)) {
  1867. VERIFYTRUE(AddGroupData(ppl, szWNTHDRSIG40, NULL, sizeof(WNTPIF40)));
  1868. }
  1869. // If we're not dealing with a NT PIF, then
  1870. // we add the NT sections so it's ALWAYS there when we're
  1871. // running on NT.
  1872. if (!GetGroupData(ppl, szWNTHDRSIG31, NULL, NULL)) {
  1873. LPWNTPIF31 lpnt31;
  1874. VERIFYTRUE(AddGroupData(ppl, szWNTHDRSIG31, NULL, sizeof(WNTPIF31)));
  1875. if (NULL != (lpnt31 = GetGroupData(ppl, szWNTHDRSIG31, NULL, NULL))) {
  1876. StringCchCopyA( lpnt31->nt31Prop.achConfigFile, ARRAYSIZE(lpnt31->nt31Prop.achConfigFile), NT_CONFIG_FILE );
  1877. StringCchCopyA( lpnt31->nt31Prop.achAutoexecFile, ARRAYSIZE(lpnt31->nt31Prop.achAutoexecFile), NT_AUTOEXEC_FILE );
  1878. }
  1879. }
  1880. if (!fLocked)
  1881. ppl->cLocks--; // UnlockPIFData(ppl);
  1882. fSuccess++;
  1883. }
  1884. }
  1885. else
  1886. ASSERTFAIL();
  1887. ppl->flProp &= ~PROP_REGEN;
  1888. }
  1889. CloseHandle(ppl->hPIF);
  1890. ppl->hPIF = INVALID_HANDLE_VALUE;
  1891. // As long as IGNOREPIF isn't set, clear SKIPPIF, because even if we
  1892. // already knew the PIF didn't exist on *this* call, one may be created
  1893. // (by someone else) by the next time we're called
  1894. Exit:
  1895. if (!(ppl->flProp & PROP_IGNOREPIF))
  1896. ppl->flProp &= ~PROP_SKIPPIF;
  1897. return fSuccess;
  1898. }
  1899. /** FlushPIFData - write dirty PIF data back to PIF
  1900. *
  1901. * INPUT
  1902. * ppl -> property
  1903. * fDiscard == TRUE to discard dirty data, FALSE to keep it
  1904. *
  1905. * OUTPUT
  1906. * TRUE if succeeded, FALSE if not
  1907. *
  1908. * NOTES
  1909. * We must first check the PROPLINK and see if the DONTWRITE bit has
  1910. * been set, in which case we have to fail the flush. Once DONTWRITE is
  1911. * set in a PROPLINK, it will never be cleared, unless the caller
  1912. * specifies fDiscard == TRUE to reload the data. This is BY DESIGN (ie,
  1913. * a UI compromise). How does DONTWRITE get set? By someone else
  1914. * having previously (and successfully) done a flush to the same PIF; at
  1915. * that point in time, we will look for all other properties that refer to
  1916. * the same file, and set their DONTWRITE bit. What about PROPLINKs that
  1917. * are created later? They're ok, they don't get DONTWRITE set until
  1918. * the above sequence takes place during their lifetime.
  1919. */
  1920. BOOL FlushPIFData(PPROPLINK ppl, BOOL fDiscard)
  1921. {
  1922. UINT u;
  1923. BOOL fSuccess = FALSE;
  1924. FunctionName(FlushPIFData);
  1925. // If nothing dirty, nothing to do
  1926. if (!(ppl->flProp & PROP_DIRTY) || (ppl->flProp & PROP_INHIBITPIF))
  1927. return TRUE; // ie, success
  1928. // If discarding, then clear PROP_DIRTY and reload the data
  1929. if (fDiscard) {
  1930. ppl->flProp &= ~(PROP_DIRTY | PROP_DONTWRITE);
  1931. return GetPIFData(ppl, FALSE);
  1932. }
  1933. if (ppl->flProp & PROP_DONTWRITE)
  1934. return fSuccess; // ie, FALSE (error)
  1935. if (!ppl->lpPIFData)
  1936. return fSuccess; // ie, FALSE (error)
  1937. ppl->cLocks++;
  1938. // If we created properties without opening a file, it may have
  1939. // been because normal PIF search processing was overridden by the
  1940. // presence of a WIN.INI entry; if that entry is still there,
  1941. // then our data is not in sync with any existing file, nor is there
  1942. // any point in creating a new file as long as that entry exists. We
  1943. // need to consider prompting the user as to whether he really wants
  1944. // that WIN.INI entry, so that it's clear what the heck is going on
  1945. if (ppl->flProp & PROP_IGNOREPIF) {
  1946. HANDLE hProps;
  1947. ppl->ckbMem = GetProfileInt(apszAppType[APPTYPE_PIF]+1, ppl->szPathName+ppl->iFileName, -1);
  1948. if (ppl->ckbMem != -1)
  1949. goto Exit;
  1950. // The WIN.INI entry apparently went away, so let's re-attempt to
  1951. // open the properties that we should have obtained in the first
  1952. // place. Assuming success, we will copy our entire block on top of
  1953. // them (thereby flushing it), and also copy their PIF name to our
  1954. // PIF name and their PIF flags to our PIF flags, so that future
  1955. // flushes are of the more normal variety
  1956. hProps = PifMgr_OpenProperties(ppl->ofPIF.szPathName, NULL, 0, OPENPROPS_RAWIO);
  1957. if (hProps) {
  1958. ppl->flProp &= ~(PROP_IGNOREPIF | PROP_SKIPPIF);
  1959. ppl->flProp |= ((PPROPLINK)hProps)->flProp & (PROP_IGNOREPIF | PROP_SKIPPIF);
  1960. StringCchCopy(ppl->ofPIF.szPathName, ARRAYSIZE(ppl->ofPIF.szPathName), ((PPROPLINK)hProps)->ofPIF.szPathName);
  1961. if (PifMgr_SetProperties(hProps, NULL, ppl->lpPIFData, ppl->cbPIFData, SETPROPS_RAWIO) == ppl->cbPIFData) {
  1962. fSuccess++;
  1963. ppl->flProp &= ~(PROP_DIRTY | PROP_TRUNCATE);
  1964. }
  1965. PifMgr_CloseProperties(hProps, CLOSEPROPS_NONE);
  1966. }
  1967. goto Exit;
  1968. }
  1969. // Disable annoying critical error popups (NO MORE GOTOS PAST HERE PLEASE)
  1970. u = SetErrorMode(SEM_FAILCRITICALERRORS);
  1971. ppl->hPIF = CreateFile( ppl->ofPIF.szPathName,
  1972. GENERIC_READ | GENERIC_WRITE,
  1973. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1974. NULL,
  1975. OPEN_ALWAYS,
  1976. FILE_ATTRIBUTE_NORMAL,
  1977. NULL );
  1978. // If we couldn't open the file, then the presumption is that the
  1979. // app didn't have a PIF (or did but someone but someone deleted it),
  1980. // and so we use the name we constructed during PifMgr_OpenProperties in case
  1981. // they ever opted to save new settings (which they obviously have done!)
  1982. // 28-Feb-95: If the PIF did exist at one time (meaning NOCREATPIF is
  1983. // set), then don't recreate it; somebody's trying to delete their own
  1984. // PIF, so let them. -JTP
  1985. if ((ppl->hPIF != INVALID_HANDLE_VALUE) && (GetLastError()!=ERROR_FILE_EXISTS)) {
  1986. if (!(ppl->flProp & PROP_NOCREATEPIF))
  1987. SetFilePointer( ppl->hPIF, 0, NULL, FILE_BEGIN );
  1988. // If the create succeeded, we're no longer using the default PIF
  1989. if (ppl->hPIF != INVALID_HANDLE_VALUE) {
  1990. ppl->flProp |= PROP_NOCREATEPIF;
  1991. ppl->flProp &= ~(PROP_TRUNCATE | PROP_NOPIF | PROP_DEFAULTPIF);
  1992. }
  1993. }
  1994. // If either the open or the create succeeded, write the PIF data out now
  1995. if (ppl->hPIF != INVALID_HANDLE_VALUE) {
  1996. PPROPLINK pplEnum;
  1997. DWORD dwDummy;
  1998. WriteFile( ppl->hPIF, (LPCVOID)ppl->lpPIFData,
  1999. ppl->cbPIFData, &dwDummy, NULL );
  2000. if (ppl->flProp & PROP_TRUNCATE)
  2001. WriteFile(ppl->hPIF, (LPCVOID)ppl->lpPIFData, 0, &dwDummy, NULL );
  2002. CloseHandle(ppl->hPIF);
  2003. ppl->hPIF = INVALID_HANDLE_VALUE;
  2004. ppl->flProp &= ~(PROP_DIRTY | PROP_TRUNCATE);
  2005. fSuccess++;
  2006. // Here's where we want to check for other active PROPLINKs using the
  2007. // same PIF. For each one found, set its DONTWRITE bit.
  2008. pplEnum = NULL;
  2009. while (NULL != (pplEnum = (PPROPLINK)EnumProperties(pplEnum))) {
  2010. if (lstrcmpi(ppl->ofPIF.szPathName, pplEnum->ofPIF.szPathName) == 0) {
  2011. if (pplEnum != ppl)
  2012. pplEnum->flProp |= PROP_DONTWRITE;
  2013. }
  2014. }
  2015. }
  2016. // Re-enable annoying critical error popups
  2017. SetErrorMode(u);
  2018. Exit:
  2019. ppl->cLocks--;
  2020. return fSuccess;
  2021. }
  2022. /** AddEnhancedData - create enhanced section(s) of PIF data
  2023. *
  2024. * INPUT
  2025. * ppl -> property
  2026. *
  2027. * OUTPUT
  2028. * lpenh or NULL
  2029. */
  2030. LPWENHPIF40 AddEnhancedData(PPROPLINK ppl, LPW386PIF30 lp386)
  2031. {
  2032. PROPPRG prg;
  2033. PROPTSK tsk;
  2034. PROPVID vid;
  2035. PROPKBD kbd;
  2036. PROPMSE mse;
  2037. PROPFNT fnt;
  2038. PROPWIN win;
  2039. PROPENV env;
  2040. void *aDataPtrs[NUM_DATA_PTRS];
  2041. LPWENHPIF40 lpenh = NULL;
  2042. FunctionName(AddEnhancedData);
  2043. // Get copies of pre-enhanced and/or default settings first,
  2044. // and do them all *before* doing the AddGroupData, because the
  2045. // functions' behavior will change once the enhanced section is added;
  2046. // in addition, zero those strucs that contain strings, since lstrcpy()
  2047. // may initialize a minimum of 1 byte, leaving garbage in the rest.
  2048. BZero(&prg, sizeof(prg));
  2049. BZero(&fnt, sizeof(fnt));
  2050. BZero(&win, sizeof(win));
  2051. BZero(&env, sizeof(env));
  2052. BZero(aDataPtrs, sizeof(aDataPtrs));
  2053. aDataPtrs[ LP386_INDEX ] = (LPVOID)lp386;
  2054. GetPrgData(ppl, aDataPtrs, &prg, sizeof(prg), GETPROPS_NONE);
  2055. GetTskData(ppl, aDataPtrs, &tsk, sizeof(tsk), GETPROPS_NONE);
  2056. GetVidData(ppl, aDataPtrs, &vid, sizeof(vid), GETPROPS_NONE);
  2057. GetKbdData(ppl, aDataPtrs, &kbd, sizeof(kbd), GETPROPS_NONE);
  2058. GetMseData(ppl, aDataPtrs, &mse, sizeof(mse), GETPROPS_NONE);
  2059. GetFntData(ppl, aDataPtrs, &fnt, sizeof(fnt), GETPROPS_NONE);
  2060. GetWinData(ppl, aDataPtrs, &win, sizeof(win), GETPROPS_NONE);
  2061. GetEnvData(ppl, aDataPtrs, &env, sizeof(env), GETPROPS_NONE);
  2062. if (AddGroupData(ppl, szWENHHDRSIG40, NULL, sizeof(WENHPIF40))) {
  2063. if (NULL != (lpenh = GetGroupData(ppl, szWENHHDRSIG40, NULL, NULL))) {
  2064. lpenh->dwEnhModeFlagsProp = prg.dwEnhModeFlags;
  2065. lpenh->dwRealModeFlagsProp = prg.dwRealModeFlags;
  2066. StringCchCopyA(lpenh->achOtherFileProp, ARRAYSIZE(lpenh->achOtherFileProp), prg.achOtherFile);
  2067. StringCchCopyA(lpenh->achIconFileProp, ARRAYSIZE(lpenh->achIconFileProp), prg.achIconFile);
  2068. lpenh->wIconIndexProp = prg.wIconIndex;
  2069. lpenh->tskProp = tsk;
  2070. lpenh->vidProp = vid;
  2071. lpenh->kbdProp = kbd;
  2072. lpenh->mseProp = mse;
  2073. lpenh->fntProp = fnt;
  2074. lpenh->winProp = win;
  2075. lpenh->envProp = env;
  2076. lpenh->wInternalRevision = WENHPIF40_VERSION;
  2077. }
  2078. }
  2079. return lpenh;
  2080. }
  2081. /** AddGroupData - add NEW property group to PIF data
  2082. *
  2083. * INPUT
  2084. * ppl -> property
  2085. * lpszGroup -> name of new group
  2086. * lpGroup -> new group record (if NULL, then group data is zero-filled)
  2087. * cbGroup == size of new group record
  2088. *
  2089. * OUTPUT
  2090. * TRUE if successful, FALSE if not
  2091. */
  2092. BOOL AddGroupData(PPROPLINK ppl, LPCSTR lpszGroup, LPCVOID lpGroup, int cbGroup)
  2093. {
  2094. INT cbOld;
  2095. LPPIFEXTHDR lpph;
  2096. FunctionName(AddGroupData);
  2097. if ((cbOld = ResizePIFData(ppl, cbGroup+sizeof(PIFEXTHDR))) != -1) {
  2098. lpph = (LPPIFEXTHDR)LPPIF_FIELDOFF(stdpifext);
  2099. while ((DWORD_PTR)lpph <= (DWORD_PTR)LPPIF_OFF(cbOld - sizeof(PIFEXTHDR)) &&
  2100. (DWORD_PTR)lpph >= (DWORD_PTR)LPPIF_FIELDOFF(stdpifext)) {
  2101. if (lpph->extnxthdrfloff == LASTHDRPTR) {
  2102. lpph->extnxthdrfloff = (WORD) cbOld;
  2103. lpph = (LPPIFEXTHDR)LPPIF_OFF(cbOld);
  2104. StringCchCopyA(lpph->extsig, ARRAYSIZE(lpph->extsig), lpszGroup);
  2105. lpph->extnxthdrfloff = LASTHDRPTR;
  2106. lpph->extfileoffset = (INT)(cbOld + sizeof(PIFEXTHDR));
  2107. lpph->extsizebytes = (WORD) cbGroup;
  2108. if (lpGroup) {
  2109. hmemcpy((LPBYTE)LPPH_OFF(sizeof(PIFEXTHDR)), lpGroup, cbGroup);
  2110. ppl->flProp |= PROP_DIRTY;
  2111. }
  2112. break;
  2113. }
  2114. lpph = (LPPIFEXTHDR)LPPIF_OFF(lpph->extnxthdrfloff);
  2115. }
  2116. ppl->cLocks--;
  2117. return TRUE;
  2118. }
  2119. ASSERTFAIL();
  2120. return FALSE;
  2121. }
  2122. /** RemoveGroupData - remove EXISTING property group from PIF data
  2123. *
  2124. * INPUT
  2125. * ppl -> property
  2126. * lpszGroup -> name of group
  2127. *
  2128. * OUTPUT
  2129. * TRUE if successful, FALSE if not
  2130. */
  2131. BOOL RemoveGroupData(PPROPLINK ppl, LPCSTR lpszGroup)
  2132. {
  2133. INT cbGroup, fSuccess;
  2134. LPBYTE lpGroup;
  2135. WORD extnxthdrfloff;
  2136. LPPIFEXTHDR lpph, lpphGroup;
  2137. FunctionName(RemoveGroupData);
  2138. ppl->cLocks++;
  2139. fSuccess = FALSE;
  2140. if (NULL != (lpGroup = GetGroupData(ppl, lpszGroup, &cbGroup, &lpphGroup))) {
  2141. // Removing groups is a bit tedious, so here goes....
  2142. // First, we will walk all the headers, attempting to find the
  2143. // one that points to the one we're about to remove, and point it
  2144. // to the next one, and at the same time adjust all file offsets that
  2145. // equal or exceed the offsets of either the outgoing data or its
  2146. // header.
  2147. lpph = (LPPIFEXTHDR)LPPIF_FIELDOFF(stdpifext);
  2148. while ((DWORD_PTR)lpph <= (DWORD_PTR)LPPIF_OFF(ppl->cbPIFData - sizeof(PIFEXTHDR)) &&
  2149. (DWORD_PTR)lpph >= (DWORD_PTR)LPPIF_FIELDOFF(stdpifext)) {
  2150. extnxthdrfloff = lpph->extnxthdrfloff;
  2151. if ((DWORD_PTR)LPPH_OFF(lpph->extfileoffset) >= (DWORD_PTR)lpGroup)
  2152. lpph->extfileoffset -= (WORD) cbGroup;
  2153. if (lpphGroup) {
  2154. if ((DWORD_PTR)LPPH_OFF(lpph->extfileoffset) >= (DWORD_PTR)lpphGroup)
  2155. lpph->extfileoffset -= sizeof(PIFEXTHDR);
  2156. if ((DWORD_PTR)LPPH_OFF(lpph->extnxthdrfloff) == (DWORD_PTR)lpphGroup)
  2157. extnxthdrfloff = lpph->extnxthdrfloff = lpphGroup->extnxthdrfloff;
  2158. }
  2159. if (extnxthdrfloff == LASTHDRPTR)
  2160. break;
  2161. if ((DWORD_PTR)LPPH_OFF(lpph->extnxthdrfloff) >= (DWORD_PTR)lpGroup)
  2162. lpph->extnxthdrfloff -= (WORD) cbGroup;
  2163. if (lpphGroup)
  2164. if ((DWORD_PTR)LPPH_OFF(lpph->extnxthdrfloff) >= (DWORD_PTR)lpphGroup)
  2165. lpph->extnxthdrfloff -= sizeof(PIFEXTHDR);
  2166. lpph = (LPPIFEXTHDR)LPPIF_OFF(extnxthdrfloff);
  2167. }
  2168. // Next, move everything up over the data, then adjust lpph as
  2169. // needed and move everything up over the header (this must be done
  2170. // in two discrete steps, because we shouldn't assume anything
  2171. // about the data's location relative to its header).
  2172. hmemcpy(lpGroup, (LPBYTE)lpGroup+cbGroup,
  2173. (DWORD_PTR)LPPIF_OFF(ppl->cbPIFData) - (DWORD_PTR)((LPBYTE)lpGroup+cbGroup));
  2174. if (lpphGroup) {
  2175. if ((DWORD_PTR)lpphGroup >= (DWORD_PTR)((LPBYTE)lpGroup+cbGroup))
  2176. lpphGroup -= cbGroup;
  2177. hmemcpy(lpphGroup, lpphGroup+1,
  2178. (DWORD_PTR)LPPIF_OFF(ppl->cbPIFData) - (DWORD_PTR)((LPBYTE)lpphGroup+1+cbGroup));
  2179. cbGroup += sizeof(PIFEXTHDR);
  2180. }
  2181. ResizePIFData(ppl, -cbGroup);
  2182. ppl->flProp |= PROP_DIRTY | PROP_TRUNCATE;
  2183. ppl->cLocks--;
  2184. }
  2185. ppl->cLocks--;
  2186. return fSuccess;
  2187. }
  2188. /** GetGroupData - get ptr to property group (by name)
  2189. *
  2190. * INPUT
  2191. * ppl -> property (assumes it is LOCKED)
  2192. * lpszGroup -> property group; may be one of the following:
  2193. * "WINDOWS 286 3.0"
  2194. * "WINDOWS 386 3.0"
  2195. * "WINDOWS PIF.400"
  2196. * or any other group name that is the name of a valid PIF extension.
  2197. * if NULL, then *lpcbGroup is a 0-based index of the group we are looking for
  2198. * lpcbGroup -> where to return size of group data (NULL if not)
  2199. * lplpph -> where to return ptr to pif extension header, if any (NULL if not)
  2200. *
  2201. * OUTPUT
  2202. * Returns ptr to property group info, NULL if not found
  2203. */
  2204. void *GetGroupData(PPROPLINK ppl, LPCSTR lpszGroup,
  2205. LPINT lpcbGroup, LPPIFEXTHDR *lplpph)
  2206. {
  2207. LPPIFEXTHDR lpph;
  2208. FunctionName(GetGroupData);
  2209. if (!ppl->lpPIFData)
  2210. return NULL;
  2211. lpph = (LPPIFEXTHDR)LPPIF_FIELDOFF(stdpifext);
  2212. while ((DWORD_PTR)lpph <= (DWORD_PTR)LPPIF_OFF(ppl->cbPIFData-sizeof(PIFEXTHDR)) &&
  2213. (DWORD_PTR)lpph >= (DWORD_PTR)LPPIF_FIELDOFF(stdpifext))
  2214. {
  2215. if (!lpszGroup) {
  2216. // searching by index *lpcbGroup
  2217. if (!(*lpcbGroup)--) {
  2218. if (lplpph)
  2219. *lplpph = lpph;
  2220. *lpcbGroup = lpph->extsizebytes;
  2221. return lpph;
  2222. }
  2223. }
  2224. else {
  2225. CHAR szTmpSig[ARRAYSIZE(lpph->extsig)];
  2226. // protect against non null-terminated extsig field
  2227. ZeroMemory(szTmpSig, sizeof(szTmpSig));
  2228. StringCchCopyA(szTmpSig, ARRAYSIZE(szTmpSig), lpph->extsig);
  2229. // PIFEDIT 3.x can trash the first byte of our extended portion
  2230. // (generally with a zero), so try to recover by stuffing the first
  2231. // character of the group we're looking for into the signature;
  2232. // if the rest of the signature matches, great, if it doesn't, then
  2233. // re-zero it.
  2234. if (!szTmpSig[0]) // attempt to fix
  2235. szTmpSig[0] = *lpszGroup;
  2236. if (lstrcmpiA(szTmpSig, lpszGroup) == 0) {
  2237. if (lplpph)
  2238. *lplpph = lpph;
  2239. if (lpcbGroup)
  2240. *lpcbGroup = lpph->extsizebytes;
  2241. if (lpph->extfileoffset >= (WORD)ppl->cbPIFData) {
  2242. ASSERTFAIL();
  2243. return NULL;
  2244. }
  2245. return (LPBYTE)LPPIF_OFF(lpph->extfileoffset);
  2246. }
  2247. }
  2248. if (lpph->extnxthdrfloff == LASTHDRPTR)
  2249. break;
  2250. lpph = (LPPIFEXTHDR)LPPIF_OFF(lpph->extnxthdrfloff);
  2251. }
  2252. // If we didn't get anywhere, check if this is a "really old" PIF;
  2253. // ie, one without any headers; if so, then if all they were asking for
  2254. // was the old stuff, return it
  2255. if (ppl->cbPIFData == sizeof(STDPIF) && lpszGroup) {
  2256. if (lstrcmpiA(szSTDHDRSIG, lpszGroup) == 0) {
  2257. if (lplpph)
  2258. *lplpph = NULL;
  2259. if (lpcbGroup)
  2260. *lpcbGroup = sizeof(STDPIF);
  2261. return ppl->lpPIFData;
  2262. }
  2263. }
  2264. return NULL;
  2265. }
  2266. /** AppWizard - call the AppWizard CPL (appwiz.cpl)
  2267. */
  2268. TCHAR c_szAPPWIZ[] = TEXT("appwiz.cpl");
  2269. CHAR c_szAppWizard[] = "AppWizard";
  2270. typedef DWORD (WINAPI *LPAPPWIZARD)(HWND hwnd, HANDLE i, UINT ui);
  2271. UINT WINAPI AppWizard(HWND hwnd, HANDLE hProps, UINT action)
  2272. {
  2273. DWORD err = 42;
  2274. LPAPPWIZARD XAppWizard;
  2275. HINSTANCE hAppWizard;
  2276. hAppWizard = LoadLibrary(c_szAPPWIZ);
  2277. if (hAppWizard)
  2278. {
  2279. if (NULL != (XAppWizard = (LPAPPWIZARD)GetProcAddress(hAppWizard, c_szAppWizard)))
  2280. {
  2281. err = XAppWizard( hwnd, hProps, action );
  2282. }
  2283. FreeLibrary((HINSTANCE)hAppWizard);
  2284. }
  2285. return (UINT)err;
  2286. }
  2287. #else // X86
  2288. // IA64 stubs go here
  2289. HANDLE WINAPI PifMgr_OpenProperties(LPCTSTR lpszApp, LPCTSTR lpszPIF, UINT hInf, UINT flOpt)
  2290. {
  2291. return NULL;
  2292. }
  2293. int WINAPI PifMgr_GetProperties(HANDLE hProps, LPCSTR lpszGroup, void *lpProps, int cbProps, UINT flOpt)
  2294. {
  2295. return 0;
  2296. }
  2297. int WINAPI PifMgr_SetProperties(HANDLE hProps, LPCSTR lpszGroup, void *lpProps, int cbProps, UINT flOpt)
  2298. {
  2299. return 0;
  2300. }
  2301. HANDLE WINAPI PifMgr_CloseProperties(HANDLE hProps, UINT flOpt)
  2302. {
  2303. return hProps; // defined error value is to return hProps
  2304. }
  2305. #endif