436 lines
9.9 KiB
C
436 lines
9.9 KiB
C
|
|
||
|
/******************************************************************************\
|
||
|
* 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 <windows.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <process.h>
|
||
|
#include <io.h>
|
||
|
#include <string.h>
|
||
|
#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
|
||
|
}
|