534 lines
15 KiB
C++
534 lines
15 KiB
C++
|
//Copyright (c) 1998 - 1999 Microsoft Corporation
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* helpers.cpp
|
||
|
*
|
||
|
* WINCFG helper functions
|
||
|
*
|
||
|
* copyright notice: Copyright 1994, Citrix Systems Inc.
|
||
|
*
|
||
|
* $Author: thanhl $ Butch Davis
|
||
|
*
|
||
|
* $Log: N:\NT\PRIVATE\UTILS\CITRIX\WINUTILS\WINCFG\VCS\HELPERS.CPP $
|
||
|
*
|
||
|
* Rev 1.17 15 Jul 1997 17:08:36 thanhl
|
||
|
* Add support for Required PDs
|
||
|
*
|
||
|
* Rev 1.16 27 Jun 1997 15:58:34 butchd
|
||
|
* Registry changes for Wds/Tds/Pds/Cds
|
||
|
*
|
||
|
* Rev 1.15 19 Jun 1997 19:22:16 kurtp
|
||
|
* update
|
||
|
*
|
||
|
* Rev 1.14 28 Feb 1997 17:59:38 butchd
|
||
|
* update
|
||
|
*
|
||
|
* Rev 1.13 24 Sep 1996 16:21:42 butchd
|
||
|
* update
|
||
|
*
|
||
|
*******************************************************************************/
|
||
|
|
||
|
/*
|
||
|
* include files
|
||
|
*/
|
||
|
#include "stdafx.h"
|
||
|
#include "wincfg.h"
|
||
|
#include "optdlg.h"
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#undef THIS_FILE
|
||
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
extern CWincfgApp *pApp;
|
||
|
extern "C" LPCTSTR WinUtilsAppName;
|
||
|
extern "C" HWND WinUtilsAppWindow;
|
||
|
extern "C" HINSTANCE WinUtilsAppInstance;
|
||
|
|
||
|
/*
|
||
|
* Define global variables for command line parsing helper.
|
||
|
*/
|
||
|
USHORT g_help = FALSE;
|
||
|
USHORT g_RegistryOnly = FALSE;
|
||
|
USHORT g_Add = FALSE;
|
||
|
WDNAME g_szType = { TEXT("") };
|
||
|
PDNAME g_szTransport = { TEXT("") };
|
||
|
ULONG g_ulCount = 0;
|
||
|
|
||
|
USHORT g_Install = FALSE; // hidden switch to let us know we're invoked by Setup
|
||
|
USHORT g_Batch = FALSE; // TRUE if an auto-command was specified;
|
||
|
// FALSE otherwise
|
||
|
|
||
|
/*
|
||
|
* This is the structure vector to be sent to ParseCommandLine.
|
||
|
*/
|
||
|
TOKMAP tokenmap[] =
|
||
|
{
|
||
|
/*-------------------------------------------------------------------------
|
||
|
-- Retail Switches
|
||
|
-------------------------------------------------------------------------*/
|
||
|
{ HELP_SWITCH, TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &g_help },
|
||
|
|
||
|
{ REGISTRYONLY_SWITCH, TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &g_RegistryOnly },
|
||
|
|
||
|
{ ADD_SWITCH, TMFLAG_OPTIONAL, TMFORM_STRING, WDNAME_LENGTH, g_szType },
|
||
|
{ TRANSPORT_SWITCH, TMFLAG_OPTIONAL, TMFORM_STRING, PDNAME_LENGTH, g_szTransport },
|
||
|
{ COUNT_SWITCH, TMFLAG_OPTIONAL, TMFORM_ULONG, sizeof(ULONG), &g_ulCount },
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
-- Debug or Hidden switches
|
||
|
-------------------------------------------------------------------------*/
|
||
|
{ INSTALL_SWITCH, TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &g_Install },
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
-- POSITIONAL PARAMETERS
|
||
|
-------------------------------------------------------------------------*/
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
-- END OF LIST
|
||
|
-------------------------------------------------------------------------*/
|
||
|
{ NULL, 0, 0, 0, NULL }
|
||
|
};
|
||
|
TOKMAP *ptm = tokenmap;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// helper functions
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* CommandLineHelper - helper function
|
||
|
*
|
||
|
* Parse the command line for optional parameters. This routine will also
|
||
|
* handle the request for 'help' and invalid command line parameter.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pszCommandLine (input)
|
||
|
* Points to command line.
|
||
|
*
|
||
|
* EXIT:
|
||
|
* (BOOL) TRUE if command line was parsed sucessfully or if internal error
|
||
|
* (command line will be ignored).
|
||
|
* FALSE if 'help' requested or error on command line (message
|
||
|
* will have been output).
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
BOOL
|
||
|
CommandLineHelper( LPTSTR pszCommandLine )
|
||
|
{
|
||
|
int rc;
|
||
|
int argc;
|
||
|
TCHAR **argv;
|
||
|
TCHAR szModuleName[DIRECTORY_LENGTH+1];
|
||
|
|
||
|
/*
|
||
|
* Get command line args
|
||
|
*/
|
||
|
GetModuleFileName( AfxGetInstanceHandle(), szModuleName,
|
||
|
lengthof(szModuleName) );
|
||
|
if ( setargv( szModuleName, pszCommandLine, &argc, &argv ) ) {
|
||
|
|
||
|
ERROR_MESSAGE((IDP_ERROR_INTERNAL_SETARGV))
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Parse command line args and then free them.
|
||
|
*/
|
||
|
rc = ParseCommandLine( (argc-1), (argv+1), ptm, 0 );
|
||
|
freeargv( argv );
|
||
|
|
||
|
/*
|
||
|
* Check for command line errors or help requested
|
||
|
*/
|
||
|
if ( ((rc != PARSE_FLAG_NO_ERROR) &&
|
||
|
!(rc & PARSE_FLAG_NO_PARMS))
|
||
|
|| g_help ) {
|
||
|
|
||
|
if ( rc & PARSE_FLAG_NOT_ENOUGH_MEMORY ) {
|
||
|
|
||
|
ERROR_MESSAGE((IDP_ERROR_INTERNAL_PARSECOMMANDLINE))
|
||
|
goto done;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
CommandLineUsage();
|
||
|
return(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
/*
|
||
|
* If a batch auto command was specified, set batch flag.
|
||
|
*/
|
||
|
if ( (g_Add = IsTokenPresent(ptm, ADD_SWITCH)) )
|
||
|
g_Batch = TRUE;
|
||
|
|
||
|
/*
|
||
|
* Set for registry only or full registry & winstation APIs.
|
||
|
*/
|
||
|
pApp->m_nRegistryOnly = (int)g_RegistryOnly;
|
||
|
|
||
|
/*
|
||
|
* If add is defined and no count given, set count to 1.
|
||
|
*/
|
||
|
if ( g_Add && (g_ulCount == 0) )
|
||
|
g_ulCount = 1;
|
||
|
|
||
|
return(TRUE);
|
||
|
|
||
|
} // end CommandLineHelper
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* CommandLineUsage - helper function
|
||
|
*
|
||
|
* Handle the request for 'help' and invalid command line parameter.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* EXIT:
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void
|
||
|
CommandLineUsage()
|
||
|
{
|
||
|
COptionsDlg OPTDlg;
|
||
|
|
||
|
OPTDlg.DoModal();
|
||
|
|
||
|
} // end CommandLineUsage
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* QueryLoggedOnCount - helper function
|
||
|
*
|
||
|
* Query the specified WinStation(s) to determine how many users are
|
||
|
* currently logged on.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pWSName (input)
|
||
|
* Points to (root) name of WinStation to query. The query will
|
||
|
* match this name with those present in the ICA Server, including
|
||
|
* multi-instanced WinStations.
|
||
|
* EXIT:
|
||
|
* (long) # of users logged onto the specified WinStation(s).
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
long
|
||
|
QueryLoggedOnCount( PWINSTATIONNAME pWSName )
|
||
|
{
|
||
|
long LoggedOnCount = 0;
|
||
|
#ifdef WINSTA
|
||
|
ULONG Entries;
|
||
|
PLOGONID pLogonId;
|
||
|
TCHAR *p;
|
||
|
CWaitCursor wait;
|
||
|
|
||
|
WinStationEnumerate(SERVERNAME_CURRENT, &pLogonId, &Entries);
|
||
|
if ( pLogonId ) {
|
||
|
|
||
|
for ( ULONG i = 0; i < Entries; i++ ) {
|
||
|
|
||
|
/*
|
||
|
* Check active, connected, and shadowing WinStations, and increment
|
||
|
* the logged on count if the specified name matches the 'root'
|
||
|
* name of current winstation.
|
||
|
*/
|
||
|
if ( (pLogonId[i].State == State_Active) ||
|
||
|
(pLogonId[i].State == State_Connected) ||
|
||
|
(pLogonId[i].State == State_Shadow) ) {
|
||
|
|
||
|
if ( (p = lstrchr(pLogonId[i].WinStationName, TEXT('#'))) )
|
||
|
*p = TEXT('\0');
|
||
|
|
||
|
if ( !lstrcmpi(pWSName, pLogonId[i].WinStationName) )
|
||
|
LoggedOnCount++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WinStationFreeMemory(pLogonId);
|
||
|
}
|
||
|
#endif // WINSTA
|
||
|
|
||
|
/*
|
||
|
* Return the logged-on count.
|
||
|
*/
|
||
|
return(LoggedOnCount);
|
||
|
|
||
|
} // end QueryLoggedOnCount
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* LBInsertInstancedName - helper function
|
||
|
*
|
||
|
* Insert the specified 'instanced' name into the specified list box,
|
||
|
* using a special sort based on the 'root' name and 'instance' count.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pName (input)
|
||
|
* Pointer to name string to insert.
|
||
|
* pListBox (input)
|
||
|
* Pointer to CListBox object to insert name string into.
|
||
|
*
|
||
|
* EXIT:
|
||
|
* (int) List box list index of name after insertion, or error code.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
int
|
||
|
LBInsertInstancedName( LPCTSTR pName,
|
||
|
CListBox *pListBox )
|
||
|
{
|
||
|
int i, count, result;
|
||
|
TCHAR NameRoot[64], ListRoot[64];
|
||
|
CString ListString;
|
||
|
long NameInstance, ListInstance;
|
||
|
|
||
|
/*
|
||
|
* Form the root and instance for this name
|
||
|
*/
|
||
|
ParseRootAndInstance( pName, NameRoot, &NameInstance );
|
||
|
|
||
|
/*
|
||
|
* Traverse list box to perform insert.
|
||
|
*/
|
||
|
for ( i = 0, count = pListBox->GetCount(); i < count; i++ ) {
|
||
|
|
||
|
/*
|
||
|
* Fetch current list box string.
|
||
|
*/
|
||
|
pListBox->GetText( i, ListString );
|
||
|
|
||
|
/*
|
||
|
* Parse the root and instance of the list box string.
|
||
|
*/
|
||
|
ParseRootAndInstance( ListString, ListRoot, &ListInstance );
|
||
|
|
||
|
/*
|
||
|
* If the list box string's root is greater than the our name string's
|
||
|
* root, or the root strings are the same but the list instance is
|
||
|
* greater than the name string's instance, the name string belongs
|
||
|
* at the current instance: insert it there.
|
||
|
*/
|
||
|
if ( ((result = lstrcmpi( ListRoot, NameRoot )) > 0) ||
|
||
|
((result == 0) && (ListInstance > NameInstance)) )
|
||
|
return( pListBox->InsertString( i, pName ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Insert this name at the end of the list.
|
||
|
*/
|
||
|
return( pListBox->InsertString( -1, pName ) );
|
||
|
|
||
|
} // end LBInsertInstancedName
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* CBInsertInstancedName - helper function
|
||
|
*
|
||
|
* Insert the specified 'instanced' name into the specified combo box,
|
||
|
* using a special sort based on the 'root' name and 'instance' count.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pName (input)
|
||
|
* Pointer to name string to insert.
|
||
|
* pComboBox (input)
|
||
|
* Pointer to CComboBox object to insert name string into.
|
||
|
*
|
||
|
* EXIT:
|
||
|
* (int) Combo box list index of name after insertion, or error code.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
int
|
||
|
CBInsertInstancedName( LPCTSTR pName,
|
||
|
CComboBox *pComboBox )
|
||
|
{
|
||
|
int i, count, result;
|
||
|
TCHAR NameRoot[64], ListRoot[64];
|
||
|
CString ListString;
|
||
|
long NameInstance, ListInstance;
|
||
|
|
||
|
/*
|
||
|
* Form the root and instance for this name
|
||
|
*/
|
||
|
ParseRootAndInstance( pName, NameRoot, &NameInstance );
|
||
|
|
||
|
/*
|
||
|
* Traverse combo box to perform insert.
|
||
|
*/
|
||
|
for ( i = 0, count = pComboBox->GetCount(); i < count; i++ ) {
|
||
|
|
||
|
/*
|
||
|
* Fetch current combo (list) box string.
|
||
|
*/
|
||
|
pComboBox->GetLBText( i, ListString );
|
||
|
|
||
|
/*
|
||
|
* Parse the root and instance of the list box string.
|
||
|
*/
|
||
|
ParseRootAndInstance( ListString, ListRoot, &ListInstance );
|
||
|
|
||
|
/*
|
||
|
* If the list box string's root is greater than the our name string's
|
||
|
* root, or the root strings are the same but the list instance is
|
||
|
* greater than the name string's instance, or the root strings are
|
||
|
* the same and the instances are the same but the entire list string
|
||
|
* is greater than the entire name string, the name string belongs
|
||
|
* at the current list position: insert it there.
|
||
|
*/
|
||
|
if ( ((result = lstrcmpi( ListRoot, NameRoot )) > 0) ||
|
||
|
((result == 0) &&
|
||
|
(ListInstance > NameInstance)) ||
|
||
|
((result == 0) &&
|
||
|
(ListInstance == NameInstance) &&
|
||
|
(lstrcmpi(ListString, pName) > 0)) )
|
||
|
return( pComboBox->InsertString( i, pName ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Insert this name at the end of the list.
|
||
|
*/
|
||
|
return( pComboBox->InsertString( -1, pName ) );
|
||
|
|
||
|
} // end CBInsertInstancedName
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* ParseRootAndInstance - helper function
|
||
|
*
|
||
|
* Parse the 'root' string and instance count for a specified string.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pString (input)
|
||
|
* Points to the string to parse.
|
||
|
* pRoot (output)
|
||
|
* Points to the buffer to store the parsed 'root' string.
|
||
|
* pInstance (output)
|
||
|
* Points to the int variable to store the parsed instance count.
|
||
|
*
|
||
|
* EXIT:
|
||
|
* ParseRootAndInstance will parse only up to the first blank character
|
||
|
* of the string (if a blank exists).
|
||
|
* If the string contains no 'instance' count (no trailing digits), the
|
||
|
* pInstance variable will contain -1. If the string consists entirely
|
||
|
* of digits, the pInstance variable will contain the conversion of those
|
||
|
* digits and pRoot will contain a null string.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void
|
||
|
ParseRootAndInstance( LPCTSTR pString,
|
||
|
LPTSTR pRoot,
|
||
|
long *pInstance )
|
||
|
{
|
||
|
LPCTSTR end, p;
|
||
|
TCHAR szString[256];
|
||
|
|
||
|
/*
|
||
|
* Make a copy of the string and terminate at first blank (if present).
|
||
|
*/
|
||
|
lstrncpy(szString, pString, lengthof(szString));
|
||
|
szString[lengthof(szString)-1] = TEXT('\0');
|
||
|
lstrtok(szString, TEXT(" "));
|
||
|
p = &(szString[lstrlen(szString)-1]);
|
||
|
|
||
|
/*
|
||
|
* Parse the instance portion of the string.
|
||
|
*/
|
||
|
end = p;
|
||
|
while( (p >= szString) && islstrdigit(*p) )
|
||
|
p--;
|
||
|
|
||
|
if ( p == end ) {
|
||
|
|
||
|
/*
|
||
|
* No trailing digits: indicate no 'instance' and make the 'root'
|
||
|
* the whole string.
|
||
|
*/
|
||
|
*pInstance = -1;
|
||
|
lstrcpy( pRoot, szString );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
/*
|
||
|
* Trailing digits found (or entire string was digits): calculate
|
||
|
* 'instance' and copy the 'root' string (null if all digits).
|
||
|
*/
|
||
|
end = p;
|
||
|
*pInstance = (int)lstrtol( p+1, NULL, 10 );
|
||
|
|
||
|
/*
|
||
|
* Copy 'root' string.
|
||
|
*/
|
||
|
for ( p = szString; p <= end; pRoot++, p++ )
|
||
|
*pRoot = *p;
|
||
|
|
||
|
/*
|
||
|
* Terminate 'root' string.
|
||
|
*/
|
||
|
*pRoot = TEXT('\0');
|
||
|
}
|
||
|
|
||
|
} // end ParseRootAndInstance
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* GetPdConfig - helper function
|
||
|
*
|
||
|
* Read the PD config structure associated with the first PD in the PdList
|
||
|
* of the specified PD class.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* pPdList (input)
|
||
|
* Points to the Pd list for selected Wd type.
|
||
|
* PdName (input)
|
||
|
* Specifies the Pd name to look for.
|
||
|
* pWSConfig (input)
|
||
|
* Pointer to WINSTATIONCONFIG2 structure to reference for Pd[0]
|
||
|
* framing type (if SdClass == SdFrame). Can be NULL if SdClass
|
||
|
* != SdFrame.
|
||
|
* pPdConfig (output)
|
||
|
* Pointer to PDCONFIG3 structure to fill.
|
||
|
* EXIT:
|
||
|
* nothing
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void
|
||
|
GetPdConfig( CObList *pPdList,
|
||
|
LPCTSTR PdName,
|
||
|
PWINSTATIONCONFIG2 pWSConfig,
|
||
|
PPDCONFIG3 pPdConfig )
|
||
|
{
|
||
|
POSITION pos;
|
||
|
PPDLOBJECT pObject;
|
||
|
BOOL bFound = FALSE;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Traverse the PD list and obtain the specified Pd's key string for query.
|
||
|
*/
|
||
|
for ( pos = pPdList->GetHeadPosition(); pos != NULL; ) {
|
||
|
|
||
|
pObject = (PPDLOBJECT)pPdList->GetNext(pos);
|
||
|
|
||
|
if ( !lstrcmp(pObject->m_PdConfig.Data.PdName, PdName ) ) {
|
||
|
bFound = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( bFound )
|
||
|
*pPdConfig = pObject->m_PdConfig;
|
||
|
|
||
|
} // end GetPdConfig
|