//WinQLProcessBootStrap.cpp

// Copyright Querysoft Limited 2013
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//Implements .exe startup and shutdown code for Windows processes

#include "WinQL/WinQL.h"
#include "WinQL/Application/Threading/WinQLCriticalSection.h"
#include "WinQL/Bootstrap/WinQLProcessBootStrap.h"
#include "WinQL/Definitions/IO.h"
#include "WinQL/System/Performance/WinQLPerformanceHelper.h"
#include "CodeQOR/ErrorSystem/ExpectedHandler.h"
#include "WinQL/Application/ErrorSystem/WinQLErrDomain.h"
#include "WinQL/System/Clock/WinQLTime.h"
#include "WinQL/Application/Process/Module/WinQLDll.h"
#include "../Source/SystemQOR/MSWindows/WinQAPI/include/ErrorDomain.h"
#include "../Source/SystemQOR/MSWindows/WinQAPI/include/DynamicLibrary.h"
#include "WinQAPI/Kernel32.h"
#include "WinQAPI/PSAPI.h"
#include <limits.h>


__QCMP_LINKAGE_C void InitThread( void );

//--------------------------------------------------------------------------------
namespace nsWin32
{

	//--------------------------------------------------------------------------------
	CProcessBootStrap::CProcessBootStrap() : CModuleBootStrap(), m_szCommandLine( 0 )
	{
		m_iArgCount = 0;
		m_pArgsList = 0;
		m_pEnvList = 0;
		m_StartupInfo = nsWin32::CProcessHelper::StartupInfo();
		InitStatic();//Initialize the process object and QOR library statics.
	}

	//--------------------------------------------------------------------------------
	CProcessBootStrap::~CProcessBootStrap()
	{

	}

	//--------------------------------------------------------------------------------
	void* CProcessBootStrap::GetEnvironmentA( void )
	{
		wchar_t *wEnv;
		wchar_t *wTmp;
		char *aEnv = NULL;
		int nSizeW;
		int nSizeA;

		// obtain wide environment block

		if ( NULL == (wEnv = GetEnvironmentStringsW()) )
		{
			return NULL;
		}

		// look for double null that indicates end of block
		wTmp = wEnv;
		while ( *wTmp != L'\0' ) 
		{
			if ( *++wTmp == L'\0' )
				wTmp++;
		}

		// calculate total size of block, including all nulls
		nSizeW = (int)(wTmp - wEnv + 1);

		// find out how much space needed for multi-byte environment
		nSizeA = WideCharToMultiByte( CP_ACP, 0, wEnv, nSizeW, NULL, 0, NULL, NULL );

		// allocate space for multi-byte string 
		if ( (nSizeA == 0) || ((aEnv = (char *)malloc(nSizeA)) == NULL) )
		{
			FreeEnvironmentStringsW( wEnv );
			return NULL;
		}

		/* do the conversion */
		if ( !WideCharToMultiByte(  CP_ACP,
									0,
									wEnv,
									nSizeW,
									aEnv,
									nSizeA,
									NULL,
									NULL ) )
		{
			free( aEnv );
			aEnv = NULL;
		}

		FreeEnvironmentStringsW( wEnv );
		return aEnv;
	}

	//--------------------------------------------------------------------------------
	void CProcessBootStrap::ParseCommandLine()
	{
		nsWin32::CProcessHelper ProcessHelper;
		m_szCommandLine = ProcessHelper.GetCommandLineT();
		m_iArgCount = 0;
		m_pArgsList = 0;
		int dowildcard = 0;

		//_aenvptr = (char *)GetEnvironmentA();

		//_acmdln = GetCommandLineA();
		//_wcmdln = GetCommandLineW();

		GetMainArgs( dowildcard );

		setenvp();
	}

