Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
6.2 KiB

  1. /*************************************************************************
  2. *
  3. * sendmsg.c
  4. *
  5. * Copyright (c) 1985 - 1999, Microsoft Corporation
  6. *
  7. * Terminal Server (Hydra) specific code
  8. *
  9. * Processend message to winstation
  10. *
  11. * $Author: Ara bernardi
  12. *
  13. *************************************************************************/
  14. //
  15. // Includes
  16. //
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. #include "dbt.h"
  20. #include "ntdddisk.h"
  21. #include "ntuser.h"
  22. #include <winsta.h>
  23. #include <wstmsg.h>
  24. #include <winuser.h>
  25. NTSTATUS ReplyInvalidWindowToTerminalServer (HWND hWnd, ULONG ulSessionId);
  26. /*******************************************************************************
  27. *
  28. * RemoteDoBrroadcastSystemMessage
  29. *
  30. * ENTRY:
  31. *
  32. * EXIT:
  33. * STATUS_SUCCESS - successful
  34. *
  35. ******************************************************************************/
  36. NTSTATUS
  37. RemoteDoBroadcastSystemMessage(
  38. PWINSTATION_APIMSG pMsg)
  39. {
  40. LONG rc;
  41. WINSTATIONBROADCASTSYSTEMMSG *pmsg;
  42. LPARAM tmpLPARAM;
  43. NTSTATUS status;
  44. pmsg = &(pMsg->u.bMsg);
  45. if ( pmsg->bufferSize )
  46. {
  47. // we have a databuffer, set the lParam to our copied data buffer
  48. tmpLPARAM = (LPARAM)pmsg->dataBuffer;
  49. }
  50. else
  51. {
  52. tmpLPARAM = pmsg->lParam ;
  53. }
  54. rc = BroadcastSystemMessage( pmsg->dwFlags, &pmsg->dwRecipients,
  55. pmsg->uiMessage, pmsg->wParam, tmpLPARAM );
  56. status = STATUS_SUCCESS;
  57. pmsg->Response = rc;
  58. return status ;
  59. }
  60. NTSTATUS
  61. RemoteDoSendWindowMessage(
  62. PWINSTATION_APIMSG pMsg)
  63. {
  64. static UINT uiReasonableTimeout = 10000; // 10 sec.
  65. static BOOL bReadTimeout = FALSE;
  66. WINSTATIONSENDWINDOWMSG *pmsg;
  67. LPARAM tmpLPARAM;
  68. ULONG_PTR rc;
  69. if (!bReadTimeout)
  70. {
  71. HKEY hKey;
  72. UNICODE_STRING UnicodeString;
  73. OBJECT_ATTRIBUTES OA;
  74. NTSTATUS Status;
  75. //
  76. // read a timeout value from registry
  77. //
  78. RtlInitUnicodeString(&UnicodeString,
  79. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Terminal Server");
  80. InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
  81. Status = NtOpenKey(&hKey, KEY_READ, &OA);
  82. if (NT_SUCCESS(Status))
  83. {
  84. BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
  85. DWORD cbSize;
  86. RtlInitUnicodeString(&UnicodeString, L"NotificationTimeOut");
  87. Status = NtQueryValueKey(hKey,
  88. &UnicodeString,
  89. KeyValuePartialInformation,
  90. (PKEY_VALUE_PARTIAL_INFORMATION)Buf,
  91. sizeof(Buf),
  92. &cbSize);
  93. if (NT_SUCCESS(Status))
  94. {
  95. uiReasonableTimeout = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
  96. if (uiReasonableTimeout == 0)
  97. uiReasonableTimeout = 10000;
  98. }
  99. NtClose(hKey);
  100. }
  101. bReadTimeout = TRUE;
  102. }
  103. pmsg = &(pMsg->u.sMsg);
  104. if ( pmsg->bufferSize )
  105. {
  106. // we have a databuffer, set the lParam to our copied data buffer
  107. tmpLPARAM = (LPARAM)pmsg->dataBuffer;
  108. }
  109. else
  110. {
  111. tmpLPARAM = (LPARAM)pmsg->lParam;
  112. }
  113. //
  114. // No need to worry about disconnected sessions (desktop), since msg is sent to a specific hwnd.
  115. // I have verified this imperically.
  116. //
  117. RIPMSG3(RIP_VERBOSE, "MEssage %x, wPAram %x, lParam %x", pmsg->Msg,
  118. pmsg->wParam, pmsg->lParam);
  119. if (pmsg->Msg == WM_WTSSESSION_CHANGE)
  120. {
  121. if (!PostMessage(pmsg->hWnd, pmsg->Msg, pmsg->wParam, pmsg->lParam) && ERROR_INVALID_WINDOW_HANDLE == GetLastError())
  122. {
  123. ReplyInvalidWindowToTerminalServer(pmsg->hWnd, gSessionId);
  124. }
  125. return STATUS_SUCCESS;
  126. }
  127. else if (pmsg->Msg == WM_APPCOMMAND)
  128. {
  129. GUITHREADINFO threadInfo;
  130. HWND hWndForeground;
  131. threadInfo.cbSize = sizeof(GUITHREADINFO);
  132. if (GetGUIThreadInfo(0, &threadInfo)) {
  133. hWndForeground = threadInfo.hwndFocus ? threadInfo.hwndFocus : threadInfo.hwndActive;
  134. if (hWndForeground) {
  135. RIPMSG1(RIP_WARNING, "Sending app command 0x%x", pmsg->wParam);
  136. SendNotifyMessage(hWndForeground,
  137. WM_APPCOMMAND,
  138. (WPARAM)hWndForeground,
  139. ((pmsg->wParam | FAPPCOMMAND_OEM)<<16));
  140. return STATUS_SUCCESS;
  141. } else {
  142. RIPMSG1(RIP_WARNING, "No window available to send to, error %x", GetLastError());
  143. return STATUS_UNSUCCESSFUL;
  144. }
  145. } else {
  146. RIPMSG1(RIP_WARNING, "Unable to get the focus window, error %x", GetLastError());
  147. return STATUS_UNSUCCESSFUL;
  148. }
  149. }
  150. else if (pmsg->Msg == WM_KEYDOWN || pmsg->Msg == WM_KEYUP)
  151. {
  152. INPUT input;
  153. ZeroMemory(&input, sizeof(INPUT));
  154. input.type = INPUT_KEYBOARD;
  155. input.ki.dwFlags = (pmsg->Msg == WM_KEYDOWN) ? 0 : KEYEVENTF_KEYUP;
  156. input.ki.wVk = LOWORD(pmsg->wParam);
  157. input.ki.wScan = LOWORD(pmsg->lParam);
  158. input.ki.dwFlags |= input.ki.wScan ? KEYEVENTF_UNICODE : KEYEVENTF_EXTENDEDKEY;
  159. RIPMSG4(RIP_WARNING, "Sending sc %c, vk %x, %s to session %x", input.ki.wScan,
  160. pmsg->wParam, (pmsg->Msg == WM_KEYDOWN) ? "down" : "up", gSessionId);
  161. SendInput(1, &input, sizeof(INPUT));
  162. return STATUS_SUCCESS;
  163. }
  164. else
  165. {
  166. if (!SendMessageTimeout(
  167. pmsg->hWnd,
  168. pmsg->Msg,
  169. pmsg->wParam,
  170. tmpLPARAM,
  171. SMTO_ABORTIFHUNG | SMTO_NORMAL,
  172. uiReasonableTimeout,
  173. &rc))
  174. {
  175. RIPMSG1(RIP_WARNING, "SendMessageTimeOut failed. LastError = %d", GetLastError());
  176. return STATUS_UNSUCCESSFUL;
  177. }
  178. else
  179. {
  180. pmsg->Response = (ULONG)rc;
  181. return STATUS_SUCCESS;
  182. }
  183. }
  184. }