#define CHANNELAPI	__declspec(dllexport)

#include <windows.h>
#include <shlobj.h>
#include <winbase.h>

#include "channel.h"
#include "..\Utilities\Util.h"
#include "..\DynamicLink\utilities.h"

#ifdef STATIC_CLIENT_CHANNEL
void InitializeStaticClient();
#endif

#ifdef CLIENT_DLL

#define SERVER_KILLED	0
#define SERVER_READY	1
#define CLIENT_OK		2

static HANDLE hServerKilledOrReady[2] = { NULL, NULL };
static HANDLE hClientReady = NULL;

#else

#define CLIENT_KILLED	0
#define CLIENT_READY	1
#define SERVER_OK		2

static HANDLE hClientKilledOrReady[2] = { NULL, NULL };
static HANDLE hServerReady = NULL;

#endif

#ifdef CLIENT_DLL


HANDLE GetHandleToServer() {
#ifndef STATIC_CLIENT_CHANNEL
	InitClientDLL();
#else
	InitializeStaticClient();
#endif

	return hServerKilledOrReady[SERVER_KILLED];
}
 
void SetHandleToServer(HANDLE hServer) {
	hServerKilledOrReady[SERVER_KILLED] = hServer;
}

static char *Buffer = NULL;
static DWORD BufferSize;
static BufferInfo LargeReceiveBufferInfo;
static	BufferInfo LargeSendBufferInfo;

char *
GetSendBuffer (int size, int smallBufferSize, char *smallBuffer, HANDLE hReceivingProcess)
{
	if( size > smallBufferSize) {
		char *dummy;
		BOOL ok;
		HANDLE hSendingProcess, hReceivingMapping;

		CreateBuffer(NULL, size, FALSE, &LargeSendBufferInfo);
		ok = DuplicateHandle(GetCurrentProcess (), LargeSendBufferInfo.hMapping,
								hReceivingProcess, &hReceivingMapping,
								NULL, FALSE, DUPLICATE_SAME_ACCESS);

		if( !ok ) {
			error();
			msg( "GetSendBuffer: could not dup handle" );
			ExitProcess(-1);
		}
		
		smallBuffer[MESSAGE_TYPE] = LARGE_MESSAGE;
		*((DWORD *) (smallBuffer+SIZE_OF_MESSAGE)) = size;
		*((HANDLE *) (smallBuffer+DATA_START)) = hReceivingMapping;

		return LargeSendBufferInfo.hView;
	} else
		return smallBuffer;
}

void
ReleaseSendBuffer (char *buffer, char *smallBuffer)
{
	if (buffer == LargeSendBufferInfo.hView)
	{	
		CloseBuffer(&LargeSendBufferInfo);
		LargeSendBufferInfo.hMapping = NULL;
		LargeSendBufferInfo.hView = NULL;
	} else if (buffer != smallBuffer) {
		msg("ReleaseSendBuffer: unrecognised buffer");
		ExitProcess(-1);
	}
}

char *
GetReceiveBuffer (char *smallBuffer)
{
	if( smallBuffer[MESSAGE_TYPE] == LARGE_MESSAGE ) {
		LargeReceiveBufferInfo.hMapping = *((HANDLE *) (smallBuffer+DATA_START));
		LargeReceiveBufferInfo.hView = (char *) MapViewOfFile( LargeReceiveBufferInfo.hMapping,
											FILE_MAP_READ, 0, 0, *((DWORD *) (smallBuffer+SIZE_OF_MESSAGE)));

		if( LargeReceiveBufferInfo.hView == NULL ) {
			error();
			msg ( "GetReceiveBuffer: could not open file mapping" );
			ExitProcess(-1);
		}

		return LargeReceiveBufferInfo.hView;
	} else
		return smallBuffer;
}