	//--------------------------------------------------------------------------------
	int CProcessBootStrap::setenvp( void )
	{
		/*
		TCHAR* p;
		TCHAR** env;              // _environ ptr traversal pointer
		int numstrings;           // number of environment strings
		int cchars;

#if defined (_MBCS)
			// If necessary, initialize the multibyte ctype table.
			if ( __mbctype_initialized == 0 )
				__initmbctable();
#endif  

		numstrings = 0;

		p = _aenvptr;//_tenvptr;

		if( p == NULL )
		{
			return -1;
		}

		//NOTE: starting with single null indicates no environ.
		//Count the number of strings. Skip drive letter settings
		//("=C:=C:\foo" type) by skipping all environment variables
		//that begin with '=' character.
		

		while( *p != _TXT( "\0" )[0] ) 
		{
			// don't count "=..." type
			if( *p != _TXT("=")[0] )
			{
				++numstrings;
			}
			p += strlen( p ) + 1;
		}

		// need pointer for each string, plus one null ptr at end 
		if ( ( environ = env = (TCHAR**)calloc( (numstrings + 1 ), sizeof( TCHAR* ) ) ) == NULL )
		{
			return -1;
		}

		// copy strings to malloc'd memory and save pointers in _environ 
		for( p = _aenvptr; *p != L'\0' ; p += cchars )
		{
			cchars = (int)strlen( p ) + 1;
			// don't copy "=..." type 
			if (*p != _TXT("=")[0]) 
			{
				if( ( *env = ( TCHAR* )calloc( cchars, sizeof(TCHAR) ) ) == NULL )
				{
					free( environ );
					environ = NULL;
					return -1;
				}
				strncpy( *env, p, cchars );
				env++;
			}
		}

		free(_aenvptr);
		_aenvptr = NULL;

		// and a final NULL pointer
		*env = NULL;
		*/
		return 0;
	}

	/*
	static void __cdecl wparse_cmdline (
    _TSCHAR *cmdstart,
    _TSCHAR **argv,
    _TSCHAR *args,
    int *numargs,
    int *numchars
    )
	{
        _TSCHAR *p;
        _TUCHAR c;
        int inquote;      
        int copychar;     
        unsigned numslash;

        *numchars = 0;
        *numargs = 1;

        
        p = cmdstart;
        if (argv)
            *argv++ = args;

#ifdef WILDCARD

		if (args)
            *args++ = *p;
        ++*numchars;

#endif  


        inquote = FALSE;
        do {
            if (*p == DQUOTECHAR )
            {
                inquote = !inquote;
                c = (_TUCHAR) *p++;
                continue;
            }
            ++*numchars;
            if (args)
                *args++ = *p;

            c = (_TUCHAR) *p++;
#ifdef _MBCS
            if (_ismbblead(c)) {
                ++*numchars;
                if (args)
                    *args++ = *p;   
                p++;  
            }
#endif  

        } while ( (c != NULCHAR && (inquote || (c !=SPACECHAR && c != TABCHAR))) );

        if ( c == NULCHAR ) {
            p--;
        } else {
            if (args)
                *(args-1) = NULCHAR;
        }

        inquote = 0;

        
        for(;;) {

            if ( *p ) {
                while (*p == SPACECHAR || *p == TABCHAR)
                    ++p;
            }

            if (*p == NULCHAR)
                break;

            
            if (argv)
                *argv++ = args;
            ++*numargs;

#ifdef WILDCARD
        if (args)
            *args++ = *p;
        ++*numchars;

#endif 

        for (;;) {
            copychar = 1;
            numslash = 0;
            while (*p == SLASHCHAR) {
                ++p;
                ++numslash;
            }
            if (*p == DQUOTECHAR) {

                if (numslash % 2 == 0) {
                    if (inquote && p[1] == DQUOTECHAR) {
                        p++;    
                    } else {    
                        copychar = 0;
                        inquote = !inquote;
                    }
                }
                numslash /= 2;
            }

       
            while (numslash--) {
                if (args)
                    *args++ = SLASHCHAR;
                ++*numchars;
            }

       
            if (*p == NULCHAR || (!inquote && (*p == SPACECHAR || *p == TABCHAR)))
                break;

       
#ifdef _MBCS
            if (copychar) {
                if (args) {
                    if (_ismbblead(*p)) {
                        *args++ = *p++;
                        ++*numchars;
                    }
                    *args++ = *p;
                } else {
                    if (_ismbblead(*p)) {
                        ++p;
                        ++*numchars;
                    }
                }
                ++*numchars;
            }
            ++p;
#else  
            if (copychar) {
                if (args)
                    *args++ = *p;
                ++*numchars;
            }
            ++p;
#endif 
            }


            if (args)
                *args++ = NULCHAR;
            ++*numchars;
        }

        
        if (argv)
            *argv++ = NULL;
        ++*numargs;
	}
	*/

