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.
 
 
 
 
 
 

2929 lines
77 KiB

#ifndef SECURITY_WIN32
#define SECURITY_WIN32
#endif
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <initguid.h>
#include <windowsx.h>
#include <winuserp.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <mdcommsg.h>
#include <lm.h>
#include <shlobj.h>
#include <Cmnquery.h>
#include <dsclient.h>
#include <Dsquery.h>
#include <htmlhelp.h>
#include <reason.h>
#include <regstr.h>
#include "resource.h"
#ifndef WARNING_DIRTY_REBOOT
#define WARNING_DIRTY_REBOOT 0x80000434L
#endif
//#define SNAPSHOT_TEST
#ifdef SNAPSHOT_TEST
#define TESTMSG(x) \
WriteToConsole((x))
#else
#define TESTMSG(x)
#endif //SNAPSHOT_TEST
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define ERROR_WITH_SZ(id, sz, code) \
{ \
LPWSTR szBuf = LoadWString(id);\
if (szBuf)\
{\
if (sz && wcslen(sz) > 0) \
{\
LPWSTR szBuf1 = (LPWSTR)LocalAlloc(LMEM_FIXED, (wcslen(szBuf) + wcslen(sz) + 20) * sizeof(WCHAR));\
if (szBuf1)\
{\
if (code != 0) \
wsprintf(szBuf1, L"%s: %s(%d)\n", sz, szBuf, code);\
else \
wsprintf(szBuf1, L"%s: %s\n", sz, szBuf);\
WriteToError(szBuf1);\
LocalFree(szBuf1);\
}\
}\
else\
{\
LPWSTR szBuf1 = (LPWSTR)LocalAlloc(LMEM_FIXED, (wcslen(szBuf) + 20) * sizeof(WCHAR));\
if (szBuf1)\
{\
if (code != 0) \
wsprintf(szBuf1, L"%s(%d)\n", szBuf, code);\
else \
wsprintf(szBuf1, L"%s\n", szBuf);\
WriteToError(szBuf1);\
LocalFree(szBuf1);\
}\
}\
LocalFree(szBuf);\
}\
}
//
// Default warning state for warning user check button
//
#define DEFAULTWARNINGSTATE BST_CHECKED
#define TITLEWARNINGLEN 32
#define MINCOMMENTLEN 0
#define MAX_TIMEOUT 60*10 // 10 min.
#define DEFAULT_TIMEOUT 30
// Name of the executable
LPWSTR g_lpszProgramName = NULL;
// Help dir.
LPWSTR g_lpszHelpdir = NULL;
LPWSTR g_lpszHelpdirHlp = NULL;
LPWSTR g_lpszHelpdirChm = NULL;
LPWSTR g_lpszHelpdirWindows = NULL;
// Name of help file.
LPWSTR HELP_FILE = L"rrc.hlp";
LPWSTR CHM_FILE = L"rrc.chm";
LPWSTR WINDOWS_HELP = L"Windows.hlp";
LPWSTR CHM_MAIN = L"::/rrcHowToShutdownRemotely.htm";
LPWSTR g_lpszDefaultTimeout = L"30";
LPWSTR g_lpszMaxTimeout = L"600";
// original edit control win proc.
WNDPROC wpOrigEditProc;
//
// Help ids
//
DWORD ShutdownDialogHelpIds[] =
{
IDOK, 28443,
IDCANCEL, 28444,
IDHELP, 28445 ,
IDC_COMBOACTION, IDH_SHUTDOWN_COMBOACTION,
IDC_COMBOOPTION, IDH_SHUTDOWN_COMBOOPTION,
IDC_LISTSELECTEDCOMPUTERS, IDH_SHUTDOWN_SELECTEDCOMPUTERS,
IDC_BUTTONREMOVE, IDH_SHUTDOWN_BUTTONREMOVE,
IDC_BUTTONBROWSE, IDH_SHUTDOWN_BUTTONBROWSE,
IDC_CHECKWARNING, IDH_SHUTDOWN_CHECKWARNING,
IDC_EDITTIMEOUT, IDH_SHUTDOWN_EDITTIMEOUT,
IDC_EDITCOMMENT, IDH_SHUTDOWN_EDITCOMMENT,
IDC_BUTTONADDNEW, IDH_SHUTDOWN_BUTTONADDNEW,
IDC_CHECK_PLANNED, IDH_SHUTDOWN_CHECK_PLANNED,
0, 0
};
DWORD AddNewDialogHelpIds[] =
{
IDOK, 28443,
IDCANCEL, 28444,
IDC_EDIT_ADDCOMPUTERS_COMPUTERS, IDH_ADDNEW_COMPUTERS,
0, 0
};
//
// Enum for all of the actions.
//
enum
{
ACTION_SHUTDOWN = 0,
ACTION_RESTART = 1,
ACTION_ANNOTATE,
ACTION_LOGOFF,
ACTION_STANDBY,
ACTION_DISCONNECT,
ACTION_ABORT
};
//
// Resource IDs for actions.
//
DWORD g_dwActions[] =
{
IDS_ACTION_SHUTDOWN,
IDS_ACTION_RESTART,
// IDS_ACTION_LOGOFF,
IDS_ACTION_ANNOTATE
//IDS_ACTION_STANDBY,
//IDS_ACTION_DISCONNECT,
//IDS_ACTION_ABORT
};
enum
{
OPTION_ABORT = 0,
OPTION_ANNOTATE,
OPTION_HIBERNATE,
OPTION_LOGOFF,
OPTION_POWEROFF,
OPTION_RESTART,
OPTION_SHUTDOWN,
FLAG_COMMENT = 0,
FLAG_REASON,
FLAG_MACHINE,
FLAG_FORCE
};
//
// Number of actions and the action strings loaded from resource.
//
const int g_nActions = sizeof(g_dwActions) / sizeof(DWORD);
WCHAR g_lppszActions[g_nActions][MAX_PATH];
LPWSTR g_lpszNewComputers = NULL;
WCHAR g_lpszDefaultDomain[MAX_PATH] = L"";
WCHAR g_lpszLocalComputerName[MAX_PATH] = L"";
WCHAR g_lpszTitleWarning[TITLEWARNINGLEN];
BOOL g_bAssumeShutdown = FALSE;
BOOL g_bDirty = FALSE;
struct _PROVIDER{
LPWSTR szName;
DWORD dwLen;
};
typedef struct _SHUTDOWNREASON
{
DWORD dwCode;
WCHAR lpName[MAX_REASON_NAME_LEN];
WCHAR lpDesc[MAX_REASON_DESC_LEN];
} SHUTDOWNREASON, *PSHUTDOWNREASON;
DWORD g_dwReasonSelect;
DWORD g_dwActionSelect;
typedef struct _SHUTDOWNCACHEDHWNDS
{
HWND hwndShutdownDialog;
HWND hwndListSelectComputers;
HWND hwndEditComment;
HWND hwndStaticDesc;
HWND hwndEditTimeout;
HWND hwndButtonWarning;
HWND hwndComboAction;
HWND hwndComboOption;
HWND hwndBtnAdd;
HWND hwndBtnRemove;
HWND hwndBtnBrowse;
HWND hwndChkPlanned;
HWND hwndButtonOK;
HWND hwndStaticComment;
} SHUTDOWNCACHEDHWNDS, *PSHUTDOWNCACHEDHWNDS;
SHUTDOWNCACHEDHWNDS g_wins;
enum
{
POWER_OPTION_HIBERNATE,
POWER_OPTION_POWEROFF
};
HMODULE g_hDllInstance = NULL;
typedef BOOL (*REASONBUILDPROC)(REASONDATA *, BOOL, BOOL);
typedef VOID (*REASONDESTROYPROC)(REASONDATA *);
BOOL GetComputerNameFromPath(LPWSTR szPath, LPWSTR szName);
VOID AdjustWindowState();
INT_PTR
CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);
INT_PTR
CALLBACK AddNew_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);
INT_PTR
CALLBACK Browse_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);
BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
BOOL AddNew_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
BOOL Browse_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
BOOL Browse_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
BOOL PowerOptionEnabled(UINT option);
BOOL Annotate(LPCWSTR lpMachine, LPDWORD lpdwReason, LPCWSTR lpComment, LPDWORD lpdwErr);
VOID report_error(DWORD error_code, LPCWSTR pwszComputer);
BOOL GetTokenHandle(PHANDLE pTokenHandle);
BOOL GetUserSid(PTOKEN_USER *ppTokenUser);
BOOL IsStaticControl (HWND hwnd);
WCHAR* LoadWString(int resid);
LRESULT APIENTRY EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
typedef void (*PSetThreadUILanguage)(DWORD);
class ShutdownHelp
{
DWORD dwCookie;
public:
ShutdownHelp():dwCookie(NULL)
{
HtmlHelp(NULL, NULL, HH_INITIALIZE, (ULONG_PTR)(&dwCookie));
}
~ShutdownHelp()
{
// HtmlHelp(NULL, NULL, HH_CLOSE_ALL, 0);
HtmlHelp(NULL, NULL, HH_UNINITIALIZE, dwCookie);
}
};
class Reasons
{
public:
PSHUTDOWNREASON m_lpReasons;
int m_cReasons;
int m_dwReasonSelect;
WCHAR m_lpszDefaultTitle[MAX_REASON_NAME_LEN];
Reasons():m_lpReasons(NULL),m_cReasons(0),m_dwReasonSelect(-1)
{
HMODULE hUser32;
REASONBUILDPROC buildProc;
REASONDESTROYPROC DestroyProc;
WCHAR lpReasonName[MAX_REASON_NAME_LEN];
REASONDATA Reasons;
m_lpszDefaultTitle[0] = L'\0';
hUser32 = LoadLibraryW(L"user32.dll");
if(hUser32 != NULL)
{
//
// We are using the user32.dll to get and destroy the reasons.
// The reasons are added to the option combo and also cached for later use.
//
LoadStringW(hUser32, IDS_REASON_DEFAULT_TITLE, m_lpszDefaultTitle, MAX_REASON_NAME_LEN);
m_lpszDefaultTitle[MAX_REASON_NAME_LEN-1] = L'\0';
buildProc = (REASONBUILDPROC)GetProcAddress(hUser32, "BuildReasonArray");
DestroyProc = (REASONDESTROYPROC)GetProcAddress(hUser32, "DestroyReasons");
if(!buildProc || !DestroyProc)
{
FreeLibrary(hUser32);
hUser32 = NULL;
return;
}
if(!(*buildProc)(&Reasons, FALSE, FALSE))
{
report_error( GetLastError( ), NULL);
FreeLibrary(hUser32);
return;
}
if (Reasons.cReasons == 0)
{
(*DestroyProc)(&Reasons);
//
// BUG 592702: shutdown.exe .NET - no reasons listed when running on XP.
// ON XP if both Clean and Dirty flags are FALSE, user32 won't build
// any reason and return success, so we will retry it with Clean
// and Dirty both are set to TRUE.
//
if(!(*buildProc)(&Reasons, TRUE, TRUE))
{
report_error( GetLastError( ), NULL);
FreeLibrary(hUser32);
return;
}
}
}
else
{
report_error( GetLastError( ), NULL);
return;
}
//
// Alloc space for reasons.
//
m_lpReasons = (PSHUTDOWNREASON)LocalAlloc(LMEM_FIXED, Reasons.cReasons * sizeof(SHUTDOWNREASON));
if(!m_lpReasons)
{
(*DestroyProc)(&Reasons);
report_error( GetLastError( ), NULL);
FreeLibrary(hUser32);
return;
}
//
// Now populate the combo according the current check state and action.
//
for (int iOption = 0; iOption < (int)Reasons.cReasons; iOption++)
{
wcscpy(m_lpReasons[iOption].lpName, Reasons.rgReasons[iOption]->szName);
wcscpy(m_lpReasons[iOption].lpDesc, Reasons.rgReasons[iOption]->szDesc);
m_lpReasons[iOption].dwCode = Reasons.rgReasons[iOption]->dwCode;
}
m_cReasons = (int)Reasons.cReasons;
(*DestroyProc)(&Reasons);
FreeLibrary(hUser32);
}
~Reasons()
{
if(m_lpReasons)
LocalFree(m_lpReasons);
}
BOOL RequireComment(DWORD dwReason, BOOL isDirty = FALSE)
{
DWORD dwFlag = isDirty ? SHTDN_REASON_FLAG_DIRTY_PROBLEM_ID_REQUIRED : SHTDN_REASON_FLAG_COMMENT_REQUIRED;
DWORD dwDirtyOrClean = isDirty ? SHTDN_REASON_FLAG_DIRTY_UI : SHTDN_REASON_FLAG_CLEAN_UI;
DWORD dwAll = SHTDN_REASON_FLAG_DIRTY_PROBLEM_ID_REQUIRED | SHTDN_REASON_FLAG_COMMENT_REQUIRED
| SHTDN_REASON_FLAG_DIRTY_UI | SHTDN_REASON_FLAG_CLEAN_UI;
if (!m_lpReasons)
return FALSE;
if (dwReason & dwFlag)
return TRUE;
for(int i = 0; i < m_cReasons; i++)
{
if(m_lpReasons[i].dwCode & dwFlag)
{
if ( ((m_lpReasons[i].dwCode & ~dwAll) == (dwReason & ~dwAll))
&& (m_lpReasons[i].dwCode & dwDirtyOrClean) )
return TRUE;
}
}
return FALSE;
}
BOOL RequireComment(DWORD dwMajor, DWORD dwMinor, BOOL isDirty, BOOL isPlanned, BOOL isUserDefined)
{
DWORD dwReason = dwMinor;
dwReason <<= 20;
dwReason &= dwMajor;
if(isPlanned)
dwReason &= SHTDN_REASON_FLAG_PLANNED;
if(isUserDefined)
dwReason &= SHTDN_REASON_FLAG_USER_DEFINED;
return RequireComment (dwReason, isDirty);
}
VOID FillCombo(HWND hwnd, BOOL isDirty, BOOL isPlanned, HWND hwndStatic)
{
int iOption;
int iFirst = -1;
DWORD dwPlanned = isPlanned ? SHTDN_REASON_FLAG_PLANNED : 0;
DWORD dwDirty = isDirty ? SHTDN_REASON_FLAG_DIRTY_UI : SHTDN_REASON_FLAG_CLEAN_UI;
if(! hwnd)
return;
//
// Remove all items from combo
//
while (ComboBox_GetCount(hwnd))
ComboBox_DeleteString(hwnd, 0);
//
// Now populate the combo according the current check state.
//
for (iOption = 0; iOption < (int)m_cReasons; iOption++)
{
if(((m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_PLANNED) == dwPlanned)
&& ((m_lpReasons[iOption].dwCode & dwDirty) == dwDirty))
{
ComboBox_AddString(hwnd, m_lpReasons[iOption].lpName);
if (iFirst == -1)
iFirst = iOption;
}
}
if(iFirst != -1)
{
ComboBox_SelectString(hwnd, -1, m_lpReasons[iFirst].lpName);
if (hwndStatic)
SetWindowTextW(hwndStatic, m_lpReasons[iFirst].lpDesc);
}
m_dwReasonSelect = iFirst;
}
VOID SetDesc(HWND hCombo, HWND hDesc)
{
WCHAR szName[MAX_REASON_NAME_LEN];
if(!hCombo || !hDesc)
return;
GetWindowText(hCombo, (LPWSTR)szName, MAX_REASON_NAME_LEN);
szName[MAX_REASON_NAME_LEN-1] = '\0';
for(DWORD dwIndex = 0; dwIndex < (DWORD)m_cReasons; dwIndex++)
{
if(lstrcmp(szName, m_lpReasons[dwIndex].lpName) == 0)
{
SetWindowTextW(hDesc, m_lpReasons[dwIndex].lpDesc);
m_dwReasonSelect = dwIndex;
break;
}
}
}
VOID GetReasonTitle(DWORD dwReason, LPWSTR szBuf, DWORD dwSize)
{
DWORD dwFlagBits = SHTDN_REASON_FLAG_CLEAN_UI | SHTDN_REASON_FLAG_DIRTY_UI;
if(!szBuf || dwSize == 0)
return;
for(int i = 0; i < m_cReasons; i++)
{
if ((dwReason & SHTDN_REASON_VALID_BIT_MASK) == (m_lpReasons[i].dwCode & SHTDN_REASON_VALID_BIT_MASK))
{
if ((!(dwReason & dwFlagBits) && !(m_lpReasons[i].dwCode & dwFlagBits))
|| (dwReason & SHTDN_REASON_FLAG_CLEAN_UI && m_lpReasons[i].dwCode & SHTDN_REASON_FLAG_CLEAN_UI)
|| (dwReason & SHTDN_REASON_FLAG_DIRTY_UI && m_lpReasons[i].dwCode & SHTDN_REASON_FLAG_DIRTY_UI) ) { // check flag bits.
lstrcpynW(szBuf, m_lpReasons[i].lpName, dwSize - 1);
szBuf[dwSize - 1] = '\0';
return;
}
}
}
wcsncpy(szBuf, m_lpszDefaultTitle, dwSize - 1);
szBuf[dwSize - 1] = '\0';
}
} g_reasons;
//
// Check whether a string is all white spaces.
//
BOOL
IsEmpty(LPCWSTR lpCWSTR)
{
if(!lpCWSTR)
return TRUE;
while(*lpCWSTR && (*lpCWSTR == '\n' || *lpCWSTR == '\t' || *lpCWSTR == '\r' || *lpCWSTR == ' '))
lpCWSTR++;
if(*lpCWSTR)
return FALSE;
return TRUE;
}
// Write the string to console
VOID
WriteOutput(
LPWSTR pszMsg,
DWORD nStdHandle
)
{
HANDLE hConsole = GetStdHandle( nStdHandle );
if ( !pszMsg || !*pszMsg )
return;
DWORD dwStrLen = lstrlenW( pszMsg );
LPSTR pszAMsg = NULL;
DWORD dwBytesWritten = 0;
DWORD dwMode = 0;
if ( (GetFileType ( hConsole ) & FILE_TYPE_CHAR ) &&
GetConsoleMode( hConsole, &dwMode ) )
{
WriteConsoleW( hConsole, pszMsg, dwStrLen, &dwBytesWritten, 0 );
return;
}
// console redirect to a file.
if ( !(pszAMsg = (LPSTR)LocalAlloc(LMEM_FIXED, (dwStrLen + 1) * sizeof(WCHAR) ) ) )
{
return;
}
if (WideCharToMultiByte(GetConsoleOutputCP(),
0,
pszMsg,
-1,
pszAMsg,
dwStrLen * sizeof(WCHAR),
NULL,
NULL) != 0
&& hConsole)
{
WriteFile( hConsole,
pszAMsg,
lstrlenA(pszAMsg),
&dwBytesWritten,
NULL );
}
LocalFree( pszAMsg );
}
// Write the string to stdout
VOID
WriteToConsole(
LPWSTR pszMsg
)
{
WriteOutput(pszMsg, STD_OUTPUT_HANDLE);
}
// Write the string to stderr
VOID
WriteToError(
LPWSTR pszMsg
)
{
WriteOutput(pszMsg, STD_ERROR_HANDLE);
}
// Report error.
VOID
report_error(
DWORD error_code,
LPCWSTR szComputer
)
{
LPVOID msgBuf = 0;
LPWSTR szBuf = NULL;
int len = 0;
if (error_code == 997 || error_code == 0)
return;
if (error_code == ERROR_NOT_READY)
{
ERROR_WITH_SZ(IDS_ERROR_NOT_READY, szComputer, error_code);
return;
}
else if (error_code == ERROR_BAD_NETPATH || error_code == WSAHOST_NOT_FOUND)
{
ERROR_WITH_SZ(IDS_ERROR_NOT_AVAILABLE, szComputer, error_code);
return;
}
else
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error_code,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
reinterpret_cast< wchar_t* >( &msgBuf ),
0,
NULL);
if (msgBuf)
{
// remove end newline.
len = wcslen(reinterpret_cast< wchar_t* >( msgBuf ));
reinterpret_cast< wchar_t* >( msgBuf )[len - 2] = L'\0';
if (szComputer && wcslen(szComputer) > 0)
{
LPWSTR szBuf1 = (LPWSTR)LocalAlloc(LMEM_FIXED,
(len + wcslen(szComputer) + 20) * sizeof(WCHAR));
if (szBuf1)
{
wsprintf(szBuf1, L"%s: %s(%d)\n", szComputer, reinterpret_cast< wchar_t* >( msgBuf ), error_code);
WriteToError(szBuf1);
LocalFree(szBuf1);
}
}
else
{
LPWSTR szBuf1 = (LPWSTR)LocalAlloc(LMEM_FIXED,
(len + 20) * sizeof(WCHAR));
if (szBuf1)
{
wsprintf(szBuf1, L"%s(%d)\n", reinterpret_cast< wchar_t* >( msgBuf ), error_code);
WriteToError(szBuf1);
LocalFree(szBuf1);
}
}
LocalFree( msgBuf );
}
}
BOOL
parse_reason_code(
LPCWSTR arg,
LPDWORD lpdwReason
)
{
// Code consists of flags;major;minor
// Qingboz: Now we make major and minor code mandatory
//
BOOL fMajor = FALSE;
BOOL fMinor = FALSE;
BOOL fUserDefined = FALSE;
int major = 0;
int minor = 0;
const int state_start = 0;
const int state_flags = 0;
const int state_major = 1;
const int state_minor = 2;
const int state_null = 3;
const int state_done = 4;
for( int i = 0, state = state_start; state != state_done; ++i )
{
switch( state )
{
case state_flags :
// Expecting flags
switch( arg[ i ] ) {
case L'U' : case L'u' :
if(fUserDefined)
{
//
// Already set.
//
return FALSE;
}
fUserDefined = TRUE;
break;
case L'P' : case L'p' :
if(*lpdwReason & 0x80000000)
{
//
// Already set.
//
return FALSE;
}
*lpdwReason |= 0x80000000; // SHTDN_REASON_FLAG_PLANNED
break;
case L':' :
if(i == 0) // ':' cannot be the first one now.
return FALSE;
state = state_major;
break;
case L'0':
case L'1':
case L'2':
case L'3':
case L'4':
case L'5':
case L'6':
case L'7':
case L'8':
case L'9':
if(i != 0) // A number here must be the first one.
return FALSE;
state = state_major;
i--; // Go back one.
break;
default :
return FALSE;
}
break;
case state_major :
// Expecting major
if( arg[ i ] >= L'0' && arg[ i ] <= L'9' ) {
fMajor = TRUE;
major = major * 10 + arg[ i ] - L'0';
}
else {
if(!fMajor)
return FALSE;
// Make sure we only have 8 bits
if( major > 0xff ) return FALSE;
if (major >= 64)
*lpdwReason |= SHTDN_REASON_FLAG_USER_DEFINED;
*lpdwReason |= major << 16;
if( arg[ i ] != L':') {
// missing minor reason.
return FALSE;
}
state = state_minor;
}
break;
case state_minor :
// Expecting minor reason
if( arg[ i ] >= L'0' && arg[ i ] <= L'9' ) {
fMinor = TRUE;
minor = minor * 10 + arg[ i ] - L'0';
}
else {
if(!fMinor)
return FALSE;
// Make sure we only have 16 bits
if( minor > 0xffff ) return FALSE;
*lpdwReason = ( *lpdwReason & 0xffff0000 ) | minor;
if( arg[ i ] != 0 )
return FALSE;
return TRUE;
}
break;
default :
return FALSE;
}
}
return FALSE;
}
// Parses an integer if it is in decimal notation.
// Returns FALSE if it is malformed.
BOOL
parse_int(
const wchar_t* arg,
LPDWORD lpdwInt
)
{
*lpdwInt = 0;
while( *arg ) {
if( *arg >= L'0' && *arg <= L'9' ) {
*lpdwInt = *lpdwInt * 10 + int( *arg++ - L'0' );
}
else {
return FALSE;
}
}
return TRUE;
}
// Parse options.
// Returns FALSE if the option strings are malformed. This causes the usage to be printed.
BOOL
parse_options(
int argc,
wchar_t *argv[],
LPBOOL lpfLogoff,
LPBOOL lpfForce,
LPBOOL lpfReboot,
LPBOOL lpfHibernate,
LPBOOL lpfAbort,
LPBOOL lpfPoweroff,
LPBOOL lpfAnnotate,
LPWSTR *ppServerName,
LPWSTR *ppMessage,
LPDWORD lpdwTimeout,
LPDWORD lpdwReason
)
{
BOOL fShutdown = FALSE;
BOOL fTimeout = FALSE;
BOOL fComment = FALSE;
BOOL fMachine = FALSE;
BOOL fReason = FALSE;
DWORD dwOption = 0;
DWORD dwFlag = 0;
*lpfLogoff = FALSE;
*lpfForce = FALSE;
*lpfReboot = FALSE;
*lpfHibernate = FALSE;
*lpfAbort = FALSE;
*lpfPoweroff = FALSE;
*lpfAnnotate = FALSE;
*ppServerName = NULL;
*ppMessage = NULL;
*lpdwTimeout = DEFAULT_TIMEOUT;
*lpdwReason = 0xff;
//
// Set default reason to be planned
//
*lpdwReason |= SHTDN_REASON_FLAG_PLANNED;
for( int i = 1; i < argc; ++i )
{
wchar_t* arg = argv[ i ];
switch( arg[ 0 ] )
{
case L'/' : case L'-' :
switch( arg[ 1 ] )
{
case L'L' : case L'l' :
if (*lpfLogoff)
return FALSE;
*lpfLogoff = TRUE;
if (arg[2] != 0) return FALSE;
dwOption++;
break;
case L'S' : case L's' :
//
// Use server name if supplied (i.e. do nothing here)
//
if(fShutdown)
return FALSE;
fShutdown = TRUE;
if( arg[ 2 ] != 0 ) return FALSE;
dwOption++;
break;
case L'F' : case L'f' :
if (*lpfForce)
return FALSE;
*lpfForce = TRUE;
if( arg[ 2 ] != 0 ) return FALSE;
break;
case L'H' : case L'h' :
if (*lpfHibernate)
return FALSE;
*lpfHibernate = TRUE;
if( arg[ 2 ] != 0 ) return FALSE;
dwOption++;
break;
case L'R' : case L'r' :
if (*lpfReboot)
return FALSE;
*lpfReboot = TRUE;
if( arg[ 2 ] != 0 ) return FALSE;
dwOption++;
break;
case L'A' : case L'a' :
if (*lpfAbort)
return FALSE;
*lpfAbort = TRUE;
if( arg[ 2 ] != 0 ) return FALSE;
dwOption++;
break;
case L'P' : case L'p' :
if (*lpfPoweroff)
return FALSE;
*lpfPoweroff = TRUE;
if( arg[ 2 ] != 0 ) return FALSE;
dwOption++;
break;
case L'E' : case L'e' :
if (*lpfAnnotate)
return FALSE;
*lpfAnnotate = TRUE;
if( arg[ 2 ] != 0 ) return FALSE;
dwOption++;
break;
case L'T' : case L't' :
//
// Next arg should be number of seconds
//
if(fTimeout) // Already did.
{
return FALSE;
}
if (++i == argc)
{
return FALSE;
}
arg = argv[i];
if( arg[ 0 ] < L'0' || arg[ 0 ] > L'9' ) return FALSE;
if( !parse_int( arg, lpdwTimeout )) return FALSE;
if(*lpdwTimeout > MAX_TIMEOUT)
return FALSE;
fTimeout = TRUE;
break;
case L'Y' : case L'y' :
// Ignore this option.
break;
case L'D' : case L'd' :
//
// Next arg should be reason code
//
if (fReason)
return FALSE;
if (++i == argc)
{
return FALSE;
}
arg = argv[i];
//
//If reason code is given, we clear the planned bit.
//
*lpdwReason = (DWORD)0xFF;
if( !parse_reason_code( arg, lpdwReason ))
{
return FALSE;
}
fReason = TRUE;
break;
case L'C' : case L'c' :
//
// Next arg should be shutdown message. Make
// sure only one is specified.
//
if (fComment)
return FALSE;
if (++i == argc || *ppMessage)
{
return FALSE;
}
arg = argv[i];
if(wcslen(arg) > MAX_REASON_COMMENT_LEN - 1 || wcslen(arg) <= MINCOMMENTLEN)
return FALSE;
*ppMessage = arg;
fComment = TRUE;
break;
case L'M' : case L'm' :
//
// Next arg should be machine name. Make
// sure only one is specified.
//
if (fMachine)
return FALSE;
if (++i == argc || *ppServerName)
{
return FALSE;
}
arg = argv[i];
if (arg[0] == L'\\' && arg[1] == L'\\')
{
*ppServerName = arg + 2;
}
else
{
*ppServerName = arg;
}
fMachine = TRUE;
break;
case L'?' : default :
return FALSE;
}
break;
default :
//
// Junk
//
return FALSE;
}
}
//
// Check for mutually exclusive options
//
if (dwOption > 1)
return FALSE;
//
// Default is to logoff
//
if (dwOption == 0)
{
*lpfLogoff = TRUE;
}
//
// Only -f can go with -l
//
if (*lpfLogoff && (fTimeout || fReason || fComment || fMachine))
return FALSE;
//
// -a can only take -m
//
if (*lpfAbort && (fTimeout || fReason || *lpfForce || fComment))
return FALSE;
//
// -h only with -f
//
if (*lpfHibernate && (fTimeout || fReason || fComment || fMachine))
return FALSE;
//
// -p can only take -d
//
if (*lpfPoweroff && (fTimeout || *lpfForce || fComment || fMachine))
return FALSE;
//
// -e must have -d.
//
if (*lpfAnnotate)
{
if (*lpfForce || fTimeout)
return FALSE;
if (! fReason)
return FALSE;
}
//
// Shutdown and reboot the same, comment must require a reason.
// Removed upon request.
//
#if 0
if (fShutdown || *lpfReboot)
{
if (fComment && !fReason)
return FALSE;
}
#endif
//
// Add the clean or dirty flag.
//
if (*lpfAnnotate)
*lpdwReason |= SHTDN_REASON_FLAG_DIRTY_UI;
else
*lpdwReason |= SHTDN_REASON_FLAG_CLEAN_UI;
return TRUE;
}
// Print out usage help string.
VOID
usage(
VOID
)
{
HMODULE hModule = GetModuleHandle( NULL );
HMODULE hUser32;
REASONBUILDPROC buildProc;
REASONDESTROYPROC DestroyProc;
WCHAR lpReasonName[MAX_PATH];
REASONDATA Reasons;
if( hModule == NULL )
{
report_error( GetLastError(), NULL);
return;
}
for (DWORD i = IDS_USAGE0; i < IDS_USAGE_END; i++)
{
WCHAR *szBuf = LoadWString(i);
if(!szBuf)
continue;
if (i == IDS_USAGE0)
{
LPWSTR msg = (LPWSTR) LocalAlloc(LMEM_FIXED, (lstrlenW(szBuf) + lstrlenW( g_lpszProgramName ) + 2) * sizeof(WCHAR));
if(!msg)
{
LocalFree(szBuf);
report_error( GetLastError(), NULL);
return;
}
swprintf(msg, szBuf, g_lpszProgramName );
WriteToConsole( msg );
LocalFree(msg);
}
else
{
WriteToConsole( szBuf );
}
LocalFree(szBuf);
}
//
// Now print out the reasons.
//
WCHAR szCode[MAX_PATH];
WCHAR *szTitle = LoadWString(IDS_REASONLISTTITLE);
if(szTitle)
{
WriteToConsole(szTitle);
LocalFree(szTitle);
}
for (int iOption = 0; iOption < (int)g_reasons.m_cReasons; iOption++)
{
WriteToConsole(L"\n");
if(g_reasons.m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_CLEAN_UI)
WriteToConsole(L"E");
else
WriteToConsole(L" ");
if(g_reasons.m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_DIRTY_UI)
WriteToConsole(L"U");
else
WriteToConsole(L" ");
if(g_reasons.m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_PLANNED)
WriteToConsole(L"P");
else
WriteToConsole(L" ");
if(g_reasons.m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_USER_DEFINED)
WriteToConsole(L"C");
else
WriteToConsole(L" ");
swprintf(szCode, L"\t%d\t%d\t", (g_reasons.m_lpReasons[iOption].dwCode & 0x00ff0000)>>16,
g_reasons.m_lpReasons[iOption].dwCode & 0x0000ffff);
WriteToConsole(szCode);
WriteToConsole(g_reasons.m_lpReasons[iOption].lpName);
}
if(iOption)
WriteToConsole(L"\n");
}
// We need shutdown privileges enabled to be able to shut down our machines.
BOOL
enable_privileges(
LPCWSTR lpServerName,
BOOL fLogoff
)
{
NTSTATUS Status = STATUS_SUCCESS;
NTSTATUS Status1 = STATUS_SUCCESS;
BOOLEAN fWasEnabled;
if (fLogoff)
{
//
// No privileges to get
//
return TRUE;
}
//
// We will always enable both privileges so
// it can work for telnet sessions.
//
Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
TRUE,
FALSE,
&fWasEnabled);
Status1 = RtlAdjustPrivilege(SE_REMOTE_SHUTDOWN_PRIVILEGE,
TRUE,
FALSE,
&fWasEnabled);
return TRUE;
}
BOOL
PowerOptionEnabled(
UINT option
)
// --------------------------------------------------------------------------
// PowerOptionEnabled
//
// Arguments: option
//
// Returns: TRUE indicates the option is enabled.
//
// Purpose: Detects if the specified power option is enabled on the system.
//
// --------------------------------------------------------------------------
{
NTSTATUS status;
SYSTEM_POWER_CAPABILITIES spc;
BOOL RetVal = FALSE;
status = NtPowerInformation(SystemPowerCapabilities,
NULL,
0,
&spc,
sizeof(spc));
switch (option)
{
case POWER_OPTION_HIBERNATE:
if (NT_SUCCESS(status) && spc.HiberFilePresent){
RetVal = TRUE;
}
break;
case POWER_OPTION_POWEROFF:
if (NT_SUCCESS(status) && spc.SystemS5){
RetVal = TRUE;
}
break;
default:
break;
}
return(RetVal);
}
BOOL WINAPI ConsoleHandlerRoutine(
DWORD dwCtrlType
)
// --------------------------------------------------------------------------
//
// Ignore the Ctrl-C and Ctrl-Break.
//
// Arguments: type of the control signal
//
// Returns: TRUE if the function handles the control.
// if return FALSE, the next handler function in the list is used.
//
// --------------------------------------------------------------------------
{
if ( dwCtrlType == CTRL_BREAK_EVENT ||
dwCtrlType == CTRL_C_EVENT )
return TRUE;
return FALSE;
}
int __cdecl
wmain(
int argc,
wchar_t *argv[]
)
{
BOOL fLogoff;
BOOL fForce;
BOOL fReboot;
BOOL fAbort;
BOOL fPoweroff;
BOOL fAnnotate;
BOOL fHibernate;
LPWSTR lpServerName;
LPWSTR lpMessage;
DWORD dwTimeout;
DWORD dwReason = 0;
DWORD dwRet = 0;
INT_PTR hResult;
NTSTATUS Status;
WCHAR szComment[MAX_REASON_COMMENT_LEN];
HINSTANCE hInstance;
//
// ignore any control-c / control-break
//
SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE);
if ( (hInstance = LoadLibrary( L"kernel32.dll" ) ) )
{
PSetThreadUILanguage SetThreadUILang = (PSetThreadUILanguage)GetProcAddress( hInstance, "SetThreadUILanguage" );
if ( SetThreadUILang )
(*SetThreadUILang)( 0 );
FreeLibrary( hInstance );
}
if(!GetEnvironmentVariableW(L"COMPUTERNAME", g_lpszLocalComputerName, MAX_PATH))
{
report_error(GetLastError(), NULL);
return 1;
}
g_hDllInstance = GetModuleHandle(NULL);
if (!g_hDllInstance)
{
report_error(GetLastError(), g_lpszLocalComputerName);
return 1;
}
// We use the program name for reporting errors.
g_lpszProgramName = argv[ 0 ];
//
// Userdomain is used as the default domain.
//
if(!GetEnvironmentVariableW(L"USERDOMAIN", g_lpszDefaultDomain, MAX_PATH))
{
report_error(GetLastError(), g_lpszLocalComputerName);
return 1;
}
//
// if there is no arguments, we will display help.
//
if(argc == 1)
{
usage();
return 0;
}
//
// If the first argument is -i or /i, we pop up UI.
//
if(wcsncmp(argv[1], L"-i", 2) == 0 || wcsncmp(argv[1], L"/i", 2) == 0
|| wcsncmp(argv[1], L"-I", 2) == 0 || wcsncmp(argv[1], L"/I", 2) == 0)
{
if(g_hDllInstance)
{
ShutdownHelp shutdownHelp;
int len = GetEnvironmentVariableW(L"SystemRoot", g_lpszHelpdir, 0);
if(len)
{
g_lpszHelpdir = new WCHAR[len + 6];
if(g_lpszHelpdir)
{
GetEnvironmentVariableW(L"SystemRoot", g_lpszHelpdir, len+6);
wcscat(g_lpszHelpdir, L"\\");
wcscat(g_lpszHelpdir, L"Help\\");
}
else
{
dwRet = ERROR_OUTOFMEMORY;
goto exit;
}
g_lpszHelpdirHlp = new WCHAR[wcslen(g_lpszHelpdir) + wcslen(HELP_FILE) + 1];
if (g_lpszHelpdirHlp)
{
wcscpy(g_lpszHelpdirHlp, g_lpszHelpdir);
wcscat(g_lpszHelpdirHlp, HELP_FILE);
}
else
{
dwRet = ERROR_OUTOFMEMORY;
goto exit;
}
g_lpszHelpdirChm = new WCHAR[wcslen(g_lpszHelpdir) + wcslen(CHM_FILE) + wcslen(CHM_MAIN) + 1];
if (g_lpszHelpdirChm)
{
wcscpy(g_lpszHelpdirChm, g_lpszHelpdir);
wcscat(g_lpszHelpdirChm, CHM_FILE);
wcscat(g_lpszHelpdirChm, CHM_MAIN);
}
else
{
dwRet = ERROR_OUTOFMEMORY;
goto exit;
}
g_lpszHelpdirWindows = new WCHAR[wcslen(g_lpszHelpdir) + wcslen(WINDOWS_HELP) + 1];
if (g_lpszHelpdirWindows)
{
wcscpy(g_lpszHelpdirWindows, g_lpszHelpdir);
wcscat(g_lpszHelpdirWindows, WINDOWS_HELP);
}
else
{
dwRet = ERROR_OUTOFMEMORY;
goto exit;
}
}
hResult = DialogBoxParam(g_hDllInstance, MAKEINTRESOURCE(IDD_DIALOGSHUTDOWN), NULL, Shutdown_DialogProc, NULL);
dwRet = (DWORD)HRESULTTOWIN32(hResult);
exit:
if(g_lpszHelpdir)
delete [] g_lpszHelpdir;
if(g_lpszHelpdirHlp)
delete [] g_lpszHelpdirHlp;
if(g_lpszHelpdirChm)
delete [] g_lpszHelpdirChm;
if(g_lpszHelpdirWindows)
delete [] g_lpszHelpdirWindows;
if (dwRet != 0)
report_error(dwRet, NULL);
WinHelpW((HWND)0, NULL, HELP_QUIT, 0) ;
}
return dwRet;
}
// Parse the options.
if( !parse_options( argc,
argv,
&fLogoff,
&fForce,
&fReboot,
&fHibernate,
&fAbort,
&fPoweroff,
&fAnnotate,
&lpServerName,
&lpMessage,
&dwTimeout,
&dwReason ))
{
usage();
return 1;
}
//
// Add the comment field for the reason.
//
if (g_reasons.RequireComment(dwReason, fAnnotate))
{
if (fAnnotate)
dwReason |= SHTDN_REASON_FLAG_DIRTY_PROBLEM_ID_REQUIRED;
else
dwReason |= SHTDN_REASON_FLAG_COMMENT_REQUIRED;
}
//
// Promote (no more)for comment if it is required and not given
//
if (g_reasons.RequireComment(dwReason, fAnnotate) && (!lpMessage || wcslen(lpMessage) == 0))
{
lpMessage = NULL;
}
// Get all privileges so that we can shutdown the machine.
enable_privileges( lpServerName, fLogoff );
// Do the work.
if( fAbort )
{
if( !AbortSystemShutdownW( lpServerName ))
{
dwRet = GetLastError();
report_error( dwRet, lpServerName);
}
}
else if (fLogoff)
{
if (!ExitWindowsEx(fForce ? (EWX_LOGOFF | EWX_FORCE) : (EWX_LOGOFF | EWX_FORCEIFHUNG),
0))
{
dwRet = GetLastError();
report_error( dwRet, g_lpszLocalComputerName);
}
}
else if (fHibernate)
{
if (!PowerOptionEnabled(POWER_OPTION_HIBERNATE))
{
ERROR_WITH_SZ(IDS_ERR_HIBERNATE_NOT_ENABLED, lpServerName, GetLastError());
}
else
{
Status = NtInitiatePowerAction(
PowerActionHibernate,
PowerSystemSleeping1,
fForce
? POWER_ACTION_CRITICAL
: POWER_ACTION_QUERY_ALLOWED,
FALSE);
if (!NT_SUCCESS(Status))
{
dwRet = RtlNtStatusToDosError(Status);
report_error( dwRet, lpServerName);
}
}
}
else if (fPoweroff)
{
//
// Special case, we call ExitWindowsEx
// Check whether power off is supported, if not just shutdown the machine.
// Although we fixed ExitWindowsEx, but we will leave this so it will work
// with older builds.
//
if(PowerOptionEnabled(POWER_OPTION_POWEROFF))
{
if (!ExitWindowsEx(EWX_POWEROFF, dwReason))
{
dwRet = GetLastError();
report_error( dwRet, lpServerName);
}
}
else
{
if (!ExitWindowsEx(EWX_SHUTDOWN, dwReason))
{
dwRet = GetLastError();
report_error( dwRet, lpServerName);
}
}
}
else if (fAnnotate)
{
//
// Annotate dirty shutdown.
//
Annotate(lpServerName, &dwReason, lpMessage, &dwRet);
}
else
{
// Do the normal form.
if( !InitiateSystemShutdownExW( lpServerName,
lpMessage,
dwTimeout,
fForce,
fReboot,
dwReason ))
{
dwRet = GetLastError();
report_error( dwRet, lpServerName);
}
}
return dwRet;
}
//
// Get computername from ADSI path
// Here we only handle WinNT, LDAP, NWCOMPAT, and NDS.
//
BOOL GetComputerNameFromPath(LPWSTR szPath, LPWSTR szName)
{
static _PROVIDER p[] =
{
{L"LDAP://", 7},
{L"WinNT://", 8},
{L"NWCOMPAT://", 11},
{L"NDS://", 6}
};
static UINT np = sizeof(p)/sizeof(_PROVIDER);
LPWSTR lpsz = NULL;
if(!szPath || !szName)
return FALSE;
for(UINT i = 0; i < np; i++)
{
if(wcsncmp(szPath, p[i].szName, p[i].dwLen) == 0)
{
switch(i)
{
case 0: // LDAP
lpsz = wcsstr(szPath, L"CN=");
if(!lpsz)
return FALSE;
lpsz += 3;
while(*lpsz && *lpsz != ',')
*szName++ = *lpsz++;
*szName = 0;
return TRUE;
case 1: // WinNT
case 2: // NWCOMPAT
lpsz = szPath + p[i].dwLen;
//
// skip domain or provider path
//
while(*lpsz && *lpsz != '/')
lpsz++;
lpsz++;
while(*lpsz && *lpsz != '/')
*szName++ = *lpsz++;
*szName = 0;
return TRUE;
case 3: // NDS
lpsz = wcsstr(szPath, L"CN=");
if(!lpsz)
return FALSE;
lpsz += 3;
while(*lpsz && *lpsz != '/')
*szName++ = *lpsz++;
*szName = 0;
return TRUE;
default:
return FALSE;
}
}
}
return FALSE;
}
//
// A centralized place for adjusting window states.
//
VOID AdjustWindowState()
{
if(g_dwActionSelect == ACTION_SHUTDOWN || g_dwActionSelect == ACTION_RESTART || g_dwActionSelect == ACTION_ANNOTATE)
{
if (g_dwActionSelect == ACTION_ANNOTATE)
{
EnableWindow(g_wins.hwndButtonWarning, FALSE);
EnableWindow(g_wins.hwndEditTimeout, FALSE);
}
else
{
EnableWindow(g_wins.hwndButtonWarning, TRUE);
if (IsDlgButtonChecked(g_wins.hwndShutdownDialog, IDC_CHECKWARNING) == BST_CHECKED)
EnableWindow(g_wins.hwndEditTimeout, TRUE);
else
EnableWindow(g_wins.hwndEditTimeout, FALSE);
}
EnableWindow(g_wins.hwndEditComment, TRUE);
if(g_bAssumeShutdown)
{
EnableWindow(g_wins.hwndComboOption, FALSE);
EnableWindow(g_wins.hwndChkPlanned, FALSE);
EnableWindow(g_wins.hwndButtonOK, TRUE);
}
else
{
EnableWindow(g_wins.hwndComboOption, TRUE);
EnableWindow(g_wins.hwndChkPlanned, TRUE);
if((g_reasons.m_dwReasonSelect != -1)
&& g_reasons.RequireComment(g_reasons.m_lpReasons[g_reasons.m_dwReasonSelect].dwCode, g_dwActionSelect == ACTION_ANNOTATE))
{
LPWSTR szStaticComment = LoadWString(IDS_COMMENT_REQUIRED);
if(szStaticComment)
{
SetWindowTextW(g_wins.hwndStaticComment, szStaticComment);
LocalFree(szStaticComment);
}
if(Edit_GetTextLength(g_wins.hwndEditComment) > MINCOMMENTLEN
&& ListBox_GetCount(g_wins.hwndListSelectComputers) > 0)
EnableWindow(g_wins.hwndButtonOK, TRUE);
else
EnableWindow(g_wins.hwndButtonOK, FALSE);
}
else
{
LPWSTR szStaticComment = LoadWString(IDS_COMMENT_OPTIONAL);
if(szStaticComment)
{
SetWindowTextW(g_wins.hwndStaticComment, szStaticComment);
LocalFree(szStaticComment);
}
if (g_reasons.m_dwReasonSelect == -1)
EnableWindow(g_wins.hwndComboOption, FALSE);
if(ListBox_GetCount(g_wins.hwndListSelectComputers) > 0)
EnableWindow(g_wins.hwndButtonOK, TRUE);
else
EnableWindow(g_wins.hwndButtonOK, FALSE);
}
}
EnableWindow(g_wins.hwndBtnAdd, TRUE);
EnableWindow(g_wins.hwndBtnBrowse, TRUE);
{
int cItems = 1024;
int lpItems[1024];
int cActualItems;
//
// Get the number of selected items.
//
cActualItems = ListBox_GetSelItems(g_wins.hwndListSelectComputers, cItems, lpItems);
if(cActualItems > 0)
EnableWindow(g_wins.hwndBtnRemove, TRUE);
else
EnableWindow(g_wins.hwndBtnRemove, FALSE);
}
EnableWindow(g_wins.hwndListSelectComputers, TRUE);
}
else
{
EnableWindow(g_wins.hwndChkPlanned, FALSE);
EnableWindow(g_wins.hwndButtonWarning, FALSE);
EnableWindow(g_wins.hwndBtnAdd, FALSE);
EnableWindow(g_wins.hwndBtnBrowse, FALSE);
EnableWindow(g_wins.hwndBtnRemove, FALSE);
EnableWindow(g_wins.hwndComboOption, FALSE);
EnableWindow(g_wins.hwndEditComment, FALSE);
EnableWindow(g_wins.hwndEditTimeout, FALSE);
EnableWindow(g_wins.hwndListSelectComputers, FALSE);
EnableWindow(g_wins.hwndButtonOK, TRUE);
}
}
//
// Init dialog handler for the shutdown dialog.
//
BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
int i;
//
// Init all of the dialog items so we dont have to find
// them everytime we need them.
//
g_wins.hwndShutdownDialog = hwnd;
g_wins.hwndButtonWarning = GetDlgItem(hwnd, IDC_CHECKWARNING);
g_wins.hwndComboAction = GetDlgItem(hwnd, IDC_COMBOACTION);
g_wins.hwndComboOption = GetDlgItem(hwnd, IDC_COMBOOPTION);
g_wins.hwndEditComment = GetDlgItem(hwnd, IDC_EDITCOMMENT);
g_wins.hwndStaticDesc = GetDlgItem(hwnd, IDC_STATICDESCRIPTION);
g_wins.hwndEditTimeout = GetDlgItem(hwnd, IDC_EDITTIMEOUT);
g_wins.hwndListSelectComputers = GetDlgItem(hwnd, IDC_LISTSELECTEDCOMPUTERS);
g_wins.hwndBtnAdd = GetDlgItem(hwnd, IDC_BUTTONADDNEW);
g_wins.hwndBtnBrowse = GetDlgItem(hwnd, IDC_BUTTONBROWSE);
g_wins.hwndBtnRemove = GetDlgItem(hwnd, IDC_BUTTONREMOVE);
g_wins.hwndChkPlanned = GetDlgItem(hwnd, IDC_CHECK_PLANNED);
g_wins.hwndButtonOK = GetDlgItem(hwnd, IDOK);
g_wins.hwndStaticComment = GetDlgItem(hwnd, IDC_STATIC_COMMENT);
if(g_wins.hwndButtonWarning == NULL
|| g_wins.hwndComboAction == NULL
|| g_wins.hwndComboOption == NULL
|| g_wins.hwndEditComment == NULL
|| g_wins.hwndStaticDesc == NULL
|| g_wins.hwndEditTimeout == NULL
|| g_wins.hwndListSelectComputers == NULL
|| g_wins.hwndBtnAdd == NULL
|| g_wins.hwndBtnBrowse == NULL
|| g_wins.hwndBtnRemove == NULL
|| g_wins.hwndChkPlanned == NULL)
{
report_error( GetLastError( ), NULL);
EndDialog(hwnd, (int)-1);
return FALSE;
}
LoadString(g_hDllInstance, IDS_DIALOGTITLEWARNING, g_lpszTitleWarning, TITLEWARNINGLEN);
// Subclass the edit control.
wpOrigEditProc = (WNDPROC) SetWindowLongPtr(g_wins.hwndEditTimeout,
GWLP_WNDPROC, (LONG_PTR) EditSubclassProc);
// Limit timeout to 3 chars.
SendMessage(g_wins.hwndEditTimeout, EM_LIMITTEXT, (WPARAM)3, 0);
//
// Default timeout is set to 30 seconds.
//
Edit_SetText(g_wins.hwndEditTimeout, g_lpszDefaultTimeout);
if(! CheckDlgButton(hwnd, IDC_CHECKWARNING, DEFAULTWARNINGSTATE))
{
report_error( GetLastError( ), NULL);
EndDialog(hwnd, (int)-1);
return FALSE;
}
//
// The for loop will load all of the actions into action combo.
// in the meantime we save them for later use.
//
for(i = 0; i < g_nActions; i++)
{
LoadString(g_hDllInstance, g_dwActions[i], g_lppszActions[i], MAX_PATH - 1);
ComboBox_AddString(g_wins.hwndComboAction, g_lppszActions[i]);
if(g_dwActions[i] == IDS_ACTION_RESTART)
{
ComboBox_SelectString(g_wins.hwndComboAction, -1, g_lppszActions[i]);
g_dwActionSelect = ACTION_RESTART;
}
}
if(g_reasons.m_cReasons)
g_bAssumeShutdown = FALSE;
else
g_bAssumeShutdown = TRUE;
//
// Set the default to be planned.
//
CheckDlgButton(hwnd, IDC_CHECK_PLANNED, BST_CHECKED);
g_reasons.FillCombo(g_wins.hwndComboOption, g_bDirty,
IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED, g_wins.hwndStaticDesc);
//
// Setup the comment box.
// We must fix the maximum characters.
//
SendMessage( g_wins.hwndEditComment, EM_LIMITTEXT, (WPARAM)MAX_REASON_COMMENT_LEN-1, (LPARAM)0 );
AdjustWindowState();
return TRUE;
}
//
// Init dialog handler for browse dialog
//
BOOL Browse_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
HWND hwndDomain = NULL;
int cItems = 1024;
int lpItems[1024];
int cActualItems;
WCHAR lpDomain[MAX_PATH];
hwndDomain = GetDlgItem(hwnd, IDC_EDITDOMAIN);
if(!hwndDomain)
return FALSE;
Edit_SetText(hwndDomain, g_lpszDefaultDomain);;
return TRUE;
}
//
// winproc for shutdown dialog
//
INT_PTR CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hwnd, WM_INITDIALOG, Shutdown_OnInitDialog);
HANDLE_MSG(hwnd, WM_COMMAND, Shutdown_OnCommand);
case WM_SYSCOMMAND:
return (Shutdown_OnCommand(hwnd, (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L);
case WM_HELP: // F1
if(g_lpszHelpdirHlp)
{
LPHELPINFO phinfo = (LPHELPINFO) lParam;
DWORD dwHelpID = 0;
if (IsStaticControl((HWND)phinfo->hItemHandle))
return (TRUE);
for(int i = 0; i < sizeof(ShutdownDialogHelpIds)/sizeof(DWORD); i++)
{
if(ShutdownDialogHelpIds[i] == phinfo->iCtrlId)
{
dwHelpID = ShutdownDialogHelpIds[++i];
break;
}
i++;
}
if ( i == sizeof(ShutdownDialogHelpIds)/sizeof(DWORD))
return TRUE;
if (dwHelpID == 28443 || dwHelpID == 28444 || dwHelpID == 28445) // special case.
WinHelpW((HWND)phinfo->hItemHandle, g_lpszHelpdirWindows, HELP_CONTEXTPOPUP,dwHelpID);
else
WinHelpW((HWND)phinfo->hItemHandle, g_lpszHelpdirHlp, HELP_CONTEXTPOPUP,dwHelpID);
}
return (TRUE);
case WM_CONTEXTMENU: // right mouse click
if (IsStaticControl((HWND)wParam))
return (TRUE);
if(g_lpszHelpdirHlp)
WinHelpW((HWND)wParam, g_lpszHelpdirHlp, HELP_CONTEXTMENU,(DWORD_PTR)(LPSTR)&ShutdownDialogHelpIds[6]);
return (TRUE);
case WM_DESTROY:
// Remove the subclass from the edit control.
SetWindowLongPtr(g_wins.hwndEditTimeout, GWLP_WNDPROC,
(LONG_PTR)wpOrigEditProc);
//
// Continue the cleanup procedure.
//
break;
}
return FALSE;
}
//
// winproc for AddNew dialog
//
INT_PTR CALLBACK AddNew_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
HANDLE_MSG(hwnd, WM_COMMAND, AddNew_OnCommand);
case WM_HELP: // F1
if (GetDlgCtrlID((HWND)wParam) == IDC_STATIC)
return (TRUE);
if(g_lpszHelpdirHlp)
{
LPHELPINFO phinfo = (LPHELPINFO) lParam;
DWORD dwHelpID = 0;
if (IsStaticControl((HWND)phinfo->hItemHandle))
return (TRUE);
for(int i = 0; i < sizeof(AddNewDialogHelpIds)/sizeof(DWORD); i++)
{
if(AddNewDialogHelpIds[i] == phinfo->iCtrlId)
{
dwHelpID = AddNewDialogHelpIds[++i];
break;
}
i++;
}
if ( i == sizeof(AddNewDialogHelpIds)/sizeof(DWORD))
return TRUE;
if (dwHelpID == 28443 || dwHelpID == 28444 || dwHelpID == 28445) // special case.
WinHelpW((HWND)phinfo->hItemHandle, g_lpszHelpdirWindows, HELP_CONTEXTPOPUP,dwHelpID);
else
WinHelpW((HWND)phinfo->hItemHandle, g_lpszHelpdirHlp, HELP_CONTEXTPOPUP,dwHelpID);
}
return (TRUE);
case WM_CONTEXTMENU: // right mouse click
if (IsStaticControl((HWND)wParam))
return (TRUE);
if(g_lpszHelpdirHlp)
WinHelpW((HWND)wParam, g_lpszHelpdirHlp, HELP_CONTEXTMENU,(DWORD_PTR)(LPSTR)&AddNewDialogHelpIds[4]);
return (TRUE);
}
return FALSE;
}
//
// Command handler for the shutdown dialog.
//
BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
BOOL fHandled = FALSE;
DWORD dwDlgResult = 0;
HINSTANCE h;
switch (id)
{
case IDCANCEL:
if (codeNotify == BN_CLICKED)
{
EndDialog(hwnd, (int) dwDlgResult);
}
fHandled = TRUE;
break;
case SC_CLOSE:
EndDialog(hwnd, (int) dwDlgResult);
fHandled = TRUE;
break;
case IDC_BUTTONREMOVE:
if (codeNotify == BN_CLICKED)
{
int cItems = 1024;
int lpItems[1024];
int cActualItems;
WCHAR lpServerName[MAX_PATH];
//
// Get the number of selected items. If there is any remove them one by one.
//
cActualItems = ListBox_GetSelItems(g_wins.hwndListSelectComputers, cItems, lpItems);
if(cActualItems > 0)
{
int i;
for(i = cActualItems-1; i >= 0; i--)
{
ListBox_DeleteString(g_wins.hwndListSelectComputers, lpItems[i]);
}
AdjustWindowState();
SetFocus(g_wins.hwndListSelectComputers);
}
fHandled = TRUE;
}
break;
case IDC_CHECK_PLANNED:
if (codeNotify == BN_CLICKED)
{
int iOption;
int iFirst = -1;
DWORD dwCheckState = 0x0;
//
// Get check button state.
//
if (IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED)
dwCheckState = SHTDN_REASON_FLAG_PLANNED;
g_reasons.FillCombo(g_wins.hwndComboOption, g_bDirty,
IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED, g_wins.hwndStaticDesc);
AdjustWindowState();
fHandled = TRUE;
}
break;
case IDC_EDITCOMMENT:
if( codeNotify == EN_CHANGE)
{
if(g_bAssumeShutdown)
{
EnableWindow(g_wins.hwndButtonOK, TRUE);
}
else if(g_reasons.m_dwReasonSelect != -1 &&
(g_reasons.m_lpReasons[g_reasons.m_dwReasonSelect].dwCode & SHTDN_REASON_FLAG_COMMENT_REQUIRED))
{
if(Edit_GetTextLength(g_wins.hwndEditComment) > MINCOMMENTLEN
&& ListBox_GetCount(g_wins.hwndListSelectComputers) > 0)
EnableWindow(g_wins.hwndButtonOK, TRUE);
else
EnableWindow(g_wins.hwndButtonOK, FALSE);
}
else
{
if(ListBox_GetCount(g_wins.hwndListSelectComputers) > 0)
EnableWindow(g_wins.hwndButtonOK, TRUE);
else
EnableWindow(g_wins.hwndButtonOK, FALSE);
}
fHandled = TRUE;
}
break;
case IDC_EDITTIMEOUT:
if( codeNotify == EN_KILLFOCUS)
{
WCHAR szTimeout[8];
int len = GetWindowTextW(g_wins.hwndEditTimeout, szTimeout, 7);
fHandled = TRUE;
if (_wtoi(szTimeout) > MAX_TIMEOUT)
SetWindowTextW(g_wins.hwndEditTimeout, g_lpszMaxTimeout);
}
break;
case IDC_BUTTONADDNEW:
if (codeNotify == BN_CLICKED)
{
WCHAR lpServerName[MAX_PATH];
LPWSTR lpBuffer;
DWORD dwIndex = 0;
INT_PTR hResult;
//
// Will pop up the addnew dialog. User can type in computer names seperated
// by white space. After click on OK, we will parse the computer names and
// add them to the selected computer list. No duplicates will be added.
//
hResult = DialogBoxParam(g_hDllInstance, MAKEINTRESOURCE(IDD_DIALOG_ADDNEW), hwnd, AddNew_DialogProc, NULL);
if(g_lpszNewComputers)
{
lpBuffer = g_lpszNewComputers;
while(*lpBuffer)
{
lpServerName[dwIndex] = '\0';
while(*lpBuffer && *lpBuffer != '\t' && *lpBuffer != '\n' && *lpBuffer != '\r' && *lpBuffer != ' ')
lpServerName[dwIndex++] = *lpBuffer++;
lpServerName[dwIndex] = '\0';
if(dwIndex > 0 && LB_ERR == ListBox_FindStringExact(g_wins.hwndListSelectComputers, -1, lpServerName))
ListBox_AddString(g_wins.hwndListSelectComputers, lpServerName);
dwIndex = 0;
while(*lpBuffer && (*lpBuffer == '\t' || *lpBuffer == '\n' || *lpBuffer == '\r' || *lpBuffer == ' '))
lpBuffer++;
}
AdjustWindowState();
LocalFree((HLOCAL)g_lpszNewComputers);
g_lpszNewComputers = NULL;
}
fHandled = TRUE;
}
break;
case IDOK:
//
// Here we gather all of the information and do the action.
//
if (codeNotify == BN_CLICKED)
{
int cItems = 1024;
int lpItems[1024];
int cActualItems;
BOOL fLogoff = FALSE;
BOOL fAbort = FALSE;
BOOL fForce = FALSE;
BOOL fReboot = FALSE;
BOOL fDisconnect = FALSE;
BOOL fStandby = FALSE;
BOOL fAnnotate = FALSE;
DWORD dwTimeout = 0;
DWORD dwReasonCode = 0;
WCHAR lpServerName[MAX_PATH];
WCHAR lpMsg[MAX_REASON_COMMENT_LEN] = L"";
DWORD dwCnt = 0;
DWORD dwActionCode = g_dwActionSelect;
WCHAR lpNotSupported[MAX_PATH];
WCHAR lpRes[MAX_PATH * 2];
WCHAR lpFailed[MAX_PATH];
WCHAR lpSuccess[MAX_PATH];
//
// The default reason code is 0 and default comment is L"".
//
if(IsDlgButtonChecked(hwnd, IDC_CHECKWARNING))
{
fForce = FALSE;
lpServerName[0] = '\0';
GetWindowText(g_wins.hwndEditTimeout, lpServerName, MAX_PATH);
if(lstrlen(lpServerName) == 0)
dwTimeout = 0;
else dwTimeout = _wtoi(lpServerName);
if(dwTimeout > MAX_TIMEOUT)
dwTimeout = MAX_TIMEOUT;
}
else
{
fForce = TRUE;
}
LoadString(g_hDllInstance, IDS_ACTIONNOTSUPPORTED, lpNotSupported, MAX_PATH);
GetWindowText(g_wins.hwndEditComment, lpMsg, MAX_REASON_COMMENT_LEN);
lpMsg[MAX_REASON_COMMENT_LEN-1] = 0;
if(dwActionCode == ACTION_LOGOFF)
{
fLogoff = TRUE;
}
else if (dwActionCode == ACTION_RESTART)
{
fReboot = TRUE;
}
else if (dwActionCode == ACTION_ANNOTATE)
fAnnotate = TRUE;
//
// Logoff is only for the local computer.
// Everything else will ingored.
//
if(fLogoff)
{
if (!ExitWindowsEx(fForce ? EWX_LOGOFF : (EWX_LOGOFF | EWX_FORCE),
0))
{
report_error(GetLastError(), g_lpszLocalComputerName);
}
EndDialog(hwnd, (int) dwDlgResult);
break;
}
if(! g_bAssumeShutdown)
{
dwReasonCode = g_reasons.m_lpReasons[g_reasons.m_dwReasonSelect].dwCode;
}
else if (fAnnotate)
break;
dwCnt = ListBox_GetCount(g_wins.hwndListSelectComputers);
if(dwCnt > 0)
{
DWORD i;
for(i = 0; i < dwCnt; i++)
{
ListBox_GetText(g_wins.hwndListSelectComputers, i, lpServerName);
//
// Get all privileges so that we can shutdown the machine.
//
enable_privileges(lpServerName, fLogoff);
//
// Do the work.
//
if( fAbort )
{
if( !AbortSystemShutdown( lpServerName ))
{
report_error( GetLastError( ), lpServerName);
}
}
else if (fAnnotate)
{
DWORD err;
Annotate(lpServerName, &dwReasonCode, lpMsg, &err);
}
else
{
//
// Do the normal form.
//
if( !InitiateSystemShutdownEx( lpServerName,
lpMsg,
dwTimeout,
fForce,
fReboot,
dwReasonCode ))
{
report_error( GetLastError( ), lpServerName);
}
}
}
}
else
{
//
// We will keep the dialog up in case user forget to add computers.
//
break;
}
EndDialog(hwnd, (int) dwDlgResult);
}
break;
case IDC_CHECKWARNING:
//
// The checkbutton state decides the state of the timeout edit box.
//
if (codeNotify == BN_CLICKED)
{
if(BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_CHECKWARNING))
{
EnableWindow(g_wins.hwndEditTimeout, TRUE);
}
else
{
EnableWindow(g_wins.hwndEditTimeout, FALSE);
}
fHandled = TRUE;
}
break;
case IDC_BUTTONBROWSE:
//
// Simply pop up the browse dialog. That dialog will be responsible
// for adding the user selection to the selected computer list.
//
if (codeNotify == BN_CLICKED)
{
HRESULT hr;
ICommonQuery* pcq;
OPENQUERYWINDOW oqw = { 0 };
DSQUERYINITPARAMS dqip = { 0 };
IDataObject *pdo;
FORMATETC fmte = {(CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES),
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL};
FORMATETC fmte2 = {(CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSQUERYPARAMS),
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL};
STGMEDIUM medium = { TYMED_NULL, NULL, NULL };
DSOBJECTNAMES *pdon;
DSQUERYPARAMS *pdqp;
CoInitialize(NULL);
//
// Windows 2000: Always use IID_ICommonQueryW explicitly. IID_ICommonQueryA is not supported.
//
hr = CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER, IID_ICommonQuery, (void**)&pcq);
if (FAILED(hr)) {
//
// if failed return.
//
CoUninitialize();
DbgPrint("Cannot create ICommonQuery, return.\n");
break;
}
//
// Initialize the OPENQUERYWINDOW structure to indicate
// we want to do a Directory Service
// Query, the default form is printers and the search
// should start once the window is initialized.
//
oqw.cbStruct = sizeof(oqw);
oqw.dwFlags = OQWF_OKCANCEL|OQWF_DEFAULTFORM|OQWF_HIDEMENUS|OQWF_REMOVEFORMS;
oqw.clsidHandler = CLSID_DsQuery;
oqw.pHandlerParameters = &dqip;
oqw.clsidDefaultForm = CLSID_DsFindComputer;
//
// Now initialize the handler specific parameters,
// in this case, the File/Save menu item is removed
//
dqip.cbStruct = sizeof(dqip);
dqip.dwFlags = DSQPF_NOSAVE;
//
// Call OpenQueryWindow, it will block until
// the Query Window is dismissed,
//
hr = pcq->OpenQueryWindow(hwnd, &oqw, &pdo);
if (FAILED(hr)) {
//
// if failed we return.
//
pcq->Release();
CoUninitialize();
break;
}
if (!pdo) {
//
// if cancelled,nothing needs to be done.
//
pcq->Release();
CoUninitialize();
break;
}
//
// Get the CFSTR_DSOBJECTNAMES data. For each selected, the data
// includes the object class and an ADsPath to the selected object.
//
hr = pdo->GetData(&fmte, &medium);
if(! FAILED(hr))
{
pdon = (DSOBJECTNAMES*)GlobalLock(medium.hGlobal);
if ( pdon )
{
WCHAR szName[MAX_PATH];
LPWSTR lpsz = NULL;
UINT i;
for (i = 0; i < pdon->cItems; i++)
{
if(!GetComputerNameFromPath((LPWSTR) ((PBYTE) pdon + pdon->aObjects[i].offsetName), szName))
continue;
//
// We don't add dups.
//
if(LB_ERR == ListBox_FindStringExact(g_wins.hwndListSelectComputers, -1, szName))
{
ListBox_AddString(g_wins.hwndListSelectComputers, szName);
}
}
GlobalUnlock(medium.hGlobal);
}
else
{
DbgPrint("GlobalLock on medium failed.\n");
}
ReleaseStgMedium(&medium);
}
else
{
DbgPrint("pdo->GetData failed: 0x%x\n", hr);
}
//
// Release resources.
//
pdo->Release();
pcq->Release();
CoUninitialize();
AdjustWindowState();
fHandled = TRUE;
}
break;
case IDC_COMBOOPTION:
//
// Here is where you select shutdown reasons.
//
if (codeNotify == CBN_SELCHANGE)
{
g_reasons.SetDesc(g_wins.hwndComboOption, g_wins.hwndStaticDesc);
AdjustWindowState();
fHandled = TRUE;
}
break;
case IDC_COMBOACTION:
//
// Select user action here.
// according to the action. some item will be disabled or enabled.
//
if (codeNotify == CBN_SELCHANGE)
{
WCHAR name[MAX_PATH];
DWORD dwIndex;
DWORD dwOldActionSelect = g_dwActionSelect;
DWORD dwCheckState = 0x0;
int iFirst = -1;
if (IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED)
dwCheckState = SHTDN_REASON_FLAG_PLANNED;
GetWindowText(g_wins.hwndComboAction, (LPWSTR)name, MAX_PATH);
for(dwIndex = 0; dwIndex < g_nActions; dwIndex++)
{
if(lstrcmp(name, g_lppszActions[dwIndex]) == 0)
{
g_dwActionSelect = dwIndex;
if(g_dwActionSelect == ACTION_ANNOTATE)
g_bDirty = TRUE;
else
g_bDirty = FALSE;
//
// If change from clean to dirty or vsv, repopulate the combo.
//
if (dwOldActionSelect != g_dwActionSelect
&& (dwOldActionSelect == ACTION_ANNOTATE || g_dwActionSelect == ACTION_ANNOTATE))
{
g_reasons.FillCombo(g_wins.hwndComboOption, g_bDirty,
dwCheckState == SHTDN_REASON_FLAG_PLANNED, g_wins.hwndStaticDesc);
}
AdjustWindowState();
break;
}
}
fHandled = TRUE;
}
break;
case IDC_LISTSELECTEDCOMPUTERS:
//
// When selection change, update the remove button state.
//
if (codeNotify == LBN_SELCHANGE)
{
AdjustWindowState();
fHandled = TRUE;
}
else if (codeNotify == WM_MOUSEMOVE)
{
MessageBox(hwnd, L"Mouse move", NULL, 0);
fHandled = TRUE;
}
break;
case IDHELP:
//
// Open the .chm file.
//
if (codeNotify == BN_CLICKED)
{
if(g_lpszHelpdirChm)
HtmlHelpW(/*hwnd*/0, g_lpszHelpdirChm, HH_DISPLAY_TOPIC,(DWORD)0);
}
}
return fHandled;
}
//
// Command handler for the addnew dialog.
// It simply copy the text into a allocated buffer when OK is clicked.
//
BOOL AddNew_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
BOOL fHandled = FALSE;
DWORD dwDlgResult = 0;
HINSTANCE h;
switch (id)
{
case IDOK:
if (codeNotify == BN_CLICKED)
{
HWND hwndEdit;
DWORD dwTextlen = 0;
hwndEdit = GetDlgItem(hwnd, IDC_EDIT_ADDCOMPUTERS_COMPUTERS);
if(hwndEdit != NULL)
{
dwTextlen = Edit_GetTextLength(hwndEdit);
if(dwTextlen)
{
g_lpszNewComputers = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(TCHAR) * (dwTextlen + 1));
if(g_lpszNewComputers){
Edit_GetText(hwndEdit, g_lpszNewComputers, dwTextlen + 1);
}
}
}
EndDialog(hwnd, (int) dwDlgResult);
}
break;
case IDCANCEL:
if (codeNotify == BN_CLICKED)
{
EndDialog(hwnd, (int) dwDlgResult);
}
break;
}
return fHandled;
}
//
// Annotate dirty shutdown on remote machine.
BOOL
Annotate(
LPCWSTR lpMachine,
LPDWORD lpdwReason,
LPCWSTR lpComment,
LPDWORD lpdwErr)
{
HKEY hRemote = NULL;
HKEY hKey = NULL;
HANDLE hEventLog = NULL;
PTOKEN_USER pTokenUser = NULL;
BOOL res = TRUE;
if(lpMachine && wcslen(lpMachine) > 1)
{
WCHAR szMachine[MAX_PATH];
szMachine[0] = '\0';
if(lpMachine[0] != '\\')
{
wcscpy(szMachine, L"\\\\");
}
wcsncat(szMachine, lpMachine, MAX_PATH - 3);
szMachine[MAX_PATH - 1] = '\0';
RegConnectRegistryW(szMachine, HKEY_LOCAL_MACHINE, &hRemote);
if(!hRemote)
{
*lpdwErr = GetLastError();
ERROR_WITH_SZ(IDS_FAILED_REG_CONN, lpMachine, *lpdwErr);
goto fail;
}
RegOpenKeyExW(hRemote,
REGSTR_PATH_RELIABILITY,
NULL,
KEY_ALL_ACCESS | KEY_WOW64_64KEY,
&hKey);
if(!hKey)
{
*lpdwErr = GetLastError();
ERROR_WITH_SZ(IDS_FAILED_REG_OPEN, lpMachine, *lpdwErr);
goto fail;
}
}
else // local machine
{
lpMachine = g_lpszLocalComputerName;
RegOpenKeyExW(HKEY_LOCAL_MACHINE,
REGSTR_PATH_RELIABILITY,
NULL,
KEY_ALL_ACCESS | KEY_WOW64_64KEY,
&hKey);
if(!hKey)
{
*lpdwErr = GetLastError();
ERROR_WITH_SZ(IDS_FAILED_REG_OPEN, lpMachine, *lpdwErr);
goto fail;
}
}
DWORD dwDirtyVal;
DWORD dwType;
DWORD dwSize = sizeof(DWORD);
static LPCWSTR lpszDirtyValName = L"DirtyShutdown";
if( ERROR_SUCCESS != RegQueryValueExW(hKey, lpszDirtyValName, NULL, &dwType, (LPBYTE)&dwDirtyVal,&dwSize))
{
*lpdwErr = GetLastError();
ERROR_WITH_SZ(IDS_NO_DIRTY_SHUTDOWN, lpMachine, *lpdwErr);
goto fail;
}
if (dwDirtyVal)
{
PSID pUserSid = NULL;
DWORD dwSidSize = sizeof(SID), dwEventID;
WCHAR szReason[MAX_REASON_NAME_LEN + 10];
LPCWSTR lpStrings[8];
WORD wEventType, wStringCnt;
WCHAR szMinorReason[32];
WCHAR szName[MAX_PATH + 1];
WCHAR szDomain[MAX_PATH + 1];
DWORD dwNameLen = MAX_PATH + 1;
DWORD dwDomainLen = MAX_PATH + 1;
SID_NAME_USE eUse;
// Get the user's SID so we can output their account name to the event log.
if (GetUserSid(&pTokenUser)) {
pUserSid = pTokenUser->User.Sid;
}
if ((hEventLog = RegisterEventSourceW(lpMachine, L"USER32")) == NULL) {
*lpdwErr = GetLastError();
ERROR_WITH_SZ(IDS_FAILED_EVENT_REG, lpMachine, *lpdwErr);
goto fail;
}
g_reasons.GetReasonTitle(*lpdwReason, szReason, ARRAY_SIZE(szReason));
// Get User name.
if (!LookupAccountSidW(NULL, pUserSid, szName, &dwNameLen, szDomain,
&dwDomainLen, &eUse)) {
goto fail;
}
szName[MAX_PATH] = 0;
szDomain[MAX_PATH] = 0;
// We need to pack into a buffer of MAX_PATH + 1 in the form L"domain\\username"
if (wcslen(szDomain) + wcslen(szName) > MAX_PATH - 1) {
goto fail;
}
if (wcslen(szDomain) > 0) {
wcscat(szDomain, L"\\");
}
wcscat(szDomain, szName);
// The minor reason is the low-order word of the reason code.
wsprintf(szMinorReason, L"0x%x", *lpdwReason);
wEventType = EVENTLOG_WARNING_TYPE;
dwEventID = WARNING_DIRTY_REBOOT;
wStringCnt = 6;
lpStrings[0] = szReason;
lpStrings[1] = szMinorReason;
lpStrings[2] = NULL;
lpStrings[3] = NULL;
lpStrings[4] = lpComment;
lpStrings[5] = szDomain;
if ( (*lpdwErr = RegDeleteValueW(hKey, lpszDirtyValName)) != ERROR_SUCCESS )
{
ERROR_WITH_SZ(IDS_NO_DIRTY_SHUTDOWN, lpMachine, *lpdwErr);
goto fail;
}
if(! ReportEventW(hEventLog, wEventType, 1, dwEventID, pUserSid,
wStringCnt, sizeof(DWORD),
lpStrings, lpdwReason))
{
DWORD dwDirtyShutdownFlag = 1;
*lpdwErr = GetLastError();
ERROR_WITH_SZ(IDS_FAILED_EVENT_REPORT, lpMachine, *lpdwErr);
RegSetValueEx( hKey,
lpszDirtyValName,
0,
REG_DWORD,
(PUCHAR) &dwDirtyShutdownFlag,
sizeof(DWORD));
goto fail;
}
}
else
{
RegDeleteValueW(hKey, lpszDirtyValName);
ERROR_WITH_SZ(IDS_NO_DIRTY_SHUTDOWN, lpMachine, 0);
}
goto exit;
fail:
res = FALSE;
exit:
if (pTokenUser != NULL) {
LocalFree(pTokenUser);
}
if(hEventLog)
DeregisterEventSource(hEventLog);
if(hKey)
RegCloseKey(hKey);
if(hRemote)
RegCloseKey(hRemote);
return res;
}
//
// Subclass procedure for edit box.
//
LRESULT APIENTRY EditSubclassProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
if (uMsg == WM_PASTE)
return TRUE;
if (uMsg == WM_CONTEXTMENU)
{
if(g_lpszHelpdir)
{
LPWSTR szHelp = new WCHAR[wcslen(g_lpszHelpdir) + 128];
if(szHelp)
{
wcscpy(szHelp, g_lpszHelpdir);
wcscat(szHelp, HELP_FILE);
WinHelpW(hwnd, szHelp, HELP_CONTEXTMENU,(DWORD_PTR)(LPSTR)ShutdownDialogHelpIds);
delete [] szHelp;
}
}
return TRUE;
}
return CallWindowProc(wpOrigEditProc, hwnd, uMsg,
wParam, lParam);
}
BOOL
GetUserSid(
PTOKEN_USER *ppTokenUser)
{
HANDLE TokenHandle;
PTOKEN_USER pTokenUser = NULL;
DWORD cbTokenUser = 0;
DWORD cbNeeded;
BOOL bRet = FALSE;
if (!GetTokenHandle(&TokenHandle)) {
return FALSE;
}
bRet = GetTokenInformation(TokenHandle,
TokenUser,
pTokenUser,
cbTokenUser,
&cbNeeded);
/*
* We've passed a NULL pointer and 0 for the amount of memory
* allocated. We expect to fail with bRet = FALSE and
* GetLastError = ERROR_INSUFFICIENT_BUFFER. If we do not
* have these conditions we will return FALSE.
*/
if (!bRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
pTokenUser = (PTOKEN_USER)LocalAlloc(LPTR, cbNeeded);
if (pTokenUser == NULL) {
goto GetUserSidDone;
}
cbTokenUser = cbNeeded;
bRet = GetTokenInformation(TokenHandle,
TokenUser,
pTokenUser,
cbTokenUser,
&cbNeeded);
} else {
/*
* Any other case -- return FALSE
*/
bRet = FALSE;
}
GetUserSidDone:
if (bRet == TRUE) {
*ppTokenUser = pTokenUser;
} else if (pTokenUser != NULL) {
LocalFree(pTokenUser);
}
CloseHandle(TokenHandle);
return bRet;
}
BOOL
GetTokenHandle(
PHANDLE pTokenHandle)
{
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
TRUE,
pTokenHandle)) {
if (GetLastError() == ERROR_NO_TOKEN) {
/* This means we are not impersonating anybody.
* Instead, lets get the token out of the process.
*/
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
pTokenHandle)) {
return FALSE;
}
} else {
return FALSE;
}
}
return TRUE;
}
WCHAR*
LoadWString(int resid)
{
DWORD len, curlen = MAX_PATH;
LPWSTR szBuf = NULL;
szBuf = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * MAX_PATH);
if(!szBuf)
return NULL;
len = LoadStringW( g_hDllInstance, resid, szBuf, curlen);
while (len + 1 == curlen)
{
LocalFree(szBuf);
szBuf = (LPWSTR)LocalAlloc(LMEM_FIXED, curlen * 2 * sizeof(WCHAR));
if(!szBuf)
return NULL;
curlen *= 2;
len = LoadStringW( g_hDllInstance, resid, szBuf, curlen);
}
szBuf[len] = '\0';
return szBuf;
}
BOOL
IsStaticControl (HWND hwnd)
{
WCHAR name[128];
if (GetClassName(hwnd, name, 128)
&& (_wcsicmp(name, L"Static") == 0 || _wcsicmp(name, L"#32770") == 0))
{
// MessageBox(NULL, name, NULL, 0);
return TRUE;
}
// MessageBox(NULL, name, NULL, 0);
return FALSE;
}