#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

static HANDLE hMsgBufferMapping = NULL;
static char *hMsgBufferView = NULL;

#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 *b = NULL;
/*
#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;

#ifdef CREATE_BUFFER2
	BufferInfo server_info;
	BufferInfo client_info;
#else
	char *hServerLibraryBufferView = NULL;
	char *hClientLibraryBufferView = NULL;
#endif
	char *hClientView;
	char *hServerView;
	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;
	}

//	_asm int 3

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

//	__asm int 3


	// message header
	b[MESSAGE_TYPE] = (char) ADDRESS_REQUEST;
	*((DWORD *) (b+SIZE_OF_MESSAGE)) = s->length;

	*((DWORD *) (b+DATA_START)) = GetCurrentProcessId();
	
	// Copy module/label-string
	rsncopy (b + DATA_START + sizeof(DWORD), s->characters, s->length);
	b[(s->length)+ DATA_START + sizeof(DWORD)] = 0;

	Send();


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

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

		// Allocate data
		data_size = *((int *) (b+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 *) (b+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( b[MESSAGE_TYPE] == NEED_BASE_OF_LIBRARIES ) {
			n_libraries = *((int *) (b+DATA_START));
			s_buffer = *((int *) (b+DATA_START+sizeof(int)));

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

#ifdef CREATE_BUFFER2
			CreateBuffer2( "ServerLibraryBuffer", s_buffer, TRUE, &server_info);
			hServerView = server_info.hView;

//			__asm int 3

#else
mff			hServerLibraryBufferView = CreateBuffer( "ServerLibraryBuffer", s_buffer, TRUE);
			hServerView = hServerLibraryBufferView;
#endif

			// Allocate a client buffer to contain the base addresses
			// of all libraries
#ifdef CREATE_BUFFER2
			CreateBuffer2( "ClientLibraryBuffer", n_libraries * sizeof(HINSTANCE), FALSE, &client_info);
			hClientView = client_info.hView;
#else
!!!			hClientLibraryBufferView = CreateBuffer( "ClientLibraryBuffer", n_libraries * sizeof(HINSTANCE), FALSE );
			hClientView = hClientLibraryBufferView;
#endif
//			__asm int 3

			for(i = 0; i < n_libraries; i++ ) {
#ifdef CREATE_BUFFER2
				library = LoadLibrary(hServerView);
#else
				library = LoadLibrary(hServerLibraryBufferView);
#endif

#ifdef DEBUG
#ifdef CREATE_BUFFER2
				msg( hServerView );
#else
				msg( hServerLibraryBufferView );
#endif
#endif

				if( library == NULL ) {
//					__asm int 3
					
					error();
//					msg(  hServerLibraryBufferView);
					msg( "<channel.c>" );
					ExitProcess(-1);
				}

#ifdef CREATE_BUFFER2
				*((int *) (hClientView)) = library;
#else
				*((int *) (hClientLibraryBufferView)) = library;
#endif


#ifdef CREATE_BUFFER2
				hServerView += rstrlen(hServerView) + 1;
				hClientView += sizeof(HINSTANCE); 
#else
				hServerLibraryBufferView += rstrlen(hServerLibraryBufferView) + 1;
				hClientLibraryBufferView += sizeof(HINSTANCE);
#endif
			} /* for */

			Send();

#ifdef CREATE_BUFFER2
			CloseBuffer2(&server_info);
#else
			CloseBuffer( hServerView );
#endif

			/*
			** Receive label
			*/
			Receive();

#ifdef CREATE_BUFFER2
			CloseBuffer2(&client_info);
#else
			CloseBuffer( hClientView );
#endif
			
		} /* if */
	}