	//--------------------------------------------------------------------------------
	void CProcessBootStrap::parse_cmdline( TCHAR* cmdstart, TCHAR** argv, TCHAR* args, int* numargs, int* numchars )
	{
        TCHAR* p;
        TCHAR c;
        int inquote;                    /* 1 = inside quotes */
        int copychar;                   /* 1 = copy char to *args */
        unsigned numslash;              /* num of backslashes seen */

        *numchars = 0;
        *numargs = 1;                   /* the program name at least */

        /* first scan the program name, copy it, and count the bytes */
        p = cmdstart;
        if( argv )
		{
            *argv++ = args;
		}

#ifdef WILDCARD
        /* To handle later wild card expansion, we prefix each entry by it's first character before quote handling.  This is done so _[w]cwild() knows whether to expand an entry or not. */
        if( args )
		{
            *args++ = *p;
		}
        ++*numchars;

#endif  /* WILDCARD */

        /* A quoted program name is handled here. The handling is much simpler than for other arguments. Basically, whatever lies
           between the leading double-quote and next one, or a terminal null character is simply accepted. Fancier handling is not required
           because the program name must be a legal NTFS/HPFS file name. Note that the double-quote characters are not copied, nor do they
           contribute to numchars. */
        inquote = FALSE;
        do 
		{
            if( *p == DQUOTECHAR )
            {
                inquote = !inquote;
                c = (TCHAR) *p++;
                continue;
            }

            ++*numchars;
            if( args )
			{
                *args++ = *p;
			}

            c = (TCHAR) *p++;
#ifdef _MBCS
            if( _ismbblead( c ) ) 
			{
                ++*numchars;
                if( args )
				{
                    *args++ = *p;   /* copy 2nd byte too */
				}
                p++;  /* skip over trail byte */
            }
#endif  /* _MBCS */

        } while ( ( c != NULCHAR && ( inquote || ( c !=SPACECHAR && c != TABCHAR ) ) ) );

        if( c == NULCHAR ) 
		{
            p--;
        } 
		else 
		{
            if( args )
			{
                *(args-1) = NULCHAR;
			}
        }

        inquote = 0;

        //Loop through arguments
        for(;;) 
		{

            if( *p ) 
			{
                while( *p == SPACECHAR || *p == TABCHAR )
				{
                    ++p;
				}
            }

            if( *p == NULCHAR )
			{
                break;              //End of arguments
			}

            // Scan argument
            if( argv )
			{
                *argv++ = args;     // Store pointer to argument
			}
            ++*numargs;

#ifdef WILDCARD
			/* To handle later wild card expansion, we prefix each entry by it's first character before quote handling.  This is done
			so _[w]cwild() knows whether to expand an entry or not. */
			if( args )
			{
				*args++ = *p;
			}
			++*numchars;

#endif//WILDCARD

			/* loop through scanning one argument */
			for (;;) 
			{
				copychar = 1;
				/* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
				   2N+1 backslashes + " ==> N backslashes + literal "
				   N backslashes ==> N backslashes */
				numslash = 0;
				while( *p == SLASHCHAR ) 
				{
					/* count number of backslashes for use below */
					++p;
					++numslash;
				}

				if( *p == DQUOTECHAR ) 
				{
					/* if 2N backslashes before, start/end quote, otherwise
						copy literally */
					if( numslash % 2 == 0 ) 
					{
						if( inquote && p[ 1 ] == DQUOTECHAR ) 
						{
							p++;    // Double quote inside quoted string
						} 
						else 
						{    
							// skip first quote char and copy second 
							copychar = 0;       // don't copy quote
							inquote = !inquote;
						}
					}
					numslash /= 2;          // divide numslash by two 
				}

				// copy slashes 
				while (numslash--) 
				{
					if( args )
					{
						*args++ = SLASHCHAR;
					}
					++*numchars;
				}

				// if at end of arg, break loop
				if( *p == NULCHAR || ( !inquote && ( *p == SPACECHAR || *p == TABCHAR ) ) )
				{
					break;
				}

	            // copy character into argument
#ifdef _MBCS
				if( copychar ) 
				{
					if( args ) 
					{
						if( _ismbblead( *p ) ) 
						{
							*args++ = *p++;
							++*numchars;
						}
						*args++ = *p;
					} 
					else 
					{
						if( _ismbblead( *p ) ) 
						{
							++p;
							++*numchars;
						}
					}
					++*numchars;
				}
				++p;
#else// _MBCS
				if( copychar ) 
				{
					if( args )
					{
						*args++ = *p;
					}
					++*numchars;
				}
				++p;
#endif //_MBCS
			}

			// null-terminate the argument

            if (args)
			{
                *args++ = NULCHAR;          // terminate string
			}
            ++*numchars;
		}

        // We put one last argument in -- a null ptr
        if( argv )
		{
            *argv++ = NULL;
		}

        ++*numargs;
	}


