mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1387 lines
38 KiB
1387 lines
38 KiB
|
|
/*************************************************************************
|
|
*
|
|
* query.c
|
|
*
|
|
* Query Register APIs
|
|
*
|
|
* Copyright (c) 1998 Microsoft Corporation
|
|
*
|
|
*
|
|
*************************************************************************/
|
|
|
|
/*
|
|
* Includes
|
|
*/
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <windows.h>
|
|
|
|
#include <ntddkbd.h>
|
|
#include <ntddmou.h>
|
|
#include <winstaw.h>
|
|
#include <regapi.h>
|
|
|
|
|
|
/*
|
|
* Procedures defined
|
|
*/
|
|
VOID QueryWinStaCreate( HKEY, PWINSTATIONCREATE );
|
|
VOID QueryUserConfig( HKEY, PUSERCONFIG );
|
|
VOID QueryConfig( HKEY, PWINSTATIONCONFIG );
|
|
VOID QueryNetwork( HKEY, PNETWORKCONFIG );
|
|
VOID QueryNasi( HKEY, PNASICONFIG );
|
|
VOID QueryAsync( HKEY, PASYNCCONFIG );
|
|
VOID QueryOemTd( HKEY, POEMTDCONFIG );
|
|
VOID QueryFlow( HKEY, PFLOWCONTROLCONFIG );
|
|
VOID QueryConnect( HKEY, PCONNECTCONFIG );
|
|
VOID QueryCd( HKEY, PCDCONFIG );
|
|
VOID QueryWd( HKEY, PWDCONFIG );
|
|
VOID QueryPdConfig( HKEY, PPDCONFIG, PULONG );
|
|
VOID QueryPdConfig2( HKEY, PPDCONFIG2, ULONG );
|
|
VOID QueryPdConfig3( HKEY, PPDCONFIG3, ULONG );
|
|
VOID QueryPdParams( HKEY, SDCLASS, PPDPARAMS );
|
|
BOOLEAN WINAPI RegBuildNumberQuery( PULONG );
|
|
BOOLEAN RegQueryOEMId( PBYTE, ULONG );
|
|
BOOLEAN WINAPI RegGetCitrixVersion(WCHAR *, PULONG);
|
|
|
|
BOOLEAN IsWallPaperDisabled( HKEY );
|
|
|
|
/*
|
|
* procedures used
|
|
*/
|
|
DWORD GetNumValue( HKEY, LPWSTR, DWORD );
|
|
DWORD GetNumValueEx( HKEY, LPWSTR, DWORD, DWORD );
|
|
LONG GetStringValue( HKEY, LPWSTR, LPWSTR, LPWSTR, DWORD );
|
|
LONG GetStringValueEx( HKEY, LPWSTR, DWORD, LPWSTR, LPWSTR, DWORD );
|
|
VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * );
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryWinStaCreate
|
|
*
|
|
* query WINSTATIONCREATE structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pCreate (output)
|
|
* address to return WINSTATIONCREATE structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryWinStaCreate( HKEY Handle,
|
|
PWINSTATIONCREATE pCreate )
|
|
{
|
|
pCreate->fEnableWinStation = (BOOLEAN) GetNumValue( Handle,
|
|
WIN_ENABLEWINSTATION,
|
|
TRUE );
|
|
pCreate->MaxInstanceCount = GetNumValue( Handle,
|
|
WIN_MAXINSTANCECOUNT,
|
|
1 );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryUserConfig
|
|
*
|
|
* query USERCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pUser (input)
|
|
* pointer to USERCONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryUserConfig( HKEY Handle,
|
|
PUSERCONFIG pUser )
|
|
{
|
|
UCHAR seed;
|
|
UNICODE_STRING UnicodePassword;
|
|
WCHAR encPassword[ PASSWORD_LENGTH + 2 ];
|
|
|
|
pUser->fInheritAutoLogon =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITAUTOLOGON, TRUE );
|
|
|
|
pUser->fInheritResetBroken =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITRESETBROKEN, TRUE );
|
|
|
|
pUser->fInheritReconnectSame =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITRECONNECTSAME, TRUE );
|
|
|
|
pUser->fInheritInitialProgram =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITINITIALPROGRAM, TRUE );
|
|
|
|
pUser->fInheritCallback =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITCALLBACK, FALSE );
|
|
|
|
pUser->fInheritCallbackNumber =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITCALLBACKNUMBER, TRUE );
|
|
|
|
pUser->fInheritShadow =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITSHADOW, TRUE );
|
|
|
|
pUser->fInheritMaxSessionTime =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITMAXSESSIONTIME, TRUE );
|
|
|
|
pUser->fInheritMaxDisconnectionTime =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITMAXDISCONNECTIONTIME, TRUE );
|
|
|
|
pUser->fInheritMaxIdleTime =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITMAXIDLETIME, TRUE );
|
|
|
|
pUser->fInheritAutoClient =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITAUTOCLIENT, TRUE );
|
|
|
|
pUser->fInheritSecurity =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITSECURITY, FALSE );
|
|
|
|
//NA 2/23/01
|
|
pUser->fInheritColorDepth =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_INHERITCOLORDEPTH, TRUE );
|
|
|
|
pUser->fPromptForPassword =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_PROMPTFORPASSWORD, FALSE );
|
|
|
|
pUser->fResetBroken =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_RESETBROKEN, FALSE );
|
|
|
|
pUser->fReconnectSame =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_RECONNECTSAME, FALSE );
|
|
|
|
pUser->fLogonDisabled =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_LOGONDISABLED, FALSE );
|
|
|
|
pUser->fAutoClientDrives =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_AUTOCLIENTDRIVES, TRUE );
|
|
|
|
pUser->fAutoClientLpts =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_AUTOCLIENTLPTS, TRUE );
|
|
|
|
pUser->fForceClientLptDef =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_FORCECLIENTLPTDEF, TRUE );
|
|
|
|
pUser->fDisableEncryption =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_DISABLEENCRYPTION, TRUE );
|
|
|
|
pUser->fHomeDirectoryMapRoot =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_HOMEDIRECTORYMAPROOT, FALSE );
|
|
|
|
pUser->fUseDefaultGina =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_USEDEFAULTGINA, FALSE );
|
|
|
|
pUser->fDisableCpm =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_DISABLECPM, FALSE );
|
|
|
|
pUser->fDisableCdm =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_DISABLECDM, FALSE );
|
|
|
|
pUser->fDisableCcm =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_DISABLECCM, FALSE );
|
|
|
|
pUser->fDisableLPT =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_DISABLELPT, FALSE );
|
|
|
|
pUser->fDisableClip =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_DISABLECLIP, FALSE );
|
|
|
|
pUser->fDisableExe =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_DISABLEEXE, FALSE );
|
|
|
|
pUser->fDisableCam =
|
|
(BOOLEAN) GetNumValue( Handle, WIN_DISABLECAM, FALSE );
|
|
|
|
GetStringValue( Handle, WIN_USERNAME, NULL, pUser->UserName,
|
|
USERNAME_LENGTH + 1 );
|
|
|
|
GetStringValue( Handle, WIN_DOMAIN, NULL, pUser->Domain,
|
|
DOMAIN_LENGTH + 1 );
|
|
|
|
// pull encrypted password out of registry
|
|
GetStringValue( Handle, WIN_PASSWORD, NULL, encPassword,
|
|
PASSWORD_LENGTH + 2 );
|
|
|
|
// check for password if there is one then decrypt it
|
|
if ( wcslen( encPassword ) ) {
|
|
|
|
// generate unicode string
|
|
RtlInitUnicodeString( &UnicodePassword, &encPassword[1] );
|
|
|
|
// decrypt password in place
|
|
seed = (UCHAR) encPassword[0];
|
|
RtlRunDecodeUnicodeString( seed, &UnicodePassword );
|
|
|
|
// pull clear text password
|
|
RtlMoveMemory( pUser->Password, &encPassword[1], sizeof(pUser->Password) );
|
|
}
|
|
else {
|
|
|
|
// set to null
|
|
pUser->Password[0] = (WCHAR) NULL;
|
|
}
|
|
|
|
GetStringValue( Handle, WIN_WORKDIRECTORY, NULL, pUser->WorkDirectory,
|
|
DIRECTORY_LENGTH + 1 );
|
|
|
|
GetStringValue( Handle, WIN_INITIALPROGRAM, NULL, pUser->InitialProgram,
|
|
INITIALPROGRAM_LENGTH + 1 );
|
|
|
|
GetStringValue( Handle, WIN_CALLBACKNUMBER, NULL, pUser->CallbackNumber,
|
|
CALLBACK_LENGTH + 1 );
|
|
|
|
pUser->Callback = GetNumValue( Handle, WIN_CALLBACK, Callback_Disable );
|
|
|
|
pUser->Shadow = GetNumValue( Handle, WIN_SHADOW, Shadow_EnableInputNotify );
|
|
|
|
pUser->MaxConnectionTime = GetNumValue( Handle, WIN_MAXCONNECTIONTIME, 0 );
|
|
|
|
pUser->MaxDisconnectionTime = GetNumValue( Handle,
|
|
WIN_MAXDISCONNECTIONTIME, 0 );
|
|
|
|
pUser->MaxIdleTime = GetNumValue( Handle, WIN_MAXIDLETIME, 0 );
|
|
|
|
pUser->KeyboardLayout = GetNumValue( Handle, WIN_KEYBOARDLAYOUT, 0 );
|
|
|
|
pUser->MinEncryptionLevel = (BYTE) GetNumValue( Handle, WIN_MINENCRYPTIONLEVEL, 1 );
|
|
|
|
pUser->fWallPaperDisabled = (BOOLEAN) IsWallPaperDisabled( Handle );
|
|
|
|
GetStringValue( Handle, WIN_NWLOGONSERVER, NULL, pUser->NWLogonServer,
|
|
NASIFILESERVER_LENGTH + 1 );
|
|
|
|
GetStringValue( Handle, WIN_WFPROFILEPATH, NULL, pUser->WFProfilePath,
|
|
DIRECTORY_LENGTH + 1 );
|
|
|
|
GetStringValue( Handle, WIN_WFHOMEDIR, NULL, pUser->WFHomeDir,
|
|
DIRECTORY_LENGTH + 1 );
|
|
|
|
GetStringValue( Handle, WIN_WFHOMEDIRDRIVE, NULL, pUser->WFHomeDirDrive,
|
|
4 );
|
|
|
|
pUser->ColorDepth = GetNumValue( Handle, POLICY_TS_COLOR_DEPTH, TS_8BPP_SUPPORT );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryConfig
|
|
*
|
|
* query WINSTATIONCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pConfig (output)
|
|
* address to return WINSTATIONCONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryConfig( HKEY Handle,
|
|
PWINSTATIONCONFIG pConfig )
|
|
{
|
|
GetStringValue( Handle, WIN_COMMENT, NULL, pConfig->Comment,
|
|
WINSTATIONCOMMENT_LENGTH + 1 );
|
|
|
|
QueryUserConfig( Handle, &pConfig->User );
|
|
|
|
(void) RegQueryOEMId( pConfig->OEMId, sizeof(pConfig->OEMId) );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryNetwork
|
|
*
|
|
* Query NETWORKCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pNetwork (output)
|
|
* address to return NETWORKCONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryNetwork( HKEY Handle,
|
|
PNETWORKCONFIG pNetwork )
|
|
{
|
|
pNetwork->LanAdapter = GetNumValue( Handle, WIN_LANADAPTER, 0 );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryNasi
|
|
*
|
|
* Query NASICONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pNasi (output)
|
|
* address to return NASICONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryNasi( HKEY Handle,
|
|
PNASICONFIG pNasi )
|
|
{
|
|
UCHAR seed;
|
|
UNICODE_STRING UnicodePassword;
|
|
WCHAR encPassword[ NASIPASSWORD_LENGTH + 2 ];
|
|
|
|
// pull encrypted password out of registry
|
|
GetStringValue( Handle, WIN_NASIPASSWORD, NULL, encPassword,
|
|
NASIPASSWORD_LENGTH + 1 );
|
|
|
|
// check for password if there is one then decrypt it
|
|
if ( wcslen( encPassword ) ) {
|
|
|
|
// generate unicode string
|
|
RtlInitUnicodeString( &UnicodePassword, &encPassword[1] );
|
|
|
|
// decrypt password in place
|
|
seed = (UCHAR) encPassword[0];
|
|
RtlRunDecodeUnicodeString( seed, &UnicodePassword );
|
|
|
|
// pull clear text password
|
|
RtlMoveMemory( pNasi->PassWord, &encPassword[1], sizeof(pNasi->PassWord) );
|
|
}
|
|
else {
|
|
|
|
// set to null
|
|
pNasi->PassWord[0] = (WCHAR) NULL;
|
|
}
|
|
|
|
GetStringValue( Handle, WIN_NASISPECIFICNAME, NULL, pNasi->SpecificName,
|
|
NASISPECIFICNAME_LENGTH + 1 );
|
|
GetStringValue( Handle, WIN_NASIUSERNAME, NULL, pNasi->UserName,
|
|
NASIUSERNAME_LENGTH + 1 );
|
|
GetStringValue( Handle, WIN_NASISESSIONNAME, NULL, pNasi->SessionName,
|
|
NASISESSIONNAME_LENGTH + 1 );
|
|
GetStringValue( Handle, WIN_NASIFILESERVER, NULL, pNasi->FileServer,
|
|
NASIFILESERVER_LENGTH + 1 );
|
|
pNasi->GlobalSession = (BOOLEAN)GetNumValue( Handle, WIN_NASIGLOBALSESSION, 0 );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryAsync
|
|
*
|
|
* query ASYNCCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pAsync (output)
|
|
* address to return ASYNCCONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryAsync( HKEY Handle,
|
|
PASYNCCONFIG pAsync )
|
|
{
|
|
GetStringValue( Handle, WIN_DEVICENAME, NULL, pAsync->DeviceName,
|
|
DEVICENAME_LENGTH + 1 );
|
|
|
|
GetStringValue( Handle, WIN_MODEMNAME, NULL, pAsync->ModemName,
|
|
MODEMNAME_LENGTH + 1 );
|
|
|
|
pAsync->BaudRate = GetNumValue( Handle, WIN_BAUDRATE, 9600 );
|
|
|
|
pAsync->Parity = GetNumValue( Handle, WIN_PARITY, NOPARITY );
|
|
|
|
pAsync->StopBits = GetNumValue( Handle, WIN_STOPBITS, ONESTOPBIT );
|
|
|
|
pAsync->ByteSize = GetNumValue( Handle, WIN_BYTESIZE, 8 );
|
|
|
|
pAsync->fEnableDsrSensitivity = (BOOLEAN) GetNumValue( Handle,
|
|
WIN_ENABLEDSRSENSITIVITY,
|
|
FALSE );
|
|
|
|
pAsync->fConnectionDriver = (BOOLEAN) GetNumValue( Handle,
|
|
WIN_CONNECTIONDRIVER,
|
|
FALSE );
|
|
|
|
QueryFlow( Handle, &pAsync->FlowControl );
|
|
|
|
QueryConnect( Handle, &pAsync->Connect );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryOemTd
|
|
*
|
|
* Query OEMTDCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pOemTd (output)
|
|
* address to return OEMTDCONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryOemTd( HKEY Handle,
|
|
POEMTDCONFIG pOemTd )
|
|
{
|
|
pOemTd->Adapter = GetNumValue( Handle, WIN_OEMTDADAPTER, 0 );
|
|
|
|
GetStringValue( Handle, WIN_OEMTDDEVICENAME, NULL, pOemTd->DeviceName,
|
|
DEVICENAME_LENGTH + 1 );
|
|
|
|
pOemTd->Flags = GetNumValue( Handle, WIN_OEMTDFLAGS, 0 );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryFlow
|
|
*
|
|
* query FLOWCONTROLCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pFlow (output)
|
|
* address to return FLOWCONTROLCONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryFlow( HKEY Handle,
|
|
PFLOWCONTROLCONFIG pFlow )
|
|
{
|
|
pFlow->fEnableSoftwareRx = (BOOLEAN) GetNumValue( Handle,
|
|
WIN_FLOWSOFTWARERX,
|
|
FALSE );
|
|
|
|
pFlow->fEnableSoftwareTx = (BOOLEAN) GetNumValue( Handle,
|
|
WIN_FLOWSOFTWARETX,
|
|
TRUE );
|
|
|
|
pFlow->fEnableDTR = (BOOLEAN) GetNumValue( Handle, WIN_ENABLEDTR, TRUE );
|
|
|
|
pFlow->fEnableRTS = (BOOLEAN) GetNumValue( Handle, WIN_ENABLERTS, TRUE );
|
|
|
|
pFlow->XonChar = (UCHAR) GetNumValue( Handle, WIN_XONCHAR, 0 );
|
|
|
|
pFlow->XoffChar = (UCHAR) GetNumValue( Handle, WIN_XOFFCHAR, 0 );
|
|
|
|
pFlow->Type = GetNumValue( Handle, WIN_FLOWTYPE, FlowControl_Hardware );
|
|
|
|
pFlow->HardwareReceive = GetNumValue( Handle, WIN_FLOWHARDWARERX,
|
|
ReceiveFlowControl_RTS );
|
|
|
|
pFlow->HardwareTransmit = GetNumValue( Handle, WIN_FLOWHARDWARETX,
|
|
TransmitFlowControl_CTS );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryConnect
|
|
*
|
|
* query CONNECTCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pConnect (output)
|
|
* address to return CONNECTCONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryConnect( HKEY Handle,
|
|
PCONNECTCONFIG pConnect )
|
|
{
|
|
pConnect->Type = GetNumValue( Handle, WIN_CONNECTTYPE, Connect_DSR );
|
|
|
|
pConnect->fEnableBreakDisconnect = (BOOLEAN) GetNumValue( Handle,
|
|
WIN_ENABLEBREAKDISCONNECT,
|
|
FALSE );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryCd
|
|
*
|
|
* query CDCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pCdConfig (output)
|
|
* address to return CDCONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryCd( HKEY Handle,
|
|
PCDCONFIG pCdConfig )
|
|
{
|
|
pCdConfig->CdClass = GetNumValue( Handle, WIN_CDCLASS, CdNone );
|
|
|
|
GetStringValue( Handle, WIN_CDNAME, NULL, pCdConfig->CdName,
|
|
CDNAME_LENGTH + 1 );
|
|
|
|
GetStringValue( Handle, WIN_CDDLL, L"", pCdConfig->CdDLL,
|
|
DLLNAME_LENGTH + 1 );
|
|
|
|
pCdConfig->CdFlag = GetNumValue( Handle, WIN_CDFLAG, 0 );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryWd
|
|
*
|
|
* query WDCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pWd (output)
|
|
* address to return WDCONFIG structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryWd( HKEY Handle,
|
|
PWDCONFIG pWd )
|
|
{
|
|
GetStringValue( Handle, WIN_WDNAME, NULL, pWd->WdName, WDNAME_LENGTH + 1 );
|
|
GetStringValue( Handle, WIN_WDDLL, L"", pWd->WdDLL, DLLNAME_LENGTH + 1 );
|
|
GetStringValue( Handle, WIN_WSXDLL, NULL, pWd->WsxDLL, DLLNAME_LENGTH + 1 );
|
|
pWd->WdFlag = GetNumValue( Handle, WIN_WDFLAG, 0 );
|
|
pWd->WdInputBufferLength = GetNumValue( Handle, WIN_INPUTBUFFERLENGTH, 2048 );
|
|
GetStringValue( Handle, WIN_CFGDLL, NULL, pWd->CfgDLL, DLLNAME_LENGTH + 1 );
|
|
GetStringValue( Handle, WIN_WDPREFIX, NULL, pWd->WdPrefix, WDPREFIX_LENGTH + 1 );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryPdConfig
|
|
*
|
|
* query PDCONFIG structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pConfig (output)
|
|
* address to return array of PDCONFIG structures
|
|
* pCount (input/output)
|
|
* pointer to number of PDCONFIG array elements
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryPdConfig( HKEY Handle,
|
|
PPDCONFIG pConfig,
|
|
PULONG pCount )
|
|
{
|
|
ULONG i;
|
|
|
|
for ( i=0; i < *pCount; i++ ) {
|
|
|
|
QueryPdConfig2( Handle, &pConfig[i].Create, i );
|
|
|
|
QueryPdParams( Handle,
|
|
pConfig[i].Create.SdClass,
|
|
&pConfig[i].Params );
|
|
}
|
|
|
|
*pCount = MAX_PDCONFIG;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryPdConfig2
|
|
*
|
|
* query PDCONFIG2 structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pPd2 (output)
|
|
* address to return PDCONFIG2 structure
|
|
* Index (input)
|
|
* Index (array index)
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryPdConfig2( HKEY Handle,
|
|
PPDCONFIG2 pPd2,
|
|
ULONG Index )
|
|
{
|
|
GetStringValueEx( Handle, WIN_PDNAME, Index,
|
|
NULL, pPd2->PdName, PDNAME_LENGTH + 1 );
|
|
|
|
pPd2->SdClass = GetNumValueEx( Handle, WIN_PDCLASS, Index, Index==0 ? SdAsync : SdNone );
|
|
|
|
GetStringValueEx( Handle, WIN_PDDLL, Index,
|
|
NULL, pPd2->PdDLL, DLLNAME_LENGTH + 1 );
|
|
|
|
pPd2->PdFlag = GetNumValueEx( Handle, WIN_PDFLAG, Index, 0 );
|
|
|
|
/*
|
|
* The following data is the same for all pds
|
|
*/
|
|
pPd2->OutBufLength = GetNumValue( Handle, WIN_OUTBUFLENGTH, 530 );
|
|
|
|
pPd2->OutBufCount = GetNumValue( Handle, WIN_OUTBUFCOUNT, 10 );
|
|
|
|
pPd2->OutBufDelay = GetNumValue( Handle, WIN_OUTBUFDELAY, 100 );
|
|
|
|
pPd2->InteractiveDelay = GetNumValue( Handle, WIN_INTERACTIVEDELAY, 10 );
|
|
|
|
pPd2->KeepAliveTimeout = GetNumValue( Handle, WIN_KEEPALIVETIMEOUT, 0 );
|
|
|
|
pPd2->PortNumber = GetNumValue( Handle, WIN_PORTNUMBER, 0 );
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryPdConfig3
|
|
*
|
|
* query PDCONFIG3 structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* pPd (output)
|
|
* address to return PDCONFIG3 structure
|
|
* Index (input)
|
|
* Index (array index)
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryPdConfig3( HKEY Handle,
|
|
PPDCONFIG3 pPd3,
|
|
ULONG Index )
|
|
{
|
|
int i;
|
|
ULONG Length;
|
|
LPWSTR tmp;
|
|
WCHAR PdName[ MAX_PDCONFIG * ( PDNAME_LENGTH + 1 ) + 1 ];
|
|
ULONG ValueType;
|
|
|
|
QueryPdConfig2( Handle, &pPd3->Data, Index );
|
|
|
|
GetStringValue( Handle, WIN_SERVICENAME, NULL,
|
|
pPd3->ServiceName,
|
|
PDNAME_LENGTH + 1 );
|
|
|
|
GetStringValue( Handle, WIN_CONFIGDLL, NULL,
|
|
pPd3->ConfigDLL,
|
|
DLLNAME_LENGTH + 1 );
|
|
|
|
Length = sizeof(PdName);
|
|
pPd3->RequiredPdCount = 0;
|
|
if ( RegQueryValueEx( Handle, WIN_REQUIREDPDS, NULL, &ValueType,
|
|
(LPBYTE)PdName, &Length ) == ERROR_SUCCESS ) {
|
|
tmp = PdName;
|
|
i = 0;
|
|
while ( *tmp != UNICODE_NULL ) {
|
|
pPd3->RequiredPdCount++;
|
|
wcscpy( pPd3->RequiredPds[i], tmp );
|
|
i++;
|
|
tmp += wcslen(tmp) + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* QueryPdParams
|
|
*
|
|
* query PDPARAMS structure
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* Handle (input)
|
|
* registry handle
|
|
* SdClass (input)
|
|
* type of PD
|
|
* pParams (output)
|
|
* address to return PDPARAMS structure
|
|
*
|
|
* EXIT:
|
|
* nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
QueryPdParams( HKEY Handle,
|
|
SDCLASS SdClass,
|
|
PPDPARAMS pParams )
|
|
{
|
|
pParams->SdClass = SdClass;
|
|
switch ( SdClass ) {
|
|
case SdNetwork :
|
|
QueryNetwork( Handle, &pParams->Network );
|
|
break;
|
|
case SdNasi :
|
|
QueryNasi( Handle, &pParams->Nasi );
|
|
break;
|
|
case SdAsync :
|
|
QueryAsync( Handle, &pParams->Async );
|
|
break;
|
|
case SdOemTransport :
|
|
QueryOemTd( Handle, &pParams->OemTd );
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define CONTROL_PANEL L"Control Panel"
|
|
#define DESKTOP L"Desktop"
|
|
#define WALLPAPER L"Wallpaper"
|
|
#define NONE L"(None)"
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* IsWallPaperDisabled
|
|
*
|
|
* Is the wall paper disabled?
|
|
*
|
|
* ENTRY:
|
|
* Handle (input)
|
|
* registry handle
|
|
* EXIT:
|
|
* TRUE or FALSE (returns FALSE as default)
|
|
*
|
|
******************************************************************************/
|
|
BOOLEAN IsWallPaperDisabled( HKEY Handle )
|
|
{
|
|
HKEY Handle1;
|
|
WCHAR KeyString[256];
|
|
|
|
wcscpy( KeyString, WIN_USEROVERRIDE );
|
|
wcscat( KeyString, L"\\" );
|
|
wcscat( KeyString, CONTROL_PANEL );
|
|
wcscat( KeyString, L"\\" );
|
|
wcscat( KeyString, DESKTOP );
|
|
|
|
if ( RegOpenKeyEx( Handle, KeyString, 0, KEY_READ,
|
|
&Handle1 ) != ERROR_SUCCESS )
|
|
return FALSE;
|
|
|
|
|
|
GetStringValue( Handle1, WALLPAPER, NULL, KeyString, 256 );
|
|
RegCloseKey( Handle1 );
|
|
|
|
if( KeyString[0] == 0 || ( _wcsicmp( NONE, KeyString ) == 0 ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* RegBuildNumberQuery
|
|
*
|
|
* Query the current build number from the registry.
|
|
*
|
|
* HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\Current Version\
|
|
* CurrentBuildNumber:REG_SZ:129
|
|
*
|
|
* ENTRY:
|
|
* Param1 (input/output)
|
|
* Comments
|
|
*
|
|
* EXIT:
|
|
* STATUS_SUCCESS - no error
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
RegBuildNumberQuery(
|
|
PULONG pBuildNum
|
|
)
|
|
{
|
|
ULONG Result, Value;
|
|
HKEY hKey;
|
|
WCHAR Buf[256];
|
|
|
|
Result = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
BUILD_NUMBER_KEY,
|
|
0, // Reserved
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
|
|
if( Result != ERROR_SUCCESS ) {
|
|
#if DBG
|
|
DbgPrint("RegBuildNumberQuery: Failed to open key %ws\n",BUILD_NUMBER_KEY);
|
|
#endif
|
|
return( FALSE );
|
|
}
|
|
|
|
Result = GetStringValue(
|
|
hKey,
|
|
BUILD_NUMBER_VALUE,
|
|
L"0",
|
|
Buf,
|
|
sizeof(Buf)
|
|
);
|
|
|
|
if( Result != ERROR_SUCCESS ) {
|
|
#if DBG
|
|
DbgPrint("RegBuildNumberQuery: Failed to query value %ws\n",BUILD_NUMBER_VALUE);
|
|
#endif
|
|
RegCloseKey( hKey );
|
|
return( FALSE );
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
//
|
|
// Now must convert it into a number
|
|
//
|
|
Value = 0;
|
|
swscanf( Buf, L"%d", &Value );
|
|
|
|
*pBuildNum = Value;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* RegQueryOEMId
|
|
*
|
|
* query oem id
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* pOEMId (output)
|
|
* pointer to buffer to return oem id
|
|
* Length (input)
|
|
* length of buffer
|
|
*
|
|
* EXIT:
|
|
*
|
|
* TRUE -- The operation succeeded.
|
|
*
|
|
* FALSE -- The operation failed. Extended error status is available
|
|
* using GetLastError.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN
|
|
RegQueryOEMId( PBYTE pOEMId, ULONG Length )
|
|
{
|
|
HKEY Handle2;
|
|
WCHAR OEMIdW[10];
|
|
|
|
/*
|
|
* Open registry (LOCAL_MACHINE\....\Terminal Server)
|
|
*/
|
|
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
|
|
KEY_READ, &Handle2 ) == ERROR_SUCCESS ) {
|
|
|
|
GetStringValue( Handle2, REG_CITRIX_OEMID, NULL, OEMIdW, 10 );
|
|
UnicodeToAnsi( pOEMId, Length, OEMIdW );
|
|
pOEMId[3] = '\0';
|
|
|
|
RegCloseKey( Handle2 );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* RegGetTServerVersion (UNICODE)
|
|
*
|
|
* Get the Terminal Server version number from the specified server.
|
|
*
|
|
* This version number is changed by Microsoft, and not OEM's.
|
|
*
|
|
* ENTRY:
|
|
* pServerName (input)
|
|
* Points to string of server to check.
|
|
*
|
|
* EXIT:
|
|
* TRUE if Hydra Terminal Server; FALSE otherwise
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOLEAN WINAPI
|
|
RegGetTServerVersion(
|
|
WCHAR * pServerName,
|
|
PULONG pVersionNumber
|
|
)
|
|
{
|
|
LONG Error;
|
|
HKEY ServerHandle, UserHandle;
|
|
ULONG Value;
|
|
|
|
/*
|
|
* Connect to registry of specified server.
|
|
*/
|
|
if ( (Error = RegConnectRegistry( pServerName,
|
|
HKEY_LOCAL_MACHINE,
|
|
&ServerHandle )) != ERROR_SUCCESS )
|
|
return( FALSE );
|
|
|
|
/*
|
|
* Open the Terminal Server key and get the Version value.
|
|
*/
|
|
if ( (Error = RegOpenKeyEx( ServerHandle, REG_CONTROL_TSERVER, 0,
|
|
KEY_READ, &UserHandle )) != ERROR_SUCCESS ) {
|
|
|
|
RegCloseKey( ServerHandle );
|
|
return( FALSE );
|
|
}
|
|
|
|
Value = GetNumValue(
|
|
UserHandle,
|
|
REG_CITRIX_VERSION,
|
|
0 );
|
|
|
|
/*
|
|
* Close registry handles.
|
|
*/
|
|
RegCloseKey( UserHandle );
|
|
RegCloseKey( ServerHandle );
|
|
|
|
*pVersionNumber = Value;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* RegQueryUtilityCommandList (UNICODE)
|
|
*
|
|
* Allocate and build an array of PROGRAMCALL structures for the specified
|
|
* MultiUser utility.
|
|
*
|
|
* ENTRY:
|
|
* pUtilityKey (input)
|
|
* Points to string containing the utility's command registry key.
|
|
* ppProgramCall (output)
|
|
* Points to a PPROGRAMCALL variable that will be set to the API-allocated
|
|
* array of PROGRAMCALL structures, containing n elements, where n =
|
|
* number of commands supported by the utility (as specified in the
|
|
* registry). The pFirst item of array element 0 will point to the
|
|
* first command (sorted alphabetically by command name). The pNext items
|
|
* are then used to walk the list, till pNext is NULL.
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS if all goes well;
|
|
* An error code is returned if failure.
|
|
*
|
|
* If success, the caller must call RegFreeUtilityCommandList with the
|
|
* ppProgramCall variable to free the PROGRAMCALL structure array when
|
|
* finished using the array.
|
|
*
|
|
* The format of the REG_MULTI_SZ command item in the registry is as follows:
|
|
*
|
|
* string 1: "0" or "1" (required)
|
|
*
|
|
* 0 specifies that the command is a normal command which will
|
|
* be presented as an option by the utility USAGE help. 1
|
|
* indicates a command alias (hidden option), which won't
|
|
* appear in USAGE help.
|
|
*
|
|
* string 2: "number" (required)
|
|
*
|
|
* Specifies the minimum number of characters that must be
|
|
* typed for the command to be recognized (base 10).
|
|
*
|
|
* string 3: "command" (required)
|
|
*
|
|
* This is the actual command that will be recognized and
|
|
* displayed in the USAGE help (if not an aliased command).
|
|
*
|
|
* string 4: "program" (required)
|
|
*
|
|
* The file name of the program that will be executed. This
|
|
* should be a standard name.extension filename, and can
|
|
* include a full path, although this is not necessary since
|
|
* the utilities will normally reside in the standard SYSTEM32
|
|
* directory, which is a part of the standard PATH.
|
|
*
|
|
* string 5: "extra args" (optional)
|
|
*
|
|
* If specified, this string will be passed along to the
|
|
* utilsub.lib ExecProgram API to specify additional
|
|
* hard-coded arguments that will be used, in addition to any
|
|
* other arguments that were specified by the user on the
|
|
* command line.
|
|
*
|
|
* Note: If the command item is not a REG_MULTI_SZ value, or the command item
|
|
* is a REG_MULTI_SZ item but there is an error in its format, that
|
|
* command will be omitted from the command list. The return value
|
|
* from this function will still be ERROR_SUCCESS, but the command in
|
|
* error will be ignored by the utilities.
|
|
*
|
|
******************************************************************************/
|
|
|
|
LONG WINAPI
|
|
RegQueryUtilityCommandList(
|
|
LPWSTR pUtilityKey,
|
|
PPROGRAMCALL * ppProgramCall
|
|
)
|
|
{
|
|
HKEY Handle = NULL;
|
|
LONG status = ERROR_SUCCESS;
|
|
DWORD iValue, cValues, ccValueName, cbValueData,
|
|
ccTmpValueName, cbTmpValueData, dwType;
|
|
LPWSTR pValueName = NULL, pValueData = NULL, pString;
|
|
PPROGRAMCALL pProg = NULL, pProgNext, pProgPrev;
|
|
ULONG ulCommandLen;
|
|
PWCHAR pEndptr;
|
|
int iCompare;
|
|
|
|
*ppProgramCall = NULL;
|
|
|
|
/*
|
|
* Open specified utility key and determine number of values and maximum
|
|
* value name and data length.
|
|
*/
|
|
if ( status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
pUtilityKey,
|
|
0,
|
|
KEY_READ,
|
|
&Handle ) != ERROR_SUCCESS ) {
|
|
#if DBG
|
|
DbgPrint("RegQueryUtilityCommandList: Can't open command list utility key %ws; error = %d\n", pUtilityKey, status);
|
|
#endif
|
|
goto error;
|
|
}
|
|
|
|
if ( status = RegQueryInfoKey( Handle,
|
|
NULL, // lpClass
|
|
NULL, // lpcbClass
|
|
NULL, // lpReserved
|
|
NULL, // lpcSubKeys
|
|
NULL, // lpcbMaxSubKeyLen
|
|
NULL, // lpcbMaxClassLen
|
|
&cValues, // lpcValues
|
|
&ccValueName, // lpcbMaxValueNameLen
|
|
&cbValueData, // lpcbMaxValueLen
|
|
NULL, // lpcbSecurityDescriptor
|
|
NULL // lpftLastWriteTime
|
|
) != ERROR_SUCCESS ) {
|
|
#if DBG
|
|
DbgPrint("RegQueryUtilityCommandList: Can't query info for utility %ws; error = %d\n", pUtilityKey, status);
|
|
#endif
|
|
goto error;
|
|
}
|
|
|
|
/*
|
|
* Allocate space for #values + 1 PROGRAMCALL elements and value name and
|
|
* data buffers.
|
|
*/
|
|
if ( ((*ppProgramCall = (PPROGRAMCALL)LocalAlloc( LPTR, (sizeof(PROGRAMCALL) * (cValues+1)) )) == NULL) ||
|
|
((pValueName = (LPWSTR)LocalAlloc( LPTR, (int)(++ccValueName * sizeof(WCHAR)) )) == NULL) ||
|
|
((pValueData = (LPWSTR)LocalAlloc( LPTR, (int)cbValueData )) == NULL) ) {
|
|
|
|
status = GetLastError();
|
|
#if DBG
|
|
DbgPrint("RegQueryUtilityCommandList: Can't allocate memory buffer(s) for utility %ws; error = %d\n", pUtilityKey, status);
|
|
#endif
|
|
goto error;
|
|
}
|
|
|
|
/*
|
|
* Enumerate and parse each value into the PROGRAMCALL components.
|
|
*/
|
|
for ( iValue = 0, pProg = *ppProgramCall;
|
|
iValue < cValues;
|
|
iValue++, pProg++ ) {
|
|
|
|
ccTmpValueName = ccValueName;
|
|
cbTmpValueData = cbValueData;
|
|
if ( (status = RegEnumValue( Handle,
|
|
iValue,
|
|
pValueName,
|
|
&ccTmpValueName,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)pValueData,
|
|
&cbTmpValueData )) != ERROR_SUCCESS ) {
|
|
#if DBG
|
|
DbgPrint("RegQueryUtilityCommandList: Can't enumerate command (index = %d) for utility %ws; error = %d\n", iValue, pUtilityKey, status);
|
|
#endif
|
|
|
|
goto error;
|
|
}
|
|
|
|
/*
|
|
* If the data is not REG_MULTI_SZ, ignore it.
|
|
*/
|
|
if ( dwType != REG_MULTI_SZ )
|
|
goto CommandInError;
|
|
|
|
/*
|
|
* Allocate data storage for this command, then parse and assign
|
|
* to the PROGRAMCALL structure items.
|
|
*/
|
|
if ( (pProg->pRegistryMultiString = LocalAlloc(LPTR, cbTmpValueData)) == NULL ) {
|
|
|
|
status = GetLastError();
|
|
#if DBG
|
|
DbgPrint("RegQueryUtilityCommandList: Can't allocate memory buffer for utility %ws; error = %d\n", pUtilityKey, status);
|
|
#endif
|
|
goto error;
|
|
}
|
|
|
|
memcpy(pProg->pRegistryMultiString, pValueData, cbTmpValueData);
|
|
pString = pProg->pRegistryMultiString;
|
|
|
|
/*
|
|
* Parse alias flag.
|
|
*/
|
|
if ( !wcscmp(pString, L"1") )
|
|
pProg->fAlias = TRUE;
|
|
else if ( !wcscmp(pString, L"0") )
|
|
pProg->fAlias = FALSE;
|
|
else
|
|
goto CommandInError;
|
|
pString += (wcslen(pString) + 1);
|
|
|
|
/*
|
|
* Parse command length.
|
|
*/
|
|
if ( *pString == L'\0' )
|
|
goto CommandInError;
|
|
ulCommandLen = wcstoul(pString, &pEndptr, 10);
|
|
if ( *pEndptr != L'\0' )
|
|
goto CommandInError;
|
|
pProg->CommandLen = (USHORT)ulCommandLen;
|
|
pString += (wcslen(pString) + 1);
|
|
|
|
/*
|
|
* Parse command string.
|
|
*/
|
|
if ( *pString == L'\0' )
|
|
goto CommandInError;
|
|
pProg->Command = pString;
|
|
pString += (wcslen(pString) + 1);
|
|
|
|
/*
|
|
* Parse program string.
|
|
*/
|
|
if ( *pString == L'\0' )
|
|
goto CommandInError;
|
|
pProg->Program = pString;
|
|
pString += (wcslen(pString) + 1);
|
|
|
|
/*
|
|
* Parse (optional) Args string.
|
|
*/
|
|
if ( *pString != L'\0' )
|
|
pProg->Args = pString;
|
|
|
|
/*
|
|
* Walk the command list to link this item in it's proper
|
|
* sorted place.
|
|
*/
|
|
if ( pProg == *ppProgramCall ) {
|
|
|
|
pProg->pFirst = pProg; // first item in the list
|
|
|
|
} else for ( pProgPrev = pProgNext = (*ppProgramCall)->pFirst; ; ) {
|
|
|
|
if ( (iCompare = _wcsicmp(pProg->Command, pProgNext->Command)) < 0 ) {
|
|
|
|
pProg->pNext = pProgNext; // point to next
|
|
|
|
if ( pProgNext == (*ppProgramCall)->pFirst )
|
|
(*ppProgramCall)->pFirst = pProg; // first item
|
|
else
|
|
pProgPrev->pNext = pProg; // link after previous
|
|
|
|
break;
|
|
|
|
} else if ( iCompare == 0 ) {
|
|
|
|
goto CommandInError; // duplicate command - ignore
|
|
}
|
|
|
|
if ( pProgNext->pNext == NULL ) {
|
|
|
|
pProgNext->pNext = pProg; // link at end of list
|
|
break;
|
|
|
|
} else {
|
|
|
|
pProgPrev = pProgNext;
|
|
pProgNext = pProgNext->pNext;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
|
|
CommandInError:
|
|
/*
|
|
* The command format is in error - ignore it.
|
|
*/
|
|
if ( pProg->pRegistryMultiString )
|
|
LocalFree(pProg->pRegistryMultiString);
|
|
memset(pProg, 0, sizeof(PROGRAMCALL));
|
|
pProg--;
|
|
}
|
|
|
|
error:
|
|
if ( Handle != NULL )
|
|
RegCloseKey(Handle);
|
|
|
|
if ( pValueName )
|
|
LocalFree(pValueName);
|
|
|
|
if ( pValueData )
|
|
LocalFree(pValueData);
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
|
|
if ( *ppProgramCall ) {
|
|
RegFreeUtilityCommandList(*ppProgramCall);
|
|
*ppProgramCall = NULL;
|
|
}
|
|
}
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* RegFreeUtilityCommandList (UNICODE)
|
|
*
|
|
* Free the specified array of PROGRAMCALL structures.
|
|
*
|
|
* ENTRY:
|
|
* pProgramCall (input)
|
|
* Points PROGRAMCALL array to free.
|
|
*
|
|
* EXIT:
|
|
* ERROR_SUCCESS if all goes well; error code if failure
|
|
*
|
|
******************************************************************************/
|
|
|
|
LONG WINAPI
|
|
RegFreeUtilityCommandList(
|
|
PPROGRAMCALL pProgramCall
|
|
)
|
|
{
|
|
PPROGRAMCALL pProg;
|
|
LONG status = ERROR_SUCCESS;
|
|
|
|
if ( pProgramCall ) {
|
|
|
|
for ( pProg = pProgramCall->pFirst; pProg != NULL; pProg = pProg->pNext ) {
|
|
|
|
if ( LocalFree( pProg->pRegistryMultiString ) != NULL ) {
|
|
|
|
status = GetLastError();
|
|
#if DBG
|
|
DbgPrint("RegFreeUtilityCommandList: Failed to free command list element for %ws; error = %d\n", pProg->Program, status);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if ( LocalFree( pProgramCall ) != NULL ) {
|
|
|
|
status = GetLastError();
|
|
#if DBG
|
|
DbgPrint("RegFreeUtilityCommandList: Failed to free command list array; error = %d\n", status);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return( status );
|
|
}
|
|
|