1362 lines
39 KiB
C++
1362 lines
39 KiB
C++
|
// UMDialog.cpp : implementation file
|
||
|
// Author: J. Eckhardt, ECO Kommunikation
|
||
|
// Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
//
|
||
|
// History:
|
||
|
// Changes
|
||
|
// Yuri Khramov
|
||
|
// 01-jun-99: DisplayName key used in the Dialog (Localization)
|
||
|
// 11-jun-99: DlgHasClosed code changed to work with app closure
|
||
|
// 15-jun-99: Timer delay increased 1000ms
|
||
|
//
|
||
|
// Bug fixes and Changes Anil Kumar 1999
|
||
|
//---------------------------------------------------------------------
|
||
|
#include <afxwin.h> // MFC core and standard components
|
||
|
#include <afxext.h> // MFC extensions
|
||
|
#include "UManDlg.h"
|
||
|
#include "UMDialog.h"
|
||
|
#include "UMAbout.h"
|
||
|
#include "_UMDlg.h"
|
||
|
#include "_UMClnt.h"
|
||
|
#include "_UMTool.h"
|
||
|
#include "UMS_Ctrl.h"
|
||
|
#include "w95trace.h"
|
||
|
#include <WinSvc.h>
|
||
|
#include <htmlhelp.h>
|
||
|
#include <initguid.h>
|
||
|
#include <ole2.h>
|
||
|
#include "deskswitch.c"
|
||
|
#include "ManageShellLinks.h"
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// constants
|
||
|
#define IDC_ABOUT 10
|
||
|
#define UPDATE_CLIENT_LIST_TIMER 1
|
||
|
// --------------------------------------------
|
||
|
// variables
|
||
|
static DWORD g_cClients = 0;
|
||
|
static umclient_tsp g_rgClients = NULL;
|
||
|
static DWORD s_dwStartMode = START_BY_OTHER;
|
||
|
static BOOL s_fShowWarningAgain = TRUE;
|
||
|
extern CUMDlgApp theApp;
|
||
|
// --------------------------------------------
|
||
|
// C prototypes
|
||
|
static BOOL InitClientData(void);
|
||
|
static BOOL StartClientsOnShow();
|
||
|
static BOOL WriteClientData(BOOL fRunningSecure);
|
||
|
static BOOL IsStartAuto();
|
||
|
static BOOL CantStopClient(umclient_tsp client);
|
||
|
static int GetClientNameFromAccelerator(WPARAM wVK);
|
||
|
|
||
|
extern "C" BOOL StartAppAsUser( LPCTSTR appPath,
|
||
|
LPTSTR cmdLine,
|
||
|
LPSTARTUPINFO lpStartupInfo,
|
||
|
LPPROCESS_INFORMATION lpProcessInformation);
|
||
|
|
||
|
|
||
|
// Help ID's for context sensitive help
|
||
|
DWORD g_rgHelpIds[] = {
|
||
|
IDC_NAME_STATUS, 3,
|
||
|
IDC_START, 1001,
|
||
|
IDC_STOP, 1002,
|
||
|
IDC_START_AT_LOGON, 1003, // TODO UE needs to update CS help
|
||
|
IDC_START_WITH_UM, 1004,
|
||
|
IDC_START_ON_LOCK, 1005, // TODO UE needs to add to CS help
|
||
|
IDOK, 1100,
|
||
|
IDCANCEL, 1200,
|
||
|
ID_HELP, 1300,
|
||
|
};
|
||
|
|
||
|
// ---------------------------------------------------------------
|
||
|
extern "C"{
|
||
|
//--------------------------------
|
||
|
HWND g_hWndDlg = NULL;
|
||
|
HWND aboutWnd = NULL;
|
||
|
static HANDLE s_hDlgThread = NULL;
|
||
|
|
||
|
static HDESK s_hdeskSave = 0;
|
||
|
static HDESK s_hdeskInput = 0;
|
||
|
|
||
|
// UnassignDesktop gets called after the thread has exited to
|
||
|
// close desktop handles opened in AssignDesktop.
|
||
|
inline void UnassignDesktop()
|
||
|
{
|
||
|
if (s_hdeskInput)
|
||
|
{
|
||
|
CloseDesktop(s_hdeskInput);
|
||
|
s_hdeskInput = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL AssignDesktop(DWORD dwThreadId)
|
||
|
{
|
||
|
s_hdeskSave = GetThreadDesktop(dwThreadId);
|
||
|
s_hdeskInput = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
|
||
|
if (!s_hdeskInput)
|
||
|
{
|
||
|
s_hdeskInput = OpenDesktop(_TEXT("Winlogon"),0,FALSE,MAXIMUM_ALLOWED);
|
||
|
}
|
||
|
|
||
|
if (s_hdeskInput)
|
||
|
{
|
||
|
BOOL fSet = SetThreadDesktop(s_hdeskInput);
|
||
|
}
|
||
|
return (s_hdeskInput)?TRUE:FALSE;
|
||
|
}
|
||
|
|
||
|
//--------------------------------
|
||
|
DWORD UManDlgThread(LPVOID /* UNUSED */ in)
|
||
|
{
|
||
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||
|
|
||
|
UMDialog dlg;
|
||
|
|
||
|
// assign thread to the input desktop (have to do
|
||
|
// this here so it works on the winlogon desktop)
|
||
|
|
||
|
if (AssignDesktop(GetCurrentThreadId()))
|
||
|
{
|
||
|
// initialize COM *after* assign to input desktop
|
||
|
// because CoInitialize creates a hidden window on
|
||
|
// the current desktop.
|
||
|
|
||
|
CoInitialize(NULL);
|
||
|
InitCommonControls();
|
||
|
|
||
|
if (InitClientData())
|
||
|
{
|
||
|
Sleep(10);
|
||
|
dlg.DoModal();
|
||
|
if (g_rgClients)
|
||
|
{
|
||
|
VirtualFree(g_rgClients,0,MEM_RELEASE);
|
||
|
g_rgClients = NULL;
|
||
|
}
|
||
|
g_cClients = 0;
|
||
|
g_hWndDlg = NULL;
|
||
|
s_hDlgThread = NULL;
|
||
|
}
|
||
|
|
||
|
CoUninitialize(); // uninitialize COM
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void StopDialog()
|
||
|
{
|
||
|
if (aboutWnd)
|
||
|
{
|
||
|
EndDialog(aboutWnd,0);
|
||
|
aboutWnd = NULL;
|
||
|
Sleep(10);
|
||
|
}
|
||
|
if (g_hWndDlg)
|
||
|
{
|
||
|
::PostMessage(g_hWndDlg, WM_CLOSE, 0, 0);
|
||
|
g_hWndDlg = NULL;
|
||
|
Sleep(10);
|
||
|
UnassignDesktop();
|
||
|
}
|
||
|
if (g_rgClients)
|
||
|
{
|
||
|
VirtualFree(g_rgClients,0,MEM_RELEASE);
|
||
|
g_rgClients = NULL;
|
||
|
}
|
||
|
g_cClients = 0;
|
||
|
}
|
||
|
|
||
|
//--------------------------------
|
||
|
#if defined(_X86_)
|
||
|
__declspec (dllexport)
|
||
|
#endif
|
||
|
// UManDlg - Opens or closes the utilman dialog.
|
||
|
//
|
||
|
// fShowDlg - TRUE if dialog should be shown, FALSE if dialog should be closed
|
||
|
// fWaitForDlgClose - TRUE if the function should not return until the dialog
|
||
|
// is closed or a desktop switch happens else FALSE.
|
||
|
// dwVersion - The utilman version
|
||
|
//
|
||
|
// returns TRUE if the dialog was opened or closed
|
||
|
// returns FALSE if the dialog could not be opened or it wasn't open
|
||
|
//
|
||
|
BOOL UManDlg(BOOL fShowDlg, BOOL fWaitForDlgClose, DWORD dwVersion)
|
||
|
{
|
||
|
BOOL fRv = FALSE;
|
||
|
if (dwVersion != UMANDLG_VERSION)
|
||
|
return FALSE;
|
||
|
|
||
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||
|
|
||
|
if (fShowDlg)
|
||
|
{
|
||
|
if (!s_hDlgThread)
|
||
|
{
|
||
|
s_hDlgThread = CreateThread(NULL, 0, UManDlgThread, NULL, 0, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetForegroundWindow((aboutWnd)?aboutWnd:g_hWndDlg);
|
||
|
}
|
||
|
|
||
|
if (s_hDlgThread && fWaitForDlgClose)
|
||
|
{
|
||
|
// This code is executed on the default desktop for the following cases:
|
||
|
//
|
||
|
// 1. Utilman #1 run from the start menu
|
||
|
// 2. Utilman #2 run from the start menu (utilman #1 is SYSTEM)
|
||
|
// 3. Utilman #2 run by utilman #1 in user's context
|
||
|
//
|
||
|
// Wait for either the dialog to close or a desktop switch then return.
|
||
|
// This will end this instance of utilman. If there is a utilman
|
||
|
// running as SYSTEM it will bring up the dialog on the other desktop.
|
||
|
|
||
|
HANDLE rghEvents[2];
|
||
|
|
||
|
rghEvents[0] = s_hDlgThread;
|
||
|
rghEvents[1] = OpenEvent(SYNCHRONIZE, FALSE, __TEXT("WinSta0_DesktopSwitch"));
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
DWORD dwObj = MsgWaitForMultipleObjects(2, rghEvents, FALSE, INFINITE, QS_ALLINPUT );
|
||
|
|
||
|
switch (dwObj)
|
||
|
{
|
||
|
case WAIT_OBJECT_0 + 1: // the desktop is changing; close the dialog
|
||
|
StopDialog();
|
||
|
// intentional fall thru to cleanup code
|
||
|
|
||
|
case WAIT_OBJECT_0: // the thread exited; clean up and return
|
||
|
CloseHandle(s_hDlgThread);
|
||
|
s_hDlgThread = 0;
|
||
|
CloseHandle(rghEvents[1]);
|
||
|
return TRUE;
|
||
|
break;
|
||
|
|
||
|
default: // process messages
|
||
|
{
|
||
|
MSG msg;
|
||
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||
|
{
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// This code is executed when utilman is running on the secure desktop. In
|
||
|
// that case, utilman brings up the dialog as a thread from its process.
|
||
|
// When the desktop switch is detected utilman calls this function to close
|
||
|
// the dialog. It will be restarted again on the new desktop.
|
||
|
|
||
|
fRv = (g_hWndDlg && s_hDlgThread);
|
||
|
|
||
|
StopDialog();
|
||
|
}
|
||
|
return fRv;
|
||
|
}
|
||
|
|
||
|
BOOL IsDialogUp()
|
||
|
{
|
||
|
return (g_hWndDlg && s_hDlgThread)?TRUE:FALSE;
|
||
|
}
|
||
|
|
||
|
}//extern "C"
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CWarningDlg dialog
|
||
|
|
||
|
|
||
|
CWarningDlg::CWarningDlg(CWnd* pParent /*=NULL*/)
|
||
|
: CDialog(CWarningDlg::IDD, pParent)
|
||
|
{
|
||
|
//{{AFX_DATA_INIT(CWarningDlg)
|
||
|
m_fDontWarnAgain = TRUE;
|
||
|
//}}AFX_DATA_INIT
|
||
|
}
|
||
|
|
||
|
|
||
|
void CWarningDlg::DoDataExchange(CDataExchange* pDX)
|
||
|
{
|
||
|
CDialog::DoDataExchange(pDX);
|
||
|
//{{AFX_DATA_MAP(CWarningDlg)
|
||
|
DDX_Check(pDX, IDC_CHK_WARN, m_fDontWarnAgain);
|
||
|
//}}AFX_DATA_MAP
|
||
|
}
|
||
|
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CWarningDlg, CDialog)
|
||
|
//{{AFX_MSG_MAP(CWarningDlg)
|
||
|
// NOTE: the ClassWizard will add message map macros here
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CWarningDlg message handlers
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// UMDialog dialog
|
||
|
// --------------------------------------------
|
||
|
UMDialog::UMDialog(CWnd* pParent /*=NULL*/)
|
||
|
: CDialog(UMDialog::IDD, pParent)
|
||
|
, m_fRunningSecure(FALSE)
|
||
|
{
|
||
|
m_szUMStr.LoadString(IDS_UM);
|
||
|
|
||
|
//{{AFX_DATA_INIT(UMDialog)
|
||
|
// NOTE: the ClassWizard will add member initialization here
|
||
|
//}}AFX_DATA_INIT
|
||
|
}
|
||
|
|
||
|
UMDialog::~UMDialog()
|
||
|
{
|
||
|
m_lbClientList.Detach();
|
||
|
}
|
||
|
// --------------------------------------------
|
||
|
void UMDialog::DoDataExchange(CDataExchange* pDX)
|
||
|
{
|
||
|
CDialog::DoDataExchange(pDX);
|
||
|
//{{AFX_DATA_MAP(UMDialog)
|
||
|
// NOTE: the ClassWizard will add DDX and DDV calls here
|
||
|
//}}AFX_DATA_MAP
|
||
|
}
|
||
|
// --------------------------------------------
|
||
|
BEGIN_MESSAGE_MAP(UMDialog, CDialog)
|
||
|
//{{AFX_MSG_MAP(UMDialog)
|
||
|
ON_WM_CLOSE()
|
||
|
ON_BN_CLICKED(IDC_START, OnStart)
|
||
|
ON_BN_CLICKED(IDC_STOP, OnStop)
|
||
|
ON_WM_TIMER()
|
||
|
ON_WM_HELPINFO()
|
||
|
ON_COMMAND( ID_HELP, OnHelp )
|
||
|
ON_LBN_SELCHANGE(IDC_NAME_STATUS, OnSelchangeNameStatus)
|
||
|
ON_BN_CLICKED(IDC_START_AT_LOGON, OnStartAtLogon)
|
||
|
ON_BN_CLICKED(IDC_START_WITH_UM, OnStartWithUm)
|
||
|
ON_WM_CONTEXTMENU()
|
||
|
ON_MESSAGE(WM_SYSCOMMAND,OnSysCommand)
|
||
|
ON_BN_CLICKED(IDC_START_ON_LOCK, OnStartOnLock)
|
||
|
ON_WM_SHOWWINDOW()
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// UMDialog message handlers
|
||
|
|
||
|
BOOL UMDialog::PreTranslateMessage(MSG* pMsg)
|
||
|
{
|
||
|
// Override that allows use of function keys to launch applets when on
|
||
|
// the logon desktop. Only pay attention to key up to avoid dup calls.
|
||
|
|
||
|
if (m_fRunningSecure && WM_KEYUP == pMsg->message)
|
||
|
{
|
||
|
int iClient = GetClientNameFromAccelerator(pMsg->wParam);
|
||
|
if (iClient >= 0)
|
||
|
{
|
||
|
m_lbClientList.SelectString(-1, g_rgClients[iClient].machine.DisplayName);
|
||
|
OnStart();
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return CDialog::PreTranslateMessage(pMsg);
|
||
|
}
|
||
|
|
||
|
BOOL UMDialog::OnInitDialog()
|
||
|
{
|
||
|
CDialog::OnInitDialog();
|
||
|
|
||
|
// set the flag indicating if we are running in secure mode
|
||
|
|
||
|
desktop_ts desktop;
|
||
|
QueryCurrentDesktop(&desktop, TRUE);
|
||
|
m_fRunningSecure = RunSecure(desktop.type);
|
||
|
|
||
|
if (s_fShowWarningAgain && s_dwStartMode == START_BY_MENU)
|
||
|
{
|
||
|
CWarningDlg dlgWarn;
|
||
|
dlgWarn.m_fDontWarnAgain = !s_fShowWarningAgain;
|
||
|
dlgWarn.DoModal();
|
||
|
s_fShowWarningAgain = !dlgWarn.m_fDontWarnAgain;
|
||
|
}
|
||
|
|
||
|
g_hWndDlg = m_hWnd;
|
||
|
|
||
|
// change system menu
|
||
|
|
||
|
CMenu *hSysMenu = GetSystemMenu(FALSE);
|
||
|
if (hSysMenu)
|
||
|
{
|
||
|
CString str;
|
||
|
hSysMenu->AppendMenu(MF_SEPARATOR);
|
||
|
str.LoadString(IDS_ABOUT_STRING);
|
||
|
hSysMenu->AppendMenu(MF_STRING,IDC_ABOUT,LPCTSTR(str));
|
||
|
}
|
||
|
|
||
|
// handle any "start when utility manager starts" applets
|
||
|
|
||
|
StartClientsOnShow();
|
||
|
|
||
|
// attach ListBox to member data and populate w/list of applications
|
||
|
|
||
|
m_lbClientList.Attach(GetDlgItem(IDC_NAME_STATUS)->m_hWnd);
|
||
|
ListClients();
|
||
|
|
||
|
// Disable Help button if we are at WinLogon because the help
|
||
|
// dialog supports "Jump to URL..." exposing security risk.
|
||
|
// The m_fRunningSecure variable is TRUE if UI shouldn't expose help.
|
||
|
|
||
|
if (m_fRunningSecure)
|
||
|
{
|
||
|
EnableDlgItem(ID_HELP, FALSE, IDOK);
|
||
|
}
|
||
|
|
||
|
// Disable "Start when UtilMan starts" unless user is an admin
|
||
|
// and we are running in non-secure mode.
|
||
|
|
||
|
if (s_dwStartMode != START_BY_MENU)
|
||
|
{
|
||
|
GetDlgItem(IDC_START_WITH_UM)->EnableWindow(IsAdmin() && !m_fRunningSecure);
|
||
|
}
|
||
|
|
||
|
// Bring dialog to top and center on desktop window
|
||
|
|
||
|
RECT rectUmanDlg,rectDesktop;
|
||
|
GetDesktopWindow()->GetWindowRect(&rectDesktop);
|
||
|
GetWindowRect(&rectUmanDlg);
|
||
|
|
||
|
long lDlgWidth = rectUmanDlg.right - rectUmanDlg.left;
|
||
|
long lDlgHieght = rectUmanDlg.bottom - rectUmanDlg.top;
|
||
|
if (!m_fRunningSecure)
|
||
|
{
|
||
|
rectUmanDlg.left = (rectDesktop.right - lDlgWidth)/2;
|
||
|
rectUmanDlg.top = (rectDesktop.bottom - lDlgHieght)/2;
|
||
|
} else
|
||
|
{
|
||
|
rectUmanDlg.left = rectDesktop.left + (long)(lDlgWidth/10);
|
||
|
rectUmanDlg.top = rectDesktop.bottom - lDlgHieght - (long)(lDlgHieght/10);
|
||
|
}
|
||
|
|
||
|
// This looks a bit odd (SetForegroundWindow should also be activating
|
||
|
// the window) but if you don't call SetActiveWindow on the secure
|
||
|
// desktop then the second, etc... WinKey+U will bring up UM hidden
|
||
|
// behind the welcome "screen".
|
||
|
|
||
|
SetActiveWindow();
|
||
|
SetForegroundWindow();
|
||
|
SetWindowPos(&wndTopMost,rectUmanDlg.left,rectUmanDlg.top,0,0,SWP_NOSIZE);
|
||
|
|
||
|
if (!m_fRunningSecure)
|
||
|
{
|
||
|
// on default desktop the above SetWindowPos makes the dialog initially
|
||
|
// on top and this call allows other apps to then be on top.
|
||
|
SetWindowPos(&wndNoTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
|
||
|
}
|
||
|
|
||
|
// start checking every so often to see if we need to update our display
|
||
|
|
||
|
SetTimer(UPDATE_CLIENT_LIST_TIMER, 3000, NULL);
|
||
|
|
||
|
return TRUE; // return TRUE unless you set the focus to a control
|
||
|
}
|
||
|
|
||
|
// -----------------------------------------------------
|
||
|
void UMDialog::OnSysCommand(UINT nID,LPARAM lParam)
|
||
|
{
|
||
|
if (nID == IDC_ABOUT)
|
||
|
{
|
||
|
UMAbout dlg;
|
||
|
dlg.DoModal();
|
||
|
aboutWnd = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CDialog::OnSysCommand(nID,lParam);
|
||
|
}
|
||
|
}//UMDialog::OnSysCommand
|
||
|
// ------------------------------------
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// CanStartOnLockedDesktop - returns TRUE if applets can
|
||
|
// be configured to be auto-started on the secure desktop
|
||
|
//
|
||
|
inline BOOL CanStartOnLockedDesktop(int iWhichClient, BOOL fRunningSecure)
|
||
|
{
|
||
|
// user can ask for auto start on secure desktop if they are logged on, the
|
||
|
// applet is OK'd to run on the secure desktop and the machine isn't using
|
||
|
// fast user switching (FUS) (w/FUS Ctrl+Alt+Del disconnects the user session
|
||
|
// rather than switching desktops).
|
||
|
|
||
|
BOOL fCanStartOnLockedDesktop =
|
||
|
(
|
||
|
!fRunningSecure &&
|
||
|
g_rgClients[iWhichClient].user.fCanRunSecure &&
|
||
|
CanLockDesktopWithoutDisconnect()
|
||
|
)?TRUE:FALSE;
|
||
|
|
||
|
return fCanStartOnLockedDesktop;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnSelchangeNameStatus is called when the user navigates the list
|
||
|
// box items by clicking with the mouse or using up/down arrows.
|
||
|
//
|
||
|
void UMDialog::OnSelchangeNameStatus()
|
||
|
{
|
||
|
// Get the currently selected item and update the controls for
|
||
|
// the currently selected item.
|
||
|
|
||
|
int iSel;
|
||
|
if (GetSelectedClient((int)g_cClients, iSel))
|
||
|
{
|
||
|
// Group box label
|
||
|
CString str(g_rgClients[iSel].machine.DisplayName);
|
||
|
CString optStr;
|
||
|
optStr.Format(IDS_OPTIONS, str);
|
||
|
GetDlgItem(IDC_OPTIONS)->SetWindowText(optStr);
|
||
|
|
||
|
// only enable options when started via WinKey+U
|
||
|
|
||
|
if (s_dwStartMode != START_BY_MENU)
|
||
|
{
|
||
|
// Disable "start at logon" at secure desktop to avoid mischief
|
||
|
|
||
|
if (!m_fRunningSecure)
|
||
|
{
|
||
|
GetDlgItem(IDC_START_AT_LOGON)->EnableWindow(TRUE);
|
||
|
} else
|
||
|
{
|
||
|
// this may be set in an upgrade situation; clear it
|
||
|
g_rgClients[iSel].user.fStartAtLogon = FALSE;
|
||
|
GetDlgItem(IDC_START_AT_LOGON)->EnableWindow(FALSE);
|
||
|
}
|
||
|
|
||
|
// Enable "start on locked desktop" if at default desktop and
|
||
|
// when applet can run on secure desktop
|
||
|
|
||
|
if (CanStartOnLockedDesktop(iSel, m_fRunningSecure))
|
||
|
{
|
||
|
GetDlgItem(IDC_START_ON_LOCK)->EnableWindow(TRUE);
|
||
|
} else
|
||
|
{
|
||
|
// this may be set in an upgrade situation; clear it
|
||
|
g_rgClients[iSel].user.fStartOnLockDesktop = FALSE;
|
||
|
GetDlgItem(IDC_START_ON_LOCK)->EnableWindow(FALSE);
|
||
|
}
|
||
|
|
||
|
// Start option checkboxes
|
||
|
|
||
|
CheckDlgButton(IDC_START_AT_LOGON, (g_rgClients[iSel].user.fStartAtLogon)?TRUE:FALSE);
|
||
|
CheckDlgButton(IDC_START_ON_LOCK, (g_rgClients[iSel].user.fStartOnLockDesktop)?TRUE:FALSE);
|
||
|
CheckDlgButton(IDC_START_WITH_UM, (g_rgClients[iSel].user.fStartWithUtilityManager)?TRUE:FALSE);
|
||
|
} else
|
||
|
{
|
||
|
GetDlgItem(IDC_START_AT_LOGON)->EnableWindow(FALSE);
|
||
|
GetDlgItem(IDC_START_ON_LOCK)->EnableWindow(FALSE);
|
||
|
GetDlgItem(IDC_START_WITH_UM)->EnableWindow(FALSE);
|
||
|
CheckDlgButton(IDC_START_AT_LOGON, FALSE);
|
||
|
CheckDlgButton(IDC_START_ON_LOCK, FALSE);
|
||
|
CheckDlgButton(IDC_START_WITH_UM, FALSE);
|
||
|
}
|
||
|
|
||
|
// Start and stop buttons
|
||
|
DWORD dwState = g_rgClients[iSel].state;
|
||
|
|
||
|
if ((dwState == UM_CLIENT_RUNNING)
|
||
|
&& (g_rgClients[iSel].runCount >= g_rgClients[iSel].machine.MaxRunCount))
|
||
|
EnableDlgItem(IDC_START, FALSE, IDC_NAME_STATUS);
|
||
|
else
|
||
|
EnableDlgItem(IDC_START, TRUE, IDC_NAME_STATUS);
|
||
|
|
||
|
if ((dwState == UM_CLIENT_NOT_RUNNING) || CantStopClient(&g_rgClients[iSel]))
|
||
|
EnableDlgItem(IDC_STOP, FALSE, IDC_NAME_STATUS);
|
||
|
else
|
||
|
EnableDlgItem(IDC_STOP, TRUE, IDC_NAME_STATUS);
|
||
|
|
||
|
}// else ignore selections not in a valid range
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
void UMDialog::OnClose()
|
||
|
{
|
||
|
// behave like cancel
|
||
|
CDialog::OnClose();
|
||
|
}//UMDialog::OnClose
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnStart is called when the Start button is clicked. It starts
|
||
|
// the client ap then lets the timer update saved state.
|
||
|
//
|
||
|
void UMDialog::OnStart()
|
||
|
{
|
||
|
int iSel;
|
||
|
if (GetSelectedClient((int)g_cClients, iSel))
|
||
|
{
|
||
|
if (StartClient(m_hWnd, &g_rgClients[iSel]))
|
||
|
{
|
||
|
KillTimer(UPDATE_CLIENT_LIST_TIMER);
|
||
|
EnableDlgItem(IDC_STOP, TRUE, IDC_NAME_STATUS);
|
||
|
ListClients();
|
||
|
SetTimer(UPDATE_CLIENT_LIST_TIMER, 3000, NULL);
|
||
|
|
||
|
if (g_rgClients[iSel].runCount+1 >= g_rgClients[iSel].machine.MaxRunCount)
|
||
|
EnableDlgItem(IDC_START, FALSE, IDC_STOP);
|
||
|
}
|
||
|
else if (g_rgClients[iSel].runCount < g_rgClients[iSel].machine.MaxRunCount)
|
||
|
{
|
||
|
// Unable to start
|
||
|
CString str;
|
||
|
str.LoadString((m_fRunningSecure)?IDS_SECUREMODE:IDS_ERRSTART);
|
||
|
MessageBox(str, m_szUMStr, MB_OK);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnStop is called when the Stop button is clicked. It stops
|
||
|
// the client ap then lets the timer update saved state.
|
||
|
//
|
||
|
void UMDialog::OnStop()
|
||
|
{
|
||
|
int iSel;
|
||
|
if (GetSelectedClient((int)g_cClients, iSel))
|
||
|
{
|
||
|
if (StopClient(&g_rgClients[iSel]))
|
||
|
{
|
||
|
KillTimer(UPDATE_CLIENT_LIST_TIMER);
|
||
|
GetDlgItem(IDC_START)->EnableWindow(TRUE);
|
||
|
ListClients();
|
||
|
EnableDlgItem(IDC_STOP, FALSE, IDOK);
|
||
|
SetTimer(UPDATE_CLIENT_LIST_TIMER, 3000, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Unable to stop
|
||
|
CString str;
|
||
|
str.LoadString(IDS_ERRSTOP);
|
||
|
MessageBox(str, m_szUMStr, MB_OK);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void UMDialog::SaveCurrentState()
|
||
|
{
|
||
|
int iSel;
|
||
|
if (GetSelectedClient((int)g_cClients, iSel))
|
||
|
{
|
||
|
g_rgClients[iSel].user.fStartAtLogon
|
||
|
= (IsDlgButtonChecked(IDC_START_AT_LOGON))?TRUE:FALSE;
|
||
|
g_rgClients[iSel].user.fStartWithUtilityManager
|
||
|
= (IsDlgButtonChecked(IDC_START_WITH_UM))?TRUE:FALSE;
|
||
|
g_rgClients[iSel].user.fStartOnLockDesktop
|
||
|
= (IsDlgButtonChecked(IDC_START_ON_LOCK))?TRUE:FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnOK is called when the user clicks the OK button to
|
||
|
// dismiss the UtilMan dialog.
|
||
|
//
|
||
|
void UMDialog::OnOK()
|
||
|
{
|
||
|
SaveCurrentState();
|
||
|
|
||
|
WriteClientData(m_fRunningSecure);
|
||
|
|
||
|
CDialog::OnOK();
|
||
|
}//UMDialog::OnOK
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// OnTimer is called to check the status of client apps that are displayed
|
||
|
// in the UI. This keeps the UI consistent with the running client app's.
|
||
|
//
|
||
|
void UMDialog::OnTimer(UINT nIDEvent)
|
||
|
{
|
||
|
if (nIDEvent == UPDATE_CLIENT_LIST_TIMER)
|
||
|
{
|
||
|
UINT uiElapsed = 3000;
|
||
|
KillTimer(UPDATE_CLIENT_LIST_TIMER);
|
||
|
|
||
|
// get current status and pick up new apps
|
||
|
if (CheckStatus(g_rgClients, g_cClients))
|
||
|
{
|
||
|
ListClients(); // something has changed - update the UI
|
||
|
uiElapsed = 500;
|
||
|
}
|
||
|
|
||
|
SetTimer(UPDATE_CLIENT_LIST_TIMER, uiElapsed, NULL);
|
||
|
}
|
||
|
CDialog::OnTimer(nIDEvent);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnHelpInfo provides context sensitive help. It only does
|
||
|
// this if not on the WinLogon desktop.
|
||
|
//
|
||
|
BOOL UMDialog::OnHelpInfo(HELPINFO* pHelpInfo)
|
||
|
{
|
||
|
if (m_fRunningSecure)
|
||
|
return FALSE;
|
||
|
|
||
|
if ( pHelpInfo->iCtrlId == IDC_OPTIONS )
|
||
|
return TRUE;
|
||
|
|
||
|
::WinHelp((HWND)pHelpInfo->hItemHandle, __TEXT("utilmgr.hlp"), HELP_WM_HELP,
|
||
|
(DWORD_PTR) (LPSTR) g_rgHelpIds);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnHelpInfo provides context sensitive help when the user
|
||
|
// right-clicks the dialog. It only does this if not on the
|
||
|
// WinLogon desktop.
|
||
|
//
|
||
|
void UMDialog::OnContextMenu(CWnd* pWnd, CPoint point)
|
||
|
{
|
||
|
if (m_fRunningSecure)
|
||
|
return;
|
||
|
|
||
|
::WinHelp(pWnd->m_hWnd, __TEXT("utilmgr.hlp"), HELP_CONTEXTMENU
|
||
|
, (DWORD_PTR) (LPSTR) g_rgHelpIds);
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnHelp provides standard help. It only does this if not
|
||
|
// on the WinLogon desktop.
|
||
|
//
|
||
|
void UMDialog::OnHelp()
|
||
|
{
|
||
|
if (m_fRunningSecure)
|
||
|
return;
|
||
|
|
||
|
::HtmlHelp(m_hWnd , TEXT("utilmgr.chm"), HH_DISPLAY_TOPIC, 0);
|
||
|
}
|
||
|
|
||
|
// ----------------------------------
|
||
|
void UMDialog::EnableDlgItem(DWORD dwEnableMe, BOOL fEnable, DWORD dwFocusHere)
|
||
|
{
|
||
|
// when disabling a control that currently has focs switch it to dwFocusHere
|
||
|
if (!fEnable && (GetFocus() == GetDlgItem(dwEnableMe)))
|
||
|
GetDlgItem(dwFocusHere)->SetFocus();
|
||
|
|
||
|
GetDlgItem(dwEnableMe)->EnableWindow(fEnable);
|
||
|
}
|
||
|
|
||
|
void UMDialog::SetStateStr(int iClient)
|
||
|
{
|
||
|
switch (g_rgClients[iClient].state)
|
||
|
{
|
||
|
case UM_CLIENT_NOT_RUNNING:
|
||
|
m_szStateStr.Format(IDS_NOT_RUNNING, g_rgClients[iClient].machine.DisplayName);
|
||
|
break;
|
||
|
|
||
|
case UM_CLIENT_RUNNING:
|
||
|
m_szStateStr.Format(IDS_RUNNING, g_rgClients[iClient].machine.DisplayName);
|
||
|
break;
|
||
|
|
||
|
case UM_CLIENT_NOT_RESPONDING:
|
||
|
m_szStateStr.Format(IDS_NOT_RESPONDING, g_rgClients[iClient].machine.DisplayName);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
m_szStateStr.Empty();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
void UMDialog::ListClients()
|
||
|
{
|
||
|
// Re-do the client list box with latest state info
|
||
|
|
||
|
int iCurSel = m_lbClientList.GetCurSel();
|
||
|
if (iCurSel == LB_ERR)
|
||
|
iCurSel = 0;
|
||
|
|
||
|
m_lbClientList.ResetContent();
|
||
|
|
||
|
for (DWORD i = 0; i < g_cClients; i++)
|
||
|
{
|
||
|
SetStateStr(i);
|
||
|
|
||
|
if (!m_szStateStr.IsEmpty())
|
||
|
{
|
||
|
m_lbClientList.AddString(m_szStateStr);
|
||
|
}
|
||
|
}
|
||
|
m_lbClientList.SetCurSel(iCurSel);
|
||
|
|
||
|
// Refresh button states in case they've changed
|
||
|
// (this happens on desktop switch)
|
||
|
|
||
|
OnSelchangeNameStatus();
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// UpdateClientState updates the client list box with the current state
|
||
|
// of the application (running, not running, not responding)
|
||
|
//
|
||
|
void UMDialog::UpdateClientState(int iSel)
|
||
|
{
|
||
|
SetStateStr(iSel);
|
||
|
m_lbClientList.DeleteString(iSel);
|
||
|
m_lbClientList.InsertString(iSel, m_szStateStr);
|
||
|
m_lbClientList.SetCurSel(iSel);
|
||
|
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnStartAtLogon updates the state of the client in memory when the
|
||
|
// Start with Windows checkbox is checked or unchecked.
|
||
|
//
|
||
|
void UMDialog::OnStartAtLogon()
|
||
|
{
|
||
|
SaveCurrentState();
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnStartWithUm updates the state of the client in memory when the
|
||
|
// Start with Utility Manager checkbox is checked or unchecked.
|
||
|
//
|
||
|
void UMDialog::OnStartWithUm()
|
||
|
{
|
||
|
SaveCurrentState();
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnStartOnLock updates the state of the client in memory when the
|
||
|
// Start when I lock my desktop checkbox is checked or unchecked.
|
||
|
//
|
||
|
void UMDialog::OnStartOnLock()
|
||
|
{
|
||
|
SaveCurrentState();
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
// OnShowWindow
|
||
|
// This was added for a timing problem where utilman came up running in the system context on the users desktop
|
||
|
// this code here makes sure that that cannot happen by cheching right when the dialog is about to appear
|
||
|
//
|
||
|
void UMDialog::OnShowWindow(BOOL bShow, UINT nStatus)
|
||
|
{
|
||
|
HDESK hdesk;
|
||
|
SID *desktopSID = NULL;
|
||
|
|
||
|
hdesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
|
||
|
// this is expected to fail for the winlogon desktop and thats ok
|
||
|
if (hdesk)
|
||
|
{
|
||
|
TCHAR desktopName[NAME_LEN];
|
||
|
DWORD nl, SIDLen = 0;
|
||
|
|
||
|
if (!GetUserObjectInformation(hdesk, UOI_NAME, desktopName, NAME_LEN, &nl))
|
||
|
goto StopDialog;
|
||
|
|
||
|
if (!GetUserObjectInformation(hdesk, UOI_USER_SID, desktopSID, 0, &SIDLen))
|
||
|
{
|
||
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||
|
goto StopDialog;
|
||
|
}
|
||
|
|
||
|
if (SIDLen > 0 && !lstrcmpi(desktopName, TEXT("Default")))
|
||
|
{
|
||
|
desktopSID = (SID*)new BYTE[SIDLen];
|
||
|
if (!desktopSID)
|
||
|
goto StopDialog;
|
||
|
|
||
|
if (!GetUserObjectInformation(hdesk, UOI_USER_SID, desktopSID, SIDLen, &SIDLen))
|
||
|
goto StopDialog;
|
||
|
|
||
|
BOOL fError;
|
||
|
HANDLE hUserToken = GetUserAccessToken(TRUE, &fError);
|
||
|
if (fError)
|
||
|
goto StopDialog;
|
||
|
|
||
|
// We get a token only if there is a logged on user.
|
||
|
// If there is not then we can come up as system with no worries.
|
||
|
if (!hUserToken)
|
||
|
goto LetDialogComeup;
|
||
|
|
||
|
BOOL fStatus = FALSE;
|
||
|
BOOL fIsInteractiveUser = FALSE;
|
||
|
PSID psidInteractive = InteractiveUserSid(TRUE);
|
||
|
|
||
|
if (!psidInteractive)
|
||
|
goto StopDialog;
|
||
|
|
||
|
fStatus = CheckTokenMembership(hUserToken, psidInteractive, &fIsInteractiveUser);
|
||
|
|
||
|
//If the logged on user is the interactive user and we are running as system then it is a
|
||
|
// security risk to show UI. This can happen when rappidly switching desktops.
|
||
|
if ( fStatus && fIsInteractiveUser && IsSystem())
|
||
|
goto StopDialog;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
LetDialogComeup:
|
||
|
if (desktopSID)
|
||
|
delete [] desktopSID;
|
||
|
return;
|
||
|
|
||
|
StopDialog:
|
||
|
StopDialog();
|
||
|
if (desktopSID)
|
||
|
delete [] desktopSID;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// C code
|
||
|
//-----------------------------------------------------------------
|
||
|
|
||
|
__inline void ReplaceDisplayName(LPTSTR szName, int iRID)
|
||
|
{
|
||
|
TCHAR szBuf[MAX_APPLICATION_NAME_LEN];
|
||
|
if (LoadString(AfxGetInstanceHandle(), iRID, szBuf, MAX_APPLICATION_NAME_LEN))
|
||
|
lstrcpy(szName, szBuf);
|
||
|
}
|
||
|
|
||
|
void SetLocalizedDisplayName()
|
||
|
{
|
||
|
// Make localization easier; don't require them to localize registry entries.
|
||
|
// Instead, replace our copy with the localized version. This appears to be
|
||
|
// duplicate code to that in umanrun.c however, that part of the code always
|
||
|
// runs as system and therefore the DisplayName is set to the default system
|
||
|
// language. This part of the code (the UI) runs as the logged on user when
|
||
|
// there is one so these resources will be the user's language. The resources
|
||
|
// and associated code should be removed from utilman.exe and this code and
|
||
|
// resources (from umandlg.dll) should be used.
|
||
|
|
||
|
for (DWORD i=0;i<g_cClients;i++)
|
||
|
{
|
||
|
if ( lstrcmp( g_rgClients[i].machine.ApplicationName, TEXT("Magnifier") ) == 0 )
|
||
|
{
|
||
|
ReplaceDisplayName(g_rgClients[i].machine.DisplayName, IDS_DISPLAY_NAME_MAGNIFIER);
|
||
|
}
|
||
|
else if ( lstrcmp( g_rgClients[i].machine.ApplicationName, TEXT("Narrator") ) == 0 )
|
||
|
{
|
||
|
ReplaceDisplayName(g_rgClients[i].machine.DisplayName, IDS_DISPLAY_NAME_NARRATOR);
|
||
|
}
|
||
|
else if ( lstrcmp( g_rgClients[i].machine.ApplicationName, TEXT("On-Screen Keyboard") ) == 0 )
|
||
|
{
|
||
|
ReplaceDisplayName(g_rgClients[i].machine.DisplayName, IDS_DISPLAY_NAME_OSK);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static BOOL InitClientData(void)
|
||
|
{
|
||
|
BOOL fRv = TRUE;
|
||
|
|
||
|
// On initial run allocate and initialize client array
|
||
|
|
||
|
if (!g_rgClients || !g_cClients)
|
||
|
{
|
||
|
umc_header_tsp pHdr = 0;
|
||
|
umclient_tsp c = 0;
|
||
|
DWORD_PTR accessID,accessID2;
|
||
|
|
||
|
g_cClients = 0;
|
||
|
g_rgClients = NULL;
|
||
|
|
||
|
fRv = FALSE;
|
||
|
|
||
|
pHdr = (umc_header_tsp)AccessIndependentMemory(
|
||
|
UMC_HEADER_FILE,
|
||
|
sizeof(umc_header_ts),
|
||
|
FILE_MAP_READ,
|
||
|
&accessID);
|
||
|
if (!pHdr)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
s_dwStartMode = pHdr->dwStartMode; // capture the Utilman start mode
|
||
|
s_fShowWarningAgain = pHdr->fShowWarningAgain; // and warning dialog flag
|
||
|
|
||
|
if (!pHdr->numberOfClients)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
c = (umclient_tsp)AccessIndependentMemory(
|
||
|
UMC_CLIENT_FILE,
|
||
|
sizeof(umclient_ts)*pHdr->numberOfClients,
|
||
|
FILE_MAP_READ,
|
||
|
&accessID2);
|
||
|
if (!c)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
g_rgClients = (umclient_tsp)VirtualAlloc(NULL, sizeof(umclient_ts)*pHdr->numberOfClients, MEM_RESERVE,PAGE_READWRITE);
|
||
|
if (!g_rgClients)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
if (!VirtualAlloc(g_rgClients, sizeof(umclient_ts)*pHdr->numberOfClients, MEM_COMMIT, PAGE_READWRITE))
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
fRv = TRUE;
|
||
|
|
||
|
g_cClients = pHdr->numberOfClients;
|
||
|
memcpy(g_rgClients,c,sizeof(umclient_ts)*pHdr->numberOfClients);
|
||
|
|
||
|
SetLocalizedDisplayName();
|
||
|
|
||
|
Cleanup:
|
||
|
if (pHdr)
|
||
|
{
|
||
|
UnAccessIndependentMemory(pHdr, accessID);
|
||
|
}
|
||
|
if (c)
|
||
|
{
|
||
|
UnAccessIndependentMemory(c, accessID2);
|
||
|
}
|
||
|
|
||
|
if (!fRv && g_rgClients)
|
||
|
{
|
||
|
VirtualFree(g_rgClients, 0, MEM_RELEASE);
|
||
|
g_rgClients = NULL;
|
||
|
g_cClients = 0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// "Start when I log on" is per-user setting so get that
|
||
|
// each time the dialog is brought up
|
||
|
|
||
|
CManageShellLinks CManageLinks(STARTUP_FOLDER);
|
||
|
for (DWORD i=0;i<g_cClients;i++)
|
||
|
{
|
||
|
g_rgClients[i].user.fStartAtLogon
|
||
|
= CManageLinks.LinkExists(g_rgClients[i].machine.ApplicationName);
|
||
|
}
|
||
|
|
||
|
return fRv;
|
||
|
}
|
||
|
|
||
|
// RegSetUMDwordValue - helper function to set a DWORD string value creating it if necessary
|
||
|
//
|
||
|
BOOL RegSetUMDwordValue(HKEY hKey, LPCTSTR pszKey, LPCTSTR pszString, DWORD dwNewValue)
|
||
|
{
|
||
|
HKEY hSubkey;
|
||
|
int iRv;
|
||
|
DWORD dwValue = dwNewValue;
|
||
|
|
||
|
iRv = RegCreateKeyEx(
|
||
|
hKey
|
||
|
, pszKey
|
||
|
, 0, NULL
|
||
|
, REG_OPTION_NON_VOLATILE
|
||
|
, KEY_ALL_ACCESS
|
||
|
, NULL, &hSubkey, NULL);
|
||
|
|
||
|
if (iRv == ERROR_SUCCESS)
|
||
|
{
|
||
|
RegSetValueEx(
|
||
|
hSubkey
|
||
|
, pszString
|
||
|
, 0, REG_DWORD
|
||
|
, (BYTE *)&dwValue
|
||
|
, sizeof(DWORD));
|
||
|
|
||
|
RegCloseKey(hSubkey);
|
||
|
}
|
||
|
|
||
|
return (iRv == ERROR_SUCCESS)?TRUE:FALSE;
|
||
|
}
|
||
|
|
||
|
void WriteUserRegData(HKEY hKeyCU, BOOL fDoAppletData)
|
||
|
{
|
||
|
HKEY hkey;
|
||
|
DWORD dwRv = RegCreateKeyEx(hKeyCU
|
||
|
, UM_HKCU_REGISTRY_KEY
|
||
|
, 0 , NULL
|
||
|
, REG_OPTION_NON_VOLATILE
|
||
|
, KEY_ALL_ACCESS, NULL
|
||
|
, &hkey, NULL);
|
||
|
|
||
|
if (dwRv == ERROR_SUCCESS)
|
||
|
{
|
||
|
dwRv = RegSetValueEx(
|
||
|
hkey
|
||
|
, UMR_VALUE_SHOWWARNING
|
||
|
, 0, REG_DWORD
|
||
|
, (BYTE *)&s_fShowWarningAgain
|
||
|
, sizeof(DWORD));
|
||
|
|
||
|
if (fDoAppletData)
|
||
|
{
|
||
|
for (DWORD i = 0; i < g_cClients; i++)
|
||
|
{
|
||
|
RegSetUMDwordValue(
|
||
|
hkey
|
||
|
, g_rgClients[i].machine.ApplicationName
|
||
|
, UMR_VALUE_STARTLOCK
|
||
|
, g_rgClients[i].user.fStartOnLockDesktop);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------
|
||
|
static BOOL CopyClientData()
|
||
|
{
|
||
|
umclient_tsp c;
|
||
|
DWORD_PTR accessID;
|
||
|
if (!g_cClients || !g_rgClients)
|
||
|
return TRUE;
|
||
|
c = (umclient_tsp)AccessIndependentMemory(
|
||
|
UMC_CLIENT_FILE,
|
||
|
sizeof(umclient_ts)*g_cClients,
|
||
|
FILE_MAP_READ|FILE_MAP_WRITE,
|
||
|
&accessID);
|
||
|
if (!c)
|
||
|
return FALSE;
|
||
|
memcpy(c,g_rgClients,sizeof(umclient_ts)*g_cClients);
|
||
|
UnAccessIndependentMemory(c, accessID);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void CopyHeaderData()
|
||
|
{
|
||
|
umc_header_tsp pHdr;
|
||
|
DWORD_PTR accessID;
|
||
|
|
||
|
pHdr = (umc_header_tsp)AccessIndependentMemory(
|
||
|
UMC_HEADER_FILE,
|
||
|
sizeof(umc_header_ts),
|
||
|
FILE_MAP_READ|FILE_MAP_WRITE,
|
||
|
&accessID);
|
||
|
if (pHdr)
|
||
|
{
|
||
|
pHdr->fShowWarningAgain = s_fShowWarningAgain;
|
||
|
UnAccessIndependentMemory(pHdr, accessID);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ----------------------------------
|
||
|
// WriteClientData - save settings to the registry
|
||
|
//
|
||
|
static BOOL WriteClientData(BOOL fRunningSecure)
|
||
|
{
|
||
|
// It only makes sense to do this if there are any applets being managed
|
||
|
// (shouldn't get here) and if there is a logged on user (otherwise the
|
||
|
// settings cannot be changed)
|
||
|
|
||
|
if (!g_cClients || !g_rgClients || fRunningSecure)
|
||
|
return TRUE;
|
||
|
|
||
|
// The SYSTEM instance of utilman needs to be updated in case the user
|
||
|
// changed any options. This is so subsequent instances of the UI will
|
||
|
// get the correct options without having to read the registry.
|
||
|
|
||
|
CopyHeaderData();
|
||
|
CopyClientData();
|
||
|
|
||
|
//
|
||
|
// Write utilman settings data. Put "Start when UtilMan starts" in HKLM,
|
||
|
// "Start when I lock desktop" in HKCU, and "Start when I log on" into
|
||
|
// a startup link in the logged on user's shell folder.
|
||
|
//
|
||
|
|
||
|
// "Start when UtilMan starts" settings... (only for admins)
|
||
|
|
||
|
DWORD i;
|
||
|
if (IsWindowEnabled(GetDlgItem(g_hWndDlg, IDC_START_WITH_UM)))
|
||
|
{
|
||
|
HKEY hHKLM;
|
||
|
DWORD dwRv = RegCreateKeyEx(HKEY_LOCAL_MACHINE
|
||
|
, UM_REGISTRY_KEY
|
||
|
, 0 , NULL
|
||
|
, REG_OPTION_NON_VOLATILE
|
||
|
, KEY_ALL_ACCESS, NULL
|
||
|
, &hHKLM, NULL);
|
||
|
if (dwRv == ERROR_SUCCESS)
|
||
|
{
|
||
|
for (i = 0; i < g_cClients; i++)
|
||
|
{
|
||
|
RegSetUMDwordValue(
|
||
|
hHKLM
|
||
|
, g_rgClients[i].machine.ApplicationName
|
||
|
, UMR_VALUE_STARTUM
|
||
|
, g_rgClients[i].user.fStartWithUtilityManager);
|
||
|
}
|
||
|
RegCloseKey(hHKLM);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// "Start when I lock my desktop" settings... (any logged on user)
|
||
|
// and Don't show me the warning anymore setting
|
||
|
//
|
||
|
WriteUserRegData(HKEY_CURRENT_USER, IsWindowEnabled(GetDlgItem(g_hWndDlg, IDC_START_ON_LOCK)));
|
||
|
|
||
|
//
|
||
|
// manage shell folder link updates (logged on user only)
|
||
|
//
|
||
|
|
||
|
if (IsWindowEnabled(GetDlgItem(g_hWndDlg, IDC_START_AT_LOGON)))
|
||
|
{
|
||
|
CManageShellLinks CManageLinks(STARTUP_FOLDER);
|
||
|
|
||
|
for (i = 0; i < g_cClients; i++)
|
||
|
{
|
||
|
LPTSTR pszAppName = g_rgClients[i].machine.ApplicationName;
|
||
|
BOOL fLinkExists = CManageLinks.LinkExists(pszAppName);
|
||
|
|
||
|
// if should start at logon and there isn't a link then create one
|
||
|
// and if shouldn't start at logon and there is a link then delete it
|
||
|
|
||
|
if (g_rgClients[i].user.fStartAtLogon && !fLinkExists)
|
||
|
{
|
||
|
TCHAR pszAppPath[MAX_PATH];
|
||
|
LPTSTR pszApp = 0;
|
||
|
|
||
|
// Following is TRUE *only* if pszAppPath is non-null string value
|
||
|
if (GetClientApplicationPath(pszAppName , pszAppPath , MAX_PATH))
|
||
|
{
|
||
|
TCHAR pszFullPath[MAX_PATH*2+1]; // path + filename
|
||
|
TCHAR pszStartIn[MAX_PATH];
|
||
|
int ctch, ctchAppPath = lstrlen(pszAppPath);
|
||
|
|
||
|
// if pszAppPath is just base name and extension then prepend system path
|
||
|
|
||
|
if (wcscspn(pszAppPath, TEXT("\\")) != (size_t)ctchAppPath
|
||
|
|| wcscspn(pszAppPath, TEXT(":")) != (size_t)ctchAppPath)
|
||
|
{
|
||
|
TCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR];
|
||
|
_wsplitpath(pszAppPath, szDrive, szDir, NULL, NULL);
|
||
|
lstrcpy(pszStartIn, szDrive);
|
||
|
lstrcat(pszStartIn, szDir);
|
||
|
|
||
|
pszApp = pszAppPath;
|
||
|
} else
|
||
|
{
|
||
|
ctch = GetSystemDirectory(pszStartIn, MAX_PATH);
|
||
|
|
||
|
lstrcpy(pszFullPath, pszStartIn); // save path to build full path
|
||
|
|
||
|
if (ctch + ctchAppPath + 2 > MAX_PATH*2)
|
||
|
{
|
||
|
DBPRINTF(TEXT("WriteClientData: Path is too short!\r\n"));
|
||
|
} else
|
||
|
{
|
||
|
if (*(pszFullPath + ctch - 1) != '\\')
|
||
|
lstrcat(pszFullPath, TEXT("\\"));
|
||
|
|
||
|
lstrcat(pszFullPath, pszAppPath);
|
||
|
pszApp = pszFullPath;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pszApp)
|
||
|
{
|
||
|
// remove ending '\' from StartIn path
|
||
|
ctch = lstrlen(pszStartIn) - 1;
|
||
|
if (*(pszStartIn + ctch) == '\\')
|
||
|
*(pszStartIn + ctch) = 0;
|
||
|
|
||
|
CManageLinks.CreateLink(
|
||
|
pszAppName
|
||
|
, pszApp
|
||
|
, pszStartIn
|
||
|
, g_rgClients[i].machine.DisplayName
|
||
|
, TEXT("/UM"));
|
||
|
}
|
||
|
}
|
||
|
} else if (!g_rgClients[i].user.fStartAtLogon && fLinkExists)
|
||
|
{
|
||
|
CManageLinks.RemoveLink(pszAppName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
// --------------------------------------------
|
||
|
static BOOL CantStopClient(umclient_tsp client)
|
||
|
{
|
||
|
switch (client->machine.ApplicationType)
|
||
|
{
|
||
|
case APPLICATION_TYPE_APPLICATION:
|
||
|
break;
|
||
|
case APPLICATION_TYPE_SERVICE:
|
||
|
{
|
||
|
SERVICE_STATUS ssStatus;
|
||
|
SC_HANDLE hService;
|
||
|
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
||
|
if (!hSCM)
|
||
|
return TRUE;
|
||
|
hService = OpenService(hSCM, client->machine.ApplicationName, SERVICE_ALL_ACCESS);
|
||
|
CloseServiceHandle(hSCM);
|
||
|
if (!hService)
|
||
|
return TRUE;
|
||
|
if (!QueryServiceStatus(hService, &ssStatus) ||
|
||
|
!(ssStatus.dwControlsAccepted & SERVICE_ACCEPT_STOP))
|
||
|
{
|
||
|
CloseServiceHandle(hService);
|
||
|
return TRUE;
|
||
|
}
|
||
|
CloseServiceHandle(hService);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}//CantStopClient
|
||
|
|
||
|
// We don't want UtilMan to startType to be Automatic
|
||
|
// It should only be made Automatic if it is required, When the user
|
||
|
// selects "Start when NT starts" through the GUI :a-anilk
|
||
|
static BOOL IsStartAuto()
|
||
|
{
|
||
|
#ifdef NEVER // MICW Don't start service anymore at logon because of TS
|
||
|
DWORD nClient;
|
||
|
|
||
|
for(nClient = 0; nClient < g_cClients; nClient++)
|
||
|
{
|
||
|
if ( g_rgClients[nClient].user.fStartAtLogon == TRUE )
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static int GetClientNameFromAccelerator(WPARAM wVK)
|
||
|
{
|
||
|
for (int i=0;i<(int)g_cClients;i++)
|
||
|
if (g_rgClients[i].machine.AcceleratorKey == wVK)
|
||
|
return i;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static BOOL StartClientsOnShow()
|
||
|
{
|
||
|
BOOL fOK = TRUE;
|
||
|
for (int i=0;i<(int)g_cClients;i++)
|
||
|
{
|
||
|
if ( g_rgClients[i].user.fStartWithUtilityManager
|
||
|
&& !StartClient(g_hWndDlg, &g_rgClients[i]))
|
||
|
fOK = FALSE;
|
||
|
}
|
||
|
return fOK;
|
||
|
}
|