/******************************************************************************\ * This is a part of the Microsoft Source Code Samples. * Copyright 1995 - 1997 Microsoft Corporation. * All rights reserved. * This source code is only intended as a supplement to * Microsoft Development Tools and/or WinHelp documentation. * See these sources for detailed information regarding the * Microsoft samples programs. \******************************************************************************/ /*++ Copyright (c) 1997 Microsoft Corporation Module Name: SrvQuery.c Abstract: The server component of Remote. Respond to client "remote /q" requests to list available remote servers on this machine. Author: Dave Hart 30 May 1997 derived from code by Mihai Costea in server.c. Environment: Console App. User mode. Revision History: --*/ #include #include #include #include #include #include #include "Remote.h" #include "Server.h" VOID FASTCALL InitializeQueryServer( VOID ) { // // hQPipe is the handle to the listening query pipe, // if we're serving it. // hQPipe = INVALID_HANDLE_VALUE; QueryOverlapped.hEvent = CreateEvent( NULL, // security TRUE, // manual-reset FALSE, // initially nonsignaled NULL // unnamed ); rghWait[WAITIDX_QUERYSRV_WAIT] = CreateMutex( &saPublic, // security FALSE, // not owner in case we open not create "MS RemoteSrv Q Mutex" ); if (INVALID_HANDLE_VALUE == rghWait[WAITIDX_QUERYSRV_WAIT]) { ErrorExit("Remote: Unable to create/open query server mutex.\n"); } } VOID FASTCALL QueryWaitCompleted( VOID ) { HANDLE hWait; DWORD dwThreadId; BOOL b; DWORD dwRead; // // The remote server (not us) which was servicing the query // pipe has left the arena. Or someone has connected. // hWait = rghWait[WAITIDX_QUERYSRV_WAIT]; if (hWait == QueryOverlapped.hEvent) { // // We're the query server and someone has connected. // Start a thread to service them. // b = GetOverlappedResult(hQPipe, &QueryOverlapped, &dwRead, TRUE); if ( !b && ERROR_PIPE_CONNECTED != GetLastError()) { TRACE(QUERY,("Connect Query Pipe returned %d\n", GetLastError())); if (INVALID_HANDLE_VALUE != hQPipe) { CloseHandle(hQPipe); hQPipe = INVALID_HANDLE_VALUE; } } else { TRACE(QUERY, ("Client connected to query pipe.\n")); ResetEvent(hWait); CloseHandle( (HANDLE) _beginthreadex( NULL, // security 0, // default stack size QueryHandlerThread, (LPVOID) hQPipe, // parameter 0, // not suspended &dwThreadId )); hQPipe = INVALID_HANDLE_VALUE; } } else { TRACE(QUERY, ("Remote server entered query mutex, will handle queries.\n")); rghWait[WAITIDX_QUERYSRV_WAIT] = QueryOverlapped.hEvent; } // // Either a client has connected and we've handed that pipe // off to a query thread to deal with, or we're just starting // to serve the query pipe, or we had an error from // ConnectNamedPipe. In any case we want to create another // query pipe instance and start listening on it. // ASSERT(INVALID_HANDLE_VALUE == hQPipe); StartServingQueryPipe(); } VOID FASTCALL StartServingQueryPipe( VOID ) { BOOL b; DWORD dwThreadId; char fullname[BUFFSIZE]; sprintf(fullname, QUERY_DEBUGGERS_PIPE, "."); do { // hand off each pipe as connected until IO_PENDING hQPipe = CreateNamedPipe( fullname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 0, &saPublic ); if (INVALID_HANDLE_VALUE == hQPipe) { ErrorExit("Unable to create query server pipe."); } b = ConnectNamedPipe(hQPipe, &QueryOverlapped); if ( ! b && ERROR_PIPE_CONNECTED == GetLastError()) { b = TRUE; } if (b) { // // That was fast. // TRACE(QUERY, ("Client connected quickly to query pipe.\n")); CloseHandle( (HANDLE) _beginthreadex( NULL, // security 0, // default stack size QueryHandlerThread, (LPVOID) hQPipe, // parameter 0, // not suspended &dwThreadId )); hQPipe = INVALID_HANDLE_VALUE; } else if (ERROR_IO_PENDING == GetLastError()) { // // The main thread will call QueryWaitCompleted when // someone connects. // TRACE(QUERY, ("Awaiting query pipe connect\n")); } else { sprintf(fullname, "Remote: error %d connecting query pipe.\n", GetLastError()); OutputDebugString(fullname); ErrorExit(fullname); } } while (b); } DWORD WINAPI QueryHandlerThread( LPVOID lpvArg ) { HANDLE hQueryPipe = (HANDLE) lpvArg; DWORD cb; BOOL b; OVERLAPPED ol; QUERY_MESSAGE QData; char pIn[1]; ZeroMemory(&ol, sizeof(ol)); ol.hEvent = CreateEvent( NULL, // security TRUE, // manual-reset FALSE, // initially nonsignaled NULL // unnamed ); // get command b = ReadFileSynch( hQueryPipe, pIn, 1, &cb, 0, &ol ); if ( ! b || 1 != cb ) { TRACE(QUERY, ("Query server unable to read byte from query pipe.\n")); goto failure; } TRACE(QUERY, ("Query server read command '%c'\n", pIn[0])); // // !!!!!! // REMOVE 'h' support, it's only here for transitional compatibility // with 1570+ remote /q original server implementation. // if(pIn[0] == 'h') { DWORD dwMinusOne = (DWORD) -1; b = WriteFileSynch( hQueryPipe, &dwMinusOne, sizeof(dwMinusOne), &cb, 0, &ol ); if ( !b || sizeof(dwMinusOne) != cb ) { goto failure; } } if(pIn[0] == 'q') { QData.size = 0; QData.allocated = 0; QData.out = NULL; EnumWindows(EnumWindowProc, (LPARAM)&QData); b = WriteFileSynch( hQueryPipe, &QData.size, sizeof(QData.size), &cb, 0, &ol ); if ( ! b || sizeof(int) != cb) { TRACE(QUERY, ("Remote: Can't write query length\n")); goto failure; } if (QData.size) { // anything to say? b = WriteFileSynch( hQueryPipe, QData.out, QData.size * sizeof(char), &cb, 0, &ol ); free(QData.out); if ( ! b || QData.size * sizeof(char) != cb) { TRACE(QUERY, ("Remote: Can't write query")); goto failure; } TRACE(QUERY, ("Sent query response\n")); } } FlushFileBuffers(hQueryPipe); failure: DisconnectNamedPipe(hQueryPipe); CloseHandle(hQueryPipe); CloseHandle(ol.hEvent); return 0; } BOOL CALLBACK EnumWindowProc( HWND hWnd, LPARAM lParam ) { #define MAX_TITLELEN 200 QUERY_MESSAGE *pQm; int titleLen; char title[MAX_TITLELEN]; char* tmp; pQm = (QUERY_MESSAGE*)lParam; if(titleLen = GetWindowText(hWnd, title, sizeof(title)/sizeof(title[0]))) { // // search for all windows that are visible // if (strstr(title, "] visible") && strstr(title, "[Remote ")) { if(pQm->size) // if message not empty pQm->out[(pQm->size)++] = '\n'; // overwrite ending null with \n else { pQm->out = (char*)malloc(MAX_TITLELEN); // first allocation if(!pQm->out) { printf("\nOut of memory\n"); return FALSE; } pQm->allocated = MAX_TITLELEN; } // fill the result if((pQm->size + titleLen) >= pQm->allocated) { tmp = (char*)realloc(pQm->out, pQm->allocated + MAX_TITLELEN); if(!tmp) { printf("\nOut of memory\n"); free(pQm->out); pQm->size = 0; return FALSE; } pQm->out = tmp; pQm->allocated += MAX_TITLELEN; } strcpy(pQm->out + pQm->size, title); pQm->size += titleLen; } } return TRUE; #undef MAX_TITLELEN }