void
ReleaseReceiveBuffer (char *buffer, char *smallBuffer)
{
	if (buffer == LargeReceiveBufferInfo.hView)
	{	
		UnmapViewOfFile(LargeReceiveBufferInfo.hView);
		CloseHandle (LargeReceiveBufferInfo.hMapping);
		LargeReceiveBufferInfo.hView = NULL;
		LargeReceiveBufferInfo.hMapping = NULL;
	} else if (buffer != smallBuffer) {
		msg("ReleaseReceiveBuffer: unrecognised buffer");
		ExitProcess(-1);
	}
}
/*
#ifdef STATIC_CLIENT_CHANNEL
	static int first_time = 0;
#endif
*/

CLEAN_STRING DoReqS(CLEAN_STRING s)
{
	/* An almost exact copy of DoReq but returns a string */
	int code_size = 0;
	int data_size = 0;
	int code = NULL;
	int data = NULL;
	int label = 0;
	int n_libraries, s_buffer;

	BufferInfo server_info;
	BufferInfo client_info;
	char *hClientView;
	char *hServerView;
	char *buffer;
	HINSTANCE library;
	int i;
	char bs[100];
	HANDLE h;
	static CLEAN_STRING clean_string = NULL;
	int length;

	if( clean_string != NULL ) {
		rfree(clean_string);
		clean_string = NULL;
	}

#ifdef STATIC_CLIENT_CHANNEL
//	if( first_time == 0 ) {
		InitializeStaticClient();
//		first_time = 1;
//		i = 1;
//	} 
#endif

	buffer	= GetSendBuffer (DATA_START+sizeof(DWORD)+s+1, BufferSize, Buffer, hServerKilledOrReady[SERVER_KILLED]);
	// message header
	buffer [MESSAGE_TYPE] = (char) ADDRESS_REQUEST;
	*((DWORD *) (buffer+SIZE_OF_MESSAGE)) = s->length;

	*((DWORD *) (buffer+DATA_START)) = GetCurrentProcessId();
	
	// Copy module/label-string
	rsncopy (buffer + DATA_START + sizeof(DWORD), s->characters, s->length);
	buffer[(s->length)+ DATA_START + sizeof(DWORD)] = 0; /* why the '\0' termination ? */

	Send();
	ReleaseSendBuffer (buffer, Buffer);

	// Receive code and data sizes 
	if( (Receive()) == SERVER_KILLED) {
		ExitProcess(-1);
	}

	while (Buffer[MESSAGE_TYPE]==ADDRESS_UNKNOWN){		
		// Allocate code
		code_size = *((int *) (Buffer+DATA_START));
		if (code_size!=0){
			code = (int *) VirtualAlloc (NULL, code_size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE );
			if (!code){
				error();
				msg ("DoReq 1");
				ExitProcess (-1);
			}
	
			*((int *) (Buffer+DATA_START)) = code;
		}

		// Allocate data
		data_size = *((int *) (Buffer+DATA_START+sizeof(int)));
		if (data_size!=0){
			data = (int *) VirtualAlloc (NULL, data_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
			if (!data){
				error();
				ExitProcess (-1);
			}

			*((int *) (Buffer+DATA_START+sizeof(int))) = data;
		}

		Send();

		// Receive a label or a request to return the base
		// addresses of used libraries
		if( (Receive()) == SERVER_KILLED) {
			msg( "sever killed");
			ExitProcess(-1);
		}

		// Need base addresses of libraries
		if( Buffer[MESSAGE_TYPE] == NEED_BASE_OF_LIBRARIES ) {
			n_libraries = *((int *) (Buffer+DATA_START));
			s_buffer = *((int *) (Buffer+DATA_START+sizeof(int)));

			// Open the server buffer containing the names of the
			// needed libraries

			CreateBuffer( "ServerLibraryBuffer", s_buffer, TRUE, &server_info);
			hServerView = server_info.hView;

			// Allocate a client buffer to contain the base addresses
			// of all libraries
			CreateBuffer( "ClientLibraryBuffer", n_libraries * sizeof(HINSTANCE), FALSE, &client_info);
			hClientView = client_info.hView;

			for (i = 0; i < n_libraries; i++ ){
				library = LoadLibrary(hServerView);
#ifdef DEBUG
				msg( hServerView );
#endif
				if( library == NULL ) {
					error();
//					msg(  hServerLibraryBufferView);
					msg( "<channel.c>" );
					ExitProcess(-1);
				}

				*((int *) (hClientView)) = library;

				hServerView += rstrlen(hServerView) + 1;
				hClientView += sizeof(HINSTANCE); 
			}

			Send();

			CloseBuffer(&server_info);

			/* Receive label */
			Receive();

			CloseBuffer(&client_info);
		} 
	}

	buffer	= GetReceiveBuffer (Buffer);

	if( buffer[MESSAGE_TYPE] == ADDRESS_KNOWN ) {
		length = *((DWORD *) (buffer+SIZE_OF_MESSAGE));
		clean_string = (CLEAN_STRING) rmalloc (sizeof(int) + length);
		clean_string->length = length;

		rsncopy(clean_string->characters, buffer + DATA_START, length);

		ReleaseReceiveBuffer (buffer, Buffer);

		return( clean_string );

	} else {
		ExitProcess(-1);
	}

	return( label );
}

#else
void SetHandlesToClient(HANDLE hserver_ready, 
						HANDLE hclient_killed,
						HANDLE hclient_ready) {

	hServerReady = hserver_ready;
	hClientKilledOrReady[CLIENT_KILLED] = hclient_killed;
	hClientKilledOrReady[CLIENT_READY] = hclient_ready;
}
#endif

#ifdef CLIENT_DLL

#ifndef STATIC_CLIENT_CHANNEL

void InitClientDLL() {
	LPTSTR cmdline;
	DWORD dwServerId;
	HANDLE hFileMapping;

	HANDLE hFileMapping2;
	BOOL ok;
	int i;
	char	buffer[100];
	DWORD	result;
	char	*charp;
	static int first_time = 1;

	if( first_time ) {
		first_time = 0;

	// dwServerId
		result = GetEnvironmentVariable("dwServerId",&buffer,100);
		if( !result ) {
			msg( "DllMain: ClientChannel.dll  could not find environment variable1!" );
			charp = GetEnvironmentStrings();
			msg( charp);

			
			ExitProcess(-1);
		}
		result = sscanf( buffer, "%u", &dwServerId);
		if( !result ) {
			msg ("conversion failed");
			ExitProcess(-1);
		}

		// hServerReady
		result = GetEnvironmentVariable("hServerReady",&buffer,100);
		if( !result ) {
			msg( "DllMain: ClientChannel.dll could not find environment variabale2 " );
			ExitProcess(-1);
		}
		sscanf( buffer, "%u", &(hServerKilledOrReady[SERVER_READY]));


		// hClientReady
		result = GetEnvironmentVariable("hClientReady",&buffer,100);
		if( !result ) {
			msg( "DllMain: ClientChannel.dll could not find environment variabale3" );
			ExitProcess(-1);
		}
		sscanf( buffer, "%u", &hClientReady);

		// hFileMapping
		result = GetEnvironmentVariable("hFileMapping",&buffer,100);
		if( !result ) {
			msg( "DllMain: ClientChannel.dll could not find environment variabale4" );
			ExitProcess(-1);
		}
		sscanf( buffer, "%u", &hFileMapping);

		// MESSAGE_SIZE
		result = GetEnvironmentVariable("MESSAGE_SIZE",&buffer,100);
		if( !result ) {
			msg( "DllMain: ClientChannel.dll could not find environment variabale6" );
			ExitProcess(-1);
		}
		sscanf( buffer, "%u", &BufferSize);

		Buffer = (char *) MapViewOfFile( hFileMapping, FILE_MAP_WRITE, 0, 0, BufferSize);
		if( Buffer == NULL ) {
			error();
			msg ( "Channel.c" );
			ExitProcess(-1);
		}

		hServerKilledOrReady[SERVER_KILLED] = OpenProcess(STANDARD_RIGHTS_REQUIRED | PROCESS_ALL_ACCESS, FALSE, dwServerId);
		if( hServerKilledOrReady[SERVER_KILLED] == NULL ) {		
			error();
			msg( "OK" );
			ExitProcess(-1);
		}

		CloseHandle( hFileMapping );
	} //
} 
#endif // STATIC_CLIENT_CHANNEL

#endif // CLIENT_DLL

void CloseChannel() {
}

int Send() {
	DWORD dwObject;

#ifdef CLIENT_DLL
	dwObject = WaitForSingleObject(hServerKilledOrReady[SERVER_KILLED],0);
#else
	dwObject = WaitForSingleObject(hClientKilledOrReady[CLIENT_KILLED], 0);
#endif

	if( dwObject == WAIT_OBJECT_0 )
#ifdef CLIENT_DLL
		return SERVER_KILLED;
#else
		return CLIENT_KILLED;
#endif
	else {
#ifdef CLIENT_DLL
	SetEvent(hClientReady);
	return( CLIENT_OK );
#else
	SetEvent(hServerReady);
	return( SERVER_OK );
#endif
	}
}
	
int Receive() {
	DWORD dwObject;

#ifdef CLIENT_DLL
	if( hServerKilledOrReady[SERVER_KILLED] == NULL )
		msg( "CLIENT: server not init");
#else
	if( hClientKilledOrReady[CLIENT_KILLED] == NULL )
		msg( "SERVER: client not init");
#endif


#ifdef CLIENT_DLL
	dwObject = WaitForMultipleObjects( 2, hServerKilledOrReady, FALSE, INFINITE);
#else
	dwObject = WaitForMultipleObjects( 2, hClientKilledOrReady, FALSE, INFINITE);
#endif

	if( dwObject == WAIT_FAILED ) {
#ifdef CLIENT_DLL
		error();
		msg( "CLIENT: wait failed; handle not set");

#else
		msg( "SERVER: wait failed; handle not set");
#endif
	}

	return( dwObject );

}

/* --------------------------------------------------------------
** Named buffers
*/
void CloseBuffer(BufferInfo *info) {
	UnmapViewOfFile(info->hView);
	CloseHandle(info->hMapping);
}

void CreateBuffer(char *name, int size, BOOL open_buffer, BufferInfo *info) {
	char s[100];

	/*
	** Create or open a buffer
	*/
	if( open_buffer ) {

		(info->hMapping) = OpenFileMapping(FILE_MAP_WRITE, FALSE, name );
		if( (info->hMapping) == NULL ) {
			error();
			msg( "CreateBuffer: error opening file mapping ");
			ExitProcess(-1);
		}
	}
	else {

		(info->hMapping) = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,size,name);
		if ((info->hMapping) == NULL) { 
			error();

#ifdef CLIENT_DLL
			msg( "Client CreateBuffer: hLibraryBufferMapping" );
			sprintf( s, "Was opening: %s ", name );
			msg( s );
#else
			msg( "Client CreateBuffer: hLibraryBufferMapping" );
			msg( "hier" );
#endif

			ExitProcess(-1);
		}
	}

	/*
	** Create a view on the buffer
	*/
	(info->hView) = (char *) MapViewOfFile(info->hMapping, FILE_MAP_WRITE, 0, 0, size);
	if ((info->hView) == NULL) {
		error(); 
		sprintf( s, "CreateBuffer: hLibraryBufferView '%d' '%s'", size, name );
		msg( s  );
		CloseHandle(info->hMapping);
		ExitProcess(-1);
	}
}

