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.

3408 lines
101 KiB

  1. /****************************************************************************/
  2. /* */
  3. /* PMGSEG.C - */
  4. /* */
  5. /* Program Manager Group Handling Routines */
  6. /* */
  7. /****************************************************************************/
  8. #include "progman.h"
  9. #include "dde.h"
  10. #include "convgrp.h"
  11. #define WORD_MIN -32767
  12. #define WORD_MAX 32767
  13. #ifndef ORGCODE
  14. #include "fcntl.h"
  15. #include "io.h"
  16. #include "stdio.h"
  17. #include <tchar.h>
  18. #define S_IREAD 0000400 /* read permission, owner */
  19. #define S_IWRITE 0000200 /* write permission, owner */
  20. #endif
  21. BOOL fFirstLoad = FALSE;
  22. extern BOOL bHandleProgramGroupsEvent;
  23. #if 0
  24. // DOS apps are no longer set to fullscreen by default in progman
  25. // 5-3-93 johannec (bug 8343)
  26. #ifdef i386
  27. BOOL IsDOSApplication(LPTSTR lpPath);
  28. BOOL SetDOSApplicationToFullScreen(LPTSTR lpTitle);
  29. #endif
  30. #endif
  31. void NEAR PASCAL RemoveItemFromList(PGROUP pGroup, PITEM pItem)
  32. // Removes a PITEM from the list.
  33. {
  34. PITEM *ppItem;
  35. /* Cause it to be repainted later. */
  36. InvalidateIcon(pGroup, pItem);
  37. if (pItem == pGroup->pItems) {
  38. /*
  39. * first one in list, must invalidate next one so it paints an active
  40. * title bar.
  41. */
  42. InvalidateIcon(pGroup,pItem->pNext);
  43. }
  44. /* Remove it from the list. */
  45. for (ppItem = &pGroup->pItems;*ppItem != pItem;
  46. ppItem = &((*ppItem)->pNext));
  47. *ppItem = pItem->pNext;
  48. /* Lastly free up the memory. */
  49. LocalFree((HANDLE)pItem);
  50. }
  51. #ifdef DEBUG
  52. void NEAR PASCAL CheckBeforeReAlloc(HANDLE h)
  53. {
  54. TCHAR buf[100];
  55. if ((BYTE)GlobalFlags(h)) {
  56. wsprintf(buf, TEXT("LockCount before realloc %d\r\n"), (BYTE)GlobalFlags(h));
  57. OutputDebugString(buf);
  58. DbgBreakPoint();
  59. }
  60. }
  61. #else
  62. #define CheckBeforeReAlloc(h)
  63. #endif
  64. #ifdef PARANOID
  65. /*--------------------------------------------------------------------------*/
  66. /* */
  67. /* CheckRange() - */
  68. /* */
  69. /*--------------------------------------------------------------------------*/
  70. void PASCAL CheckRange(
  71. LPGROUPDEF lpgd,
  72. LPTSTR lp1,
  73. WORD *lpw1,
  74. WORD cb1,
  75. LPTSTR lp2,
  76. WORD w2,
  77. WORD cb2,
  78. LPTSTR lpThing)
  79. {
  80. WORD w1 = *lpw1;
  81. WORD e1, e2;
  82. if (!w1 || (w1 == w2)) {
  83. return;
  84. }
  85. if (!cb1) {
  86. cb1 = (WORD)lstrlen((LPTSTR) PTR(lpgd, *lpw1));
  87. }
  88. e1 = w1 + cb1;
  89. e2 = w2 + cb2;
  90. if ((w1 < e2) && (w2 < e1)) {
  91. KdPrint(("ERROR: %s overlaps %s in %s!!!!\r\n",lp2,lp1,lpThing));
  92. }
  93. }
  94. /*--------------------------------------------------------------------------*/
  95. /* */
  96. /* CheckPointer() - */
  97. /* */
  98. /*--------------------------------------------------------------------------*/
  99. void PASCAL CheckPointer(
  100. LPGROUPDEF lpgd,
  101. LPTSTR lp,
  102. WORD *lpw,
  103. WORD cb,
  104. WORD limit)
  105. {
  106. LPITEMDEF lpid;
  107. int i;
  108. if (lpw == NULL || !*lpw) {
  109. KdPrint(("Warning: %s is NULL\r\n", lp));
  110. DebugBreak();
  111. }
  112. if (!cb) {
  113. cb = lstrlen((LPTSTR) PTR(lpgd, *lpw));
  114. }
  115. if (*lpw + cb > limit) {
  116. KdPrint(("ERROR: %s runs off end of group\r\n", lp));
  117. return;
  118. }
  119. }
  120. /*--------------------------------------------------------------------------*/
  121. /* */
  122. /* VerifyGroup() - */
  123. /* */
  124. /*--------------------------------------------------------------------------*/
  125. void PASCAL VerifyGroup(
  126. LPGROUPDEF lpgd)
  127. {
  128. int i;
  129. LPITEMDEF lpid;
  130. DWORD limit = lpgd->cbGroup;
  131. KdPrint(("\r\nChecking Group %s\r\n",(LPTSTR) PTR(lpgd, lpgd->pName)));
  132. CheckPointer(lpgd, TEXT("Group Name"), &lpgd->pName, 0, limit);
  133. for (i = 0; i < (int)lpgd->cItems; i++) {
  134. if (!lpgd->rgiItems[i]) {
  135. continue;
  136. }
  137. lpid = ITEM(lpgd, i);
  138. KdPrint(("Checking item %d at %4.4X (%s):\r\n", i, lpgd->rgiItems[i],
  139. (LPTSTR) PTR(lpgd, lpid->pName)));
  140. CheckPointer(lpgd, TEXT("Itemdef"), lpgd->rgiItems + i, sizeof(ITEMDEF), limit);
  141. CheckPointer(lpgd, TEXT("Item name"), &lpid->pName, 0, limit);
  142. CheckPointer(lpgd, TEXT("item command"), &lpid->pCommand, 0, limit);
  143. CheckPointer(lpgd, TEXT("item icon path"), &lpid->pIconPath, 0, limit);
  144. }
  145. }
  146. #endif
  147. /*--------------------------------------------------------------------------*/
  148. /* */
  149. /* IsGroupReadOnly() - */
  150. /* */
  151. /*--------------------------------------------------------------------------*/
  152. BOOL FAR PASCAL IsGroupReadOnly(LPTSTR szGroupKey, BOOL bCommonGroup)
  153. {
  154. HKEY hkey;
  155. HKEY hkeyGroups;
  156. if (bCommonGroup)
  157. hkeyGroups = hkeyCommonGroups;
  158. else if (bUseANSIGroups)
  159. hkeyGroups = hkeyAnsiProgramGroups;
  160. else
  161. hkeyGroups = hkeyProgramGroups;
  162. if (!hkeyGroups)
  163. return(FALSE);
  164. if (!RegOpenKeyEx(hkeyGroups, szGroupKey, 0, DELETE | KEY_READ | KEY_WRITE, &hkey)){
  165. RegCloseKey(hkey);
  166. return(FALSE);
  167. }
  168. return(TRUE);
  169. }
  170. /*--------------------------------------------------------------------------*/
  171. /* */
  172. /* GroupCheck() - */
  173. /* */
  174. /*--------------------------------------------------------------------------*/
  175. BOOL FAR PASCAL GroupCheck(PGROUP pGroup)
  176. {
  177. if (!fExiting && IsGroupReadOnly(pGroup->lpKey, pGroup->fCommon)) {
  178. pGroup->fRO = TRUE;
  179. return FALSE;
  180. }
  181. pGroup->fRO = FALSE;
  182. return TRUE;
  183. }
  184. /*--------------------------------------------------------------------------*/
  185. /* */
  186. /* MyDwordAlign() - */
  187. /* */
  188. /*--------------------------------------------------------------------------*/
  189. INT MyDwordAlign(INT wStrLen)
  190. {
  191. return ((wStrLen + 3) & ~3);
  192. }
  193. /*--------------------------------------------------------------------------*/
  194. /* */
  195. /* SizeofGroup() - */
  196. /* */
  197. /*--------------------------------------------------------------------------*/
  198. DWORD PASCAL SizeofGroup(LPGROUPDEF lpgd)
  199. {
  200. LPPMTAG lptag;
  201. DWORD cbSeg;
  202. DWORD cb;
  203. cbSeg = (DWORD)GlobalSize(lpgd);
  204. lptag = (LPPMTAG)((LPSTR)lpgd+lpgd->cbGroup);
  205. if ((DWORD)((PCHAR)lptag - (PCHAR)lpgd +MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb))+4) <= cbSeg
  206. && lptag->wID == ID_MAGIC
  207. && lptag->wItem == (int)0xFFFF
  208. && lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) + 4)
  209. && *(PLONG)lptag->rgb == PMTAG_MAGIC)
  210. {
  211. while ((cb = (DWORD)((PCHAR)lptag - (PCHAR)lpgd + MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)))) <= cbSeg)
  212. {
  213. if (lptag->wID == ID_LASTTAG)
  214. return cb;
  215. (LPSTR)lptag += lptag->cb;
  216. }
  217. }
  218. return lpgd->cbGroup;
  219. }
  220. /*--------------------------------------------------------------------------*/
  221. /* */
  222. /* LockGroup() - */
  223. /* */
  224. /*--------------------------------------------------------------------------*/
  225. /* Given the handle to the group's window, lock the group segment and return
  226. * a pointer thereto. Reloads the group segment if it is not in memory.
  227. */
  228. LPGROUPDEF FAR PASCAL LockGroup(HWND hwndGroup)
  229. {
  230. PGROUP pGroup;
  231. LPGROUPDEF lpgd;
  232. WORD status;
  233. LPTSTR lpszKey;
  234. HKEY hKey = NULL;
  235. LONG err;
  236. DWORD cbMaxValueLen = 0;
  237. FILETIME ft;
  238. TCHAR szClass[64];
  239. DWORD dummy = 64;
  240. DWORD cbSecDesc;
  241. HKEY hkeyGroups;
  242. BOOL bCommonGroup;
  243. wLockError = 0; // No errors.
  244. /* Find the handle and try to lock it. */
  245. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
  246. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  247. /* If we got a non-NULL selector, return the pointer. */
  248. if (pGroup->fLoaded)
  249. return(lpgd);
  250. if (lpgd) {
  251. GlobalUnlock(pGroup->hGroup);
  252. }
  253. NukeIconBitmap(pGroup); // invalidate the bitmap
  254. /* The group has been discarded, must reread the file... */
  255. lpszKey = pGroup->lpKey;
  256. pGroup->fRO = FALSE;
  257. bCommonGroup = pGroup->fCommon;
  258. if (bCommonGroup)
  259. hkeyGroups = hkeyCommonGroups;
  260. else if (bUseANSIGroups)
  261. hkeyGroups = hkeyAnsiProgramGroups;
  262. else
  263. hkeyGroups = hkeyProgramGroups;
  264. if (!hkeyGroups)
  265. goto RegError;
  266. /* Try to open the group key. */
  267. if (err = RegOpenKeyEx(hkeyGroups, lpszKey, 0,
  268. DELETE | KEY_READ | KEY_WRITE,
  269. &hKey)) {
  270. /* Try read-only access */
  271. if (err = RegOpenKeyEx(hkeyGroups, lpszKey, 0,
  272. KEY_READ, &hKey) || !hKey) {
  273. status = IDS_NOGRPFILE;
  274. goto LGError1;
  275. }
  276. if (!bUseANSIGroups) {
  277. pGroup->fRO = TRUE;
  278. }
  279. }
  280. if (!(err = RegQueryInfoKey(hKey,
  281. szClass,
  282. &dummy, // cbClass
  283. NULL, // Title index
  284. &dummy, // cbSubKeys
  285. &dummy, // cb Max subkey length
  286. &dummy, // max class len
  287. &dummy, // values count
  288. &dummy, // max value name length
  289. &cbMaxValueLen,
  290. &cbSecDesc, // cb Security Descriptor
  291. &ft))) {
  292. if (!pGroup->ftLastWriteTime.dwLowDateTime &&
  293. !pGroup->ftLastWriteTime.dwHighDateTime)
  294. pGroup->ftLastWriteTime = ft;
  295. else if (pGroup->ftLastWriteTime.dwLowDateTime != ft.dwLowDateTime ||
  296. pGroup->ftLastWriteTime.dwHighDateTime != ft.dwHighDateTime ) {
  297. wLockError = LOCK_FILECHANGED;
  298. status = IDS_GRPHASCHANGED;
  299. if (!fExiting) // Don't reload changed groups on exit.
  300. PostMessage(hwndProgman,WM_RELOADGROUP,(WPARAM)pGroup,0L);
  301. goto LGError2;
  302. }
  303. }
  304. /* Find the size of the file by seeking to the end. */
  305. if (cbMaxValueLen < sizeof(GROUPDEF)) {
  306. status = IDS_BADFILE;
  307. goto LGError2;
  308. }
  309. /* Allocate some memory for the thing. */
  310. CheckBeforeReAlloc(pGroup->hGroup);
  311. if (!GlobalReAlloc(pGroup->hGroup, (DWORD)cbMaxValueLen, GMEM_MOVEABLE)) {
  312. wLockError = LOCK_LOWMEM;
  313. status = IDS_LOWMEM;
  314. lpszKey = NULL;
  315. goto LGError2;
  316. }
  317. pGroup->fLoaded = TRUE;
  318. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  319. /* Read the whole group data into memory. */
  320. status = IDS_BADFILE;
  321. if (err = RegQueryValueEx(hKey, NULL, 0, 0, (LPBYTE)lpgd, &cbMaxValueLen)) {
  322. goto LGError3;
  323. }
  324. //
  325. // If we start out from the ANSI groups, we need the security description
  326. // to copy the entire information to the UNICODE groups
  327. //
  328. if (bUseANSIGroups) {
  329. pGroup->pSecDesc = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, cbSecDesc);
  330. RegGetKeySecurity(hKey, DACL_SECURITY_INFORMATION, pGroup->pSecDesc, &cbSecDesc);
  331. }
  332. else {
  333. pGroup->pSecDesc = NULL;
  334. }
  335. //
  336. // If we loaded an old format ANSI group, then convert it to the
  337. // UNICODE format and save it back in the registry.
  338. //
  339. if (lpgd->dwMagic == GROUP_MAGIC) {
  340. HANDLE hUNIGroup;
  341. if (cbMaxValueLen = ConvertToUnicodeGroup((LPGROUPDEF_A)lpgd, &hUNIGroup)) {
  342. UnlockGroup(hwndGroup);
  343. /* Free the ANSI group. */
  344. GlobalFree(pGroup->hGroup);
  345. pGroup->hGroup = hUNIGroup;
  346. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  347. }
  348. else {
  349. goto LGError3;
  350. }
  351. }
  352. if (lpgd->dwMagic != GROUP_UNICODE)
  353. goto LGError3;
  354. if (lpgd->cbGroup > cbMaxValueLen)
  355. goto LGError3;
  356. /* Now return the pointer. */
  357. RegCloseKey(hKey);
  358. return(lpgd);
  359. LGError3:
  360. GlobalUnlock(pGroup->hGroup);
  361. GlobalDiscard(pGroup->hGroup);
  362. pGroup->fLoaded = FALSE;
  363. LGError2:
  364. RegCloseKey(hKey);
  365. LGError1:
  366. if (status != IDS_LOWMEM && status != IDS_GRPHASCHANGED && status != IDS_NOGRPFILE) {
  367. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, status, pGroup->lpKey,
  368. MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  369. if (status == IDS_BADFILE) {
  370. //
  371. // stop handling of Program Groups key changes.
  372. //
  373. bHandleProgramGroupsEvent = FALSE;
  374. RegDeleteKey(hkeyGroups, lpszKey);
  375. //
  376. // reset handling of Program Groups key changes.
  377. //
  378. ResetProgramGroupsEvent(bCommonGroup);
  379. bHandleProgramGroupsEvent = TRUE;
  380. }
  381. return(NULL);
  382. }
  383. /*
  384. * Special case the group not being found so we can delete it's entry...
  385. */
  386. if (status == IDS_NOGRPFILE) {
  387. /*
  388. * If no restrictions then we can fixup progman.ini...
  389. */
  390. if (!fNoSave && dwEditLevel < 1) {
  391. TCHAR szGroup[10];
  392. if (MyMessageBox(hwndProgman,IDS_GROUPFILEERR,IDS_NOGRPFILE2,lpszKey, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON1 | MB_SYSTEMMODAL) == IDNO) {
  393. wsprintf(szGroup,TEXT("Group%d"),pGroup->wIndex);
  394. //
  395. // stop handling of Program Groups key changes.
  396. //
  397. bHandleProgramGroupsEvent = FALSE;
  398. RegDeleteKey(hkeyProgramGroups, lpszKey);
  399. //
  400. // reset handling of Program Groups key changes.
  401. //
  402. ResetProgramGroupsEvent(bCommonGroup);
  403. bHandleProgramGroupsEvent = TRUE;
  404. RegDeleteValue(hkeyPMGroups, szGroup);
  405. if (!fFirstLoad)
  406. PostMessage(hwndProgman,WM_UNLOADGROUP,(WPARAM)hwndGroup,0L);
  407. }
  408. }
  409. else {
  410. RegError:
  411. /*
  412. * Restrictions mean that the user can only OK this error...
  413. */
  414. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_NOGRPFILE, lpszKey,
  415. MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  416. }
  417. }
  418. ShowWindow(hwndGroup, SW_SHOWMINNOACTIVE);
  419. return(NULL);
  420. }
  421. /*--------------------------------------------------------------------------*/
  422. /* */
  423. /* UnlockGroup() - */
  424. /* */
  425. /*--------------------------------------------------------------------------*/
  426. void FAR PASCAL UnlockGroup(register HWND hwndGroup)
  427. {
  428. GlobalUnlock(((PGROUP)GetWindowLongPtr(hwndGroup,GWLP_PGROUP))->hGroup);
  429. }
  430. /*--------------------------------------------------------------------------*/
  431. /* */
  432. /* LockItem() - */
  433. /* */
  434. /*--------------------------------------------------------------------------*/
  435. LPITEMDEF FAR PASCAL LockItem(PGROUP pGroup, PITEM pItem)
  436. {
  437. LPGROUPDEF lpgd;
  438. lpgd = LockGroup(pGroup->hwnd);
  439. if (!lpgd)
  440. return((LPITEMDEF)NULL);
  441. return ITEM(lpgd,pItem->iItem);
  442. }
  443. /*--------------------------------------------------------------------------*/
  444. /* */
  445. /* KeepGroupAround() - */
  446. /* */
  447. /*--------------------------------------------------------------------------*/
  448. /*
  449. * Sets or unsets the discardable flag for the given group file. If setting
  450. * to non-discard, forces the group to be in memory.
  451. */
  452. HANDLE PASCAL KeepGroupAround(HWND hwndGroup, BOOL fKeep)
  453. {
  454. PGROUP pGroup;
  455. UNREFERENCED_PARAMETER(fKeep);
  456. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
  457. return pGroup->hGroup;
  458. #ifdef ORGCODE
  459. PGROUP pGroup;
  460. WORD flag;
  461. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
  462. if (fKeep) {
  463. if (LockGroup(hwndGroup)) {
  464. UnlockGroup(hwndGroup); // it is still in memory
  465. } else {
  466. return NULL; // failure
  467. }
  468. flag = GMEM_MODIFY | GMEM_MOVEABLE; // make non discardable
  469. } else {
  470. flag = GMEM_MODIFY | GMEM_MOVEABLE | GMEM_DISCARDABLE; // discardable
  471. }
  472. return GlobalReAlloc(pGroup->hGroup, 0, flag);
  473. #endif
  474. }
  475. /*--------------------------------------------------------------------------*/
  476. /* */
  477. /* SaveGroup() - */
  478. /* */
  479. /*--------------------------------------------------------------------------*/
  480. /*
  481. * Writes out a group file. It must already be in memory or the operation
  482. * is meaningless.
  483. */
  484. BOOL APIENTRY SaveGroup(
  485. HWND hwndGroup, BOOL bDiscard
  486. )
  487. {
  488. LPGROUPDEF lpgd;
  489. HKEY hKey;
  490. PGROUP pGroup;
  491. WORD status = 0;
  492. DWORD cb;
  493. LONG err;
  494. HKEY hkeyGroups;
  495. BOOL bCommonGroup;
  496. DWORD dwDisposition;
  497. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
  498. bCommonGroup = pGroup->fCommon;
  499. if (!bUseANSIGroups && IsGroupReadOnly(pGroup->lpKey, bCommonGroup)) {
  500. // Don't produce an error message for RO groups.
  501. return FALSE;
  502. }
  503. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  504. if (!lpgd) {
  505. return FALSE;
  506. }
  507. if (bCommonGroup)
  508. hkeyGroups = hkeyCommonGroups;
  509. else
  510. hkeyGroups = hkeyProgramGroups;
  511. if (!hkeyGroups) {
  512. goto Exit1;
  513. }
  514. // it may already exist
  515. if (err = RegCreateKeyEx(hkeyGroups, pGroup->lpKey, 0, 0, 0,
  516. DELETE | KEY_READ | KEY_WRITE | WRITE_DAC,
  517. pSecurityAttributes, &hKey, &dwDisposition)) {
  518. //if (err = RegOpenKeyEx(hkeyGroups, pGroup->lpKey, 0,
  519. // KEY_SET_VALUE, &hKey)) {
  520. /*
  521. * We can't open output group key.
  522. */
  523. if (err = RegOpenKeyEx(hkeyGroups, pGroup->lpKey, 0,
  524. KEY_READ, &hKey)) {
  525. status = IDS_NOGRPFILE;
  526. } else {
  527. // status = IDS_GRPISRO;
  528. RegCloseKey(hKey);
  529. }
  530. goto Exit1;
  531. }
  532. else {
  533. if (dwDisposition == REG_CREATED_NEW_KEY && bUseANSIGroups) {
  534. RegSetKeySecurity(hKey, DACL_SECURITY_INFORMATION, pGroup->pSecDesc);
  535. LocalFree(pGroup->pSecDesc);
  536. pGroup->pSecDesc = NULL;
  537. }
  538. }
  539. //
  540. // stop handling Program Groups key changes for a SAveGroup.
  541. //
  542. bHandleProgramGroupsEvent = FALSE;
  543. cb = SizeofGroup(lpgd);
  544. if (err = RegSetValueEx(hKey, NULL, 0, REG_BINARY, (LPBYTE)lpgd, cb)) {
  545. status = IDS_CANTWRITEGRP;
  546. }
  547. RegFlushKey(hKey);
  548. RegCloseKey(hKey);
  549. pGroup->ftLastWriteTime.dwLowDateTime = 0; // update file time stamp if we need to reload
  550. pGroup->ftLastWriteTime.dwHighDateTime = 0;
  551. Exit1:
  552. GlobalUnlock(pGroup->hGroup);
  553. if (status && !fExiting) {
  554. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, status, pGroup->lpKey,
  555. MB_OK | MB_ICONEXCLAMATION);
  556. /*
  557. * Force the group to be reset.
  558. */
  559. if (bDiscard) {
  560. GlobalDiscard(pGroup->hGroup);
  561. pGroup->fLoaded = FALSE;
  562. InvalidateRect(pGroup->hwnd, NULL, TRUE);
  563. }
  564. }
  565. //
  566. // reset handling of Program Groups key changes.
  567. //
  568. ResetProgramGroupsEvent(bCommonGroup);
  569. bHandleProgramGroupsEvent = TRUE;
  570. return (status == 0);
  571. }
  572. /*--------------------------------------------------------------------------*/
  573. /* */
  574. /* AdjustPointers() - */
  575. /* */
  576. /*--------------------------------------------------------------------------*/
  577. /*
  578. * Adjusts pointers in the segment after a section is moved up or down.
  579. */
  580. void PASCAL AdjustPointers(LPGROUPDEF lpgd, DWORD iFirst, DWORD di)
  581. {
  582. WORD i;
  583. LPITEMDEF lpid;
  584. if (lpgd->pName >= iFirst) {
  585. lpgd->pName += di;
  586. }
  587. for (i = 0; i < lpgd->cItems; i++) {
  588. if (!lpgd->rgiItems[i]) {
  589. continue;
  590. }
  591. if (lpgd->rgiItems[i] >= iFirst) {
  592. lpgd->rgiItems[i] += di;
  593. }
  594. lpid = ITEM(lpgd, i);
  595. if (lpid->pIconRes >= iFirst)
  596. lpid->pIconRes += di;
  597. if (lpid->pName >= iFirst)
  598. lpid->pName += di;
  599. if (lpid->pCommand >= iFirst)
  600. lpid->pCommand += di;
  601. if (lpid->pIconPath >= iFirst)
  602. lpid->pIconPath += di;
  603. }
  604. }
  605. /*--------------------------------------------------------------------------*/
  606. /* */
  607. /* FindFreeItemIndex() - */
  608. /* */
  609. /* Returns the index of a free slot in the item offset array. If necessary,*/
  610. /* moves stuff around. */
  611. /* */
  612. /*--------------------------------------------------------------------------*/
  613. WORD PASCAL FindFreeItemIndex(HWND hwndGroup)
  614. {
  615. LPGROUPDEF lpgd;
  616. PGROUP pGroup;
  617. WORD i;
  618. LPTSTR lp1;
  619. LPTSTR lp2;
  620. DWORD cb;
  621. lpgd = LockGroup(hwndGroup);
  622. if (!lpgd) {
  623. return(0xFFFF);
  624. }
  625. for (i = 0; i < lpgd->cItems; i++) {
  626. if (!lpgd->rgiItems[i]) {
  627. UnlockGroup(hwndGroup);
  628. return(i);
  629. }
  630. }
  631. /*
  632. * Didn't find an empty slot... make some new ones.
  633. */
  634. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
  635. // Current groups+tags size.
  636. cb = SizeofGroup(lpgd);
  637. // Increase space reserved item info.
  638. lpgd->cbGroup += NSLOTS*sizeof(DWORD);
  639. // Increase size of whole group.
  640. cb += NSLOTS*sizeof(DWORD);
  641. UnlockGroup(hwndGroup);
  642. CheckBeforeReAlloc(pGroup->hGroup);
  643. if (!GlobalReAlloc(pGroup->hGroup, cb, GMEM_MOVEABLE)) {
  644. return 0xFFFF;
  645. }
  646. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  647. /*
  648. * Copy tags junk (which starts at the end of the rgiItems array)
  649. * up a bit to make room for the bigger array..
  650. */
  651. lp1 = (LPTSTR)&(lpgd->rgiItems[lpgd->cItems]);
  652. lp2 = (LPTSTR)&(lpgd->rgiItems[lpgd->cItems + NSLOTS]);
  653. /*
  654. * Copy everything down in the segment.
  655. */
  656. RtlMoveMemory(lp2, lp1, (WORD)(cb - (DWORD)((LPSTR)lp2 - (LPSTR)lpgd)));
  657. /*
  658. * Zero out the new offsets.
  659. */
  660. for (i = (WORD)lpgd->cItems; i < (WORD)(lpgd->cItems + NSLOTS); i++) {
  661. lpgd->rgiItems[i] = 0;
  662. }
  663. i = lpgd->cItems;
  664. /* Record that we now have more slots */
  665. lpgd->cItems += NSLOTS;
  666. /*
  667. * Fix up all the offsets in the segment. Since the rgiItems array is
  668. * part of the group header, all the pointers will change.
  669. */
  670. AdjustPointers(lpgd, (WORD)1, NSLOTS * sizeof(DWORD));
  671. GlobalUnlock(pGroup->hGroup);
  672. return i;
  673. }
  674. /*--------------------------------------------------------------------------*/
  675. /* */
  676. /* DeleteThing() - */
  677. /* */
  678. /* */
  679. /* Removes a part of the group segment. Updates everything in the segment */
  680. /* but does not realloc. */
  681. /* */
  682. /*--------------------------------------------------------------------------*/
  683. void NEAR PASCAL DeleteThing(LPGROUPDEF lpgd, LPDWORD lpiThing, WORD cbThing)
  684. {
  685. DWORD dwThingOffset;
  686. LPTSTR lp1;
  687. LPTSTR lp2;
  688. INT cb;
  689. WORD cbThingSize;
  690. if (cbThing == 0xFFFF) {
  691. return;
  692. }
  693. dwThingOffset = *lpiThing;
  694. if (!dwThingOffset)
  695. return;
  696. *lpiThing = 0;
  697. lp1 = (LPTSTR) PTR(lpgd, dwThingOffset);
  698. /* If its a string we're removing, the caller can pass 0 as the length
  699. * and have it calculated!!!
  700. */
  701. if (!cbThing) {
  702. cbThing = (WORD)sizeof(TCHAR)*(1 + lstrlen(lp1));
  703. }
  704. cbThingSize = (WORD)MyDwordAlign((int)cbThing);
  705. lp2 = (LPTSTR)((LPBYTE)lp1 + cbThingSize);
  706. cb = (int)SizeofGroup(lpgd);
  707. RtlMoveMemory(lp1, lp2, (cb - (DWORD)((LPSTR)lp2 - (LPSTR)lpgd)));
  708. lpgd->cbGroup -= cbThingSize;
  709. AdjustPointers(lpgd, dwThingOffset, -cbThingSize);
  710. }
  711. /*--------------------------------------------------------------------------*/
  712. /* */
  713. /* AddThing() - */
  714. /* */
  715. /* in: */
  716. /* hGroup group handle, must not be discardable */
  717. /* lpStuff pointer to data or NULL to init data to zero */
  718. /* cbStuff count of item (may be 0) if lpStuff is a string */
  719. /* */
  720. /* Adds an object to the group segment and returns its offset. Will */
  721. /* reallocate the segment if necessary. */
  722. /* */
  723. /* Handle passed in must not be discardable */
  724. /* */
  725. /* returns: */
  726. /* 0 failure */
  727. /* > 0 offset to thing in the segment */
  728. /* */
  729. /*--------------------------------------------------------------------------*/
  730. DWORD PASCAL AddThing(HANDLE hGroup, LPTSTR lpStuff, DWORD cbStuff)
  731. {
  732. DWORD cb;
  733. LPGROUPDEF lpgd;
  734. DWORD offset;
  735. LPTSTR lpT;
  736. DWORD cbStuffSize;
  737. DWORD cbGroupSize;
  738. DWORD myOffset;
  739. if (cbStuff == 0xFFFFFFFF) {
  740. return 0xFFFFFFFF;
  741. }
  742. if (!cbStuff) {
  743. cbStuff = sizeof(TCHAR)*(DWORD)(1 + lstrlen(lpStuff));
  744. }
  745. cbStuffSize = MyDwordAlign((int)cbStuff);
  746. lpgd = (LPGROUPDEF)GlobalLock(hGroup);
  747. cb = SizeofGroup(lpgd);
  748. cbGroupSize = MyDwordAlign((int)cb);
  749. offset = lpgd->cbGroup;
  750. myOffset = (DWORD)MyDwordAlign((int)offset);
  751. GlobalUnlock(hGroup);
  752. CheckBeforeReAlloc(hGroup);
  753. if (!GlobalReAlloc(hGroup,(DWORD)(cbGroupSize + cbStuffSize), GMEM_MOVEABLE))
  754. return 0;
  755. lpgd = (LPGROUPDEF)GlobalLock(hGroup);
  756. /*
  757. * Slide the tags up
  758. */
  759. RtlMoveMemory((LPSTR)lpgd + myOffset + cbStuffSize, (LPSTR)lpgd + myOffset,
  760. (cbGroupSize - myOffset));
  761. lpgd->cbGroup += cbStuffSize;
  762. lpT = (LPTSTR)((LPSTR)lpgd + myOffset);
  763. if (lpStuff) {
  764. RtlMoveMemory(lpT, lpStuff, cbStuff);
  765. } else {
  766. /*
  767. * Zero it
  768. */
  769. while (cbStuffSize--) {
  770. *((LPSTR)lpT)++ = 0;
  771. }
  772. }
  773. GlobalUnlock(hGroup);
  774. return myOffset;
  775. }
  776. /*--------------------------------------------------------------------------*/
  777. /* */
  778. /* FindTag() - */
  779. /* */
  780. /*--------------------------------------------------------------------------*/
  781. LPPMTAG NEAR PASCAL FindTag(LPGROUPDEF lpgd, int item, WORD id)
  782. {
  783. LPPMTAG lptag;
  784. int cbSeg;
  785. int cb;
  786. cbSeg = (DWORD)GlobalSize(lpgd);
  787. lptag = (LPPMTAG)((LPSTR)lpgd+lpgd->cbGroup);
  788. if ((PCHAR)lptag - (PCHAR)lpgd + MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) + 4 <= cbSeg
  789. && lptag->wID == ID_MAGIC
  790. && lptag->wItem == (int)0xFFFF
  791. && lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) +4)
  792. && *(LONG FAR *)lptag->rgb == PMTAG_MAGIC) {
  793. while ((cb = (int)((PCHAR)lptag - (PCHAR)lpgd + MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)))) <= cbSeg)
  794. {
  795. if ((item == lptag->wItem)
  796. && (id == 0 || id == lptag->wID)) {
  797. return lptag;
  798. }
  799. if (lptag->wID == ID_LASTTAG)
  800. return NULL;
  801. (LPSTR)lptag += lptag->cb;
  802. }
  803. }
  804. return NULL;
  805. }
  806. /*--------------------------------------------------------------------------*/
  807. /* */
  808. /* CopyTag() - */
  809. /* */
  810. /*--------------------------------------------------------------------------*/
  811. INT FAR PASCAL CopyTag(LPGROUPDEF lpgd, int item, WORD id, LPTSTR lpbuf, int cb)
  812. {
  813. LPTSTR lpt;
  814. LPPMTAG lptag;
  815. WORD cbT;
  816. lptag = FindTag(lpgd,item,id);
  817. if (lptag == NULL)
  818. return 0;
  819. if (cb > (int)lptag->cb)
  820. cb = lptag->cb;
  821. cbT = (WORD)cb;
  822. lpt = (LPTSTR) lptag->rgb;
  823. while (*lpt && cbT) {
  824. *lpbuf++=*lpt++;
  825. cbT--;
  826. }
  827. if (!(*lpt) && cbT) {
  828. *lpbuf = TEXT('\0');
  829. }
  830. return cb;
  831. }
  832. /*--------------------------------------------------------------------------*/
  833. /* */
  834. /* DeleteTag() - */
  835. /* */
  836. /* in: */
  837. /* hGroup group handle, can be discardable (alwayws shrink object) */
  838. /* */
  839. /*--------------------------------------------------------------------------*/
  840. VOID FAR PASCAL DeleteTag(HANDLE hGroup, int item, WORD id)
  841. {
  842. LPPMTAG lptag;
  843. LPTSTR lp1, lp2;
  844. LPTSTR lpend;
  845. LPGROUPDEF lpgd;
  846. lpgd = (LPGROUPDEF) GlobalLock(hGroup);
  847. lptag = FindTag(lpgd,item,id);
  848. if (lptag == NULL) {
  849. GlobalUnlock(hGroup);
  850. return;
  851. }
  852. lp1 = (LPTSTR)lptag;
  853. lp2 = (LPTSTR)((LPSTR)lptag + lptag->cb);
  854. lpend = (LPTSTR)((LPSTR)lpgd + SizeofGroup(lpgd));
  855. while (lp2 < lpend) {
  856. *lp1++ = *lp2++;
  857. }
  858. /* always reallocing smaller
  859. */
  860. GlobalUnlock(hGroup);
  861. CheckBeforeReAlloc(hGroup);
  862. GlobalReAlloc(hGroup, (DWORD)((LPSTR)lp1 - (LPSTR)lpgd), 0);
  863. return;
  864. }
  865. /*--------------------------------------------------------------------------*/
  866. /* */
  867. /* AddTag() - */
  868. /* */
  869. /* in: */
  870. /* h group handle, must not be discardable! */
  871. /* */
  872. /* returns: */
  873. /* 0 failure */
  874. /* 1 success */
  875. /*--------------------------------------------------------------------------*/
  876. INT PASCAL AddTag(HANDLE h, int item, WORD id, LPTSTR lpbuf, int cb)
  877. {
  878. LPPMTAG lptag;
  879. WORD fAddFirst;
  880. LPGROUPDEF lpgd;
  881. int cbNew;
  882. int cbMyLen;
  883. LPGROUPDEF lpgdOld;
  884. if (!cb && lpbuf) {
  885. cb = sizeof(TCHAR)*(lstrlen(lpbuf) + 1);
  886. }
  887. cbMyLen = MyDwordAlign(cb);
  888. if (!lpbuf) {
  889. cb = 0;
  890. cbMyLen = 0;
  891. }
  892. /*
  893. * Remove the old version of the tag, if any.
  894. */
  895. DeleteTag(h, item, id);
  896. lpgd = (LPGROUPDEF)GlobalLock(h);
  897. lptag = FindTag(lpgd, (int)0xFFFF, (WORD)ID_LASTTAG);
  898. if (!lptag) {
  899. /*
  900. * In this case, there are no tags at all, and we have to add
  901. * the first tag, the interesting tag, and the last tag
  902. */
  903. cbNew = 3 * (MyDwordAlign(sizeof(PMTAG)) - MyDwordAlign(sizeof(lptag->rgb))) + 4 + cbMyLen;
  904. fAddFirst = TRUE;
  905. lptag = (LPPMTAG)((LPSTR)lpgd + lpgd->cbGroup);
  906. } else {
  907. /*
  908. * In this case, only the interesting tag needs to be added
  909. * but we count in the last because the delta is from lptag
  910. */
  911. cbNew = 2 * (MyDwordAlign(sizeof(PMTAG)) - MyDwordAlign(sizeof(lptag->rgb))) + cbMyLen;
  912. fAddFirst = FALSE;
  913. }
  914. /*
  915. * check for 64K limit
  916. */
  917. if ((DWORD_PTR)lptag + cbNew < (DWORD_PTR)lptag) {
  918. return 0;
  919. }
  920. cbNew += (int)((PCHAR)lptag -(PCHAR)lpgd);
  921. lpgdOld = lpgd;
  922. GlobalUnlock(h);
  923. CheckBeforeReAlloc(h);
  924. if (!GlobalReAlloc(h, (DWORD)cbNew, GMEM_MOVEABLE)) {
  925. return 0;
  926. }
  927. lpgd = (LPGROUPDEF)GlobalLock(h);
  928. lptag = (LPPMTAG)((LPSTR)lpgd + ((LPSTR)lptag - (LPSTR)lpgdOld));
  929. if (fAddFirst) {
  930. /*
  931. * Add the first tag
  932. */
  933. lptag->wID = ID_MAGIC;
  934. lptag->wItem = (int)0xFFFF;
  935. *(LONG FAR *)lptag->rgb = PMTAG_MAGIC;
  936. lptag->cb = (WORD)(MyDwordAlign(sizeof(PMTAG)) - MyDwordAlign(sizeof(lptag->rgb)) + 4);
  937. (LPSTR)lptag += lptag->cb;
  938. }
  939. /*
  940. * Add the tag
  941. */
  942. lptag->wID = id;
  943. lptag->wItem = item;
  944. lptag->cb = (WORD)(MyDwordAlign(sizeof(PMTAG)) - MyDwordAlign(sizeof(lptag->rgb)) + cbMyLen);
  945. if (lpbuf) {
  946. RtlMoveMemory(lptag->rgb, lpbuf, (WORD)cb);
  947. }
  948. (LPSTR)lptag += lptag->cb;
  949. /*
  950. * Add the end tag
  951. */
  952. lptag->wID = ID_LASTTAG;
  953. lptag->wItem = (int)0xFFFF;
  954. lptag->cb = 0;
  955. GlobalUnlock(h);
  956. return 1;
  957. }
  958. /*--------------------------------------------------------------------------*/
  959. /* */
  960. /* NukeIconBitmap -- Deletes the icon bitmap if one exists for the group */
  961. /* */
  962. /*--------------------------------------------------------------------------*/
  963. void PASCAL NukeIconBitmap(PGROUP pGroup)
  964. {
  965. if (pGroup->hbm) {
  966. DeleteObject(pGroup->hbm);
  967. pGroup->hbm = NULL;
  968. }
  969. }
  970. /*--------------------------------------------------------------------------*/
  971. /* */
  972. /* GroupFlag() - */
  973. /* */
  974. /*--------------------------------------------------------------------------*/
  975. WORD PASCAL GroupFlag(PGROUP pGroup, PITEM pItem, WORD wFlag)
  976. {
  977. LPGROUPDEF lpgd;
  978. LPPMTAG lptag;
  979. WORD wT = 0;
  980. int wItem;
  981. if (pItem) {
  982. wItem = pItem->iItem;
  983. } else {
  984. wItem = (int)0xFFFF;
  985. }
  986. lpgd = LockGroup(pGroup->hwnd);
  987. if (!lpgd)
  988. return 0;
  989. lptag = FindTag(lpgd, wItem, wFlag);
  990. if (!lptag)
  991. wT = 0;
  992. else if (lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb))))
  993. wT = 1;
  994. else if (lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) + 1))
  995. wT = lptag->rgb[0];
  996. else if (lptag->cb == (WORD)(MyDwordAlign(sizeof(PMTAG))-MyDwordAlign(sizeof(lptag->rgb)) + 4))
  997. wT = *(LPWORD)lptag->rgb;
  998. UnlockGroup(pGroup->hwnd);
  999. return wT;
  1000. }
  1001. /*--------------------------------------------------------------------------*/
  1002. /* */
  1003. /* GetGroupTag() - */
  1004. /* */
  1005. /*--------------------------------------------------------------------------*/
  1006. WORD PASCAL GetGroupTag(
  1007. PGROUP pGroup,
  1008. PITEM pItem,
  1009. WORD id,
  1010. LPTSTR lpT,
  1011. WORD cb)
  1012. {
  1013. WORD wT;
  1014. LPGROUPDEF lpgd;
  1015. int wItem;
  1016. if (pItem)
  1017. wItem = pItem->iItem;
  1018. else
  1019. wItem = (int)0xFFFF;
  1020. lpgd = LockGroup(pGroup->hwnd);
  1021. if (!lpgd)
  1022. return 0;
  1023. wT = (WORD)CopyTag(lpgd, wItem, id, lpT, cb);
  1024. UnlockGroup(pGroup->hwnd);
  1025. return wT;
  1026. }
  1027. /*--------------------------------------------------------------------------*/
  1028. /* */
  1029. /* ChangeTagID() - */
  1030. /* */
  1031. /*--------------------------------------------------------------------------*/
  1032. void PASCAL ChangeTagID(
  1033. LPGROUPDEF lpgd,
  1034. int iOld,
  1035. int iNew)
  1036. {
  1037. LPPMTAG lptag;
  1038. while (lptag = FindTag(lpgd,iOld,0)) {
  1039. lptag->wItem = iNew;
  1040. }
  1041. }
  1042. /*--------------------------------------------------------------------------*/
  1043. /* */
  1044. /* LoadItem() - */
  1045. /* */
  1046. /* Creates an item window (iconic) within a group window. Assumes that the */
  1047. /* group segment is up to date. */
  1048. /* */
  1049. /*--------------------------------------------------------------------------*/
  1050. PITEM PASCAL LoadItem(HWND hwndGroup, WORD iItem, BOOL bActivate)
  1051. {
  1052. LPGROUPDEF lpgd;
  1053. LPITEMDEF lpid;
  1054. PGROUP pGroup;
  1055. PITEM pItem;
  1056. PITEM *ppItem;
  1057. lpgd = LockGroup(hwndGroup);
  1058. if (!lpgd)
  1059. return NULL;
  1060. pItem = (PITEM)LocalAlloc(LPTR, sizeof(ITEM));
  1061. if (!pItem) {
  1062. UnlockGroup(hwndGroup);
  1063. return NULL;
  1064. }
  1065. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
  1066. NukeIconBitmap(pGroup);
  1067. if (bActivate) {
  1068. InvalidateIcon(pGroup, pGroup->pItems);
  1069. pItem->pNext = pGroup->pItems;
  1070. pGroup->pItems = pItem;
  1071. } else {
  1072. ppItem = &pGroup->pItems;
  1073. while (*ppItem) {
  1074. ppItem = &((*ppItem)->pNext);
  1075. }
  1076. pItem->pNext = NULL;
  1077. *ppItem = pItem;
  1078. }
  1079. lpid = ITEM(lpgd, iItem);
  1080. pItem->iItem = iItem;
  1081. pItem->dwDDEId = 0;
  1082. SetRectEmpty(&pItem->rcTitle);
  1083. SetRectEmpty(&pItem->rcIcon);
  1084. ComputeIconPosition(pGroup, lpid->pt, &pItem->rcIcon, &pItem->rcTitle,
  1085. (LPTSTR) PTR(lpgd, lpid->pName));
  1086. UnlockGroup(hwndGroup);
  1087. InvalidateIcon(pGroup, pItem);
  1088. return pItem;
  1089. }
  1090. PITEM FindItemName(LPGROUPDEF lpgd, register PITEM pItem, LPTSTR lpTitle)
  1091. {
  1092. LPITEMDEF lpid;
  1093. while (pItem) {
  1094. lpid = ITEM(lpgd, pItem->iItem);
  1095. if (!lstrcmp(lpTitle, (LPTSTR) PTR(lpgd, lpid->pName)))
  1096. return pItem;
  1097. pItem = pItem->pNext;
  1098. }
  1099. return NULL;
  1100. }
  1101. /*--------------------------------------------------------------------------*/
  1102. /* */
  1103. /* CreateNewItem() - */
  1104. /* */
  1105. /*--------------------------------------------------------------------------*/
  1106. /*
  1107. * Creates a new item in the file, and adds a window for it.
  1108. */
  1109. PITEM PASCAL CreateNewItem(
  1110. HWND hwndGroup,
  1111. LPTSTR lpTitle,
  1112. LPTSTR lpCommand,
  1113. LPTSTR lpIconPath,
  1114. LPTSTR lpDefDir,
  1115. WORD wHotKey,
  1116. BOOL fMinimize,
  1117. WORD wIconId,
  1118. WORD wIconIndex,
  1119. HICON hIcon,
  1120. LPPOINT lppt,
  1121. DWORD dwFlags)
  1122. {
  1123. LPGROUPDEF lpgd;
  1124. LPITEMDEF lpid;
  1125. WORD id;
  1126. DWORD offset;
  1127. PGROUP pGroup;
  1128. LPTSTR lpIconRes;
  1129. WORD cbIconRes;
  1130. //DWORD dwVer;
  1131. WORD wVer;
  1132. WORD idError = IDS_LOWMEM;
  1133. PITEM pItem;
  1134. DWORD cb;
  1135. TCHAR szCommand[3*MAX_PATH];
  1136. TCHAR szExeDir[MAXITEMPATHLEN + 1];
  1137. TCHAR szIconExe[MAX_PATH];
  1138. TCHAR szTemp[MAXITEMPATHLEN+1];
  1139. LPTSTR lp1, lp2, lp3;
  1140. HANDLE hIconRes;
  1141. HANDLE hModule;
  1142. BOOL fWin32App = FALSE;
  1143. BOOL fUseDefaultIcon = FALSE;
  1144. BOOL bNoIconPath = TRUE;
  1145. TCHAR cSeparator;
  1146. /*
  1147. * Before we do anything, whack the command line and exedir
  1148. */
  1149. lp1 = lpCommand;
  1150. if (*lpCommand == TEXT('"') && wcschr(lpCommand + 1, TEXT('"'))) {
  1151. cSeparator = TEXT('"');
  1152. //lp1++;
  1153. }
  1154. else {
  1155. cSeparator = TEXT(' ');
  1156. }
  1157. for (lp2=lp3=szExeDir; *lp1 && *lp1 != cSeparator; lp1 = CharNext(lp1))
  1158. {
  1159. *lp2++ = *lp1;
  1160. /*
  1161. * We know we're looking at the first byte
  1162. */
  1163. if ((*lp1 == TEXT(':')) || (*lp1 == TEXT('\\'))) {
  1164. lp3 = lp2;
  1165. }
  1166. }
  1167. *lp2 = 0;
  1168. /*
  1169. * If the default dir pointer is NULL then we use the directory
  1170. * component of the command line. Otherwise we do the normal
  1171. * path whacking stuff to get everything into 3.0 format.
  1172. */
  1173. if (lpDefDir) {
  1174. LPTSTR lpT;
  1175. lpT = lpDefDir;
  1176. // We have a valid pointer.
  1177. lstrcpy(szCommand,lpDefDir);
  1178. #if 0
  1179. /* spaces are allowed in LFN.
  1180. */
  1181. RemoveLeadingSpaces(szCommand);
  1182. #endif
  1183. // If a default dir was supplied then go ahead and whack it
  1184. // into 3.0 format otherwise leave it blank.
  1185. if (*lpDefDir)
  1186. {
  1187. LPTSTR lpNextChar;
  1188. // locate the character before the NULL
  1189. while ( *(lpNextChar = CharNext(lpDefDir)) )
  1190. lpDefDir = lpNextChar;
  1191. // If there is no '\' seperator, add one.
  1192. if (lpDefDir[0] != TEXT('\\')) {
  1193. lstrcat(szCommand,TEXT("\\"));
  1194. }
  1195. }
  1196. /*
  1197. * Now add the filename itself. this puts the command in the
  1198. * 3.0 format: defdir\exename
  1199. */
  1200. lstrcat(szCommand, lp3);
  1201. /*
  1202. * Append the arguments
  1203. */
  1204. lstrcat(szCommand, lp1);
  1205. lpDefDir = lpT;
  1206. } else {
  1207. /*
  1208. * Use the same command line (note def dir is assigned exe dir
  1209. */
  1210. lstrcpy(szCommand, lpCommand);
  1211. }
  1212. /*
  1213. * Now truncate exedir so that it does not include the command filename
  1214. */
  1215. *lp3 = 0;
  1216. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
  1217. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1218. if (!GroupCheck(pGroup)) {
  1219. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_GROUPRO,
  1220. (LPTSTR) PTR(lpgd, lpgd->pName),
  1221. MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  1222. GlobalUnlock(pGroup->hGroup);
  1223. return NULL;
  1224. }
  1225. GlobalUnlock(pGroup->hGroup);
  1226. if (*lpIconPath) {
  1227. bNoIconPath = FALSE;
  1228. }
  1229. lstrcpy(szIconExe, lpIconPath);
  1230. if (bNoIconPath && !(dwFlags & CI_NO_ASSOCIATION)) {
  1231. lstrcpy(szIconExe, lpCommand);
  1232. }
  1233. DoEnvironmentSubst(szIconExe, (WORD)CharSizeOf(szIconExe));
  1234. StripArgs(szIconExe);
  1235. if (!bNoIconPath) {
  1236. TagExtension(szIconExe, sizeof(szIconExe));
  1237. }
  1238. if (*szIconExe == TEXT('"') && *(szIconExe + lstrlen(szIconExe)-1) == TEXT('"')) {
  1239. SheRemoveQuotes(szIconExe);
  1240. }
  1241. if (bNoIconPath) {
  1242. //
  1243. // if it's a relative path, extractassociatedicon and LoadLibrary don't
  1244. // handle that so find the executable first
  1245. //
  1246. SetCurrentDirectory(szOriginalDirectory);
  1247. FindExecutable(szIconExe, lpDefDir, szTemp);
  1248. if (*szTemp) {
  1249. lstrcpy(szIconExe, szTemp);
  1250. TagExtension(szIconExe, sizeof(szIconExe));
  1251. if (*szIconExe == TEXT('"') && *(szIconExe + lstrlen(szIconExe)-1) == TEXT('"')) {
  1252. SheRemoveQuotes(szIconExe);
  1253. }
  1254. }
  1255. else {
  1256. *szIconExe = 0; // Use a dummy value so no icons will be found
  1257. // and progman's item icon will be used instead
  1258. // This is to make moricons.dll item icon be the
  1259. // right one. -johannec 6/4/93
  1260. }
  1261. //
  1262. // reset the current directory to progman's working directory i.e. Windows directory
  1263. //
  1264. SetCurrentDirectory(szWindowsDirectory);
  1265. wIconId = 0;
  1266. wIconIndex = 0;
  1267. }
  1268. NoIcon:
  1269. if (!wIconId) {
  1270. TCHAR szOldIconExe[MAX_PATH];
  1271. lstrcpy(szOldIconExe, szIconExe);
  1272. hIcon = ExtractAssociatedIconEx(hAppInstance, szIconExe, &wIconIndex, &wIconId);
  1273. if (lstrcmp(szOldIconExe, szIconExe)) {
  1274. /* using default icon from Progman.exe */
  1275. fUseDefaultIcon = TRUE;
  1276. }
  1277. if (hIcon)
  1278. DestroyIcon(hIcon);
  1279. }
  1280. lpIconRes = NULL;
  1281. hIconRes = NULL;
  1282. if (hModule = LoadLibrary(szIconExe)) {
  1283. fWin32App = TRUE;
  1284. hIconRes = FindResource(hModule, (LPTSTR) MAKEINTRESOURCE(wIconId), (LPTSTR) MAKEINTRESOURCE(RT_ICON));
  1285. if (hIconRes) {
  1286. //dwVer = 0x00030000; // resource version is windows 3.x
  1287. wVer = 3; // resource version is windows 3.x
  1288. cbIconRes = (WORD)SizeofResource(hModule, hIconRes);
  1289. hIconRes = LoadResource(hModule, hIconRes);
  1290. lpIconRes = LockResource(hIconRes);
  1291. }
  1292. if (fUseDefaultIcon) {
  1293. wIconId = 0;
  1294. }
  1295. }
  1296. else { // Win 3.1 app
  1297. if (wVer = ExtractIconResInfo(hAppInstance, szIconExe, wIconIndex, &cbIconRes, &hIconRes)){
  1298. lpIconRes = GlobalLock(hIconRes);
  1299. }
  1300. }
  1301. if (!lpIconRes) {
  1302. wIconId = 0;
  1303. wIconIndex = 0;
  1304. // ToddB: I see no harm in always setting the current directory to the WinDir
  1305. // before jumping back to NoIcon. Seems to be required to fix a Japanese bug.
  1306. // The WinDir is the default directory of Progman anyhow, I really don't see
  1307. // where it's possible for us to not already be in this directory.
  1308. SetCurrentDirectory(szWindowsDirectory);
  1309. goto NoIcon;
  1310. }
  1311. if (!KeepGroupAround(hwndGroup, TRUE)) {
  1312. goto FreeIcon;
  1313. }
  1314. id = FindFreeItemIndex(hwndGroup);
  1315. if (id == 0xFFFF) {
  1316. goto FreeIcon;
  1317. }
  1318. if (id >= CITEMSMAX) { // check group size limit
  1319. idError = IDS_TOOMANYITEMS;
  1320. goto FreeIcon;
  1321. }
  1322. offset = AddThing(pGroup->hGroup, (TCHAR)0, (WORD)sizeof(ITEMDEF));
  1323. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1324. if (!offset) {
  1325. goto QuitThis;
  1326. }
  1327. lpgd->rgiItems[id] = offset;
  1328. lpid = ITEM(lpgd, id);
  1329. GlobalUnlock(pGroup->hGroup);
  1330. offset = AddThing(pGroup->hGroup, lpTitle, (WORD)0);
  1331. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1332. lpid = ITEM(lpgd, id);
  1333. if (!offset) {
  1334. goto PuntCreation;
  1335. }
  1336. lpid->pName = offset;
  1337. GlobalUnlock(pGroup->hGroup);
  1338. offset = AddThing(pGroup->hGroup, szCommand,(WORD) 0);
  1339. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1340. lpid = ITEM(lpgd, id);
  1341. if (!offset) {
  1342. goto PuntCreation;
  1343. }
  1344. lpid->pCommand = offset;
  1345. GlobalUnlock(pGroup->hGroup);
  1346. CheckEscapes(szIconExe, CharSizeOf(szIconExe));
  1347. offset = AddThing(pGroup->hGroup, szIconExe,(WORD) 0);
  1348. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1349. lpid = ITEM(lpgd, id);
  1350. if (!offset)
  1351. goto PuntCreation;
  1352. lpid->pIconPath = offset;
  1353. GlobalUnlock(pGroup->hGroup);
  1354. offset = AddThing(pGroup->hGroup, lpIconRes, cbIconRes);
  1355. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1356. lpid = ITEM(lpgd, id);
  1357. if (!offset)
  1358. goto PuntCreation;
  1359. lpid->pIconRes = offset;
  1360. if (lppt) {
  1361. lpid->pt = *lppt;
  1362. } else {
  1363. lpid->pt.x = lpid->pt.y = -1;
  1364. }
  1365. lpid->iIcon = wIconId;
  1366. lpid->wIconIndex = wIconIndex;
  1367. //lpid->dwIconVer = dwVer;
  1368. lpid->wIconVer = wVer;
  1369. lpid->cbIconRes = cbIconRes;
  1370. if (cbIconRes != 0xFFFF)
  1371. if (fWin32App) {
  1372. UnlockResource(hIconRes);
  1373. FreeResource(hIconRes);
  1374. FreeLibrary(hModule);
  1375. }
  1376. else {
  1377. GlobalUnlock(hIconRes);
  1378. GlobalFree(hIconRes);
  1379. }
  1380. GlobalUnlock(pGroup->hGroup);
  1381. if (wHotKey) {
  1382. AddTag(pGroup->hGroup, (int)id, (WORD)ID_HOTKEY, (LPTSTR)&wHotKey, sizeof(wHotKey));
  1383. }
  1384. if (fMinimize) {
  1385. AddTag(pGroup->hGroup, (int)id, (WORD)ID_MINIMIZE, NULL, 0);
  1386. }
  1387. if (dwFlags & CI_SEPARATE_VDM) {
  1388. AddTag(pGroup->hGroup, (int)id, (WORD)ID_NEWVDM, NULL, 0);
  1389. }
  1390. if (*szExeDir) {
  1391. AddTag(pGroup->hGroup, (int)id, (WORD)ID_APPLICATIONDIR, szExeDir, 0);
  1392. }
  1393. pItem = LoadItem(hwndGroup, id, dwFlags & CI_ACTIVATE);
  1394. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1395. lpid = ITEM(lpgd, id);
  1396. if (!pItem) {
  1397. goto PuntCreation;
  1398. }
  1399. lpid->pt.x = pItem->rcIcon.left;
  1400. lpid->pt.y = pItem->rcIcon.top;
  1401. GlobalUnlock(pGroup->hGroup);
  1402. #if 0
  1403. // DOS apps are no longer set to fullscreen by default in progman
  1404. // 5-3-93 johannec (bug 8343)
  1405. #ifdef i386
  1406. //
  1407. // If this is a new DOS application, set the default to full screen.
  1408. // This is only done for x86, since mips doesn't have full screen.
  1409. //
  1410. lstrcpy(szCommand, lpCommand);
  1411. DoEnvironmentSubst(szCommand, (WORD)lstrlen(szCommand));
  1412. StripArgs(szCommand);
  1413. TagExtension(szCommand, sizeof(szCommand));
  1414. *szTemp = 0;
  1415. FindExecutable(szCommand, lpDefDir, szTemp);
  1416. if ((dwFlags & CI_SET_DOS_FULLSCRN) && *szTemp && IsDOSApplication(szTemp)) {
  1417. SetDOSApplicationToFullScreen(lpTitle);
  1418. }
  1419. #endif
  1420. #endif
  1421. KeepGroupAround(hwndGroup, FALSE);
  1422. // We need to save the current group to disk now
  1423. // in case a setup program is doing DDE with us,
  1424. // and they reboot the system when finished.
  1425. if (!SaveGroup (hwndGroup, FALSE)) {
  1426. idError = 0;
  1427. DeleteItem(pGroup, pItem);
  1428. goto FreeIcon;
  1429. }
  1430. return pItem;
  1431. PuntCreation:
  1432. /*
  1433. * Note, must set lpid after each because it may move
  1434. */
  1435. DeleteThing(lpgd, (LPDWORD)&lpid->pName, 0);
  1436. DeleteThing(lpgd, (LPDWORD)&lpid->pCommand, 0);
  1437. DeleteThing(lpgd, (LPDWORD)&lpid->pIconPath, 0);
  1438. DeleteThing(lpgd, (LPDWORD)&lpid->pIconRes, lpid->cbIconRes);
  1439. DeleteThing(lpgd, (LPDWORD)&lpgd->rgiItems[id], sizeof(ITEMDEF));
  1440. QuitThis:
  1441. cb = SizeofGroup(lpgd);
  1442. UnlockGroup(pGroup->hwnd);
  1443. CheckBeforeReAlloc(pGroup->hGroup);
  1444. GlobalReAlloc(pGroup->hGroup, cb, GMEM_MOVEABLE);
  1445. KeepGroupAround(hwndGroup, FALSE);
  1446. FreeIcon:
  1447. if (cbIconRes != 0xFFFF)
  1448. if (fWin32App) {
  1449. UnlockResource(hIconRes);
  1450. FreeResource(hIconRes);
  1451. FreeLibrary(hModule);
  1452. }
  1453. else {
  1454. GlobalUnlock(hIconRes);
  1455. GlobalFree(hIconRes);
  1456. }
  1457. if (idError != 0)
  1458. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, idError, NULL,
  1459. MB_OK | MB_ICONEXCLAMATION);
  1460. // Force re-read of group.
  1461. //GlobalDiscard(pGroup->hGroup);
  1462. //pGroup->fLoaded = FALSE ;
  1463. //LockGroup(pGroup->hwnd);
  1464. //UnlockGroup(pGroup->hwnd);
  1465. return NULL;
  1466. }
  1467. /*--------------------------------------------------------------------------*/
  1468. /* */
  1469. /* DeleteItem() - */
  1470. /* */
  1471. /*--------------------------------------------------------------------------*/
  1472. VOID FAR PASCAL DeleteItem(PGROUP pGroup, PITEM pItem)
  1473. {
  1474. LPGROUPDEF lpgd;
  1475. LPITEMDEF lpid;
  1476. DWORD cb;
  1477. LPPMTAG lptag;
  1478. lpgd = LockGroup(pGroup->hwnd);
  1479. if (!lpgd)
  1480. return;
  1481. if (!GroupCheck(pGroup)) {
  1482. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_GROUPRO,
  1483. (LPTSTR) PTR(lpgd, lpgd->pName),
  1484. MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  1485. InvalidateIcon(pGroup, pItem);
  1486. return;
  1487. }
  1488. NukeIconBitmap(pGroup);
  1489. lpid = ITEM(lpgd,pItem->iItem);
  1490. if ( (lpgd->cbGroup != (DWORD)MyDwordAlign((int)lpgd->cbGroup)) ||
  1491. (lpid->pName != (DWORD)MyDwordAlign((int)lpid->pName)) ||
  1492. (lpid->pCommand != (DWORD)MyDwordAlign((int)lpid->pCommand)) ||
  1493. (lpid->pIconPath != (DWORD)MyDwordAlign((int)lpid->pIconPath)) ||
  1494. (lpgd->rgiItems[pItem->iItem] != (DWORD)MyDwordAlign((int)lpgd->rgiItems[pItem->iItem])) ) {
  1495. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_BADFILE,
  1496. (LPTSTR) PTR(lpgd, lpgd->pName),
  1497. MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  1498. return;
  1499. }
  1500. /* note, must set lpid after each because it may move
  1501. */
  1502. DeleteThing(lpgd, (LPDWORD)&lpid->pName, 0);
  1503. DeleteThing(lpgd, (LPDWORD)&lpid->pCommand, 0);
  1504. DeleteThing(lpgd, (LPDWORD)&lpid->pIconPath, 0);
  1505. DeleteThing(lpgd, (LPDWORD)&lpid->pIconRes, lpid->cbIconRes);
  1506. DeleteThing(lpgd, (LPDWORD)&lpgd->rgiItems[pItem->iItem], sizeof(ITEMDEF));
  1507. while (lptag = FindTag(lpgd,pItem->iItem,0)) {
  1508. /* delete all tags associated with this item
  1509. */
  1510. UnlockGroup(pGroup->hwnd);
  1511. DeleteTag(pGroup->hGroup, lptag->wItem, lptag->wID);
  1512. lpgd = LockGroup(pGroup->hwnd);
  1513. }
  1514. /* Don't need Item anymore so delete it. */
  1515. RemoveItemFromList(pGroup, pItem);
  1516. cb = SizeofGroup(lpgd);
  1517. UnlockGroup(pGroup->hwnd);
  1518. CheckBeforeReAlloc(pGroup->hGroup);
  1519. GlobalReAlloc(pGroup->hGroup, cb, GMEM_MOVEABLE);
  1520. if (bAutoArrange && !bAutoArranging)
  1521. ArrangeItems(pGroup->hwnd);
  1522. else if (!bAutoArranging)
  1523. CalcGroupScrolls(pGroup->hwnd);
  1524. }
  1525. /*--------------------------------------------------------------------------*/
  1526. /* */
  1527. /* CreateItemIcons() - */
  1528. /* */
  1529. /* Creates all the item windows... */
  1530. /* */
  1531. /*--------------------------------------------------------------------------*/
  1532. VOID PASCAL CreateItemIcons(HWND hwndGroup)
  1533. {
  1534. LPGROUPDEF lpgd;
  1535. int i;
  1536. lpgd = LockGroup(hwndGroup);
  1537. if (!lpgd) {
  1538. return;
  1539. }
  1540. /*
  1541. * Create the items in reverse Z-Order.
  1542. */
  1543. for (i = lpgd->cItems - 1; i >= 0; i--) {
  1544. if (lpgd->rgiItems[i]) {
  1545. LoadItem(hwndGroup, (WORD)i, TRUE);
  1546. }
  1547. }
  1548. UnlockGroup(hwndGroup);
  1549. // REVIEW This may be not be needed because LoadGroupWindow does a
  1550. // SetInternalWindowPos which MIGHT already be generating the messages
  1551. // to do this.
  1552. if (bAutoArrange && !bAutoArranging)
  1553. ArrangeItems(hwndGroup);
  1554. else if (!bAutoArranging)
  1555. CalcGroupScrolls(hwndGroup);
  1556. }
  1557. /*--------------------------------------------------------------------------*/
  1558. /* */
  1559. /* CheckIconResolution() - */
  1560. /* */
  1561. /* Makes sure we have the right icons loaded... reextracts and saves */
  1562. /* the file if not. */
  1563. /* */
  1564. /*--------------------------------------------------------------------------*/
  1565. VOID NEAR PASCAL CheckIconResolution(HWND hwndGroup)
  1566. {
  1567. LPGROUPDEF lpgd;
  1568. LPITEMDEF lpid;
  1569. register PGROUP pGroup;
  1570. HANDLE hGroup;
  1571. BOOL fGottaDoIt;
  1572. register HDC hdc;
  1573. int i;
  1574. HICON hIcon;
  1575. WORD cbIconRes;
  1576. DWORD pIconRes;
  1577. LPTSTR lpIconRes;
  1578. WORD wFormat;
  1579. TCHAR szTemp[MAXITEMPATHLEN];
  1580. HANDLE hModule;
  1581. BOOL fWin32App;
  1582. //DWORD dwVer;
  1583. WORD wVer;
  1584. lpgd = LockGroup(hwndGroup);
  1585. if (!lpgd)
  1586. return;
  1587. hdc = GetDC(hwndGroup);
  1588. wFormat = (WORD)GetDeviceCaps(hdc, BITSPIXEL) |
  1589. (WORD)GetDeviceCaps(hdc, PLANES) * (WORD)256;
  1590. ReleaseDC(hwndGroup,hdc);
  1591. fGottaDoIt = lpgd->wIconFormat != wFormat ||
  1592. lpgd->cxIcon != (WORD)GetSystemMetrics(SM_CXICON) ||
  1593. lpgd->cyIcon != (WORD)GetSystemMetrics(SM_CYICON);
  1594. if (!fGottaDoIt) {
  1595. goto CleanUpAndLeave;
  1596. }
  1597. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup,GWLP_PGROUP);
  1598. NukeIconBitmap(pGroup);
  1599. /* Save the new resolution parameters in the group file. */
  1600. lpgd->wIconFormat = wFormat;
  1601. lpgd->cxIcon = (WORD)GetSystemMetrics(SM_CXICON);
  1602. lpgd->cyIcon = (WORD)GetSystemMetrics(SM_CYICON);
  1603. hGroup = pGroup->hGroup;
  1604. for (i = 0; i < (int)lpgd->cItems; ++i) {
  1605. if (!lpgd->rgiItems[i])
  1606. continue;
  1607. lpid = ITEM(lpgd, i);
  1608. DeleteThing(lpgd, (LPDWORD)&lpid->pIconRes, lpid->cbIconRes);
  1609. lpid = ITEM(lpgd, i);
  1610. lstrcpy(szTemp, (LPTSTR) PTR(lpgd, lpid->pIconPath));
  1611. if (!*szTemp) {
  1612. /* Get default icon path */
  1613. lstrcpy(szTemp, (LPTSTR) PTR(lpgd, lpid->pCommand));
  1614. DoEnvironmentSubst(szTemp, (WORD)(MAXITEMPATHLEN+1));
  1615. StripArgs(szTemp);
  1616. }
  1617. SheRemoveQuotes(szTemp);
  1618. cbIconRes = 0xFFFF;
  1619. lpIconRes = NULL;
  1620. hIcon = NULL;
  1621. if (hModule = LoadLibrary(szTemp)) {
  1622. // if WIN32 app
  1623. fWin32App = TRUE;
  1624. hIcon = (HICON)FindResource(hModule, (LPTSTR) MAKEINTRESOURCE(lpid->iIcon), (LPTSTR) MAKEINTRESOURCE(RT_ICON));
  1625. if (hIcon) {
  1626. //dwVer = 0x00030000;
  1627. wVer = 3;
  1628. cbIconRes = (WORD)SizeofResource(hModule, (HRSRC)hIcon);
  1629. hIcon = (HICON)LoadResource(hModule, (HRSRC)hIcon);
  1630. lpIconRes = LockResource(hIcon);
  1631. }
  1632. }
  1633. else { // Win 3.1 app
  1634. fWin32App = FALSE;
  1635. if (wVer = ExtractIconResInfo(hAppInstance, szTemp, lpid->iIcon, &cbIconRes, (LPHANDLE)&hIcon)){
  1636. lpIconRes = GlobalLock(hIcon);
  1637. }
  1638. }
  1639. UnlockGroup(hwndGroup);
  1640. pIconRes = AddThing(pGroup->hGroup, lpIconRes, cbIconRes);
  1641. lpgd = LockGroup(hwndGroup);
  1642. if (!lpgd)
  1643. continue;
  1644. /* In case the segment got moved... */
  1645. lpid = ITEM(lpgd, i);
  1646. if (hIcon)
  1647. if (fWin32App) {
  1648. UnlockResource(hIcon);
  1649. FreeResource(hIcon);
  1650. FreeLibrary(hModule);
  1651. }
  1652. else {
  1653. GlobalUnlock(hIcon);
  1654. GlobalFree(hIcon);
  1655. }
  1656. lpid->pIconRes = pIconRes;
  1657. //lpid->dwIconVer = dwVer;
  1658. lpid->wIconVer = wVer;
  1659. lpid->cbIconRes = cbIconRes;
  1660. }
  1661. #ifdef ORGCODE
  1662. // Check everythings OK.
  1663. if (!pHdr || !pAND || !pXOR)
  1664. {
  1665. // FU - delete icon stuff for this item..
  1666. // REVIEW UNDONE - warn user about memory problem ?
  1667. #ifdef DEBUG
  1668. KdPrint(("PM.CIR: Corrupted icon %s \n\r", (LPTSTR) PTR(lpid->pName)));
  1669. #endif
  1670. lpid = ITEM(lpgd, i);
  1671. DeleteThing(lpgd, (LPDWORD)&lpid->pIconRes, lpid->cbIconRes);
  1672. // Mark item as being effed - the header is checked by
  1673. // GetItemIcon.
  1674. lpid = ITEM(lpgd, i);
  1675. lpid->pIconRes = NULL;
  1676. lpid->wIconVer = 0; // This is the important one.
  1677. lpid->cbIconRes = 0;
  1678. // Warn user when we're through, not right in the middle.
  1679. fErrorOnExtract = TRUE;
  1680. }
  1681. }
  1682. #endif
  1683. if (!GroupCheck(pGroup))
  1684. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_EEGROUPRO,
  1685. (LPTSTR) PTR(lpgd, lpgd->pName),
  1686. MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  1687. CleanUpAndLeave:
  1688. UnlockGroup(hwndGroup);
  1689. //REVIEW See above.
  1690. KeepGroupAround(hwndGroup, FALSE);
  1691. return;
  1692. }
  1693. /*--------------------------------------------------------------------------*/
  1694. /* */
  1695. /* CreateGroupHandle() - */
  1696. /* */
  1697. /* Creates a discarded handle for use as a group handle... on the first */
  1698. /* LockGroup() the file will be loaded. */
  1699. /* */
  1700. /*--------------------------------------------------------------------------*/
  1701. HANDLE NEAR PASCAL CreateGroupHandle(void)
  1702. {
  1703. register HANDLE hGroup;
  1704. if (hGroup = GlobalAlloc(GMEM_MOVEABLE | GMEM_DISCARDABLE, 1L))
  1705. GlobalDiscard(hGroup);
  1706. return(hGroup);
  1707. }
  1708. /*--------------------------------------------------------------------------*/
  1709. /* */
  1710. /* StartupGroup() - */
  1711. /* */
  1712. /*--------------------------------------------------------------------------*/
  1713. VOID FAR PASCAL StartupGroup(HWND hwnd)
  1714. {
  1715. PITEM pItemCur, pItemExec;
  1716. LPGROUPDEF lpgd;
  1717. INT xLast, yLast; // Coord of icon to exec.
  1718. INT xBest, yBest; // Coord of next topmost-leftmost icon.
  1719. MSG msg; // Peek a message.
  1720. PGROUP pGroup; // The group.
  1721. pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
  1722. /*
  1723. * Handle Startup group in icon position order - not Z-order.
  1724. */
  1725. lpgd = LockGroup(hwnd);
  1726. if (!lpgd)
  1727. return;
  1728. /*
  1729. * Starts with the top left and works from left to right then
  1730. * top to bottom.
  1731. * This is really naff in terms of speed, but groups are usually
  1732. * small and the time cost is still small compared to that of execing.
  1733. */
  1734. yLast = WORD_MIN;
  1735. xLast = WORD_MIN;
  1736. for (;;) {
  1737. /*
  1738. * Init
  1739. */
  1740. xBest = WORD_MAX;
  1741. yBest = WORD_MAX;
  1742. pItemExec = NULL;
  1743. /*
  1744. * Find next icon to the right of this one.
  1745. */
  1746. for (pItemCur = pGroup->pItems; pItemCur; pItemCur = pItemCur->pNext) {
  1747. /*
  1748. * Look for Icon to the right of this one.
  1749. * REVIEW This will ignore icons stacked on top of each other.
  1750. */
  1751. if (pItemCur->rcIcon.top >= yLast
  1752. && pItemCur->rcIcon.top <= yLast + (cyArrange/2)
  1753. && pItemCur->rcIcon.left < xBest
  1754. && pItemCur->rcIcon.left > xLast) {
  1755. pItemExec = pItemCur;
  1756. xBest = pItemCur->rcIcon.left;
  1757. }
  1758. /*
  1759. * Check if it'll be suitable for the next row.
  1760. */
  1761. else if (pItemCur->rcIcon.top > yLast + (cyArrange/2)
  1762. && pItemCur->rcIcon.top < yBest) {
  1763. yBest = pItemCur->rcIcon.top;
  1764. }
  1765. }
  1766. if (pItemExec) {
  1767. /*
  1768. * Found one on the current row.
  1769. */
  1770. xLast = xBest;
  1771. /*
  1772. * Move this item to the top of the z-order so that any searches
  1773. * done during DDE will find the last execed item first.
  1774. * REVIEW This messes with the z-odrder of the startup group.
  1775. */
  1776. BringItemToTop(pGroup, pItemExec, TRUE);
  1777. /* Start it up. */
  1778. ExecItem(pGroup,pItemExec,FALSE, TRUE);
  1779. /*
  1780. * Handle any DDE before doing anything else to stop
  1781. * the message queue from over-flowing.
  1782. */
  1783. while(PeekMessage(&msg, hwndProgman, 0, 0, PM_REMOVE|PM_NOYIELD)) {
  1784. TranslateMessage(&msg);
  1785. DispatchMessage(&msg);
  1786. }
  1787. }
  1788. else if (yBest != WORD_MAX) {
  1789. /*
  1790. * Nothing left on the current row but there is another row.
  1791. */
  1792. yLast = yBest;
  1793. xLast = WORD_MIN;
  1794. }
  1795. else {
  1796. /*
  1797. * Nothing left.
  1798. */
  1799. goto Quit;
  1800. }
  1801. }
  1802. Quit:
  1803. UnlockGroup(pGroup->hwnd);
  1804. }
  1805. /*---------------------------------------------------------------------------
  1806. * Check for null item pointers and item pointers that go out of the group.
  1807. * REVIEW UNDONE this doesn't check that the pointers point to things
  1808. * after the end of the items array.
  1809. */
  1810. BOOL NEAR PASCAL ValidItems(LPGROUPDEF lpgd)
  1811. {
  1812. INT i;
  1813. LPITEMDEF lpid;
  1814. DWORD cbGroup;
  1815. if (!lpgd)
  1816. return FALSE;
  1817. cbGroup = lpgd->cbGroup;
  1818. for (i = 0; (WORD)i < lpgd->cItems; i++) {
  1819. if (!lpgd->rgiItems[i])
  1820. continue;
  1821. lpid = ITEM(lpgd,i);
  1822. if (!lpid)
  1823. return FALSE;
  1824. if (lpid->pName > cbGroup)
  1825. return FALSE;
  1826. if (lpid->pCommand > cbGroup)
  1827. return FALSE;
  1828. if (lpid->pIconPath > cbGroup)
  1829. return FALSE;
  1830. if ((lpid->cbIconRes != (WORD)-1) && (lpid->pIconRes > cbGroup))
  1831. return FALSE;
  1832. }
  1833. return(TRUE);
  1834. }
  1835. /*--------------------------------------------------------------------------*/
  1836. /* */
  1837. /* IsGroupAlreadyLoaded() - */
  1838. /* */
  1839. /* Determines if the user is trying to load a currently loaded group. */
  1840. /* */
  1841. /*--------------------------------------------------------------------------*/
  1842. HWND NEAR PASCAL IsGroupAlreadyLoaded(LPTSTR lpGroupKey, BOOL bCommonGroup)
  1843. {
  1844. HWND hwndT;
  1845. PGROUP pGroup;
  1846. for (hwndT=GetWindow(hwndMDIClient, GW_CHILD); hwndT; hwndT=GetWindow(hwndT, GW_HWNDNEXT)) {
  1847. if (GetWindow(hwndT, GW_OWNER))
  1848. continue;
  1849. pGroup = (PGROUP)GetWindowLongPtr(hwndT, GWLP_PGROUP);
  1850. if (!lstrcmpi(lpGroupKey, pGroup->lpKey)) {
  1851. if (bCommonGroup) {
  1852. if (pGroup->fCommon)
  1853. return(hwndT);
  1854. } else {
  1855. if (!pGroup->fCommon)
  1856. return(hwndT);
  1857. }
  1858. }
  1859. }
  1860. return(NULL);
  1861. }
  1862. BOOL NEAR PASCAL IndexUsed(WORD wIndex, BOOL bCommonGroup)
  1863. {
  1864. PGROUP pGroup;
  1865. for (pGroup = pFirstGroup; pGroup; pGroup = pGroup->pNext)
  1866. if ((pGroup->wIndex == wIndex) && (pGroup->fCommon == bCommonGroup))
  1867. return TRUE;
  1868. return FALSE;
  1869. }
  1870. /*--------------------------------------------------------------------------*/
  1871. /* */
  1872. /* LoadGroupWindow() - */
  1873. /* */
  1874. /* Creates a group window by sending an MDI create message to the MDI client. */
  1875. /* The MDICREATESTRUCT contains a parameter pointer to the name of the group */
  1876. /* key. */
  1877. /* */
  1878. /*--------------------------------------------------------------------------*/
  1879. // GroupFile must be ANSI.
  1880. HWND PASCAL LoadGroupWindow(LPTSTR lpKey, WORD wIndex, BOOL bCommonGroup)
  1881. {
  1882. MDICREATESTRUCT mdics;
  1883. PGROUP pGroup;
  1884. TCHAR szGroupClass[64];
  1885. LPGROUPDEF lpgd;
  1886. HWND hwnd;
  1887. TCHAR szCommonGroupSuffix[MAXKEYLEN];
  1888. TCHAR szCommonGroupTitle[2*MAXKEYLEN];
  1889. WINDOWPLACEMENT wp;
  1890. //
  1891. // Check if the group is already loaded. This will prevent duplicate groups.
  1892. //
  1893. if (hwnd = IsGroupAlreadyLoaded(lpKey, bCommonGroup)) {
  1894. return(hwnd);
  1895. }
  1896. if (!wIndex) {
  1897. while (IndexUsed(++wIndex, bCommonGroup))
  1898. ;
  1899. }
  1900. if (!LoadString(hAppInstance, IDS_GROUPCLASS, szGroupClass,
  1901. CharSizeOf(szGroupClass))) {
  1902. return NULL;
  1903. }
  1904. pGroup = (PGROUP)LocalAlloc(LPTR,sizeof(GROUP));
  1905. if (!pGroup) {
  1906. return NULL;
  1907. }
  1908. pGroup->hGroup = CreateGroupHandle();
  1909. pGroup->pItems = NULL;
  1910. pGroup->hbm = NULL;
  1911. pGroup->wIndex = wIndex;
  1912. pGroup->fCommon = bCommonGroup;
  1913. pGroup->ftLastWriteTime.dwLowDateTime = 0;
  1914. pGroup->ftLastWriteTime.dwHighDateTime = 0;
  1915. pGroup->lpKey = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)*(lstrlen(lpKey) + 1));
  1916. pGroup->fLoaded = FALSE;
  1917. if (!pGroup->lpKey) {
  1918. GoAway:
  1919. GlobalFree(pGroup->hGroup);
  1920. LocalFree((HANDLE)pGroup);
  1921. if (!fLowMemErrYet) {
  1922. MyMessageBox(hwndProgman, IDS_APPTITLE, IDS_LOWMEMONINIT,
  1923. lpKey, MB_OK|MB_ICONEXCLAMATION);
  1924. fLowMemErrYet = TRUE;
  1925. }
  1926. return NULL;
  1927. }
  1928. lstrcpy(pGroup->lpKey, lpKey);
  1929. mdics.szTitle = TEXT("");
  1930. mdics.hOwner = hAppInstance;
  1931. mdics.szClass = szGroupClass;
  1932. mdics.style = WS_VSCROLL|WS_HSCROLL;
  1933. mdics.x = mdics.y = mdics.cx = mdics.cy = CW_USEDEFAULT;
  1934. mdics.lParam = (LPARAM)pGroup;
  1935. /*
  1936. * REVIEW HACK - Set the auto arranging flag to stop the group being
  1937. * loaded by ArrangingIcons doing a LockGroup and then producing
  1938. * an error if something goes wrong. We're going to do a lock
  1939. * later on anyway and we don't want two error messages.
  1940. */
  1941. bAutoArranging = TRUE;
  1942. pGroup->hwnd = (HWND)SendMessage(hwndMDIClient, WM_MDICREATE, 0, (LPARAM)(LPTSTR)&mdics);
  1943. bAutoArranging = FALSE;
  1944. if (!pGroup->hwnd) {
  1945. LocalFree((HANDLE)pGroup->lpKey);
  1946. goto GoAway;
  1947. }
  1948. /*
  1949. * Note that we're about to load a group for the first time.
  1950. * NB Stting this tells LockGroup that the caller can handle the errors.
  1951. */
  1952. fFirstLoad = TRUE;
  1953. lpgd = LockGroup(pGroup->hwnd);
  1954. /*
  1955. * The group has been loaded or at least we tried.
  1956. */
  1957. fFirstLoad = FALSE;
  1958. if (!lpgd) {
  1959. LoadFail:
  1960. /* Loading the group failed somehow... */
  1961. SendMessage(hwndMDIClient, WM_MDIDESTROY, (WPARAM)pGroup->hwnd, 0L);
  1962. //
  1963. // stop handling of Program Groups key changes.
  1964. //
  1965. bHandleProgramGroupsEvent = FALSE;
  1966. RegDeleteKey(hkeyProgramGroups, pGroup->lpKey);
  1967. //
  1968. // reset handling of Program Groups key changes.
  1969. //
  1970. ResetProgramGroupsEvent(bCommonGroup);
  1971. bHandleProgramGroupsEvent = TRUE;
  1972. LocalFree((HANDLE)pGroup->lpKey);
  1973. GlobalFree(pGroup->hGroup);
  1974. LocalFree((HANDLE)pGroup);
  1975. return NULL;
  1976. }
  1977. /*
  1978. * test if it is a Windows 3.1 group file format. If so it is not
  1979. * valid in WIN32. In Windows 3.1 RECT and POINT are WORD instead of LONG.
  1980. */
  1981. if ( (lpgd->rcNormal.left != (INT)(SHORT)lpgd->rcNormal.left) ||
  1982. (lpgd->rcNormal.right != (INT)(SHORT)lpgd->rcNormal.right) ||
  1983. (lpgd->rcNormal.top != (INT)(SHORT)lpgd->rcNormal.top) ||
  1984. (lpgd->rcNormal.bottom != (INT)(SHORT)lpgd->rcNormal.bottom) ){
  1985. /* The group is invalid. */
  1986. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_BADFILE,
  1987. (LPTSTR) PTR(lpgd, lpgd->pName),
  1988. MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  1989. UnlockGroup(pGroup->hwnd);
  1990. goto LoadFail;
  1991. }
  1992. if (!ValidItems(lpgd)) {
  1993. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_BADFILE,
  1994. (LPTSTR) PTR(lpgd, lpgd->pName),
  1995. MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  1996. UnlockGroup(pGroup->hwnd);
  1997. goto LoadFail;
  1998. }
  1999. if (lpgd->nCmdShow) {
  2000. SetInternalWindowPos(pGroup->hwnd, (UINT)lpgd->nCmdShow, &lpgd->rcNormal,
  2001. &lpgd->ptMin);
  2002. }
  2003. if (pGroup->fCommon) {
  2004. //
  2005. // Add the common group suffix to the name of the group e.g. (Common)
  2006. // Only do this if the group window is not minimized.
  2007. //
  2008. wp.length = sizeof(WINDOWPLACEMENT);
  2009. GetWindowPlacement(pGroup->hwnd, &wp);
  2010. if ((wp.showCmd == SW_MINIMIZE) ||
  2011. (wp.showCmd == SW_SHOWMINIMIZED) ||
  2012. (wp.showCmd == SW_SHOWMINNOACTIVE) ) {
  2013. SetWindowText(pGroup->hwnd, (LPTSTR) PTR(lpgd, lpgd->pName));
  2014. }
  2015. else {
  2016. lstrcpy(szCommonGroupTitle, (LPTSTR) PTR(lpgd, lpgd->pName));
  2017. if (LoadString(hAppInstance, IDS_COMMONGRPSUFFIX, szCommonGroupSuffix,
  2018. CharSizeOf(szCommonGroupSuffix))) {
  2019. lstrcat(szCommonGroupTitle, szCommonGroupSuffix);
  2020. }
  2021. SetWindowText(pGroup->hwnd, szCommonGroupTitle);
  2022. if (!UserIsAdmin) {
  2023. pGroup->fRO = TRUE;
  2024. }
  2025. }
  2026. }
  2027. else {
  2028. SetWindowText(pGroup->hwnd, (LPTSTR) PTR(lpgd, lpgd->pName));
  2029. }
  2030. UnlockGroup(pGroup->hwnd);
  2031. //CheckIconResolution(pGroup->hwnd);
  2032. CreateItemIcons(pGroup->hwnd);
  2033. /*
  2034. * Link the group.
  2035. */
  2036. pGroup->pNext = NULL;
  2037. *pLastGroup = pGroup;
  2038. pLastGroup = &pGroup->pNext;
  2039. pCurrentGroup = pGroup;
  2040. #ifdef NOTINUSER
  2041. CalcChildScroll(pGroup->hwnd, SB_BOTH);
  2042. #endif
  2043. GroupCheck(pGroup);
  2044. return(pGroup->hwnd);
  2045. }
  2046. /*--------------------------------------------------------------------------*/
  2047. /* */
  2048. /* UnloadGroupWindow() - */
  2049. /* */
  2050. /*--------------------------------------------------------------------------*/
  2051. void FAR PASCAL UnloadGroupWindow(HWND hwnd)
  2052. {
  2053. PGROUP pGroup, *ppGroup;
  2054. PITEM pItem, pItemNext;
  2055. pGroup = (PGROUP)GetWindowLongPtr(hwnd,GWLP_PGROUP);
  2056. /* Destroy the window. */
  2057. SendMessage(hwndMDIClient,WM_MDIDESTROY,(WPARAM)hwnd,0L);
  2058. /* Free the group segment. */
  2059. GlobalFree(pGroup->hGroup);
  2060. /* Free the local stuff. */
  2061. LocalFree((HANDLE)pGroup->lpKey);
  2062. /* The cached bitmap if there is one. */
  2063. if (pGroup->hbm) {
  2064. DeleteObject(pGroup->hbm);
  2065. pGroup->hbm = NULL;
  2066. }
  2067. /* The item data. */
  2068. for (pItem = pGroup->pItems; pItem; pItem = pItemNext) {
  2069. pItemNext = pItem->pNext;
  2070. LocalFree((HANDLE) pItem);
  2071. }
  2072. /* Remove the group from the linked list. */
  2073. for (ppGroup = &pFirstGroup; *ppGroup; ppGroup = &((*ppGroup)->pNext)) {
  2074. if (*ppGroup == pGroup) {
  2075. *ppGroup = pGroup->pNext;
  2076. break;
  2077. }
  2078. }
  2079. if (pLastGroup == &pGroup->pNext)
  2080. pLastGroup = ppGroup;
  2081. /* Lastly, free the group structure itself. */
  2082. LocalFree((HANDLE)pGroup);
  2083. }
  2084. /*--------------------------------------------------------------------------*/
  2085. /* */
  2086. /* RemoveBackslashFromKeyName() - */
  2087. /* */
  2088. /* replace the invalid characters for a key name by some valid charater. */
  2089. /* the same characters that are invalid for a file name are invalid for a */
  2090. /* key name. */
  2091. /* */
  2092. /*--------------------------------------------------------------------------*/
  2093. void RemoveBackslashFromKeyName(LPTSTR lpKeyName)
  2094. {
  2095. LPTSTR lpt;
  2096. for (lpt = lpKeyName; *lpt; lpt++) {
  2097. if ((*lpt == TEXT('\\')) || (*lpt == TEXT(':')) || (*lpt == TEXT('>')) || (*lpt == TEXT('<')) ||
  2098. (*lpt == TEXT('*')) || (*lpt == TEXT('?')) ){
  2099. *lpt = TEXT('.');
  2100. }
  2101. }
  2102. }
  2103. /*--------------------------------------------------------------------------*/
  2104. /* */
  2105. /* CreateNewGroup() - */
  2106. /* */
  2107. /* This function creates a new, empty group. */
  2108. /* */
  2109. /*--------------------------------------------------------------------------*/
  2110. HWND PASCAL CreateNewGroup(LPTSTR pGroupName, BOOL bCommonGroup)
  2111. {
  2112. HANDLE hT;
  2113. LPGROUPDEF lpgd;
  2114. PGROUP pGroup;
  2115. HDC hdc;
  2116. int i;
  2117. int cb;
  2118. TCHAR szKeyName[MAXKEYLEN+1];
  2119. HWND hwnd;
  2120. DWORD status = 0;
  2121. WORD cGroups;
  2122. INT wGroupNameLen; //length of pGroupName DWORD aligned.
  2123. HKEY hkeyGroups;
  2124. HKEY hKey;
  2125. HWND hwndT;
  2126. PSECURITY_ATTRIBUTES pSecAttr;
  2127. /*
  2128. * Check we're not trying to create too many groups.
  2129. * Count the current number of groups.
  2130. */
  2131. cGroups = 0;
  2132. for (hwnd = GetWindow(hwndMDIClient, GW_CHILD); hwnd; hwnd = GetWindow(hwnd, GW_HWNDNEXT)) {
  2133. if (GetWindow(hwnd, GW_OWNER))
  2134. continue;
  2135. //
  2136. // count the common groups seperately from the personal group.
  2137. // Both have a maximum of CGROUPSMAX groups.
  2138. //
  2139. pGroup = (PGROUP)GetWindowLongPtr(hwnd, GWLP_PGROUP);
  2140. if (bCommonGroup && pGroup->fCommon ||
  2141. !bCommonGroup && !pGroup->fCommon) {
  2142. cGroups++;
  2143. }
  2144. }
  2145. // Compare with limit.
  2146. if (cGroups >= CGROUPSMAX) {
  2147. status = bCommonGroup ? IDS_TOOMANYCOMMONGROUPS : IDS_TOOMANYGROUPS;
  2148. goto Exit;
  2149. }
  2150. if (bCommonGroup) {
  2151. hkeyGroups = hkeyCommonGroups;
  2152. pSecAttr = pAdminSecAttr;
  2153. if (!hkeyGroups) {
  2154. if (MyMessageBox(hwndProgman,
  2155. IDS_COMMONGROUPERR,
  2156. IDS_NOCOMMONGRPS,
  2157. pGroupName,
  2158. MB_OKCANCEL | MB_ICONEXCLAMATION | MB_TASKMODAL)
  2159. == IDOK) {
  2160. hkeyGroups = hkeyProgramGroups;
  2161. pSecAttr = pSecurityAttributes;
  2162. bCommonGroup = FALSE;
  2163. } else {
  2164. return(NULL);
  2165. }
  2166. }
  2167. } else {
  2168. hkeyGroups = hkeyProgramGroups;
  2169. pSecAttr = pSecurityAttributes;
  2170. }
  2171. if (!hkeyGroups) {
  2172. status = IDS_NOGRPFILE;
  2173. goto Exit;
  2174. }
  2175. //
  2176. // Replace backslash in the group name because the registry does not
  2177. // allow key names with backslash, bckslash is used to separate keys.
  2178. //
  2179. lstrcpy(szKeyName, pGroupName);
  2180. RemoveBackslashFromKeyName(szKeyName);
  2181. //
  2182. // Test for existing key.
  2183. //
  2184. while (!RegOpenKeyEx(hkeyGroups, szKeyName, 0, KEY_READ, &hKey)) {
  2185. /* a group with this name already exists */
  2186. if (hwndT = IsGroupAlreadyLoaded(szKeyName, bCommonGroup)) {
  2187. if (lstrlen(szKeyName) < MAXKEYLEN) {
  2188. lstrcat(szKeyName, TEXT("."));
  2189. GlobalUnlock(pGroup->hGroup);
  2190. RegCloseKey(hKey);
  2191. continue;
  2192. }
  2193. }
  2194. RegCloseKey(hKey);
  2195. goto LoadGroupFile;
  2196. }
  2197. wGroupNameLen = MyDwordAlign(sizeof(TCHAR)*(lstrlen(pGroupName) + 1));
  2198. cb = sizeof(GROUPDEF) + (NSLOTS * sizeof(DWORD)) + wGroupNameLen;
  2199. /*
  2200. * In CreateNewGroup before GlobalAlloc.
  2201. */
  2202. hT = GlobalAlloc(GHND, (DWORD)cb);
  2203. if (!hT) {
  2204. status = IDS_LOWMEM;
  2205. goto Exit;
  2206. }
  2207. lpgd = (LPGROUPDEF)GlobalLock(hT);
  2208. lpgd->dwMagic = GROUP_UNICODE;
  2209. lpgd->cbGroup = (DWORD)cb;
  2210. lpgd->nCmdShow = 0; /* use MDI defaults */
  2211. lpgd->pName = sizeof(GROUPDEF) + NSLOTS * sizeof(DWORD);
  2212. hdc = GetDC(NULL);
  2213. lpgd->wIconFormat = (WORD)GetDeviceCaps(hdc, BITSPIXEL) + (WORD)256 *
  2214. (WORD)GetDeviceCaps(hdc, PLANES);
  2215. ReleaseDC(NULL, hdc);
  2216. lpgd->cxIcon = (WORD)GetSystemMetrics(SM_CXICON);
  2217. lpgd->cyIcon = (WORD)GetSystemMetrics(SM_CYICON);
  2218. lpgd->Reserved1 = (WORD)-1;
  2219. lpgd->Reserved2 = (DWORD)-1;
  2220. lpgd->cItems = NSLOTS;
  2221. for (i = 0; i < NSLOTS; i++) {
  2222. lpgd->rgiItems[i] = 0;
  2223. }
  2224. lstrcpy((LPTSTR)((LPSTR)lpgd + sizeof(GROUPDEF) + NSLOTS * sizeof(DWORD)),
  2225. pGroupName);
  2226. /*
  2227. * In CreateNewGroup before SizeofGroup.
  2228. */
  2229. cb = (int)SizeofGroup(lpgd);
  2230. //
  2231. // stop handling of Program Groups key changes when creating groups.
  2232. //
  2233. bHandleProgramGroupsEvent = FALSE;
  2234. //
  2235. // REARCHITECT: pSecurityAttributes might change for Common groups.
  2236. //
  2237. if (!RegCreateKeyEx(hkeyGroups, szKeyName, 0, 0, 0,
  2238. DELETE | KEY_READ | KEY_WRITE,
  2239. pSecAttr, &hKey, NULL)) {
  2240. if (RegSetValueEx(hKey, NULL, 0, REG_BINARY, (LPBYTE)lpgd, cb))
  2241. status = IDS_CANTWRITEGRP;
  2242. RegCloseKey(hKey);
  2243. }
  2244. else
  2245. status = IDS_NOGRPFILE;
  2246. GlobalUnlock(hT);
  2247. GlobalFree(hT);
  2248. Exit:
  2249. if (status) {
  2250. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, (WORD)status, pGroupName,
  2251. MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
  2252. ResetProgramGroupsEvent(bCommonGroup);
  2253. bHandleProgramGroupsEvent = TRUE;
  2254. return NULL;
  2255. }
  2256. LoadGroupFile:
  2257. /*
  2258. * The group file now exists on the disk... load it in!
  2259. */
  2260. fLowMemErrYet = FALSE;
  2261. fErrorOnExtract = FALSE;
  2262. hwnd = LoadGroupWindow(szKeyName, 0, bCommonGroup);
  2263. if (fErrorOnExtract) {
  2264. // On observed problem with icon extraction has been to do
  2265. // with a low memory.
  2266. MyMessageBox(hwndProgman, IDS_OOMEXITTITLE, IDS_LOWMEMONEXTRACT,
  2267. NULL, MB_OK|MB_ICONHAND|MB_SYSTEMMODAL);
  2268. }
  2269. // Save the group section even if SaveSettings is off to stop
  2270. // users from themselves.
  2271. if (!bCommonGroup) {
  2272. WriteGroupsSection();
  2273. }
  2274. ResetProgramGroupsEvent(bCommonGroup);
  2275. bHandleProgramGroupsEvent = TRUE;
  2276. return hwnd;
  2277. }
  2278. /*--------------------------------------------------------------------------*/
  2279. /* */
  2280. /* DeleteGroup() - */
  2281. /* */
  2282. /*--------------------------------------------------------------------------*/
  2283. VOID FAR PASCAL DeleteGroup(HWND hwndGroup)
  2284. {
  2285. PGROUP pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
  2286. PGROUP *ppGroup;
  2287. PITEM pItem;
  2288. TCHAR szT[10];
  2289. BOOL bCommonGroup;
  2290. HKEY hkeyGroups;
  2291. //
  2292. // stop handling of Program Groups key changes when deleting groups.
  2293. //
  2294. bHandleProgramGroupsEvent = FALSE;
  2295. bCommonGroup = pGroup->fCommon;
  2296. if (bCommonGroup)
  2297. hkeyGroups = hkeyCommonGroups;
  2298. else
  2299. hkeyGroups = hkeyProgramGroups;
  2300. if (pGroup->fRO || RegDeleteKey(hkeyGroups, pGroup->lpKey) != ERROR_SUCCESS) {
  2301. MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_ERRORDELETEGROUP,
  2302. pGroup->lpKey, MB_OK);
  2303. //
  2304. // reset handling of Program Groups key changes.
  2305. //
  2306. ResetProgramGroupsEvent(bCommonGroup);
  2307. bHandleProgramGroupsEvent = TRUE;
  2308. return; // cannot delete the group
  2309. }
  2310. //
  2311. // reset handling of Program Groups key changes.
  2312. //
  2313. ResetProgramGroupsEvent(bCommonGroup);
  2314. bHandleProgramGroupsEvent = TRUE;
  2315. /* Destroy the window, the global memory block, and the file. */
  2316. SendMessage(hwndMDIClient, WM_MDIDESTROY, (WPARAM)hwndGroup, 0L);
  2317. NukeIconBitmap(pGroup);
  2318. GlobalFree(pGroup->hGroup);
  2319. if (!bCommonGroup) {
  2320. //
  2321. // Remove the program manager's settings for that personal group.
  2322. //
  2323. wsprintf(szT,TEXT("Group%d"),pGroup->wIndex);
  2324. RegDeleteValue(hkeyPMGroups, szT);
  2325. }
  2326. /* Unlink the group structure. */
  2327. for (ppGroup=&pFirstGroup; *ppGroup && *ppGroup != pGroup; ppGroup = &(*ppGroup)->pNext)
  2328. ;
  2329. if (*ppGroup)
  2330. *ppGroup = pGroup->pNext;
  2331. if (pLastGroup == &pGroup->pNext)
  2332. pLastGroup = ppGroup;
  2333. /* Destroying the window should activate another one, but if it is the
  2334. * last one, nothing will get activated, so to make sure punt the
  2335. * current group pointer...
  2336. */
  2337. if (pCurrentGroup == pGroup)
  2338. pCurrentGroup = NULL;
  2339. /* Lastly, toss out the group and item structures. */
  2340. while (pGroup->pItems) {
  2341. pItem = pGroup->pItems;
  2342. pGroup->pItems = pItem->pNext;
  2343. LocalFree((HANDLE)pItem);
  2344. }
  2345. LocalFree((HANDLE)pGroup->lpKey);
  2346. LocalFree((HANDLE)pGroup);
  2347. if (!bCommonGroup) {
  2348. //
  2349. // Change the program manager's settings for that personal group.
  2350. //
  2351. WriteGroupsSection();
  2352. }
  2353. }
  2354. /*--------------------------------------------------------------------------*/
  2355. /* */
  2356. /* ChangeGroupTitle() - */
  2357. /* */
  2358. /* Modifies the name of a program group, on the screen and in the file. */
  2359. /* */
  2360. /*--------------------------------------------------------------------------*/
  2361. VOID FAR PASCAL ChangeGroupTitle(HWND hwndGroup, LPTSTR lpName, BOOL bCommonGroup)
  2362. {
  2363. LPGROUPDEF lpgd;
  2364. PGROUP pGroup;
  2365. DWORD pName;
  2366. TCHAR szCommonGroupSuffix[MAXKEYLEN];
  2367. TCHAR szCommonGroupTitle[2*MAXKEYLEN];
  2368. WINDOWPLACEMENT wp;
  2369. if (!hwndGroup)
  2370. return;
  2371. //
  2372. // Change the title of the window.
  2373. //
  2374. if (bCommonGroup) {
  2375. //
  2376. // Add the common group suffix to the name of the group e.g. (Common),
  2377. // do not append the common suffix if the group window is minimized.
  2378. //
  2379. wp.length = sizeof(WINDOWPLACEMENT);
  2380. GetWindowPlacement(hwndGroup, &wp);
  2381. if (wp.showCmd == SW_MINIMIZE || wp.showCmd == SW_SHOWMINIMIZED ||
  2382. wp.showCmd == SW_SHOWMINNOACTIVE) {
  2383. SetWindowText(hwndGroup, lpName);
  2384. }
  2385. else {
  2386. lstrcpy(szCommonGroupTitle, lpName);
  2387. if (LoadString(hAppInstance, IDS_COMMONGRPSUFFIX, szCommonGroupSuffix,
  2388. CharSizeOf(szCommonGroupSuffix))) {
  2389. lstrcat(szCommonGroupTitle, szCommonGroupSuffix);
  2390. }
  2391. SetWindowText(hwndGroup, szCommonGroupTitle);
  2392. }
  2393. }
  2394. else {
  2395. SetWindowText(hwndGroup, lpName);
  2396. }
  2397. //
  2398. // Remove the old name.
  2399. //
  2400. lpgd = LockGroup(hwndGroup);
  2401. if (!lpgd)
  2402. return;
  2403. DeleteThing(lpgd, (LPDWORD)&lpgd->pName, 0);
  2404. UnlockGroup(hwndGroup);
  2405. //
  2406. // Insert the new one.
  2407. //
  2408. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup,GWLP_PGROUP);
  2409. pName = AddThing(pGroup->hGroup, lpName ,(WORD)0);
  2410. //
  2411. // Set the new offset...
  2412. //
  2413. if (lpgd = LockGroup(hwndGroup)) {
  2414. lpgd->pName = pName;
  2415. UnlockGroup(hwndGroup);
  2416. }
  2417. }
  2418. /*--------------------------------------------------------------------------*/
  2419. /* */
  2420. /* SetGroupDimensions() - */
  2421. /* */
  2422. /* Saves the size and position of the group file in the group segment, as */
  2423. /* as well as the positions of all the item icons */
  2424. /* */
  2425. /*--------------------------------------------------------------------------*/
  2426. VOID NEAR PASCAL SetGroupDimensions(HWND hwndGroup)
  2427. {
  2428. LPGROUPDEF lpgd;
  2429. LPITEMDEF lpid;
  2430. PGROUP pGroup;
  2431. PITEM pItem;
  2432. WORD i;
  2433. lpgd = LockGroup(hwndGroup);
  2434. if (!lpgd)
  2435. return;
  2436. lpgd->nCmdShow = (WORD)GetInternalWindowPos(hwndGroup, &lpgd->rcNormal,
  2437. &lpgd->ptMin);
  2438. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup,GWLP_PGROUP);
  2439. NukeIconBitmap(pGroup); // invalidate the bitmap
  2440. for (pItem=pGroup->pItems; pItem; pItem=pItem->pNext) {
  2441. lpid = ITEM(lpgd,pItem->iItem);
  2442. lpid->pt.x = pItem->rcIcon.left;
  2443. lpid->pt.y = pItem->rcIcon.top;
  2444. /* save offset of ITEMDEF for each item
  2445. */
  2446. ChangeTagID(lpgd,pItem->iItem,(int)lpgd->rgiItems[pItem->iItem]);
  2447. pItem->iItem = (int)lpgd->rgiItems[pItem->iItem];
  2448. }
  2449. for (i=0, pItem=pGroup->pItems; pItem; pItem=pItem->pNext, i++) {
  2450. /* write offsets back out in Z order and update the index
  2451. */
  2452. ChangeTagID(lpgd,pItem->iItem,(int)i);
  2453. lpgd->rgiItems[i] = (DWORD)pItem->iItem;
  2454. pItem->iItem = (int)i;
  2455. }
  2456. /* Clear out remaining pointers to prevent duped item wierdness. */
  2457. while (i < lpgd->cItems)
  2458. lpgd->rgiItems[i++] = 0;
  2459. UnlockGroup(hwndGroup);
  2460. }
  2461. /*--------------------------------------------------------------------------*/
  2462. /* */
  2463. /* WriteGroupsSection() - */
  2464. /* */
  2465. /*--------------------------------------------------------------------------*/
  2466. void PASCAL WriteGroupsSection(VOID)
  2467. {
  2468. PGROUP pGroup;
  2469. HCURSOR hCursor;
  2470. HWND hwndGroup;
  2471. LPGROUPDEF lpgd;
  2472. TCHAR szT[66];
  2473. TCHAR szOrd[CGROUPSMAX*8+7];
  2474. TCHAR szFmt[] = TEXT("Group%d");
  2475. TCHAR szFmtCommonGrp[] = TEXT("GroupC%d");
  2476. INT cGroups;
  2477. TCHAR szGroupKey[MAXKEYLEN];
  2478. INT i;
  2479. RECT rc;
  2480. POINT ptMin;
  2481. TCHAR szCGrpInfo[MAXKEYLEN];
  2482. INT cbValueName;
  2483. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2484. ShowCursor(TRUE);
  2485. if (!(hwndGroup = GetWindow(hwndMDIClient, GW_CHILD))) {
  2486. goto WPIExit;
  2487. }
  2488. hwndGroup = GetWindow(hwndGroup, GW_HWNDLAST);
  2489. szOrd[0] = 0;
  2490. cGroups = 0;
  2491. //
  2492. // Clear user's previous positioning of common groups.
  2493. //
  2494. if (hkeyPMCommonGroups) {
  2495. cbValueName = CharSizeOf(szGroupKey);
  2496. while (!RegEnumValue(hkeyPMCommonGroups, 0, szGroupKey, &cbValueName, 0, 0,
  2497. 0, 0)) {
  2498. RegDeleteValue(hkeyPMCommonGroups, szGroupKey);
  2499. cbValueName = CharSizeOf(szGroupKey);
  2500. }
  2501. }
  2502. for (; hwndGroup; hwndGroup = GetWindow(hwndGroup, GW_HWNDPREV)) {
  2503. /*
  2504. * Check to make sure we're not out of room for the order string.
  2505. */
  2506. if (cGroups > CGROUPSMAX) {
  2507. MessageBeep(0);
  2508. break;
  2509. }
  2510. if (GetWindow(hwndGroup, GW_OWNER)) {
  2511. continue;
  2512. }
  2513. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
  2514. if (!pGroup->lpKey || !*pGroup->lpKey) {
  2515. if (pGroup->lpKey) {
  2516. LocalFree((HANDLE)pGroup->lpKey);
  2517. }
  2518. lpgd = LockGroup(hwndGroup);
  2519. if (!lpgd) {
  2520. continue;
  2521. }
  2522. lstrcpy(szGroupKey, (LPTSTR) PTR(lpgd, lpgd->pName));
  2523. pGroup->lpKey = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)*(lstrlen(szGroupKey) + 1));
  2524. lstrcpy(pGroup->lpKey, szGroupKey);
  2525. UnlockGroup(hwndGroup);
  2526. }
  2527. if (pGroup->fCommon) {
  2528. wsprintf(szT, szFmtCommonGrp, pGroup->wIndex);
  2529. lstrcat(szOrd, TEXT(" C"));
  2530. lstrcat(szOrd, szT + CCHCOMMONGROUP);
  2531. if (hkeyPMCommonGroups) {
  2532. i = GetInternalWindowPos(hwndGroup, &rc, &ptMin);
  2533. if (i==SW_SHOWMINNOACTIVE)
  2534. i = SW_SHOWNORMAL;
  2535. wsprintf(szCGrpInfo, TEXT("%d %d %d %d %d %d %d "),
  2536. rc.left, rc.top, rc.right, rc.bottom,
  2537. ptMin.x, ptMin.y, i);
  2538. lstrcat(szCGrpInfo, pGroup->lpKey);
  2539. RegSetValueEx(hkeyPMCommonGroups, szT, 0, REG_SZ, (LPBYTE)szCGrpInfo, sizeof(TCHAR)*(lstrlen(szCGrpInfo)+1));
  2540. }
  2541. }
  2542. else {
  2543. wsprintf(szT, szFmt, pGroup->wIndex);
  2544. lstrcat(szOrd, TEXT(" "));
  2545. lstrcat(szOrd, szT + CCHGROUP);
  2546. if (hkeyPMGroups) {
  2547. RegSetValueEx(hkeyPMGroups, szT, 0, REG_SZ, (LPBYTE)pGroup->lpKey, sizeof(TCHAR)*(lstrlen(pGroup->lpKey)+1));
  2548. }
  2549. }
  2550. cGroups++;
  2551. }
  2552. if (hkeyPMSettings) {
  2553. RegSetValueEx(hkeyPMSettings, szOrder, 0, REG_SZ, (LPBYTE)szOrd, sizeof(TCHAR)*(lstrlen(szOrd) + 1));
  2554. }
  2555. WPIExit:
  2556. ShowCursor(FALSE);
  2557. SetCursor(hCursor);
  2558. }
  2559. /*--------------------------------------------------------------------------*/
  2560. /* */
  2561. /* SaveGroupsContent() -
  2562. /*
  2563. /* Save the contents of the all the groups, doesn't save changes in
  2564. /* size or position if bSaveGroupSettings is FALSE, only the group items.
  2565. /* */
  2566. /*--------------------------------------------------------------------------*/
  2567. BOOL SaveGroupsContent(BOOL bSaveGroupSettings)
  2568. {
  2569. HWND hwndGroup;
  2570. hwndGroup = GetWindow(hwndMDIClient, GW_CHILD);
  2571. if (!hwndGroup)
  2572. return FALSE;
  2573. for (hwndGroup=GetWindow(hwndGroup, GW_HWNDLAST); hwndGroup; hwndGroup=GetWindow(hwndGroup, GW_HWNDPREV)) {
  2574. if (GetWindow(hwndGroup, GW_OWNER))
  2575. continue;
  2576. /* Save the latest sizes and positions. */
  2577. if (bSaveGroupSettings) {
  2578. SetGroupDimensions(hwndGroup);
  2579. if (wLockError == LOCK_LOWMEM && !fLowMemErrYet) {
  2580. // No more error messages.
  2581. fLowMemErrYet = TRUE;
  2582. wLockError = 0;
  2583. // Warn user that some settings couldn't be saved.
  2584. MyMessageBox(hwndProgman, IDS_OOMEXITTITLE, IDS_LOWMEMONEXIT, NULL,
  2585. MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);
  2586. }
  2587. }
  2588. SaveGroup(hwndGroup, TRUE);
  2589. }
  2590. RegFlushKey(HKEY_CURRENT_USER);
  2591. return(TRUE);
  2592. }
  2593. /*--------------------------------------------------------------------------*/
  2594. /* */
  2595. /* WriteINIFile() - */
  2596. /* */
  2597. /*--------------------------------------------------------------------------*/
  2598. void FAR PASCAL WriteINIFile()
  2599. {
  2600. register int i;
  2601. RECT rc;
  2602. TCHAR szT[40];
  2603. HANDLE hCursor;
  2604. //
  2605. // Don't save if restricted. But force save if we've just converted the
  2606. // ansi groups to unicode so we can work from unicode the next time around.
  2607. //
  2608. if (fNoSave && !bUseANSIGroups)
  2609. return;
  2610. fLowMemErrYet = FALSE;
  2611. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2612. ShowCursor(TRUE);
  2613. i = GetInternalWindowPos(hwndProgman, &rc, NULL);
  2614. if (i==SW_SHOWMINNOACTIVE)
  2615. i = SW_SHOWNORMAL;
  2616. wsprintf(szT, TEXT("%d %d %d %d %d"), rc.left, rc.top, rc.right, rc.bottom, i);
  2617. if (hkeyPMSettings) {
  2618. RegSetValueEx(hkeyPMSettings, szWindow, 0, REG_SZ, (LPBYTE)szT, sizeof(TCHAR)*(lstrlen(szT)+ 1));
  2619. }
  2620. if (!bLoadEvil)
  2621. WriteGroupsSection();
  2622. //
  2623. // Save all groups content, TRUE means we want the size and position saved
  2624. // as well.
  2625. //
  2626. SaveGroupsContent(TRUE);
  2627. ShowCursor(FALSE);
  2628. SetCursor(hCursor);
  2629. }
  2630. /*--------------------------------------------------------------------------*/
  2631. /* */
  2632. /* GetItemCommand() - */
  2633. /* */
  2634. /*--------------------------------------------------------------------------*/
  2635. void FAR PASCAL GetItemCommand(
  2636. PGROUP pGroup,
  2637. PITEM pItem,
  2638. LPTSTR lpCommand,
  2639. LPTSTR lpDir)
  2640. {
  2641. BYTE b=0;
  2642. LPTSTR lp1, lp2, lp3;
  2643. LPGROUPDEF lpgd;
  2644. LPITEMDEF lpid;
  2645. BOOL bNoFirstQuote = TRUE;
  2646. if (!GetGroupTag(pGroup,pItem,(WORD)ID_APPLICATIONDIR,lpCommand,MAXITEMPATHLEN)) {
  2647. // the application directory is not defined
  2648. *lpCommand = 0;
  2649. }
  2650. lpgd = LockGroup(pGroup->hwnd);
  2651. if (!lpgd) {
  2652. *lpCommand = 0;
  2653. *lpDir = 0;
  2654. return;
  2655. }
  2656. lpid = ITEM(lpgd,pItem->iItem);
  2657. // init working directory
  2658. lp3 = lpDir;
  2659. *lp3 = 0;
  2660. // item command
  2661. lp1 = (LPTSTR) PTR(lpgd, lpid->pCommand);
  2662. if (*lp1 == TEXT('"')) {
  2663. lp2 = lp1;
  2664. while (lp2 && (lp2 = wcschr(lp2+1, TEXT('"'))) && *(lp2+1) != TEXT('\\')) { //go to next quote
  2665. ;
  2666. }
  2667. if (!lp2) {
  2668. //
  2669. // The directory is not in quotes and since the command path starts
  2670. // with a quote, there's no working directory.
  2671. //
  2672. lp2 = lpDir;
  2673. *lp2 = 0;
  2674. }
  2675. else {
  2676. if (*(lp2+1) == TEXT('\\')) {
  2677. //
  2678. // the working directory is in quotes
  2679. //
  2680. *lp3++ = *lp1++; //write first quote
  2681. for (; *lp1 && lp1 != lp2; lp1 = CharNext(lp1)) {
  2682. *lp3++ = *lp1;
  2683. }
  2684. if (*lp1 == TEXT('"')) {
  2685. *lp3++ = *lp1++; //write last quote
  2686. lp1++;
  2687. *lp3 = 0;
  2688. }
  2689. }
  2690. lp2 = lp3 + lstrlen(lp3);
  2691. }
  2692. }
  2693. else {
  2694. //
  2695. // if there's a working directory, it is not in quotes
  2696. //
  2697. for (lp2 = lp3 = lpDir; *lp1 && *lp1 != TEXT(' ') && *lp1 != TEXT('"'); // the command line might be in quotes
  2698. lp1 = CharNext(lp1)) {
  2699. *lp3++ = *lp1;
  2700. if (*lp1 == TEXT(':') || *lp1 == TEXT('\\'))
  2701. lp2 = lp3;
  2702. }
  2703. *lp3 = 0;
  2704. }
  2705. /* we are assuming the exe dir contains the necessary separator
  2706. * add the filename to the command line
  2707. */
  2708. lstrcat(lpCommand,lp2);
  2709. /* add the arguments to the command line
  2710. */
  2711. lstrcat(lpCommand,lp1);
  2712. /* truncate the command name from the exe path. note this implies
  2713. * that if there is no path, lpDir will be empty
  2714. */
  2715. *lp2 = 0;
  2716. lp2 = CharPrev(lpDir,lp2);
  2717. if (*lp2 == TEXT('\\') && *CharPrev(lpDir,lp2) != TEXT(':'))
  2718. *lp2 = 0;
  2719. UnlockGroup(pGroup->hwnd);
  2720. }
  2721. /*--------------------------------------------------------------------------*/
  2722. /* */
  2723. /* DuplicateItem() - */
  2724. /* */
  2725. /*--------------------------------------------------------------------------*/
  2726. PITEM PASCAL DuplicateItem(
  2727. PGROUP pGroup,
  2728. PITEM pItem,
  2729. PGROUP pGNew,
  2730. LPPOINT lppt)
  2731. {
  2732. WORD wIconId;
  2733. WORD wIconIndex;
  2734. LPITEMDEF lpid;
  2735. LPGROUPDEF lpgd;
  2736. TCHAR szCommand[MAXITEMPATHLEN + 1];
  2737. TCHAR szDefDir[2 * (MAXITEMPATHLEN + 1)];
  2738. TCHAR szIconPath[MAXITEMPATHLEN + 1];
  2739. TCHAR szName[64];
  2740. TCHAR szExpPath[MAXITEMPATHLEN+1];
  2741. TCHAR szExpDir[MAXITEMPATHLEN+1];
  2742. DWORD dwFlags = CI_ACTIVATE;
  2743. lpid = LockItem(pGroup, pItem);
  2744. if (lpid == 0L) {
  2745. UnlockGroup(pGroup->hwnd);
  2746. return NULL;
  2747. }
  2748. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  2749. lstrcpy(szName, (LPTSTR) PTR(lpgd, lpid->pName));
  2750. lstrcpy(szIconPath, (LPTSTR) PTR(lpgd, lpid->pIconPath));
  2751. wIconId = lpid->iIcon;
  2752. wIconIndex = lpid->wIconIndex;
  2753. GlobalUnlock(pGroup->hGroup);
  2754. UnlockGroup(pGroup->hwnd);
  2755. GetItemCommand(pGroup, pItem, szCommand, szDefDir);
  2756. //
  2757. // I f there's no icon path, check if we have an executable associated
  2758. // with the command path.
  2759. //
  2760. if (!*szIconPath) {
  2761. lstrcpy(szExpPath, szCommand);
  2762. DoEnvironmentSubst(szExpPath, CharSizeOf(szExpPath));
  2763. StripArgs(szExpPath);
  2764. lstrcpy(szExpDir, szDefDir);
  2765. DoEnvironmentSubst(szExpDir, CharSizeOf(szExpDir));
  2766. FindExecutable(szExpPath, szExpDir, szIconPath);
  2767. if (!*szIconPath) {
  2768. dwFlags |= CI_NO_ASSOCIATION;
  2769. }
  2770. else
  2771. *szIconPath = 0;
  2772. }
  2773. if (GroupFlag(pGroup, pItem, (WORD)ID_NEWVDM)) {
  2774. dwFlags |= CI_SEPARATE_VDM;
  2775. }
  2776. return CreateNewItem(pGNew->hwnd,
  2777. szName,
  2778. szCommand,
  2779. szIconPath,
  2780. szDefDir,
  2781. GroupFlag(pGroup, pItem, (WORD)ID_HOTKEY),
  2782. GroupFlag(pGroup, pItem, (WORD)ID_MINIMIZE),
  2783. wIconId,
  2784. wIconIndex,
  2785. NULL,
  2786. lppt,
  2787. dwFlags);
  2788. }