	/*
	//--------------------------------------------------------------------------------
	//Wide character with wild card
	int __cdecl CProcessBootStrap::__wsetargv( void )
	{
        _TSCHAR *p = NULL;
        _TSCHAR *cmdstart;                  
        int numargs, numchars;

        static _TSCHAR _pgmname[ MAX_PATH + 1 ];

#if !defined (CRTDLL) && defined (_MBCS)
        

        if ( __mbctype_initialized == 0 )
            __initmbctable();
#endif  

        

        _pgmname[ MAX_PATH ] = '\0';
        GetModuleFileName( NULL, _pgmname, MAX_PATH );

        _set_wpgmptr(_pgmname);



        cmdstart = (_wcmdln == NULL || *_wcmdln == NULCHAR)
                   ? _pgmname : _wcmdln;

        wparse_cmdline(cmdstart, NULL, NULL, &numargs, &numchars);

        CRT_WARNING_DISABLE_PUSH(22011, "Silence prefast about overflow/underflow");

        if (numargs >= (SIZE_MAX / sizeof(_TSCHAR *)) ||
            numchars >= (SIZE_MAX / sizeof(_TSCHAR)))
        {
            return -1;
        }
        if ((numargs * sizeof(_TSCHAR *) + numchars * sizeof(_TSCHAR)) < (numchars * sizeof(_TSCHAR)))
        {
            return -1;
        }
        p = _malloc_crt(numargs * sizeof(_TSCHAR *) + numchars * sizeof(_TSCHAR));
        if (p == NULL)
            return -1;


        wparse_cmdline(cmdstart, (wchar_t **)p, (wchar_t *)(((char *)p) + numargs * sizeof(wchar_t *)), &numargs, &numchars);

		CRT_WARNING_POP;

        __argc = numargs - 1;
        __wargv = (wchar_t **)p;


        if (_wcwild())
            return -1;

        return 0;

	}

	//--------------------------------------------------------------------------------
	//narrow character with wild card
	int __cdecl __setargv ( void )
	{
        _TSCHAR *p = NULL;
        _TSCHAR *cmdstart;
        int numargs, numchars;

        static _TSCHAR _pgmname[ MAX_PATH + 1 ];

#if !defined (CRTDLL) && defined (_MBCS)
        
        if ( __mbctype_initialized == 0 )
            __initmbctable();
#endif  

        

        _pgmname[ MAX_PATH ] = '\0';
        GetModuleFileName( NULL, _pgmname, MAX_PATH );
        _set_pgmptr(_pgmname);


        cmdstart = (_acmdln == NULL || *_acmdln == NULCHAR)
                   ? _pgmname : _acmdln;

        parse_cmdline(cmdstart, NULL, NULL, &numargs, &numchars);

        CRT_WARNING_DISABLE_PUSH(22011, "Silence prefast about overflow/underflow");

        if (numargs >= (SIZE_MAX / sizeof(_TSCHAR *)) ||
            numchars >= (SIZE_MAX / sizeof(_TSCHAR)))
        {
            return -1;
        }
        if ((numargs * sizeof(_TSCHAR *) + numchars * sizeof(_TSCHAR)) < (numchars * sizeof(_TSCHAR)))
        {
            return -1;
        }
        p = _malloc_crt(numargs * sizeof(_TSCHAR *) + numchars * sizeof(_TSCHAR));
        if (p == NULL)
            return -1;


        parse_cmdline(cmdstart, (char **)p, p + numargs * sizeof(char *), &numargs, &numchars);
        CRT_WARNING_POP;

        __argc = numargs - 1;
        __argv = (char **)p;

        if (_cwild())
            return -1;

        return 0;
	}


	//--------------------------------------------------------------------------------
	//No Wild card Wide character
	int __cdecl _wsetargv( void )
	{
        _TSCHAR *p = NULL;
        _TSCHAR *cmdstart;
        int numargs, numchars;

        static _TSCHAR _pgmname[ MAX_PATH + 1 ];

#if !defined (CRTDLL) && defined (_MBCS)
        if ( __mbctype_initialized == 0 )
            __initmbctable();
#endif


        _pgmname[ MAX_PATH ] = '\0';
        GetModuleFileName( NULL, _pgmname, MAX_PATH );
        _set_wpgmptr(_pgmname);


        cmdstart = (_wcmdln == NULL || *_wcmdln == NULCHAR)
                   ? _pgmname : _wcmdln;


        wparse_cmdline(cmdstart, NULL, NULL, &numargs, &numchars);


        CRT_WARNING_DISABLE_PUSH(22011, "Silence prefast about overflow/underflow");

        if (numargs >= (SIZE_MAX / sizeof(_TSCHAR *)) ||
            numchars >= (SIZE_MAX / sizeof(_TSCHAR)))
        {
            return -1;
        }
        if ((numargs * sizeof(_TSCHAR *) + numchars * sizeof(_TSCHAR)) < (numchars * sizeof(_TSCHAR)))
        {
            return -1;
        }
        p = _malloc_crt(numargs * sizeof(_TSCHAR *) + numchars * sizeof(_TSCHAR));
        if (p == NULL)
            return -1;

        wparse_cmdline(cmdstart, (wchar_t **)p, (wchar_t *)(((char *)p) + numargs * sizeof(wchar_t *)), &numargs, &numchars);

		CRT_WARNING_POP;

        __argc = numargs - 1;
        __wargv = (wchar_t **)p;

        return 0;
	}
*/

