/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*********************************************************************************************** 
 ***                            Confidential - Westwood Studios                              *** 
 *********************************************************************************************** 
 *                                                                                             * 
 *                 Project Name : Installer                                                    * 
 *                                                                                             * 
 *                     $Archive:: /Commando/Code/Installer/Utilities.cpp  $* 
 *                                                                                             * 
 *                      $Author:: Ian_l                   $* 
 *                                                                                             * 
 *                     $Modtime:: 1/11/02 10:27a                $* 
 *                                                                                             * 
 *                    $Revision:: 10                    $* 
 *                                                                                             * 
 *---------------------------------------------------------------------------------------------* 
 * Functions:                                                                                  * 
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

// Includes.
#include "Utilities.h"
#include "ErrorHandler.h"
#include "Resource.h"
#include "Translator.h"
#include <shlwapi.h>
#include <stdlib.h>
#include	<winbase.h>
#include <shlobj.h>


// Private prototypes.
static bool	  Create_Directory (const WCHAR *drive, const WCHAR *directory, WCHAR *subdirectory, bool remove, DynamicVectorClass <StringClass> *log);
static WCHAR *Standardize_Path (const WideStringClass &path, WideStringClass &standardpath);
static bool	  Validate_Install_CD (const char driveletter, const WideStringClass &installvolumename);


