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.

2651 lines
85 KiB

  1. /****************************************************************************/
  2. /* */
  3. /* PMDDE.C - */
  4. /* */
  5. /* Windows Program Starter DDE Routines */
  6. /* */
  7. /****************************************************************************/
  8. #include "progman.h"
  9. #include "dde.h"
  10. #include "uniconv.h"
  11. #define PMPrint(s) KdPrint(("PROGMAN: ")); \
  12. KdPrint(s); \
  13. KdPrint(("\n"));
  14. //
  15. // Define this if you want to know everything about Progman DDE
  16. //
  17. //#define VERBOSE_PROGMANDDE
  18. #ifdef VERBOSE_PROGMANDDE
  19. #define VerbosePrint(s) PMPrint(s)
  20. #else
  21. #define VerbosePrint(s)
  22. #endif
  23. /* DDE window classes */
  24. TCHAR szProgmanDDE[] = TEXT("ProgmanDDE");
  25. TCHAR szAppIconDDE[] = TEXT("AppIconDDE");
  26. TCHAR szAppDescDDE[] = TEXT("AppDescDDE");
  27. TCHAR szAppWDirDDE[] = TEXT("AppWDirDDE");
  28. //
  29. // For compatibility reasons, allow the old WIn3.1 Shell - AppProperties
  30. // DDE connection.
  31. //
  32. TCHAR szAppProperties[] = TEXT("AppProperties");
  33. BOOL bProgmanDDE = TRUE;
  34. BOOL bAppIconDDE = TRUE;
  35. BOOL bAppDescDDE = TRUE;
  36. BOOL bAppWDirDDE = TRUE;
  37. /* application names*/
  38. TCHAR szShell[] = TEXT("Shell");
  39. /* topics*/
  40. TCHAR szAppIcon[] = TEXT("AppIcon");
  41. TCHAR szAppDesc[] = TEXT("AppDescription");
  42. TCHAR szAppWDir[] = TEXT("AppWorkingDir");
  43. TCHAR szSystem[] = TEXT("System");
  44. /* items*/
  45. TCHAR szGroupList[] = TEXT("Groups");
  46. #define DDE_PROGMAN 0
  47. #define APP_ICON 1
  48. #define APP_DESC 2
  49. #define APP_WDIR 3
  50. #define WCHAR_QUOTE L'"'
  51. BOOL fForcePoint = FALSE; /* used for replacement*/
  52. POINT ptForce;
  53. typedef struct _datadde
  54. {
  55. unsigned short unused:12,
  56. fResponse:1,
  57. fRelease:1,
  58. reserved:1,
  59. fAckReq:1;
  60. WORD cfFormat;
  61. } DATADDE;
  62. typedef struct _newicondata
  63. {
  64. DATADDE dd;
  65. DWORD dwResSize;
  66. DWORD dwVer;
  67. BYTE iResource;
  68. } NEWICONDATA;
  69. int NEAR PASCAL myatoi(LPTSTR lp);
  70. LPTSTR NEAR PASCAL SkipWhite(LPTSTR lpsz);
  71. LPTSTR APIENTRY GetOneParameter(LPTSTR lpCmd, WPARAM *lpW, BOOL bSaveQuotes);
  72. LPTSTR NEAR PASCAL GetCommandName(LPTSTR lpCmd, LPTSTR lpFormat, WPARAM *lpW);
  73. HANDLE NEAR PASCAL GetDDECommands(LPTSTR lpCmd, LPTSTR lpFormat);
  74. typedef struct _ddeconversation {
  75. HWND hwndClient;
  76. HWND hwndServer;
  77. DWORD dwType;
  78. struct _ddeconversation *Next;
  79. } DDECONVERSATION, *PDDECONVERSATION;
  80. PDDECONVERSATION pDdeConversation = NULL;
  81. /*--------------------------------------------------------------------------*/
  82. /* */
  83. /* InitDDEConverstionStruct() - */
  84. /* */
  85. /*--------------------------------------------------------------------------*/
  86. VOID InitDdeConversationStruct()
  87. {
  88. pDdeConversation = (PDDECONVERSATION)LocalAlloc(LPTR, sizeof(DDECONVERSATION));
  89. pDdeConversation->Next = NULL;
  90. }
  91. /*--------------------------------------------------------------------------*/
  92. /* */
  93. /* AddDdeConverstion() - */
  94. /* */
  95. /*--------------------------------------------------------------------------*/
  96. VOID AddDdeConversation(HWND hwndServer, HWND hwndClient, DWORD dwType)
  97. {
  98. PDDECONVERSATION pT = NULL;
  99. if (!pDdeConversation) {
  100. return;
  101. }
  102. if (pT = (PDDECONVERSATION)LocalAlloc(LPTR, sizeof(DDECONVERSATION))) {
  103. pT->hwndServer = hwndServer;
  104. pT->hwndClient = hwndClient;
  105. pT->dwType = dwType;
  106. pT->Next = pDdeConversation->Next;
  107. pDdeConversation->Next = pT;
  108. }
  109. }
  110. /*--------------------------------------------------------------------------*/
  111. /* */
  112. /* RemoveDdeConverstion() - */
  113. /* */
  114. /*--------------------------------------------------------------------------*/
  115. VOID RemoveDdeConversation(HWND hwndServer, HWND hwndClient, DWORD dwType)
  116. {
  117. PDDECONVERSATION pT;
  118. PDDECONVERSATION pFree;
  119. if (!pDdeConversation) {
  120. return;
  121. }
  122. for (pT = pDdeConversation; pT->Next; pT = pT->Next) {
  123. if ((pT->Next->hwndClient == hwndClient) &&
  124. (pT->Next->hwndServer == hwndServer) &&
  125. (pT->Next->dwType == dwType)) {
  126. pFree = pT->Next;
  127. pT->Next = pT->Next->Next;
  128. LocalFree(pFree);
  129. return;
  130. }
  131. }
  132. }
  133. /*--------------------------------------------------------------------------*/
  134. /* */
  135. /* IsDDEConverstion() - */
  136. /* */
  137. /*--------------------------------------------------------------------------*/
  138. BOOL IsDdeConversation(HWND hwndServer, HWND hwndClient, DWORD dwType)
  139. {
  140. PDDECONVERSATION pT;
  141. if (!pDdeConversation) {
  142. return(FALSE);
  143. }
  144. for (pT = pDdeConversation; pT->Next; pT = pT->Next) {
  145. if ((pT->Next->hwndClient == hwndClient) &&
  146. (pT->Next->hwndServer == hwndServer) &&
  147. (pT->Next->dwType == dwType)) {
  148. return(TRUE);
  149. }
  150. }
  151. return(FALSE);
  152. }
  153. /*--------------------------------------------------------------------------*/
  154. /* */
  155. /* DDEFail() - */
  156. /* */
  157. /*--------------------------------------------------------------------------*/
  158. VOID APIENTRY DDEFail(HWND hWnd, HWND hwndTo, ATOM aItem)
  159. {
  160. MPostWM_DDE_ACK(hwndTo, hWnd, ACK_NEG, aItem);
  161. }
  162. /*--------------------------------------------------------------------------*/
  163. /* */
  164. /* SkipWhite() - */
  165. /* */
  166. /* Returns a pointer to the first non-whitespace character in a string. */
  167. /* */
  168. /*--------------------------------------------------------------------------*/
  169. LPTSTR APIENTRY SkipWhite(LPTSTR lpsz)
  170. {
  171. /* prevent sign extension */
  172. while (*lpsz && (TUCHAR)*lpsz <= (TUCHAR)TEXT(' '))
  173. lpsz++;
  174. return(lpsz);
  175. }
  176. /*--------------------------------------------------------------------------*/
  177. /* */
  178. /* GetCommandName() - */
  179. /* */
  180. /* Extracts an alphabetic string and looks it up in a list of possible
  181. /* commands, returning a pointer to the character after the command and
  182. /* sticking the command index somewhere.
  183. /*
  184. /* lpFormat string syntax:
  185. /* cmd\0cmd\0...\0\0
  186. /*
  187. /*--------------------------------------------------------------------------*/
  188. LPTSTR APIENTRY GetCommandName(LPTSTR lpCmd, LPTSTR lpFormat, WPARAM *lpW)
  189. {
  190. register TCHAR chT;
  191. register WORD iCmd = 0;
  192. LPTSTR lpT;
  193. /* Eat any white space. */
  194. lpT = lpCmd = SkipWhite(lpCmd);
  195. /* Find the end of the token. */
  196. while (IsCharAlpha(*lpCmd))
  197. lpCmd++;
  198. /* Temporarily NULL terminate it. */
  199. chT = *lpCmd;
  200. *lpCmd = TEXT('\0');
  201. /* Look up the token in a list of commands. */
  202. *lpW = (DWORD_PTR)0xFFFF;
  203. while (*lpFormat) {
  204. if (!lstrcmpi(lpFormat, lpT)) {
  205. *lpW = iCmd;
  206. break;
  207. }
  208. iCmd++;
  209. while (*lpFormat++)
  210. ;
  211. }
  212. *lpCmd = chT;
  213. return(lpCmd);
  214. }
  215. /*--------------------------------------------------------------------------*/
  216. /* */
  217. /* ValidateFileName() - */
  218. /* */
  219. /* Checks if the given filename really exists. The filename passed */
  220. /* in will have quotes around it, so this routine removes the quotes */
  221. /* first. Returns TRUE if it is a valid file. */
  222. /* */
  223. /*--------------------------------------------------------------------------*/
  224. BOOL APIENTRY ValidateFileName (LPTSTR lpFileName)
  225. {
  226. TCHAR chT;
  227. WORD wLen;
  228. LPTSTR lpEnd;
  229. BOOL bResult = FALSE;
  230. HANDLE hFile;
  231. WIN32_FIND_DATA fd;
  232. // Save the last character (better be a quote), and move
  233. // the terminating NULL one character forward.
  234. wLen = (WORD)lstrlen (lpFileName);
  235. lpEnd = lpFileName + wLen - 1;
  236. chT = *lpEnd;
  237. // MarkTa fix for spaces at the end of a filename
  238. // Remove the spaces by moving the quote forward.
  239. while (*(lpEnd-1) == TEXT(' '))
  240. lpEnd--;
  241. *lpEnd = TEXT('\0');
  242. // Test if this is a file.
  243. hFile = FindFirstFile(lpFileName+1, &fd);
  244. if (hFile != INVALID_HANDLE_VALUE)
  245. {
  246. FindClose (hFile);
  247. bResult = TRUE;
  248. }
  249. // Put back the character we removed eariler, and NULL terminate
  250. *lpEnd = chT;
  251. *(lpEnd+1) = TEXT('\0');
  252. return (bResult);
  253. }
  254. /*--------------------------------------------------------------------------*/
  255. /* */
  256. /* GetOneParameter() - */
  257. /* */
  258. /* Reads a parameter out of a string removing leading and trailing whitespace.
  259. /* Terminated by , or ). ] [ and ( are not allowed. Exception: quoted
  260. /* strings are treated as a whole parameter and may contain []() and ,.
  261. /* Places the offset of the first character of the parameter into some place
  262. /* and NULL terminates the parameter.
  263. /*
  264. /*--------------------------------------------------------------------------*/
  265. LPTSTR APIENTRY GetOneParameter(LPTSTR lpCmd, WPARAM *lpW, BOOL bSaveQuotes)
  266. {
  267. LPTSTR lpT;
  268. LPTSTR lpTemp;
  269. TCHAR chT;
  270. WORD wLen;
  271. LPTSTR lpEnd;
  272. switch (*lpCmd) {
  273. case TEXT(','):
  274. *lpW = (DWORD_PTR)lpCmd;
  275. *lpCmd++ = 0; /* comma: becomes a NULL string */
  276. break;
  277. case TEXT('"'): /* quoted string... trim off " */
  278. VerbosePrint (("Quoted parameter before parsing: %S", lpCmd));
  279. VerbosePrint (("bSaveQuotes = %d", bSaveQuotes));
  280. if (bSaveQuotes)
  281. {
  282. // Set the beginning marker at the quote then increment.
  283. *lpW = (DWORD_PTR)lpCmd;
  284. ++lpCmd;
  285. }
  286. else
  287. {
  288. // Increment first to skip the quote
  289. ++lpCmd;
  290. *lpW = (DWORD_PTR)lpCmd;
  291. }
  292. while (*lpCmd && *lpCmd != TEXT('"'))
  293. lpCmd++;
  294. if (!*lpCmd)
  295. return(NULL);
  296. lpTemp = lpCmd; // lpTemp should point at the quote
  297. lpCmd++;
  298. if (bSaveQuotes)
  299. {
  300. chT = *lpCmd;
  301. *lpCmd = TEXT('\0');
  302. VerbosePrint (("Checking %S to confirm that it really is a file.", *lpW));
  303. if (!ValidateFileName ((LPTSTR) *lpW))
  304. {
  305. // file doesn't exist. Remove the quotes.
  306. VerbosePrint (("No, this isn't a file. Removing the quotes."));
  307. *lpW = *lpW + sizeof (TCHAR);
  308. lpTemp = (LPTSTR)(*lpW) + lstrlen((LPTSTR) (*lpW)) - 1;
  309. *lpTemp = TEXT('\0');
  310. VerbosePrint (("New string after removing the quotes: %S", *lpW));
  311. }
  312. else
  313. {
  314. //
  315. // The quoted filename is valid, so now we want to test if
  316. // the quotes are really necessary. To do this, remove
  317. // the quotes, and then call CheckEscapes to look for funny
  318. // characters.
  319. //
  320. VerbosePrint (("Yes, %S is a file. Checking if we really need these quotes", *lpW));
  321. SheRemoveQuotes ((LPTSTR) *lpW);
  322. CheckEscapes ((LPTSTR) *lpW, lstrlen ((LPTSTR) *lpW) + 2);
  323. VerbosePrint (("After checking quotes we have %S", *lpW));
  324. }
  325. *lpCmd = chT;
  326. }
  327. else
  328. *lpTemp = TEXT(' ');
  329. while (*lpCmd && *lpCmd != TEXT(')') && *lpCmd != TEXT(','))
  330. lpCmd++;
  331. if (!*lpCmd)
  332. return(NULL);
  333. if (*lpCmd == TEXT(','))
  334. {
  335. *lpCmd = TEXT('\0');
  336. lpCmd++;
  337. }
  338. else
  339. *lpCmd = TEXT('\0');
  340. // Remove the space at the end of the string if the parser
  341. // added it.
  342. wLen = (WORD)lstrlen ((LPTSTR)(*lpW));
  343. lpEnd = (LPTSTR)(*lpW) + wLen - 1;
  344. if (*lpEnd == TEXT (' '))
  345. *lpEnd = TEXT('\0');
  346. VerbosePrint (("Quoted parameter after parsing: %S", *lpW));
  347. break;
  348. case TEXT(')'):
  349. return(lpCmd); /* we ought not to hit this */
  350. case TEXT('('):
  351. case TEXT('['):
  352. case TEXT(']'):
  353. return(NULL); /* these are illegal */
  354. default:
  355. lpT = lpCmd;
  356. *lpW = (DWORD_PTR)lpT;
  357. while (*lpCmd && *lpCmd != TEXT(',') && *lpCmd != TEXT(')')) {
  358. /* Check for illegal characters. */
  359. if (*lpCmd == TEXT(']') || *lpCmd == TEXT('[') || *lpCmd == TEXT('(') )
  360. return(NULL);
  361. /* Remove trailing whitespace */
  362. /* prevent sign extension */
  363. if ((TUCHAR)*lpCmd > (TUCHAR)TEXT(' '))
  364. lpT = lpCmd;
  365. lpCmd = CharNext(lpCmd);
  366. }
  367. /* Eat any trailing comma. */
  368. if (*lpCmd == TEXT(','))
  369. lpCmd++;
  370. /* NULL terminator after last nonblank character -- may write over
  371. * terminating ')' but the caller checks for that because this is
  372. * a hack.
  373. */
  374. lpT = CharNext(lpT);
  375. *lpT = TEXT('\0');
  376. break;
  377. }
  378. /* Return next unused character. */
  379. return(lpCmd);
  380. }
  381. /*--------------------------------------------------------------------------*/
  382. /* */
  383. /* GetDDECommands() - */
  384. /* */
  385. /* Called with: far pointer to a string to parse and a far pointer to a
  386. /* list of sz's containing the allowed function names.
  387. /* The function returns a global handle to an array of words containing
  388. /* one or more command definitions. A command definition consists of
  389. /* a command index, a parameter count, and that number of offsets. Each
  390. /* offset is an offset to a parameter in lpCmd which is now zero terminated.
  391. /* The list of command is terminated with -1.
  392. /* If there was a syntax error the return value is NULL.
  393. /* Caller must free block.
  394. /*
  395. /*--------------------------------------------------------------------------*/
  396. HANDLE NEAR PASCAL GetDDECommands(LPTSTR lpCmd, LPTSTR lpFormat)
  397. {
  398. register WORD cParm;
  399. WORD cCmd = 0;
  400. register HANDLE hDDECmds;
  401. DWORD_PTR * lpW = NULL;
  402. BOOL bAddItem = FALSE;
  403. /* Will allow up to 128 words, 64 single command (less with parms). */
  404. /*
  405. * Now these are 32bit, since the offset is now replaced by the
  406. * full pointer which is 32 bit.
  407. *
  408. * (And if they are 64bit, they get even bigger.)
  409. */
  410. hDDECmds = GlobalAlloc(GHND, 128 * sizeof(DWORD_PTR));
  411. if (!hDDECmds)
  412. return(NULL);
  413. /* Get pointer to array. */
  414. lpW = (DWORD_PTR *)GlobalLock(hDDECmds);
  415. while (*lpCmd) {
  416. /* Skip leading whitespace. */
  417. lpCmd = SkipWhite(lpCmd);
  418. /* Are we at a NULL? */
  419. if (!*lpCmd) {
  420. /* Did we find any commands yet? */
  421. if (cCmd)
  422. goto GDEExit;
  423. else
  424. goto GDEErrExit;
  425. }
  426. /* Each command should be inside square brackets. */
  427. if (*lpCmd != TEXT('['))
  428. goto GDEErrExit;
  429. lpCmd++;
  430. /* Get the command name. */
  431. lpCmd = GetCommandName(lpCmd, lpFormat, lpW);
  432. if (*lpW == (DWORD_PTR)0xFFFF)
  433. goto GDEErrExit;
  434. if (*lpW == 1)
  435. bAddItem = TRUE;
  436. lpW++;
  437. /* Start with zero parms. */
  438. cParm = 0;
  439. lpCmd = SkipWhite(lpCmd);
  440. /* Check for opening '(' */
  441. if (*lpCmd == TEXT('(')) {
  442. lpCmd++;
  443. /* Skip white space and then find some parameters (may be none). */
  444. lpCmd = SkipWhite(lpCmd);
  445. while (*lpCmd != TEXT(')')) {
  446. if (!*lpCmd)
  447. goto GDEErrExit;
  448. /* Get the parameter. */
  449. if (bAddItem && (cParm == 0 || cParm == 2 || cParm == 6))
  450. {
  451. // In this case, we are working with filenames of
  452. // the command line, icon path, or default directory of
  453. // the AddItem command.
  454. // We don't want to strip the quotes if they exist.
  455. if (!(lpCmd = GetOneParameter(lpCmd, lpW + (++cParm), TRUE)))
  456. goto GDEErrExit;
  457. }
  458. else
  459. {
  460. // This is for every other parameter. The quotes will be
  461. // stripped.
  462. if (!(lpCmd = GetOneParameter(lpCmd, lpW + (++cParm), FALSE)))
  463. goto GDEErrExit;
  464. }
  465. /* HACK: Did GOP replace a ')' with a NULL? */
  466. if (!*lpCmd)
  467. break;
  468. /* Find the next one or ')' */
  469. lpCmd = SkipWhite(lpCmd);
  470. }
  471. lpCmd++;
  472. /* Skip the terminating stuff. */
  473. lpCmd = SkipWhite(lpCmd);
  474. }
  475. /* Set the count of parameters and then skip the parameters. */
  476. *lpW++ = cParm;
  477. lpW += cParm;
  478. /* We found one more command. */
  479. cCmd++;
  480. /* Commands must be in square brackets. */
  481. if (*lpCmd != TEXT(']'))
  482. goto GDEErrExit;
  483. lpCmd++;
  484. }
  485. GDEExit:
  486. /* Terminate the command list with -1. */
  487. *lpW = (DWORD_PTR)0xFFFF;
  488. GlobalUnlock(hDDECmds);
  489. return(hDDECmds);
  490. GDEErrExit:
  491. GlobalUnlock(hDDECmds);
  492. GlobalFree(hDDECmds);
  493. return(NULL);
  494. }
  495. /*--------------------------------------------------------------------------*/
  496. /* */
  497. /* IsParameterANumber() - */
  498. /* */
  499. /*--------------------------------------------------------------------------*/
  500. BOOL APIENTRY IsParameterANumber(LPTSTR lp)
  501. {
  502. while (*lp) {
  503. if (*lp < TEXT('0') || *lp > TEXT('9'))
  504. return(FALSE);
  505. lp++;
  506. }
  507. return(TRUE);
  508. }
  509. /*--------------------------------------------------------------------------*/
  510. /* */
  511. /* myatoi() - */
  512. /* */
  513. /*--------------------------------------------------------------------------*/
  514. int APIENTRY myatoi(LPTSTR lp)
  515. {
  516. register int i = 0;
  517. while (*lp >= TEXT('0') && *lp <= TEXT('9')) {
  518. i *= 10;
  519. i += (int)(*lp-TEXT('0'));
  520. lp++;
  521. }
  522. return(i);
  523. }
  524. /*--------------------------------------------------------------------------*/
  525. /* */
  526. /* ExecuteHandler() - */
  527. /* */
  528. /* Handles WM_DDE_EXECUTE messages... */
  529. /* */
  530. /* return 0 if it fails */
  531. /* 1 if it succeeds */
  532. /* 2 if it succeeds and the command was ExitProgman */
  533. /* */
  534. /*--------------------------------------------------------------------------*/
  535. DWORD APIENTRY ExecuteHandler(HANDLE hString)
  536. {
  537. register HWND hwndT;
  538. LPTSTR lpT;
  539. LPTSTR lpString;
  540. register HANDLE hCmd;
  541. DWORD_PTR * lpwCmd;
  542. DWORD dwRet = 0;
  543. PGROUP pGroup;
  544. LPGROUPDEF lpgd;
  545. WCHAR lpFmtinit[] = TEXT("CreateGroup#AddItem#DeleteGroup#ExitProgman#ShowGroup#DeleteItem#ReplaceItem#Reload#ChangeINIFile#");
  546. LPTSTR lpFmt ;
  547. lpFmt = lpFmtinit;
  548. /* Lock the command string. */
  549. lpString = (LPTSTR)GlobalLock(hString);
  550. if(!lpString)
  551. return(0);
  552. VerbosePrint(("Execute Handler received: %S", lpString));
  553. #ifdef DEBUG_PROGMAN_DDE
  554. {
  555. TCHAR szDebug[300];
  556. wsprintf (szDebug, TEXT("%d PROGMAN: Execute Handler recived: %s\r\n"),
  557. GetTickCount(), lpString);
  558. OutputDebugString(szDebug);
  559. }
  560. #endif
  561. bInDDE = TRUE;
  562. /* Parse the commands. */
  563. // the following line does not work on build 363! TEXT string is truncated
  564. // after "CreateGroup".
  565. //hCmd = GetDDECommands(lpString, (LPTSTR)TEXT("CreateGroup\0AddItem\0DeleteGroup\0ExitProgman\0ShowGroup\0DeleteItem\0ReplaceItem\0Reload\0ChangeINIFile\0"));
  566. // substitute nulls for '#'
  567. while (*lpFmt) {
  568. if (*lpFmt == TEXT('#'))
  569. *lpFmt = (TCHAR) 0;
  570. lpFmt++ ;
  571. }
  572. lpFmt = lpFmtinit; // reset the pointer back to the begining
  573. hCmd = GetDDECommands(lpString, lpFmt) ;
  574. if (!hCmd)
  575. goto DEHErrExit1;
  576. /* Lock the list of commands and parameter offsets. */
  577. lpwCmd = (DWORD_PTR *)GlobalLock(hCmd);
  578. /* Execute each command. */
  579. while (*lpwCmd != (DWORD_PTR)0xFFFF) {
  580. switch (*lpwCmd++) {
  581. case 0:
  582. {
  583. INT cParm;
  584. INT nCommonGrp = -1;
  585. LPTSTR lpCommonGrp = NULL;
  586. LPTSTR lpGroupName;
  587. /* [ CreateGroup ( groupname [, groupfile] [, common_group_flag] ) ] */
  588. /*
  589. * The groups are now in the registry thus no more group files
  590. * and therefore this is now replaced by
  591. * [ CreateGroup ( groupname ) ]
  592. * The groupfile is specified is ignored. This will cause an error
  593. * for compatability reasons.
  594. */
  595. /*
  596. * A new optional parameter is added to specify whether to create
  597. * a Common group or a Personal group.
  598. * 1 for Common Group
  599. * 0 for Personal Group
  600. * Only users with administrative rights can create/delete Common
  601. * groups. The default if this parameter is not specified is:
  602. * Common group if user has admin rights
  603. * Personal group if not
  604. */
  605. /* Make sure that we have 1, 2 or 3 parameters, ignore the 2nd one
  606. * if it represents a groupfile name.
  607. */
  608. cParm = (INT)*lpwCmd++;
  609. if ((cParm < 1) || (cParm > 3))
  610. goto DEHErrExit;
  611. /* Get a pointer to the group name. */
  612. lpT = (LPTSTR) *lpwCmd++;
  613. VerbosePrint (("CreateGroup received: %S", lpT));
  614. if (cParm == 3) {
  615. // skip group file parameter
  616. lpwCmd++;
  617. }
  618. if (cParm > 1) {
  619. //
  620. // Test if the 2nd parameter is a groupfile name or the
  621. // common group flag
  622. //
  623. if (IsParameterANumber((LPTSTR)*lpwCmd)) {
  624. // get the common group flag
  625. if ((nCommonGrp = myatoi((LPTSTR) *lpwCmd++)) &&
  626. !AccessToCommonGroups)
  627. goto DEHErrExit;
  628. }
  629. else {
  630. lpwCmd++;
  631. }
  632. }
  633. /* Search for the group... if it already exists, activate it. */
  634. hwndT = GetWindow(hwndMDIClient, GW_CHILD);
  635. while (hwndT) {
  636. /* Skip icon titles. */
  637. if (!GetWindow(hwndT, GW_OWNER)) {
  638. /* Compare the group title with the request. */
  639. pGroup = (PGROUP)GetWindowLongPtr(hwndT, GWLP_PGROUP);
  640. if (lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup)) {
  641. lpGroupName = (LPTSTR) PTR(lpgd, lpgd->pName);
  642. GlobalUnlock(pGroup->hGroup);
  643. if (!lstrcmpi(lpT, lpGroupName)) {
  644. BOOL bContinueSearch = TRUE;
  645. //
  646. // First case is the app didn't request
  647. // a specific type of group.
  648. //
  649. if (nCommonGrp == -1) {
  650. //
  651. // If the user has access to
  652. // common groups (thus also has
  653. // access to personal groups), or
  654. // the existing group is personal,
  655. // then we are finished.
  656. //
  657. if (AccessToCommonGroups || !pGroup->fCommon) {
  658. bContinueSearch = FALSE;
  659. }
  660. }
  661. //
  662. // Second case the app requested
  663. // a common group match.
  664. //
  665. else if (nCommonGrp == 1) {
  666. //
  667. // If user has access to the common groups
  668. // and the group found is common, then we
  669. // are finished.
  670. //
  671. if (AccessToCommonGroups && pGroup->fCommon) {
  672. bContinueSearch = FALSE;
  673. }
  674. }
  675. //
  676. // Third case is the app requested
  677. // a personal group match.
  678. //
  679. else if (nCommonGrp == 0) {
  680. //
  681. // Check to see if the group is also
  682. // personal.
  683. //
  684. if (!pGroup->fCommon) {
  685. bContinueSearch = FALSE;
  686. }
  687. }
  688. if (bContinueSearch) {
  689. hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  690. continue;
  691. } else {
  692. VerbosePrint (("CreateGroup: Activing group"));
  693. BringWindowToTop(hwndT);
  694. break;
  695. }
  696. }
  697. }
  698. }
  699. hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  700. }
  701. /* If we didn't find it, add it. */
  702. if (!hwndT) {
  703. TCHAR szTemp[MAXITEMPATHLEN+1]; // Group name.
  704. //
  705. // If the app does care what type of group to create,
  706. // the default is to create a common group if the
  707. // user has admin privilages. Otherwise they get a
  708. // personal group.
  709. //
  710. if (nCommonGrp == -1) {
  711. if (AccessToCommonGroups) {
  712. nCommonGrp = 1;
  713. } else {
  714. nCommonGrp = 0;
  715. }
  716. }
  717. lstrcpy(szTemp, lpT);
  718. VerbosePrint (("CreateGroup: Creating new group"));
  719. CreateNewGroup(szTemp, (nCommonGrp == 1));
  720. }
  721. break;
  722. }
  723. case 1:
  724. {
  725. INT cParm;
  726. WORD iIconIndex;
  727. POINT pt;
  728. LPPOINT lppt;
  729. DWORD dwFlags = CI_SET_DOS_FULLSCRN;
  730. BOOL fMinimize;
  731. WORD wHotKey;
  732. TCHAR szExpPath[MAXITEMPATHLEN+1];
  733. TCHAR szExpDir[MAXITEMPATHLEN+1];
  734. HICON hIcon;
  735. TCHAR szT[MAX_PATH];
  736. WORD id;
  737. /* [ AddItem (command,name,icopath,index,pointx,pointy,
  738. defdir,hotkey,fminimize) ] */
  739. //
  740. // pActiveGroup is non NULL when the user
  741. // has an item or group properties dialog up in
  742. // progman i.e. the user is working in progman
  743. // while some other app is doing DDE.
  744. // We can't have both play on the same group at
  745. // the same time.
  746. // johannec 5-13-93 bug 9513
  747. //
  748. if (pCurrentGroup == pActiveGroup) {
  749. PMPrint (("AddItem: DDE converstation started with the group you have open! Exiting."));
  750. goto DEHErrExit;
  751. }
  752. /* There must be at least a command string. */
  753. if ((cParm = (INT)*lpwCmd++) < 1) {
  754. PMPrint (("AddItem: No command string!"));
  755. goto DEHErrExit;
  756. }
  757. /* Make sure we have a reasonable number of parameters. */
  758. if (cParm == 5 || cParm > 10) {
  759. PMPrint (("AddItem: Not enough or too many parameters!"));
  760. goto DEHErrExit;
  761. }
  762. /* If all else fails, there must be a command string! */
  763. lpT = (LPTSTR) *lpwCmd++;
  764. if (!*lpT) {
  765. PMPrint (("AddItem: Null pointer for command string!"));
  766. goto DEHErrExit;
  767. }
  768. VerbosePrint (("AddItem: szPathField = %S", lpT));
  769. lstrcpy(szPathField, lpT);
  770. lstrcpy(szExpPath, szPathField);
  771. DoEnvironmentSubst(szExpPath, CharSizeOf(szExpPath));
  772. VerbosePrint (("AddItem: Expanded path = %S", szExpPath));
  773. StripArgs(szExpPath);
  774. VerbosePrint (("AddItem: Path after StripArgs call = %S", szExpPath));
  775. if (*szExpPath != WCHAR_QUOTE)
  776. CheckEscapes(szExpPath, CharSizeOf(szExpPath));
  777. VerbosePrint (("AddItem: Path after CheckEscapes call = %S", szExpPath));
  778. /* Look for the name field. */
  779. szNameField[0] = TEXT('\0');
  780. if (cParm > 1) {
  781. /* Get the next parameter. */
  782. lpT = (LPTSTR)*lpwCmd++;
  783. if (lstrlen (lpT) > MAXITEMNAMELEN)
  784. lpT[MAXITEMNAMELEN] = TEXT('\0');
  785. lstrcpy(szNameField, lpT);
  786. }
  787. /* If none given, generate one from the command. */
  788. if (szNameField[0] == TEXT('\0')) {
  789. // NB Use the unexpanded path.
  790. BuildDescription(szNameField, szPathField);
  791. }
  792. VerbosePrint (("AddItem: Name field will be: %S", szNameField));
  793. /* Look for the icon's path. */
  794. szIconPath[0] = TEXT('\0');
  795. if (cParm > 2) {
  796. lpT = (LPTSTR)*lpwCmd++;
  797. lstrcpy(szIconPath,lpT);
  798. VerbosePrint(("AddItem: An icon path was given of: %S", szIconPath));
  799. StripArgs(szIconPath);
  800. // I am removing this call to CheckEscapes because
  801. // the filenames could now have quotes around them.
  802. // This call will automaticly add another set of quotes
  803. // thus causing the wrong icon to be displayed.
  804. // ericflo 2/25/94
  805. //CheckEscapes(szIconPath, CharSizeOf(szIconPath));
  806. VerbosePrint (("AddItem: After stripping args the icon path = %S", szIconPath));
  807. }
  808. else
  809. szIconPath[0] = TEXT('\0');
  810. /* Get the icon index. */
  811. if (cParm > 3) {
  812. lpT = (LPTSTR)*lpwCmd++;
  813. iIconIndex = (WORD)myatoi(lpT);
  814. }
  815. else
  816. iIconIndex = 0;
  817. if (iIconIndex >= 666) {
  818. iIconIndex -= 666;
  819. }
  820. else {
  821. dwFlags |= CI_ACTIVATE;
  822. }
  823. //
  824. // If there is no icon path, check if we have an executable associated
  825. // with the command path.
  826. //
  827. if (!*szIconPath) {
  828. FindExecutable(szExpPath, szExpDir, szT);
  829. if (!*szT) {
  830. dwFlags |= CI_NO_ASSOCIATION;
  831. }
  832. }
  833. else {
  834. //
  835. // convert the icon index to the icon id which is what progman
  836. // uses.
  837. //
  838. lstrcpy(szT, szIconPath);
  839. id = iIconIndex;
  840. hIcon = ExtractAssociatedIcon(hAppInstance, szT, &id);
  841. if (lstrcmpi(szT, szIconPath)) {
  842. id = iIconIndex;
  843. }
  844. }
  845. VerbosePrint (("AddItem: Icon index = %d", id));
  846. /* Get the point :) Note x cannot be specified alone. */
  847. if (cParm > 4) {
  848. lpT = (LPTSTR)*lpwCmd++;
  849. if (*lpT) {
  850. pt.x = myatoi(lpT);
  851. }
  852. else {
  853. pt.x = -1;
  854. }
  855. lpT = (LPTSTR)*lpwCmd++;
  856. if (*lpT) {
  857. pt.y = myatoi(lpT);
  858. }
  859. else {
  860. pt.x = -1;
  861. }
  862. lppt = (LPPOINT)&pt;
  863. }
  864. else
  865. lppt = (LPPOINT)NULL;
  866. if (fForcePoint) {
  867. lppt = &ptForce;
  868. fForcePoint = FALSE;
  869. }
  870. /* look to see if there is a default directory
  871. */
  872. if (cParm > 6) {
  873. lpT = (LPTSTR)*lpwCmd++;
  874. VerbosePrint (("AddItem: Given this default direcotry: %S", lpT));
  875. lstrcpy(szDirField, lpT);
  876. lstrcpy(szExpDir, lpT);
  877. DoEnvironmentSubst(szExpDir, CharSizeOf(szExpDir));
  878. StripArgs(szExpDir);
  879. VerbosePrint(("AddItem: After expanding and strip args, we have: %S", szExpDir));
  880. }
  881. else {
  882. szDirField[0] = TEXT('\0');
  883. }
  884. // If the directory is null then use the path bit
  885. // of the command line. (Unexpanded)
  886. if (!*szDirField) {
  887. GetDirectoryFromPath(szPathField, szDirField);
  888. if (*szDirField) {
  889. CheckEscapes (szDirField, MAXITEMPATHLEN+1);
  890. }
  891. }
  892. VerbosePrint (("AddItem: Default directory is: %S", szDirField));
  893. /* hotkey
  894. */
  895. if (cParm > 7) {
  896. lpT = (LPTSTR)*lpwCmd++;
  897. wHotKey = (WORD)myatoi(lpT);
  898. }
  899. else
  900. wHotKey = 0;
  901. /* fminimize
  902. */
  903. if (cParm > 8) {
  904. lpT = (LPTSTR)*lpwCmd++;
  905. fMinimize = myatoi(lpT);
  906. }
  907. else
  908. fMinimize = FALSE;
  909. /* fseparateVDM
  910. */
  911. if (cParm > 9) {
  912. lpT = (LPTSTR)*lpwCmd++;
  913. if (myatoi(lpT)) {
  914. dwFlags |= CI_SEPARATE_VDM;
  915. VerbosePrint (("AddItem: Separate VDM flag specified"));
  916. }
  917. }
  918. VerbosePrint (("AddItem: Results passed to CreateNewItem are:"));
  919. VerbosePrint ((" Name Field = %S", szNameField));
  920. VerbosePrint ((" Path Field = %S", szPathField));
  921. VerbosePrint ((" Icon Path = %S", szIconPath));
  922. VerbosePrint ((" Dir Field = %S", szDirField));
  923. VerbosePrint ((" Hot Key = %d", wHotKey));
  924. VerbosePrint ((" Minimize = %d", fMinimize));
  925. VerbosePrint ((" id = %d", id));
  926. VerbosePrint ((" Icon Index = %d", iIconIndex));
  927. VerbosePrint ((" Flags = %lx", dwFlags));
  928. /* Now add the new item!!! */
  929. if (!CreateNewItem(pCurrentGroup->hwnd,
  930. szNameField, szPathField,
  931. szIconPath, szDirField, wHotKey, fMinimize,
  932. id, iIconIndex, NULL, lppt, dwFlags))
  933. goto DEHErrExit;
  934. // Update scrollbars.
  935. if ((bAutoArrange) && (!bAutoArranging))
  936. ArrangeItems(pCurrentGroup->hwnd);
  937. else if (!bAutoArranging)
  938. CalcGroupScrolls(pCurrentGroup->hwnd);
  939. break;
  940. }
  941. case 2:
  942. {
  943. int cParm;
  944. BOOL fCommonGrp = FALSE;
  945. BOOL fCommonDefaulted = FALSE;
  946. LPTSTR lpGroupName;
  947. HWND hwndPersGrp = NULL;
  948. /* [ DeleteGroup (group_name [, common_group_flag] ) ] */
  949. /*
  950. * A new optional parameter is added to specify whether to delete
  951. * a Common group or a Personal group.
  952. * 1 for Common Group
  953. * 0 for Personal Group
  954. * Only users with administrative rights can create/delete Common
  955. * groups. The default if this parameter is not specified is:
  956. * Common group if user has admin rights
  957. * Personal group if not
  958. */
  959. /* Make sure that we have 1 or 2 parameter. */
  960. cParm = (int)*lpwCmd++;
  961. if ((cParm < 1) || (cParm > 2))
  962. goto DEHErrExit;
  963. /* Get a pointer to the group name. */
  964. lpT = (LPTSTR) *lpwCmd++;
  965. if (cParm == 2) {
  966. //
  967. // Get the common group flag. The User must have Write and
  968. // Delete access to the common groups.
  969. //
  970. if ((fCommonGrp = myatoi((LPTSTR) *lpwCmd++)) &&
  971. !AccessToCommonGroups)
  972. goto DEHErrExit;
  973. }
  974. else if (AccessToCommonGroups) {
  975. //
  976. // The default for a user with Write access rights to the Common
  977. // Groups is deleting a common group.
  978. //
  979. fCommonGrp = TRUE;
  980. fCommonDefaulted = TRUE;
  981. }
  982. /* Search for the group... */
  983. hwndT = GetWindow(hwndMDIClient, GW_CHILD);
  984. while (hwndT) {
  985. /* Skip icon titles. */
  986. if (!GetWindow(hwndT, GW_OWNER)) {
  987. /* Compare the group title with the request. */
  988. pGroup = (PGROUP)GetWindowLongPtr(hwndT, GWLP_PGROUP);
  989. if (lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup)) {
  990. lpGroupName = (LPTSTR) PTR(lpgd, lpgd->pName);
  991. GlobalUnlock(pGroup->hGroup);
  992. if (!lstrcmpi(lpT, lpGroupName)) {
  993. if ((fCommonGrp && !pGroup->fCommon) ||
  994. (!fCommonGrp && pGroup->fCommon) ) {
  995. //
  996. // If the app did not specify common nor personal
  997. // group and we defaulted to common group (because
  998. // the user is an admin), then don't ignore the
  999. // personal group that was found. If no common group
  1000. // is found, we'll default to the personal group.
  1001. // 5-7-93 johannec bug ????
  1002. //
  1003. if (fCommonGrp && fCommonDefaulted) {
  1004. hwndPersGrp = hwndT;
  1005. }
  1006. hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  1007. continue;
  1008. }
  1009. //
  1010. // pActiveGroup is non NULL when the user
  1011. // has an item or group properties dialog up in
  1012. // progman i.e. the user is working in progman
  1013. // while some other app is doing DDE.
  1014. // We can't have both play on the same group at
  1015. // the same time.
  1016. // johannec 5-13-93 bug 9513
  1017. //
  1018. if (pGroup == pActiveGroup) {
  1019. goto DEHErrExit;
  1020. }
  1021. DeleteGroup(hwndT);
  1022. break;
  1023. }
  1024. }
  1025. }
  1026. hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  1027. }
  1028. /* If we didn't find it, report the error. */
  1029. if (!hwndT) {
  1030. if (hwndPersGrp) {
  1031. //
  1032. // If a personal group was found instead of the common group
  1033. // delete it.
  1034. //
  1035. pGroup = (PGROUP)GetWindowLongPtr(hwndPersGrp, GWLP_PGROUP);
  1036. //
  1037. // pActiveGroup is non NULL when the user
  1038. // has an item or group properties dialog up in
  1039. // progman i.e. the user is working in progman
  1040. // while some other app is doing DDE.
  1041. // We can't have both play on the same group at
  1042. // the same time.
  1043. // johannec 5-13-93 bug 9513
  1044. //
  1045. if (pGroup == pActiveGroup) {
  1046. goto DEHErrExit;
  1047. }
  1048. DeleteGroup(hwndPersGrp);
  1049. } else {
  1050. goto DEHErrExit;
  1051. }
  1052. }
  1053. break;
  1054. }
  1055. case 3:
  1056. /* [ ExitProgman (bSaveGroups) ] */
  1057. if (bExitWindows)
  1058. goto DEHErrExit;
  1059. /* Make sure that we have 1 parameter. */
  1060. if (*lpwCmd++ != 1)
  1061. goto DEHErrExit;
  1062. /* Get a pointer to the parm. */
  1063. lpT = (LPTSTR) *lpwCmd++;
  1064. bSaveSettings = FALSE;
  1065. if (*lpT == TEXT('1'))
  1066. WriteINIFile();
  1067. //
  1068. // The 2 is a magic return value inside of the
  1069. // DDEMsgProc routine.
  1070. //
  1071. dwRet = 2;
  1072. goto DEHErrExit;
  1073. break;
  1074. case 4:
  1075. {
  1076. INT cParm;
  1077. int iShowCmd;
  1078. BOOL fCommonGrp = FALSE;
  1079. BOOL fCommonDefaulted = FALSE;
  1080. HWND hwndPersGrp = NULL;
  1081. TCHAR szT[MAXKEYLEN + 1];
  1082. TCHAR szCommonGroupSuffix[MAXKEYLEN + 1];
  1083. WINDOWPLACEMENT wp;
  1084. /* [ ShowGroup (group_name, wShowParm [, fCommonGroup] ) ] */
  1085. /*
  1086. * A new optional parameter is added to specify whether to show
  1087. * a Common group or a Personal group.
  1088. * 1 for Common Group
  1089. * 0 for Personal Group
  1090. * Only users with administrative rights can create/delete Common
  1091. * groups. The default if this parameter is not specified is:
  1092. * Common group if user has admin rights
  1093. * Personal group if not
  1094. */
  1095. /* Make sure that we have 2 or 3 parameters. */
  1096. cParm = (INT)*lpwCmd++;
  1097. if ((cParm < 2) || (cParm > 3))
  1098. goto DEHErrExit;
  1099. /* Get a pointer to the group name. */
  1100. lpT = (LPTSTR) *lpwCmd++;
  1101. VerbosePrint (("ShowGroup: Called with %S", lpT));
  1102. iShowCmd = myatoi((LPTSTR) *lpwCmd++);
  1103. if (cParm == 3) {
  1104. //
  1105. // get the common group flag
  1106. //
  1107. fCommonGrp = myatoi((LPTSTR) *lpwCmd++);
  1108. }
  1109. else if (AccessToCommonGroups) {
  1110. //
  1111. // The default for a user with administrative rights is Common
  1112. // Groups.
  1113. //
  1114. fCommonGrp = TRUE;
  1115. fCommonDefaulted = TRUE;
  1116. }
  1117. /* Search for the group... */
  1118. hwndT = GetWindow(hwndMDIClient, GW_CHILD);
  1119. while (hwndT) {
  1120. //
  1121. // Skip icon titles.
  1122. //
  1123. if (GetWindow(hwndT, GW_OWNER)) {
  1124. hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  1125. continue;
  1126. }
  1127. /* Compare the group title with the request. */
  1128. pGroup = (PGROUP)GetWindowLongPtr(hwndT, GWLP_PGROUP);
  1129. if (lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup)) {
  1130. lstrcpy(szT, (LPTSTR) PTR(lpgd, lpgd->pName));
  1131. GlobalUnlock(pGroup->hGroup);
  1132. if (!lstrcmpi(lpT, szT)) {
  1133. if ((fCommonGrp && !pGroup->fCommon) ||
  1134. (!fCommonGrp && pGroup->fCommon) ) {
  1135. //
  1136. // If the app did not specify common nor personal
  1137. // group and we defaulted to common group (because
  1138. // the user is an admin), then don't ignore the
  1139. // personal group that was found. If no common group
  1140. // is found, we'll default to the personal group.
  1141. // 5-7-93 johannec bug ????
  1142. //
  1143. if (fCommonGrp && fCommonDefaulted) {
  1144. hwndPersGrp = hwndT;
  1145. }
  1146. hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  1147. continue;
  1148. }
  1149. ShowWindow(hwndT, iShowCmd);
  1150. //
  1151. // if the group is common and not being minimized
  1152. // then must add the common suffix to the group
  1153. // window title. If the group is being minimized
  1154. // then make sure the common suffix is not there.
  1155. //
  1156. if (fCommonGrp) {
  1157. wp.length = sizeof(WINDOWPLACEMENT);
  1158. GetWindowPlacement(hwndT, &wp);
  1159. if (wp.showCmd != SW_SHOWMINIMIZED &&
  1160. wp.showCmd != SW_MINIMIZE &&
  1161. wp.showCmd != SW_SHOWMINNOACTIVE ) {
  1162. LoadString(hAppInstance, IDS_COMMONGRPSUFFIX,
  1163. szCommonGroupSuffix,
  1164. CharSizeOf(szCommonGroupSuffix));
  1165. lstrcat(szT, szCommonGroupSuffix);
  1166. }
  1167. SetWindowText(hwndT, szT);
  1168. }
  1169. SendMessage(hwndT, WM_ACTIVATE, 1, 0);
  1170. break;
  1171. }
  1172. }
  1173. hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  1174. }
  1175. /* If we didn't find it, report the error. */
  1176. if (!hwndT) {
  1177. if (hwndPersGrp) {
  1178. //
  1179. // If a personal group was found instead of the common group
  1180. // show it.
  1181. //
  1182. ShowWindow(hwndPersGrp, iShowCmd);
  1183. SendMessage(hwndPersGrp, WM_ACTIVATE, 1, 0);
  1184. }
  1185. else {
  1186. goto DEHErrExit;
  1187. }
  1188. }
  1189. break;
  1190. }
  1191. case 6:
  1192. /* [ ReplaceItem (item_name) ] */
  1193. fForcePoint = TRUE;
  1194. ptForce.x = -1; // in case we don't really find the item
  1195. ptForce.y = -1;
  1196. /* fall thru */
  1197. case 5:
  1198. {
  1199. PITEM pItem;
  1200. LPITEMDEF lpid;
  1201. /* [ DeleteItem (item_name) ] */
  1202. //
  1203. // pActiveGroup is non NULL when the user
  1204. // has an item or group properties dialog up in
  1205. // progman i.e. the user is working in progman
  1206. // while some other app is doing DDE.
  1207. // We can't have both play on the same group at
  1208. // the same time.
  1209. // johannec 5-13-93 bug 9513
  1210. //
  1211. if (pCurrentGroup == pActiveGroup) {
  1212. goto DEHErrExit;
  1213. }
  1214. /* exactly one parameter
  1215. */
  1216. if (*lpwCmd++ != 1)
  1217. goto DEHErrExit;
  1218. lpT = (LPTSTR) *lpwCmd++;
  1219. lpgd = LockGroup(pCurrentGroup->hwnd);
  1220. if (!lpgd)
  1221. goto DEHErrExit;
  1222. for (pItem = pCurrentGroup->pItems; pItem; pItem = pItem->pNext) {
  1223. lpid = ITEM(lpgd,pItem->iItem);
  1224. if (!lstrcmpi((LPTSTR) PTR(lpgd, lpid->pName),lpT)) {
  1225. ptForce.x = pItem->rcIcon.left;
  1226. ptForce.y = pItem->rcIcon.top;
  1227. UnlockGroup(pCurrentGroup->hwnd);
  1228. DeleteItem(pCurrentGroup,pItem);
  1229. break;
  1230. }
  1231. }
  1232. if (!pItem) {
  1233. UnlockGroup(pCurrentGroup->hwnd);
  1234. goto DEHErrExit;
  1235. }
  1236. break;
  1237. }
  1238. case 7:
  1239. {
  1240. int cParm;
  1241. BOOL fAll;
  1242. BOOL fCommonGrp = FALSE;
  1243. /* [ Reload [(groupname [, common_group_flag] )] ] */
  1244. /*
  1245. * A new optional parameter is added to specify whether to reload
  1246. * a Common group or a Personal group.
  1247. * 1 for Common Group
  1248. * 0 for Personal Group
  1249. * Only users with administrative rights can create/delete Common
  1250. * groups. The default if this parameter is not specified is:
  1251. * Common group if user has admin rights
  1252. * Personal group if not
  1253. */
  1254. cParm = (int)*lpwCmd++;
  1255. if (!cParm)
  1256. fAll = TRUE;
  1257. else if ((cParm == 1) || (cParm == 2))
  1258. fAll = FALSE;
  1259. else
  1260. goto DEHErrExit;
  1261. if (fAll) {
  1262. HWND hwndT;
  1263. ShowWindow(hwndMDIClient, SW_HIDE);
  1264. ValidateRect(hwndProgman,NULL);
  1265. /* unload all the groups!
  1266. */
  1267. for (hwndT = GetWindow(hwndMDIClient, GW_CHILD);
  1268. hwndT;
  1269. hwndT = GetWindow(hwndMDIClient, GW_CHILD)) {
  1270. /* Skip icon titles. */
  1271. while (GetWindow(hwndT, GW_OWNER)) {
  1272. hwndT = GetWindow(hwndT,GW_HWNDNEXT);
  1273. if (!hwndT)
  1274. break;
  1275. }
  1276. if (hwndT)
  1277. UnloadGroupWindow(hwndT);
  1278. }
  1279. LoadAllGroups();
  1280. ShowWindow(hwndMDIClient,SW_SHOW);
  1281. }
  1282. else {
  1283. TCHAR szT[120];
  1284. WORD idGroup;
  1285. HWND hwndT;
  1286. /* get the name to reload
  1287. */
  1288. lpT = (LPTSTR) *lpwCmd++;
  1289. if (cParm == 2) {
  1290. //
  1291. // Get the common group flag. The User must have Write
  1292. // access to the reload common groups.
  1293. //
  1294. if ((fCommonGrp = myatoi((LPTSTR) *lpwCmd++)) &&
  1295. !AccessToCommonGroups)
  1296. goto DEHErrExit;
  1297. }
  1298. else if (AccessToCommonGroups) {
  1299. //
  1300. // The default for a user with administrative rights is Common
  1301. // Groups.
  1302. //
  1303. fCommonGrp = TRUE;
  1304. }
  1305. /* search for it
  1306. */
  1307. for (hwndT = GetWindow(hwndMDIClient, GW_CHILD);
  1308. hwndT;
  1309. hwndT = GetWindow(hwndT, GW_HWNDNEXT)) {
  1310. /* Skip icon titles. */
  1311. if (GetWindow(hwndT, GW_OWNER))
  1312. continue;
  1313. /* Compare the group title with the request. */
  1314. pGroup = (PGROUP)GetWindowLongPtr(hwndT, GWLP_PGROUP);
  1315. if (lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup)) {
  1316. lstrcpy(szT, (LPTSTR) PTR(lpgd, lpgd->pName));
  1317. GlobalUnlock(pGroup->hGroup);
  1318. if (lstrcmpi(lpT, szT))
  1319. continue;
  1320. if ((fCommonGrp && !pGroup->fCommon) ||
  1321. (!fCommonGrp && pGroup->fCommon) )
  1322. continue;
  1323. /* we found the group. Unload and reload it.
  1324. */
  1325. lstrcpy(szT,pGroup->lpKey);
  1326. idGroup = pGroup->wIndex;
  1327. UnloadGroupWindow(hwndT);
  1328. LoadGroupWindow(szT, idGroup, fCommonGrp);
  1329. break;
  1330. }
  1331. }
  1332. if (!hwndT)
  1333. goto DEHErrExit;
  1334. }
  1335. break;
  1336. }
  1337. default:
  1338. goto DEHErrExit;
  1339. }
  1340. }
  1341. /* 't all woiked! */
  1342. dwRet = 1;
  1343. DEHErrExit:
  1344. GlobalUnlock(hCmd);
  1345. GlobalFree(hCmd);
  1346. DEHErrExit1:
  1347. GlobalUnlock(hString);
  1348. bInDDE = FALSE;
  1349. return dwRet;
  1350. }
  1351. /*--------------------------------------------------------------------------*/
  1352. /* */
  1353. /* InitRespond() - */
  1354. /* */
  1355. /*--------------------------------------------------------------------------*/
  1356. BOOL APIENTRY InitRespond( HANDLE hWnd, WPARAM wParam, LPARAM lParam,
  1357. LPTSTR szApp, LPTSTR szTopic,
  1358. BOOL fBCReply // Whether or not to reply to a broadcast message.
  1359. // ie a null app string.
  1360. )
  1361. {
  1362. HWND hwndDDE = NULL;
  1363. ATOM atom1, atom2;
  1364. DWORD dwType;
  1365. atom1 = GlobalAddAtom(szApp);
  1366. atom2 = GlobalAddAtom(szTopic);
  1367. if ((!LOWORD(lParam) && fBCReply) || LOWORD(lParam) == atom1) {
  1368. if (!HIWORD(lParam) || HIWORD(lParam) == atom2) {
  1369. if (!lstrcmp(szApp, szProgman)) { // use Progman's main hwnd
  1370. dwType = DDE_PROGMAN;
  1371. if (IsDdeConversation(hWnd, (HWND)wParam, DDE_PROGMAN)) {
  1372. MPostWM_DDE_TERMINATE((HWND)wParam, hWnd);
  1373. hwndDDE = CreateWindow(szProgmanDDE, NULL, WS_CHILD, 0, 0, 0, 0,
  1374. hwndProgman, NULL, hAppInstance, NULL);
  1375. }
  1376. else {
  1377. // use Progman's hwnd for the first DDE conversation
  1378. hwndDDE = hWnd;
  1379. }
  1380. } else if (!lstrcmp(szApp, szShell)) {
  1381. if (!lstrcmp(szTopic, szAppIcon)) {
  1382. if (IsDdeConversation(hWnd, (HWND)wParam, APP_ICON)) {
  1383. return(TRUE);
  1384. }
  1385. dwType = APP_ICON;
  1386. hwndDDE = CreateWindow(szAppIconDDE, NULL, WS_CHILD, 0, 0, 0, 0,
  1387. hwndProgman, NULL, hAppInstance, NULL);
  1388. }
  1389. else if (!lstrcmp(szTopic, szAppDesc)) {
  1390. if (IsDdeConversation(hWnd, (HWND)wParam, APP_DESC)) {
  1391. return(TRUE);
  1392. }
  1393. dwType = APP_DESC;
  1394. hwndDDE = CreateWindow(szAppDescDDE, NULL, WS_CHILD, 0, 0, 0, 0,
  1395. hwndProgman, NULL, hAppInstance, NULL);
  1396. }
  1397. else if (!lstrcmp(szTopic, szAppWDir)) {
  1398. if (IsDdeConversation(hWnd, (HWND)wParam, APP_WDIR)) {
  1399. return(TRUE);
  1400. }
  1401. dwType = APP_WDIR;
  1402. hwndDDE = CreateWindow(szAppWDirDDE, NULL, WS_CHILD, 0, 0, 0, 0,
  1403. hwndProgman, NULL, hAppInstance, NULL);
  1404. }
  1405. }
  1406. //
  1407. // For compatibility reasons, allow Shell - AppProperties DDE
  1408. // connection.
  1409. //
  1410. if (!lstrcmp(szApp, szShell) &&
  1411. !lstrcmp(szTopic, szAppProperties) ) { // use Progman's main hwnd
  1412. dwType = DDE_PROGMAN;
  1413. if (IsDdeConversation(hWnd, (HWND)wParam, DDE_PROGMAN)) {
  1414. MPostWM_DDE_TERMINATE((HWND)wParam, hWnd);
  1415. hwndDDE = CreateWindow(szProgmanDDE, NULL, WS_CHILD, 0, 0, 0, 0,
  1416. hwndProgman, NULL, hAppInstance, NULL);
  1417. }
  1418. else {
  1419. // use Progman's hwnd for the first DDE conversation
  1420. hwndDDE = hWnd;
  1421. }
  1422. }
  1423. if (hwndDDE) {
  1424. SendMessage((HWND)wParam, WM_DDE_ACK, (WPARAM)hwndDDE,
  1425. MAKELONG(atom1, atom2));
  1426. AddDdeConversation(hwndDDE, (HWND)wParam, dwType);
  1427. return(TRUE);
  1428. }
  1429. }
  1430. }
  1431. /*
  1432. * No message sent or
  1433. * Destination won't accept the ACK and so didn't delete
  1434. * the atoms we provided - so we must do it.
  1435. */
  1436. // GlobalDeleteAtom(atom1);
  1437. // GlobalDeleteAtom(atom2);
  1438. return(FALSE);
  1439. }
  1440. /*--------------------------------------------------------------------------*/
  1441. /* */
  1442. /* GroupRequest() - */
  1443. /* */
  1444. /*--------------------------------------------------------------------------*/
  1445. VOID APIENTRY GroupRequest(HWND hWnd, HWND hwndClient, ATOM fmt, ATOM aItem)
  1446. {
  1447. DWORD cb;
  1448. LPTSTR lpT;
  1449. register HANDLE hT;
  1450. register PGROUP pGroup;
  1451. HANDLE hReAlloc;
  1452. LPGROUPDEF lpgd;
  1453. if (fmt != CF_TEXT && fmt != CF_UNICODETEXT) {
  1454. DDEFail(hWnd, hwndClient, aItem);
  1455. return;
  1456. }
  1457. /*sizeof (WORD) ok, as hT becomes lpT which is LPSTR*/
  1458. cb = 2 * sizeof(WORD) + 2;
  1459. hT = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cb);
  1460. if (!hT) {
  1461. DDEFail(hWnd,hwndClient,aItem);
  1462. return;
  1463. }
  1464. /* Ask the client to release the data and inform him that this
  1465. * is in response to a request message. Clipboard format is
  1466. * plain text.
  1467. */
  1468. lpT = (LPTSTR)GlobalLock(hT);
  1469. ((WORD FAR *)lpT)[0] = 3 << 12;
  1470. ((WORD FAR *)lpT)[1] = CF_TEXT;
  1471. ((WORD FAR *)lpT)[2] = 0;
  1472. GlobalUnlock(hT);
  1473. /* Go through the list of groups appending the name of each
  1474. * group as a line in the shared memory item.
  1475. */
  1476. for (pGroup=pFirstGroup; pGroup; pGroup = pGroup->pNext) {
  1477. lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup);
  1478. cb += sizeof(TCHAR) * (2 + lstrlen( (LPTSTR)PTR(lpgd, lpgd->pName) ));
  1479. if (!(hReAlloc = GlobalReAlloc(hT, cb, GMEM_MOVEABLE))) {
  1480. GlobalFree(hT);
  1481. DDEFail(hWnd,hwndClient,aItem);
  1482. return;
  1483. }
  1484. hT = hReAlloc;
  1485. /*sizeof (WORD) ok, as hT becomes lpT which is LPSTR*/
  1486. lpT = (LPTSTR)((LPSTR)GlobalLock(hT) + 2 * sizeof(WORD));
  1487. lpT += lstrlen(lpT);
  1488. /* we've already allocated it to be large enough...
  1489. */
  1490. //
  1491. // The title may contain ' (Common)' at the end if the group is a
  1492. // common group. So get the group title from the group itself not
  1493. // from the window title.
  1494. //
  1495. lstrcpy(lpT, (LPTSTR)PTR(lpgd, lpgd->pName));
  1496. lstrcat(lpT, TEXT("\r\n"));
  1497. GlobalUnlock(pGroup->hGroup);
  1498. GlobalUnlock(hT);
  1499. }
  1500. if (fmt == CF_TEXT) {
  1501. LPSTR lpMultiByteStr = NULL;
  1502. int cchMultiByte = 0;
  1503. HANDLE hMultiByte;
  1504. // convert the string to Ansi
  1505. lpT = GlobalLock(hT) ;
  1506. cchMultiByte = WideCharToMultiByte(CP_ACP, 0,
  1507. (LPTSTR)((LPBYTE)lpT+ 2*sizeof(WORD)), -1,
  1508. lpMultiByteStr, cchMultiByte, NULL, NULL);
  1509. hMultiByte = GlobalAlloc(GMEM_MOVEABLE,(++cchMultiByte) + 2 * sizeof(WORD));
  1510. lpMultiByteStr = GlobalLock(hMultiByte);
  1511. ((WORD FAR *)lpMultiByteStr)[0] = 3 << 12;
  1512. ((WORD FAR *)lpMultiByteStr)[1] = CF_TEXT;
  1513. WideCharToMultiByte(CP_ACP, 0,
  1514. (LPTSTR)((LPBYTE)lpT+ 2*sizeof(WORD)), -1,
  1515. (LPSTR)(lpMultiByteStr + 2 * sizeof(WORD)),
  1516. cchMultiByte, NULL, NULL);
  1517. GlobalUnlock(hMultiByte);
  1518. GlobalUnlock(hT);
  1519. GlobalFree(hT);
  1520. hT = hMultiByte;
  1521. }
  1522. MPostWM_DDE_DATA(hwndClient, hWnd, hT, aItem);
  1523. }
  1524. /*--------------------------------------------------------------------------*/
  1525. /* */
  1526. /* FindIconProp() - */
  1527. /* */
  1528. /*--------------------------------------------------------------------------*/
  1529. extern ULONG Color16Palette[];
  1530. extern ULONG Color256Palette[];
  1531. VOID APIENTRY FindIconProp(HWND hWnd, WPARAM wParam, LPARAM lParam, WORD iProp)
  1532. {
  1533. PGROUP pGroup;
  1534. PITEM pItem;
  1535. LPGROUPDEF lpgd;
  1536. LPITEMDEF lpid;
  1537. UINT uiMsg = WM_DDE_ACK;
  1538. HANDLE hData;
  1539. DDEDATA FAR * lpdd;
  1540. WORD cb;
  1541. NEWICONDATA FAR * lpIconData;
  1542. LPBYTE lpS;
  1543. LPBYTE lpD;
  1544. HWND hwndT;
  1545. TCHAR szCommand[MAXITEMPATHLEN+1];
  1546. TCHAR szDefDir[2 * (MAXITEMPATHLEN+1)];
  1547. ATOM aItem; // the app.'s id for which the info. is requested.
  1548. TCHAR szId[16]; //to extract the id from the atom.
  1549. DWORD dwId;
  1550. PBITMAPINFOHEADER pbih, pbihNew;
  1551. DWORD colors;
  1552. LPVOID palette;
  1553. if (fInExec) {
  1554. /* we are inside the exec call! it must have come from the
  1555. * current icon!
  1556. */
  1557. pGroup = pCurrentGroup;
  1558. pItem = pGroup->pItems;
  1559. goto GotIt;
  1560. }
  1561. /* use the mdi window list to get the z-order */
  1562. aItem = HIWORD(lParam);
  1563. if (!GlobalGetAtomName(aItem, (LPTSTR)szId, 16))
  1564. goto Fail;
  1565. dwId = MyAtoi((LPTSTR)szId);
  1566. if (!dwId) {
  1567. goto Fail;
  1568. }
  1569. for (hwndT=GetWindow(hwndMDIClient, GW_CHILD); hwndT; hwndT=GetWindow(hwndT, GW_HWNDNEXT)) {
  1570. if (GetWindow(hwndT, GW_OWNER))
  1571. continue;
  1572. pGroup = (PGROUP)GetWindowLongPtr(hwndT, GWLP_PGROUP);
  1573. for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
  1574. if (pItem->dwDDEId == dwId) {
  1575. goto GotIt;
  1576. }
  1577. }
  1578. }
  1579. Fail:
  1580. /* didn't find it; fail
  1581. */
  1582. MPostDDEMsg((HWND)wParam, uiMsg, hWnd, (UINT)0, (UINT)aItem);
  1583. return;
  1584. GotIt:
  1585. /* from now on, we say use default instead of not me
  1586. */
  1587. uiMsg = WM_DDE_DATA;
  1588. lpgd = LockGroup(pGroup->hwnd);
  1589. if (!lpgd)
  1590. goto Fail;
  1591. lpid = ITEM(lpgd,pItem->iItem);
  1592. switch (iProp) {
  1593. case APP_ICON:
  1594. cb = (WORD)(sizeof(NEWICONDATA) + lpid->cbIconRes);
  1595. pbih = (PBITMAPINFOHEADER)PTR(lpgd, lpid->pIconRes);
  1596. if (pbih->biClrUsed == -1) {
  1597. colors = (1 << (pbih ->biPlanes * pbih->biBitCount));
  1598. if (colors == 16 || colors == 256) {
  1599. cb += (WORD)(colors * sizeof(RGBQUAD));
  1600. }
  1601. }
  1602. break;
  1603. case APP_DESC:
  1604. cb = (WORD)(sizeof(DDEDATA) + sizeof(TCHAR)*lstrlen((LPTSTR) PTR(lpgd, lpid->pName)));
  1605. break;
  1606. case APP_WDIR:
  1607. GetItemCommand(pGroup, pItem, szCommand, szDefDir);
  1608. cb = (WORD)(sizeof(DDEDATA) + sizeof(TCHAR)*lstrlen(szDefDir));
  1609. break;
  1610. default:
  1611. goto Fail;
  1612. }
  1613. hData = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT,
  1614. (DWORD)cb);
  1615. if (!hData) {
  1616. UnlockGroup(pGroup->hwnd);
  1617. goto Fail;
  1618. }
  1619. lpdd = (DDEDATA FAR *)GlobalLock(hData);
  1620. if (!lpdd) {
  1621. GlobalFree(hData);
  1622. UnlockGroup(pGroup->hwnd);
  1623. goto Fail;
  1624. }
  1625. lpdd->fResponse = TRUE;
  1626. lpdd->fRelease = TRUE;
  1627. lpdd->cfFormat = CF_TEXT;
  1628. switch (iProp) {
  1629. case APP_ICON:
  1630. if ((short)lpid->cbIconRes <= 0) {
  1631. // This icon is toast.
  1632. GlobalUnlock(hData);
  1633. UnlockGroup(pGroup->hwnd);
  1634. goto Fail;
  1635. }
  1636. lpIconData = (NEWICONDATA FAR *)lpdd;
  1637. lpIconData->dwResSize = (DWORD)lpid->cbIconRes;
  1638. //lpIconData->dwVer = lpid->dwIconVer;
  1639. lpIconData->dwVer = (lpid->wIconVer == 2) ? 0x00020000 : 0x00030000;
  1640. lpD = (LPBYTE)&(lpIconData->iResource);
  1641. lpS = (LPBYTE)PTR(lpgd, lpid->pIconRes);
  1642. cb = lpid->cbIconRes;
  1643. if ((pbih->biClrUsed == -1) && (colors == 16 || colors == 32)) {
  1644. if (colors == 16) {
  1645. palette = Color16Palette;
  1646. } else if (colors == 256) {
  1647. palette = Color256Palette;
  1648. }
  1649. pbihNew = (PBITMAPINFOHEADER)lpD;
  1650. RtlCopyMemory(pbihNew, pbih, sizeof( *pbih ));
  1651. pbihNew->biClrUsed = 0;
  1652. RtlCopyMemory((pbihNew+1), palette, colors * sizeof(RGBQUAD));
  1653. RtlCopyMemory((PCHAR)(pbihNew+1) + (colors * sizeof(RGBQUAD)),
  1654. (pbih+1),
  1655. lpid->cbIconRes - sizeof(*pbih)
  1656. );
  1657. } else {
  1658. while (cb--) {
  1659. *lpD++ = *lpS++;
  1660. }
  1661. }
  1662. break;
  1663. case APP_DESC:
  1664. lstrcpy((LPTSTR)lpdd->Value,(LPTSTR) PTR(lpgd, lpid->pName));
  1665. break;
  1666. case APP_WDIR:
  1667. lstrcpy((LPTSTR)lpdd->Value,szDefDir);
  1668. break;
  1669. }
  1670. GlobalUnlock(hData);
  1671. UnlockGroup(pGroup->hwnd);
  1672. if (!MPostWM_DDE_DATA((HWND)wParam, hWnd, hData, (ATOM)aItem)){
  1673. GlobalFree(hData);
  1674. }
  1675. }
  1676. /*--------------------------------------------------------------------------*/
  1677. /* */
  1678. /* FindIconPath() - */
  1679. /* In NT groups the icon path is not stored when it is not specified by */
  1680. /* the user when the item is created. For DDE requests on groups, the */
  1681. /* icon path needs to be returned. This function will determine the */
  1682. /* icon path the way it first find the icon. */
  1683. /* 9/17/93 JOhannec
  1684. /* */
  1685. /*--------------------------------------------------------------------------*/
  1686. VOID FindIconPath(
  1687. LPTSTR szPathField,
  1688. LPTSTR szDirField,
  1689. LPTSTR szIconPath
  1690. )
  1691. {
  1692. TCHAR szIconExe[MAX_PATH];
  1693. TCHAR szTemp[MAX_PATH];
  1694. HICON hIcon;
  1695. WORD wIconIndex;
  1696. WORD wIconId;
  1697. lstrcpy(szIconExe, szPathField);
  1698. DoEnvironmentSubst(szIconExe, CharSizeOf(szIconExe));
  1699. StripArgs(szIconExe);
  1700. TagExtension(szIconExe, sizeof(szIconExe));
  1701. if (*szIconExe == TEXT('"') && *(szIconExe + lstrlen(szIconExe)-1) == TEXT('"')) {
  1702. SheRemoveQuotes(szIconExe);
  1703. }
  1704. //
  1705. // if it's a relative path, extractassociatedicon and LoadLibrary don't
  1706. // handle that so find the executable first
  1707. //
  1708. SetCurrentDirectory(szOriginalDirectory);
  1709. FindExecutable(szIconExe, szDirField, szTemp);
  1710. if (*szTemp) {
  1711. lstrcpy(szIconExe, szTemp);
  1712. TagExtension(szIconExe, sizeof(szIconExe));
  1713. if (*szIconExe == TEXT('"') && *(szIconExe + lstrlen(szIconExe)-1) == TEXT('"')) {
  1714. SheRemoveQuotes(szIconExe);
  1715. }
  1716. }
  1717. else {
  1718. *szIconExe = 0; // Use a dummy value so no icons will be found
  1719. // and progman's item icon will be used instead
  1720. // This is to make moricons.dll item icon be the
  1721. // right one. -johannec 6/4/93
  1722. }
  1723. //
  1724. // reset the current directory to progman's working directory i.e. Windows directory
  1725. //
  1726. SetCurrentDirectory(szWindowsDirectory);
  1727. wIconIndex = 0;
  1728. hIcon = ExtractAssociatedIconEx(hAppInstance, szIconExe, &wIconIndex, &wIconId);
  1729. if (hIcon)
  1730. DestroyIcon(hIcon);
  1731. lstrcpy(szIconPath, szIconExe);
  1732. }
  1733. /*--------------------------------------------------------------------------*/
  1734. /* */
  1735. /* AddStringToSeg() - */
  1736. /* */
  1737. /*--------------------------------------------------------------------------*/
  1738. BOOL APIENTRY AddStringToSeg(LPHANDLE lphT, LPINT lpcb, LPTSTR lpsz, WORD wT, BOOL fCR)
  1739. {
  1740. TCHAR szT[10];
  1741. INT cb;
  1742. LPTSTR lp;
  1743. HANDLE hReAlloc;
  1744. if (!lpsz) {
  1745. wsprintf(szT,TEXT("%d"),wT);
  1746. lpsz = szT;
  1747. wT = (WORD)0;
  1748. }
  1749. cb = sizeof(TCHAR) * (lstrlen(lpsz) + (wT ? 2 : 0) + (fCR ? 2 : 1));
  1750. if (!(hReAlloc = GlobalReAlloc(*lphT,*lpcb+cb,GMEM_MOVEABLE|GMEM_ZEROINIT))) {
  1751. GlobalFree(*lphT);
  1752. return FALSE;
  1753. }
  1754. else {
  1755. *lphT = hReAlloc;
  1756. }
  1757. lp = (LPTSTR)((LPSTR)GlobalLock(*lphT) + *lpcb - 2); // this is to go before the null byte
  1758. if (wT)
  1759. *lp++ = TEXT('"');
  1760. lstrcpy(lp,lpsz);
  1761. lp += lstrlen(lp);
  1762. if (wT)
  1763. *lp++ = TEXT('"');
  1764. if (fCR) {
  1765. *lp++ = TEXT('\r');
  1766. *lp++ = TEXT('\n');
  1767. }
  1768. else
  1769. *lp++ = TEXT(',');
  1770. *lp = 0;
  1771. GlobalUnlock(*lphT);
  1772. *lpcb += cb;
  1773. return TRUE;
  1774. }
  1775. /*--------------------------------------------------------------------------*/
  1776. /* */
  1777. /* DumpGroup() - */
  1778. /* */
  1779. /*--------------------------------------------------------------------------*/
  1780. VOID APIENTRY DumpGroup(HWND hwnd, ATOM aName, HWND hwndConv, WORD cfFormat)
  1781. {
  1782. HWND hwndGroup;
  1783. PGROUP pGroup;
  1784. PITEM pItem;
  1785. LPGROUPDEF lpgd;
  1786. LPITEMDEF lpid;
  1787. WORD i;
  1788. INT cb;
  1789. HANDLE hT;
  1790. LPTSTR lpT;
  1791. INT state;
  1792. BOOL fActivated;
  1793. if (cfFormat != CF_TEXT && cfFormat != CF_UNICODETEXT)
  1794. goto Fail;
  1795. for (hwndGroup = GetWindow(hwndMDIClient,GW_CHILD);
  1796. hwndGroup;
  1797. hwndGroup = GetWindow(hwndGroup,GW_HWNDNEXT)) {
  1798. if (GetWindow(hwndGroup,GW_OWNER))
  1799. continue;
  1800. lpgd = LockGroup(hwndGroup);
  1801. if (!lpgd)
  1802. goto Fail;
  1803. if (aName == GlobalFindAtom((LPTSTR) PTR(lpgd, lpgd->pName)))
  1804. goto FoundGroup;
  1805. UnlockGroup(hwndGroup);
  1806. }
  1807. Fail:
  1808. #ifdef ORGCODE
  1809. DDEFail(hwnd,hwndConv,MAKELONG(cfFormat,aName));
  1810. #else
  1811. DDEFail(hwnd, hwndConv, aName);
  1812. #endif
  1813. return;
  1814. FoundGroup:
  1815. pGroup = (PGROUP)GetWindowLongPtr(hwndGroup,GWLP_PGROUP);
  1816. /*sizeof (WORD) ok, as hT becomes lpT which is LPSTR*/
  1817. cb = 2 * sizeof(WORD) + 2;
  1818. hT = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cb);
  1819. if (!hT)
  1820. goto Fail;
  1821. /* Ask the client to release the data and inform him that this
  1822. * is in response to a request message. Clipboard format is
  1823. * plain text.
  1824. */
  1825. lpT = (LPTSTR)GlobalLock(hT);
  1826. ((WORD FAR *)lpT)[0] = 3 << 12;
  1827. ((WORD FAR *)lpT)[1] = CF_TEXT;
  1828. ((WORD FAR *)lpT)[2] = 0;
  1829. GlobalUnlock(hT);
  1830. /* the first line is group properties
  1831. */
  1832. if (!AddStringToSeg(&hT,&cb,(LPTSTR) PTR(lpgd, lpgd->pName),TRUE,FALSE))
  1833. goto Fail;
  1834. #if 1
  1835. // don't allow apps to know the group key.
  1836. //
  1837. // change 2-21-93 johannec
  1838. // for compatibilty reasons we must privide the group filename which
  1839. // doesn't mean anything in NT so we provide the key name instad.
  1840. if (!AddStringToSeg(&hT,&cb,pGroup->lpKey, FALSE, FALSE))
  1841. goto Fail;
  1842. #endif
  1843. /* put the number of items in
  1844. */
  1845. for (i = 0, pItem = pGroup->pItems; pItem; pItem = pItem->pNext)
  1846. i++;
  1847. #if 1
  1848. if (!AddStringToSeg(&hT,&cb,NULL,i,FALSE))
  1849. goto Fail;
  1850. // Return the window state as a SW_ value.
  1851. // REVIEW not all SW_ values are supported.
  1852. // It would be nice if there was some way to query a SW_ value
  1853. // but I guess it would too much to ask for windows to be even remotely
  1854. // orthogonal. I don't know who "designed" the Windows API but it
  1855. // really is the worst windowing system I have ever used.
  1856. // Luckily orthogonality doesn't affect stock prices :-)
  1857. state = SW_SHOWNORMAL;
  1858. if (pGroup == pCurrentGroup) {
  1859. fActivated = TRUE;
  1860. }
  1861. else {
  1862. fActivated = FALSE;
  1863. }
  1864. if (IsZoomed(hwndGroup)) {
  1865. // Maxed.
  1866. state = SW_SHOWMAXIMIZED;
  1867. }
  1868. else if (IsIconic(hwndGroup)) {
  1869. // Minned.
  1870. if(fActivated)
  1871. state = SW_SHOWMINIMIZED;
  1872. else
  1873. state = SW_SHOWMINNOACTIVE;
  1874. }
  1875. else {
  1876. // It's normal.
  1877. if(fActivated)
  1878. state = SW_SHOWNORMAL;
  1879. else
  1880. state = SW_SHOWNOACTIVATE;
  1881. }
  1882. // Give info on the state.
  1883. if (!AddStringToSeg(&hT,&cb,NULL,(WORD)state, FALSE))
  1884. goto Fail;
  1885. #else
  1886. if (!AddStringToSeg(&hT,&cb,NULL,i,FALSE))
  1887. goto Fail;
  1888. #endif
  1889. if (!AddStringToSeg(&hT,&cb,NULL,(WORD)pGroup->fCommon,TRUE))
  1890. goto Fail;
  1891. /* each additional line is an item
  1892. */
  1893. for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
  1894. lpid = ITEM(lpgd,pItem->iItem);
  1895. /* name
  1896. */
  1897. if (!AddStringToSeg(&hT, &cb, (LPTSTR) PTR(lpgd, lpid->pName), TRUE, FALSE))
  1898. goto Fail;
  1899. /* command line and default directory
  1900. */
  1901. GetItemCommand(pGroup, pItem, szPathField, szDirField);
  1902. if (!AddStringToSeg(&hT, &cb, szPathField, TRUE, FALSE))
  1903. goto Fail;
  1904. if (!AddStringToSeg(&hT, &cb, szDirField, FALSE, FALSE))
  1905. goto Fail;
  1906. /* icon path
  1907. */
  1908. if (!*(LPTSTR)PTR(lpgd, lpid->pIconPath)) {
  1909. FindIconPath(szPathField, szDirField, szIconPath);
  1910. }
  1911. else {
  1912. lstrcpy(szIconPath, (LPTSTR) PTR(lpgd, lpid->pIconPath));
  1913. }
  1914. if (!AddStringToSeg(&hT, &cb, szIconPath, FALSE, FALSE))
  1915. goto Fail;
  1916. /* x-y coordinates
  1917. */
  1918. if (!AddStringToSeg(&hT, &cb, NULL, (WORD)pItem->rcIcon.left, FALSE))
  1919. goto Fail;
  1920. if (!AddStringToSeg(&hT, &cb, NULL, (WORD)pItem->rcIcon.top, FALSE))
  1921. goto Fail;
  1922. /* icon, hotkey, fminimize
  1923. */
  1924. if ((SHORT)lpid->wIconIndex >= 0) {
  1925. //
  1926. // apps requesting group info are expecting icon index not icon id.
  1927. //
  1928. if (!AddStringToSeg(&hT, &cb, NULL, lpid->wIconIndex,FALSE))
  1929. goto Fail;
  1930. }
  1931. else {
  1932. if (!AddStringToSeg(&hT, &cb, NULL, lpid->iIcon, FALSE))
  1933. goto Fail;
  1934. }
  1935. if (!AddStringToSeg(&hT,&cb,NULL,GroupFlag(pGroup,pItem,(WORD)ID_HOTKEY),FALSE))
  1936. goto Fail;
  1937. if (!AddStringToSeg(&hT,&cb,NULL,GroupFlag(pGroup,pItem,(WORD)ID_MINIMIZE),FALSE))
  1938. goto Fail;
  1939. if (!AddStringToSeg(&hT,&cb,NULL,GroupFlag(pGroup,pItem,(WORD)ID_NEWVDM),TRUE))
  1940. goto Fail;
  1941. }
  1942. #ifdef ORGCODE
  1943. PostMessage(hwndConv, WM_DDE_DATA, hwnd, MAKELONG(hT,cfFormat));
  1944. #else
  1945. if (cfFormat == CF_TEXT) {
  1946. LPSTR lpMultiByteStr = NULL;
  1947. int cchMultiByte = 0;
  1948. HANDLE hMultiByte;
  1949. // convert the string to Ansi
  1950. lpT = GlobalLock(hT) ;
  1951. cchMultiByte = WideCharToMultiByte(CP_ACP, 0,
  1952. (LPTSTR)((LPBYTE)lpT+ 2*sizeof(WORD)), -1,
  1953. lpMultiByteStr, cchMultiByte, NULL, NULL);
  1954. hMultiByte = GlobalAlloc(GMEM_MOVEABLE,(++cchMultiByte) + 2 * sizeof(WORD));
  1955. lpMultiByteStr = GlobalLock(hMultiByte);
  1956. ((WORD FAR *)lpMultiByteStr)[0] = 3 << 12;
  1957. ((WORD FAR *)lpMultiByteStr)[1] = CF_TEXT;
  1958. WideCharToMultiByte(CP_ACP, 0,
  1959. (LPTSTR)((LPBYTE)lpT+ 2*sizeof(WORD)), -1,
  1960. (LPSTR)(lpMultiByteStr + 2 * sizeof(WORD)),
  1961. cchMultiByte, NULL, NULL);
  1962. GlobalUnlock(hMultiByte);
  1963. GlobalUnlock(hT);
  1964. GlobalFree(hT);
  1965. hT = hMultiByte;
  1966. }
  1967. MPostWM_DDE_DATA(hwndConv, hwnd, hT, (ATOM)aName);
  1968. #endif
  1969. }
  1970. /*--------------------------------------------------------------------------*/
  1971. /* */
  1972. /* DDEMsgProc() - */
  1973. /* */
  1974. /*--------------------------------------------------------------------------*/
  1975. LRESULT APIENTRY DDEMsgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  1976. {
  1977. switch (wMsg) {
  1978. // should go in ProgmanWndProc
  1979. case WM_DDE_INITIATE:
  1980. //
  1981. // HACK: returning 1 if the WM_DDE_ACK was sent successfully in
  1982. // InitRespond is NOT part of the DDE Protocol BUT for backward
  1983. // compatability with WIndows3.0 and 3.1 this solves
  1984. // some problems with WOW apps' setup.
  1985. //
  1986. #ifdef DEBUG_PROGMAN_DDE
  1987. {
  1988. TCHAR szDebug[300];
  1989. wsprintf (szDebug, TEXT("%d PROGMAN: Received WM_DDE_INITIATE\r\n"),
  1990. GetTickCount());
  1991. OutputDebugString(szDebug);
  1992. }
  1993. #endif
  1994. if (InitRespond(hWnd,wParam,lParam,szShell,szAppIcon, TRUE))
  1995. return(1L);
  1996. if (InitRespond(hWnd,wParam,lParam,szShell,szAppDesc, TRUE))
  1997. return(1L);
  1998. if (InitRespond(hWnd,wParam,lParam,szShell,szAppWDir, TRUE))
  1999. return(1L);
  2000. // InitRespond(hWnd,wParam,lParam,szShell,szSystem, TRUE);
  2001. if (InitRespond(hWnd,wParam,lParam,szProgman,szProgman, FALSE)) {
  2002. #ifdef DEBUG_PROGMAN_DDE
  2003. {
  2004. TCHAR szDebug[300];
  2005. wsprintf (szDebug, TEXT("%d PROGMAN: Received WM_DDE_INITIATE. return 1\r\n"),
  2006. GetTickCount());
  2007. OutputDebugString(szDebug);
  2008. }
  2009. #endif
  2010. return(1L);
  2011. }
  2012. //
  2013. // For compatibility reasons, allow Shell - AppProperties DDE
  2014. // connection
  2015. //
  2016. if (InitRespond(hWnd,wParam,lParam,szShell,szAppProperties, TRUE))
  2017. return(1L);
  2018. #ifdef DEBUG_PROGMAN_DDE
  2019. {
  2020. TCHAR szDebug[300];
  2021. wsprintf (szDebug, TEXT("%d PROGMAN: Received WM_DDE_INITIATE. FAILED\r\n"),
  2022. GetTickCount());
  2023. OutputDebugString(szDebug);
  2024. }
  2025. #endif
  2026. break;
  2027. case WM_DDE_REQUEST:
  2028. {
  2029. ATOM fmt;
  2030. ATOM aItem;
  2031. fmt = GET_WM_DDE_REQUEST_FORMAT(wParam, lParam);
  2032. aItem = GET_WM_DDE_REQUEST_ITEM(wParam, lParam);
  2033. if (aItem == GlobalFindAtom(szProgman)
  2034. || aItem == GlobalFindAtom(szGroupList)) {
  2035. GroupRequest(hWnd, (HWND)wParam, fmt, aItem);
  2036. }
  2037. else
  2038. DumpGroup(hWnd, aItem, (HWND)wParam, fmt);
  2039. DDEFREE(WM_DDE_REQUEST, lParam);
  2040. break;
  2041. }
  2042. case WM_DDE_EXECUTE:
  2043. {
  2044. HANDLE hCommands;
  2045. WORD wStatus;
  2046. DWORD ret;
  2047. LPSTR lpCommands ;
  2048. HLOCAL hloc ;
  2049. HLOCAL hlocTemp ;
  2050. int cchMultiByte ;
  2051. LPWSTR lpWideCharStr = NULL ;
  2052. int cchWideChar = 0 ;
  2053. BOOL bIsWindowUnicode ;
  2054. UnpackDDElParam(WM_DDE_EXECUTE, lParam, NULL, (PUINT_PTR)&hCommands);
  2055. // was the sending window a unicode app?
  2056. bIsWindowUnicode=IsWindowUnicode((HWND)wParam) ;
  2057. if (!bIsWindowUnicode) {
  2058. // convert the string to unicode
  2059. lpCommands = GlobalLock(hCommands) ;
  2060. cchMultiByte=MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,lpCommands,
  2061. -1,lpWideCharStr,cchWideChar) ;
  2062. hloc = GlobalAlloc(GMEM_MOVEABLE,(++cchMultiByte)*sizeof(TCHAR)) ;
  2063. lpWideCharStr = GlobalLock(hloc) ;
  2064. MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,lpCommands,
  2065. -1,lpWideCharStr,cchMultiByte) ;
  2066. GlobalUnlock(hloc) ;
  2067. GlobalUnlock(hCommands) ;
  2068. hlocTemp = hCommands;
  2069. hCommands = hloc ;
  2070. }
  2071. if (ret = ExecuteHandler(hCommands)) {
  2072. wStatus = 0x8000;
  2073. } else {
  2074. wStatus = 0x0000;
  2075. }
  2076. if (!bIsWindowUnicode) {
  2077. hCommands = hlocTemp;
  2078. GlobalFree(hloc) ;
  2079. }
  2080. MPostWM_DDE_EXECACK((HWND)wParam, hWnd, wStatus, hCommands);
  2081. if (ret == 2) { // Exit command was executed
  2082. MPostWM_DDE_TERMINATE((HWND)wParam, hWnd);
  2083. PostMessage(hwndProgman, WM_CLOSE, 0, 0L);
  2084. }
  2085. // DDEFREE(WM_DDE_EXECUTE, lParam); // executes arn't really packed.
  2086. break;
  2087. }
  2088. case WM_DDE_TERMINATE:
  2089. #ifdef ORGCODE
  2090. SendMessage(wParam, WM_DDE_TERMINATE, (WPARAM)hWnd, lParam);
  2091. #else
  2092. RemoveDdeConversation(hWnd, (HWND)wParam, DDE_PROGMAN);
  2093. MPostWM_DDE_TERMINATE((HWND)wParam, hWnd);
  2094. // DDEFREE(WM_DDE_TERMINATE, lParam); // terminates arn't packed
  2095. #endif
  2096. if (hWnd != hwndProgman) {
  2097. DestroyWindow (hWnd);
  2098. }
  2099. break;
  2100. case WM_DDE_ACK:
  2101. DDEFREE(WM_DDE_ACK, lParam);
  2102. break;
  2103. /* All other DDE messages are unsupported. */
  2104. case WM_DDE_DATA:
  2105. case WM_DDE_ADVISE:
  2106. case WM_DDE_UNADVISE:
  2107. case WM_DDE_POKE:
  2108. #ifdef ORGCODE
  2109. DDEFail(hWnd,wParam,lParam);
  2110. #else
  2111. {
  2112. UINT_PTR uiHi;
  2113. UnpackDDElParam(wMsg, lParam, NULL, &uiHi);
  2114. DDEFail(hWnd, (HWND)wParam, (ATOM)uiHi);
  2115. DDEFREE(wMsg, lParam);
  2116. }
  2117. #endif
  2118. break;
  2119. default:
  2120. return DefWindowProc(hWnd,wMsg,wParam,lParam);
  2121. }
  2122. return(0L);
  2123. }
  2124. /*--------------------------------------------------------------------------*/
  2125. /* */
  2126. /* AppIconDDEMsgProc() - */
  2127. /* */
  2128. /* Application = "Shell" */
  2129. /* Topic = "AppIcon" */
  2130. /* */
  2131. /*--------------------------------------------------------------------------*/
  2132. LRESULT APIENTRY AppIconDDEMsgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  2133. {
  2134. switch (wMsg) {
  2135. case WM_DDE_REQUEST:
  2136. FindIconProp(hWnd, wParam, lParam, APP_ICON);
  2137. DDEFREE(WM_DDE_REQUEST, lParam);
  2138. break;
  2139. case WM_DDE_TERMINATE:
  2140. RemoveDdeConversation(hWnd, (HWND)wParam, APP_ICON);
  2141. MPostWM_DDE_TERMINATE((HWND)wParam, hWnd);
  2142. DDEFREE(WM_DDE_TERMINATE, lParam);
  2143. DestroyWindow(hWnd);
  2144. break;
  2145. default:
  2146. return DDEMsgProc(hWnd, wMsg, wParam, lParam);
  2147. }
  2148. return 0L;
  2149. }
  2150. /*--------------------------------------------------------------------------*/
  2151. /* */
  2152. /* AppDescriptionDDEMsgProc() - */
  2153. /* */
  2154. /* Application = "Shell" */
  2155. /* Topic = "AppDescription" */
  2156. /* */
  2157. /*--------------------------------------------------------------------------*/
  2158. LRESULT APIENTRY AppDescriptionDDEMsgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  2159. {
  2160. switch (wMsg) {
  2161. case WM_DDE_REQUEST:
  2162. FindIconProp(hWnd, wParam, lParam, APP_DESC);
  2163. DDEFREE(WM_DDE_REQUEST, lParam);
  2164. break;
  2165. case WM_DDE_TERMINATE:
  2166. RemoveDdeConversation(hWnd, (HWND)wParam, APP_DESC);
  2167. PostMessage((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hWnd, 0L);
  2168. DestroyWindow(hWnd);
  2169. break;
  2170. default:
  2171. return DDEMsgProc(hWnd, wMsg, wParam, lParam);
  2172. }
  2173. return 0L;
  2174. }
  2175. /*--------------------------------------------------------------------------*/
  2176. /* */
  2177. /* AppWorkingDirDDEMsgProc() - */
  2178. /* */
  2179. /* Application = "Shell" */
  2180. /* Topic = "AppWorkingDir" */
  2181. /* */
  2182. /*--------------------------------------------------------------------------*/
  2183. LRESULT APIENTRY AppWorkingDirDDEMsgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  2184. {
  2185. switch (wMsg) {
  2186. case WM_DDE_REQUEST:
  2187. FindIconProp(hWnd, wParam, lParam, APP_WDIR);
  2188. DDEFREE(WM_DDE_REQUEST, lParam);
  2189. break;
  2190. case WM_DDE_TERMINATE:
  2191. RemoveDdeConversation(hWnd, (HWND)wParam, APP_WDIR);
  2192. MPostWM_DDE_TERMINATE((HWND)wParam, hWnd);
  2193. DDEFREE(WM_DDE_TERMINATE, lParam);
  2194. DestroyWindow(hWnd);
  2195. break;
  2196. default:
  2197. return DDEMsgProc(hWnd, wMsg, wParam, lParam);
  2198. }
  2199. return 0L;
  2200. }
  2201. VOID APIENTRY RegisterDDEClasses(HANDLE hInstance)
  2202. {
  2203. WNDCLASS wc;
  2204. wc.style = 0;
  2205. wc.lpfnWndProc = AppIconDDEMsgProc;
  2206. wc.cbClsExtra = 0;
  2207. wc.cbWndExtra = 0;
  2208. wc.hInstance = hInstance;
  2209. wc.hIcon = NULL;
  2210. wc.hCursor = NULL;
  2211. wc.hbrBackground = NULL;
  2212. wc.lpszMenuName = NULL;
  2213. wc.lpszClassName = szAppIconDDE;
  2214. if (!RegisterClass(&wc))
  2215. bAppIconDDE = FALSE;
  2216. wc.lpfnWndProc = AppDescriptionDDEMsgProc;
  2217. wc.lpszClassName = szAppDescDDE;
  2218. if (!RegisterClass(&wc))
  2219. bAppDescDDE = FALSE;
  2220. wc.lpfnWndProc = AppWorkingDirDDEMsgProc;
  2221. wc.lpszClassName = szAppWDirDDE;
  2222. if (!RegisterClass(&wc))
  2223. bAppWDirDDE = FALSE;
  2224. wc.lpfnWndProc = DDEMsgProc;
  2225. wc.lpszClassName = szProgmanDDE;
  2226. if (!RegisterClass(&wc))
  2227. bProgmanDDE = FALSE;
  2228. InitDdeConversationStruct();
  2229. }