Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2350 lines
66 KiB

//____________________________________________________________________________
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995 - 1996.
//
// File: general.cxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// Notes: For the first release of the scheduling agent, all security
// operations are disabled under Win95, even Win95 to NT.
//
// History: 3/4/1996 RaviR Created
// 1-30-1997 DavidMun params edit becomes working dir
// 02/29/01 JBenton BUG 280401 app icon was not being updated
// on prop sheet in case of service not running
//
//____________________________________________________________________________
#include "..\pch\headers.hxx"
#pragma hdrstop
#include "..\inc\dll.hxx"
#include "..\folderui\dbg.h"
#include "..\folderui\macros.h"
#include "dlg.hxx"
#include "..\folderui\jobicons.hxx"
#include "..\inc\resource.h"
#include "..\inc\defines.hxx"
#include "..\inc\common.hxx"
#include "..\inc\misc.hxx"
#include "..\inc\policy.hxx"
#include <StrSafe.h>
#define SECURITY_WIN32
#include <security.h> // GetUserNameEx
#undef SECURITY_WIN32
#include "SASecRPC.h" // SASetNSAccountInformation RPC definition.
#include "..\inc\network.hxx"
#include "rc.h"
#include "defines.h"
#include <mstask.h>
#include "uiutil.hxx"
#include "commdlg.h"
#include "helpids.h"
#include "iconhlpr.hxx"
#include "schedui.hxx"
//
// extern
//
extern HINSTANCE g_hInstance;
//
// Forward references
//
// CenterDialog - Centers a dialog on screen. Used by the security-related
// subdialogs.
//
void
CenterDialog(HWND hDlg);
void
GetDefaultDomainAndUserName(
LPTSTR ptszDomainAndUserName,
ULONG cchBuf);
//
// Launches the modal set password dialog.
//
INT_PTR
LaunchSetPasswordDlg(
HWND hWnd,
AccountInfo * pAccountInfo);
INT_PTR APIENTRY
SetPasswordDlgProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam);
INT_PTR APIENTRY
SetAccountInformationDlgProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam);
int
SchedGetDlgItemTextLength(
HWND hwnd,
int id);
//
// (Control id, help id) list for context sensitivity help.
//
ULONG s_aGeneralPageHelpIds[] =
{
idc_icon, Hidc_icon,
lbl_job_name, Hlbl_job_name,
lbl_comments, Hlbl_comments,
txt_comments, Htxt_comments,
lbl_app_name, Hlbl_app_name,
txt_app_name, Htxt_app_name,
btn_browse, Hbtn_browse,
lbl_workingdir, Hlbl_workingdir,
txt_workingdir, Htxt_workingdir,
lbl_run_as, Hlbl_execute_as,
txt_run_as, Htxt_execute_as,
btn_passwd, Hbtn_passwd,
chk_enable_job, Hchk_enable_job,
btn_settings, Hbtn_settings,
0,0
};
const ULONG s_aSetPasswordDlgHelpIds[] =
{
set_passwd_dlg, Hset_passwd_dlg,
lbl_sp_passwd, Hlbl_sp_passwd,
edt_sp_passwd, Hedt_sp_passwd,
lbl_sp_cfrmpasswd, Hlbl_sp_cfrmpasswd,
edt_sp_cfrmpasswd, Hedt_sp_cfrmpasswd,
0,0
};
extern "C" TCHAR szMstaskHelp[];
const TCHAR SAGERUN_PARAM[] = TEXT("/SAGERUN:");
TCHAR szMstaskHelp[] = TEXT("%windir%\\help\\mstask.hlp");
//____________________________________________________________________________
//____________________________________________________________________________
//________________ ______________________________________
//________________ class CGeneralPage ______________________________________
//________________ ______________________________________
//____________________________________________________________________________
//____________________________________________________________________________
class CGeneralPage : public CPropPage
{
public:
CGeneralPage(ITask * pIJob, LPTSTR ptszTaskPath, BOOL fPersistChanges);
~CGeneralPage();
private:
virtual LRESULT _OnInitDialog(LPARAM lParam);
virtual LRESULT _OnCommand(int id, HWND hwndCtl, UINT codeNotify);
virtual LRESULT _OnApply(void);
virtual LRESULT _OnCancel(void);
virtual LRESULT _OnPSMQuerySibling(WPARAM wParam, LPARAM lParam);
virtual LRESULT _OnPSNKillActive(LPARAM lParam);
virtual LRESULT _OnHelp(HANDLE hRequesting, UINT uiHelpCommand);
VOID _ExpandAppName(LPTSTR tszApp, size_t cchBuff);
VOID _ExpandWorkingDir();
VOID _GetAppAndArgs(LPTSTR tszApp, size_t appBufSize, LPTSTR * pptszArg);
VOID _UpdateAppNameAndIcon(LPWSTR wszApp, size_t appBufSize, LPWSTR * ppwszArg);
VOID _UpdateAppIcon(LPCTSTR tszApp);
VOID _SetAppEdit(LPCTSTR tszApp, LPCTSTR tszArgs);
BOOL _JobObjectIsLocal();
void _UpdateRunAsControl(void);
BOOL _Browse(TCHAR szFilePath[]);
void _ErrorDialog(int idsErr, LONG error = 0, UINT idsHelpHint = 0)
{ SchedUIErrorDialog(Hwnd(), idsErr, error, idsHelpHint); }
void _DisableUI(void);
AccountInfo m_AccountInfo; // Account/password change info.
ITask * m_pIJob;
// Flag values. Note the compiler allocates a single dword for these
DWORD m_CommentDirty : 1; //
DWORD m_AppNameDirty : 1; //
DWORD m_WorkingDirDirty : 1; // A value of 1 => dirty
DWORD m_RunAsDirty : 1; //
DWORD m_updateIcon : 1; // 1 => update needed
DWORD m_ChangeFromSetText : 1;// 0 => en_change from user
//
// icon helper
//
CIconHelper * m_pIconHelper;
//
// flags
//
BOOL m_fPersistChanges; // Should we save on Apply or OK?
BOOL m_fEnableJob; // Is the job enabled?
BOOL m_fNetScheduleJob; // Is this an AT job?
//
// Saved or new sage settings parameter
//
TCHAR m_tszSageRunParam[20]; // /SAGERUN:4294967295
//
// The RunAs edit control can be updated by the user, or automatically
// with apply via the set account information dialog. In response to
// user edits, we want to apply the changes. For the automatic RunAs
// update, we've already applied the changes, therefore, this flag
// exists to not re-dirty the page.
//
BOOL m_fApplyRunAsEditChange;
//
// The other pages need to query the general page if there is an
// application or security account change for the common security
// code in the page's save path (JFSaveJob). The record of this
// dirty information must be retained post-Apply; therefore, these
// slightly redundant flags are necessary.
//
BOOL m_fTaskApplicationChange;
BOOL m_fTaskAccountChange;
//
// Set this flag to TRUE if we have launched the set password dialog.
// Othwerwise, the user may get a redundant set account information
// dialog on apply.
//
BOOL m_fSuppressAcctInfoRequestOnApply;
}; // class CGeneralPage
inline
CGeneralPage::CGeneralPage(
ITask * pIJob,
LPTSTR ptszTaskPath,
BOOL fPersistChanges)
:
m_pIJob(pIJob),
m_pIconHelper(NULL),
m_fPersistChanges(fPersistChanges),
m_ChangeFromSetText(FALSE),
m_fApplyRunAsEditChange(TRUE),
m_fTaskApplicationChange(FALSE),
m_fTaskAccountChange(FALSE),
m_fSuppressAcctInfoRequestOnApply(FALSE),
m_fNetScheduleJob(FALSE),
CPropPage(MAKEINTRESOURCE(general_page), ptszTaskPath)
{
TRACE(CGeneralPage, CGeneralPage);
Win4Assert(m_pIJob != NULL);
m_pIJob->AddRef();
m_tszSageRunParam[0] = TEXT('\0');
InitializeAccountInfo(&m_AccountInfo);
}
inline
CGeneralPage::~CGeneralPage()
{
TRACE(CGeneralPage, ~CGeneralPage);
if (m_pIconHelper != NULL)
{
m_pIconHelper->Release();
}
if (m_pIJob != NULL)
{
m_pIJob->Release();
}
ResetAccountInfo(&m_AccountInfo);
}
//+--------------------------------------------------------------------------
//
// Member: CGeneralPage::_JobObjectIsLocal
//
// Synopsis: Return TRUE if job object being edited lives on the local
// machine, FALSE otherwise.
//
// History: 2-01-1997 DavidMun Created
//
//---------------------------------------------------------------------------
inline BOOL
CGeneralPage::_JobObjectIsLocal()
{
return IsLocalFilename(GetTaskPath());
}
LRESULT
CGeneralPage::_OnInitDialog(
LPARAM lParam)
{
TRACE(CGeneralPage, _OnInitDialog);
HRESULT hr = S_OK;
LPWSTR pwsz = NULL;
BOOL fEnableSecurity = FALSE;
TCHAR tszApp[MAX_PATH + 1] = TEXT("");
//
// Note that we don't limit the txt_app_name control. App names are
// limited to MAX_PATH characters, but app parameters are not.
//
HWND hwnd;
if (hwnd = _hCtrl(txt_comments)) Edit_LimitText(hwnd, MAX_PATH);
if (hwnd = _hCtrl(txt_workingdir)) Edit_LimitText(hwnd, MAX_PATH);
if (hwnd = _hCtrl(txt_run_as)) Edit_LimitText(hwnd, MAX_USERNAME);
//
// Policy - if this reg key is valid, disable browse
//
if (RegReadPolicyKey(TS_KEYPOLICY_DENY_BROWSE))
{
DEBUG_OUT((DEB_ITRACE, "Policy ALLOW_BROWSE active, no browse or edit\n"));
if (hwnd = _hCtrl(btn_browse)) EnableWindow(hwnd, FALSE);
if (hwnd = _hCtrl(btn_browse)) ShowWindow(hwnd, SW_HIDE);
if (hwnd = _hCtrl(txt_app_name)) EnableWindow(hwnd, FALSE);
if (hwnd = _hCtrl(txt_workingdir)) EnableWindow(hwnd, FALSE);
}
do
{
// Determine if the security settings should be shown or not.
// The task object must reside within a tasks folder & exist
// on an NT machine.
//
fEnableSecurity = (this->GetPlatformId() == VER_PLATFORM_WIN32_NT &&
this->IsTaskInTasksFolder());
if (!fEnableSecurity)
{
if (hwnd = _hCtrl(lbl_run_as)) DestroyWindow(hwnd);
if (hwnd = _hCtrl(txt_run_as)) DestroyWindow(hwnd);
if (hwnd = _hCtrl(btn_passwd)) DestroyWindow(hwnd);
}
//
// Set the job enabled check box
//
DWORD dwFlags;
hr = m_pIJob->GetFlags(&dwFlags);
m_fEnableJob = (dwFlags & TASK_FLAG_DISABLED) ? FALSE : TRUE;
CheckDlgButton(m_hPage, chk_enable_job, m_fEnableJob);
//
// Remember this for use later
//
m_fNetScheduleJob = dwFlags & JOB_I_FLAG_NET_SCHEDULE;
// See if the schedule page has already created the icon
// helper, if not create it here.
m_pIconHelper = (CIconHelper *)PropSheet_QuerySiblings(
GetParent(Hwnd()), GET_ICON_HELPER, 0);
if (m_pIconHelper == NULL)
{
m_pIconHelper = new CIconHelper();
if (m_pIconHelper == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
}
else
{
m_pIconHelper->AddRef();
}
//
// Set job name (static text showing path to .job object)
//
SetDlgItemText(Hwnd(), lbl_job_name, this->GetTaskPath());
//
// Set comments
//
hr = m_pIJob->GetComment(&pwsz);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
I_SetDlgItemText(Hwnd(), txt_comments, pwsz);
CoTaskMemFree(pwsz);
//
// Get application name preparatory to setting it.
//
hr = m_pIJob->GetApplicationName(&pwsz);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
lstrcpyn(tszApp, pwsz, MAX_PATH + 1);
//
// If the application name fetched from the job object has spaces in
// it, add quotes around the tchar version.
//
if (wcschr(pwsz, L' '))
{
AddQuotes(tszApp, MAX_PATH + 1);
}
CoTaskMemFree(pwsz);
//
// Now get the parameters and append a space and the tchar
// representation to the app name.
//
hr = m_pIJob->GetParameters(&pwsz);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
TCHAR * tszArg = pwsz;
//
// If the /SAGERUN:n parameter appears in the arguments, save it in
// an internal buffer, but don't show it in the UI.
//
LPTSTR ptszSageRun = _tcsstr(tszArg, SAGERUN_PARAM);
if (ptszSageRun)
{
lstrcpyn(m_tszSageRunParam,
ptszSageRun,
ARRAYLEN(m_tszSageRunParam));
*ptszSageRun = TEXT('\0');
StripLeadTrailSpace(tszArg); // get rid of spaces before /sagerun
}
_SetAppEdit(tszApp, tszArg);
CoTaskMemFree(pwsz);
//
// Set the working directory
//
hr = m_pIJob->GetWorkingDirectory(&pwsz);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
if (wcschr(pwsz, L' '))
{
WCHAR wszWorkingDir[MAX_PATH + 1] = L"\"";
wcsncpy(wszWorkingDir + 1, pwsz, MAX_PATH - 1);
StringCchCat(wszWorkingDir, MAX_PATH + 1, L"\"");
I_SetDlgItemText(Hwnd(), txt_workingdir, wszWorkingDir);
}
else
{
I_SetDlgItemText(Hwnd(), txt_workingdir, pwsz);
}
CoTaskMemFree(pwsz);
if (!this->IsTaskInTasksFolder())
{
EnableWindow(_hCtrl(chk_enable_job), FALSE);
m_fEnableJob = FALSE;
}
if (fEnableSecurity)
{
//
// Set account name (run as)
//
DWORD cchAccount = MAX_USERNAME + 1;
WCHAR wszDisplayAccount[MAX_USERNAME + 1] = L"";
hr = m_pIJob->GetAccountInformation(&pwsz);
if (SUCCEEDED(hr))
{
//
// Translate account prior to display, then display it
//
hr = TranslateAccount(TRANSLATE_FOR_DISPLAY, pwsz, wszDisplayAccount, cchAccount);
if (SUCCEEDED(hr))
{
I_SetDlgItemText(Hwnd(), txt_run_as, wszDisplayAccount); // display the translated account
}
m_AccountInfo.pwszAccountName = pwsz; // use the untranslated account internally
EnableWindow(_hCtrl(btn_passwd), TRUE);
}
else if (hr == SCHED_E_ACCOUNT_INFORMATION_NOT_SET)
{
WCHAR wszAccount[MAX_USERNAME + 1];
if (m_fNetScheduleJob)
{
//
// get the name of the AT service account
//
RpcTryExcept
{
hr = SAGetNSAccountInformation(NULL, cchAccount, wszAccount);
}
RpcExcept(1)
{
DWORD Status = RpcExceptionCode();
hr = SchedMapRpcError(Status);
}
RpcEndExcept;
if (FAILED(hr) || S_FALSE == hr)
{
wszAccount[0] = L'\0';
}
}
else
{
//
// Set the run as field to the current user's name and
// enable the set/change password button.
//
GetDefaultDomainAndUserName(wszAccount, cchAccount);
//
// Sometimes I think this would be better than defaulting to the current user, because
// the user can get confused and think that the account is already set when it isn't.
//
// lstrcpyW(wszAccount,L"***Account not set***");
//
}
//
// Translate account prior to display, then display it
//
hr = TranslateAccount(TRANSLATE_FOR_DISPLAY, wszAccount, wszDisplayAccount, cchAccount);
if (SUCCEEDED(hr))
{
SetDlgItemText(Hwnd(), txt_run_as, wszDisplayAccount);
}
EnableWindow(_hCtrl(btn_passwd), TRUE);
//
// everything is ok, really
//
hr = S_OK;
}
else
{
//
// Disable the run as and set/change password button ctrls &
// put up an error dialog letting the user know that security
// services are unavailable.
//
// Actually, the set/change password button is already
// disabled.
//
CHECK_HRESULT(hr);
EnableWindow(_hCtrl(lbl_run_as), FALSE);
EnableWindow(_hCtrl(txt_run_as), FALSE);
}
}
} while (0);
//
// Disable all controls if this is an AT job
// to prevent user from making changes
//
if (m_fNetScheduleJob)
_DisableUI();
if (FAILED(hr))
{
if (hr == E_OUTOFMEMORY)
{
_ErrorDialog(IERR_OUT_OF_MEMORY);
}
else
{
_ErrorDialog(IERR_GENERAL_PAGE_INIT, hr);
}
//
// Show application icon
//
m_updateIcon = 1;
_UpdateAppIcon(tszApp);
EnableWindow(Hwnd(), FALSE);
return FALSE;
}
//
// Show application icon
//
m_updateIcon = 1;
_UpdateAppIcon(tszApp);
//
// Need to initialize these here since doing a SetDlgItemText causes
// a WM_COMMAND msg with EN_CHANGE to be called for edit boxes.
//
m_CommentDirty = 0;
m_AppNameDirty = 0;
m_WorkingDirDirty = 0;
m_RunAsDirty = 0;
m_fDirty = FALSE;
return TRUE;
}
//+--------------------------------------------------------------------------
//
// Member: CGeneralPage::_DisableUI
//
// Synopsis: Disable UI so the user can only view the settings
//
// History: 2001-11-13 ShBrown Created
//
//---------------------------------------------------------------------------
void
CGeneralPage::_DisableUI(void)
{
HWND hwnd;
if (hwnd = _hCtrl(txt_app_name)) EnableWindow(hwnd, FALSE);
if (hwnd = _hCtrl(txt_workingdir)) EnableWindow(hwnd, FALSE);
if (hwnd = _hCtrl(txt_comments)) EnableWindow(hwnd, FALSE);
if (hwnd = _hCtrl(txt_run_as)) EnableWindow(hwnd, FALSE);
if (hwnd = _hCtrl(chk_enable_job)) EnableWindow(hwnd, FALSE);
if (hwnd = _hCtrl(btn_browse)) EnableWindow(hwnd, FALSE);
if (hwnd = _hCtrl(btn_browse)) ShowWindow(hwnd, SW_HIDE);
if (hwnd = _hCtrl(btn_passwd)) EnableWindow(hwnd, FALSE);
if (hwnd = _hCtrl(btn_passwd)) ShowWindow(hwnd, SW_HIDE);
}
//+--------------------------------------------------------------------------
//
// Function: GetDefaultDomainAndUserName
//
// Synopsis: Fill [pwszDomainAndUserName] with "domain\user" string
//
// Arguments: [pwszDomainAndUserName] - buffer to receive string
// [cchBuf] - should be at least MAX_USERNAME
//
// Modifies: *[pwszDomainAndUserName].
//
// History: 06-03-1997 DavidMun Created
// 2001-11-13 ShBrown Modified to use wchar rather than tchar
//
// Notes: If an error occurs while retrieving the domain name, only
// the user name is returned. If even that cannot be
// retrieved, the buffer is set to an empty string.
//
//---------------------------------------------------------------------------
VOID
GetDefaultDomainAndUserName(
LPWSTR pwszDomainAndUserName,
ULONG cchBuf)
{
TRACE_FUNCTION(GetDefaultDomainAndUserName);
if (!GetUserNameExW(NameSamCompatible,
pwszDomainAndUserName,
&cchBuf))
{
DEBUG_OUT((DEB_ERROR,
"GetDefaultDomainAndUserName: GetUserNameExW failed %d\n",
GetLastError()));
pwszDomainAndUserName[0] = L'\0';
}
}
void
CGeneralPage::_UpdateAppIcon(
LPCTSTR ptszAppName)
{
if (m_updateIcon == 0)
{
return;
}
m_updateIcon = 0;
if (ptszAppName)
{
m_pIconHelper->SetAppIcon((LPTSTR)ptszAppName);
}
BOOL fEnabled;
if (this->IsTaskInTasksFolder())
{
fEnabled = (IsDlgButtonChecked(m_hPage, chk_enable_job)
== BST_CHECKED);
}
else
{
fEnabled = FALSE;
}
m_pIconHelper->SetJobIcon(fEnabled);
SendDlgItemMessage(Hwnd(), idc_icon, STM_SETICON,
(WPARAM)m_pIconHelper->hiconJob, 0L);
}
BOOL
CGeneralPage::_Browse(
TCHAR szFilePath[]) // of size MAX_PATH
{
TCHAR szDefExt[5];
TCHAR szBrowserDir[MAX_PATH];
TCHAR szFilters[MAX_PATH];
TCHAR szTitle[100];
DWORD dwFlags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
LoadString(g_hInstance, IDS_EXE, szDefExt, ARRAYLEN(szDefExt));
LoadString(g_hInstance, IDS_BROWSE, szTitle, ARRAYLEN(szTitle));
SecureZeroMemory(szFilters, sizeof(szFilters));
if (!LoadString(g_hInstance,
IDS_PROGRAMSFILTER,
szFilters,
ARRAYLEN(szFilters)))
{
CHECK_HRESULT( HRESULT_FROM_WIN32(GetLastError()) );
return FALSE;
}
GetCurrentDirectory(MAX_PATH, szBrowserDir);
OPENFILENAME ofn;
SecureZeroMemory(&ofn, sizeof(ofn));
szFilePath[0] = TEXT('\0');
// Setup info for comm dialog.
ofn.lStructSize = CDSIZEOF_STRUCT(OPENFILENAME, lpTemplateName);
ofn.hwndOwner = Hwnd();
ofn.hInstance = g_hInstance;
ofn.lpstrFilter = szFilters;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFilePath;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrInitialDir = szBrowserDir;
ofn.lpstrTitle = szTitle;
ofn.Flags = dwFlags;
ofn.lpstrDefExt = szDefExt;
// Call it.
if (GetOpenFileName(&ofn) == FALSE)
{
DEBUG_OUT((DEB_ERROR, "GetOpenFileName failed<0x%x>\n",
CommDlgExtendedError()));
return FALSE;
}
return TRUE;
}
LRESULT
CGeneralPage::_OnCommand(
int id,
HWND hwndCtl,
UINT codeNotify)
{
TRACE(CGeneralPage, _OnCommand);
if ((id == btn_browse) && (codeNotify == BN_CLICKED))
{
// popup the file browse dialog
TCHAR tszFilePath[MAX_PATH+1];
if (_Browse(tszFilePath))
{
if (_tcschr(tszFilePath, TEXT(' ')))
{
AddQuotes(tszFilePath, MAX_PATH);
}
SetDlgItemText(Hwnd(), txt_app_name, tszFilePath);
SendMessage(Hwnd(),
WM_NEXTDLGCTL,
(WPARAM)_hCtrl(txt_workingdir),
TRUE);
_UpdateAppIcon(tszFilePath);
_EnableApplyButton();
}
}
else if (id == btn_passwd && codeNotify == BN_CLICKED)
{
// popup the set password dialog
LaunchSetPasswordDlg(Hwnd(), &m_AccountInfo);
//
// Since we've launched the set password dialog, we want
// to suppress the set account information dialog which
// otherwise may come up on apply.
//
m_fSuppressAcctInfoRequestOnApply = TRUE;
_EnableApplyButton();
}
else if (codeNotify == EN_CHANGE)
{
switch (id)
{
case txt_comments:
m_CommentDirty = 1;
break;
case txt_app_name:
//
// If we just did a SetDlgItemText, then this change notification
// should be ignored.
//
if (m_ChangeFromSetText)
{
m_ChangeFromSetText = 0;
}
else
{
m_AppNameDirty = 1;
m_updateIcon = 1;
}
break;
case txt_workingdir:
m_WorkingDirDirty = 1;
break;
case txt_run_as:
//
// If m_fApplyRunAsEditChange is TRUE, the user has edited
// the RunAs control, therefore, we want to apply changes.
// If FALSE, the RunAs control has been automatically updated
// by the UI as a result of an apply. In this case, we do
// not want to apply the change, as it already has been.
//
if (m_fApplyRunAsEditChange)
{
m_RunAsDirty = 1;
HWND hwnd;
if (hwnd = _hCtrl(btn_passwd)) EnableWindow(hwnd, TRUE);
break;
}
else
{
Win4Assert(!m_fDirty);
return TRUE;
}
default:
return FALSE;
}
_EnableApplyButton();
}
else if (codeNotify == EN_KILLFOCUS &&
id == txt_app_name)
{
if (m_AppNameDirty == 1)
{
TCHAR tszApp[MAX_PATH + 1];
_GetAppAndArgs(tszApp, MAX_PATH + 1, NULL);
if (_JobObjectIsLocal())
{
_ExpandAppName(tszApp, MAX_PATH + 1);
}
_UpdateAppIcon(tszApp);
}
}
else if (id == chk_enable_job)
{
_EnableApplyButton();
m_updateIcon = 1;
_UpdateAppIcon(NULL);
}
return TRUE;
}
LRESULT
CGeneralPage::_OnApply(void)
{
TRACE(CGeneralPage, _OnApply);
if (m_fDirty == FALSE)
{
return TRUE;
}
HRESULT hr = S_OK;
WCHAR wcBuff[MAX_PATH+1];
LPWSTR pwszArg = NULL;
BOOL bNoAccountSpecified = FALSE;
do
{
if (m_CommentDirty == 1)
{
wcBuff[0] = L'\0';
I_GetDlgItemText(Hwnd(), txt_comments, wcBuff, MAX_PATH+1);
hr = m_pIJob->SetComment(wcBuff);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
m_CommentDirty = 0;
}
m_fTaskApplicationChange = FALSE;
if (m_AppNameDirty == 1)
{
WCHAR wszApp[MAX_PATH + 1];
_UpdateAppNameAndIcon(wszApp, MAX_PATH + 1, &pwszArg);
if (pwszArg == NULL)
{
break;
}
hr = m_pIJob->SetApplicationName(wszApp);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
hr = m_pIJob->SetParameters(pwszArg);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
m_AppNameDirty = 0;
m_fTaskApplicationChange = TRUE;
}
if (m_WorkingDirDirty == 1)
{
wcBuff[0] = L'\0';
_ExpandWorkingDir();
I_GetDlgItemText(Hwnd(), txt_workingdir, wcBuff, MAX_PATH+1);
hr = m_pIJob->SetWorkingDirectory(wcBuff);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
m_WorkingDirDirty = 0;
}
m_fTaskAccountChange = FALSE;
if (m_RunAsDirty == 1 || m_AccountInfo.pwszPassword != tszEmpty)
{
wcBuff[0] = L'\0';
DWORD ccAccountName = I_GetDlgItemText(Hwnd(),
txt_run_as,
wcBuff,
MAX_USERNAME + 1);
//
// Yell if the user blanked out the field.
//
if (wcBuff[0] == L'\0')
{
bNoAccountSpecified = TRUE;
hr = E_FAIL;
break;
}
if ((m_RunAsDirty == 1 && m_AccountInfo.pwszAccountName == NULL) ||
(m_RunAsDirty == 1 && m_AccountInfo.pwszAccountName != NULL &&
lstrcmpiW(m_AccountInfo.pwszAccountName, wcBuff) != 0))
{
//
// The user has changed the account name. Check if they have
// specified a password.
//
if (m_AccountInfo.pwszPassword == tszEmpty)
{
//
// User hasn't specified a password. Launch the set
// password dialog.
//
LaunchSetPasswordDlg(Hwnd(), &m_AccountInfo);
//
// Since we've launched the set password dialog, we want
// to suppress the set account information dialog which
// otherwise may come up on apply.
//
m_fSuppressAcctInfoRequestOnApply = TRUE;
}
}
if (m_AccountInfo.pwszPassword != tszEmpty)
{
//
// Translate input account prior to saving, then save it
//
DWORD cchAccount = MAX_USERNAME + 1;
WCHAR wszAccount[MAX_USERNAME + 1] = L"";
hr = TranslateAccount(TRANSLATE_FOR_INTERNAL, wcBuff, wszAccount, cchAccount, &(m_AccountInfo.pwszPassword));
if (SUCCEEDED(hr))
{
hr = m_pIJob->SetAccountInformation(wszAccount, m_AccountInfo.pwszPassword);
}
if (FAILED(hr))
{
CHECK_HRESULT(hr);
break;
}
m_RunAsDirty = 0;
m_AccountInfo.fDirty = FALSE;
m_fTaskAccountChange = TRUE;
}
}
//
// Save the job enabled state
//
if (this->IsTaskInTasksFolder())
{
DWORD dwFlags;
hr = m_pIJob->GetFlags(&dwFlags);
BOOL fTemp = (IsDlgButtonChecked(m_hPage, chk_enable_job)
== BST_CHECKED);
if (m_fEnableJob != fTemp)
{
m_fEnableJob = fTemp;
if (m_fEnableJob == TRUE)
{
dwFlags &= ~TASK_FLAG_DISABLED;
}
else
{
dwFlags |= TASK_FLAG_DISABLED;
}
hr = m_pIJob->SetFlags(dwFlags);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
}
}
//
// reset dirty flag
//
m_fDirty = FALSE;
//
// If evrything went well see if the other pages are ready to
// save the job to storage.
//
if ((m_fPersistChanges == TRUE) &&
(PropSheet_QuerySiblings(GetParent(Hwnd()),
QUERY_READY_TO_BE_SAVED, 0))
== 0)
{
//
// Save the job file to storage.
//
// For the first release of the scheduling agent, all security
// operations are disabled under Win95, even Win95 to NT.
//
hr = JFSaveJob(Hwnd(),
m_pIJob,
this->GetPlatformId() == VER_PLATFORM_WIN32_NT &&
this->IsTaskInTasksFolder(),
m_fTaskAccountChange,
m_fTaskApplicationChange,
m_fSuppressAcctInfoRequestOnApply);
CHECK_HRESULT(hr);
BREAK_ON_FAIL(hr);
m_fTaskApplicationChange = FALSE;
m_fTaskAccountChange = FALSE;
m_fSuppressAcctInfoRequestOnApply = FALSE;
// Will result in refresh of the run as edit control.
//
_UpdateRunAsControl();
}
} while (0);
delete [] pwszArg;
if (FAILED(hr))
{
if (hr == E_OUTOFMEMORY)
{
_ErrorDialog(IERR_OUT_OF_MEMORY);
}
else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
{
_ErrorDialog(IERR_FILE_NOT_FOUND);
}
else if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
{
_ErrorDialog(IERR_ACCESS_DENIED);
}
else if (bNoAccountSpecified)
{
_ErrorDialog(IERR_ACCOUNTNAME);
}
else
{
_ErrorDialog(IERR_INTERNAL_ERROR, hr);
}
}
return SUCCEEDED(hr);
}
//+--------------------------------------------------------------------------
//
// Member: CGeneralPage::_UpdateAppNameAndIcon
//
// Synopsis: Update the application name edit control with an expanded
// path for the app, then update the icon for the new path.
//
// Arguments: [wszApp] - NULL or buffer to receive WCHAR app name
// [appBufSize] - size of buffer in WCHARs
// [ppwszArgs] - NULL or address of pointer to buffer to receive
// WCHAR arguments. Must be deallocated with delete[].
//
// Modifies: *[wszApp], *[ppwszArgs]
//
// History: 1-31-1997 DavidMun Created
//
// Notes: App path is only expanded if job object is local.
//
//---------------------------------------------------------------------------
VOID
CGeneralPage::_UpdateAppNameAndIcon(
LPWSTR wszApp,
size_t appBufSize,
LPWSTR * ppwszArgs)
{
TCHAR tszApp[MAX_PATH + 1];
LPTSTR ptszArgs = NULL;
_GetAppAndArgs(tszApp, MAX_PATH + 1, &ptszArgs);
if (ptszArgs == NULL)
{
return;
}
if (_JobObjectIsLocal())
{
_ExpandAppName(tszApp, MAX_PATH + 1);
m_updateIcon = 1;
_UpdateAppIcon(tszApp);
//
// If the working directory is empty and the app is on the local
// machine, provide a default of the directory where the app lives.
//
TCHAR tszWorkingDir[MAX_PATH + 1];
GetDlgItemText(Hwnd(), txt_workingdir, tszWorkingDir, MAX_PATH + 1);
StripLeadTrailSpace(tszWorkingDir);
DeleteQuotes(tszWorkingDir);
if (!*tszWorkingDir && IsLocalFilename(tszApp))
{
StringCchCopy(tszWorkingDir, MAX_PATH + 1, tszApp);
DeleteQuotes(tszWorkingDir);
// Get rid of the filename at the end of the string
PathRemoveFileSpec(tszWorkingDir);
if (HasSpaces(tszWorkingDir))
{
AddQuotes(tszWorkingDir, MAX_PATH + 1);
}
SetDlgItemText(Hwnd(), txt_workingdir, tszWorkingDir);
}
m_ChangeFromSetText = 1;
_SetAppEdit(tszApp, ptszArgs);
}
if (wszApp)
{
StringCchCopy(wszApp, appBufSize, tszApp);
}
if (ppwszArgs)
{
*ppwszArgs = ptszArgs;
}
else
{
delete [] ptszArgs;
}
}
//+--------------------------------------------------------------------------
//
// Member: CGeneralPage::_ExpandWorkingDir
//
// Synopsis: Replace the string in the working directory edit control
// with one which has expanded environment strings.
//
// History: 06-04-1997 DavidMun Created
//
// Notes: Note that this will result in the working dir being marked
// as dirty.
//
//---------------------------------------------------------------------------
VOID
CGeneralPage::_ExpandWorkingDir()
{
TCHAR tszApp[MAX_PATH + 1];
//
// If editing a remote job, don't touch the working dir, since we
// can't expand using its environment variables.
//
if (!_JobObjectIsLocal())
{
return;
}
TCHAR tszWorkingDir[MAX_PATH + 1];
GetDlgItemText(Hwnd(), txt_workingdir, tszWorkingDir, MAX_PATH + 1);
StripLeadTrailSpace(tszWorkingDir);
DeleteQuotes(tszWorkingDir);
TCHAR tszExpandedWorkingDir[MAX_PATH + 1];
ULONG cchWritten;
cchWritten = ExpandEnvironmentStrings(tszWorkingDir,
tszExpandedWorkingDir,
ARRAYLEN(tszExpandedWorkingDir));
//
// If the call succeeded, write the update string to the working dir
// edit control. If there were no environment variables to replace,
// the string will be unchanged.
//
// Note that writing to the edit control will cause an EN_CHANGE which
// will result in m_WorkingDirDirty being set.
//
if (cchWritten && cchWritten <= ARRAYLEN(tszExpandedWorkingDir))
{
SetDlgItemText(Hwnd(), txt_workingdir, tszExpandedWorkingDir);
}
}
//+--------------------------------------------------------------------------
//
// Member: CGeneralPage::_GetAppAndArgs
//
// Synopsis: Fetch the string in the application name edit control and
// split it into the app name part and the arguments part.
//
// Arguments: [tszApp] - NULL or buffer for app name
// [pptszArgs] - NULL or address of pointer to buffer for args,
// must be deallocated with delete[]
//
// Modifies: *[tszApp], *[pptszArgs]
//
// History: 1-31-1997 DavidMun Created
//
// Notes: Application name is space delimited and must be surrounded
// by double quotes if it contains spaces. For example:
//
// text in edit ctrl 'filename' 'arguments'
// --------------------- -------------------------
// notepad.exe foo.txt => 'notepad.exe' 'foo.txt'
// "notepad.exe"foo.txt => '"notepad.exe"foo.txt' ''
// "notepad.exe" foo.txt => '"notepad.exe"' 'foo.txt'
// "no pad.exe" foo.txt => '"no pad.exe"' 'foo.txt'
// no pad.exe foo.txt => 'no' ' pad.exe foo.txt'
//
//---------------------------------------------------------------------------
VOID
CGeneralPage::_GetAppAndArgs(
LPTSTR tszApp,
size_t appBufSize,
LPTSTR * pptszArgs)
{
//
// Split application name into executable name & parameters. First
// strip lead/trail spaces and null terminate at the first whitespace
// outside a quote.
//
int cch = SchedGetDlgItemTextLength(Hwnd(), txt_app_name) + 1;
if (cch <= 1)
{
DEBUG_OUT((DEB_ERROR,
"SchedGetDlgItemTextLength failed %d\n",
GetLastError()));
}
TCHAR *ptszBoth = new TCHAR[cch];
if (ptszBoth == NULL)
{
DEBUG_OUT((DEB_ERROR,
"_GetAppAndArgs alloc failed %d\n",
GetLastError()));
return;
}
GetDlgItemText(Hwnd(), txt_app_name, ptszBoth, cch);
StripLeadTrailSpace(ptszBoth);
LPTSTR ptsz;
BOOL fInQuote = FALSE;
for (ptsz = ptszBoth; *ptsz; ptsz = NextChar(ptsz))
{
if (*ptsz == TEXT('"'))
{
fInQuote = !fInQuote;
}
else if (*ptsz == TEXT(' '))
{
if (!fInQuote)
{
*ptsz++ = L'\0';
break;
}
}
}
//
// Return app name if caller wants it.
//
if (tszApp)
{
StringCchCopy(tszApp, appBufSize, ptszBoth);
}
//
// Now ptsz points to the first char past the application
// name. If there are no arguments, then ptsz is pointing
// to the end of the string. Otherwise it's pointing to the
// start of the argument string. Return this if caller wants it.
//
if (pptszArgs)
{
size_t bufSize = cch - (ptsz - ptszBoth);
*pptszArgs = new TCHAR[bufSize];
if (*pptszArgs == NULL)
{
DEBUG_OUT((DEB_ERROR,
"_GetAppAndArgs second alloc failed %d\n",
GetLastError()));
}
else
{
StringCchCopy(*pptszArgs, bufSize, ptsz);
}
}
delete [] ptszBoth;
}
//+--------------------------------------------------------------------------
//
// Member: CGeneralPage::_ExpandAppName
//
// Synopsis: Change filename in [tszApp] to full path.
//
// Arguments: [tszApp] - filename to modify
//
// Modifies: *[tszApp]
//
// History: 1-31-1997 DavidMun Created
//
// Notes: CAUTION: Should be called only for job objects on the
// LOCAL MACHINE.
//
//---------------------------------------------------------------------------
VOID
CGeneralPage::_ExpandAppName(
LPTSTR tszApp,
size_t cchBuff)
{
TCHAR tszWorkingDir[MAX_PATH + 1];
BOOL fFound;
GetDlgItemText(Hwnd(), txt_workingdir, tszWorkingDir, MAX_PATH + 1);
fFound = ProcessApplicationName(tszApp, cchBuff, tszWorkingDir);
if (_tcschr(tszApp, TEXT(' ')))
{
AddQuotes(tszApp, MAX_PATH);
}
}
//+--------------------------------------------------------------------------
//
// Member: CGeneralPage::_SetAppEdit
//
// Synopsis: Set the application edit control to contain the concatenated
// text in [tszApp] and [tszArgs].
//
// Arguments: [tszApp] - application name
// [tszArgs] - arguments
//
// History: 1-31-1997 DavidMun Created
//
// Notes: No modification (adding quotes, etc.) is done to [tszApp].
// Caller should set m_ChangeFromSetText = 1 if calling from
// outside of wm_initdialog processing.
//
//---------------------------------------------------------------------------
VOID
CGeneralPage::_SetAppEdit(LPCTSTR tszApp, LPCTSTR tszArgs)
{
HWND hwndAppName = GetDlgItem(Hwnd(), txt_app_name);
Edit_SetText(hwndAppName, tszApp);
if (tszArgs && *tszArgs)
{
ULONG cchApp = lstrlen(tszApp);
Edit_SetSel(hwndAppName, cchApp, cchApp);
Edit_ReplaceSel(hwndAppName, TEXT(" "));
Edit_SetSel(hwndAppName, cchApp + 1, cchApp + 1);
Edit_ReplaceSel(hwndAppName, tszArgs);
}
}
LRESULT CGeneralPage::_OnCancel(void)
{
return 0;
}
LRESULT
CGeneralPage::_OnPSMQuerySibling(
WPARAM wParam,
LPARAM lParam)
{
TRACE(CGeneralPage, _OnPSMQuerySibling);
INT_PTR iRet = 0;
switch (wParam)
{
case QUERY_READY_TO_BE_SAVED:
iRet = (int)m_fDirty;
break;
case GET_ICON_HELPER:
iRet = (INT_PTR)m_pIconHelper;
break;
case QUERY_TASK_APPLICATION_DIRTY_STATUS:
*((BOOL *)lParam) = m_fTaskApplicationChange;
iRet = 1;
break;
case QUERY_TASK_ACCOUNT_INFO_DIRTY_STATUS:
*((BOOL *)lParam) = m_fTaskAccountChange;
iRet = 1;
break;
case QUERY_SUPPRESS_ACCOUNT_INFO_REQUEST_FLAG:
*((BOOL *)lParam) = m_fSuppressAcctInfoRequestOnApply;
iRet = 1;
break;
case RESET_TASK_APPLICATION_DIRTY_STATUS:
m_fTaskApplicationChange = FALSE;
iRet = 1;
break;
case RESET_TASK_ACCOUNT_INFO_DIRTY_STATUS:
m_fTaskAccountChange = FALSE;
iRet = 1;
break;
case RESET_SUPPRESS_ACCOUNT_INFO_REQUEST_FLAG:
m_fSuppressAcctInfoRequestOnApply = FALSE;
iRet = 1;
break;
case TASK_ACCOUNT_CHANGE_NOTIFY:
Win4Assert(!m_fDirty);
_UpdateRunAsControl();
iRet = 1;
break;
}
SetWindowLongPtr(Hwnd(), DWLP_MSGRESULT, iRet);
return iRet;
}
void
CGeneralPage::_UpdateRunAsControl(void)
{
LPWSTR pwsz;
if (SUCCEEDED(m_pIJob->GetAccountInformation(&pwsz)))
{
//
// Instruct the EN_CHANGE processing of the RunAs edit control
// to not apply this change.
//
m_fApplyRunAsEditChange = FALSE;
I_SetDlgItemText(Hwnd(), txt_run_as, pwsz);
m_fApplyRunAsEditChange = TRUE;
CoTaskMemFree(pwsz);
}
}
LRESULT
CGeneralPage::_OnPSNKillActive(
LPARAM lParam)
{
TRACE(CGeneralPage, _OnPSNKillActive);
if (m_AppNameDirty)
{
_UpdateAppNameAndIcon(NULL, 0, NULL);
}
if (m_WorkingDirDirty)
{
_ExpandWorkingDir();
}
return CPropPage::_OnPSNKillActive(lParam);
}
LRESULT
CGeneralPage::_OnHelp(
HANDLE hRequesting,
UINT uiHelpCommand)
{
WinHelp((HWND)hRequesting,
szMstaskHelp,
uiHelpCommand,
(DWORD_PTR)(LPSTR)s_aGeneralPageHelpIds);
return TRUE;
}
HRESULT
GetGeneralPage(
ITask * pIJob,
LPTSTR ptszTaskPath,
BOOL fPersistChanges,
HPROPSHEETPAGE * phpage)
{
TRACE_FUNCTION(GetGeneralPage);
Win4Assert(pIJob != NULL);
Win4Assert(phpage != NULL);
HRESULT hr = S_OK;
LPOLESTR polestr = NULL;
IPersistFile * ppf = NULL;
LPTSTR ptszPath = NULL;
do
{
//
// Get the job name.
//
if (ptszTaskPath != NULL)
{
//
// use passed-in path
//
ptszPath = ptszTaskPath;
}
else
{
//
// Obtain the job path from the interfaces.
//
hr = GetJobPath(pIJob, &ptszPath);
}
BREAK_ON_FAIL(hr);
CGeneralPage * pPage = new CGeneralPage(
pIJob,
ptszPath,
fPersistChanges);
if (pPage == NULL)
{
hr = E_OUTOFMEMORY;
CHECK_HRESULT(hr);
break;
}
HPROPSHEETPAGE hpage = CreatePropertySheetPage(&pPage->m_psp);
if (hpage == NULL)
{
delete pPage;
hr = E_OUTOFMEMORY;
CHECK_HRESULT(hr);
break;
}
*phpage = hpage;
} while (0);
//
// If we made a copy of pIJob's path string, free it.
//
if (ptszPath != ptszTaskPath)
{
delete [] ptszPath;
}
if (ppf != NULL)
{
ppf->Release();
}
return hr;
}
HRESULT
AddGeneralPage(
PROPSHEETHEADER &psh,
ITask * pIJob)
{
TRACE_FUNCTION(AddGeneralPage);
HPROPSHEETPAGE hpage = NULL;
HRESULT hr = GetGeneralPage(pIJob, NULL, TRUE, &hpage);
if (SUCCEEDED(hr))
{
psh.phpage[psh.nPages++] = hpage;
}
return hr;
}
HRESULT
AddGeneralPage(
LPFNADDPROPSHEETPAGE lpfnAddPage,
LPARAM cookie,
ITask * pIJob)
{
HPROPSHEETPAGE hpage = NULL;
HRESULT hr = GetGeneralPage(pIJob, NULL, TRUE, &hpage);
if (SUCCEEDED(hr))
{
if (!lpfnAddPage(hpage, cookie))
{
DestroyPropertySheetPage(hpage);
hr = E_FAIL;
CHECK_HRESULT(hr);
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: ResetAccountInfo
//
// Synopsis: Deallocate and initialize the account information specified.
//
// Arguments: [pAccountInfo] -- Account info structure.
//
// Returns: None.
//
// Notes: None.
//
//----------------------------------------------------------------------------
void
ResetAccountInfo(
AccountInfo * pAccountInfo)
{
//
// Delete the account name.
//
if (pAccountInfo->pwszAccountName != NULL)
{
//
// NB : pwszAccountName always allocated by CoTaskMemAlloc.
//
CoTaskMemFree(pAccountInfo->pwszAccountName);
pAccountInfo->pwszAccountName = NULL;
}
//
// Zero, delete the password. Except when the password is set to the
// static empty string.
//
if (pAccountInfo->pwszPassword != NULL &&
pAccountInfo->pwszPassword != tszEmpty)
{
ZERO_PASSWORD(pAccountInfo->pwszPassword);
delete pAccountInfo->pwszPassword;
pAccountInfo->pwszPassword = (LPWSTR) tszEmpty;
}
}
//+---------------------------------------------------------------------------
//
// Function: InitializeAccountInfo
//
// Synopsis: Initializes account info fields.
//
// Arguments: [pAccountInfo] -- Account info structure.
//
// Returns: None.
//
// Notes: None.
//
//----------------------------------------------------------------------------
void
InitializeAccountInfo(AccountInfo * pAccountInfo)
{
pAccountInfo->pwszAccountName = NULL;
//
// If we haven't prompted for a password, pwszPassword points to the
// global empty string variable. This allows us to tell whether the
// user intended the password to be an empty string, or we simply
// haven't prompted for it.
//
pAccountInfo->pwszPassword = (LPWSTR) tszEmpty;
}
//
// Helpers to launch Set/Change Password & Set Account Information dialogs.
//
//+---------------------------------------------------------------------------
//
// Function: LaunchSetPasswordDlg
//
// Synopsis: Helper to launch the dialog to modify the account password.
//
// Arguments: [hWnd] -- Parent window handle.
// [pAccountInfo] -- Structure manipulated by the dialog.
//
// Returns: DialogBoxParam return code.
//
// Notes: None.
//
//----------------------------------------------------------------------------
INT_PTR
LaunchSetPasswordDlg(HWND hWnd, AccountInfo * pAccountInfo)
{
return(DialogBoxParam(g_hInstance,
MAKEINTRESOURCE(set_passwd_dlg),
hWnd,
SetPasswordDlgProc,
(LPARAM)pAccountInfo));
}
//+---------------------------------------------------------------------------
//
// Function: LaunchSetAccountInformationDlg
//
// Synopsis: Helper to launch the dialog to modify the account namd and
// password.
//
// Arguments: [hWnd] -- Parent window handle.
// [pAccountInfo] -- Structure manipulated by the dialog.
//
// Returns: DialogBoxParam return code.
//
// Notes: None.
//
//----------------------------------------------------------------------------
INT_PTR
LaunchSetAccountInformationDlg(HWND hWnd, AccountInfo * pAccountInfo)
{
return(DialogBoxParam(g_hInstance,
MAKEINTRESOURCE(set_account_info_dlg),
hWnd,
SetAccountInformationDlgProc,
(LPARAM)pAccountInfo));
}
//
// Set/Change Password & Set Account Information dialogs.
//
//+---------------------------------------------------------------------------
//
// Function: SetPasswordDlgProc
//
// Synopsis: This dialog allows the user specify an account password.
// The password is confirmed by a redundant confirmation edit
// field.
//
// Arguments: [hDlg] -- Dialog handle.
// [uMsg] -- Message.
// [wParam] -- Command.
// [lParam] -- Account information dialog ptr on WM_INITDIALOG.
//
// Returns: TRUE -- Message processed by this dialog.
// FALSE -- Message not processed (WM_INITDIALOG excepted).
//
// Notes: None.
//
//----------------------------------------------------------------------------
INT_PTR APIENTRY
SetPasswordDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static AccountInfo * pai = NULL;
TCHAR tszPassword[MAX_PASSWORD + 1] = TEXT("");
TCHAR tszConfirmedPassword[MAX_PASSWORD + 1] = TEXT("");
LPWSTR pwszPassword;
switch (uMsg)
{
case WM_INITDIALOG:
Win4Assert(lParam != NULL);
pai = (AccountInfo *)lParam;
Edit_LimitText(GetDlgItem(hDlg, edt_sp_passwd), MAX_PASSWORD);
Edit_LimitText(GetDlgItem(hDlg, edt_sp_cfrmpasswd), MAX_PASSWORD);
I_SetDlgItemText(hDlg, edt_sp_passwd, pai->pwszPassword);
I_SetDlgItemText(hDlg, edt_sp_cfrmpasswd, pai->pwszPassword);
//
// Center the dialog.
//
CenterDialog(hDlg);
return TRUE; // TRUE == let windows set focus
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
DWORD ccPassword;
ccPassword = GetDlgItemText(hDlg,
edt_sp_passwd,
tszPassword,
MAX_PASSWORD + 1);
GetDlgItemText(hDlg,
edt_sp_cfrmpasswd,
tszConfirmedPassword,
MAX_PASSWORD + 1);
if (lstrcmp(tszPassword, tszConfirmedPassword) != 0)
{
//
// Passwords didn't match. Let the user know so he/she
// can correct it.
//
SecureZeroMemory(tszPassword, sizeof tszPassword);
SecureZeroMemory(tszConfirmedPassword, sizeof tszConfirmedPassword);
SchedUIErrorDialog(hDlg, IERR_PASSWORD, (LPTSTR)NULL);
return(TRUE);
}
if (ccPassword)
{
//
// Non-NULL password.
//
ccPassword++;
pwszPassword = new WCHAR[ccPassword];
if (pwszPassword != NULL)
{
StringCchCopy(pwszPassword, ccPassword, tszPassword);
SecureZeroMemory(tszPassword, sizeof tszPassword);
SecureZeroMemory(tszConfirmedPassword, sizeof tszConfirmedPassword);
}
else
{
SchedUIErrorDialog(hDlg, IERR_OUT_OF_MEMORY,
(LPTSTR)NULL);
}
}
else
{
//
// Clear the password.
//
pwszPassword = new WCHAR[1];
if (pwszPassword != NULL)
{
*pwszPassword = L'\0';
}
else
{
SchedUIErrorDialog(hDlg, IERR_OUT_OF_MEMORY,
(LPTSTR)NULL);
EndDialog(hDlg, wParam);
return(TRUE);
}
}
//
// Zero, delete the previous password. But don't delete the
// static empty string.
//
if (pai->pwszPassword != NULL &&
pai->pwszPassword != tszEmpty)
{
ZERO_PASSWORD(pai->pwszPassword);
delete pai->pwszPassword;
}
pai->pwszPassword = pwszPassword;
case IDCANCEL:
SecureZeroMemory(tszPassword, sizeof tszPassword);
SecureZeroMemory(tszConfirmedPassword, sizeof tszConfirmedPassword);
EndDialog(hDlg, wParam);
return TRUE;
default:
return FALSE;
}
case WM_HELP:
WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle,
szMstaskHelp,
HELP_WM_HELP,
(DWORD_PTR)(LPSTR)s_aSetPasswordDlgHelpIds);
return TRUE;
case WM_CONTEXTMENU:
WinHelp((HWND) wParam,
szMstaskHelp,
HELP_CONTEXTMENU,
(DWORD_PTR)(LPSTR)s_aSetPasswordDlgHelpIds);
return TRUE;
default:
return FALSE;
}
}
//+---------------------------------------------------------------------------
//
// Function: SetAccountInformationDlgProc
//
// Synopsis: This dialog allows the user to specify full account
// information: the account name and password. The password
// is confirmed by a redundant confirmation edit field.
// Logic also ensures the user must specify an account name.
//
// Arguments: [hDlg] -- Dialog handle.
// [uMsg] -- Message.
// [wParam] -- Command.
// [lParam] -- Account information dialog ptr on WM_INITDIALOG.
//
// Returns: TRUE -- Message processed by this dialog.
// FALSE -- Message not processed (WM_INITDIALOG excepted).
//
// Notes: None.
//
//----------------------------------------------------------------------------
INT_PTR APIENTRY
SetAccountInformationDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam,
LPARAM lParam)
{
static AccountInfo * pai = NULL;
TCHAR tszAccountName[MAX_USERNAME + 1] = TEXT("");
TCHAR tszPassword[MAX_PASSWORD + 1] = TEXT("");
TCHAR tszConfirmedPassword[MAX_PASSWORD + 1] = TEXT("");
DWORD ccAccountName = MAX_USERNAME + 1;
LPWSTR pwszPassword;
switch (uMsg)
{
case WM_INITDIALOG:
Win4Assert(lParam != NULL);
pai = (AccountInfo *)lParam;
Edit_LimitText(GetDlgItem(hDlg, edt_sa_passwd), MAX_USERNAME);
Edit_LimitText(GetDlgItem(hDlg, edt_sa_passwd), MAX_PASSWORD);
Edit_LimitText(GetDlgItem(hDlg, edt_sa_cfrmpasswd), MAX_PASSWORD);
if (pai->pwszAccountName != NULL)
{
//
// Translate account prior to display, then display it
//
HRESULT hr = TranslateAccount(TRANSLATE_FOR_DISPLAY, pai->pwszAccountName, tszAccountName, ccAccountName);
if (FAILED(hr))
{
StringCchCopy(tszAccountName, MAX_USERNAME + 1, pai->pwszAccountName);
}
}
else
{
GetDefaultDomainAndUserName(tszAccountName, ccAccountName);
}
SetDlgItemText(hDlg, txt_sa_run_as, tszAccountName);
I_SetDlgItemText(hDlg, edt_sa_passwd, pai->pwszPassword);
I_SetDlgItemText(hDlg, edt_sa_cfrmpasswd, pai->pwszPassword);
//
// Center the dialog.
//
CenterDialog(hDlg);
return TRUE; // TRUE == let windows set focus
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
DWORD ccAccountName, ccPassword;
tszAccountName[0] = _T('\0');
ccAccountName = GetDlgItemText(hDlg, txt_sa_run_as,
tszAccountName, MAX_USERNAME + 1);
if (tszAccountName[0] != _T('\0'))
{
ccAccountName++;
LPWSTR pwszAccountName = (LPWSTR)CoTaskMemAlloc(
ccAccountName * sizeof(WCHAR));
if (pwszAccountName != NULL)
{
StringCchCopy(pwszAccountName, ccAccountName, tszAccountName);
ccPassword = GetDlgItemText(hDlg, edt_sa_passwd,
tszPassword,
MAX_PASSWORD + 1);
GetDlgItemText(hDlg, edt_sa_cfrmpasswd,
tszConfirmedPassword, MAX_PASSWORD + 1);
if (lstrcmp(tszPassword, tszConfirmedPassword) != 0)
{
//
// Passwords didn't match. Let the user know so he/she
// can correct it.
//
CoTaskMemFree(pwszAccountName);
SchedUIErrorDialog(hDlg, IERR_PASSWORD,
(LPTSTR)NULL);
return(TRUE);
}
else
{
if (ccPassword)
{
//
// Non-NULL password.
//
ccPassword++;
pwszPassword = new WCHAR[ccPassword];
if (pwszPassword != NULL)
{
StringCchCopy(pwszPassword, ccPassword, tszPassword);
SecureZeroMemory(tszPassword, sizeof tszPassword);
SecureZeroMemory(tszConfirmedPassword, sizeof tszConfirmedPassword);
}
else
{
CoTaskMemFree(pwszAccountName);
SchedUIErrorDialog(hDlg, IERR_OUT_OF_MEMORY,
(LPTSTR)NULL);
EndDialog(hDlg, wParam);
return(TRUE);
}
}
else
{
//
// Clear the password.
//
pwszPassword = new WCHAR[1];
if (pwszPassword != NULL)
{
*pwszPassword = L'\0';
}
else
{
CoTaskMemFree(pwszAccountName);
SchedUIErrorDialog(hDlg, IERR_OUT_OF_MEMORY,
(LPTSTR)NULL);
EndDialog(hDlg, wParam);
return(TRUE);
}
}
}
if (pai->pwszAccountName != NULL)
{
CoTaskMemFree(pai->pwszAccountName);
pai->pwszAccountName = NULL;
}
if (pai->pwszPassword != NULL &&
pai->pwszPassword != tszEmpty)
{
ZERO_PASSWORD(pai->pwszPassword);
delete pai->pwszPassword;
pai->pwszPassword = NULL;
}
//
// Translate input account prior to saving, then save it
//
DWORD cchAccount = MAX_USERNAME + 1;
WCHAR wszAccount[MAX_USERNAME + 1] = L"";
HRESULT hr = TranslateAccount(TRANSLATE_FOR_INTERNAL, pwszAccountName, wszAccount, cchAccount, &pwszPassword);
if (SUCCEEDED(hr))
{
lstrcpynW(pwszAccountName, wszAccount, cchAccount); // copy translated name back into original buffer which will evenutally be CoTaskMemFree'd
pai->pwszAccountName = pwszAccountName;
pai->pwszPassword = pwszPassword;
}
else
{
CoTaskMemFree(pwszAccountName);
SchedUIErrorDialog(hDlg, IERR_INTERNAL_ERROR, (LPTSTR)NULL);
EndDialog(hDlg, wParam);
return(TRUE);
}
}
else
{
SchedUIErrorDialog(hDlg, IERR_OUT_OF_MEMORY, (LPTSTR)NULL);
EndDialog(hDlg, wParam);
return(TRUE);
}
}
else
{
//
// User cannot specify an empty account name.
//
SchedUIErrorDialog(hDlg, IERR_ACCOUNTNAME, (LPTSTR)NULL);
return(TRUE);
}
case IDCANCEL:
EndDialog(hDlg, wParam);
return TRUE;
}
default:
return FALSE;
}
}
//+---------------------------------------------------------------------------
//
// Function: CenterDialog
//
// Synopsis: Helper to center a dialog on screen.
//
// Arguments: [hDlg] -- Dialog handle.
//
// Returns: None.
//
// Notes: None.
//
//----------------------------------------------------------------------------
void
CenterDialog(HWND hDlg)
{
RECT rc;
GetWindowRect(hDlg, &rc);
SetWindowPos(hDlg,
NULL,
((GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2),
((GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2),
0,
0,
SWP_NOSIZE | SWP_NOACTIVATE);
}
//+---------------------------------------------------------------------------
//
// Function: SchedGetDlgItemTextLength
//
// Synopsis: Implements a GetDlgItemTextLength function since Win32 lacks it
//
// Arguments:
//
// Returns:
//
//----------------------------------------------------------------------------
int
SchedGetDlgItemTextLength(
HWND hwnd,
int id)
{
if ((hwnd = GetDlgItem(hwnd, id)) != NULL)
{
return GetWindowTextLength(hwnd);
}
return 0;
}