Source code of Windows XP (NT5)
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.

1083 lines
34 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997-2001.
  5. //
  6. // File: Dialogs.cpp
  7. //
  8. // Contents:
  9. //
  10. //----------------------------------------------------------------------------
  11. /////////////////////////////////////////////////////////////////////
  12. // Dialogs.cpp
  13. //
  14. // DlgProc for Send Console Message Snapin.
  15. //
  16. // HISTORY
  17. // 4-Aug-97 t-danm Creation.
  18. // 13 Feb 2001 bryanwal Use object picker instead of add recipients
  19. // dialog
  20. /////////////////////////////////////////////////////////////////////
  21. #include "stdafx.h"
  22. #include <objsel.h>
  23. #include "debug.h"
  24. #include "util.h"
  25. #include "dialogs.h"
  26. #include "resource.h"
  27. #include <htmlhelp.h> //<mmc.h>
  28. #if 1
  29. #define ThreadTrace0(sz) Trace0(sz)
  30. #define ThreadTrace1(sz, p1) Trace1(sz, p1)
  31. #else
  32. #define ThreadTrace0(sz)
  33. #define ThreadTrace1(sz, p1)
  34. #endif
  35. const PCWSTR CONTEXT_HELP_FILE = L"sendcmsg.hlp";
  36. const PCWSTR HTML_HELP_FILE = L"sendcmsg.chm";
  37. // Register clipboard formats used by the Send Console Message
  38. UINT g_cfSendConsoleMessageText = ::RegisterClipboardFormat(_T("mmc.sendcmsg.MessageText"));
  39. UINT g_cfSendConsoleMessageRecipients = ::RegisterClipboardFormat(_T("mmc.sendcmsg.MessageRecipients"));
  40. enum
  41. {
  42. iImageComputer = 0, // Generic image of a computer
  43. iImageComputerOK,
  44. iImageComputerError
  45. };
  46. // Maximum length of a recipient (machine name)
  47. const int cchRecipientNameMax = MAX_PATH;
  48. enum
  49. {
  50. COL_NAME = 0,
  51. COL_RESULT,
  52. NUM_COLS // must be last
  53. };
  54. #define IID_PPV_ARG(Type, Expr) IID_##Type, \
  55. reinterpret_cast<void**>(static_cast<Type **>(Expr))
  56. /////////////////////////////////////////////////////////////////////
  57. ///////////////////////////////////////////////////////////////////////////////
  58. ///////////////////////////////////////////////////////////////////////////////
  59. // Generic Computer Picker
  60. ///////////////////////////////////////////////////////////////////////////////
  61. //+--------------------------------------------------------------------------
  62. //
  63. // Function: InitObjectPickerForComputers
  64. //
  65. // Synopsis: Call IDsObjectPicker::Initialize with arguments that will
  66. // set it to allow the user to pick a single computer object.
  67. //
  68. // Arguments: [pDsObjectPicker] - object picker interface instance
  69. //
  70. // Returns: Result of calling IDsObjectPicker::Initialize.
  71. //
  72. // History: 10-14-1998 DavidMun Created
  73. //
  74. //---------------------------------------------------------------------------
  75. HRESULT InitObjectPickerForComputers(IDsObjectPicker *pDsObjectPicker)
  76. {
  77. if ( !pDsObjectPicker )
  78. return E_POINTER;
  79. //
  80. // Prepare to initialize the object picker.
  81. // Set up the array of scope initializer structures.
  82. //
  83. static const int SCOPE_INIT_COUNT = 2;
  84. DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
  85. ZeroMemory(aScopeInit, sizeof(DSOP_SCOPE_INIT_INFO) * SCOPE_INIT_COUNT);
  86. //
  87. // 127399: JonN 10/30/00 JOINED_DOMAIN should be starting scope
  88. //
  89. aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  90. aScopeInit[0].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
  91. | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
  92. aScopeInit[0].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE;
  93. aScopeInit[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS;
  94. aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
  95. aScopeInit[1].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
  96. aScopeInit[1].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN
  97. | DSOP_SCOPE_TYPE_GLOBAL_CATALOG
  98. | DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN
  99. | DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN
  100. | DSOP_SCOPE_TYPE_WORKGROUP
  101. | DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE
  102. | DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE;
  103. aScopeInit[1].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS;
  104. aScopeInit[1].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
  105. //
  106. // Put the scope init array into the object picker init array
  107. //
  108. DSOP_INIT_INFO initInfo;
  109. ZeroMemory(&initInfo, sizeof(initInfo));
  110. initInfo.cbSize = sizeof(initInfo);
  111. initInfo.pwzTargetComputer = NULL; // NULL == local machine
  112. initInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
  113. initInfo.aDsScopeInfos = aScopeInit;
  114. initInfo.cAttributesToFetch = 1;
  115. static PCWSTR pwszDnsHostName = L"dNSHostName";
  116. initInfo.apwzAttributeNames = &pwszDnsHostName;
  117. //
  118. // Note object picker makes its own copy of initInfo. Also note
  119. // that Initialize may be called multiple times, last call wins.
  120. //
  121. return pDsObjectPicker->Initialize(&initInfo);
  122. }
  123. //+--------------------------------------------------------------------------
  124. //
  125. // Function: ProcessSelectedObjects
  126. //
  127. // Synopsis: Retrieve the list of selected items from the data object
  128. // created by the object picker and print out each one.
  129. //
  130. // Arguments: [pdo] - data object returned by object picker
  131. //
  132. // History: 10-14-1998 DavidMun Created
  133. //
  134. //---------------------------------------------------------------------------
  135. HRESULT ProcessSelectedObjects(IDataObject *pdo, PWSTR computerName, int cbLen)
  136. {
  137. if ( !pdo )
  138. return E_POINTER;
  139. HRESULT hr = S_OK;
  140. static UINT g_cfDsObjectPicker =
  141. RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
  142. STGMEDIUM stgmedium =
  143. {
  144. TYMED_HGLOBAL,
  145. NULL,
  146. NULL
  147. };
  148. FORMATETC formatetc =
  149. {
  150. (CLIPFORMAT)g_cfDsObjectPicker,
  151. NULL,
  152. DVASPECT_CONTENT,
  153. -1,
  154. TYMED_HGLOBAL
  155. };
  156. bool fGotStgMedium = false;
  157. do
  158. {
  159. hr = pdo->GetData(&formatetc, &stgmedium);
  160. if ( SUCCEEDED (hr) )
  161. {
  162. fGotStgMedium = true;
  163. PDS_SELECTION_LIST pDsSelList =
  164. (PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal);
  165. if (!pDsSelList)
  166. {
  167. hr = HRESULT_FROM_WIN32 (GetLastError());
  168. break;
  169. }
  170. Assert (1 == pDsSelList->cItems);
  171. if ( 1 == pDsSelList->cItems )
  172. {
  173. PDS_SELECTION psel = &(pDsSelList->aDsSelection[0]);
  174. VARIANT* pvarDnsName = &(psel->pvarFetchedAttributes[0]);
  175. if ( NULL == pvarDnsName
  176. || VT_BSTR != pvarDnsName->vt
  177. || NULL == pvarDnsName->bstrVal
  178. || L'\0' == (pvarDnsName->bstrVal)[0] )
  179. {
  180. wcsncpy (computerName, psel->pwzName, cbLen);
  181. }
  182. else
  183. {
  184. wcsncpy (computerName, pvarDnsName->bstrVal, cbLen);
  185. }
  186. }
  187. else
  188. hr = E_UNEXPECTED;
  189. GlobalUnlock(stgmedium.hGlobal);
  190. }
  191. } while (0);
  192. if (fGotStgMedium)
  193. {
  194. ReleaseStgMedium(&stgmedium);
  195. }
  196. return hr;
  197. }
  198. ///////////////////////////////////////////////////////////////////////////////
  199. // Generic method for launching a single-select computer picker
  200. //
  201. // Paremeters:
  202. // hwndParent (IN) - window handle of parent window
  203. // computerName (OUT) - computer name returned
  204. //
  205. // Returns S_OK if everything succeeded, S_FALSE if user pressed "Cancel"
  206. //
  207. //////////////////////////////////////////////////////////////////////////////
  208. HRESULT ComputerNameFromObjectPicker (HWND hwndParent, PWSTR computerName, int cbLen)
  209. {
  210. //
  211. // Create an instance of the object picker. The implementation in
  212. // objsel.dll is apartment model.
  213. //
  214. CComPtr<IDsObjectPicker> spDsObjectPicker;
  215. HRESULT hr = CoCreateInstance(CLSID_DsObjectPicker,
  216. NULL,
  217. CLSCTX_INPROC_SERVER,
  218. IID_IDsObjectPicker,
  219. (void **) &spDsObjectPicker);
  220. if ( SUCCEEDED (hr) )
  221. {
  222. Assert(!!spDsObjectPicker);
  223. //
  224. // Initialize the object picker to choose computers
  225. //
  226. hr = InitObjectPickerForComputers(spDsObjectPicker);
  227. if ( SUCCEEDED (hr) )
  228. {
  229. //
  230. // Now pick a computer
  231. //
  232. CComPtr<IDataObject> spDataObject;
  233. hr = spDsObjectPicker->InvokeDialog(hwndParent, &spDataObject);
  234. if ( S_OK == hr )
  235. {
  236. Assert(!!spDataObject);
  237. hr = ProcessSelectedObjects(spDataObject, computerName, cbLen);
  238. }
  239. }
  240. }
  241. return hr;
  242. }
  243. /////////////////////////////////////////////////////////////////////
  244. /////////////////////////////////////////////////////////////////////
  245. CSendConsoleMessageDlg::CSendConsoleMessageDlg()
  246. : m_cRefCount (0),
  247. m_hImageList (0),
  248. m_hdlg (0),
  249. m_hwndEditMessageText (0),
  250. m_hwndListviewRecipients (0)
  251. {
  252. m_DispatchInfo.pargbItemStatus = NULL;
  253. InitializeCriticalSection(OUT &m_DispatchInfo.cs);
  254. }
  255. CSendConsoleMessageDlg::~CSendConsoleMessageDlg()
  256. {
  257. ThreadTrace0("Destroying CSendConsoleMessageDlg object.\n");
  258. Assert(m_hdlg == NULL);
  259. delete m_DispatchInfo.pargbItemStatus;
  260. DeleteCriticalSection(IN &m_DispatchInfo.cs);
  261. }
  262. /////////////////////////////////////////////////////////////////////
  263. void CSendConsoleMessageDlg::AddRef()
  264. {
  265. EnterCriticalSection(INOUT &m_DispatchInfo.cs);
  266. Assert(m_cRefCount >= 0);
  267. Assert(HIWORD(m_cRefCount) == 0);
  268. m_cRefCount++;
  269. LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
  270. }
  271. /////////////////////////////////////////////////////////////////////
  272. void CSendConsoleMessageDlg::Release()
  273. {
  274. EnterCriticalSection(INOUT &m_DispatchInfo.cs);
  275. Assert(HIWORD(m_cRefCount) == 0);
  276. m_cRefCount--;
  277. BOOL fDeleteObject = (m_cRefCount <= 0);
  278. if (m_hdlg != NULL)
  279. {
  280. Assert(IsWindow(m_hdlg));
  281. // Cause the UI to refresh
  282. PostMessage(m_hdlg, WM_COMMAND, MAKEWPARAM(IDC_EDIT_MESSAGE_TEXT, EN_CHANGE), 0);
  283. }
  284. LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
  285. if (fDeleteObject)
  286. delete this;
  287. }
  288. /////////////////////////////////////////////////////////////////////
  289. void CSendConsoleMessageDlg::OnInitDialog(HWND hdlg, IDataObject * pDataObject)
  290. {
  291. Assert(IsWindow(hdlg));
  292. Assert(pDataObject != NULL);
  293. if ( !IsWindow (hdlg) || ! pDataObject )
  294. return;
  295. m_hdlg = hdlg;
  296. m_hwndEditMessageText = GetDlgItem(m_hdlg, IDC_EDIT_MESSAGE_TEXT);
  297. m_hwndListviewRecipients = GetDlgItem(m_hdlg, IDC_LIST_RECIPIENTS);
  298. Assert(::IsWindow(m_hwndEditMessageText));
  299. Assert(::IsWindow(m_hwndListviewRecipients));
  300. WCHAR * pawszMessage = NULL;
  301. (void) HrExtractDataAlloc(IN pDataObject, g_cfSendConsoleMessageText, OUT (PVOID *)&pawszMessage);
  302. // Set the initial message text
  303. if ( pawszMessage )
  304. {
  305. SetWindowTextW(m_hwndEditMessageText, pawszMessage);
  306. GlobalFree(pawszMessage);
  307. }
  308. SendMessage(m_hwndEditMessageText, EM_SETSEL, 0, 0);
  309. SetFocus(m_hwndEditMessageText);
  310. Assert(m_hImageList == NULL);
  311. m_hImageList = ImageList_LoadImage(
  312. g_hInstance,
  313. MAKEINTRESOURCE(IDB_BITMAP_COMPUTER),
  314. 16, 3, RGB(255, 0, 255),
  315. IMAGE_BITMAP, 0);
  316. Report(m_hImageList != NULL);
  317. ListView_SetImageList(m_hwndListviewRecipients, m_hImageList, LVSIL_SMALL);
  318. // Set up columns in list view
  319. int colWidths[NUM_COLS] = {150, 200};
  320. LVCOLUMN lvColumn;
  321. ::ZeroMemory (&lvColumn, sizeof (LVCOLUMN));
  322. lvColumn.mask = LVCF_WIDTH;
  323. lvColumn.cx = colWidths[COL_NAME];
  324. int nCol = ListView_InsertColumn (m_hwndListviewRecipients, COL_NAME, &lvColumn);
  325. Assert (-1 != nCol);
  326. lvColumn.cx = colWidths[COL_RESULT];
  327. nCol = ListView_InsertColumn (m_hwndListviewRecipients, COL_RESULT, &lvColumn);
  328. Assert (-1 != nCol);
  329. // Get the list of recipients
  330. WCHAR * pagrwszRecipients = NULL;
  331. (void)HrExtractDataAlloc(IN pDataObject, g_cfSendConsoleMessageRecipients, OUT (PVOID *)&pagrwszRecipients);
  332. if (pagrwszRecipients == NULL)
  333. {
  334. UpdateUI();
  335. return;
  336. }
  337. // Add the recipients to the listview
  338. const WCHAR * pszRecipient = pagrwszRecipients;
  339. while (*pszRecipient != '\0')
  340. {
  341. // Strip off leading "\\" if present.
  342. if ( !_wcsnicmp (pszRecipient, L"\\\\", 2) )
  343. {
  344. pszRecipient+= 2;
  345. }
  346. AddRecipient(pszRecipient);
  347. while(*pszRecipient++ != '\0')
  348. ; // Skip until the next string
  349. } // while
  350. // NTRAID# 213370 [SENDCMSG] Accessibility - Main dialog tab stop on
  351. // Recipients listview has no visible focus indicator until object is
  352. // selected
  353. int nIndex = ListView_GetTopIndex (m_hwndListviewRecipients);
  354. ListView_SetItemState (m_hwndListviewRecipients, nIndex, LVIS_FOCUSED,
  355. LVIS_FOCUSED);
  356. GlobalFree(pagrwszRecipients);
  357. UpdateUI();
  358. } // CSendConsoleMessageDlg::OnInitDialog()
  359. /////////////////////////////////////////////////////////////////////
  360. void CSendConsoleMessageDlg::OnOK()
  361. {
  362. Assert(m_cRefCount == 1 && "There is already another thread running.");
  363. m_DispatchInfo.status = e_statusDlgInit;
  364. m_DispatchInfo.cErrors = 0;
  365. delete m_DispatchInfo.pargbItemStatus;
  366. m_DispatchInfo.pargbItemStatus = NULL;
  367. (void)DoDialogBox(IDD_DISPATCH_MESSAGES, m_hdlg,
  368. (DLGPROC)DlgProcDispatchMessageToRecipients, (LPARAM)this);
  369. if (m_DispatchInfo.cErrors == 0 && m_DispatchInfo.status == e_statusDlgCompleted)
  370. {
  371. // No problems dispatching the message to recipients
  372. EndDialog(m_hdlg, TRUE); // Close the dialog
  373. return;
  374. }
  375. Assert(IsWindow(m_hwndListviewRecipients));
  376. ListView_UnselectAllItems(m_hwndListviewRecipients);
  377. if (m_DispatchInfo.cErrors > 0)
  378. {
  379. DoMessageBox(IDS_ERR_CANNOT_SEND_TO_ALL_RECIPIENTS);
  380. }
  381. // We did not finished the job, so display the status to the UI
  382. if (m_DispatchInfo.pargbItemStatus == NULL)
  383. {
  384. // The progress was unable to allocate memory for the status
  385. Trace0("CSendConsoleMessageDlg::OnOK() - Out of memory.\n");
  386. return;
  387. }
  388. // Remove all the successful items, leaving only the failed targets and
  389. // the unsent targets (in the event the user pressed Cancel).
  390. int iItem = ListView_GetItemCount (m_hwndListviewRecipients);
  391. iItem--;
  392. const BYTE * pb = m_DispatchInfo.pargbItemStatus + iItem;
  393. for (; iItem >= 0 && pb >= m_DispatchInfo.pargbItemStatus;
  394. pb--, iItem--)
  395. {
  396. if ( *pb == iImageComputerOK )
  397. VERIFY (ListView_DeleteItem (m_hwndListviewRecipients, iItem));
  398. }
  399. } // CSendConsoleMessageDlg::OnOK()
  400. /////////////////////////////////////////////////////////////////////
  401. void CSendConsoleMessageDlg::DispatchMessageToRecipients()
  402. {
  403. const int cRecipients = ListView_GetItemCount(m_hwndListviewRecipients);
  404. TCHAR szT[100 + cchRecipientNameMax];
  405. TCHAR szFmtStaticRecipient[128]; // "Sending console message to %s..."
  406. TCHAR szFmtStaticMessageOf[128]; // "Sending message %d of %d."
  407. TCHAR szFmtStaticTotalErrors[128]; // "Total errors encountered\t%d."
  408. GetWindowText(m_DispatchInfo.hctlStaticRecipient, OUT szFmtStaticRecipient, LENGTH(szFmtStaticRecipient));
  409. GetWindowText(m_DispatchInfo.hctlStaticMessageOf, szFmtStaticMessageOf, LENGTH(szFmtStaticMessageOf));
  410. GetWindowText(m_DispatchInfo.hctlStaticErrors, OUT szFmtStaticTotalErrors, LENGTH(szFmtStaticTotalErrors));
  411. SendMessage(m_DispatchInfo.hctlProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, cRecipients));
  412. //
  413. // Set the image of each recipient to normal computer
  414. //
  415. ListView_UnselectAllItems(m_hwndListviewRecipients);
  416. for (int i = 0; i < cRecipients; i++)
  417. {
  418. ListView_SetItemImage(m_hwndListviewRecipients, i, iImageComputer);
  419. ListView_SetItemText(m_hwndListviewRecipients, i, COL_RESULT, L"");
  420. }
  421. UpdateUI(); // Update the other UI controls (especially OK button)
  422. //
  423. // Get the text from the edit control
  424. //
  425. int cchMessage = GetWindowTextLength(m_hwndEditMessageText) + 1;
  426. WCHAR * pawszMessage = new WCHAR[cchMessage];
  427. if (pawszMessage != NULL)
  428. {
  429. GetWindowTextW(m_hwndEditMessageText, OUT pawszMessage, cchMessage);
  430. }
  431. else
  432. {
  433. cchMessage = 0;
  434. Trace0("Unable to allocate memory for message.\n");
  435. }
  436. WCHAR wszRecipient[cchRecipientNameMax];
  437. LV_ITEMW lvItem;
  438. GarbageInit(OUT &lvItem, sizeof(lvItem));
  439. lvItem.iItem = 0;
  440. lvItem.iSubItem = 0;
  441. lvItem.pszText = wszRecipient;
  442. lvItem.cchTextMax = LENGTH(wszRecipient);
  443. Assert(m_DispatchInfo.pargbItemStatus == NULL && "Memory Leak");
  444. m_DispatchInfo.pargbItemStatus = new BYTE[cRecipients+1];
  445. if (m_DispatchInfo.pargbItemStatus != NULL)
  446. {
  447. memset(OUT m_DispatchInfo.pargbItemStatus, iImageComputer, cRecipients+1);
  448. }
  449. else
  450. {
  451. Trace0("Unable to allocate memory for listview item status.\n");
  452. }
  453. Assert(m_DispatchInfo.status == e_statusDlgInit);
  454. m_DispatchInfo.status = e_statusDlgDispatching; // Allow the user to cancel the dialog
  455. TCHAR szFailure[128];
  456. CchLoadString(IDS_MESSAGE_COULD_NOT_BE_SENT, OUT szFailure,
  457. LENGTH(szFailure));
  458. for (i = 0; i < cRecipients; i++)
  459. {
  460. ThreadTrace1("Sending message to recipient %d.\n", i + 1);
  461. EnterCriticalSection(INOUT &m_DispatchInfo.cs);
  462. if (m_DispatchInfo.status == e_statusUserCancel)
  463. {
  464. ThreadTrace0("DispatchMessageToRecipients() - Aborting loop @1...\n");
  465. LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
  466. break;
  467. }
  468. ListView_SelectItem(m_hwndListviewRecipients, i);
  469. ListView_EnsureVisible(m_hwndListviewRecipients, i, FALSE);
  470. lvItem.iItem = i;
  471. wszRecipient[0] = '\0';
  472. // Get the recipient name
  473. SendMessage(m_hwndListviewRecipients, LVM_GETITEMTEXTW, i, OUT (LPARAM)&lvItem);
  474. if (m_DispatchInfo.pargbItemStatus != NULL)
  475. m_DispatchInfo.pargbItemStatus[i] = iImageComputerError;
  476. wsprintf(OUT szT, szFmtStaticRecipient, wszRecipient);
  477. SetWindowTextW(m_DispatchInfo.hctlStaticRecipient, szT);
  478. wsprintf(OUT szT, szFmtStaticMessageOf, i + 1, cRecipients);
  479. SetWindowText(m_DispatchInfo.hctlStaticMessageOf, szT);
  480. switch ( m_DispatchInfo.cErrors )
  481. {
  482. case 0:
  483. break;
  484. case 1:
  485. ::ShowWindow (m_DispatchInfo.hctlStaticErrors, SW_SHOW);
  486. {
  487. TCHAR sz1NotSet[128];
  488. CchLoadString(IDS_1_RECIPIENT_NOT_CONTACTED, OUT sz1NotSet,
  489. LENGTH(sz1NotSet));
  490. SetWindowText(m_DispatchInfo.hctlStaticErrors, sz1NotSet);
  491. }
  492. break;
  493. default:
  494. wsprintf(OUT szT, szFmtStaticTotalErrors, m_DispatchInfo.cErrors);
  495. SetWindowText(m_DispatchInfo.hctlStaticErrors, szT);
  496. break;
  497. }
  498. LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
  499. // Send the message to the recipient (ie, computer)
  500. NET_API_STATUS err;
  501. err = ::NetMessageBufferSend(
  502. NULL,
  503. wszRecipient,
  504. NULL,
  505. (BYTE *)pawszMessage,
  506. cchMessage * sizeof(WCHAR));
  507. int iImage = iImageComputerOK;
  508. if (err != ERROR_SUCCESS)
  509. {
  510. Trace3("Error sending message to recipient %ws. err=%d (0x%X).\n", wszRecipient, err, err);
  511. m_DispatchInfo.cErrors++;
  512. iImage = iImageComputerError;
  513. }
  514. if (m_DispatchInfo.pargbItemStatus != NULL)
  515. m_DispatchInfo.pargbItemStatus[i] = (BYTE)iImage;
  516. EnterCriticalSection(INOUT &m_DispatchInfo.cs);
  517. if (m_DispatchInfo.status == e_statusUserCancel)
  518. {
  519. ThreadTrace0("DispatchMessageToRecipients() - Aborting loop @2...\n");
  520. LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
  521. break;
  522. }
  523. //
  524. // Update the listview
  525. //
  526. ListView_UnselectItem(m_hwndListviewRecipients, i);
  527. ListView_SetItemImage(m_hwndListviewRecipients, i, iImage);
  528. if ( iImage == iImageComputerError )
  529. ListView_SetItemText(m_hwndListviewRecipients, i, COL_RESULT,
  530. szFailure);
  531. //
  532. // Update the progress dialog
  533. //
  534. SendMessage(m_DispatchInfo.hctlProgressBar, PBM_SETPOS, i + 1, 0);
  535. LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
  536. } // for
  537. delete pawszMessage;
  538. Sleep(500);
  539. EnterCriticalSection(INOUT &m_DispatchInfo.cs);
  540. if (m_DispatchInfo.status != e_statusUserCancel)
  541. {
  542. // We are done dispatching the message to all the recipients
  543. // and the user did not canceled the operation.
  544. m_DispatchInfo.status = e_statusDlgCompleted;
  545. Assert(IsWindow(m_DispatchInfo.hdlg));
  546. EndDialog(m_DispatchInfo.hdlg, TRUE); // Gracefully close the dialog
  547. }
  548. LeaveCriticalSection(INOUT &m_DispatchInfo.cs);
  549. } // CSendConsoleMessageDlg::DispatchMessageToRecipients()
  550. /////////////////////////////////////////////////////////////////////
  551. // Add a recipient to the listview control
  552. //
  553. // Return the index of the inserted item.
  554. //
  555. int CSendConsoleMessageDlg::AddRecipient(
  556. LPCTSTR pszRecipient, // IN: Machine name
  557. BOOL fSelectItem) // TRUE => Select the item that is inserted
  558. {
  559. Assert(pszRecipient != NULL);
  560. LV_ITEM lvItem;
  561. GarbageInit(OUT &lvItem, sizeof(lvItem));
  562. lvItem.mask = LVIF_TEXT | LVIF_IMAGE;
  563. lvItem.iSubItem = 0;
  564. lvItem.iImage = iImageComputer;
  565. lvItem.pszText = const_cast<TCHAR *>(pszRecipient);
  566. if (fSelectItem)
  567. {
  568. lvItem.mask = LVIF_TEXT | LVIF_IMAGE |LVIF_STATE;
  569. lvItem.state = LVIS_SELECTED;
  570. }
  571. return ListView_InsertItem(m_hwndListviewRecipients, IN &lvItem);
  572. } // CSendConsoleMessageDlg::AddRecipient()
  573. /////////////////////////////////////////////////////////////////////
  574. LRESULT CSendConsoleMessageDlg::OnNotify(NMHDR * pNmHdr)
  575. {
  576. Assert(pNmHdr != NULL);
  577. switch (pNmHdr->code)
  578. {
  579. case LVN_ENDLABELEDIT:
  580. {
  581. TCHAR * pszText = ((LV_DISPINFO *)pNmHdr)->item.pszText;
  582. if (pszText == NULL)
  583. break; // User canceled editing
  584. // HACK: Modifying a string which I'm not sure where it is allocated
  585. (void)FTrimString(INOUT pszText);
  586. // Check out if there is already another recipient
  587. int iItem = ListView_FindString(m_hwndListviewRecipients, pszText);
  588. if (iItem >= 0)
  589. {
  590. ListView_SelectItem(m_hwndListviewRecipients, iItem);
  591. DoMessageBox(IDS_RECIPIENT_ALREADY_EXISTS);
  592. break;
  593. }
  594. // Otherwise accept the changes
  595. SetWindowLongPtr(m_hdlg, DWLP_MSGRESULT, TRUE);
  596. return TRUE;
  597. }
  598. case LVN_ITEMCHANGED: // Selection changed
  599. UpdateUI();
  600. break;
  601. case LVN_KEYDOWN:
  602. switch (((LV_KEYDOWN *)pNmHdr)->wVKey)
  603. {
  604. case VK_INSERT:
  605. SendMessage(m_hdlg, WM_COMMAND, IDC_BUTTON_ADD_RECIPIENT, 0);
  606. break;
  607. case VK_DELETE:
  608. SendMessage(m_hdlg, WM_COMMAND, IDC_BUTTON_REMOVE_RECIPIENT, 0);
  609. break;
  610. } // switch
  611. break;
  612. case NM_CLICK:
  613. UpdateUI();
  614. break;
  615. case NM_DBLCLK:
  616. UpdateUI();
  617. break;
  618. } // switch
  619. return 0;
  620. } // CSendConsoleMessageDlg::OnNotify()
  621. /////////////////////////////////////////////////////////////////////
  622. void CSendConsoleMessageDlg::EnableDlgItem(INT nIdDlgItem, BOOL fEnable)
  623. {
  624. Assert(::IsWindow(::GetDlgItem(m_hdlg, nIdDlgItem)));
  625. ::EnableWindow(::GetDlgItem(m_hdlg, nIdDlgItem), fEnable);
  626. }
  627. /////////////////////////////////////////////////////////////////////
  628. void CSendConsoleMessageDlg::UpdateUI()
  629. {
  630. Assert(m_cRefCount > 0);
  631. int cchMessage = GetWindowTextLength(m_hwndEditMessageText);
  632. int cItems = ListView_GetItemCount(m_hwndListviewRecipients);
  633. EnableDlgItem(IDOK, (cchMessage > 0) && (cItems > 0) && (m_cRefCount == 1));
  634. int iItemSelected = ListView_GetSelectedItem(m_hwndListviewRecipients);
  635. EnableDlgItem(IDC_BUTTON_REMOVE_RECIPIENT, iItemSelected >= 0);
  636. UpdateWindow(m_hwndListviewRecipients);
  637. } // CSendConsoleMessageDlg::UpdateUI()
  638. /////////////////////////////////////////////////////////////////////
  639. // Dialog proc for the Send Console Message snapin.
  640. //
  641. // USAGE
  642. // DoDialogBox(IDD_SEND_CONSOLE_MESSAGE, ::GetActiveWindow(), CSendConsoleMessageDlg::DlgProc);
  643. //
  644. INT_PTR CSendConsoleMessageDlg::DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  645. {
  646. CSendConsoleMessageDlg * pThis;
  647. pThis = (CSendConsoleMessageDlg *)::GetWindowLongPtr(hdlg, GWLP_USERDATA);
  648. switch (uMsg)
  649. {
  650. case WM_INITDIALOG:
  651. Assert(pThis == NULL);
  652. if (pThis != NULL)
  653. return FALSE;
  654. pThis = new CSendConsoleMessageDlg;
  655. if (pThis == NULL)
  656. {
  657. Trace0("Unable to allocate CSendConsoleMessageDlg object.\n");
  658. return -1;
  659. }
  660. SetWindowLongPtr(hdlg, GWLP_USERDATA, (LONG_PTR)pThis);
  661. pThis->AddRef();
  662. pThis->OnInitDialog(hdlg, (IDataObject *)lParam);
  663. SendDlgItemMessage (hdlg, IDC_EDIT_MESSAGE_TEXT, EM_LIMITTEXT, 885, 0);
  664. return FALSE;
  665. case WM_NCDESTROY:
  666. ThreadTrace0("CSendConsoleMessageDlg::DlgProc() - WM_NCDESTROY.\n");
  667. EnterCriticalSection(INOUT &pThis->m_DispatchInfo.cs);
  668. pThis->m_hdlg = NULL;
  669. LeaveCriticalSection(INOUT &pThis->m_DispatchInfo.cs);
  670. pThis->Release();
  671. break;
  672. case WM_COMMAND:
  673. switch (LOWORD(wParam))
  674. {
  675. case IDOK:
  676. if (HIWORD(wParam) == BN_CLICKED)
  677. {
  678. Assert((HWND)lParam == GetDlgItem(hdlg, IDOK));
  679. pThis->OnOK();
  680. }
  681. break;
  682. case IDCANCEL:
  683. if (HIWORD(wParam) == BN_CLICKED)
  684. {
  685. Assert((HWND)lParam == GetDlgItem(hdlg, IDCANCEL));
  686. EndDialog(hdlg, FALSE);
  687. }
  688. break;
  689. case IDC_EDIT_MESSAGE_TEXT:
  690. if (HIWORD(wParam) == EN_CHANGE)
  691. pThis->UpdateUI();
  692. break;
  693. case IDC_BUTTON_ADD_RECIPIENT:
  694. {
  695. const int cbLen = MAX_PATH;
  696. PWSTR pszComputerName = new WCHAR[MAX_PATH];
  697. if ( pszComputerName )
  698. {
  699. // S_FALSE means user pressed "Cancel"
  700. if ( S_OK == ComputerNameFromObjectPicker (hdlg,
  701. pszComputerName, cbLen) )
  702. {
  703. pThis->AddRecipient (pszComputerName, TRUE);
  704. }
  705. delete [] pszComputerName;
  706. }
  707. pThis->UpdateUI();
  708. }
  709. break;
  710. case IDC_BUTTON_REMOVE_RECIPIENT:
  711. while (TRUE)
  712. {
  713. // Remove all the selected recipients
  714. int iItem = ListView_GetSelectedItem(pThis->m_hwndListviewRecipients);
  715. if (iItem < 0)
  716. break;
  717. ListView_DeleteItem(pThis->m_hwndListviewRecipients, iItem);
  718. }
  719. ::SetFocus(pThis->m_hwndListviewRecipients);
  720. pThis->UpdateUI();
  721. break;
  722. case IDC_BUTTON_ADVANCED:
  723. (void)DoDialogBox(IDD_ADVANCED_MESSAGE_OPTIONS, hdlg, (DLGPROC)CSendMessageAdvancedOptionsDlg::DlgProc);
  724. break;
  725. } // switch
  726. break;
  727. case WM_NOTIFY:
  728. Assert(wParam == IDC_LIST_RECIPIENTS);
  729. return pThis->OnNotify((NMHDR *)lParam);
  730. case WM_HELP:
  731. return pThis->OnHelp (lParam, IDD_SEND_CONSOLE_MESSAGE);
  732. default:
  733. return FALSE;
  734. } // switch
  735. return TRUE;
  736. } // CSendConsoleMessageDlg::DlgProc()
  737. /////////////////////////////////////////////////////////////////////
  738. // DlgProcDispatchMessageToRecipients()
  739. //
  740. // Private dialog to indicate the progress while a background
  741. // thread dispatches a message to each recipient.
  742. //
  743. INT_PTR CSendConsoleMessageDlg::DlgProcDispatchMessageToRecipients(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  744. {
  745. CSendConsoleMessageDlg * pThis = (CSendConsoleMessageDlg *)::GetWindowLongPtr(hdlg, GWLP_USERDATA);
  746. switch (uMsg)
  747. {
  748. case WM_INITDIALOG:
  749. Assert(pThis == NULL);
  750. if (pThis != NULL)
  751. return FALSE;
  752. pThis = (CSendConsoleMessageDlg *)lParam;
  753. SetWindowLongPtr(hdlg, GWLP_USERDATA, (LONG_PTR)pThis);
  754. Assert(pThis != NULL);
  755. Assert(pThis->m_DispatchInfo.status == e_statusDlgInit);
  756. pThis->m_DispatchInfo.hdlg = hdlg;
  757. pThis->m_DispatchInfo.hctlStaticRecipient = GetDlgItem(hdlg, IDC_STATIC_RECIPIENT);
  758. pThis->m_DispatchInfo.hctlStaticMessageOf = GetDlgItem(hdlg, IDC_STATIC_MESSAGE_OF);
  759. pThis->m_DispatchInfo.hctlStaticErrors = GetDlgItem(hdlg, IDC_STATIC_ERRORS_ENCOUNTERED);
  760. pThis->m_DispatchInfo.hctlProgressBar = GetDlgItem(hdlg, IDC_PROGRESS_MESSAGES);
  761. {
  762. DWORD dwThreadId;
  763. HANDLE hThread = ::CreateThread(NULL, 0,
  764. (LPTHREAD_START_ROUTINE)ThreadProcDispatchMessageToRecipients, pThis, 0, OUT &dwThreadId);
  765. Report(hThread != NULL && "Unable to create thread");
  766. if (hThread != NULL)
  767. {
  768. VERIFY( ::CloseHandle(hThread) );
  769. }
  770. else
  771. {
  772. Trace0("Unable to create thread.\n");
  773. // Prevent a potential deadlock
  774. pThis->m_DispatchInfo.status = e_statusUserCancel; // Pretend the user clicked on cancel
  775. EndDialog(hdlg, FALSE);
  776. }
  777. }
  778. break;
  779. case WM_DESTROY:
  780. // Those variables are set to NULL just in case
  781. pThis->m_DispatchInfo.hdlg = NULL;
  782. pThis->m_DispatchInfo.hctlStaticRecipient = NULL;
  783. pThis->m_DispatchInfo.hctlStaticMessageOf = NULL;
  784. pThis->m_DispatchInfo.hctlStaticErrors = NULL;
  785. pThis->m_DispatchInfo.hctlProgressBar = NULL;
  786. break;
  787. case WM_COMMAND:
  788. if (wParam == IDCANCEL)
  789. {
  790. Trace0("INFO: WM_COMMAND: IDCANCEL: User canceled operation.\n");
  791. BOOL fEndDialog = FALSE;
  792. if (TryEnterCriticalSection(INOUT &pThis->m_DispatchInfo.cs))
  793. {
  794. if (pThis->m_DispatchInfo.status != e_statusDlgInit)
  795. {
  796. pThis->m_DispatchInfo.status = e_statusUserCancel;
  797. fEndDialog = TRUE;
  798. }
  799. LeaveCriticalSection(INOUT &pThis->m_DispatchInfo.cs);
  800. }
  801. if (fEndDialog)
  802. {
  803. EndDialog(hdlg, FALSE);
  804. }
  805. else
  806. {
  807. ThreadTrace0("Critical section already in use. Try again...\n");
  808. PostMessage(hdlg, WM_COMMAND, IDCANCEL, 0);
  809. Sleep(100);
  810. } // if...else
  811. } // if
  812. break;
  813. case WM_HELP:
  814. return pThis->OnHelp (lParam, IDD_DISPATCH_MESSAGES);
  815. default:
  816. return FALSE;
  817. } // switch
  818. return TRUE;
  819. } // CSendConsoleMessageDlg::DlgProcDispatchMessageToRecipients()
  820. /////////////////////////////////////////////////////////////////////
  821. DWORD CSendConsoleMessageDlg::ThreadProcDispatchMessageToRecipients(CSendConsoleMessageDlg * pThis)
  822. {
  823. Assert(pThis != NULL);
  824. pThis->AddRef();
  825. Assert(pThis->m_cRefCount > 1);
  826. pThis->DispatchMessageToRecipients();
  827. pThis->Release();
  828. return 0;
  829. } // CSendConsoleMessageDlg::ThreadProcDispatchMessageToRecipients()
  830. #define IDH_EDIT_MESSAGE_TEXT 900
  831. #define IDH_LIST_RECIPIENTS 901
  832. #define IDH_BUTTON_ADD_RECIPIENT 903
  833. #define IDH_BUTTON_REMOVE_RECIPIENT 904
  834. const DWORD g_aHelpIDs_IDD_SEND_CONSOLE_MESSAGE[]=
  835. {
  836. IDC_EDIT_MESSAGE_TEXT, IDH_EDIT_MESSAGE_TEXT,
  837. IDOK, IDOK,
  838. IDC_LIST_RECIPIENTS, IDH_LIST_RECIPIENTS,
  839. IDC_BUTTON_ADD_RECIPIENT, IDH_BUTTON_ADD_RECIPIENT,
  840. IDC_BUTTON_REMOVE_RECIPIENT, IDH_BUTTON_REMOVE_RECIPIENT,
  841. 0, 0
  842. };
  843. BOOL CSendConsoleMessageDlg::OnHelp(LPARAM lParam, int nDlgIDD)
  844. {
  845. const LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  846. if (pHelpInfo && pHelpInfo->iContextType == HELPINFO_WINDOW)
  847. {
  848. switch (nDlgIDD)
  849. {
  850. case IDD_SEND_CONSOLE_MESSAGE:
  851. DoSendConsoleMessageContextHelp ((HWND) pHelpInfo->hItemHandle);
  852. break;
  853. }
  854. }
  855. else
  856. HtmlHelpW (NULL, HTML_HELP_FILE, HH_DISPLAY_TOPIC, 0);
  857. return TRUE;
  858. }
  859. void CSendConsoleMessageDlg::DoSendConsoleMessageContextHelp (HWND hWndControl)
  860. {
  861. switch (::GetDlgCtrlID (hWndControl))
  862. {
  863. case IDCANCEL:
  864. case IDC_BUTTON_ADVANCED:
  865. break;
  866. default:
  867. // Display context help for a control
  868. if ( !::WinHelp (
  869. hWndControl,
  870. CONTEXT_HELP_FILE,
  871. HELP_WM_HELP,
  872. (DWORD_PTR) g_aHelpIDs_IDD_SEND_CONSOLE_MESSAGE) )
  873. {
  874. Trace1 ("WinHelp () failed: 0x%x\n", GetLastError ());
  875. }
  876. break;
  877. }
  878. }
  879. /////////////////////////////////////////////////////////////////////
  880. /////////////////////////////////////////////////////////////////////
  881. void CSendMessageAdvancedOptionsDlg::OnInitDialog(HWND hdlg)
  882. {
  883. m_hdlg = hdlg;
  884. m_fSendAutomatedMessage = FALSE;
  885. CheckDlgButton(m_hdlg, IDC_CHECK_SEND_AUTOMATED_MESSAGE, m_fSendAutomatedMessage);
  886. UpdateUI();
  887. }
  888. /////////////////////////////////////////////////////////////////////
  889. void CSendMessageAdvancedOptionsDlg::UpdateUI()
  890. {
  891. static const UINT rgid[] =
  892. {
  893. IDC_STATIC_RESOURCE_NAME,
  894. IDC_EDIT_RESOURCE_NAME,
  895. IDC_STATIC_SHUTDOWN_OCCURS,
  896. IDC_EDIT_SHUTDOWN_OCCURS,
  897. //IDC_SPIN_SHUTDOWN_OCCURS,
  898. IDC_STATIC_SHUTDOWN_OCCURS_UNIT,
  899. IDC_STATIC_RESEND,
  900. IDC_EDIT_RESEND,
  901. //IDC_SPIN_RESEND,
  902. IDC_STATIC_RESEND_UNIT,
  903. IDC_STATIC_RESOURCE_BACK_ONLINE,
  904. IDC_EDIT_RESOURCE_BACK_ONLINE,
  905. };
  906. for (int i = 0; i < LENGTH(rgid); i++)
  907. {
  908. EnableWindow(GetDlgItem(m_hdlg, rgid[i]), m_fSendAutomatedMessage);
  909. }
  910. } // CSendMessageAdvancedOptionsDlg::UpdateUI()
  911. /////////////////////////////////////////////////////////////////////
  912. INT_PTR CSendMessageAdvancedOptionsDlg::DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM /*lParam*/)
  913. {
  914. CSendMessageAdvancedOptionsDlg * pThis;
  915. pThis = (CSendMessageAdvancedOptionsDlg *)GetWindowLongPtr(hdlg, GWLP_USERDATA);
  916. switch (uMsg)
  917. {
  918. case WM_INITDIALOG:
  919. Assert(pThis == NULL);
  920. pThis = new CSendMessageAdvancedOptionsDlg;
  921. if (pThis == NULL)
  922. return -1;
  923. SetWindowLongPtr(hdlg, GWLP_USERDATA, (LONG_PTR)pThis);
  924. pThis->OnInitDialog(hdlg);
  925. break;
  926. case WM_COMMAND:
  927. switch (wParam)
  928. {
  929. case IDOK:
  930. EndDialog(hdlg, TRUE);
  931. break;
  932. case IDCANCEL:
  933. EndDialog(hdlg, FALSE);
  934. break;
  935. case IDC_CHECK_SEND_AUTOMATED_MESSAGE:
  936. pThis->m_fSendAutomatedMessage = IsDlgButtonChecked(hdlg, IDC_CHECK_SEND_AUTOMATED_MESSAGE);
  937. pThis->UpdateUI();
  938. break;
  939. } // switch
  940. break;
  941. default:
  942. return FALSE;
  943. } // switch
  944. return TRUE;
  945. } // CSendMessageAdvancedOptionsDlg::DlgProc()
  946. BOOL CSendMessageAdvancedOptionsDlg::OnHelp(LPARAM /*lParam*/)
  947. {
  948. HtmlHelpW (NULL, HTML_HELP_FILE, HH_DISPLAY_TOPIC, 0);
  949. return TRUE;
  950. }