608 lines
14 KiB
C
608 lines
14 KiB
C
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: dplaysvr.c
|
|
* Content: dplay winsock shared .exe - allows multiple apps to share
|
|
* a single winsock port
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 2/10/97 andyco created it from ddhelp
|
|
* 29-jan-98 sohailm added support for stream enum sessions
|
|
*
|
|
***************************************************************************/
|
|
|
|
#ifdef WINNT
|
|
#ifdef DBG
|
|
#undef DEBUG
|
|
#define DEBUG
|
|
#endif
|
|
#endif
|
|
|
|
#include <windows.h>
|
|
#include "dplaysvr.h"
|
|
#include "newdpf.h"
|
|
#include "memalloc.h"
|
|
#include "dphelp.h"
|
|
|
|
HANDLE hInstApp;
|
|
BOOL bNoCallbacks;
|
|
CRITICAL_SECTION gcsCritSection; // the crit section we take in winmain
|
|
// this is a global so dphelp can take it before
|
|
// forwarding enum requests that come in on its
|
|
// receive thread (manbugs 3907)
|
|
int gnCSCount; // dplaysvr lock count
|
|
|
|
/*
|
|
* Externs
|
|
*/
|
|
extern RECEIVELIST gReceiveList;
|
|
extern FDS gReadfds;
|
|
|
|
|
|
// we watch every dplay process so when it exits we
|
|
// make sure it cleaned up...
|
|
typedef struct _PROCESSDATA
|
|
{
|
|
struct _PROCESSDATA *link;
|
|
DWORD pid;
|
|
} PROCESSDATA, *LPPROCESSDATA;
|
|
|
|
LPPROCESSDATA lpProcessList; // list of all processes that are registered
|
|
// with us
|
|
|
|
/*
|
|
* ThreadProc
|
|
*
|
|
* Open a process and wait for it to terminate
|
|
*/
|
|
DWORD WINAPI ThreadProc( LPVOID *pdata )
|
|
{
|
|
HANDLE hproc;
|
|
DWORD rc;
|
|
LPPROCESSDATA ppd;
|
|
LPPROCESSDATA curr;
|
|
LPPROCESSDATA prev;
|
|
PROCESSDATA pd;
|
|
DPHELPDATA hd;
|
|
|
|
ppd = (LPPROCESSDATA) pdata;
|
|
|
|
/*
|
|
* get a handle to the process that attached to DDRAW
|
|
*/
|
|
DPF( 2, "Watchdog thread started for pid %08lx", ppd->pid );
|
|
|
|
hproc = OpenProcess( PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
|
|
FALSE, ppd->pid );
|
|
if( hproc == NULL )
|
|
{
|
|
DPF( 1, "OpenProcess for %08lx failed!", ppd->pid );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
/*
|
|
* wait for process to die
|
|
*/
|
|
rc = WaitForSingleObject( hproc, INFINITE );
|
|
if( rc == WAIT_FAILED )
|
|
{
|
|
DPF( 1, "Wait for process %08lx failed", ppd->pid );
|
|
CloseHandle( hproc );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
/*
|
|
* remove process from the list of watched processes
|
|
*/
|
|
ENTER_DPLAYSVR();
|
|
pd = *ppd;
|
|
curr = lpProcessList;
|
|
prev = NULL;
|
|
while( curr != NULL )
|
|
{
|
|
if( curr == ppd )
|
|
{
|
|
if( prev == NULL )
|
|
{
|
|
lpProcessList = curr->link;
|
|
}
|
|
else
|
|
{
|
|
prev->link = curr->link;
|
|
}
|
|
DPF( 2, "PID %08lx removed from list", ppd->pid );
|
|
MemFree( curr );
|
|
break;
|
|
}
|
|
prev = curr;
|
|
curr = curr->link;
|
|
}
|
|
|
|
if( bNoCallbacks )
|
|
{
|
|
DPF( 1, "No callbacks allowed: leaving thread early" );
|
|
LEAVE_DPLAYSVR();
|
|
CloseHandle( hproc );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
|
|
// clean up!
|
|
|
|
memset(&hd,0,sizeof(hd));
|
|
hd.pid = pd.pid;
|
|
DPlayHelp_DeleteServer(&hd,TRUE);
|
|
|
|
LEAVE_DPLAYSVR();
|
|
CloseHandle( hproc );
|
|
|
|
ExitThread( 0 );
|
|
|
|
return 0;
|
|
|
|
} /* ThreadProc */
|
|
|
|
/*
|
|
* MainWndProc
|
|
*/
|
|
LONG_PTR __stdcall MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
switch(message)
|
|
{
|
|
case WM_ENDSESSION:
|
|
/*
|
|
* shoot ourselves in the head
|
|
*/
|
|
if( lParam == FALSE )
|
|
{
|
|
DPF( 3, "WM_ENDSESSION" );
|
|
ENTER_DPLAYSVR();
|
|
DPF( 1, "Setting NO CALLBACKS" );
|
|
bNoCallbacks = TRUE;
|
|
LEAVE_DPLAYSVR();
|
|
}
|
|
else
|
|
{
|
|
DPF( 3, "User logging off" );
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
} /* MainWndProc */
|
|
|
|
/*
|
|
* WindowThreadProc
|
|
*/
|
|
void WindowThreadProc( LPVOID pdata )
|
|
{
|
|
static char szClassName[] = "DPlayHelpWndClass";
|
|
WNDCLASS cls;
|
|
MSG msg;
|
|
HWND hwnd;
|
|
|
|
/*
|
|
* build class and create window
|
|
*/
|
|
cls.lpszClassName = szClassName;
|
|
cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
cls.hInstance = hInstApp;
|
|
cls.hIcon = NULL;
|
|
cls.hCursor = NULL;
|
|
cls.lpszMenuName = NULL;
|
|
cls.style = 0;
|
|
cls.lpfnWndProc = (WNDPROC)MainWndProc;
|
|
cls.cbWndExtra = 0;
|
|
cls.cbClsExtra = 0;
|
|
|
|
if( !RegisterClass( &cls ) )
|
|
{
|
|
DPF( 1, "RegisterClass FAILED!" );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
hwnd = CreateWindow( szClassName, szClassName,
|
|
WS_POPUP, 0, 0, 0, 0, NULL, NULL, hInstApp, NULL);
|
|
|
|
if( hwnd == NULL )
|
|
{
|
|
DPF( 1, "No monitor window!" );
|
|
ExitThread( 0 );
|
|
}
|
|
|
|
/*
|
|
* pump the messages
|
|
*/
|
|
while( GetMessage( &msg, NULL, 0, 0 ) )
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessage( &msg );
|
|
}
|
|
DPF( 1, "Exiting WindowThreadProc" );
|
|
ExitThread( 1 );
|
|
|
|
} /* WindowThreadProc */
|
|
|
|
//
|
|
// called by by DPlayHelp_AddServer when we get a new process attached.
|
|
// we wait for the process to go away, and then make sure it cleaned
|
|
// all its registered servers up.
|
|
//
|
|
void WatchNewPid(LPDPHELPDATA phd)
|
|
{
|
|
LPPROCESSDATA ppd;
|
|
BOOL found;
|
|
DWORD tid;
|
|
|
|
DPF( 1, "watching new pid" );
|
|
|
|
ENTER_DPLAYSVR();
|
|
|
|
ppd = lpProcessList;
|
|
found = FALSE;
|
|
while( ppd != NULL )
|
|
{
|
|
if( ppd->pid == phd->pid )
|
|
{
|
|
DPF( 2, "Have thread for process %08lx already", phd->pid );
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
ppd = ppd->link;
|
|
}
|
|
|
|
/*
|
|
* couldn't find anyone waiting on this process, so create
|
|
* a brand spanking new thread
|
|
*/
|
|
if( !found )
|
|
{
|
|
DPF( 2, "Allocating new thread for process %08lx",phd->pid );
|
|
ppd = MemAlloc( sizeof( PROCESSDATA ) );
|
|
if( ppd != NULL )
|
|
{
|
|
HANDLE h;
|
|
|
|
ppd->link = lpProcessList;
|
|
lpProcessList = ppd;
|
|
ppd->pid = phd->pid;
|
|
h = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) ThreadProc,
|
|
(LPVOID)ppd,
|
|
0,
|
|
(LPDWORD)&tid);
|
|
if( h != NULL )
|
|
{
|
|
DPF( 2, "Thread %08lx created",tid);
|
|
CloseHandle( h );
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
DPF( 0, "COULD NOT CREATE HELPER THREAD FOR PID %08lx", phd->pid );
|
|
DebugBreak(); //_asm int 3;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
DPF( 0, "OUT OF MEMORY CREATING HELPER THREAD FOR PID %08lx", phd->pid );
|
|
DebugBreak(); //_asm int 3;
|
|
#endif
|
|
}
|
|
}
|
|
LEAVE_DPLAYSVR();
|
|
|
|
} // WatchNewPid
|
|
|
|
typedef DWORD (WINAPI *PFNREGISTERSERVICE)(DWORD,DWORD);
|
|
// nt's winbase.h doesn't have these constants - we need them
|
|
// so we can compile. taken from \proj\dev\inc\winbase.h
|
|
#ifndef RSP_UNREGISTER_SERVICE
|
|
#define RSP_UNREGISTER_SERVICE 0x00000000
|
|
#endif
|
|
#ifndef RSP_SIMPLE_SERVICE
|
|
#define RSP_SIMPLE_SERVICE 0x00000001
|
|
#endif
|
|
|
|
// on Win95, we want to call RegisterServiceProcess
|
|
// but, it's not available on NT, so we can't import it directly
|
|
// here we try to find it dynamically in kernel32. if we find it,
|
|
// we call it, otherwise we assume we're on NT and it's not avaible
|
|
void MakeMeService()
|
|
{
|
|
HANDLE hLib;
|
|
PFNREGISTERSERVICE pfnRegisterServiceProcess;
|
|
|
|
hLib = LoadLibrary("kernel32.dll");
|
|
if (!hLib)
|
|
{
|
|
// wacky!
|
|
DPF(1,"could not load library kernel32 to register service proc");
|
|
return;
|
|
}
|
|
|
|
pfnRegisterServiceProcess = (PFNREGISTERSERVICE)GetProcAddress(hLib,"RegisterServiceProcess");
|
|
if (!pfnRegisterServiceProcess)
|
|
{
|
|
// this is expected on NT
|
|
DPF(3,"could not register service process - expected on NT");
|
|
FreeLibrary(hLib);
|
|
return ;
|
|
}
|
|
|
|
pfnRegisterServiceProcess( 0, RSP_SIMPLE_SERVICE );
|
|
FreeLibrary(hLib);
|
|
|
|
return ;
|
|
} // MakeMeService
|
|
|
|
// on Win95, we want to call RegisterServiceProcess to Unregister
|
|
// (see MakeMeService)
|
|
void StopServiceProcess()
|
|
{
|
|
HANDLE hLib;
|
|
PFNREGISTERSERVICE pfnRegisterServiceProcess;
|
|
|
|
hLib = LoadLibrary("kernel32.dll");
|
|
if (!hLib)
|
|
{
|
|
// wacky!
|
|
DPF(1,"could not load library kernel32 to register service proc");
|
|
return;
|
|
}
|
|
|
|
pfnRegisterServiceProcess = (PFNREGISTERSERVICE)GetProcAddress(hLib,"RegisterServiceProcess");
|
|
if (!pfnRegisterServiceProcess)
|
|
{
|
|
// this is expected on NT
|
|
DPF(3,"could not unregister service process - not avail - not tragic");
|
|
FreeLibrary(hLib);
|
|
return ;
|
|
}
|
|
|
|
// unregistered!
|
|
pfnRegisterServiceProcess( 0, RSP_UNREGISTER_SERVICE );
|
|
FreeLibrary(hLib);
|
|
|
|
return ;
|
|
|
|
} // StopServiceProcess
|
|
|
|
/*
|
|
* WinMain
|
|
*/
|
|
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
DWORD tid;
|
|
DWORD rc;
|
|
HANDLE hstartevent;
|
|
HANDLE hstartupevent;
|
|
HANDLE hmutex;
|
|
HANDLE hackevent;
|
|
LPDPHELPDATA phd;
|
|
HANDLE hsharedmem;
|
|
HANDLE h;
|
|
char szSystemDir[1024];
|
|
|
|
/*
|
|
* Set our working directory to the system directory.
|
|
* This prevents us from holding network connections open
|
|
* forever if the first DirectDraw app that we run is across
|
|
* a network connection.
|
|
*/
|
|
GetSystemDirectory(szSystemDir, sizeof(szSystemDir));
|
|
SetCurrentDirectory(szSystemDir);
|
|
|
|
// try to register ourselves as a service so user can't see us
|
|
// in task list
|
|
MakeMeService();
|
|
|
|
#if 0
|
|
|
|
// andyco - not sure if we need this...
|
|
|
|
/*
|
|
* We must guarantee that DPHELP unloads after the last ddraw app,
|
|
* since ctrl-alt-del may have happened while an app held the ddraw
|
|
* lock, and DPHELP needs to clean up orphaned cheap ddraw mutex
|
|
* locks.
|
|
*/
|
|
if ( ! SetProcessShutdownParameters(0x100,SHUTDOWN_NORETRY) )
|
|
{
|
|
DPF(0,"dplaysvr could not set itself to shutdown last!");
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
hInstApp = hInstance;
|
|
|
|
/*
|
|
* create startup event
|
|
*/
|
|
hstartupevent = CreateEvent( NULL, TRUE, FALSE, DPHELP_STARTUP_EVENT_NAME );
|
|
|
|
DPFINIT();
|
|
DPF( 2, "*** dplaysvr STARTED, PID=%08lx ***", GetCurrentProcessId() );
|
|
|
|
if( !MemInit() )
|
|
{
|
|
DPF( 1, "Could not init memory manager" );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* create shared memory area
|
|
*/
|
|
hsharedmem = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,
|
|
PAGE_READWRITE, 0, sizeof( DPHELPDATA ),
|
|
DPHELP_SHARED_NAME );
|
|
if( hsharedmem == NULL )
|
|
{
|
|
DPF( 1, "Could not create file mapping!" );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* create mutex for people who want to use the shared memory area
|
|
*/
|
|
hmutex = CreateMutex( NULL, FALSE, DPHELP_MUTEX_NAME );
|
|
if( hmutex == NULL )
|
|
{
|
|
DPF( 1, "Could not create mutex " DPHELP_MUTEX_NAME );
|
|
CloseHandle( hsharedmem );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* create events
|
|
*/
|
|
hstartevent = CreateEvent( NULL, FALSE, FALSE, DPHELP_EVENT_NAME );
|
|
if( hstartevent == NULL )
|
|
{
|
|
DPF( 1, "Could not create event " DPHELP_EVENT_NAME );
|
|
CloseHandle( hmutex );
|
|
CloseHandle( hsharedmem );
|
|
return 0;
|
|
}
|
|
hackevent = CreateEvent( NULL, FALSE, FALSE, DPHELP_ACK_EVENT_NAME );
|
|
if( hackevent == NULL )
|
|
{
|
|
DPF( 1, "Could not create event " DPHELP_ACK_EVENT_NAME );
|
|
CloseHandle( hmutex );
|
|
CloseHandle( hsharedmem );
|
|
CloseHandle( hstartevent );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Create window so we can get messages
|
|
*/
|
|
h = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) WindowThreadProc,
|
|
NULL,
|
|
0,
|
|
(LPDWORD)&tid );
|
|
if( h == NULL )
|
|
{
|
|
DPF( 1, "Create of WindowThreadProc FAILED!" );
|
|
CloseHandle( hackevent );
|
|
CloseHandle( hmutex );
|
|
CloseHandle( hsharedmem );
|
|
CloseHandle( hstartevent );
|
|
return 0;
|
|
}
|
|
CloseHandle( h );
|
|
|
|
/*
|
|
* serialize access to us
|
|
*/
|
|
INIT_DPLAYSVR_CSECT();
|
|
|
|
/*
|
|
* let invoker and anyone else who comes along know we exist
|
|
*/
|
|
SetEvent( hstartupevent );
|
|
|
|
/*
|
|
* loop forever, processing requests
|
|
*/
|
|
while( 1 )
|
|
{
|
|
/*
|
|
* wait to be notified of a request
|
|
*/
|
|
DPF( 1, "Waiting for next request" );
|
|
rc = WaitForSingleObject( hstartevent, INFINITE );
|
|
if( rc == WAIT_FAILED )
|
|
{
|
|
DPF( 1, "Wait FAILED!!!" );
|
|
continue;
|
|
}
|
|
|
|
ENTER_DPLAYSVR();
|
|
phd = (LPDPHELPDATA) MapViewOfFile( hsharedmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
|
|
if( phd == NULL )
|
|
{
|
|
DPF( 1, "Could not create view of file!" );
|
|
LEAVE_DPLAYSVR();
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* find out what we need to do
|
|
*/
|
|
switch( phd->req )
|
|
{
|
|
case DPHELPREQ_SUICIDE:
|
|
DPF( 1, "DPHELPREQ_SUICIDE" );
|
|
|
|
DPlayHelp_FreeServerList();
|
|
|
|
SetEvent( hackevent );
|
|
CloseHandle( hmutex );
|
|
UnmapViewOfFile( phd );
|
|
CloseHandle( hsharedmem );
|
|
CloseHandle( hstartevent );
|
|
if (gReceiveList.pConnection)
|
|
{
|
|
MemFree(gReceiveList.pConnection);
|
|
}
|
|
if (gReadfds.pfdbigset)
|
|
{
|
|
MemFree(gReadfds.pfdbigset);
|
|
}
|
|
FINI_DPLAYSVR_CSECT();
|
|
|
|
#ifdef DEBUG
|
|
MemState();
|
|
#endif
|
|
DPF( 3, "Good Night Gracie" );
|
|
TerminateProcess( GetCurrentProcess(), 0 );
|
|
break;
|
|
|
|
case DPHELPREQ_RETURNHELPERPID:
|
|
|
|
DPF( 2, "DDHELPREQ_RETURNHELPERPID" );
|
|
phd->pid = GetCurrentProcessId();
|
|
break;
|
|
|
|
|
|
case DPHELPREQ_DPLAYADDSERVER:
|
|
|
|
DPF( 2, "DPHELPREQ_DPLAYADDSERVER" );
|
|
phd->hr = DPlayHelp_AddServer(phd);
|
|
break;
|
|
|
|
case DPHELPREQ_DPLAYDELETESERVER:
|
|
|
|
DPF( 2, "DPHELPREQ_DPLAYDELETESERVER" );
|
|
DPlayHelp_DeleteServer(phd,FALSE);
|
|
break;
|
|
|
|
default:
|
|
DPF( 1, "helper - Unknown Request???" );
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* let caller know we've got the news
|
|
*/
|
|
UnmapViewOfFile( phd );
|
|
SetEvent( hackevent );
|
|
LEAVE_DPLAYSVR();
|
|
}
|
|
|
|
StopServiceProcess();
|
|
|
|
} /* WinMain */
|