// 
char *GetPathOfDynamicLinker() {

	LONG lResult;
	HKEY hkResult;
	DWORD dwLength;
	DWORD dwType;
	int i;

	static char szDynamicLinker[MAX_PATH+1];

	lResult = RegOpenKeyEx( 
		HKEY_CLASSES_ROOT,
		"prjfile\\Shell\\dynamic link\\command",
		NULL,
		KEY_ALL_ACCESS,
		&hkResult);
	if( lResult != ERROR_SUCCESS)
		return( NULL );
	
	dwLength = MAX_PATH+1;
	RegQueryValue( 
		hkResult,
		NULL,
		szDynamicLinker,
		&dwLength);
	if( lResult != ERROR_SUCCESS)
		return( NULL );
	
	RegCloseKey( hkResult );

	return( szDynamicLinker );
}

CLEAN_STRING GetDynamicLinkerPath() {
	char *p;
	int length;

	static CLEAN_STRING r = NULL;

	if( r )
		rfree( r ); 

	// get dynamic linker path
	p = GetPathOfDynamicLinker();

	// allocate memory
	length = rstrlen(p);
	r = (CLEAN_STRING) rmalloc (sizeof (int) + length);

	// copy path to clean string
	rsncopy(r->characters, p, length);
	
	// set length
	r->length = length;

	return( r );
}