	//No wildcard narrow char
	int CProcessBootStrap::_setargv( void )
	{
		/*
        TCHAR* p = 0;
        TCHAR* cmdstart;                  // start of command line to parse
        int numargs, numchars;

        static TCHAR _pgmname[ MAX_PATH + 1 ];

#if defined (_MBCS)
        // If necessary, initialize the multibyte ctype table.
        if ( __mbctype_initialized == 0 )
            __initmbctable();
#endif  

        // Get the program name pointer from Win32 Base

        _pgmname[ MAX_PATH ] = '\0';
        GetModuleFileName( NULL, _pgmname, MAX_PATH );

        //TODO:_set_pgmptr( _pgmname );

        // if there's no command line at all (won't happen from cmd.exe, but
         //possibly another program), then we use _pgmptr as the command line
         //to parse, so that argv[0] is initialized to the program name

        cmdstart = ( _acmdln == 0 || *_acmdln == NULCHAR ) ? _pgmname : _acmdln;

        // first find out how much space is needed to store args
        parse_cmdline( cmdstart, 0, 0, &numargs, &numchars);

        //CRT_WARNING_DISABLE_PUSH(22011, "Silence prefast about overflow/underflow");

        // allocate space for argv[] vector and strings
        if( numargs >= ( Size_Max / sizeof( TCHAR*) ) || numchars >= ( Size_Max / sizeof(TCHAR) ) )
        {
            return -1;
        }

        if( ( numargs * sizeof(TCHAR*) + numchars * sizeof(TCHAR) ) < ( numchars * sizeof(TCHAR) ) )
        {
            return -1;
        }

        p = reinterpret_cast< TCHAR* >( malloc( numargs * sizeof( TCHAR* ) + numchars * sizeof( TCHAR ) ) );
        if( p == 0 )
		{
            return -1;
		}

        // store args and argv ptrs in just allocated block

        parse_cmdline( cmdstart, (char **)p, p + numargs * sizeof( char* ), &numargs, &numchars );
        //CRT_WARNING_POP;

        // set argv and argc
        m_iArgCount = numargs - 1;
        m_pArgsList = (char **)p;
		*/
        return 0;
	}


	//--------------------------------------------------------------------------------
	int CProcessBootStrap::GetMainArgs( int dowildcard )
	{
		int ret = 0;

		// set global new mode flag
		//_newmode = m_StartupInfo.newmode;

		if( dowildcard )
		{
			//ret = __setargv();  /* do wildcard expansion after parsing args */
		}
		else
		{
			ret = _setargv();   /* NO wildcard expansion; just parse args */
		}

		return ret;
	}

