windows-nt/Source/XPSP1/NT/ds/security/gina/msgina/winutil.c

1380 lines
35 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/****************************** Module Header ******************************\
* Module Name: winutil.c
*
* Copyright (c) 1991, Microsoft Corporation
*
* Implements windows specific utility functions
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
#include "msgina.h"
#include <stdio.h>
#include <wchar.h>
//
// Define this if you want a verbose commentary from these routines
//
// #define VERBOSE_UTILS
#ifdef VERBOSE_UTILS
#define VerbosePrint(s) WLPrint(s)
#else
#define VerbosePrint(s)
#endif
#define LRM 0x200E // UNICODE Left-to-right mark control character
#define RLM 0x200F // UNICODE Left-to-right mark control character
/***************************************************************************\
* SetupSystemMenu
*
* Purpose : Does any manipulation required for a dialog system menu.
* Should be called during WM_INITDIALOG processing for a dialog
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
VOID
SetupSystemMenu(
HWND hDlg
)
{
// Remove the Close item from the system menu if we don't
// have a CANCEL button
if (GetDlgItem(hDlg, IDCANCEL) == NULL) {
HMENU hMenu = GetSystemMenu(hDlg, FALSE);
if (hMenu)
{
DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}
}
}
/***************************************************************************\
* CentreWindow
*
* Purpose : Positions a window so that it is centred in its parent
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
VOID
CentreWindow(
HWND hwnd
)
{
RECT rect;
LONG dx, dy;
LONG dxParent, dyParent;
LONG Style;
// Get window rect
GetWindowRect(hwnd, &rect);
dx = rect.right - rect.left;
dy = rect.bottom - rect.top;
// Get parent rect
Style = GetWindowLong(hwnd, GWL_STYLE);
if ((Style & WS_CHILD) == 0) {
// Return the desktop windows size (size of main screen)
dxParent = GetSystemMetrics(SM_CXSCREEN);
dyParent = GetSystemMetrics(SM_CYSCREEN);
} else {
HWND hwndParent;
RECT rectParent;
hwndParent = GetParent(hwnd);
if (hwndParent == NULL) {
hwndParent = GetDesktopWindow();
}
GetWindowRect(hwndParent, &rectParent);
dxParent = rectParent.right - rectParent.left;
dyParent = rectParent.bottom - rectParent.top;
}
// Centre the child in the parent
rect.left = (dxParent - dx) / 2;
rect.top = (dyParent - dy) / 3;
// Move the child into position
SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, 0, 0, SWP_NOSIZE);
SetForegroundWindow(hwnd);
}
/***************************************************************************\
* SetPasswordFocus
*
* Sets the focus window in a dialog to the first empty control in
* the list IDD_LOGON_DOMAIN, IDD_NEW_PASSWORD
* This routine would normally be called during WM_INITDIALOG processing.
*
* Returns FALSE if the focus was set, otherwise TRUE - this value can
* be used as the return value to the WM_INITDIALOG message.
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
BOOL
SetPasswordFocus(
HWND hDlg
)
{
int ids[] = { IDD_LOGON_NAME,
IDD_LOGON_DOMAIN,
IDD_LOGON_PASSWORD,
IDD_UNLOCK_PASSWORD,
IDD_CHANGEPWD_OLD,
IDD_CHANGEPWD_NEW,
IDD_CHANGEPWD_CONFIRM,
};
SHORT Index;
HWND hwndFocus = NULL;
// Set focus to first enabled, visible, empty field
for (Index = 0; Index < sizeof(ids)/sizeof(*ids); Index ++) {
int idControl = ids[Index];
HWND hwndControl;
hwndControl = GetDlgItem(hDlg, idControl);
if (hwndControl != NULL) {
if ( (GetWindowTextLength(hwndControl) == 0) &&
((GetWindowLong(hwndControl, GWL_STYLE) &
(WS_VISIBLE | WS_DISABLED)) == WS_VISIBLE)) {
hwndFocus = hwndControl;
break;
}
}
}
if (hwndFocus != NULL) {
SetFocus(hwndFocus);
}
return(hwndFocus == NULL);
}
//
// Globals used to store cursor handles for SetupCursor
//
static HCURSOR hCursorArrow = NULL;
static HCURSOR hCursorWait = NULL;
/***************************************************************************\
* SetupCursor
*
* Sets the cursor to an hourglass if fWait = TRUE, otherwise sets it
* to an arrow.
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
VOID
SetupCursor(
BOOL fWait
)
{
if (hCursorArrow == NULL) {
hCursorArrow = LoadCursor(NULL, IDC_ARROW);
}
if (hCursorWait == NULL) {
hCursorWait = LoadCursor(NULL, IDC_WAIT);
}
SetCursor(fWait ? hCursorWait : hCursorArrow);
}
/****************************************************************************
FUNCTION: TimeFieldsToSystemTime
PURPOSE: Converts a TIME_FIELDS structure into a SYSTEMTIME structure
RETURNS : nothing
History:
05-15-93 RobertRe Created.
****************************************************************************/
VOID
TimeFieldsToSystemTime(
IN PTIME_FIELDS TimeFields,
OUT LPSYSTEMTIME SystemTime
)
{
SystemTime->wYear = TimeFields->Year ;
SystemTime->wMonth = TimeFields->Month ;
SystemTime->wDayOfWeek = TimeFields->Weekday ;
SystemTime->wDay = TimeFields->Day ;
SystemTime->wHour = TimeFields->Hour ;
SystemTime->wMinute = TimeFields->Minute ;
SystemTime->wSecond = TimeFields->Second ;
SystemTime->wMilliseconds = TimeFields->Milliseconds;
return;
}
/****************************************************************************
FUNCTION: FormatTime
PURPOSE: Converts a system time into a readable string(in local time).
if flags contains FT_TIME the time appears in the string
if flags contains FT_DATE the date appears in the string.
if both values appear, the string contains date then time.
RETURNS : TRUE on success, FALSE on failure
****************************************************************************/
BOOL
FormatTime(
IN PTIME Time,
IN OUT PWCHAR Buffer,
IN ULONG BufferLength,
IN USHORT Flags
)
{
NTSTATUS Status;
TIME_FIELDS TimeFields;
TIME LocalTime;
SYSTEMTIME SystemTime;
DWORD dwDateFlags = DATE_SHORTDATE;
//
// Terminate the string in case they didn't pass any flags
//
if (BufferLength > 0) {
Buffer[0] = 0;
}
//
// Convert the system time to local time
//
Status = RtlSystemTimeToLocalTime(Time, &LocalTime);
if (!NT_SUCCESS(Status)) {
WLPrint(("Failed to convert system time to local time, status = 0x%lx", Status));
return(FALSE);
}
//
// Split the time into its components
//
RtlTimeToTimeFields(&LocalTime, &TimeFields);
TimeFieldsToSystemTime( &TimeFields, &SystemTime );
//
// Format the string
//
if (Flags & FT_LTR)
dwDateFlags |= DATE_LTRREADING;
else if(Flags & FT_RTL)
dwDateFlags |= DATE_RTLREADING;
if (Flags & FT_DATE) {
int Length;
WCHAR DateString[256];
Length = GetDateFormatW(GetUserDefaultLCID(),
dwDateFlags,
&SystemTime,
NULL,
DateString,
256
);
Length = _snwprintf( Buffer,
BufferLength,
TEXT("%s"),
DateString
);
Buffer += Length;
BufferLength -= Length;
}
if (Flags & FT_TIME) {
int Length;
WCHAR TimeString[256];
if (Flags & FT_DATE) {
if (BufferLength > 0) {
*Buffer++ = TEXT(' ');
BufferLength --;
}
// [msadek]; need to insert strong a Unicode control character to simulate
// a strong run in the opposite base direction to enforce
// correct display of concatinated string in all cases.
if((BufferLength > 0) && (Flags & FT_RTL)) {
*Buffer++ = LRM; // simulate an opposite run
*Buffer++ = RLM; // force RTL display of the time part.
*Buffer = 0; // in case GetTimeFormat doesn't add anything
BufferLength -= 2;
}
else if((BufferLength > 0) && (Flags & FT_LTR)) {
*Buffer++ = RLM; // simulate an opposite run
*Buffer++ = LRM; // force LTR display of the time part.
*Buffer = 0; // in case GetTimeFormat doesn't add anything
BufferLength -= 2;
}
}
Length = GetTimeFormatW(GetUserDefaultLCID(),
0,
&SystemTime,
NULL,
TimeString,
256
);
_snwprintf(Buffer, BufferLength,
TEXT("%s"),
TimeString
);
}
return(TRUE);
}
/***************************************************************************\
* DuplicateUnicodeString
*
* Purpose : Allocates space for new string then copies new into old.
* The new string is always 0 terminated
* The new string should be free using RtlFreeUnicodeString()
*
* Returns : TRUE on success, FALSE on failure
*
* History:
* 11-04-92 Davidc Created.
* 05-29-98 DSheldon Modified so that no uni->ansi->uni translation occurs
\***************************************************************************/
BOOL
DuplicateUnicodeString(
PUNICODE_STRING OutString,
PUNICODE_STRING InString
)
{
*OutString = *InString ;
OutString->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, InString->Length + sizeof(WCHAR) );
if ( OutString->Buffer )
{
RtlCopyMemory( OutString->Buffer,
InString->Buffer,
InString->Length );
OutString->Buffer[ OutString->Length / sizeof( WCHAR ) ] = L'\0';
OutString->MaximumLength = OutString->Length + sizeof( WCHAR );
}
return (OutString->Buffer != NULL);
}
/***************************************************************************\
* UnicodeStringToString
*
* Purpose : Converts a unicode string to it's local format and allocates
* space for it. The returned NULL terminated string can be freed
* using Free()
*
* Returns : Pointer to NULL terminated string or NULL on failure.
*
* History:
* 11-04-92 Davidc Created.
\***************************************************************************/
LPTSTR
UnicodeStringToString(
PUNICODE_STRING UnicodeString
)
{
LPTSTR String;
ULONG BytesRequired = sizeof(TCHAR)*(UnicodeString->Length + 1);
String = Alloc(BytesRequired);
if (String != NULL) {
if (UnicodeString->Length && UnicodeString->Buffer ) {
lstrcpy(String, UnicodeString->Buffer);
} else {
Free(String);
String = 0;
}
}
return(String);
}
/***************************************************************************\
* FUNCTION: OpenIniFileUserMapping
*
* PURPOSE: Forces the ini file mapping apis to reference the current user's
* registry.
*
* RETURNS: TRUE on success, FALSE on failure
*
* HISTORY:
*
* 24-Aug-92 Davidc Created.
*
\***************************************************************************/
BOOL
OpenIniFileUserMapping(
PGLOBALS pGlobals
)
{
BOOL Result;
HANDLE ImpersonationHandle;
//
// Impersonate the user
//
ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
if (ImpersonationHandle == NULL) {
DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to impersonate user"));
return(FALSE);
}
Result = OpenProfileUserMapping();
if (!Result) {
DebugLog((DEB_ERROR, "OpenProfileUserMapping failed, error = %d", GetLastError()));
}
//
// Revert to being 'ourself'
//
if (!StopImpersonating(ImpersonationHandle)) {
DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to revert to self"));
}
return(Result);
}
/***************************************************************************\
* FUNCTION: CloseIniFileUserMapping
*
* PURPOSE: Closes the ini file mapping to the user's registry such
* that future use of the ini apis will fail if they reference
* the user's registry.
*
* RETURNS: Nothing
*
* HISTORY:
*
* 24-Aug-92 Davidc Created.
*
\***************************************************************************/
VOID
CloseIniFileUserMapping(
PGLOBALS pGlobals
)
{
BOOL Result;
Result = CloseProfileUserMapping();
if (!Result) {
DebugLog((DEB_ERROR, "CloseProfileUserMapping failed, error = %d", GetLastError()));
}
UNREFERENCED_PARAMETER(pGlobals);
}
/***************************************************************************\
* FUNCTION: AllocAndGetDlgItemText
*
* PURPOSE: Allocates memory for and returns pointer to a copy of the text
* in the specified dialog control.
* The returned string should be freed using Free()
*
* RETURNS: Pointer to copy of dlg item text, or NULL on failure.
*
* HISTORY:
*
* 9-Sep-92 Davidc Created.
*
\***************************************************************************/
LPTSTR
AllocAndGetDlgItemText(
HWND hDlg,
int iItem
)
{
HWND hwnd;
LPTSTR String;
LONG Length;
LONG BytesRequired;
LONG LengthCopied;
//
// Go find the window handle of the control
//
hwnd = GetDlgItem(hDlg, iItem);
if (hwnd == NULL) {
DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : Couldn't find control %d in dialog 0x%lx", iItem, hDlg));
ASSERT(hwnd != NULL);
return(NULL);
}
//
// Get the length of the control's text
//
Length = (LONG)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
if (Length < 0) {
DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : Dialog control text length < 0 (%d)", Length));
ASSERT(Length >= 0);
return(NULL);
}
//
// Calculate the bytes required for the string.
// The length doesn't include the terminator
//
Length ++; // Add one for terminator
BytesRequired = Length * sizeof(TCHAR);
String = (LPTSTR)Alloc(BytesRequired);
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : Failed to allocate %d bytes for dialog control text", BytesRequired));
return(NULL);
}
//
// Fill in the allocated block with the text
//
LengthCopied = (LONG)SendMessage(hwnd, WM_GETTEXT, Length, (LPARAM)String);
if (LengthCopied != (Length - 1)) {
DebugLog((DEB_ERROR, "AllocAndGetDlgItemText : WM_GETTEXT for %d chars only copied %d chars", Length-1, LengthCopied));
ASSERT(LengthCopied == (Length - 1));
Free(String);
return(NULL);
}
String[Length - 1] = TEXT('\0');
return(String);
}
/***************************************************************************\
* FUNCTION: AllocAndGetPrivateProfileString
*
* PURPOSE: Allocates memory for and returns pointer to a copy of the
* specified profile string
* The returned string should be freed using Free()
*
* RETURNS: Pointer to copy of profile string or NULL on failure.
*
* HISTORY:
*
* 12-Nov-92 Davidc Created.
*
\***************************************************************************/
LPTSTR
AllocAndGetPrivateProfileString(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
LPCTSTR lpDefault,
LPCTSTR lpFileName
)
{
LPTSTR String;
LPTSTR NewString ;
LONG LengthAllocated;
LONG LengthCopied;
//
// Pick a random buffer length, if it's not big enough reallocate
// it and try again until it is.
//
LengthAllocated = TYPICAL_STRING_LENGTH;
String = Alloc(LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
return(NULL);
}
while (TRUE) {
LengthCopied = GetPrivateProfileString( lpAppName,
lpKeyName,
lpDefault,
String,
LengthAllocated,
lpFileName
);
//
// If the returned value is our passed size - 1 (weird way for error)
// then our buffer is too small. Make it bigger and start over again.
//
if (LengthCopied == (LengthAllocated - 1)) {
VerbosePrint(("AllocAndGetPrivateProfileString: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
LengthAllocated *= 2;
NewString = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
if (NewString == NULL) {
Free( String );
String = NULL ;
DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
break;
}
String = NewString ;
//
// Go back and try to read it again
//
} else {
//
// Success!
//
break;
}
}
return(String);
}
/***************************************************************************\
* FUNCTION: WritePrivateProfileInt
*
* PURPOSE: Writes out an integer to a profile file
*
* RETURNS: TRUE on success, FALSE on failure
*
* HISTORY:
*
* 12-Nov-92 Davidc Created.
*
\***************************************************************************/
BOOL
WritePrivateProfileInt(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
UINT Value,
LPCTSTR lpFileName
)
{
NTSTATUS Status;
TCHAR String[30];
UNICODE_STRING UniString;
UniString.MaximumLength = 30;
UniString.Buffer = String;
Status = RtlIntegerToUnicodeString(Value,10,&UniString);
if (!NT_SUCCESS(Status)) {
return(FALSE);
}
return (WritePrivateProfileString(lpAppName, lpKeyName, UniString.Buffer, lpFileName));
}
/***************************************************************************\
* FUNCTION: AllocAndExpandEnvironmentStrings
*
* PURPOSE: Allocates memory for and returns pointer to buffer containing
* the passed string expanded to include environment strings
* The returned buffer should be freed using Free()
*
* RETURNS: Pointer to expanded string or NULL on failure.
*
* HISTORY:
*
* 21-Dec-92 Davidc Created.
*
\***************************************************************************/
LPTSTR
AllocAndExpandEnvironmentStrings(
LPCTSTR lpszSrc
)
{
LPTSTR String;
LONG LengthAllocated;
LONG LengthCopied;
//
// Pick a random buffer length, if it's not big enough reallocate
// it and try again until it is.
//
LengthAllocated = lstrlen(lpszSrc) + TYPICAL_STRING_LENGTH;
String = Alloc(LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
return(NULL);
}
while (TRUE) {
LengthCopied = ExpandEnvironmentStrings( lpszSrc,
String,
LengthAllocated
);
if (LengthCopied == 0) {
DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : ExpandEnvironmentStrings failed, error = %d", GetLastError()));
Free(String);
String = NULL;
break;
}
//
// If the buffer was too small, make it bigger and try again
//
if (LengthCopied > LengthAllocated) {
VerbosePrint(("AllocAndExpandEnvironmentStrings: Failed with buffer length = %d, reallocating to %d and retrying (retry should succeed)", LengthAllocated, LengthCopied));
String = ReAlloc(String, LengthCopied * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
break;
}
//
// Go back and try to expand the string again
//
} else {
//
// Success!
//
break;
}
}
return(String);
}
/***************************************************************************\
* FUNCTION: AllocAndRegEnumKey
*
* PURPOSE: Allocates memory for and returns pointer to buffer containing
* the next registry sub-key name under the specified key
* The returned buffer should be freed using Free()
*
* RETURNS: Pointer to sub-key name or NULL on failure. The reason for the
* error can be obtains using GetLastError()
*
* HISTORY:
*
* 21-Dec-92 Davidc Created.
*
\***************************************************************************/
LPTSTR
AllocAndRegEnumKey(
HKEY hKey,
DWORD iSubKey
)
{
LPTSTR String;
LONG LengthAllocated;
//
// Pick a random buffer length, if it's not big enough reallocate
// it and try again until it is.
//
LengthAllocated = TYPICAL_STRING_LENGTH;
String = Alloc(LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
return(NULL);
}
while (TRUE) {
DWORD Error = RegEnumKey(hKey, iSubKey, String, LengthAllocated);
if (Error == ERROR_SUCCESS) {
break;
}
if (Error != ERROR_MORE_DATA) {
if (Error != ERROR_NO_MORE_ITEMS) {
DebugLog((DEB_ERROR, "AllocAndRegEnumKey : RegEnumKey failed, error = %d", Error));
}
Free(String);
String = NULL;
SetLastError(Error);
break;
}
//
// The buffer was too small, make it bigger and try again
//
VerbosePrint(("AllocAndRegEnumKey: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
LengthAllocated *= 2;
String = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
break;
}
}
return(String);
}
/***************************************************************************\
* FUNCTION: AllocAndRegQueryValueEx
*
* PURPOSE: Version of RegQueryValueEx that returns value in allocated buffer.
* The returned buffer should be freed using Free()
*
* RETURNS: Pointer to key value or NULL on failure. The reason for the
* error can be obtains using GetLastError()
*
* HISTORY:
*
* 15-Jan-93 Davidc Created.
*
\***************************************************************************/
LPTSTR
AllocAndRegQueryValueEx(
HKEY hKey,
LPTSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType
)
{
LPTSTR String;
DWORD BytesAllocated;
//
// Pick a random buffer length, if it's not big enough reallocate
// it and try again until it is.
//
BytesAllocated = TYPICAL_STRING_LENGTH * sizeof(TCHAR);
String = Alloc(BytesAllocated);
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to allocate %d bytes for string", BytesAllocated));
return(NULL);
}
while (TRUE) {
DWORD Error;
DWORD BytesReturned = BytesAllocated;
Error = RegQueryValueEx(hKey,
lpValueName,
lpReserved,
lpType,
(LPBYTE)String,
&BytesReturned);
if (Error == ERROR_SUCCESS) {
break;
}
if (Error != ERROR_MORE_DATA) {
DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : RegQueryValueEx failed, error = %d", Error));
Free(String);
String = NULL;
SetLastError(Error);
break;
}
//
// The buffer was too small, make it bigger and try again
//
VerbosePrint(("AllocAndRegQueryValueEx: Failed with buffer length = %d bytes, reallocating and retrying", BytesAllocated));
BytesAllocated *= 2;
String = ReAlloc(String, BytesAllocated);
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to reallocate %d bytes for string", BytesAllocated));
break;
}
}
return(String);
}
/***************************************************************************\
* FUNCTION: ReadWinlogonBoolValue
*
* PURPOSE: Determines the correct BOOL value for the requested
* value name by first looking up the machine preference
* and then checking for policy
*
* RETURNS: TRUE or FALSE
*
* HISTORY:
*
* EricFlo 10-14-98 Created
*
\***************************************************************************/
BOOL
ReadWinlogonBoolValue (LPTSTR lpValueName, BOOL bDefault)
{
BOOL bResult;
HKEY hKey;
DWORD dwSize, dwType;
//
// Get the machine preference first
//
bResult = GetProfileInt(APPLICATION_NAME, lpValueName, bDefault);
//
// Check for a machine policy
//
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY,
0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
dwSize = sizeof(bResult);
RegQueryValueEx(hKey, lpValueName, 0, &dwType,
(LPBYTE)&bResult, &dwSize);
RegCloseKey (hKey);
}
return bResult;
}
/***************************************************************************\
* HandleComboBoxOK
*
* Deals with UI requirements when OK is selected in a dialog when the
* focus is on or in a combo-box.
*
* This routine should be called from a dialog proc that contains a
* combo-box when a WM_COMMAND, IDOK is received.
*
* Returns TRUE if the message was dealt with and the caller should ignore it,
* FALSE if this routine did nothing with it and the caller should process it
* normally.
*
* History:
* 24-Sep-92 Davidc Created.
\***************************************************************************/
BOOL
HandleComboBoxOK(
HWND hDlg,
int ComboBoxId
)
{
HWND hwndFocus = GetFocus();
HWND hwndCB = GetDlgItem(hDlg, ComboBoxId);
//
// Hitting enter on a combo-box with the list showing should simply
// hide the list.
// We check for focus window being a child of the combo-box to
// handle non-list style combo-boxes which have the focus on
// the child edit control.
//
if ((hwndFocus == hwndCB) || IsChild(hwndCB, hwndFocus)) {
if (SendMessage(hwndCB, CB_GETDROPPEDSTATE, 0, 0)) {
//
// Make the list-box disappear and we're done.
//
SendMessage(hwndCB, CB_SHOWDROPDOWN, (WPARAM)FALSE, 0);
return(TRUE);
}
}
//
// We didn't do anything
//
return(FALSE);
}
/***************************************************************************\
* FUNCTION: EncodeMultiSzW
*
* PURPOSE: Converts a multi-sz string and encodes it to look like
* a single string.
*
* We replace the terminators between strings
* with the TERMINATOR_REPLACEMENT character. We replace
* existing occurrences of the replacement character with
* two of them.
*
* RETURNS: Pointer to encoded string or NULL on failure.
* The returned buffer should be freed using Free()
*
* HISTORY:
*
* 01-12-93 Davidc Created.
*
\***************************************************************************/
#define TERMINATOR_REPLACEMENT TEXT(',')
LPWSTR
EncodeMultiSzW(
IN LPWSTR MultiSz
)
{
DWORD Length;
DWORD NewLength;
LPWSTR NewBuffer;
LPWSTR p, q;
DWORD ExtraCharacters;
//
// First calculate the length of the new string (with replacements)
//
p = MultiSz;
ExtraCharacters = 0;
while (*p) {
while (*p) {
if (*p == TERMINATOR_REPLACEMENT) {
ExtraCharacters ++;
}
p ++;
}
p ++;
}
Length = (DWORD)(p - MultiSz); // p points at 'second' (final) null terminator
NewLength = Length + ExtraCharacters;
//
// Allocate space for the new string
//
NewBuffer = Alloc((NewLength + 1) * sizeof(WCHAR));
if (NewBuffer == NULL) {
DebugLog((DEB_ERROR, "EncodeMultiSz: failed to allocate space for %d bytes", (NewLength + 1) * sizeof(WCHAR)));
return(NULL);
}
//
// Copy the string into the new buffer making replacements as we go
//
p = MultiSz;
q = NewBuffer;
while (*p) {
while (*p) {
*q = *p;
if (*p == TERMINATOR_REPLACEMENT) {
q ++;
*q = TERMINATOR_REPLACEMENT;
}
p ++;
q ++;
}
*q = TERMINATOR_REPLACEMENT;
p ++;
q ++;
}
ASSERT((DWORD)(q - NewBuffer) == NewLength);
//
// Add terminator
//
*q = 0;
return(NewBuffer);
}
/***************************************************************************\
* TimeoutMessageBox
*
* Same as a normal message box, but times out if there is no user input
* for the specified number of seconds
* For convenience, this api takes string resource ids rather than string
* pointers as input. The resources are loaded from the .exe module
*
* 12-05-91 Davidc Created.
\***************************************************************************/
INT_PTR
TimeoutMessageBox(
HWND hwnd,
PGLOBALS pGlobals,
UINT IdText,
UINT IdCaption,
UINT wType,
TIMEOUT Timeout
)
{
TCHAR CaptionBuffer[MAX_STRING_BYTES];
PTCHAR Caption = CaptionBuffer;
TCHAR Text[MAX_STRING_BYTES];
LoadString(hDllInstance, IdText, Text, MAX_STRING_LENGTH);
if (IdCaption != 0) {
LoadString(hDllInstance, IdCaption, Caption, MAX_STRING_LENGTH);
} else {
Caption = NULL;
}
return TimeoutMessageBoxlpstr(hwnd, pGlobals, Text, Caption, wType, Timeout);
}
/***************************************************************************\
* TimeoutMessageBoxlpstr
*
* Same as a normal message box, but times out if there is no user input
* for the specified number of seconds
*
* 12-05-91 Davidc Created.
\***************************************************************************/
INT_PTR
TimeoutMessageBoxlpstr(
HWND hwnd,
PGLOBALS pGlobals,
LPTSTR Text,
LPTSTR Caption,
UINT wType,
TIMEOUT Timeout
)
{
INT_PTR DlgResult;
BOOL fStatusHostHidden;
fStatusHostHidden = _Shell_LogonStatus_IsHidden();
_Shell_LogonStatus_Hide();
// Set up input timeout
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, Timeout);
DlgResult = pWlxFuncs->WlxMessageBox( pGlobals->hGlobalWlx,
hwnd,
Text,
Caption,
wType);
if (!fStatusHostHidden)
{
_Shell_LogonStatus_Show();
}
return(DlgResult);
}
PWSTR
DupString(PWSTR pszString)
{
DWORD cbString;
PWSTR pszNewString;
cbString = (DWORD) (wcslen(pszString) + 1) * sizeof(WCHAR);
pszNewString = LocalAlloc(LMEM_FIXED, cbString);
if (pszNewString)
{
CopyMemory(pszNewString, pszString, cbString);
}
return(pszNewString);
}
PWSTR
DupUnicodeString(PUNICODE_STRING pString)
{
PWSTR pszNewString;
if (pString->Length)
{
pszNewString = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, pString->Length + sizeof(WCHAR));
if (pszNewString)
{
CopyMemory(pszNewString, pString->Buffer, pString->Length);
}
}
else
pszNewString = NULL;
return(pszNewString);
}
/***************************************************************************\
* FUNCTION: EnableDomainForUPN
*
* PURPOSE: Enables or disables the domain text box based on whether or not
* a UPN-style name is typed into the username box.
*
* RETURNS: none
*
* HISTORY:
*
* 04-17-1998 dsheldon created
*
\***************************************************************************/
void EnableDomainForUPN(HWND hwndUsername, HWND hwndDomain)
{
BOOL fEnable;
// Get the string the user is typing
TCHAR* pszLogonName;
int cchBuffer = (int)SendMessage(hwndUsername, WM_GETTEXTLENGTH, 0, 0) + 1;
pszLogonName = (TCHAR*) Alloc(cchBuffer * sizeof(TCHAR));
if (pszLogonName != NULL)
{
SendMessage(hwndUsername, WM_GETTEXT, (WPARAM) cchBuffer, (LPARAM) pszLogonName);
// Disable the domain combo if the user is using a
// UPN (if there is a "@") - ie foo@microsoft.com
fEnable = (NULL == wcschr(pszLogonName, TEXT('@')));
EnableWindow(hwndDomain, fEnable);
Free(pszLogonName);
}
}
// TRUE if we must always hide the domain box (local logon, UPN, smartcard only)
// FALSE if this policy isn't set or is set to 0x0
BOOL ForceNoDomainUI()
{
DWORD dwPolicyVal = 0;
HKEY hkey;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_QUERY_VALUE, &hkey))
{
DWORD cbData = sizeof (dwPolicyVal);
DWORD dwType;
if (ERROR_SUCCESS != RegQueryValueEx(hkey, NODOMAINCOMBO, 0, &dwType, (LPBYTE) &dwPolicyVal, &cbData))
{
dwPolicyVal = 0;
}
RegCloseKey(hkey);
}
return (0 != dwPolicyVal);
}
DWORD GetReasonSelection(HWND hwndCombo)
{
DWORD dwResult;
PREASON pReason;
int iItem = ComboBox_GetCurSel(hwndCombo);
if (iItem != (int) CB_ERR) {
pReason = (PREASON) ComboBox_GetItemData(hwndCombo, iItem);
dwResult = pReason->dwCode;
} else {
dwResult = SHTDN_REASON_UNKNOWN;
}
return dwResult;
}
VOID SetReasonDescription(HWND hwndCombo, HWND hwndStatic)
{
PREASON pReason;
int iItem = ComboBox_GetCurSel(hwndCombo);
if (iItem != CB_ERR) {
pReason = (PREASON) ComboBox_GetItemData(hwndCombo, iItem);
SetWindowText(hwndStatic, pReason->szDesc);
}
}