/***********************************************************************************************
 * Prompt_Install_CD -- Is the install CD in one of the CD drives? If not prompt for it.		  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Prompt_Install_CD (const WideStringClass &installvolumename, char &sourcedriveletter)
{
	bool success = false;

	while (!success) {
	
		for (char r = 'A'; r <= 'Z'; r++) {
			
			char rootpathname [] = "?:\\";

			rootpathname [0] = r;

			// If the drive is a CD-ROM...
			if (GetDriveType (rootpathname) == DRIVE_CDROM) {
				if (Validate_Install_CD (r, installvolumename)) {
					sourcedriveletter = r;
					success = true;
					break;
				}
			}
		}

		if (!success) {

			bool cancel;

			// No CD-ROM with the correct label found. Ask user to insert the CD-ROM.
			ShowCursor (true);
			cancel = MessageBoxExW (NULL, TxWideStringClass (IDS_INSERT_GAME_CD_ROM), TxWideStringClass (IDS_APPLICATION_NAME), MB_RETRYCANCEL | MB_APPLMODAL | MB_SETFOREGROUND, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT)) == IDCANCEL;
			ShowCursor (false);
			if (cancel) break;
		}
	}

	return (success);
}


/***********************************************************************************************
 * Validate_Install_CD -- Is the install CD in the designated CD drive?								  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Validate_Install_CD (const WideStringClass &sourcepath, const WideStringClass &installvolumename)
{
	StringClass multibytesourcepath (sourcepath);
	return (Validate_Install_CD (multibytesourcepath [0], installvolumename));
}


/***********************************************************************************************
 * Validate_Install_CD -- Is the install CD in the designated CD drive?								  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Validate_Install_CD (const char driveletter, const WideStringClass &installvolumename)
{
	char	multibytevolumename [_MAX_PATH];
	char	filesystemname [_MAX_PATH];
	DWORD	maxfilenamelength;
	DWORD	flags;
	char	rootpathname [] = "?:\\";

	rootpathname [0] = driveletter;
	if (GetVolumeInformation (rootpathname, multibytevolumename, _MAX_PATH, NULL, &maxfilenamelength, &flags, filesystemname, _MAX_PATH)) {
				 
		WideStringClass volumename (multibytevolumename);
		
		// Windows '95 appears to have a volume name limit of 11 characters. I cannot find a Win32
		// call that will return the maximum volume name length so the value '11' is hard-coded here
		// and the assumption made that all OS's have this length or better.
		if (wcsncmp (volumename, installvolumename, MAX (11, volumename.Get_Length())) == 0)	{
			return (true);
		}
	}
	return (false);
}


/***********************************************************************************************
 * Get_Disk_Space_Available --																					  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:																											  *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Get_Disk_Space_Available (const WideStringClass &path, __int64 &diskspace)
{
	StringClass    multibytepath (path);
	char				drive [_MAX_DRIVE];
	ULARGE_INTEGER freebytecount;		// Free bytes on disk available to caller (caller may not have access to entire disk).
	ULARGE_INTEGER totalbytecount;	// Total bytes on disk.
	StringClass		kernelpathname;

	int (__stdcall *getfreediskspaceex) (LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);

	// Extract the drive.
	// NOTE 0: Even though GetDiskFreeSpaceEx() will accept a full path, it will err if the path is not valid.
	// NOTE 1: _splitpath() automatically handles multi-byte character strings.
	_splitpath (multibytepath, drive, NULL, NULL, NULL);

	GetSystemDirectory (kernelpathname.Get_Buffer (_MAX_PATH), _MAX_PATH);
	kernelpathname += "\\";
	kernelpathname += "Kernel32.dll";
	getfreediskspaceex = (int (_stdcall*) (LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)) GetProcAddress (GetModuleHandle (kernelpathname.Peek_Buffer()), "GetDiskFreeSpaceExA");
	if (getfreediskspaceex != NULL) {

		// NOTE: This function uses GetDiskFreeSpaceEx() and therefore assumes Win '95 OSR2 or greater.
		if (!getfreediskspaceex (drive, &freebytecount, &totalbytecount, NULL)) return (false);
	
		// Convert to a 64-bit integer.
		diskspace = freebytecount.QuadPart;
	
	} else {

		DWORD sectorspercluster, bytespersector, freeclustercount, totalclustercount;
		
		// The Ex version is not available. Use the Win'95 version.
		// QUESTION: SDK docs say that values returned by this function are erroneous if partition > 2Gb.
		//				 Does that mean that the partition is guaranteed to be <= 2Gb if Ex is not available?
		if (!GetDiskFreeSpace (drive, &sectorspercluster, &bytespersector, &freeclustercount, &totalclustercount)) return (false); 
		diskspace = sectorspercluster * bytespersector * freeclustercount;
	}

	return (true);
}


/***********************************************************************************************
 * Validate_Path --																									  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Validate_Path (const WideStringClass &path, int &errorcode)
{
	bool valid = false;

	// Check that path has syntax <drive>:\<directory>\<directory>...
	if (path.Get_Length() > _MAX_DRIVE) {
		if (((path [0] >= L'A') && (path [0] <= L'Z')) || ((path [0] >= L'a') && (path [0] <= L'z'))) {
			if ((path [1] == L':') && ((path [2] == L'\\') || (path [2] == L'/'))) {

				const WCHAR *c = ((WideStringClass) path).Peek_Buffer() + _MAX_DRIVE;
	
				while	(*c != L'\0') {
					if ((*c == L'\\') || (*c == L'/')) {

						// Cannot have two adjacent slashes.
						if ((*(c - 1) == L'\\') || (*(c - 1) == L'/')) break;
					}
					c++;
				}
	
				// Parsed entire string?
				if (*c == L'\0') {
			
					// Check that path does not contain any illegal characters.
					if (wcscspn (((WideStringClass) path).Peek_Buffer(), L"*?<>|") == (size_t) path.Get_Length()) {

						WCHAR				 drive [_MAX_DRIVE + 1];
						WideStringClass directory;

						wcsncpy (drive, path, _MAX_DRIVE);
						drive [_MAX_DRIVE] = L'\0';
						directory = ((WideStringClass) path).Peek_Buffer() + _MAX_DRIVE;

						// Attempt to create (and then remove) the path.
						if (Create_Directory (drive, directory.Peek_Buffer(), directory.Peek_Buffer(), true, NULL)) {
							valid = true;	
						} else {
							errorcode = IDS_CANNOT_CREATE_DIRECTORY;
						}

					} else {
						errorcode = IDS_INVALID_PATH;
					}
				
				} else {
					errorcode = IDS_INVALID_PATH;
				}

			} else {
				errorcode = IDS_INVALID_PATH;
			}

		} else {
			errorcode = IDS_INVALID_PATH;
		}

	} else {
		errorcode = IDS_INVALID_PATH;
	}

	return (valid);
}


/***********************************************************************************************
 * Create_Directory --																								  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Create_Directory (const WideStringClass &path, DynamicVectorClass <StringClass> *log)
{
	WCHAR				 drive [_MAX_DRIVE + 1];
	WideStringClass directory;

	// NOTE: Assumes that path is a full path. If not, an error may be thrown.
	wcsncpy (drive, path, _MAX_DRIVE);
	drive [_MAX_DRIVE] = L'\0';
	directory = ((WideStringClass) path).Peek_Buffer() + _MAX_DRIVE;

	return (Create_Directory (drive, directory.Peek_Buffer(), directory.Peek_Buffer(), false, log));
}
	

/***********************************************************************************************
 * Create_Directory --																								  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Create_Directory (const WCHAR *drive, const WCHAR *directory, WCHAR *subdirectory, bool remove, DynamicVectorClass <StringClass> *log)
{
	bool				  valid;
	WCHAR				 *c, replacement;
	WideStringClass  path;
	StringClass		  multibytepath;
	DWORD				  errorcode;

	// If subdirectory is empty, we're done.
	c = subdirectory;
	if (*c != L'\0') {

		// Step down the subdirectory to the next slash or null.
		while ((*c != L'\\') && (*c != L'/') && (*c != L'\0')) c++;
		replacement = *c;
		*c = L'\0';

		path  = drive;
		path += directory;

		path.Convert_To (multibytepath);
		if (CreateDirectory (multibytepath, NULL)) {
			errorcode = 0;
			if (log != NULL) log->Add (multibytepath);
		} else {
			errorcode = GetLastError();
		}
		
		// If no error or directory already exists...
		if ((errorcode == 0) || (errorcode == ERROR_ALREADY_EXISTS)) {

			// Recurse if not at end of string.
			if (replacement != L'\0') {
				*c = replacement;
				valid = Create_Directory (drive, directory, c + 1, remove, log);
			} else {
				valid = true;
			}

			// If caller wants it removed (and it didn't already exist) then remove it (ie. just verify that it can be created).
			if (remove && (errorcode == 0)) {
				if (!RemoveDirectory (multibytepath)) FATAL_SYSTEM_ERROR;
			}
		
		} else {
			valid = false;
		}

	} else {
		valid = true;
	}
		
	return (valid);
}


/***********************************************************************************************
 * Cluster_Padding --																								  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
__int64 Cluster_Padding (unsigned filecount)
{
	// NOTE: Currently, it is not known how to obtain (or if it is possible to obtain) the cluster size
	//			of a hard disk. According to MS documentation, the largest possible cluster size of FAT16,
	//			FAT32 and NTFS file systems is 64K (and is more typically 4-16K). Therefore, conservatively
	//			estimate the cluster size as 64K.

	const unsigned clustersize = 0x10000;

	__int64 padding = clustersize * filecount;
	return (padding);
}


/***********************************************************************************************
 * Is_Same_Path --																										  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Is_Same_Path (const WideStringClass &path0, const WideStringClass &path1, bool standardize)
{
	if (standardize) {

		WideStringClass path0copy, path1copy;
		
		Standardize_Path (path0, path0copy);
		Standardize_Path (path1, path1copy);
		return (path0copy.Compare (path1copy) == 0);
	} else {
		return (path0.Compare (path1) == 0);
	}
}


/***********************************************************************************************
 * Is_Sub_Path --																										  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Is_Sub_Path (const WideStringClass &path0, const WideStringClass &path1, bool standardize)
{
	WideStringClass path0copy, path1copy;

	if (standardize) {
		Standardize_Path (path0, path0copy);
		Standardize_Path (path1, path1copy);
	} else {
		path0copy = path0;
		path1copy = path1;
	}

	if	(wcsstr (path0copy, path1copy) != NULL) {

		if (path0copy.Get_Length() == path1copy.Get_Length()) {
		
			return (true);
		
		} else {
	
			WCHAR c;

			c = path0copy [path1copy.Get_Length()];
			if ((c == L'\\') || (c == L'/')) return (true);
		}
	}

	return (false);
}


/***********************************************************************************************
 * Standardize_Path --																								  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
WCHAR *Standardize_Path (const WideStringClass &path, WideStringClass &standardpath)
{
	WideStringClass t (path);
	int				 i, c;

	// Remove leading white space.
	i = 0;
	while (t [i] == L' ') {
		i++;
	}
	if (i > 0) t.Erase (0, i);

	// Remove trailing white space and any trailing slashes.
	c = 0;
	i = t.Get_Length() - 1;
	while ((i >= 0) && ((t [i] == L' ') || (t [i] == L'\\') || (t [i] == L'/'))) {
		i--;
		c++;
	}
	if (c > 0) t.Erase (i + 1, c);

	// Replace back slashes with forward slashes and change to upper case.
	for (i = 0; i < t.Get_Length(); i++) {
		if (t [i] == L'/') t [i] = L'\\';
		t [i] = towupper (t [i]);
	}

	standardpath = t;
	return (standardpath.Peek_Buffer());
}


/***********************************************************************************************
 * Remove_Trailing_Name --																							  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
WCHAR *Remove_Trailing_Name (WideStringClass &path)
{
	int i, c;

	for (i = path.Get_Length() - 1, c = 1; i >= 0; i--, c++) {
		if ((path [i] == L'\\') || (path [i] == L'/')) {
			path.Erase (i, c);
			break;
		}
	}
	return (path.Peek_Buffer());
}


/***********************************************************************************************
 * Extract_Suffix_Root --																							  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
WCHAR *Extract_Suffix_Root (WideStringClass &path, const WideStringClass &prefixpath)
{
	if (wcsstr (path, prefixpath) == path) {

		int s, e, c;
		
		s = prefixpath.Get_Length();
		if ((path [s] == L'\\') || (path [s] == L'/')) s++;
		if (s > 0) path.Erase (0, s);
		e = 0;
		c = path.Get_Length();
		for (e = 0, c = path.Get_Length(); c > 0; e++, c--) { 
			if ((path [e] == L'\\') || (path [e] == L'/')) {
				path.Erase (e, c);
				break;
			}
		}
		return (path.Peek_Buffer());
	}
	return (NULL);
}


/***********************************************************************************************
 * Extract_Trailing_Name --																						  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
WCHAR *Extract_Trailing_Name (WideStringClass &path)
{
	int i;

	for (i = path.Get_Length() - 1; i >= 0; i--) {
		if ((path [i] == L'\\') || (path [i] == L'/')) {
			path.Erase (0, i + 1);
			break;
		}
	}
	return (path.Peek_Buffer());
}


/***********************************************************************************************
 * Directory_Exists --																								  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Directory_Exists (const WideStringClass &path)
{
	StringClass multibytepath (path);
	DWORD			errorcode;

	if (CreateDirectory (multibytepath, NULL)) {
		errorcode = 0; 
	} else {
		errorcode = GetLastError();
	}
	
	if (errorcode == 0) {
		if (!RemoveDirectory (multibytepath)) FATAL_SYSTEM_ERROR;
		return (false);
	} else {
		return (errorcode == ERROR_ALREADY_EXISTS);
	}
}


/***********************************************************************************************
 * Is_System_Directory --																							  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Is_System_Directory (const WideStringClass &path)
{
	const int DirectoryTypes [] = {

		CSIDL_DESKTOP,							// 0x0000 <user name>\desktop
		CSIDL_PROGRAMS,						// 0x0002 <user name>\Start Menu\Programs
		CSIDL_PERSONAL,						// 0x0005 <user name>\Start Menu\My Documents
		CSIDL_FAVORITES,						// 0x0006 <user name>Favorites
		CSIDL_STARTUP,							// 0x0007 <user name>\Start Menu\Programs\Startup
		CSIDL_RECENT,							// 0x0008 <user name>\Recent
		CSIDL_SENDTO,							// 0x0009 <user name>\SendTo
		CSIDL_STARTMENU,						// 0x000b <user name>\Start Menu
		CSIDL_DESKTOPDIRECTORY,				// 0x0010 <user name>\Desktop
		CSIDL_NETHOOD,							// 0x0013 <user name>\nethood
		CSIDL_FONTS,							// 0x0014 windows\fonts
		CSIDL_TEMPLATES,						// 0x0015 <user name>\Templates
		CSIDL_COMMON_STARTMENU,				// 0x0016 All Users\Start Menu
		CSIDL_COMMON_PROGRAMS,				// 0X0017 All Users\Start Menu\Programs
		CSIDL_COMMON_STARTUP,				// 0x0018 All Users\Start Menu\Programs\Startup
		CSIDL_COMMON_DESKTOPDIRECTORY,	// 0x0019 All Users\Desktop
		CSIDL_APPDATA,							// 0x001a <user name>\Application Data
		CSIDL_PRINTHOOD,						// 0x001b <user name>\PrintHood
		CSIDL_COMMON_FAVORITES,				// 0x001f All Users\Favorites
		CSIDL_INTERNET_CACHE,				// 0x0020 <user name>\Local Settings\Temporary Internet Files
		CSIDL_COOKIES,							// 0x0021 <user name>\Cookies
		CSIDL_HISTORY							// 0x0022 <user name>\Local Settings\History
	};

	char				 multibytesystempath [_MAX_PATH];
	WideStringClass systempath;
	bool				 result;
	HINSTANCE		 hinstLib; 

	// Test for Windows directory.
	if (!GetWindowsDirectory (multibytesystempath, _MAX_PATH)) FATAL_SYSTEM_ERROR;
	systempath = multibytesystempath;
	if (Is_Sub_Path (path, systempath)) return (true);

	//	 Test for System directory.
	if (!GetSystemDirectory (multibytesystempath, _MAX_PATH)) FATAL_SYSTEM_ERROR;
	systempath = multibytesystempath;
	if (Is_Sub_Path (path, systempath)) return (true);

   // Get a handle to the DLL module.
   result = false;
	hinstLib = LoadLibrary ("shfolder.dll"); 
	if (hinstLib != NULL) { 

		HRESULT (__stdcall * PFNSHGETFOLDERPATHA)(HWND, int, HANDLE, DWORD, LPSTR);
		PFNSHGETFOLDERPATHA = ( HRESULT ( __stdcall * )(HWND, int, HANDLE, DWORD, LPSTR)) GetProcAddress( hinstLib, "SHGetFolderPathA" );

		if (PFNSHGETFOLDERPATHA != NULL) {

			HRESULT hr = 0;

			for (int i = 0; i < sizeof (DirectoryTypes) / sizeof(int); i++) {			

				// Get each of the known directories above and compare to the desired directory.
				hr = (*PFNSHGETFOLDERPATHA)( NULL, DirectoryTypes [i], NULL, 0, multibytesystempath);
				if (hr == S_OK) {
					systempath = multibytesystempath;
					if (Is_Sub_Path (path, systempath)) {
						result = true;
						break;
					}
				}
			}
    	}

		// Free the DLL module.
		FreeLibrary (hinstLib); 
	}
	
	return (result);
}


/***********************************************************************************************
 * Get_Current_Directory --																						  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
void Get_Current_Directory (WideStringClass &path)
{
	StringClass multibytepath;

	if (!GetCurrentDirectory (_MAX_PATH, multibytepath.Get_Buffer (MAX_PATH))) FATAL_SYSTEM_ERROR;
	path = multibytepath;
}


/***********************************************************************************************
 * Generate_Temporary_Pathname --																				  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
bool Generate_Temporary_Pathname (const WideStringClass &path, StringClass &multibytetemporarypathname)
{
	StringClass multibytepath;

	// Create temporary file.
	multibytepath = path;
	if (!GetTempFileName (multibytepath, "XXX", 0, multibytetemporarypathname.Get_Buffer (_MAX_PATH))) return (false);
	return (true);
}


/***********************************************************************************************
 * Message_Box --																										  *
 *                                                                                             *
 * INPUT:                                                                                      *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/22/01    IML : Created.                                                                * 
 *=============================================================================================*/
void Message_Box (const WideStringClass &header, const WideStringClass &errormessage)
{
	ShowCursor (true);
	MessageBoxExW (NULL, ((WideStringClass) errormessage).Peek_Buffer(), ((WideStringClass) header).Peek_Buffer(), MB_OK | MB_APPLMODAL | MB_SETFOREGROUND, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT));
	ShowCursor (false);
}