	//--------------------------------------------------------------------------------
	nsCodeQOR::CTLinkedList< nsWin32::CDll > CProcessBootStrap::GetModuleList( void )
	{
		nsWinQAPI::CPSAPI PSAPIHelper;
		nsCodeQOR::CTLinkedList< nsWin32::CDll > ModuleList;
		ModuleHandle nHandle;
		ModuleHandle* pHandles = 0;
		unsigned long ulByteCount = 0;
		PSAPIHelper.EnumProcessModules( reinterpret_cast< InstanceHandle >( nsWinQAPI::CKernel32::GetCurrentProcess() ), (HMODULE*)&nHandle, 1, &ulByteCount );
		unsigned long ulModuleCount = ( ulByteCount / sizeof( nsWin32::InstanceHandle ) );

		if( ulModuleCount > 0 )
		{
			pHandles = new ModuleHandle[ ulModuleCount ];
			memset( pHandles, 0, ulModuleCount * sizeof( nsWin32::InstanceHandle ) );
			PSAPIHelper.EnumProcessModules( reinterpret_cast< InstanceHandle >( nsWinQAPI::CKernel32::GetCurrentProcess() ), (HMODULE*)pHandles, ulByteCount, &ulByteCount );

			while( ulModuleCount > 0 )
			{
				if( pHandles[ --ulModuleCount ] != 0 )
				{
					nsWin32::CDll* pModule = new nsWin32::CDll( reinterpret_cast< void* >( pHandles[ ulModuleCount ] ), true );
					ModuleList.Append( pModule );
				}
			};
			delete [] pHandles;
		}

		return ModuleList;
	}

