windows-nt/Source/XPSP1/NT/base/remoteboot/rbsetup/client/main.cpp
2020-09-26 16:20:57 +08:00

779 lines
22 KiB
C++

/****************************************************************************
Copyright (c) Microsoft Corporation 1997
All rights reserved
***************************************************************************/
#include "pch.h"
#include <windowsx.h>
#include <setupapi.h>
#include <advpub.h>
#include <regstr.h>
#include <lm.h>
#include "utils.h"
DEFINE_MODULE("Main");
// Globals
HINSTANCE g_hinstance = NULL;
#define SMALL_BUFFER_SIZE 256
#define MAX_FILES_SIZE 512
#define STRING_BUFFER_SIZE 65535
static TCHAR g_szServerName[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szRemoteBoot[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szBootFilename[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szBootIniOptions[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szClientName[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szMAC[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szInstallation[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szClientDomain[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szAdminUser[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szAdminPasswd[ SMALL_BUFFER_SIZE ] = { 0 };
static TCHAR g_szWinntTemplate[ SMALL_BUFFER_SIZE ] = { 0 };
// search and replace structure
typedef struct {
LPTSTR pszToken;
LPTSTR pszString;
} SAR, * LPSAR;
//
// Searches and replaces text.
//
// NOTE: There is no check for writing beyond the buffer even though
// I passed the paramater.
//
void
SearchAndReplace(
LPSAR psarList,
LPTSTR pszString,
DWORD dwSize )
{
LPTSTR psz = pszString;
if ( !psarList || !pszString )
return;
while ( *psz )
{
if ( *psz == TEXT('%') )
{
LPSAR psar = psarList;
psz++; // move forward
while( psar->pszToken )
{
int iCmp;
DWORD dwString = lstrlen( psar->pszString );
DWORD dwToken = lstrlen( psar->pszToken );
LPTSTR pszTemp = psz + dwToken;
TCHAR ch = *pszTemp;
*pszTemp = 0;
iCmp = lstrcmpi( psz, psar->pszToken );
*pszTemp = ch;
if ( !iCmp )
{ // match, so replace
psz--; // move back
if ( 2 + dwToken < dwString )
{
DWORD dwLen = lstrlen( &psz[ 2 + dwToken ] ) + 1;
MoveMemory( &psz[ dwString ], &psz[ 2 + dwToken ], dwLen * sizeof(TCHAR));
}
CopyMemory( psz, psar->pszString, dwString * sizeof(TCHAR) );
if ( 2 + dwToken > dwString )
{
lstrcpy( &psz[ dwString ], &psz[ 2 + dwToken ] );
}
psz++; // move forward
break;
}
psar++;
}
}
else
{
psz++;
}
}
}
//
// Munge the registry
//
LONG
MungeRegistry(
LPCTSTR pszPath,
LPCTSTR pszKey,
LPTSTR pszResult,
LPDWORD pdwSize )
{
HKEY hkeyComputer;
LONG lResult;
lResult = RegOpenKey( HKEY_LOCAL_MACHINE,
pszPath,
&hkeyComputer );
if ( lResult != ERROR_SUCCESS )
goto Finish;
lResult = RegQueryValueEx( hkeyComputer,
pszKey,
NULL, // reserved
NULL, // type
(LPBYTE) pszResult,
pdwSize );
RegCloseKey( hkeyComputer );
Finish:
return lResult;
}
//
// Munges the registry for the computer name
//
LONG
RetrieveComputerName( void )
{
DWORD dwSize = sizeof( g_szServerName );
return MungeRegistry( REGSTR_PATH_COMPUTRNAME,
REGSTR_VAL_COMPUTERNAME,
g_szServerName,
&dwSize );
}
//
// Populates the Installation ComboBox
//
HRESULT
PopulateInstallationComboBox(
HWND hDlg )
{
BOOL fKeepSearching = TRUE;
HRESULT hr = S_OK;
TCHAR szPath[ MAX_PATH ];
DWORD dwLen;
WIN32_FIND_DATA fd;
HANDLE handle;
HWND hwndCB = GetDlgItem( hDlg, IDC_CB_INSTALLATION );
LPSHARE_INFO_2 psi = NULL;
NetShareGetInfo( NULL, // this machine
g_szRemoteBoot,
2, // share level 2
(LPBYTE *) &psi );
// create the directory
lstrcpy( szPath, psi->shi2_path );
dwLen = lstrlen( szPath );
szPath[ dwLen++ ] = TEXT('\\');
LoadString( g_hinstance, IDS_SETUP, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen );
dwLen = lstrlen( szPath );
lstrcpy( &szPath[ dwLen ], TEXT("\\*") );
handle = FindFirstFile( szPath, &fd );
if ( handle == INVALID_HANDLE_VALUE )
goto Cleanup;
while ( fKeepSearching)
{
if ( fd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY &&
lstrcmp( fd.cFileName, TEXT(".") ) && // ignore
lstrcmp( fd.cFileName, TEXT("..") ) ) // ignore
{
ComboBox_AddString( hwndCB, fd.cFileName );
}
fKeepSearching = FindNextFile( handle, &fd );
}
ComboBox_SetCurSel( hwndCB, 0 );
Cleanup:
if ( handle != INVALID_HANDLE_VALUE)
FindClose( handle );
if ( psi )
NetApiBufferFree( psi );
return hr;
}
//
// Populates the Configuration ComboBox
//
HRESULT
PopulateConfigurationComboBox(
HWND hDlg )
{
BOOL fKeepSearching = TRUE;
HRESULT hr = S_OK;
TCHAR szPath[ MAX_PATH ];
DWORD dwLen;
WIN32_FIND_DATA fd;
HANDLE handle;
HWND hwndCB = GetDlgItem( hDlg, IDC_CB_WINNTSIF );
LPSHARE_INFO_2 psi = NULL;
int iSel;
ComboBox_ResetContent( hwndCB );
NetShareGetInfo( NULL, // this machine
g_szRemoteBoot,
2, // share level 2
(LPBYTE *) &psi );
// create the directory
lstrcpy( szPath, psi->shi2_path );
dwLen = lstrlen( szPath );
szPath[ dwLen++ ] = TEXT('\\');
LoadString( g_hinstance, IDS_TEMPLATES, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen );
dwLen = lstrlen( szPath );
szPath[ dwLen++ ] = TEXT('\\');
LoadString( g_hinstance, IDS_INTELPATH, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen );
dwLen = lstrlen( szPath );
szPath[ dwLen++ ] = TEXT('\\');
LoadString( g_hinstance, IDS_WINNTTEMPLATEFILES, &szPath[ dwLen ], ARRAYSIZE( szPath ) - dwLen );
handle = FindFirstFile( szPath, &fd );
if ( handle == INVALID_HANDLE_VALUE )
goto Cleanup;
while ( fKeepSearching)
{
// whack it at the period
LPTSTR psz = fd.cFileName;
while ( *psz )
{
if ( *psz == TEXT('.') )
{
*psz = 0;
break;
}
psz++;
}
ComboBox_AddString( hwndCB, fd.cFileName );
fKeepSearching = FindNextFile( handle, &fd );
}
ComboBox_SetCurSel( hwndCB, 0 );
Cleanup:
if ( handle != INVALID_HANDLE_VALUE)
FindClose( handle );
if ( psi )
NetApiBufferFree( psi );
return hr;
}
//
//
//
BOOL CALLBACK
ClientDlgProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam )
{
NMHDR FAR *lpnmhdr;
DWORD dw;
switch ( uMsg )
{
case WM_INITDIALOG:
CenterDialog( hDlg );
SetDlgItemText( hDlg, IDC_E_SERVER, g_szServerName );
SetDlgItemText( hDlg, IDC_E_REMOTEBOOT, g_szRemoteBoot );
SetDlgItemText( hDlg, IDC_E_BOOTFILENAME, g_szBootFilename );
SetDlgItemText( hDlg, IDC_E_BOOTINIOPTIONS, g_szBootIniOptions);
PopulateInstallationComboBox( hDlg );
PopulateConfigurationComboBox( hDlg );
Edit_LimitText( GetDlgItem( hDlg, IDC_E_MAC ), 12 );
break;
case WM_COMMAND:
{
switch ( LOWORD( wParam ) )
{
case IDOK:
{
DWORD dwLen;
TCHAR sz[ SMALL_BUFFER_SIZE ];
GetDlgItemText( hDlg, IDC_E_SERVER, g_szServerName, ARRAYSIZE( g_szServerName ));
GetDlgItemText( hDlg, IDC_E_REMOTEBOOT, g_szRemoteBoot, ARRAYSIZE( g_szRemoteBoot ));
GetDlgItemText( hDlg, IDC_E_BOOTFILENAME, g_szBootFilename, ARRAYSIZE( g_szBootFilename ));
GetDlgItemText( hDlg, IDC_E_BOOTINIOPTIONS, g_szBootIniOptions, ARRAYSIZE( g_szBootIniOptions ));
GetDlgItemText( hDlg, IDC_E_MAC, g_szMAC, ARRAYSIZE( g_szMAC ));
GetDlgItemText( hDlg, IDC_E_MACHINENAME, g_szClientName, ARRAYSIZE( g_szClientName ));
GetDlgItemText( hDlg, IDC_CB_INSTALLATION, g_szInstallation, ARRAYSIZE( g_szInstallation ));
GetDlgItemText( hDlg, IDC_E_CLIENTDOMAIN, g_szClientDomain, ARRAYSIZE( g_szClientDomain ));
GetDlgItemText( hDlg, IDC_E_ADMINUSER, g_szAdminUser, ARRAYSIZE( g_szAdminUser ));
GetDlgItemText( hDlg, IDC_E_ADMINPASSWD, g_szAdminPasswd, ARRAYSIZE( g_szAdminPasswd ));
GetDlgItemText( hDlg, IDC_CB_WINNTSIF, g_szWinntTemplate, ARRAYSIZE( g_szWinntTemplate ));
// add that extension
dw = LoadString( g_hinstance, IDS_WINNTTEMPLATEFILES, sz, ARRAYSIZE( sz ));
Assert( dw );
dwLen = lstrlen( g_szWinntTemplate );
lstrcpy( &g_szWinntTemplate[ dwLen ], &sz[ 1 ] );
EndDialog( hDlg, IDOK );
}
break;
case IDCANCEL:
EndDialog( hDlg, IDCANCEL );
break;
}
}
break;
default:
return FALSE;
}
return TRUE;
}
//
// change semicolon delinated list to double-null list
//
void
SemiColonToDoubleNullList( LPTSTR pszList )
{
while ( *pszList )
{
if ( *pszList == TEXT(';') )
{
*pszList = 0;
}
pszList++;
}
pszList++;
*pszList = 0; // double the null.
}
//
// Adds files to the Queue to be copied. It returns the number of files added
// to the Queue.
//
DWORD
CopyFilesAddToQueue(
HSPFILEQ Queue, // setup Queue
LPTSTR pszSource,
LPTSTR pszDest,
LPTSTR pszFiles, // Double-null terminated file list
LPTSTR pszSubpath ) // optional sub-path
{
DWORD dwCount = 0;
LPTSTR psz = pszFiles;
while ( *pszFiles )
{
DWORD dwLen;
// check for comma which indicates rename
psz = pszFiles;
while (*psz && *psz != TEXT(','))
psz++;
if ( *psz == TEXT(',') )
{
*psz= 0; // terminate
psz++;
}
else
{ // sources name is dest name
psz = pszFiles;
}
SetupQueueCopy(
Queue,
pszSource,
NULL,
pszFiles,
NULL,
NULL,
pszDest,
psz,
SP_COPY_NEWER | SP_COPY_NOOVERWRITE | SP_COPY_WARNIFSKIP );
// get next file
pszFiles = psz + lstrlen( psz ) + 1;
dwCount++;
}
return dwCount;
}
//
//
//
HRESULT
SetupClient( )
{
HRESULT hr = E_FAIL;
TCHAR szImage[ MAX_PATH ];
TCHAR szSetup[ MAX_PATH ];
TCHAR szTemplates[ MAX_PATH ];
TCHAR szBootIni[ MAX_PATH ];
TCHAR szString[ MAX_PATH ];
TCHAR szDosNetFilename[ MAX_PATH ];
TCHAR szWinntSif[ MAX_PATH ];
DWORD dwLen;
DWORD dw;
HSPFILEQ Queue;
PVOID pContext;
HANDLE hFile = INVALID_HANDLE_VALUE;
HKEY hkeyBINL;
HKEY hkeyMAC;
LPTSTR pszFiles = (LPTSTR) TraceAlloc( GMEM_FIXED, MAX_FILES_SIZE );
LPTSTR psz = NULL;
LPSHARE_INFO_2 psi = NULL;
LPVOID args[ 6 ];
SAR sExpand[] = {
{ TEXT("BINLSERVER"), g_szServerName },
{ TEXT("INSTALLATION"), g_szInstallation },
{ TEXT("CLIENTNAME"), g_szClientName },
{ TEXT("REMOTEBOOT"), g_szRemoteBoot },
{ TEXT("CLIENTDOMAIN"), g_szClientDomain },
{ TEXT("ADMINUSER"), g_szAdminUser },
{ TEXT("ADMINPASSWD"), g_szAdminPasswd },
{ NULL, NULL } // end of list
};
char chString[ STRING_BUFFER_SIZE ];
NetShareGetInfo( NULL, // this machine
g_szRemoteBoot,
2, // share level 2
(LPBYTE *) &psi );
// create the directory
lstrcpy( szImage, psi->shi2_path );
dwLen = lstrlen( szImage );
szImage[ dwLen++ ] = TEXT('\\');
dw = LoadString( g_hinstance, IDS_IMAGES, &szImage[ dwLen ], ARRAYSIZE( szImage ) - dwLen );
Assert( dw );
dwLen = lstrlen( szImage );
szImage[ dwLen++ ] = TEXT('\\');
lstrcpy( &szImage[ dwLen ], g_szClientName );
CreateDirectory( szImage, NULL );
// setup path
lstrcpy( szSetup, psi->shi2_path );
dwLen = lstrlen( szSetup );
szSetup[ dwLen++ ] = TEXT('\\');
dw = LoadString( g_hinstance, IDS_SETUP, &szSetup[ dwLen ], ARRAYSIZE( szSetup ) - dwLen );
Assert( dw );
dwLen = lstrlen( szSetup );
szSetup[ dwLen++ ] = TEXT('\\');
lstrcpy( &szSetup[ dwLen ], g_szInstallation );
dwLen = lstrlen( szSetup );
szSetup[ dwLen++ ] = TEXT('\\');
dw = LoadString( g_hinstance, IDS_INTELPATH, &szSetup[ dwLen ], ARRAYSIZE( szSetup ) - dwLen );
Assert( dw );
// Create DOSNET.INF filepath
lstrcpy( szDosNetFilename, szSetup );
dwLen = lstrlen( szDosNetFilename );
szDosNetFilename[ dwLen ] = TEXT('\\');
dwLen++;
dw = LoadString( g_hinstance, IDS_DOSNETINFFILENAME,
&szDosNetFilename[ dwLen ], ARRAYSIZE( szDosNetFilename ) - dwLen );
Assert( dw );
Queue = SetupOpenFileQueue( );
// Retrieve the list of files from the INF and add to Queue
GetPrivateProfileSection( TEXT("RootBootFiles"), pszFiles, MAX_FILES_SIZE,
szDosNetFilename );
CopyFilesAddToQueue( Queue, szSetup, szImage, pszFiles, NULL );
// add additional files from resources
dw = LoadString( g_hinstance, IDS_FILESTOBECOPIED, pszFiles, MAX_FILES_SIZE );
Assert( dw );
SemiColonToDoubleNullList( pszFiles );
CopyFilesAddToQueue( Queue, szSetup, szImage, pszFiles, NULL );
// copy winnt.sif template
lstrcpy( szTemplates, psi->shi2_path );
dwLen = lstrlen( szTemplates );
szTemplates[ dwLen++ ] = TEXT('\\');
dw = LoadString( g_hinstance, IDS_TEMPLATES, &szTemplates[ dwLen ], ARRAYSIZE( szTemplates ) - dwLen );
Assert( dw );
dwLen = lstrlen( szTemplates );
szTemplates[ dwLen++ ] = TEXT('\\');
dw = LoadString( g_hinstance, IDS_INTELPATH, &szTemplates[ dwLen ], ARRAYSIZE( szTemplates ) - dwLen );
Assert( dw );
lstrcpy( pszFiles, g_szWinntTemplate );
dwLen = lstrlen( pszFiles );
pszFiles[ dwLen++ ] = TEXT(',');
dw = LoadString( g_hinstance, IDS_WINNTSIF, &pszFiles[ dwLen ], MAX_PATH );
Assert( dw );
SemiColonToDoubleNullList( pszFiles );
CopyFilesAddToQueue( Queue, szTemplates, szImage, pszFiles, NULL );
TraceFree( pszFiles );
pContext = SetupInitDefaultQueueCallback( NULL );
if (!SetupCommitFileQueue( NULL, Queue, SetupDefaultQueueCallback,
pContext ) )
goto Cleanup;
dw = LoadString( g_hinstance, IDS_REG_BINL_PARAMETER, szString, ARRAYSIZE( szString ));
Assert( dw );
if ( ERROR_SUCCESS ==
RegOpenKey( HKEY_LOCAL_MACHINE, szString, &hkeyBINL ) )
{
if ( ERROR_SUCCESS ==
RegCreateKey( hkeyBINL, g_szMAC, &hkeyMAC ) )
{
dw = LoadString( g_hinstance, IDS_IMAGES, szString, ARRAYSIZE( dw ));
Assert( dw );
dwLen = lstrlen( szString );
szString[ dwLen++ ] = TEXT('\\');
lstrcpy( &szString[ dwLen ], g_szClientName );
dwLen = lstrlen( szString );
szString[ dwLen++ ] = TEXT('\\');
lstrcpy( &szString[ dwLen ], g_szBootFilename );
dwLen = ( lstrlen( szString ) + 1 ) * sizeof(TCHAR);
RegSetValueEx( hkeyMAC, TEXT("BootFileName"), 0, REG_SZ, (LPBYTE) szString, dwLen );
dwLen = ( lstrlen( g_szServerName ) + 1 ) * sizeof(TCHAR);
RegSetValueEx( hkeyMAC, TEXT("HostName"), 0, REG_SZ, (LPBYTE) g_szServerName, dwLen );
RegCloseKey( hkeyMAC );
}
RegCloseKey( hkeyBINL );
}
// create MAC Address file
lstrcpy( szString, szImage );
dwLen = lstrlen( szString );
szString[ dwLen++ ] = TEXT('\\');
lstrcpy( &szString[ dwLen ], g_szMAC );
hFile = CreateFile( szString,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL, // security attribs
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, // maybe FILE_ATTRIBUTE_HIDDEN
NULL ); // template
CloseHandle( hFile );
lstrcpy( szBootIni, szImage );
dwLen = lstrlen( szBootIni );
szBootIni[ dwLen++ ] = TEXT('\\');
dw = LoadString( g_hinstance, IDS_BOOTINI, &szBootIni[ dwLen ], ARRAYSIZE( szBootIni ) - dwLen );
Assert( dw );
hFile = CreateFile( szBootIni,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL, // security attribs
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, // maybe FILE_ATTRIBUTE_HIDDEN
NULL ); // template
if ( hFile == INVALID_HANDLE_VALUE )
goto Cleanup;
dw = LoadString( g_hinstance, IDS_BOOTLOADER, szString, ARRAYSIZE( szString ));
Assert( dw );
args[0] = (LPVOID) &g_szServerName;
args[1] = (LPVOID) &g_szRemoteBoot;
args[2] = (LPVOID) &g_szClientName;
args[3] = (LPVOID) &g_szInstallation;
args[4] = (LPVOID) &g_szBootIniOptions;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
szString,
NULL, // message id - n/a
NULL, // language - use system
(LPTSTR) &psz,
0, // minimum length
(char **) &args );
DebugMemoryAddAddress( psz );
WideCharToMultiByte( CP_ACP, 0, psz, -1, chString, ARRAYSIZE( chString ), NULL, NULL );
dwLen = lstrlenA( chString );
WriteFile( hFile, chString, dwLen, &dw, NULL );
CloseHandle( hFile );
TraceFree( psz );
// process WINNT.SIF
lstrcpy( szWinntSif, szImage );
dwLen = lstrlen( szWinntSif );
szWinntSif[ dwLen++ ] = TEXT('\\');
dw = LoadString( g_hinstance, IDS_WINNTSIF, &szWinntSif[ dwLen ], ARRAYSIZE( szWinntSif ) - dwLen );
Assert( dw );
hFile = CreateFile( szWinntSif,
GENERIC_READ,
FILE_SHARE_READ,
NULL, // security attribs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, // maybe FILE_ATTRIBUTE_HIDDEN
NULL ); // template
if ( hFile == INVALID_HANDLE_VALUE )
goto Cleanup;
ReadFile( hFile, chString, ARRAYSIZE( chString ), &dw, NULL );
Assert( dw != ARRAYSIZE( chString ));
CloseHandle( hFile );
psz = (LPTSTR) TraceAlloc( GMEM_FIXED, ARRAYSIZE( chString ));
MultiByteToWideChar( CP_ACP, 0, chString, -1, psz, ARRAYSIZE( chString ));
SearchAndReplace( sExpand, psz, ARRAYSIZE( chString ));
hFile = CreateFile( szWinntSif,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL, // security attribs
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, // maybe FILE_ATTRIBUTE_HIDDEN
NULL ); // template
if ( hFile == INVALID_HANDLE_VALUE )
goto Cleanup;
WideCharToMultiByte( CP_ACP, 0, psz, -1, chString, ARRAYSIZE( chString ), NULL, NULL );
dwLen = lstrlenA( chString );
WriteFile( hFile, chString, dwLen, &dw, NULL );
CloseHandle( hFile );
TraceFree( psz );
hr = S_OK;
Cleanup:
if ( Queue )
SetupCloseFileQueue( Queue );
if ( psi )
NetApiBufferFree( psi );
return hr;
}
//
// WinMain()
//
int APIENTRY
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HANDLE hMutex;
HRESULT hr = S_OK;
DWORD dw;
g_hinstance = hInstance;
INITIALIZE_TRACE_MEMORY;
// Initialize
RetrieveComputerName( );
dw = LoadString( g_hinstance, IDS_REMOTEBOOT, g_szRemoteBoot, ARRAYSIZE( g_szRemoteBoot ));
Assert( dw );
dw = LoadString( g_hinstance, IDS_BOOTFILENAME, g_szBootFilename, ARRAYSIZE( g_szBootFilename ));
Assert( dw );
dw = LoadString( g_hinstance, IDS_BOOTINIOPTIONS, g_szBootIniOptions, ARRAYSIZE( g_szBootIniOptions ));
Assert( dw );
if ( IDOK == DialogBox( g_hinstance, MAKEINTRESOURCE( IDD_CLIENT ), NULL, ClientDlgProc ) )
{
if ( lstrlen( g_szMAC ) != 12 )
goto Cleanup;
if ( !lstrlen( g_szClientName ) )
goto Cleanup;
hr = SetupClient( );
}
Cleanup:
UNINITIALIZE_TRACE_MEMORY;
RRETURN(hr);
}
// stolen from the CRT, used to shrink our code
int _stdcall ModuleEntry(void)
{
int i;
STARTUPINFOA si;
LPSTR pszCmdLine = GetCommandLineA();
if ( *pszCmdLine == '\"' )
{
/*
* Scan, and skip over, subsequent characters until
* another double-quote or a null is encountered.
*/
while ( *++pszCmdLine && (*pszCmdLine != '\"') );
/*
* If we stopped on a double-quote (usual case), skip
* over it.
*/
if ( *pszCmdLine == '\"' )
pszCmdLine++;
}
else
{
while (*pszCmdLine > ' ')
pszCmdLine++;
}
/*
* Skip past any white space preceeding the second token.
*/
while (*pszCmdLine && (*pszCmdLine <= ' '))
{
pszCmdLine++;
}
si.dwFlags = 0;
GetStartupInfoA(&si);
i = WinMain(GetModuleHandle(NULL), NULL, pszCmdLine,
si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
ExitProcess(i);
return i; // We never come here.
}