Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

658 lines
15 KiB

  1. /*
  2. * Microsoft Confidential
  3. * Copyright (C) Microsoft Corporation 1991
  4. * All Rights Reserved.
  5. *
  6. *
  7. * PIFLIB.C
  8. * User interface routines for PIFMGR.DLL
  9. *
  10. * History:
  11. * Created 31-Jul-1992 3:30pm by Jeff Parsons
  12. */
  13. #include "shellprv.h"
  14. #pragma hdrstop
  15. #define LIB_SIG 0x504A
  16. #define LIB_DEFER LOADPROPLIB_DEFER
  17. typedef struct LIBLINK { /* ll */
  18. struct LIBLINK *pllNext; //
  19. struct LIBLINK *pllPrev; //
  20. int iSig; // liblink signature
  21. int flLib; // proplink flags (LIB_*)
  22. HINSTANCE hDLL; // if NULL, then load has been deferred
  23. TCHAR achDLL[80]; // name of DLL
  24. } LIBLINK;
  25. typedef LIBLINK *PLIBLINK;
  26. #define SHEET_SIG 0x504A
  27. typedef struct SHEETLINK { /* sl */
  28. struct SHEETLINK *pslNext;
  29. struct SHEETLINK *pslPrev;
  30. int iSig;
  31. int iType;
  32. PROPSHEETPAGE psi;
  33. } SHEETLINK;
  34. typedef SHEETLINK *PSHEETLINK;
  35. UINT cEdits; // number of edit sessions in progress
  36. PLIBLINK pllHead; // pointer to first lib link
  37. HANDLE offHighestLibLink; // highest offset of a lib link thus far recorded
  38. PSHEETLINK pslHead; // pointer to first sheet link
  39. UINT cSheetLinks; // number of sheet links
  40. HANDLE offHighestSheetLink; // highest offset of a sheet link thus far recorded
  41. struct { // built-in property sheet info
  42. LPCTSTR lpTemplateName;
  43. DLGPROC lpfnDlgProc;
  44. int iType;
  45. } const aPSInfo[] = {
  46. { MAKEINTRESOURCE(IDD_PROGRAM), DlgPrgProc, SHEETTYPE_SIMPLE},
  47. { MAKEINTRESOURCE(IDD_FONT), DlgFntProc, SHEETTYPE_SIMPLE},
  48. { MAKEINTRESOURCE(IDD_MEMORY), DlgMemProc, SHEETTYPE_SIMPLE},
  49. { MAKEINTRESOURCE(IDD_SCREEN), DlgVidProc, SHEETTYPE_SIMPLE},
  50. { MAKEINTRESOURCE(IDD_MISC), DlgMscProc, SHEETTYPE_SIMPLE},
  51. };
  52. /** LoadPropertyLib - load new property library
  53. *
  54. * INPUT
  55. * lpszDLL -> name of DLL
  56. * fLoad == flags (see LOADPROPLIB_*)
  57. *
  58. * OUTPUT
  59. * handle to property library if loaded, FALSE if not
  60. */
  61. HANDLE WINAPI LoadPropertyLib(LPCTSTR lpszDLL, int fLoad)
  62. {
  63. HINSTANCE hDLL;
  64. register PLIBLINK pll;
  65. FunctionName(LoadPropertyLib);
  66. hDLL = NULL;
  67. if (!(fLoad & LOADPROPLIB_DEFER)) {
  68. hDLL = LoadLibrary(lpszDLL);
  69. if (hDLL < (HINSTANCE)HINSTANCE_ERROR)
  70. return FALSE;
  71. }
  72. // Allocate new lib link
  73. if (!(pll = (PLIBLINK)LocalAlloc(LPTR, SIZEOF(LIBLINK))))
  74. return FALSE;
  75. if ((HANDLE) pll > offHighestLibLink)
  76. offHighestLibLink = pll;
  77. // Initialize the lib link
  78. pll->pllPrev = NULL;
  79. pll->iSig = LIB_SIG;
  80. pll->hDLL = hDLL;
  81. pll->flLib = 0;
  82. if (!hDLL)
  83. pll->flLib |= LIB_DEFER;
  84. lstrcpyn(pll->achDLL, lpszDLL, ARRAYSIZE(pll->achDLL));
  85. // Link into the global lib list
  86. if (NULL != (pll->pllNext = pllHead))
  87. pllHead->pllPrev = pll;
  88. pllHead = pll;
  89. return pll;
  90. }
  91. /** EnumPropertyLibs - enumerate property libraries
  92. *
  93. * INPUT
  94. * iLib == 0 to begin enumeration, or result of previous call
  95. * lphDLL -> where to store handle (NULL if don't care)
  96. * lpszDLL -> where to store name of library (NULL if don't care)
  97. * cchszDLL == size of space (in chars) to store name
  98. *
  99. * OUTPUT
  100. * lphDLL and lpszDLL filled in as appropriate, 0 if no more libs (or error)
  101. */
  102. HANDLE WINAPI EnumPropertyLibs(HANDLE iLib, LPHANDLE lphDLL, LPTSTR lpszDLL, int cchszDLL)
  103. {
  104. register PLIBLINK pll;
  105. FunctionName(EnumPropertyLibs);
  106. if (!iLib)
  107. pll = pllHead;
  108. else
  109. pll = ((PLIBLINK)iLib)->pllNext;
  110. // Validate the handle
  111. if (!pll)
  112. return 0;
  113. if ((HANDLE) pll > offHighestLibLink)
  114. return 0;
  115. if (pll->iSig != LIB_SIG)
  116. return 0;
  117. if (lphDLL)
  118. *lphDLL = pll->hDLL;
  119. if (lpszDLL)
  120. lstrcpyn(lpszDLL, pll->achDLL, min(cchszDLL, ARRAYSIZE(pll->achDLL)));
  121. return pll;
  122. }
  123. /** FreePropertyLib - free installable property library
  124. *
  125. * INPUT
  126. * hLib == handle to property library
  127. *
  128. * OUTPUT
  129. * TRUE if successful, FALSE otherwise
  130. */
  131. BOOL WINAPI FreePropertyLib(HANDLE hLib)
  132. {
  133. register PLIBLINK pll;
  134. FunctionName(FreePropertyLib);
  135. // Validate the handle
  136. if (!hLib)
  137. return FALSE;
  138. if ((HANDLE)hLib > offHighestLibLink)
  139. return FALSE;
  140. pll = (PLIBLINK)hLib;
  141. if (pll->iSig != LIB_SIG)
  142. return FALSE;
  143. // Free the associated library
  144. if (pll->hDLL)
  145. FreeLibrary(pll->hDLL);
  146. // Unlink from the global list
  147. if (pll->pllPrev)
  148. pll->pllPrev->pllNext = pll->pllNext;
  149. else
  150. pllHead = pll->pllNext;
  151. if (pll->pllNext)
  152. pll->pllNext->pllPrev = pll->pllPrev;
  153. EVAL(LocalFree(pll) == NULL);
  154. return TRUE;
  155. }
  156. /** AddPropertySheet - install new property sheet
  157. *
  158. * INPUT
  159. * lppsi -> property sheet info structure
  160. * iType == sheet type (see SHEETTYPE_* constants)
  161. *
  162. * OUTPUT
  163. * handle to property sheet link, or NULL if failure
  164. */
  165. HANDLE WINAPI AddPropertySheet(const PROPSHEETPAGE *lppsi, int iType)
  166. {
  167. register PSHEETLINK psl;
  168. FunctionName(AddPropertySheet);
  169. // Allocate new sheet link
  170. if (!(psl = (PSHEETLINK)LocalAlloc(LPTR, SIZEOF(SHEETLINK))))
  171. return FALSE;
  172. if ((HANDLE) psl > offHighestSheetLink)
  173. offHighestSheetLink = psl;
  174. // Initialize the sheet link
  175. psl->pslPrev = NULL;
  176. psl->iSig = SHEET_SIG;
  177. psl->psi = *lppsi;
  178. psl->iType = iType;
  179. // Link into the global sheet list
  180. if (NULL != (psl->pslNext = pslHead))
  181. pslHead->pslPrev = psl;
  182. pslHead = psl;
  183. cSheetLinks++;
  184. return psl;
  185. }
  186. /** RemovePropertySheet - remove installable property sheet
  187. *
  188. * INPUT
  189. * hSheet == handle to sheet link
  190. *
  191. * OUTPUT
  192. * TRUE if successful, FALSE otherwise
  193. */
  194. BOOL WINAPI RemovePropertySheet(HANDLE hSheet)
  195. {
  196. register PSHEETLINK psl;
  197. FunctionName(RemovePropertySheet);
  198. // Validate the handle
  199. if (!hSheet)
  200. return FALSE;
  201. if ((HANDLE)hSheet > offHighestSheetLink)
  202. return FALSE;
  203. psl = (PSHEETLINK)hSheet;
  204. if (psl->iSig != SHEET_SIG)
  205. return FALSE;
  206. // Unlink from the global list
  207. cSheetLinks--;
  208. if (psl->pslPrev)
  209. psl->pslPrev->pslNext = psl->pslNext;
  210. else
  211. pslHead = psl->pslNext;
  212. if (psl->pslNext)
  213. psl->pslNext->pslPrev = psl->pslPrev;
  214. EVAL(LocalFree(psl) == NULL);
  215. return TRUE;
  216. }
  217. /** LoadPropertySheets - load property sheets
  218. *
  219. * INPUT
  220. * hProps = property handle
  221. * flags = 0 (reserved)
  222. *
  223. * OUTPUT
  224. * # of sheets loaded, 0 if error
  225. */
  226. int WINAPI LoadPropertySheets(HANDLE hProps, int flags)
  227. {
  228. register PLIBLINK pll;
  229. FunctionName(LoadPropertySheets);
  230. // If this is the first edit session, do global init now
  231. if (cEdits++ == 0)
  232. if (!LoadGlobalEditData())
  233. return 0;
  234. pll = NULL;
  235. while (NULL != (pll = (PLIBLINK)EnumPropertyLibs(pll, NULL, NULL, 0))) {
  236. if (!pll->hDLL && (pll->flLib & LIB_DEFER)) {
  237. pll->hDLL = LoadLibrary(pll->achDLL);
  238. // If the load failed, to us that simply means those sheets
  239. // will not be available; the particular error is not interesting,
  240. // so nullify the handle
  241. if (pll->hDLL < (HINSTANCE)HINSTANCE_ERROR)
  242. pll->hDLL = NULL;
  243. }
  244. }
  245. return cSheetLinks + ARRAYSIZE(aPSInfo);
  246. }
  247. /** EnumPropertySheets - enumerate property sheets
  248. *
  249. * INPUT
  250. * hProps == property handle
  251. * iType == sheet type (see SHEETTYPE_* constants)
  252. * iSheet == 0 to begin enumeration, or result of previous call
  253. * lppsi -> property sheet info structure to be filled in
  254. *
  255. * OUTPUT
  256. * lppsi filled in as appropriate, 0 if no more sheets (or error)
  257. */
  258. INT_PTR WINAPI EnumPropertySheets(HANDLE hProps, int iType, INT_PTR iSheet, LPPROPSHEETPAGE lppsp)
  259. {
  260. register PSHEETLINK psl;
  261. FunctionName(EnumPropertySheets);
  262. while (iSheet < ARRAYSIZE(aPSInfo)) {
  263. if (aPSInfo[iSheet].iType <= iType) {
  264. if (lppsp) {
  265. lppsp->dwSize = SIZEOF(PROPSHEETPAGE);
  266. lppsp->dwFlags = PSP_DEFAULT;
  267. lppsp->hInstance = HINST_THISDLL;
  268. lppsp->pszTemplate = aPSInfo[iSheet].lpTemplateName;
  269. lppsp->pfnDlgProc = aPSInfo[iSheet].lpfnDlgProc;
  270. // lppsp->pszTitle = NULL;
  271. lppsp->lParam = (LONG_PTR)hProps;
  272. }
  273. return ++iSheet;
  274. }
  275. ++iSheet;
  276. }
  277. if (iSheet == ARRAYSIZE(aPSInfo))
  278. psl = pslHead;
  279. else
  280. psl = ((PSHEETLINK)iSheet)->pslNext;
  281. // Validate the handle
  282. while (psl && (HANDLE) psl <= offHighestSheetLink && psl->iSig == SHEET_SIG) {
  283. if (psl->iType <= iType) {
  284. *lppsp = psl->psi;
  285. lppsp->lParam = (LONG_PTR)hProps;
  286. return (INT_PTR) psl;
  287. }
  288. psl = psl->pslNext;
  289. }
  290. return 0; // no more matching sheets
  291. }
  292. /** FreePropertySheets - free property sheets
  293. *
  294. * INPUT
  295. * hProps = property handle
  296. * flags = 0 (reserved)
  297. *
  298. * OUTPUT
  299. * Nothing
  300. */
  301. HANDLE WINAPI FreePropertySheets(HANDLE hProps, int flags)
  302. {
  303. register PLIBLINK pll;
  304. FunctionName(FreePropertySheets);
  305. pll = NULL;
  306. while (NULL != (pll = (PLIBLINK)EnumPropertyLibs(pll, NULL, NULL, 0))) {
  307. if (pll->hDLL && (pll->flLib & LIB_DEFER)) {
  308. FreeLibrary(pll->hDLL);
  309. pll->hDLL = NULL;
  310. }
  311. }
  312. // If this is the last edit session, do global un-init now
  313. if (--cEdits == 0)
  314. FreeGlobalEditData();
  315. return 0;
  316. }
  317. /** InitRealModeFlag - Initialize PROP_REALMODE
  318. *
  319. * INPUT
  320. * ppl = properties
  321. *
  322. * OUTPUT
  323. * ppl->flProp PROP_REALMODE bit set if sheet is for real-mode app,
  324. * else clear.
  325. */
  326. void InitRealModeFlag(PPROPLINK ppl)
  327. {
  328. PROPPRG prg;
  329. if (!PifMgr_GetProperties(ppl, MAKELP(0,GROUP_PRG),
  330. &prg, SIZEOF(prg), GETPROPS_NONE)) {
  331. return; /* Weird */
  332. }
  333. if (prg.flPrgInit & PRGINIT_REALMODE) {
  334. ppl->flProp |= PROP_REALMODE;
  335. } else {
  336. ppl->flProp &= ~PROP_REALMODE;
  337. }
  338. }
  339. /** EditProperties - edit property info
  340. *
  341. * INPUT
  342. * hProps = handle to properties
  343. * lpszTitle = pointer to title to use (NULL if none)
  344. * uStartPage = starting property sheet #
  345. * hwnd = handle to window of parent (NULL if none)
  346. * uMsgPost = msg # to post to hwnd with change notification (0 if none)
  347. *
  348. * OUTPUT
  349. * TRUE if successful, FALSE otherwise
  350. */
  351. int WINAPI EditProperties(HANDLE hProps, LPCTSTR lpszTitle, UINT uStartPage, HWND hwnd, UINT uMsgPost)
  352. {
  353. int cSheets;
  354. INT_PTR iSheet;
  355. PPROPLINK ppl;
  356. PROPSHEETHEADER psh;
  357. PROPSHEETPAGE *ppsp;
  358. register PSHEETLINK psl;
  359. FunctionName(EditProperties);
  360. if (!(ppl = ValidPropHandle(hProps)))
  361. return FALSE;
  362. if (hwnd && uMsgPost) {
  363. ppl->hwndNotify = hwnd;
  364. ppl->uMsgNotify = uMsgPost;
  365. }
  366. cSheets = LoadPropertySheets(hProps, 0);
  367. psl = pslHead;
  368. if (!(ppsp = (PROPSHEETPAGE *)LocalAlloc(LPTR, cSheets*SIZEOF(PROPSHEETPAGE))))
  369. return FALSE;
  370. psh.dwSize = SIZEOF(psh);
  371. psh.dwFlags = PSH_PROPTITLE | PSH_PROPSHEETPAGE;
  372. psh.hwndParent = hwnd;
  373. if (!lpszTitle)
  374. psh.pszCaption = ppl->szPathName+ppl->iFileName;
  375. else
  376. psh.pszCaption = ppl->lpszTitle = lpszTitle;
  377. psh.nPages = 0;
  378. psh.nStartPage = uStartPage;
  379. psh.ppsp = ppsp;
  380. iSheet = cSheets = 0;
  381. while (0 != (iSheet = EnumPropertySheets(hProps, SHEETTYPE_SIMPLE, iSheet, ppsp))) {
  382. cSheets++;
  383. ppsp++;
  384. }
  385. psh.nPages = cSheets;
  386. // Since the user wishes to *explicitly* change settings for this app
  387. // we make sure that the DONTWRITE flag isn't going to get in his way...
  388. ppl->flProp &= ~PROP_DONTWRITE;
  389. InitRealModeFlag(ppl);
  390. PropertySheet(&psh);
  391. VERIFYFALSE(LocalFree((HLOCAL)psh.ppsp));
  392. FreePropertySheets(hProps, 0);
  393. if (ppl->flProp & PROP_NOTIFY) {
  394. ppl->flProp &= ~PROP_NOTIFY;
  395. PostMessage(ppl->hwndNotify, ppl->uMsgNotify, 0, 0);
  396. }
  397. ppl->hwndNotify = NULL;
  398. ppl->uMsgNotify = 0;
  399. ppl->lpszTitle = NULL;
  400. return TRUE;
  401. }
  402. BOOL LoadGlobalEditData()
  403. {
  404. FunctionName(LoadGlobalEditData);
  405. if (!LoadGlobalFontEditData())
  406. return FALSE;
  407. return TRUE;
  408. }
  409. void FreeGlobalEditData()
  410. {
  411. FunctionName(FreeGlobalEditData);
  412. FreeGlobalFontEditData();
  413. }
  414. UINT CALLBACK PifPropPageRelease(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE lppsp)
  415. {
  416. FunctionName(PifPropPageRelease);
  417. if (uMsg == PSPCB_RELEASE) {
  418. PPROPLINK ppl = (PPROPLINK)(INT_PTR)lppsp->lParam;
  419. if ((--ppl->iSheetUsage) == 0) {
  420. FreePropertySheets(ppl, 0);
  421. PifMgr_CloseProperties(ppl, CLOSEPROPS_NONE);
  422. }
  423. }
  424. return 1;
  425. }
  426. #define MZMAGIC ((WORD)'M'+((WORD)'Z'<<8))
  427. //
  428. // call SHELL.DLL to get the EXE type.
  429. //
  430. BOOL IsWinExe(LPCTSTR lpszFile)
  431. {
  432. DWORD dw = (DWORD) SHGetFileInfo(lpszFile, 0, NULL, 0, SHGFI_EXETYPE);
  433. return dw && LOWORD(dw) != MZMAGIC;
  434. }
  435. BOOL WINAPI PifPropGetPages(LPVOID lpv,
  436. LPFNADDPROPSHEETPAGE lpfnAddPage,
  437. LPARAM lParam)
  438. {
  439. #define hDrop (HDROP)lpv
  440. PPROPLINK ppl;
  441. PROPSHEETPAGE psp;
  442. int iType, cSheets;
  443. INT_PTR iSheet;
  444. HPROPSHEETPAGE hpage;
  445. TCHAR szFileName[MAXPATHNAME];
  446. FunctionName(PifPropGetPages);
  447. // only process things if hDrop contains only one file
  448. if (DragQueryFile(hDrop, (UINT)-1, NULL, 0) != 1)
  449. {
  450. return TRUE;
  451. }
  452. // get the name of the file
  453. DragQueryFile(hDrop, 0, szFileName, ARRAYSIZE(szFileName));
  454. if (GetFileAttributes( szFileName) & FILE_ATTRIBUTE_OFFLINE)
  455. {
  456. return FALSE;
  457. }
  458. // if this is a windows app, don't do no properties
  459. if (IsWinExe(szFileName))
  460. return TRUE;
  461. // if we can't get a property handle, don't do no properties either
  462. if (!(ppl = (PPROPLINK)PifMgr_OpenProperties(szFileName, NULL, 0, OPENPROPS_NONE)))
  463. return TRUE;
  464. InitRealModeFlag(ppl);
  465. if (!(cSheets = LoadPropertySheets(ppl, 0)))
  466. goto CloseProps;
  467. // Since the user wishes to *explicitly* change settings for this app
  468. // we make sure that the DONTWRITE flag isn't going to get in his way...
  469. ppl->flProp &= ~PROP_DONTWRITE;
  470. iSheet = cSheets = 0;
  471. iType = (GetKeyState(VK_CONTROL) >= 0? SHEETTYPE_SIMPLE : SHEETTYPE_ADVANCED);
  472. while (TRUE) {
  473. if (!(iSheet = EnumPropertySheets(ppl, iType, iSheet, &psp))) {
  474. // done with enumeration
  475. break;
  476. }
  477. psp.dwFlags |= PSP_USECALLBACK;
  478. psp.pfnCallback = PifPropPageRelease;
  479. psp.pcRefParent = 0;
  480. hpage = CreatePropertySheetPage(&psp);
  481. if (hpage)
  482. {
  483. // the PROPLINK is now being used by this property sheet as well
  484. if (lpfnAddPage(hpage, lParam))
  485. {
  486. ppl->iSheetUsage++;
  487. cSheets++;
  488. }
  489. else
  490. {
  491. PifPropPageRelease(NULL, PSPCB_RELEASE, &psp);
  492. }
  493. }
  494. }
  495. if (!cSheets) {
  496. FreePropertySheets(ppl, 0);
  497. CloseProps:
  498. PifMgr_CloseProperties(ppl, CLOSEPROPS_NONE);
  499. }
  500. return TRUE;
  501. }
  502. #undef hDrop