/*
** ------------------------------------------------------------------
** STATIC CLIENT CHANNEL
**
** If an CLEAN application is eagerly linked, the named channel is
** used to communicate with the server. The server responds by 
** sending synchronization objects etc.
*/

#ifdef STATIC_CLIENT_CHANNEL
#include <winreg.h>
#include "..\DynamicLink\serverblock.h"
#include "..\DynamicLink\clean_bool.h"

static char *replaced_command_line = NULL;

BOOL replace_command_line(CLEAN_STRING s) {

//	__asm int 3

	replaced_command_line = (char *) rmalloc (s->length + 1);

	rsncopy(replaced_command_line,s->characters,s->length);
	
	replaced_command_line[s->length] = '\0';

	return( CLEAN_TRUE );
}

//if( NewKey ( "prjfile\\shell\\dynamic link\\command", commandline, REG_EXPAND_SZ ) == FALSE )
BOOL CleanNewKey(CLEAN_STRING key,CLEAN_STRING value) {
	// key, value are null-terminated Clean strings

	return( NewKey(key->characters, value->characters, REG_EXPAND_SZ) ? CLEAN_TRUE : CLEAN_FALSE );
}

BOOL NewKey(LPCTSTR keypath, LPCTSTR value, DWORD dwType ) {

	HKEY hkResult;
	DWORD dwDisposition;
	LONG lResult;

	// .dlc
	lResult = RegCreateKeyEx(
		HKEY_CLASSES_ROOT,
		keypath,
		0,
		"SZ_STRING_EXPAND",
		REG_OPTION_NON_VOLATILE,
		KEY_ALL_ACCESS, 
		NULL,
		&hkResult,
		&dwDisposition);

	if( lResult != ERROR_SUCCESS )
		return( FALSE );

	//
	lResult = RegSetValueEx( 
		hkResult, 
		NULL,
		0,
		REG_SZ, //dwType,
		value,
		strlen(value) + 1);

	if( lResult != ERROR_SUCCESS ) {
		RegCloseKey( hkResult );
		return( FALSE );
	}

	lResult = RegCloseKey( hkResult );
	if( lResult != ERROR_SUCCESS ) {
		return( FALSE );
	}

	return( TRUE );
}