//	__asm int 3
	} while (b[MESSAGE_TYPE] == ADDRESS_UNKNOWN);

	if( b[MESSAGE_TYPE] == ADDRESS_KNOWN ) {
		length = *((DWORD *) (b+SIZE_OF_MESSAGE));
		clean_string = (CLEAN_STRING) rmalloc (sizeof(int) + length);
		clean_string->length = length;
		
		rsncopy(clean_string->characters, b + DATA_START, length);
	
		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;
	DWORD offset;
	DWORD length;

	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);

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

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

		b = (char *) MapViewOfFile( hFileMapping, FILE_MAP_WRITE, 0, offset, length);
		if( b == 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


BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID fImpLoad) {

	static BOOL dll_loaded_in_server = FALSE;

#ifdef CLIENT_DLL
	LPTSTR cmdline;
	DWORD dwServerId;
	HANDLE hFileMapping;
	DWORD offset;
	DWORD length;

	HANDLE hFileMapping2;
	BOOL ok;
	int i;
	char	buffer[100];
	DWORD	result;
	char	*charp;
#endif

	if( dll_loaded_in_server )
		return( TRUE );

	switch(fdwReason) {
	
#ifdef CLIENT_DLL

#ifndef STATIC_CLIENT_CHANNEL

	case DLL_PROCESS_ATTACH:
//		InitClientDLL();
		break;
//		__asm int 3
#ifdef SKIP
		// 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);

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

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

#ifdef _UNUSED
			cmdline = GetCommandLine();

		i = sscanf( cmdline, "%u %u %u %u %u %u", 
			&dwServerId, 
			&(hServerKilledOrReady[SERVER_READY]), 
			&hClientReady,
			&hFileMapping,
			&offset,
			&length);
		if( i == 0 ) {
			/*
			** The ClientChannel must not be loaded in the Server process
			** because the ServerChannel handles synchronisation. Under
			** Windows NT, the DLL is loaded without the system calling
			** DllMain using the flag DONT_RESOLVE_DLL_REFERENCES. The
			** flag doesn't exist on 95/98. Therefore this routine takes
			** care of not actually initializing.
			*/
			dll_loaded_in_server = TRUE;
			return( TRUE );
		}
#endif 
		b = (char *) MapViewOfFile( hFileMapping, FILE_MAP_WRITE, 0, offset, length);
		if( b == 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 // SKIP

		break;
#else
	case DLL_PROCESS_ATTACH:
		break;
#endif

/* ServerChannel */
#else
	case DLL_PROCESS_ATTACH:

		break;
#endif

	case DLL_THREAD_ATTACH:
		break;

	case DLL_THREAD_DETACH:
		break;

	case DLL_PROCESS_DETACH:

		break;
	}
	return(TRUE);
}

void CloseChannel() {

	UnmapViewOfFile(hMsgBufferView);

	CloseHandle(hMsgBufferMapping);
}

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
*/
#ifdef CREATE_BUFFER2
void CloseBuffer2(BufferInfo *info) {
	UnmapViewOfFile(info->hView);
	CloseHandle(info->hMapping);
}

void CreateBuffer2(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);
	}
}
#else
static HANDLE hLibraryBufferMapping = NULL;
static char *hLibraryBufferView= NULL;

void CloseBuffer3(char *hLibraryBufferView) {
	UnmapViewOfFile(hLibraryBufferView);
	CloseHandle(hLibraryBufferMapping);
}

char *CreateBuffer3(char *name, int size, BOOL open_buffer) {
	char s[100];

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

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

		hLibraryBufferMapping = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,size,name);
		if (hLibraryBufferMapping == 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
	*/
	hLibraryBufferView = (char *) MapViewOfFile(hLibraryBufferMapping, FILE_MAP_WRITE, 0, 0, size);
	if (hLibraryBufferView == NULL) {
		error(); 
		sprintf( s, "CreateBuffer: hLibraryBufferView '%d' '%s'", size, name );
		msg( s  );
		CloseHandle(hLibraryBufferMapping);
		ExitProcess(-1);
	}

	return( hLibraryBufferView );
}
#endif

// 
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 );
}

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  offset;
	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\\DynamicLinker11.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.
	*/
	b = (char *) MapViewOfFile( hFileMapping, FILE_MAP_WRITE, 0, 0, MESSAGE_SIZE);
	if( b == NULL ) {
		error();
		msg ( "StartDynamicLinker: could not open file mapping" );
		ExitProcess(-1);
	}

	dwServerId = *((DWORD *) (b+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 *) (b+GLOBAL_BUFFER_START)) = GetCurrentProcessId();

//	__asm int 3
	sprintf( b + 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 *) (b+GLOBAL_BUFFER_START));
	hServerReady_new = *((HANDLE *) (b+ GLOBAL_BUFFER_START + sizeof(DWORD) ));
	hClientReady_new = *((HANDLE *) (b+ GLOBAL_BUFFER_START + sizeof(DWORD) + sizeof(HANDLE) ));
	hFileMapping_new = *((HANDLE *) (b+ GLOBAL_BUFFER_START + sizeof(DWORD) + 2 * sizeof(HANDLE) ));
	offset			 = *((DWORD *) (b+ GLOBAL_BUFFER_START + sizeof(DWORD) + 3 * sizeof(HANDLE) ));
	length			 = *((DWORD *) (b+ GLOBAL_BUFFER_START + 2 * 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( b );

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

	b = (char *) MapViewOfFile( hFileMapping_new, FILE_MAP_WRITE, 0, offset, length);
	if( b == 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