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.

435 lines
9.9 KiB

  1. /******************************************************************************\
  2. * This is a part of the Microsoft Source Code Samples.
  3. * Copyright 1995 - 1997 Microsoft Corporation.
  4. * All rights reserved.
  5. * This source code is only intended as a supplement to
  6. * Microsoft Development Tools and/or WinHelp documentation.
  7. * See these sources for detailed information regarding the
  8. * Microsoft samples programs.
  9. \******************************************************************************/
  10. /*++
  11. Copyright (c) 1997 Microsoft Corporation
  12. Module Name:
  13. SrvQuery.c
  14. Abstract:
  15. The server component of Remote. Respond to client
  16. "remote /q" requests to list available remote servers
  17. on this machine.
  18. Author:
  19. Dave Hart 30 May 1997
  20. derived from code by Mihai Costea in server.c.
  21. Environment:
  22. Console App. User mode.
  23. Revision History:
  24. --*/
  25. #include <windows.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <process.h>
  29. #include <io.h>
  30. #include <string.h>
  31. #include "Remote.h"
  32. #include "Server.h"
  33. VOID
  34. FASTCALL
  35. InitializeQueryServer(
  36. VOID
  37. )
  38. {
  39. //
  40. // hQPipe is the handle to the listening query pipe,
  41. // if we're serving it.
  42. //
  43. hQPipe = INVALID_HANDLE_VALUE;
  44. QueryOverlapped.hEvent =
  45. CreateEvent(
  46. NULL, // security
  47. TRUE, // manual-reset
  48. FALSE, // initially nonsignaled
  49. NULL // unnamed
  50. );
  51. rghWait[WAITIDX_QUERYSRV_WAIT] =
  52. CreateMutex(
  53. &saPublic, // security
  54. FALSE, // not owner in case we open not create
  55. "MS RemoteSrv Q Mutex"
  56. );
  57. if (INVALID_HANDLE_VALUE == rghWait[WAITIDX_QUERYSRV_WAIT]) {
  58. ErrorExit("Remote: Unable to create/open query server mutex.\n");
  59. }
  60. }
  61. VOID
  62. FASTCALL
  63. QueryWaitCompleted(
  64. VOID
  65. )
  66. {
  67. HANDLE hWait;
  68. DWORD dwThreadId;
  69. BOOL b;
  70. DWORD dwRead;
  71. //
  72. // The remote server (not us) which was servicing the query
  73. // pipe has left the arena. Or someone has connected.
  74. //
  75. hWait = rghWait[WAITIDX_QUERYSRV_WAIT];
  76. if (hWait == QueryOverlapped.hEvent) {
  77. //
  78. // We're the query server and someone has connected.
  79. // Start a thread to service them.
  80. //
  81. b = GetOverlappedResult(hQPipe, &QueryOverlapped, &dwRead, TRUE);
  82. if ( !b && ERROR_PIPE_CONNECTED != GetLastError()) {
  83. TRACE(QUERY,("Connect Query Pipe returned %d\n", GetLastError()));
  84. if (INVALID_HANDLE_VALUE != hQPipe) {
  85. CloseHandle(hQPipe);
  86. hQPipe = INVALID_HANDLE_VALUE;
  87. }
  88. } else {
  89. TRACE(QUERY, ("Client connected to query pipe.\n"));
  90. ResetEvent(hWait);
  91. CloseHandle( (HANDLE)
  92. _beginthreadex(
  93. NULL, // security
  94. 0, // default stack size
  95. QueryHandlerThread,
  96. (LPVOID) hQPipe, // parameter
  97. 0, // not suspended
  98. &dwThreadId
  99. ));
  100. hQPipe = INVALID_HANDLE_VALUE;
  101. }
  102. } else {
  103. TRACE(QUERY, ("Remote server entered query mutex, will handle queries.\n"));
  104. rghWait[WAITIDX_QUERYSRV_WAIT] = QueryOverlapped.hEvent;
  105. }
  106. //
  107. // Either a client has connected and we've handed that pipe
  108. // off to a query thread to deal with, or we're just starting
  109. // to serve the query pipe, or we had an error from
  110. // ConnectNamedPipe. In any case we want to create another
  111. // query pipe instance and start listening on it.
  112. //
  113. ASSERT(INVALID_HANDLE_VALUE == hQPipe);
  114. StartServingQueryPipe();
  115. }
  116. VOID
  117. FASTCALL
  118. StartServingQueryPipe(
  119. VOID
  120. )
  121. {
  122. BOOL b;
  123. DWORD dwThreadId;
  124. char fullname[BUFFSIZE];
  125. sprintf(fullname, QUERY_DEBUGGERS_PIPE, ".");
  126. do { // hand off each pipe as connected until IO_PENDING
  127. hQPipe =
  128. CreateNamedPipe(
  129. fullname,
  130. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  131. PIPE_TYPE_BYTE | PIPE_WAIT,
  132. PIPE_UNLIMITED_INSTANCES,
  133. 0,
  134. 0,
  135. 0,
  136. &saPublic
  137. );
  138. if (INVALID_HANDLE_VALUE == hQPipe) {
  139. ErrorExit("Unable to create query server pipe.");
  140. }
  141. b = ConnectNamedPipe(hQPipe, &QueryOverlapped);
  142. if ( ! b && ERROR_PIPE_CONNECTED == GetLastError()) {
  143. b = TRUE;
  144. }
  145. if (b) {
  146. //
  147. // That was fast.
  148. //
  149. TRACE(QUERY, ("Client connected quickly to query pipe.\n"));
  150. CloseHandle( (HANDLE)
  151. _beginthreadex(
  152. NULL, // security
  153. 0, // default stack size
  154. QueryHandlerThread,
  155. (LPVOID) hQPipe, // parameter
  156. 0, // not suspended
  157. &dwThreadId
  158. ));
  159. hQPipe = INVALID_HANDLE_VALUE;
  160. } else if (ERROR_IO_PENDING == GetLastError()) {
  161. //
  162. // The main thread will call QueryWaitCompleted when
  163. // someone connects.
  164. //
  165. TRACE(QUERY, ("Awaiting query pipe connect\n"));
  166. } else {
  167. sprintf(fullname, "Remote: error %d connecting query pipe.\n", GetLastError());
  168. OutputDebugString(fullname);
  169. ErrorExit(fullname);
  170. }
  171. } while (b);
  172. }
  173. DWORD
  174. WINAPI
  175. QueryHandlerThread(
  176. LPVOID lpvArg
  177. )
  178. {
  179. HANDLE hQueryPipe = (HANDLE) lpvArg;
  180. DWORD cb;
  181. BOOL b;
  182. OVERLAPPED ol;
  183. QUERY_MESSAGE QData;
  184. char pIn[1];
  185. ZeroMemory(&ol, sizeof(ol));
  186. ol.hEvent =
  187. CreateEvent(
  188. NULL, // security
  189. TRUE, // manual-reset
  190. FALSE, // initially nonsignaled
  191. NULL // unnamed
  192. );
  193. // get command
  194. b = ReadFileSynch(
  195. hQueryPipe,
  196. pIn,
  197. 1,
  198. &cb,
  199. 0,
  200. &ol
  201. );
  202. if ( ! b || 1 != cb ) {
  203. TRACE(QUERY, ("Query server unable to read byte from query pipe.\n"));
  204. goto failure;
  205. }
  206. TRACE(QUERY, ("Query server read command '%c'\n", pIn[0]));
  207. //
  208. // !!!!!!
  209. // REMOVE 'h' support, it's only here for transitional compatibility
  210. // with 1570+ remote /q original server implementation.
  211. //
  212. if(pIn[0] == 'h') {
  213. DWORD dwMinusOne = (DWORD) -1;
  214. b = WriteFileSynch(
  215. hQueryPipe,
  216. &dwMinusOne,
  217. sizeof(dwMinusOne),
  218. &cb,
  219. 0,
  220. &ol
  221. );
  222. if ( !b || sizeof(dwMinusOne) != cb )
  223. {
  224. goto failure;
  225. }
  226. }
  227. if(pIn[0] == 'q') {
  228. QData.size = 0;
  229. QData.allocated = 0;
  230. QData.out = NULL;
  231. EnumWindows(EnumWindowProc, (LPARAM)&QData);
  232. b = WriteFileSynch(
  233. hQueryPipe,
  234. &QData.size,
  235. sizeof(QData.size),
  236. &cb,
  237. 0,
  238. &ol
  239. );
  240. if ( ! b || sizeof(int) != cb) {
  241. TRACE(QUERY, ("Remote: Can't write query length\n"));
  242. goto failure;
  243. }
  244. if (QData.size) { // anything to say?
  245. b = WriteFileSynch(
  246. hQueryPipe,
  247. QData.out,
  248. QData.size * sizeof(char),
  249. &cb,
  250. 0,
  251. &ol
  252. );
  253. free(QData.out);
  254. if ( ! b || QData.size * sizeof(char) != cb) {
  255. TRACE(QUERY, ("Remote: Can't write query"));
  256. goto failure;
  257. }
  258. TRACE(QUERY, ("Sent query response\n"));
  259. }
  260. }
  261. FlushFileBuffers(hQueryPipe);
  262. failure:
  263. DisconnectNamedPipe(hQueryPipe);
  264. CloseHandle(hQueryPipe);
  265. CloseHandle(ol.hEvent);
  266. return 0;
  267. }
  268. BOOL
  269. CALLBACK
  270. EnumWindowProc(
  271. HWND hWnd,
  272. LPARAM lParam
  273. )
  274. {
  275. #define MAX_TITLELEN 200
  276. QUERY_MESSAGE *pQm;
  277. int titleLen;
  278. char title[MAX_TITLELEN];
  279. char* tmp;
  280. pQm = (QUERY_MESSAGE*)lParam;
  281. if(titleLen = GetWindowText(hWnd, title, sizeof(title)/sizeof(title[0])))
  282. {
  283. //
  284. // search for all windows that are visible
  285. //
  286. if (strstr(title, "] visible") &&
  287. strstr(title, "[Remote "))
  288. {
  289. if(pQm->size) // if message not empty
  290. pQm->out[(pQm->size)++] = '\n'; // overwrite ending null with \n
  291. else
  292. {
  293. pQm->out = (char*)malloc(MAX_TITLELEN); // first allocation
  294. if(!pQm->out)
  295. {
  296. printf("\nOut of memory\n");
  297. return FALSE;
  298. }
  299. pQm->allocated = MAX_TITLELEN;
  300. }
  301. // fill the result
  302. if((pQm->size + titleLen) >= pQm->allocated)
  303. {
  304. tmp = (char*)realloc(pQm->out, pQm->allocated + MAX_TITLELEN);
  305. if(!tmp)
  306. {
  307. printf("\nOut of memory\n");
  308. free(pQm->out);
  309. pQm->size = 0;
  310. return FALSE;
  311. }
  312. pQm->out = tmp;
  313. pQm->allocated += MAX_TITLELEN;
  314. }
  315. strcpy(pQm->out + pQm->size, title);
  316. pQm->size += titleLen;
  317. }
  318. }
  319. return TRUE;
  320. #undef MAX_TITLELEN
  321. }