/*++ Copyright (c) 1996 Microsoft Corporation Module Name: ntui.c Abstract: Processing indicator dialog shows percentage of completion in a progress bar. The progress is updated by the caller. Author: Jim Schmidt (jimschm) 13-Aug-1996 Revision History: jimschm 19-Oct-1998 Updated to use wizard status line jimschm 23-Sep-1998 Redesigned domain account resolution jimschm 02-Jul-1998 Finally rewrote progress bar jimschm 18-Dec-1996 Moved to new lib, slated to be rewritten --*/ #include "pch.h" static PCTSTR g_LocalAccountString; static PCTSTR g_SearchAgainString; static HWND g_StatusPopup; static OUR_CRITICAL_SECTION g_StatusPopupCs; static HANDLE g_AbortDelayEvent; static HANDLE g_DelayThread; static BOOL g_ClassRegistered = FALSE; static DWORD g_ThreadId; #define WMX_SETTEXT (WM_USER+500) #define S_STATUS_CLASS TEXT("StatusWnd") typedef struct { INT ConversionX; INT ConversionY; } CONVERSIONFACTORS, *PCONVERSIONFACTORS; #define CONVERSION_RESOLUTION 100 VOID pShowStatusPopup ( VOID ); VOID pKillDelayThread ( VOID ); VOID pUpdateDialog ( HWND hdlg, PRESOLVE_ACCOUNTS_ARRAY Array, BOOL UserList, BOOL DomainList ) { HWND hwndUsers; HWND hwndDomain; UINT Count; TCHAR Buf[256]; UINT Selection; UINT Index; UINT Item; PCTSTR *DomainNamePtr; PCTSTR Message; PCTSTR ArgArray[1]; hwndUsers = GetDlgItem (hdlg, IDC_USER_LIST); hwndDomain = GetDlgItem (hdlg, IDC_DOMAIN_LIST); if (UserList) { // // Populate the list box with logs onto // Selection = SendMessage (hwndUsers, LB_GETCURSEL, 0, 0); if (Selection == LB_ERR) { Selection = 0; } SendMessage (hwndUsers, LB_RESETCONTENT, 0, 0); for (Count = 0 ; Array[Count].UserName ; Count++) { if (Array[Count].RetryFlag) { wsprintf ( Buf, TEXT("%s\t%s"), Array[Count].UserName, g_SearchAgainString ); } else { wsprintf ( Buf, TEXT("%s\t%s"), Array[Count].UserName, Array[Count].OutboundDomain ? Array[Count].OutboundDomain : g_LocalAccountString ); } Item = SendMessage (hwndUsers, LB_ADDSTRING, 0, (LPARAM) Buf); SendMessage (hwndUsers, LB_SETITEMDATA, Item, Count); } SendMessage (hwndUsers, LB_SETCURSEL, Selection, 0); } if (DomainList) { // // Get the current user selection // Selection = SendMessage (hwndUsers, LB_GETCURSEL, 0, 0); if (Selection == LB_ERR) { Selection = 0; } Index = SendMessage (hwndUsers, LB_GETITEMDATA, Selection, 0); // // Fill the combo box // SendMessage (hwndDomain, CB_RESETCONTENT, 0, 0); DomainNamePtr = Array[Index].DomainArray; // Insert all domain names while (*DomainNamePtr) { Item = SendMessage (hwndDomain, CB_ADDSTRING, 0, (LPARAM) (*DomainNamePtr)); SendMessage (hwndDomain, CB_SETITEMDATA, Item, (LPARAM) (*DomainNamePtr)); DomainNamePtr++; } // Insert standard strings Item = SendMessage (hwndDomain, CB_ADDSTRING, 0, (LPARAM) g_LocalAccountString); SendMessage (hwndDomain, CB_SETITEMDATA, Item, (LPARAM) g_LocalAccountString); Item = SendMessage (hwndDomain, CB_ADDSTRING, 0, (LPARAM) g_SearchAgainString); SendMessage (hwndDomain, CB_SETITEMDATA, Item, (LPARAM) g_SearchAgainString); // Restore selection if (Array[Index].RetryFlag) { Item = SendMessage (hwndDomain, CB_FINDSTRINGEXACT, 0, (LPARAM) g_SearchAgainString); SendMessage (hwndDomain, CB_SETCURSEL, Item, 0); } else if (Array[Index].OutboundDomain) { Item = SendMessage (hwndDomain, CB_FINDSTRINGEXACT, 0, (LPARAM) (Array[Index].OutboundDomain)); SendMessage (hwndDomain, CB_SETCURSEL, Item, 0); } else { Item = SendMessage (hwndDomain, CB_FINDSTRINGEXACT, 0, (LPARAM) g_LocalAccountString); SendMessage (hwndDomain, CB_SETCURSEL, Item, 0); } ArgArray[0] = Array[Index].UserName; Message = ParseMessageID (MSG_USER_DOMAIN_LOGON_DLG, ArgArray); SetDlgItemText (hdlg, IDC_DOMAIN_LIST_TITLE, Message); FreeStringResource (Message); } } VOID pInitConversionFactors ( IN HWND hdlg, OUT PCONVERSIONFACTORS Factors ) { RECT rect; rect.left = 0; rect.right = CONVERSION_RESOLUTION; rect.top = 0; rect.bottom = CONVERSION_RESOLUTION; MapDialogRect (hdlg, &rect); Factors->ConversionX = rect.right - rect.left; Factors->ConversionY = rect.bottom - rect.top; } INT pConvertPixelsToDialogX ( IN PCONVERSIONFACTORS Factors, IN INT Pixels ) { return CONVERSION_RESOLUTION * Pixels / Factors->ConversionX; } INT pConvertPixelsToDialogY ( IN PCONVERSIONFACTORS Factors, IN INT Pixels ) { return CONVERSION_RESOLUTION * Pixels / Factors->ConversionY; } BOOL CALLBACK pResolveAccountsDlgProc ( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) /*++ Routine Description: pResolveAccountsDlgProc prompts the user with a list of domain choices, the local machine, or retry the network search. Upon init, the lParam specifies the RESULT_ACCOUNTS_ARRAY pointer that provides the user list and initial state. Upon exit, the array is updated to reflect the user's choices. Arguments: hdlg - The dialog handle uMsg - The message to process wParam - The wParam for the message lParam - The lParam for the message Return value: The dialog always ends with IDOK. --*/ { static PRESOLVE_ACCOUNTS_ARRAY Array; static CONVERSIONFACTORS Factors; RECT rect; INT Tabs; UINT Selection; UINT Index; HWND hwndList; PCTSTR NewDomain; switch (uMsg) { case WM_INITDIALOG: CenterWindow (hdlg, GetDesktopWindow()); Array = (PRESOLVE_ACCOUNTS_ARRAY) lParam; MYASSERT (Array); pInitConversionFactors (hdlg, &Factors); // // Get the strings // g_LocalAccountString = GetStringResource (MSG_LOCAL_ACCOUNT_DLG); g_SearchAgainString = GetStringResource (MSG_DOMAIN_NOT_LISTED_DLG); // // Set the tab stops // GetWindowRect (GetDlgItem (hdlg, IDC_USER_TITLE), &rect); Tabs = pConvertPixelsToDialogX (&Factors, (rect.right - rect.left) + 8); SendMessage (GetDlgItem (hdlg, IDC_USER_LIST), LB_SETTABSTOPS, 1, (LPARAM) &Tabs); // // Clear the retry flag // for (Index = 0 ; Array[Index].UserName ; Index++) { Array[Index].RetryFlag = FALSE; } // // Fill the controls // pUpdateDialog (hdlg, Array, TRUE, TRUE); return TRUE; case WM_COMMAND: switch (LOWORD (wParam)) { case IDOK: FreeStringResource (g_LocalAccountString); g_LocalAccountString = NULL; FreeStringResource (g_SearchAgainString); g_SearchAgainString = NULL; EndDialog (hdlg, IDOK); return TRUE; case IDC_USER_LIST: if (HIWORD (wParam) == LBN_SELCHANGE) { pUpdateDialog (hdlg, Array, FALSE, TRUE); } return TRUE; case IDC_DOMAIN_LIST: if (HIWORD (wParam) == CBN_SELCHANGE) { hwndList = GetDlgItem (hdlg, IDC_USER_LIST); Selection = SendMessage (hwndList, LB_GETCURSEL, 0, 0); Index = SendMessage (hwndList, LB_GETITEMDATA, Selection, 0); hwndList = GetDlgItem (hdlg, IDC_DOMAIN_LIST); Selection = SendMessage (hwndList, CB_GETCURSEL, 0, 0); NewDomain = (PCTSTR) SendMessage (hwndList, CB_GETITEMDATA, Selection, 0); if (NewDomain == g_LocalAccountString) { Array[Index].OutboundDomain = NULL; Array[Index].RetryFlag = FALSE; } else if (NewDomain == g_SearchAgainString) { Array[Index].OutboundDomain = NULL; Array[Index].RetryFlag = TRUE; } else { Array[Index].OutboundDomain = NewDomain; Array[Index].RetryFlag = FALSE; } pUpdateDialog (hdlg, Array, TRUE, FALSE); } } break; } return FALSE; } BOOL CALLBACK NetworkDownDlgProc ( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) /*++ Routine Description: NetworkDownDlgProc asks the user if they want to: (A) Continue searching with retry prompts (B) Continue searching, skipping down domains (C) Stop searching Arguments: hdlg - The dialog handle uMsg - The message to process wParam - The wParam for the message lParam - The lParam for the message Return value: The call to DialogBox returns: IDC_STOP - Stop searching IDC_RETRY - Continue with retry IDC_NO_RETRY - Continue without retry --*/ { switch (uMsg) { case WM_INITDIALOG: CenterWindow (hdlg, GetDesktopWindow()); CheckDlgButton (hdlg, IDC_RETRY, TRUE); return TRUE; case WM_COMMAND: switch (LOWORD (wParam)) { case IDOK: if (IsDlgButtonChecked (hdlg, IDC_RETRY)) { EndDialog (hdlg, IDC_RETRY); } else if (IsDlgButtonChecked (hdlg, IDC_NO_RETRY)) { EndDialog (hdlg, IDC_NO_RETRY); } else if (IsDlgButtonChecked (hdlg, IDC_STOP)) { EndDialog (hdlg, IDC_STOP); } return TRUE; } break; } return FALSE; } VOID ResolveAccounts ( PRESOLVE_ACCOUNTS_ARRAY Array ) { DialogBoxParam ( g_hInst, MAKEINTRESOURCE (IDD_CHOOSE_DOMAIN), g_ParentWnd, pResolveAccountsDlgProc, (LPARAM) Array ); } LRESULT CALLBACK pStatusWndProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { RECT Desktop; RECT Client; INT Top, Left; INT Width, Height; INT TextWidth, TextHeight; static HWND StatusText; PCTSTR InitialMsg; TEXTMETRIC tm; HDC hdc; switch (uMsg) { case WM_CREATE: g_StatusPopup = hwnd; InitialMsg = GetStringResource (MSG_INITIAL_STATUS_MSG); MYASSERT (InitialMsg); // // Compute proper size // GetWindowRect (GetDesktopWindow(), &Desktop); hdc = CreateDC (TEXT("DISPLAY"), NULL, NULL, NULL); SelectObject (hdc, GetStockObject (DEFAULT_GUI_FONT)); GetTextMetrics (hdc, &tm); DeleteDC (hdc); Width = (Desktop.right - Desktop.left) / 2; Height = (Desktop.bottom - Desktop.top) / 20; TextWidth = tm.tmAveCharWidth * 3 * CharCount (InitialMsg); TextHeight = tm.tmHeight * 3; Width = min (Width, TextWidth); Height = min (Height, TextHeight); Top = Desktop.bottom - Height - tm.tmAveCharWidth; Left = Desktop.right - Width - tm.tmHeight; SetWindowPos (hwnd, HWND_TOPMOST, Left, Top, Width, Height, SWP_NOACTIVATE); // // Create text window // GetClientRect (hwnd, &Client); Width = (Client.right - Client.left) * 7 / 8; Height = (Client.bottom - Client.top) * 7 / 8; Top = (Client.right - Client.left) / 16; Left = (Client.bottom - Client.top) / 16; StatusText = CreateWindow ( TEXT("STATIC"), InitialMsg, WS_CHILD|WS_VISIBLE|SS_NOPREFIX|SS_CENTERIMAGE, Top, Left, Width, Height, hwnd, (PVOID) 100, g_hInst, NULL ); SendMessage (StatusText, WM_SETFONT, (WPARAM) GetStockObject (DEFAULT_GUI_FONT), 0); // // Make window initially hidden // HideStatusPopup (STATUS_DELAY); FreeStringResource (InitialMsg); return TRUE; case WMX_SETTEXT: SetWindowText (StatusText, (PCTSTR) lParam); break; case WM_DESTROY: if (StatusText) { DestroyWindow (StatusText); StatusText = NULL; } break; } return DefWindowProc (hwnd, uMsg, wParam, lParam); } DWORD WINAPI pStatusDlgThread ( PVOID Arg ) { WNDCLASS wc; HWND hwnd; MSG msg; if (!g_ClassRegistered) { ZeroMemory (&wc, sizeof (wc)); wc.lpfnWndProc = pStatusWndProc; wc.hInstance = g_hInst; wc.hbrBackground = (HBRUSH) COLOR_WINDOW; wc.lpszClassName = S_STATUS_CLASS; RegisterClass (&wc); g_ClassRegistered = TRUE; } hwnd = CreateWindowEx ( 0, S_STATUS_CLASS, TEXT(""), WS_POPUP|WS_BORDER|WS_THICKFRAME, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, g_ParentWnd, NULL, g_hInst, NULL ); while (GetMessage (&msg, NULL, 0, 0)) { if (msg.hwnd == NULL) { if (msg.message == WM_CLOSE) { break; } } TranslateMessage (&msg); DispatchMessage (&msg); } DestroyWindow (g_StatusPopup); g_StatusPopup = NULL; return 0; } VOID CreateStatusPopup ( VOID ) { HWND Child; PCTSTR InitialMsg; g_StatusPopup = GetDlgItem (g_ParentWnd, IDC_PROGRESS_BAR_LABEL); if (!g_StatusPopup) { // // Scan all children for IDC_PROGRESS_BAR_LABEL // Child = GetWindow (g_ParentWnd, GW_CHILD); while (Child) { g_StatusPopup = GetDlgItem (Child, IDC_PROGRESS_BAR_LABEL); if (g_StatusPopup) { break; } Child = GetWindow (Child, GW_HWNDNEXT); } } MYASSERT (g_StatusPopup); HideStatusPopup (STATUS_DELAY); InitialMsg = GetStringResource (MSG_INITIAL_STATUS_MSG); if (InitialMsg) { SetWindowText (g_StatusPopup, InitialMsg); FreeStringResource (InitialMsg); } #if 0 HANDLE Thread; InitializeOurCriticalSection (&g_StatusPopupCs); Thread = CreateThread ( NULL, 0, pStatusDlgThread, NULL, 0, &g_ThreadId ); MYASSERT (Thread); CloseHandle (Thread); #endif } VOID DestroyStatusPopup ( VOID ) { pKillDelayThread(); EnterOurCriticalSection (&g_StatusPopupCs); if (g_StatusPopup) { ShowWindow (g_StatusPopup, SW_HIDE); //PostThreadMessage (g_ThreadId, WM_CLOSE, 0, 0); } if (g_AbortDelayEvent) { CloseHandle (g_AbortDelayEvent); g_AbortDelayEvent = NULL; } LeaveOurCriticalSection (&g_StatusPopupCs); DeleteOurCriticalSection (&g_StatusPopupCs); } VOID UpdateStatusPopup ( PCTSTR NewMessage ) { EnterOurCriticalSection (&g_StatusPopupCs); if (g_StatusPopup) { SetWindowText (g_StatusPopup, NewMessage); #if 0 SendMessage (g_StatusPopup, WMX_SETTEXT, 0, (LPARAM) NewMessage); #endif } LeaveOurCriticalSection (&g_StatusPopupCs); } DWORD WINAPI pDelayThenShowStatus ( PVOID Arg ) { DWORD Result; Result = WaitForSingleObject (g_AbortDelayEvent, (UINT) Arg); if (WAIT_TIMEOUT == Result) { EnterOurCriticalSection (&g_StatusPopupCs); pShowStatusPopup(); LeaveOurCriticalSection (&g_StatusPopupCs); } EnterOurCriticalSection (&g_StatusPopupCs); if (g_AbortDelayEvent) { CloseHandle (g_AbortDelayEvent); g_AbortDelayEvent = NULL; } LeaveOurCriticalSection (&g_StatusPopupCs); return 0; } VOID pKillDelayThread ( VOID ) { // // This routine makes sure the delay thread is stopped, // that the thread handle is closed, and that the show event // is cleaned up. // // There is no affect on the visibility of the status dialog. // if (!g_DelayThread) { return; } EnterOurCriticalSection (&g_StatusPopupCs); if (g_AbortDelayEvent) { SetEvent (g_AbortDelayEvent); } LeaveOurCriticalSection (&g_StatusPopupCs); WaitForSingleObject (g_DelayThread, INFINITE); EnterOurCriticalSection (&g_StatusPopupCs); CloseHandle (g_DelayThread); g_DelayThread = NULL; LeaveOurCriticalSection (&g_StatusPopupCs); } VOID HideStatusPopup ( UINT Timeout ) { pKillDelayThread(); EnterOurCriticalSection (&g_StatusPopupCs); ShowWindow (g_StatusPopup, SW_HIDE); if (Timeout != INFINITE) { MYASSERT (!g_DelayThread); MYASSERT (!g_AbortDelayEvent); g_AbortDelayEvent = CreateEvent (NULL, TRUE, FALSE, NULL); g_DelayThread = StartThread (pDelayThenShowStatus, (PVOID) Timeout); } LeaveOurCriticalSection (&g_StatusPopupCs); } VOID pShowStatusPopup ( VOID ) { // // Caller handles mutex // if (g_StatusPopup) { ShowWindow (g_StatusPopup, SW_SHOW); UpdateWindow (g_StatusPopup); } #if 0 if (g_StatusPopup) { SetWindowPos ( g_StatusPopup, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE ); UpdateWindow (g_StatusPopup); } #endif } VOID ShowStatusPopup ( VOID ) { pKillDelayThread(); EnterOurCriticalSection (&g_StatusPopupCs); pShowStatusPopup(); LeaveOurCriticalSection (&g_StatusPopupCs); } BOOL IsStatusPopupVisible ( VOID ) { BOOL b; EnterOurCriticalSection (&g_StatusPopupCs); b = IsWindowVisible (g_StatusPopup); LeaveOurCriticalSection (&g_StatusPopupCs); return b; }