|
|
//+---------------------------------------------------------------------------
//
// 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; }
|