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.

221 lines
5.6 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. DelayShowGroup.cpp
  5. Abstract:
  6. When the ShowGroup command is sent to Program Manager (DDE),
  7. wait for the window to actually appear before returning.
  8. History:
  9. 10/05/2000 robkenny Created
  10. --*/
  11. #include "precomp.h"
  12. #include <ParseDDE.h>
  13. IMPLEMENT_SHIM_BEGIN(DelayShowGroup)
  14. #include "ShimHookMacro.h"
  15. APIHOOK_ENUM_BEGIN
  16. APIHOOK_ENUM_ENTRY(DdeClientTransaction)
  17. APIHOOK_ENUM_END
  18. static DWORD dwMaxWaitTime = 5000; // 5 seconds
  19. // A list of DDE commands that we are interested in.
  20. const char * c_sDDECommands[] =
  21. {
  22. "ShowGroup",
  23. NULL,
  24. } ;
  25. // Return FALSE if this window contains the pathname in lParam
  26. BOOL
  27. CALLBACK WindowEnumCB(
  28. HWND hwnd, // handle to parent window
  29. LPARAM lParam // application-defined value
  30. )
  31. {
  32. const char * szGroupName = (const char *)lParam;
  33. char lpWindowTitle[MAX_PATH];
  34. if (GetWindowTextA(hwnd, lpWindowTitle, MAX_PATH) > 0)
  35. {
  36. //DPF(eDbgLevelSpew, "Window(%s)\n", lpWindowTitle);
  37. if (_tcsicmp(lpWindowTitle, szGroupName) == 0)
  38. return FALSE;
  39. }
  40. return TRUE; // keep enumming
  41. }
  42. // Determine if a window with the szGroupName exists on the sytem
  43. BOOL
  44. CheckForWindow(const char * szGroupName)
  45. {
  46. DWORD success = EnumDesktopWindows(NULL, WindowEnumCB, (LPARAM)szGroupName);
  47. BOOL retval = success == 0 && GetLastError() == 0;
  48. return retval;
  49. }
  50. // Check to see if this is a ShowGroup command,
  51. // if it is do not return until the window actually exists
  52. void
  53. DelayIfShowGroup(LPBYTE pData)
  54. {
  55. if (pData)
  56. {
  57. // Now we need to parse the string, looking for a DeleteGroup command
  58. // Format "ShowGroup(GroupName,ShowCommand[,CommonGroupFlag])"
  59. // CommonGroupFlag is optional
  60. char * pszBuf = StringDuplicateA((const char *)pData);
  61. if (!pszBuf)
  62. return;
  63. UINT * lpwCmd = GetDDECommands(pszBuf, c_sDDECommands, FALSE);
  64. if (lpwCmd)
  65. {
  66. // Store off lpwCmd so we can free the correct addr later
  67. UINT *lpwCmdTemp = lpwCmd;
  68. // Execute a command.
  69. while (*lpwCmd != (UINT)-1)
  70. {
  71. UINT wCmd = *lpwCmd++;
  72. // Subtract 1 to account for the terminating NULL
  73. if (wCmd < ARRAYSIZE(c_sDDECommands)-1)
  74. {
  75. // We found a command--it must be DeleteGroup--since there is only 1
  76. BOOL iCommonGroup = -1;
  77. // From DDE_ShowGroup
  78. if (*lpwCmd < 2 || *lpwCmd > 3)
  79. {
  80. goto Leave;
  81. }
  82. if (*lpwCmd == 3) {
  83. //
  84. // Need to check for common group flag
  85. //
  86. if (pszBuf[*(lpwCmd + 3)] == '1') {
  87. iCommonGroup = 1;
  88. } else {
  89. iCommonGroup = 0;
  90. }
  91. }
  92. const char * groupName = pszBuf + lpwCmd[1];
  93. // Build a path to the directory
  94. CHAR szGroupName[MAX_PATH];
  95. GetGroupPath(groupName, szGroupName, 0, iCommonGroup);
  96. // We need to wait until we have a window whose title matches this group
  97. DWORD dwStartTime = GetTickCount();
  98. DWORD dwNowTime = dwStartTime;
  99. BOOL bWindowExists = FALSE;
  100. while (dwNowTime - dwStartTime < dwMaxWaitTime)
  101. {
  102. bWindowExists = CheckForWindow(szGroupName);
  103. if (bWindowExists)
  104. break;
  105. Sleep(100); // wait a bit more
  106. dwNowTime = GetTickCount();
  107. }
  108. LOGN(
  109. eDbgLevelError,
  110. "DelayIfShowGroup: %8s(%s).",
  111. bWindowExists ? "Show" : "Timeout",
  112. szGroupName);
  113. }
  114. // Next command.
  115. lpwCmd += *lpwCmd + 1;
  116. }
  117. Leave:
  118. // Tidyup...
  119. GlobalFree(lpwCmdTemp);
  120. }
  121. free(pszBuf);
  122. }
  123. }
  124. HDDEDATA
  125. APIHOOK(DdeClientTransaction)(
  126. LPBYTE pData, // pointer to data to pass to server
  127. DWORD cbData, // length of data
  128. HCONV hConv, // handle to conversation
  129. HSZ hszItem, // handle to item name string
  130. UINT wFmt, // clipboard data format
  131. UINT wType, // transaction type
  132. DWORD dwTimeout, // time-out duration
  133. LPDWORD pdwResult // pointer to transaction result
  134. )
  135. {
  136. #if 0
  137. dwTimeout = 0x0fffffff; // a long time, enables me to debug explorer
  138. #endif
  139. if (pData)
  140. {
  141. DPFN(eDbgLevelInfo, "DdeClientTransaction(%s) called.", pData);
  142. }
  143. // Pass data through untouched.
  144. HDDEDATA retval = ORIGINAL_API(DdeClientTransaction)(
  145. pData, // pointer to data to pass to server
  146. cbData, // length of data
  147. hConv, // handle to conversation
  148. hszItem, // handle to item name string
  149. wFmt, // clipboard data format
  150. wType, // transaction type
  151. dwTimeout, // time-out duration
  152. pdwResult // pointer to transaction result
  153. );
  154. if (pData)
  155. DelayIfShowGroup(pData);
  156. return retval;
  157. }
  158. /*++
  159. Register hooked functions
  160. --*/
  161. HOOK_BEGIN
  162. APIHOOK_ENTRY(USER32.DLL, DdeClientTransaction)
  163. HOOK_END
  164. IMPLEMENT_SHIM_END