home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / remote / srvquery.c < prev    next >
C/C++ Source or Header  |  1997-10-12  |  11KB  |  436 lines

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