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.
 
 
 
 
 
 

1141 lines
39 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997-2002.
//
// File: Dialogs.cpp
//
// Contents:
//
//----------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////
// Dialogs.cpp
//
// DlgProc for Send Console Message Snapin.
//
// HISTORY
// 4-Aug-97 t-danm Creation.
// 13 Feb 2001 bryanwal Use object picker instead of add recipients
// dialog
/////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <strsafe.h>
#include <objsel.h>
#include "debug.h"
#include "util.h"
#include "dialogs.h"
#include "resource.h"
#include <htmlhelp.h> //<mmc.h>
#if 1
#define ThreadTrace0(sz) Trace0(sz)
#define ThreadTrace1(sz, p1) Trace1(sz, p1)
#else
#define ThreadTrace0(sz)
#define ThreadTrace1(sz, p1)
#endif
const PCWSTR CONTEXT_HELP_FILE = L"sendcmsg.hlp";
const PCWSTR HTML_HELP_FILE = L"sendcmsg.chm";
// Register clipboard formats used by the Send Console Message
UINT g_cfSendConsoleMessageText = ::RegisterClipboardFormat(_T("mmc.sendcmsg.MessageText"));
UINT g_cfSendConsoleMessageRecipients = ::RegisterClipboardFormat(_T("mmc.sendcmsg.MessageRecipients"));
enum
{
iImageComputer = 0, // Generic image of a computer
iImageComputerOK,
iImageComputerError
};
// Maximum length of a recipient (machine name)
const int cchRECIPIENT_NAME_MAX = MAX_PATH;
enum
{
COL_NAME = 0,
COL_RESULT,
NUM_COLS // must be last
};
/////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Generic Computer Picker
///////////////////////////////////////////////////////////////////////////////
//+--------------------------------------------------------------------------
//
// Function: InitObjectPickerForComputers
//
// Synopsis: Call IDsObjectPicker::Initialize with arguments that will
// set it to allow the user to pick a single computer object.
//
// Arguments: [pDsObjectPicker] - object picker interface instance
//
// Returns: Result of calling IDsObjectPicker::Initialize.
//
// History: 10-14-1998 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT InitObjectPickerForComputers(IDsObjectPicker *pDsObjectPicker)
{
if ( !pDsObjectPicker )
return E_POINTER;
//
// Prepare to initialize the object picker.
// Set up the array of scope initializer structures.
//
static const int SCOPE_INIT_COUNT = 2;
DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
ZeroMemory(aScopeInit, sizeof(aScopeInit));
//
// 127399: JonN 10/30/00 JOINED_DOMAIN should be starting scope
//
aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[0].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
| DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
aScopeInit[0].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE;
aScopeInit[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS;
aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
aScopeInit[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[1].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN
| DSOP_SCOPE_TYPE_GLOBAL_CATALOG
| DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN
| DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN
| DSOP_SCOPE_TYPE_WORKGROUP
| DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE
| DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE;
aScopeInit[1].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS;
aScopeInit[1].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
//
// Put the scope init array into the object picker init array
//
DSOP_INIT_INFO initInfo;
ZeroMemory(&initInfo, sizeof(initInfo));
initInfo.cbSize = sizeof(initInfo);
initInfo.pwzTargetComputer = NULL; // NULL == local machine
initInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
initInfo.aDsScopeInfos = aScopeInit;
initInfo.cAttributesToFetch = 1;
static PCWSTR pwszDnsHostName = L"dNSHostName";
initInfo.apwzAttributeNames = &pwszDnsHostName;
//
// Note object picker makes its own copy of initInfo. Also note
// that Initialize may be called multiple times, last call wins.
//
return pDsObjectPicker->Initialize(&initInfo);
}
//+--------------------------------------------------------------------------
//
// Function: ProcessSelectedObjects
//
// Synopsis: Retrieve the list of selected items from the data object
// created by the object picker and print out each one.
//
// Arguments: [pdo] - data object returned by object picker
//
// History: 10-14-1998 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT ProcessSelectedObjects(IDataObject *pdo, PWSTR computerName, int cchLen)
{
Assert (pdo && computerName);
if ( !pdo || !computerName)
return E_POINTER;
HRESULT hr = S_OK;
static UINT g_cfDsObjectPicker =
RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
STGMEDIUM stgmedium =
{
TYMED_HGLOBAL,
NULL,
NULL
};
FORMATETC formatetc =
{
(CLIPFORMAT)g_cfDsObjectPicker,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
bool fGotStgMedium = false;
do
{
hr = pdo->GetData(&formatetc, &stgmedium);
if ( SUCCEEDED (hr) )
{
fGotStgMedium = true;
PDS_SELECTION_LIST pDsSelList =
(PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal);
if (!pDsSelList)
{
hr = HRESULT_FROM_WIN32 (GetLastError());
break;
}
Assert (1 == pDsSelList->cItems);
if ( 1 == pDsSelList->cItems )
{
PDS_SELECTION psel = &(pDsSelList->aDsSelection[0]);
VARIANT* pvarDnsName = &(psel->pvarFetchedAttributes[0]);
if ( NULL == pvarDnsName
|| VT_BSTR != pvarDnsName->vt
|| NULL == pvarDnsName->bstrVal
|| L'\0' == (pvarDnsName->bstrVal)[0] )
{
// security review 3/1/2002 BryanWal
// ISSUE - possible non-null termination - convert to strsafe
// NTRAID# Bug9 560859 security: SendCMsg: possible non-null termination of computer name
wcsncpy (computerName, psel->pwzName, cchLen);
}
else
{
// security review 3/1/2002 BryanWal
// ISSUE - possible non-null termination - convert to strsafe
// NTRAID# Bug9 560859 security: SendCMsg: possible non-null termination of computer name
wcsncpy (computerName, pvarDnsName->bstrVal, cchLen);
}
}
else
hr = E_UNEXPECTED;
GlobalUnlock(stgmedium.hGlobal);
}
} while (0);
if (fGotStgMedium)
{
ReleaseStgMedium(&stgmedium);
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// Generic method for launching a single-select computer picker
//
// Paremeters:
// hwndParent (IN) - window handle of parent window
// computerName (OUT) - computer name returned
//
// Returns S_OK if everything succeeded, S_FALSE if user pressed "Cancel"
//
//////////////////////////////////////////////////////////////////////////////
HRESULT ComputerNameFromObjectPicker (HWND hwndParent, PWSTR computerName, int cchLen)
{
Assert (computerName);
if ( !computerName )
return E_POINTER;
//
// Create an instance of the object picker. The implementation in
// objsel.dll is apartment model.
//
CComPtr<IDsObjectPicker> spDsObjectPicker;
// security review 3/1/2002 BryanWal ok
HRESULT hr = CoCreateInstance(CLSID_DsObjectPicker,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDsObjectPicker,
(void **) &spDsObjectPicker);
if ( SUCCEEDED (hr) )
{
Assert(!!spDsObjectPicker);
//
// Initialize the object picker to choose computers
//
hr = InitObjectPickerForComputers(spDsObjectPicker);
if ( SUCCEEDED (hr) )
{
//
// Now pick a computer
//
CComPtr<IDataObject> spDataObject;
hr = spDsObjectPicker->InvokeDialog(hwndParent, &spDataObject);
if ( S_OK == hr )
{
Assert(!!spDataObject);
hr = ProcessSelectedObjects(spDataObject, computerName, cchLen);
}
}
}
return hr;
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
CSendConsoleMessageDlg::CSendConsoleMessageDlg()
: m_cRefCount (0),
m_hImageList (0),
m_hdlg (0),
m_hwndEditMessageText (0),
m_hwndListviewRecipients (0)
{
m_DispatchInfo.pargbItemStatus = NULL;
// security review 3/1/2002 BryanWal
// ISSUE - can raise a STATUS_NO_MEMORY exception. consider pre-allocating at DLL_PROCESS_ATTACH
// NTRAID Bug9 565939 SendCMsg: InitializeCriticalSection throws uncaught exception
InitializeCriticalSection(OUT &m_DispatchInfo.cs);
}
CSendConsoleMessageDlg::~CSendConsoleMessageDlg()
{
ThreadTrace0("Destroying CSendConsoleMessageDlg object.\n");
Assert(m_hdlg == NULL);
delete m_DispatchInfo.pargbItemStatus;
DeleteCriticalSection(IN &m_DispatchInfo.cs);
}
/////////////////////////////////////////////////////////////////////
void CSendConsoleMessageDlg::AddRef()
{
// ISSUE - use interlocked increment
// security review 3/1/2002 BryanWal
// NTRAID# Bug9 561315 Security: SendCMsg: Replace critical sections with interlocked_increment
EnterCriticalSection(INOUT &m_DispatchInfo.cs);
Assert(m_cRefCount >= 0);
Assert(HIWORD(m_cRefCount) == 0);
m_cRefCount++;
LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
}
/////////////////////////////////////////////////////////////////////
void CSendConsoleMessageDlg::Release()
{
// Security Review 3/1/2002 BryanWal ok
EnterCriticalSection(INOUT &m_DispatchInfo.cs);
Assert(HIWORD(m_cRefCount) == 0);
m_cRefCount--;
BOOL fDeleteObject = (m_cRefCount <= 0);
if (m_hdlg != NULL)
{
Assert(IsWindow(m_hdlg));
// Cause the UI to refresh
PostMessage(m_hdlg, WM_COMMAND, MAKEWPARAM(IDC_EDIT_MESSAGE_TEXT, EN_CHANGE), 0);
}
LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
if (fDeleteObject)
delete this;
}
/////////////////////////////////////////////////////////////////////
void CSendConsoleMessageDlg::OnInitDialog(HWND hdlg, IDataObject * pDataObject)
{
Assert(IsWindow(hdlg));
Assert(pDataObject != NULL);
if ( !IsWindow (hdlg) || ! pDataObject )
return;
m_hdlg = hdlg;
m_hwndEditMessageText = GetDlgItem(m_hdlg, IDC_EDIT_MESSAGE_TEXT);
m_hwndListviewRecipients = GetDlgItem(m_hdlg, IDC_LIST_RECIPIENTS);
Assert(::IsWindow(m_hwndEditMessageText));
Assert(::IsWindow(m_hwndListviewRecipients));
WCHAR * pawszMessage = NULL;
(void) HrExtractDataAlloc(IN pDataObject, g_cfSendConsoleMessageText, OUT (PVOID *)&pawszMessage);
// Set the initial message text
if ( pawszMessage )
{
SetWindowTextW(m_hwndEditMessageText, pawszMessage);
GlobalFree(pawszMessage);
}
SendMessage(m_hwndEditMessageText, EM_SETSEL, 0, 0);
SetFocus(m_hwndEditMessageText);
Assert(m_hImageList == NULL);
m_hImageList = ImageList_LoadImage(
g_hInstance,
MAKEINTRESOURCE(IDB_BITMAP_COMPUTER),
16, 3, RGB(255, 0, 255),
IMAGE_BITMAP, 0);
Report(m_hImageList != NULL);
ListView_SetImageList(m_hwndListviewRecipients, m_hImageList, LVSIL_SMALL);
// Set up columns in list view
int colWidths[NUM_COLS] = {200, 200};
LVCOLUMN lvColumn;
WCHAR szColumnText[128];
::ZeroMemory (&lvColumn, sizeof (lvColumn));
lvColumn.mask = LVCF_WIDTH | LVCF_TEXT;
lvColumn.cx = colWidths[COL_NAME];
CchLoadString (IDS_RECIPIENT, OUT szColumnText, LENGTH(szColumnText));
lvColumn.pszText = szColumnText;
int nCol = ListView_InsertColumn (m_hwndListviewRecipients, COL_NAME, &lvColumn);
Assert (-1 != nCol);
lvColumn.cx = colWidths[COL_RESULT];
CchLoadString (IDS_MESSAGE_STATUS, OUT szColumnText, LENGTH(szColumnText));
lvColumn.pszText = szColumnText;
nCol = ListView_InsertColumn (m_hwndListviewRecipients, COL_RESULT, &lvColumn);
Assert (-1 != nCol);
if ( -1 != nCol )
{
// Make column fill remaining space
ListView_SetColumnWidth (m_hwndListviewRecipients, COL_RESULT,
LVSCW_AUTOSIZE_USEHEADER);
}
// Get the list of recipients
WCHAR * pagrwszRecipients = NULL;
(void)HrExtractDataAlloc(IN pDataObject, g_cfSendConsoleMessageRecipients, OUT (PVOID *)&pagrwszRecipients);
if (pagrwszRecipients == NULL)
{
UpdateUI();
return;
}
// Add the recipients to the listview
const WCHAR * pszRecipient = pagrwszRecipients;
while (*pszRecipient != '\0')
{
// Strip off leading "\\" if present.
// security review 3/1/2002 BryanWal ok
if ( !_wcsnicmp (pszRecipient, L"\\\\", 2) )
{
pszRecipient+= 2;
}
AddRecipient(pszRecipient);
while(*pszRecipient++ != '\0')
; // Skip until the next string
} // while
// NTRAID# 213370 [SENDCMSG] Accessibility - Main dialog tab stop on
// Recipients listview has no visible focus indicator until object is
// selected
int nIndex = ListView_GetTopIndex (m_hwndListviewRecipients);
ListView_SetItemState (m_hwndListviewRecipients, nIndex, LVIS_FOCUSED,
LVIS_FOCUSED);
GlobalFree(pagrwszRecipients);
UpdateUI();
} // CSendConsoleMessageDlg::OnInitDialog()
/////////////////////////////////////////////////////////////////////
void CSendConsoleMessageDlg::OnOK()
{
Assert(m_cRefCount == 1 && "There is already another thread running.");
m_DispatchInfo.status = e_statusDlgInit;
m_DispatchInfo.cErrors = 0;
delete m_DispatchInfo.pargbItemStatus;
m_DispatchInfo.pargbItemStatus = NULL;
(void)DoDialogBox(IDD_DISPATCH_MESSAGES, m_hdlg,
DlgProcDispatchMessageToRecipients, (LPARAM)this);
if (m_DispatchInfo.cErrors == 0 && m_DispatchInfo.status == e_statusDlgCompleted)
{
// No problems dispatching the message to recipients
EndDialog(m_hdlg, TRUE); // Close the dialog
return;
}
Assert(IsWindow(m_hwndListviewRecipients));
ListView_UnselectAllItems(m_hwndListviewRecipients);
if (m_DispatchInfo.cErrors > 0)
{
DoMessageBox(m_hdlg, IDS_ERR_CANNOT_SEND_TO_ALL_RECIPIENTS);
}
// We did not finished the job, so display the status to the UI
if (m_DispatchInfo.pargbItemStatus == NULL)
{
// The progress was unable to allocate memory for the status
Trace0("CSendConsoleMessageDlg::OnOK() - Out of memory.\n");
return;
}
// Remove all the successful items, leaving only the failed targets and
// the unsent targets (in the event the user pressed Cancel).
int iItem = ListView_GetItemCount (m_hwndListviewRecipients);
iItem--;
const BYTE * pb = m_DispatchInfo.pargbItemStatus + iItem;
for (; iItem >= 0 && pb >= m_DispatchInfo.pargbItemStatus;
pb--, iItem--)
{
if ( *pb == iImageComputerOK )
VERIFY (ListView_DeleteItem (m_hwndListviewRecipients, iItem));
}
} // CSendConsoleMessageDlg::OnOK()
/////////////////////////////////////////////////////////////////////
void CSendConsoleMessageDlg::DispatchMessageToRecipients()
{
const size_t FORMAT_BUF_LEN = 128;
const int cRecipients = ListView_GetItemCount(m_hwndListviewRecipients);
WCHAR szT[FORMAT_BUF_LEN + cchRECIPIENT_NAME_MAX];
WCHAR szFmtStaticRecipient[FORMAT_BUF_LEN]; // "Sending console message to %s..."
WCHAR szFmtStaticMessageOf[FORMAT_BUF_LEN]; // "Sending message %d of %d."
WCHAR szFmtStaticTotalErrors[FORMAT_BUF_LEN]; // "Total errors encountered\t%d."
GetWindowText(m_DispatchInfo.hctlStaticRecipient, OUT szFmtStaticRecipient, LENGTH(szFmtStaticRecipient));
GetWindowText(m_DispatchInfo.hctlStaticMessageOf, szFmtStaticMessageOf, LENGTH(szFmtStaticMessageOf));
GetWindowText(m_DispatchInfo.hctlStaticErrors, OUT szFmtStaticTotalErrors, LENGTH(szFmtStaticTotalErrors));
SendMessage(m_DispatchInfo.hctlProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, cRecipients));
//
// Set the image of each recipient to normal computer
//
ListView_UnselectAllItems(m_hwndListviewRecipients);
for (int i = 0; i < cRecipients; i++)
{
ListView_SetItemImage(m_hwndListviewRecipients, i, iImageComputer);
ListView_SetItemText(m_hwndListviewRecipients, i, COL_RESULT, L"");
}
UpdateUI(); // Update the other UI controls (especially OK button)
//
// Get the text from the edit control
//
int cchMessage = GetWindowTextLength(m_hwndEditMessageText) + 1;
WCHAR * pawszMessage = new WCHAR[cchMessage];
if (pawszMessage != NULL)
{
// security review 3/1/2002 BryanWal ok - cchMessage includes null terminator
GetWindowTextW(m_hwndEditMessageText, OUT pawszMessage, cchMessage);
}
else
{
cchMessage = 0;
Trace0("Unable to allocate memory for message.\n");
}
WCHAR wszRecipient[cchRECIPIENT_NAME_MAX];
LV_ITEMW lvItem;
::ZeroMemory (&lvItem, sizeof(lvItem));
lvItem.iItem = 0;
lvItem.iSubItem = 0;
lvItem.pszText = wszRecipient;
lvItem.cchTextMax = LENGTH(wszRecipient);
Assert(m_DispatchInfo.pargbItemStatus == NULL && "Memory Leak");
m_DispatchInfo.pargbItemStatus = new BYTE[cRecipients+1];
if (m_DispatchInfo.pargbItemStatus != NULL)
{
// security review 3/1/2002 BryanWal ok
memset(OUT m_DispatchInfo.pargbItemStatus, iImageComputer, cRecipients+1);
}
else
{
Trace0("Unable to allocate memory for listview item status.\n");
}
Assert(m_DispatchInfo.status == e_statusDlgInit);
m_DispatchInfo.status = e_statusDlgDispatching; // Allow the user to cancel the dialog
WCHAR szFailure[128];
CchLoadString(IDS_MESSAGE_COULD_NOT_BE_SENT, OUT szFailure,
LENGTH(szFailure));
for (i = 0; i < cRecipients; i++)
{
ThreadTrace1("Sending message to recipient %d.\n", i + 1);
// security review 3/1/2002 BryanWal ok
EnterCriticalSection(INOUT &m_DispatchInfo.cs);
if (m_DispatchInfo.status == e_statusUserCancel)
{
ThreadTrace0("DispatchMessageToRecipients() - Aborting loop @1...\n");
LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
break;
}
ListView_SelectItem(m_hwndListviewRecipients, i);
ListView_EnsureVisible(m_hwndListviewRecipients, i, FALSE);
lvItem.iItem = i;
wszRecipient[0] = '\0';
// Get the recipient name
SendMessage(m_hwndListviewRecipients, LVM_GETITEMTEXTW, i, OUT (LPARAM)&lvItem);
if (m_DispatchInfo.pargbItemStatus != NULL)
m_DispatchInfo.pargbItemStatus[i] = iImageComputerError;
// security review 3/1/2002 BryanWal
// Issue: convert to strsafe - possible buffer overflow because of static allocation
HRESULT hr = ::StringCchPrintf (OUT szT, sizeof (szT)/sizeof (szT[0]), szFmtStaticRecipient, wszRecipient);
Assert (SUCCEEDED (hr));
if ( FAILED (hr) )
continue;
SetWindowTextW(m_DispatchInfo.hctlStaticRecipient, szT);
// security review 3/1/2002 BryanWal
// Issue: convert to strsafe - possible buffer overflow because of static allocation
hr = ::StringCchPrintf (OUT szT, sizeof (szT)/sizeof (szT[0]), szFmtStaticMessageOf, i + 1, cRecipients);
Assert (SUCCEEDED (hr));
if ( FAILED (hr) )
continue;
SetWindowText(m_DispatchInfo.hctlStaticMessageOf, szT);
switch ( m_DispatchInfo.cErrors )
{
case 0:
break;
case 1:
::ShowWindow (m_DispatchInfo.hctlStaticErrors, SW_SHOW);
{
WCHAR sz1NotSet[128];
CchLoadString(IDS_1_RECIPIENT_NOT_CONTACTED, OUT sz1NotSet,
LENGTH(sz1NotSet));
SetWindowText(m_DispatchInfo.hctlStaticErrors, sz1NotSet);
}
break;
default:
// security review 3/1/2002 BryanWal
// ISSUE - convert to strsafe - possible buffer overflow because of static allocation
hr = ::StringCchPrintf (OUT szT, sizeof (szT)/sizeof (szT[0]), szFmtStaticTotalErrors, m_DispatchInfo.cErrors);
Assert (SUCCEEDED (hr));
if ( SUCCEEDED (hr) )
SetWindowText(m_DispatchInfo.hctlStaticErrors, szT);
break;
}
LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
// Send the message to the recipient (ie, computer)
NET_API_STATUS err;
err = ::NetMessageBufferSend(
NULL,
wszRecipient,
NULL,
(BYTE *)pawszMessage,
cchMessage * sizeof(WCHAR));
int iImage = iImageComputerOK;
if (err != ERROR_SUCCESS)
{
Trace3("Error sending message to recipient %ws. err=%d (0x%X).\n", wszRecipient, err, err);
m_DispatchInfo.cErrors++;
iImage = iImageComputerError;
}
if (m_DispatchInfo.pargbItemStatus != NULL)
m_DispatchInfo.pargbItemStatus[i] = (BYTE)iImage;
// security review 3/1/2002 BryanWal - ok - nothing in here throws an exception
EnterCriticalSection(INOUT &m_DispatchInfo.cs);
if (m_DispatchInfo.status == e_statusUserCancel)
{
ThreadTrace0("DispatchMessageToRecipients() - Aborting loop @2...\n");
LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
break;
}
//
// Update the listview
//
ListView_UnselectItem(m_hwndListviewRecipients, i);
ListView_SetItemImage(m_hwndListviewRecipients, i, iImage);
if ( iImage == iImageComputerError )
ListView_SetItemText(m_hwndListviewRecipients, i, COL_RESULT,
szFailure);
//
// Update the progress dialog
//
SendMessage(m_DispatchInfo.hctlProgressBar, PBM_SETPOS, i + 1, 0);
LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
} // for
delete [] pawszMessage;
Sleep(500);
// security review 3/1/2002 BryanWal ok
EnterCriticalSection(INOUT &m_DispatchInfo.cs);
if (m_DispatchInfo.status != e_statusUserCancel)
{
// We are done dispatching the message to all the recipients
// and the user did not canceled the operation.
m_DispatchInfo.status = e_statusDlgCompleted;
Assert(IsWindow(m_DispatchInfo.hdlg));
EndDialog(m_DispatchInfo.hdlg, TRUE); // Gracefully close the dialog
}
LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
} // CSendConsoleMessageDlg::DispatchMessageToRecipients()
/////////////////////////////////////////////////////////////////////
// Add a recipient to the listview control
//
// Return the index of the inserted item.
//
int CSendConsoleMessageDlg::AddRecipient(
PCWSTR pszRecipient, // IN: Machine name
BOOL fSelectItem) // TRUE => Select the item that is inserted
{
Assert(pszRecipient != NULL);
// NTRAID# 498210 [Send Console Message] User can add the same computer to
// the Recipients listbox multiple times, sending multiple messages
LVFINDINFO lvfi;
::ZeroMemory (&lvfi, sizeof (lvfi));
lvfi.flags = LVFI_STRING;
lvfi.psz = const_cast<WCHAR *>(pszRecipient);
if ( -1 == ListView_FindItem (m_hwndListviewRecipients, -1, &lvfi) )
{
LV_ITEM lvItem;
::ZeroMemory (&lvItem, sizeof(lvItem));
lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
lvItem.iSubItem = 0;
lvItem.iImage = iImageComputer;
lvItem.pszText = const_cast<WCHAR *>(pszRecipient);
if (fSelectItem)
{
lvItem.mask = LVIF_TEXT | LVIF_IMAGE |LVIF_STATE;
lvItem.state = LVIS_SELECTED;
}
return ListView_InsertItem(m_hwndListviewRecipients, IN &lvItem);
}
else
return -1;
} // CSendConsoleMessageDlg::AddRecipient()
/////////////////////////////////////////////////////////////////////
LRESULT CSendConsoleMessageDlg::OnNotify(NMHDR * pNmHdr)
{
Assert(pNmHdr != NULL);
switch (pNmHdr->code)
{
case LVN_ENDLABELEDIT:
{
WCHAR * pszText = ((LV_DISPINFO *)pNmHdr)->item.pszText;
if (pszText == NULL)
break; // User canceled editing
// HACK: Modifying a string which I'm not sure where it is allocated
(void)FTrimString(INOUT pszText);
// Check out if there is already another recipient
int iItem = ListView_FindString(m_hwndListviewRecipients, pszText);
if (iItem >= 0)
{
ListView_SelectItem(m_hwndListviewRecipients, iItem);
DoMessageBox(m_hdlg, IDS_RECIPIENT_ALREADY_EXISTS);
break;
}
// Otherwise accept the changes
SetWindowLongPtr(m_hdlg, DWLP_MSGRESULT, TRUE);
return TRUE;
}
case LVN_ITEMCHANGED: // Selection changed
UpdateUI();
break;
case LVN_KEYDOWN:
switch (((LV_KEYDOWN *)pNmHdr)->wVKey)
{
case VK_INSERT:
SendMessage(m_hdlg, WM_COMMAND, IDC_BUTTON_ADD_RECIPIENT, 0);
break;
case VK_DELETE:
SendMessage(m_hdlg, WM_COMMAND, IDC_BUTTON_REMOVE_RECIPIENT, 0);
break;
} // switch
break;
case NM_CLICK:
UpdateUI();
break;
case NM_DBLCLK:
UpdateUI();
break;
} // switch
return 0;
} // CSendConsoleMessageDlg::OnNotify()
/////////////////////////////////////////////////////////////////////
void CSendConsoleMessageDlg::EnableDlgItem(INT nIdDlgItem, BOOL fEnable)
{
Assert(::IsWindow(::GetDlgItem(m_hdlg, nIdDlgItem)));
::EnableWindow(::GetDlgItem(m_hdlg, nIdDlgItem), fEnable);
}
/////////////////////////////////////////////////////////////////////
void CSendConsoleMessageDlg::UpdateUI()
{
Assert(m_cRefCount > 0);
int cchMessage = GetWindowTextLength(m_hwndEditMessageText);
int cItems = ListView_GetItemCount(m_hwndListviewRecipients);
EnableDlgItem(IDOK, (cchMessage > 0) && (cItems > 0) && (m_cRefCount == 1));
int iItemSelected = ListView_GetSelectedItem(m_hwndListviewRecipients);
EnableDlgItem(IDC_BUTTON_REMOVE_RECIPIENT, iItemSelected >= 0);
UpdateWindow(m_hwndListviewRecipients);
} // CSendConsoleMessageDlg::UpdateUI()
/////////////////////////////////////////////////////////////////////
// Dialog proc for the Send Console Message snapin.
//
// USAGE
// DoDialogBox(IDD_SEND_CONSOLE_MESSAGE, ::GetActiveWindow(), CSendConsoleMessageDlg::DlgProc);
//
INT_PTR CALLBACK CSendConsoleMessageDlg::DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CSendConsoleMessageDlg * pThis;
pThis = (CSendConsoleMessageDlg *)::GetWindowLongPtr(hdlg, GWLP_USERDATA);
switch (uMsg)
{
case WM_INITDIALOG:
Assert(pThis == NULL);
if (pThis != NULL)
return FALSE;
pThis = new CSendConsoleMessageDlg;
if (pThis == NULL)
{
Trace0("Unable to allocate CSendConsoleMessageDlg object.\n");
return -1;
}
SetWindowLongPtr(hdlg, GWLP_USERDATA, (LONG_PTR)pThis);
pThis->AddRef();
pThis->OnInitDialog(hdlg, (IDataObject *)lParam);
SendDlgItemMessage (hdlg, IDC_EDIT_MESSAGE_TEXT, EM_LIMITTEXT, 885, 0);
return FALSE;
case WM_NCDESTROY:
ThreadTrace0("CSendConsoleMessageDlg::DlgProc() - WM_NCDESTROY.\n");
// security review 3/1/2002 BryanWal
EnterCriticalSection(INOUT &pThis->m_DispatchInfo.cs);
pThis->m_hdlg = NULL;
LeaveCriticalSection(INOUT &pThis->m_DispatchInfo.cs);
pThis->Release();
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
if (HIWORD(wParam) == BN_CLICKED)
{
Assert((HWND)lParam == GetDlgItem(hdlg, IDOK));
pThis->OnOK();
}
break;
case IDCANCEL:
if (HIWORD(wParam) == BN_CLICKED)
{
Assert((HWND)lParam == GetDlgItem(hdlg, IDCANCEL));
EndDialog(hdlg, FALSE);
}
break;
case IDC_EDIT_MESSAGE_TEXT:
if (HIWORD(wParam) == EN_CHANGE)
pThis->UpdateUI();
break;
case IDC_BUTTON_ADD_RECIPIENT:
{
WCHAR szComputerName[MAX_PATH];
// S_FALSE means user pressed "Cancel"
if ( S_OK == ComputerNameFromObjectPicker (hdlg,
szComputerName, MAX_PATH) )
{
pThis->AddRecipient (szComputerName, TRUE);
}
pThis->UpdateUI();
}
break;
case IDC_BUTTON_REMOVE_RECIPIENT:
while (TRUE)
{
// Remove all the selected recipients
int iItem = ListView_GetSelectedItem(pThis->m_hwndListviewRecipients);
if (iItem < 0)
break;
ListView_DeleteItem(pThis->m_hwndListviewRecipients, iItem);
}
::SetFocus(pThis->m_hwndListviewRecipients);
pThis->UpdateUI();
break;
case IDC_BUTTON_ADVANCED:
(void)DoDialogBox(IDD_ADVANCED_MESSAGE_OPTIONS, hdlg, CSendMessageAdvancedOptionsDlg::DlgProc);
break;
} // switch
break;
case WM_NOTIFY:
return pThis->OnNotify((NMHDR *)lParam);
case WM_HELP:
return pThis->OnHelp (lParam, IDD_SEND_CONSOLE_MESSAGE);
default:
return FALSE;
} // switch
return TRUE;
} // CSendConsoleMessageDlg::DlgProc()
/////////////////////////////////////////////////////////////////////
// DlgProcDispatchMessageToRecipients()
//
// Private dialog to indicate the progress while a background
// thread dispatches a message to each recipient.
//
INT_PTR CALLBACK CSendConsoleMessageDlg::DlgProcDispatchMessageToRecipients(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CSendConsoleMessageDlg * pThis = (CSendConsoleMessageDlg *)::GetWindowLongPtr(hdlg, GWLP_USERDATA);
switch (uMsg)
{
case WM_INITDIALOG:
Assert(pThis == NULL);
if (pThis != NULL)
return FALSE;
pThis = (CSendConsoleMessageDlg *)lParam;
SetWindowLongPtr(hdlg, GWLP_USERDATA, (LONG_PTR)pThis);
Assert(pThis != NULL);
Assert(pThis->m_DispatchInfo.status == e_statusDlgInit);
pThis->m_DispatchInfo.hdlg = hdlg;
pThis->m_DispatchInfo.hctlStaticRecipient = GetDlgItem(hdlg, IDC_STATIC_RECIPIENT);
pThis->m_DispatchInfo.hctlStaticMessageOf = GetDlgItem(hdlg, IDC_STATIC_MESSAGE_OF);
pThis->m_DispatchInfo.hctlStaticErrors = GetDlgItem(hdlg, IDC_STATIC_ERRORS_ENCOUNTERED);
pThis->m_DispatchInfo.hctlProgressBar = GetDlgItem(hdlg, IDC_PROGRESS_MESSAGES);
{
DWORD dwThreadId;
HANDLE hThread = ::CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)ThreadProcDispatchMessageToRecipients, pThis, 0, OUT &dwThreadId);
Report(hThread != NULL && "Unable to create thread");
if (hThread != NULL)
{
VERIFY( ::CloseHandle(hThread) );
}
else
{
Trace0("Unable to create thread.\n");
// Prevent a potential deadlock
pThis->m_DispatchInfo.status = e_statusUserCancel; // Pretend the user clicked on cancel
EndDialog(hdlg, FALSE);
}
}
break;
case WM_DESTROY:
// Those variables are set to NULL just in case
pThis->m_DispatchInfo.hdlg = NULL;
pThis->m_DispatchInfo.hctlStaticRecipient = NULL;
pThis->m_DispatchInfo.hctlStaticMessageOf = NULL;
pThis->m_DispatchInfo.hctlStaticErrors = NULL;
pThis->m_DispatchInfo.hctlProgressBar = NULL;
break;
case WM_COMMAND:
if (wParam == IDCANCEL)
{
Trace0("INFO: WM_COMMAND: IDCANCEL: User canceled operation.\n");
BOOL fEndDialog = FALSE;
if (TryEnterCriticalSection(INOUT &pThis->m_DispatchInfo.cs))
{
if (pThis->m_DispatchInfo.status != e_statusDlgInit)
{
pThis->m_DispatchInfo.status = e_statusUserCancel;
fEndDialog = TRUE;
}
LeaveCriticalSection(INOUT &pThis->m_DispatchInfo.cs);
}
if (fEndDialog)
{
EndDialog(hdlg, FALSE);
}
else
{
ThreadTrace0("Critical section already in use. Try again...\n");
PostMessage(hdlg, WM_COMMAND, IDCANCEL, 0);
Sleep(100);
} // if...else
} // if
break;
case WM_HELP:
return pThis->OnHelp (lParam, IDD_DISPATCH_MESSAGES);
default:
return FALSE;
} // switch
return TRUE;
} // CSendConsoleMessageDlg::DlgProcDispatchMessageToRecipients()
/////////////////////////////////////////////////////////////////////
DWORD CSendConsoleMessageDlg::ThreadProcDispatchMessageToRecipients(CSendConsoleMessageDlg * pThis)
{
Assert(pThis != NULL);
pThis->AddRef();
Assert(pThis->m_cRefCount > 1);
pThis->DispatchMessageToRecipients();
pThis->Release();
return 0;
} // CSendConsoleMessageDlg::ThreadProcDispatchMessageToRecipients()
#define IDH_EDIT_MESSAGE_TEXT 900
#define IDH_LIST_RECIPIENTS 901
#define IDH_BUTTON_ADD_RECIPIENT 903
#define IDH_BUTTON_REMOVE_RECIPIENT 904
const DWORD g_aHelpIDs_IDD_SEND_CONSOLE_MESSAGE[]=
{
IDC_EDIT_MESSAGE_TEXT, IDH_EDIT_MESSAGE_TEXT,
IDOK, IDOK,
IDC_LIST_RECIPIENTS, IDH_LIST_RECIPIENTS,
IDC_BUTTON_ADD_RECIPIENT, IDH_BUTTON_ADD_RECIPIENT,
IDC_BUTTON_REMOVE_RECIPIENT, IDH_BUTTON_REMOVE_RECIPIENT,
0, 0
};
BOOL CSendConsoleMessageDlg::OnHelp(LPARAM lParam, int nDlgIDD)
{
const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
if (pHelpInfo && pHelpInfo->iContextType == HELPINFO_WINDOW)
{
switch (nDlgIDD)
{
case IDD_SEND_CONSOLE_MESSAGE:
DoSendConsoleMessageContextHelp ((HWND) pHelpInfo->hItemHandle);
break;
}
}
else
HtmlHelpW (NULL, HTML_HELP_FILE, HH_DISPLAY_TOPIC, 0);
return TRUE;
}
void CSendConsoleMessageDlg::DoSendConsoleMessageContextHelp (HWND hWndControl)
{
switch (::GetDlgCtrlID (hWndControl))
{
case IDCANCEL:
case IDC_BUTTON_ADVANCED:
break;
default:
// Display context help for a control
if ( !::WinHelp (
hWndControl,
CONTEXT_HELP_FILE,
HELP_WM_HELP,
(DWORD_PTR) g_aHelpIDs_IDD_SEND_CONSOLE_MESSAGE) )
{
Trace1 ("WinHelp () failed: 0x%x\n", GetLastError ());
}
break;
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
void CSendMessageAdvancedOptionsDlg::OnInitDialog(HWND hdlg)
{
m_hdlg = hdlg;
m_fSendAutomatedMessage = FALSE;
CheckDlgButton(m_hdlg, IDC_CHECK_SEND_AUTOMATED_MESSAGE, m_fSendAutomatedMessage);
UpdateUI();
}
/////////////////////////////////////////////////////////////////////
void CSendMessageAdvancedOptionsDlg::UpdateUI()
{
static const UINT rgid[] =
{
IDC_STATIC_RESOURCE_NAME,
IDC_EDIT_RESOURCE_NAME,
IDC_STATIC_SHUTDOWN_OCCURS,
IDC_EDIT_SHUTDOWN_OCCURS,
//IDC_SPIN_SHUTDOWN_OCCURS,
IDC_STATIC_SHUTDOWN_OCCURS_UNIT,
IDC_STATIC_RESEND,
IDC_EDIT_RESEND,
//IDC_SPIN_RESEND,
IDC_STATIC_RESEND_UNIT,
IDC_STATIC_RESOURCE_BACK_ONLINE,
IDC_EDIT_RESOURCE_BACK_ONLINE,
};
for (int i = 0; i < LENGTH(rgid); i++)
{
EnableWindow(GetDlgItem(m_hdlg, rgid[i]), m_fSendAutomatedMessage);
}
} // CSendMessageAdvancedOptionsDlg::UpdateUI()
/////////////////////////////////////////////////////////////////////
INT_PTR CALLBACK CSendMessageAdvancedOptionsDlg::DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM /*lParam*/)
{
CSendMessageAdvancedOptionsDlg * pThis;
pThis = (CSendMessageAdvancedOptionsDlg *)GetWindowLongPtr(hdlg, GWLP_USERDATA);
switch (uMsg)
{
case WM_INITDIALOG:
Assert(pThis == NULL);
pThis = new CSendMessageAdvancedOptionsDlg;
if (pThis == NULL)
return -1;
SetWindowLongPtr(hdlg, GWLP_USERDATA, (LONG_PTR)pThis);
pThis->OnInitDialog(hdlg);
break;
case WM_COMMAND:
switch (wParam)
{
case IDOK:
EndDialog(hdlg, TRUE);
break;
case IDCANCEL:
EndDialog(hdlg, FALSE);
break;
case IDC_CHECK_SEND_AUTOMATED_MESSAGE:
pThis->m_fSendAutomatedMessage = IsDlgButtonChecked(hdlg, IDC_CHECK_SEND_AUTOMATED_MESSAGE);
pThis->UpdateUI();
break;
} // switch
break;
default:
return FALSE;
} // switch
return TRUE;
} // CSendMessageAdvancedOptionsDlg::DlgProc()
BOOL CSendMessageAdvancedOptionsDlg::OnHelp(LPARAM /*lParam*/)
{
HtmlHelpW (NULL, HTML_HELP_FILE, HH_DISPLAY_TOPIC, 0);
return TRUE;
}