char *extract_dlink_path(char *path) {

	static char buffer[MAX_PATH];
	int i;
	int pclose;

	if( path == NULL )
		return( NULL );

	if( path[0] == '\0' )
		return( NULL );

	i = 1;
	while( path[i] != '\0' && path[i] != '\"' )
		buffer[i-1] = path[i++];

	if( path[i] == '\0' )
		return( NULL );

	buffer[i-1] = '\0';
	return( buffer );
	msg ( "aaa1");
}

void my_error() {
	LPVOID lpMsgBuf;
		
	FormatMessage( 
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,    NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR) &lpMsgBuf,    0,    NULL );// Display the string.

	MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
	LocalFree( lpMsgBuf );
}




/*
** StartDynamicLinker
** If the DynamicLinker has already been started, the commandline of
** this instantion is sent to the first instance.
*/
void StartDynamicLinker() {

	HANDLE hObjects[2];
	DWORD dwResult;

	// Path from registry to dynamic linker
	char *szDynamicLinker;

	// Needed for dynamic linker start
	PROCESS_INFORMATION pi;
	DWORD dwExitCode;
	STARTUPINFO si;
	BOOL fSuccess;
	char commandline[MAX_PATH*2];

	//
	HANDLE hFileMapping;
	HANDLE hGlobalServerReady;
	DWORD dwServerId;

	//
	HANDLE hServerReady_new;
	HANDLE hClientReady_new;
	DWORD length;

	HANDLE hFileMapping_new;


	// Temp
	char *s;
	char executable[MAX_PATH];

//	msg( "StartDynamicLinker" );

	// 	szDynamicLinker = SelectDynamicLinkerFolder();
	//			__asm int 3


	
	hFileMapping = OpenFileMapping( FILE_MAP_WRITE, FALSE, GLOBAL_BUFFER_NAME );
	if( hFileMapping == NULL ) {
		szDynamicLinker = extract_dlink_path( GetPathOfDynamicLinker() );

		ZeroMemory(&si, sizeof(si));
		si.cb = sizeof(si);

		fSuccess = 0;
		if( szDynamicLinker != NULL ) {
			// first try registry path
			sprintf( commandline, "\"%s\" /W", szDynamicLinker );

			fSuccess = CreateProcess( 
				szDynamicLinker,
				commandline ,	
				NULL,				
				NULL,			
				FALSE,				
				0,				
				NULL,				
				NULL, 
				&si,				
				&pi);
		}

		if( !fSuccess ) {
			// ask user

			szDynamicLinker = SelectDynamicLinkerFolder();


			if( szDynamicLinker == NULL )
				ExitProcess(-1);

			sprintf( executable, "%s\\DynamicLinker.exe", szDynamicLinker );
			sprintf( commandline, "\"%s\" /W", szDynamicLinker );

			fSuccess = CreateProcess( 
				executable,
				commandline ,	
				NULL,				
				NULL,			
				FALSE,				
				0,				
				NULL,				
				NULL, 
				&si,				
				&pi);
			if( !fSuccess ) {
				msg( "StaticClientChannel: internal error" );
				ExitProcess(-1);
			}
				// Dynamic start

			sprintf( commandline, "\"%s\" /S \"%%1\"", executable );
			if( NewKey ( "prjfile\\shell\\dynamic link\\command", commandline, REG_EXPAND_SZ ) == FALSE )

			//			if( NewKey ( "prjfile\\shell\\Lazy start\\command", commandline, REG_EXPAND_SZ ) == FALSE )
				msg( "een probleem" );			
		};


		/*
		** Process created 
		*/
		CloseHandle(pi.hThread);
//		CloseHandle(pi.hProcess);


		// wait for dynamic linker to be ready to communicate
		hObjects[0] = pi.hProcess;
		hObjects[1] = NULL;


		while( !((dwResult = WaitForMultipleObjects( 
				(hObjects[1] == NULL) ? 1 : 2, 
				hObjects, 
				FALSE, 
				0)) < 2)
			) {

			hObjects[1] = OpenEvent( EVENT_ALL_ACCESS , FALSE, GLOBAL_SERVER_READY_NAME );
		};
		CloseHandle(pi.hProcess);


		if( (dwResult - WAIT_OBJECT_0) == 0) {
			msg( "StaticClientChannel: dynamic linker killed" );
			ExitProcess(-1);
		} else
			hGlobalServerReady = hObjects[1];
		
		/*
		** It is guaranteed that the hGlobalServerReady--event only 
		** becomes signaled AFTER the buffer has been allocated and
		** initialized
		*/
		hFileMapping = OpenFileMapping( FILE_MAP_WRITE, FALSE, GLOBAL_BUFFER_NAME );
		if( hFileMapping == NULL ) {
			msg( "StartDynamicLinker: could not open mapping" );
			ExitProcess(-1);
		}		
	} else {
	//	my_error();

		hGlobalServerReady = OpenEvent( EVENT_ALL_ACCESS , FALSE, GLOBAL_SERVER_READY_NAME );
		if( hGlobalServerReady == NULL ) {
			msg( "!!!!StartDynamicLinker: could not open global server ready-event" );
			ExitProcess(-1);
		}
		WaitForSingleObject( hGlobalServerReady, INFINITE );
	}

	/*
	** The hGlobalServerReady was ready and the buffer has been opened.
	*/
	Buffer = (char *) MapViewOfFile( hFileMapping, FILE_MAP_WRITE, 0, 0, MESSAGE_SIZE);
	if( Buffer == NULL ) {
		error();
		msg ( "StartDynamicLinker: could not open file mapping" );
		ExitProcess(-1);
	}

	dwServerId = *((DWORD *) (Buffer+GLOBAL_BUFFER_SERVER_ID));
	hServerKilledOrReady[SERVER_KILLED] = OpenProcess(STANDARD_RIGHTS_REQUIRED | PROCESS_ALL_ACCESS, FALSE, dwServerId);
	if( hServerKilledOrReady[SERVER_KILLED] == NULL ) {		
		error();
		msg( "StartDynamicLinker: could not open process handle of server" );
			ExitProcess(-1);
		}

	hServerKilledOrReady[SERVER_READY] = OpenEvent( EVENT_ALL_ACCESS , FALSE, LOCAL_SERVER_READY_NAME );
	if( hServerKilledOrReady[SERVER_READY] == NULL ) {
		msg( "StartDynamicLinker: could not open lobal server ready-event" );
		ExitProcess(-1);
	} 

	hClientReady = OpenEvent( EVENT_ALL_ACCESS, FALSE, LOCAL_CLIENT_READY_NAME );
	if( hClientReady == NULL ) {
		msg( "StartDynamicLinker: could not open local client ready--event" );
		ExitProcess(-1);
	}

	// Protocol
	// AddAndInit <command_line>
	//
	// layout
	// GLOBAL_BUFFER_START		Contents
	// + 0						UNKNOWN_CLIENT or CLIENT_ID
	// + 4						AddAndInt\ncommand_line\n\n
	*((DWORD *) (Buffer+GLOBAL_BUFFER_START)) = GetCurrentProcessId();

//	__asm int 3
	sprintf( Buffer + sizeof(DWORD) + GLOBAL_BUFFER_START, "AddAndInit\n%s\n%s\n\n", replaced_command_line ? replaced_command_line : GetCommandLine(), replaced_command_line ? "T" : "F");

	Send(); 

	Receive();

	dwServerId = *((DWORD *) (Buffer+GLOBAL_BUFFER_START));
	hServerReady_new = *((HANDLE *) (Buffer+ GLOBAL_BUFFER_START + sizeof(DWORD) ));
	hClientReady_new = *((HANDLE *) (Buffer+ GLOBAL_BUFFER_START + sizeof(DWORD) + sizeof(HANDLE) ));
	hFileMapping_new = *((HANDLE *) (Buffer+ GLOBAL_BUFFER_START + sizeof(DWORD) + 2 * sizeof(HANDLE) ));
	length			 = *((DWORD *) (Buffer+ GLOBAL_BUFFER_START + sizeof(DWORD) + 3 * sizeof(HANDLE) ));

	// Signal server that buffer contents is processed
	Send();
	
	Receive(); //make hClientReady signaled, hServerReady unsignaled

	/*
	** Free resources
	*/
	CloseHandle( hFileMapping );
	CloseHandle( hGlobalServerReady );
	CloseHandle( hServerKilledOrReady[SERVER_KILLED] );
	CloseHandle( hServerKilledOrReady[SERVER_READY] );
	CloseHandle( hClientReady );
	UnmapViewOfFile( Buffer );

	/*
	** Initialize the channel using the received objects
	*/
	hServerKilledOrReady[SERVER_READY] = hServerReady_new;
	hClientReady = hClientReady_new;

	Buffer = (char *) MapViewOfFile( hFileMapping_new, FILE_MAP_WRITE, 0, 0, length);
	if( Buffer == NULL ) {
		error();
		msg ( "Channel.c" );
		ExitProcess(-1);
	}

	hServerKilledOrReady[SERVER_KILLED] = OpenProcess(STANDARD_RIGHTS_REQUIRED | PROCESS_ALL_ACCESS, FALSE, dwServerId);
	if( hServerKilledOrReady[SERVER_KILLED] == NULL ) {		
		error();
		msg( "OK" );
		ExitProcess(-1);
	}

	CloseHandle( hFileMapping_new );

}

void InitializeStaticClient() {

	static int first_time = 1;

//	__asm int 3

	if( first_time ) {
		first_time = 0;
		StartDynamicLinker();
	}
}


#endif