	//--------------------------------------------------------------------------------
	void CProcessBootStrap::InitStatic()
	{
		InitWindowsProcess();//Create the Windows Process Object

		nsCodeQOR::mxGUID nullGUID = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
		nsCodeQOR::mxGUID aDependencies[][5] =
		{
			{
				{ 0xdb51fb8c, 0x4bef, 0x43f2, { 0xa4, 0x61, 0x7e, 0x49, 0x4f, 0xaf, 0xad, 0x75 } },
					{ 0x2c101426, 0x4e38, 0x49c0, { 0x91, 0xc8, 0x0c, 0xea, 0xf5, 0x14, 0xbc, 0x02 } }, nullGUID, nullGUID, nullGUID
			},

			{
				{ 0x559bde19, 0x75ed, 0x4ff9,{ 0x92, 0x45, 0x86, 0x9a, 0xcc, 0xe4, 0xcd, 0xb6 } },//WinQLCOM is dependent on
				{ 0xdd8152fd, 0xcdd8, 0x4c26,{ 0xb3, 0x55, 0x00, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
				nullGUID, nullGUID, nullGUID
			},

			{
				{ 0xa2250e96, 0xd07d, 0x4440, { 0xb3, 0xd7, 0xbd, 0x1, 0xc0, 0xc7, 0x7c, 0xef } },//WinQL is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x00, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					nullGUID, nullGUID, nullGUID
			},

			{
				{ 0x74346fa1, 0xab39, 0x48b7, { 0xbe, 0x13, 0xe1, 0xdf, 0x5b, 0x7b, 0x22, 0xe6 } }, //SystemQOR  is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					nullGUID, nullGUID, nullGUID
			},

			{
				{ 0xc20a868d, 0x9678, 0x4c61, { 0xa2, 0x5c, 0xb3, 0x1e, 0x89, 0xb8, 0xa8, 0xad } }, //Qurses  is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					nullGUID, nullGUID, nullGUID
			},

			{
				{ 0xa2c43bf9, 0xc341, 0x447a, { 0xbe, 0xf5, 0xe0, 0xcf, 0x66, 0x3f, 0x3a, 0x31 } }, //stdQOR is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					{ 0x2c101426, 0x4e38, 0x49c0,{ 0x91, 0xc8, 0xc, 0xea, 0xf5, 0x14, 0xbc, 0x2 } }, //CQOR
					{ 0x74346fa1, 0xab39, 0x48b7,{ 0xbe, 0x13, 0xe1, 0xdf, 0x5b, 0x7b, 0x22, 0xe6 } }, //SystemQOR
					{ 0xc36f2544, 0x5965, 0x4414,{ 0x80, 0x3f, 0xe2, 0x16, 0xb7, 0x19, 0x78, 0x3d } } //PosumQOR
			},


			{
				{ 0xc36f2544, 0x5965, 0x4414,{ 0x80, 0x3f, 0xe2, 0x16, 0xb7, 0x19, 0x78, 0x3d } }, //PosumQOR is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					{ 0xbc26d453, 0x1662, 0x43f1,{ 0x8c, 0x95, 0xfa, 0x27, 0xb1, 0xf5, 0x29, 0x8f } }, //WinPosum
					nullGUID, nullGUID
			},


			{
				{ 0xbc26d453, 0x1662, 0x43f1, { 0x8c, 0x95, 0xfa, 0x27, 0xb1, 0xf5, 0x29, 0x8f } }, //WinPosum is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					{ 0xa2250e96, 0xd07d, 0x4440,{ 0xb3, 0xd7, 0xbd, 0x1, 0xc0, 0xc7, 0x7c, 0xef } }, //WinQL
					nullGUID, nullGUID
			},

			{
				{ 0x66f10921, 0x8a75, 0x4446, { 0x8f, 0x58, 0xe4, 0xda, 0x6d, 0xf4, 0x3f, 0x75 } },	//WinQL-GUI is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					nullGUID, nullGUID, nullGUID
			},

			{
				{ 0x6dc84e1d, 0x8faf, 0x4ed2, { 0xbf, 0xe0, 0x8f, 0x44, 0x7, 0x37, 0x33, 0x4a } },	//MammutQOR is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					nullGUID, nullGUID, nullGUID
			},

			{
				{ 0x5fd99507, 0xa96f, 0x46c4, { 0x8a, 0x4, 0x2f, 0x92, 0x2e, 0xab, 0x1f, 0x11 } },	//AppocritaQOR is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					nullGUID, nullGUID, nullGUID
			},

			{
				{ 0x2c101426, 0x4e38, 0x49c0, { 0x91, 0xc8, 0xc, 0xea, 0xf5, 0x14, 0xbc, 0x2 } },	//CQOR is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					nullGUID, nullGUID, nullGUID
			},

			{
				{ 0xc63037bf, 0x6ebd, 0x4e0c, { 0x81, 0x83, 0x14, 0xa1, 0x66, 0xb7, 0xc3, 0x46 } },	//CodeQOR is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					nullGUID, nullGUID, nullGUID
			},

			{
				{ 0x131ac44c, 0xe028, 0x4436, { 0x96, 0x61, 0xe6, 0x83, 0xb4, 0xe1, 0x3c, 0x31 } },	//BluefootQOR is dependent on
					{ 0xdd8152fd, 0xcdd8, 0x4c26, { 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
					nullGUID, nullGUID, nullGUID
			},

			{
				{ 0x6d8a9cb5, 0x7ab7, 0x47f1,{ 0x87, 0x9c, 0x55, 0x9e, 0x94, 0xfa, 0x86, 0xa4 } },	//MonkiQOR is dependent on
				{ 0xdd8152fd, 0xcdd8, 0x4c26,{ 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
				nullGUID, nullGUID, nullGUID
			},

			{
				{ 0x8519f0c2, 0xd864, 0x4477,{ 0xbb, 0x36, 0xa0, 0xed, 0xbc, 0x0b, 0xb5, 0x05 } },	//CompilerQOR is dependent on
				{ 0xdd8152fd, 0xcdd8, 0x4c26,{ 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
				nullGUID, nullGUID, nullGUID
			},

			{
				{ 0x36dbc0c9, 0xb4cf, 0x4b8d,{ 0x91, 0xec, 0xd0, 0x63, 0xd4, 0xce, 0x7, 0x7a } },	//WinQAPI is dependent on
				{ 0xdd8152fd, 0xcdd8, 0x4c26,{ 0xb3, 0x55, 0x0, 0xd5, 0x79, 0x55, 0xb8, 0x7a } }, //ArchQOR
				nullGUID, nullGUID, nullGUID
			},
			nullGUID,
		};

		//Get the Module list
		nsCodeQOR::CTLinkedList< nsWin32::CDll > ModuleList( GetModuleList() );
		//nsCodeQOR::CExpectedHandler ExpectingError( nsWinQAPI::GENERAL_API_ERROR );

		nsCodeQOR::CTLinkedList< nsCodeQOR::CTPair< nsCodeQOR::__mxGUID, nsWinQAPI::CLibrary::DefProc > > InitFuncList;

		//Strip out non QOR libraries and collect ids and entry points for the QOR libraries
		int iModule = 1;
		while( iModule <= static_cast< int >( ModuleList.GetCount() ) )
		{
			nsWin32::CDll* pModule = ModuleList.GetItem( iModule );
			nsWinQAPI::CLibrary::DefProc pIdentity = reinterpret_cast< nsWinQAPI::CLibrary::DefProc >( pModule->GetProcAddress( "QORidentity" ) );
			if( pIdentity == 0 )
			{
				ModuleList.Remove( iModule );
			}
			else
			{
				nsCodeQOR::CTPair< nsCodeQOR::__mxGUID, nsWinQAPI::CLibrary::DefProc >* pInitEntryPoint = new nsCodeQOR::CTPair< nsCodeQOR::__mxGUID, nsWinQAPI::CLibrary::DefProc >(
					*( ( pModule->Call< nsCodeQOR::mxGUID* >( pIdentity ) ) ),
					reinterpret_cast< nsWinQAPI::CLibrary::DefProc >( pModule->GetProcAddress( "QORinit" ) ) );
				InitFuncList.Append( pInitEntryPoint );
				iModule++;
			}
		};

#ifndef	QOR_MONOLITHIC
		//For each remaining library ensure all its static dependencies are higher up the list than it is by moving it to just after the last one

		bool bFinished = false;
		while( !bFinished )
		{
			bFinished = true;
			int iEntry = 1;
			while( iEntry <= static_cast< int >( InitFuncList.GetCount() ) )
			{
				//Find any static dependencies for the module
				int iMain = 0;
				nsCodeQOR::mxGUID* pMainGUID = aDependencies[iMain++];
				while( pMainGUID[0] != nullGUID && pMainGUID[ 0 ] != InitFuncList.GetItem(iEntry)->First() )
				{
					pMainGUID = aDependencies[iMain++];
				}

				if( pMainGUID != 0 && pMainGUID[0] != nullGUID )
				{
					int iDependency = 1;
					nsCodeQOR::__mxGUID DependentGUID = pMainGUID[iDependency++];
					while( DependentGUID != nullGUID )
					{
						//ensure MainGUID occurs after DependentGUID in InitFuncList;
						int iMainIndex = 1;
						int iSearchIndex = 1;
						int iDependsIndex = 1;
						int iTargetMainIndex = 1;
						while( iSearchIndex <= static_cast< int > ( InitFuncList.GetCount() ) )
						{
							if( InitFuncList.GetItem( iSearchIndex )->First() == pMainGUID[ 0 ] )
							{
								iMainIndex = iSearchIndex;
							}
							if( InitFuncList.GetItem( iSearchIndex )->First() == DependentGUID )
							{
								iDependsIndex = iSearchIndex;
							}
							iSearchIndex++;
						}
						if( iDependsIndex > iMainIndex )
						{
							iTargetMainIndex = iDependsIndex;
						}
						if( iTargetMainIndex > iMainIndex )
						{
							nsCodeQOR::CTPair< nsCodeQOR::__mxGUID, nsWinQAPI::CLibrary::DefProc >* pMainEntry = InitFuncList.GetItem( iMainIndex );
							InitFuncList.Drop( iMainIndex );
							InitFuncList.Insert( iTargetMainIndex, pMainEntry );
							bFinished = false;
						}

						DependentGUID = pMainGUID[iDependency++];
					}
				}
				if( !bFinished )
				{
					break;
				}
				iEntry++;
			};
		};

#endif//QOR_MONOLITHIC

		int iEntry = 1;
		while( iEntry <= static_cast< int >( InitFuncList.GetCount() ) )
		{
			nsCodeQOR::CTPair< nsCodeQOR::__mxGUID, nsWinQAPI::CLibrary::DefProc >* pEntry = InitFuncList.GetItem( iEntry++ );
			if( pEntry->Second() != 0 )
			{
				( pEntry->Second() )( );
			}
			else
			{
				pEntry = pEntry;//No QORInit on a QOR Module!
			}
		}

	}

}//nsWin32
