PageChat.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. /////////////////////////////////////////////////////////////////////////////
  2. // PageChat.cpp : implementation file
  3. //
  4. #include "stdafx.h"
  5. #include "AllSrvUI.h"
  6. #include "AllSrvUISheet.h"
  7. #include "DlgChatPreferences.h"
  8. #include "PageChat.h"
  9. #include "AdminPageThreadWnd.h"
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15. /////////////////////////////////////////////////////////////////////////////
  16. // CPageChat property page
  17. IMPLEMENT_DYNAMIC(CPageChat, CPropertyPage)
  18. /////////////////////////////////////////////////////////////////////////////
  19. // Static Initializtion
  20. BEGIN_AUTO_SIZER_MAP(_AutoSizerMap)
  21. AUTO_SIZER_ENTRY(IDC_CHAT_LIST_CLEAR , LeftRight, 0, Right, NoRefresh)
  22. AUTO_SIZER_ENTRY(IDC_CHAT_LIST_CLEAR , TopBottom, 0, Bottom, NoRefresh)
  23. AUTO_SIZER_ENTRY(IDC_CHAT_PREFERENCES , TopBottom, 0, Bottom, NoRefresh)
  24. AUTO_SIZER_ENTRY(IDC_SEND_CHAT_CAPTION , TopBottom, 0, Bottom, NoRefresh)
  25. AUTO_SIZER_ENTRY(IDC_SEND_CHAT_TEXT , Right, 0, Right, NoRefresh)
  26. AUTO_SIZER_ENTRY(IDC_SEND_CHAT_TEXT , TopBottom, 0, Bottom, NoRefresh)
  27. AUTO_SIZER_ENTRY(IDC_SEND_CHAT_ALL_GAMES, LeftRight, 0, Right, NoRefresh)
  28. AUTO_SIZER_ENTRY(IDC_SEND_CHAT_ALL_GAMES, TopBottom, 0, Bottom, NoRefresh)
  29. AUTO_SIZER_ENTRY(IDC_CHAT_LIST , Right, 0, Right, NoRefresh)
  30. AUTO_SIZER_ENTRY(IDC_CHAT_LIST , Bottom, 0, Bottom, NoRefresh)
  31. END_AUTO_SIZER_MAP()
  32. /////////////////////////////////////////////////////////////////////////////
  33. // Message Map
  34. BEGIN_MESSAGE_MAP(CPageChat, CPropertyPage)
  35. //{{AFX_MSG_MAP(CPageChat)
  36. ON_NOTIFY(HDN_ENDDRAG, 0, OnEndDragChatList)
  37. ON_NOTIFY(HDN_ENDTRACK, 0, OnEndTrackChatList)
  38. ON_BN_CLICKED(IDC_CHAT_PREFERENCES, OnChatPreferences)
  39. ON_BN_CLICKED(IDC_CHAT_LIST_CLEAR, OnChatListClear)
  40. ON_WM_DESTROY()
  41. ON_WM_TIMER()
  42. ON_BN_CLICKED(IDC_SEND_CHAT_ALL_GAMES, OnSendChatAllGames)
  43. //}}AFX_MSG_MAP
  44. END_MESSAGE_MAP()
  45. /////////////////////////////////////////////////////////////////////////////
  46. // Construction
  47. CPageChat::CPageChat() :
  48. CPropertyPage(CPageChat::IDD),
  49. m_Prefs(this),
  50. m_bAdminPageActivated(false),
  51. m_bChatActivated(false),
  52. m_pthAdminPageMsg(NULL),
  53. m_pthAdminPageRun(NULL),
  54. m_pWndAdminPageMsgThread(NULL),
  55. m_pWndAdminPageRunThread(NULL)
  56. {
  57. //{{AFX_DATA_INIT(CPageChat)
  58. m_strSendChat = _T("");
  59. m_bSendChatAllGames = FALSE;
  60. //}}AFX_DATA_INIT
  61. // Create a TCObj.Strings object
  62. HRESULT hr = m_spStrings.CreateInstance("TCObj.Strings");
  63. if (FAILED(hr))
  64. GetSheet()->HandleError(hr, "creating TCObj.Strings helper object", true);
  65. }
  66. /////////////////////////////////////////////////////////////////////////////
  67. // Attributes
  68. /////////////////////////////////////////////////////////////////////////////
  69. // Overrides
  70. void CPageChat::OnEvent(IAGCEvent* pEvent)
  71. {
  72. AGCEventID eEvent;
  73. if (FAILED(pEvent->get_ID(&eEvent)))
  74. return;
  75. switch (eEvent)
  76. {
  77. case EventID_GameCreated:
  78. case EventID_GameDestroyed:
  79. {
  80. UpdateUI();
  81. break;
  82. }
  83. case EventID_ChatMessage:
  84. case EventID_AdminPage:
  85. {
  86. // Determine if this is an Admin alert
  87. bool bAdminAlert = EventID_AdminPage == eEvent;
  88. // Get the GameID parameter of the event
  89. CComVariant varGameID;
  90. if (FAILED(pEvent->get_Property(&CComVariant(L"GameID"), &varGameID)))
  91. return;
  92. if (VT_BSTR != V_VT(&varGameID) || 0 != _wcsicmp(V_BSTR(&varGameID), L"TEST"))
  93. {
  94. varGameID.ChangeType(VT_I4);
  95. // Get the current GameID
  96. if (!GetSheet()->GetGame())
  97. return;
  98. AGCGameID idGame = 0;
  99. if (FAILED(GetSheet()->GetGame()->get_GameID(&idGame)))
  100. return;
  101. // Ignore chats not for this game
  102. if (idGame != V_I4(&varGameID))
  103. return;
  104. }
  105. // Add the chat to the list control
  106. if (!bAdminAlert || m_Prefs.m_bAdminChatList)
  107. {
  108. // Extract the event parameters
  109. CComBSTR bstrSender, bstrTarget, bstrMessage;
  110. if (FAILED(pEvent->get_SubjectName(&bstrSender)))
  111. return;
  112. CComVariant varTarget, varMessage;
  113. if (FAILED(pEvent->get_Property(&CComVariant(L"Target"), &varTarget)))
  114. return;
  115. if (FAILED(pEvent->get_Property(&CComVariant(L"Message"), &varMessage)))
  116. return;
  117. varTarget.ChangeType(VT_BSTR);
  118. bstrTarget = V_BSTR(&varTarget);
  119. varMessage.ChangeType(VT_BSTR);
  120. bstrMessage = V_BSTR(&varMessage);
  121. // Get the current item count
  122. int cItems = m_listChat.GetItemCount();
  123. // Determine if the last item in the list is visible
  124. int nLastPlus = m_listChat.GetTopIndex() + m_listChat.GetCountPerPage();
  125. bool bLastWasVisible = nLastPlus >= cItems;
  126. // Add the new item to the end
  127. USES_CONVERSION;
  128. int iIndex = cItems;
  129. m_listChat.InsertItem(iIndex, OLE2CT(bstrSender));
  130. m_listChat.SetItemText(iIndex, c_iColumnTarget, OLE2CT(bstrTarget));
  131. m_listChat.SetItemText(iIndex, c_iColumnMessage, OLE2CT(bstrMessage));
  132. // Make last item visible if last was previously
  133. if (bLastWasVisible)
  134. m_listChat.EnsureVisible(iIndex, false);
  135. }
  136. // Trim the size of the list if it has more than limit
  137. TrimExcessChats();
  138. // Was this an admin alert?
  139. if (bAdminAlert)
  140. {
  141. // Check preferences
  142. if (m_Prefs.m_bAdminMessageBox)
  143. m_pWndAdminPageMsgThread->PostAdminPageMsg(pEvent);
  144. if (m_Prefs.m_bAdminRun)
  145. m_pWndAdminPageRunThread->PostAdminPageRun(pEvent);
  146. }
  147. break;
  148. }
  149. }
  150. }
  151. BOOL CPageChat::OnSetActive()
  152. {
  153. // Reload the chat MRU from the registry
  154. LoadFromRegistry();
  155. // Update the UI
  156. UpdateUI();
  157. // Perform default processing
  158. return CPropertyPage::OnSetActive();
  159. }
  160. BOOL CPageChat::PreTranslateMessage(MSG* pMsg)
  161. {
  162. if (WM_KEYDOWN == pMsg->message)
  163. {
  164. if (VK_RETURN == pMsg->wParam)
  165. {
  166. if (&m_comboSendChat == GetFocus() ||
  167. &m_comboSendChat == GetFocus()->GetParent())
  168. {
  169. SendChat();
  170. return true;
  171. }
  172. }
  173. }
  174. // Perform default processing
  175. return CPropertyPage::PreTranslateMessage(pMsg);
  176. }
  177. void CPageChat::DoDataExchange(CDataExchange* pDX)
  178. {
  179. // Perform default processing
  180. CPropertyPage::DoDataExchange(pDX);
  181. //{{AFX_DATA_MAP(CPageChat)
  182. DDX_Control(pDX, IDC_SEND_CHAT_ALL_GAMES, m_btnSendChatAllGames);
  183. DDX_Control(pDX, IDC_CHAT_LIST, m_listChat);
  184. DDX_Control(pDX, IDC_SEND_CHAT_CAPTION, m_staticSendChat);
  185. DDX_Control(pDX, IDC_SEND_CHAT_TEXT, m_comboSendChat);
  186. DDX_CBString(pDX, IDC_SEND_CHAT_TEXT, m_strSendChat);
  187. DDX_Check(pDX, IDC_SEND_CHAT_ALL_GAMES, m_bSendChatAllGames);
  188. //}}AFX_DATA_MAP
  189. }
  190. LRESULT CPageChat::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  191. {
  192. LRESULT lr;
  193. if (m_AutoSizer.ProcessMessage(message, wParam, lParam, &lr))
  194. return lr;
  195. // Perform default processing
  196. return CPropertyPage::WindowProc(message, wParam, lParam);
  197. }
  198. /////////////////////////////////////////////////////////////////////////////
  199. // Implementation
  200. void CPageChat::LoadFromRegistry()
  201. {
  202. // Allow the Preferences dialog to load its registry first
  203. m_Prefs.LoadFromRegistry();
  204. // Open/create the registry key
  205. CRegKey key;
  206. key.Create(HKEY_LOCAL_MACHINE, HKLM_AllSrvUI);
  207. // ChatListColumnOrder
  208. CComBSTR bstrColumnOrder;
  209. LoadRegString(key, TEXT("ChatListColumnOrder"), bstrColumnOrder);
  210. m_spStrings->RemoveAll();
  211. m_spStrings->AddDelimited(CComBSTR(L","), bstrColumnOrder);
  212. long cOrderedColumns = 0;
  213. m_spStrings->get_Count(&cOrderedColumns);
  214. if (c_cColumns == cOrderedColumns)
  215. {
  216. int vecOrder[c_cColumns];
  217. for (CComVariant i(0L); V_I4(&i) < c_cColumns; ++V_I4(&i))
  218. {
  219. bstrColumnOrder.Empty();
  220. m_spStrings->get_Item(&i, &bstrColumnOrder);
  221. vecOrder[V_I4(&i)] = _wtoi(bstrColumnOrder);
  222. }
  223. m_listChat.SetColumnOrderArray(c_cColumns, vecOrder);
  224. }
  225. // ChatListColumnWidths
  226. CComBSTR bstrColumnWidths;
  227. LoadRegString(key, TEXT("ChatListColumnWidths"), bstrColumnWidths);
  228. m_spStrings->RemoveAll();
  229. m_spStrings->AddDelimited(CComBSTR(L","), bstrColumnWidths);
  230. long cWidthColumns = 0;
  231. m_spStrings->get_Count(&cWidthColumns);
  232. if (c_cColumns == cWidthColumns)
  233. {
  234. for (CComVariant i(0L); V_I4(&i) < c_cColumns; ++V_I4(&i))
  235. {
  236. bstrColumnWidths.Empty();
  237. m_spStrings->get_Item(&i, &bstrColumnWidths);
  238. m_listChat.SetColumnWidth(V_I4(&i), _wtoi(bstrColumnWidths));
  239. }
  240. }
  241. else
  242. {
  243. for (int i = 0; i < c_cColumns; ++i)
  244. {
  245. TCHAR szColumn[_MAX_PATH];
  246. LVCOLUMN lvc = {LVCF_TEXT, 0, 0, szColumn, sizeofArray(szColumn)};
  247. m_listChat.GetColumn(i, &lvc);
  248. int cx = m_listChat.GetStringWidth(CString(szColumn) + TEXT(" "));
  249. m_listChat.SetColumnWidth(i, cx);
  250. }
  251. }
  252. // SendChatMRU
  253. m_comboSendChat.ResetContent();
  254. CRegKey keyMRU;
  255. if (ERROR_SUCCESS == keyMRU.Create(key, TEXT("SendChatMRU")))
  256. {
  257. // Read the count of strings
  258. DWORD cStrings = 0;
  259. keyMRU.QueryValue(cStrings, TEXT(".Count"));
  260. // Read each string and add it to the combo box
  261. for (DWORD i = 0; i < cStrings; ++i)
  262. {
  263. TCHAR szInt[16];
  264. CString strMRUItem;
  265. LoadRegString(keyMRU, _itot(i, szInt, 10), strMRUItem);
  266. strMRUItem.TrimLeft();
  267. strMRUItem.TrimRight();
  268. if (!strMRUItem.IsEmpty())
  269. m_comboSendChat.InsertString(i, strMRUItem);
  270. }
  271. }
  272. // SendChatAllGames
  273. DWORD dwSendChatAllGames = 0;
  274. key.QueryValue(dwSendChatAllGames, TEXT("SendChatAllGames"));
  275. m_bSendChatAllGames = !!dwSendChatAllGames;
  276. }
  277. void CPageChat::SaveChatListColumnOrderToRegistry()
  278. {
  279. // Open/create the registry key
  280. CRegKey key;
  281. key.Create(HKEY_LOCAL_MACHINE, HKLM_AllSrvUI);
  282. // Get the current column ordering
  283. int vecOrder[c_cColumns];
  284. for (int iCol = 0; iCol < c_cColumns; ++iCol)
  285. vecOrder[iCol] = iCol;
  286. m_listChat.GetColumnOrderArray(vecOrder, c_cColumns);
  287. // Format a comma-delimited string of the column ordering
  288. CString strColumnOrder;
  289. for (int i = 0; i < c_cColumns; ++i)
  290. {
  291. if (i)
  292. strColumnOrder += ",";
  293. TCHAR szNum[16];
  294. strColumnOrder += _itot(vecOrder[i], szNum, 10);
  295. }
  296. // Save to the registry
  297. key.SetValue(strColumnOrder, TEXT("ChatListColumnOrder"));
  298. }
  299. void CPageChat::SaveChatListColumnWidthsToRegistry()
  300. {
  301. // Open/create the registry key
  302. CRegKey key;
  303. key.Create(HKEY_LOCAL_MACHINE, HKLM_AllSrvUI);
  304. // Get the column header of the chat list
  305. CHeaderCtrl* pHeader = m_listChat.GetHeaderCtrl();
  306. // Format a comma-delimited string of the column widths
  307. CString strColumnWidths;
  308. for (int i = 0; i < c_cColumns; ++i)
  309. {
  310. HDITEM hdi = {HDI_WIDTH};
  311. pHeader->GetItem(i, &hdi);
  312. if (i)
  313. strColumnWidths += ",";
  314. TCHAR szNum[16];
  315. strColumnWidths += _itot(hdi.cxy, szNum, 10);
  316. }
  317. // Save to the registry
  318. key.SetValue(strColumnWidths, TEXT("ChatListColumnWidths"));
  319. }
  320. void CPageChat::SaveSendChatMRUToRegistry()
  321. {
  322. // Open/create the registry key
  323. CRegKey key;
  324. if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, HKLM_AllSrvUI))
  325. return;
  326. // SendChatMRU
  327. CRegKey keyMRU;
  328. if (ERROR_SUCCESS != keyMRU.Create(key, TEXT("SendChatMRU")))
  329. return;
  330. // Write the count of strings
  331. int cStrings = min(m_comboSendChat.GetCount(), c_cMaxChatsInRegistry);
  332. keyMRU.SetValue(cStrings, TEXT(".Count"));
  333. // Write each string
  334. for (int i = 0; i < cStrings; ++i)
  335. {
  336. TCHAR szInt[16];
  337. CString strMRUItem;
  338. m_comboSendChat.GetLBText(i, strMRUItem);
  339. keyMRU.SetValue(strMRUItem, _itot(i, szInt, 10));
  340. }
  341. }
  342. void CPageChat::SaveSendChatAllGames()
  343. {
  344. // Open/create the registry key
  345. CRegKey key;
  346. if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, HKLM_AllSrvUI))
  347. return;
  348. // SendChatAllGames
  349. DWORD dwSendChatAllGames = m_bSendChatAllGames;
  350. key.SetValue(dwSendChatAllGames, TEXT("SendChatAllGames"));
  351. }
  352. void CPageChat::TrimExcessChats()
  353. {
  354. // Only trim if there is a limit
  355. if (m_Prefs.m_dwChatListLimit)
  356. {
  357. int cExcess = m_listChat.GetItemCount() - m_Prefs.m_dwChatListLimit;
  358. if (cExcess > 0)
  359. {
  360. m_listChat.SetRedraw(false);
  361. while (cExcess--)
  362. m_listChat.DeleteItem(0);
  363. m_listChat.SetRedraw(true);
  364. m_listChat.Invalidate();
  365. }
  366. }
  367. }
  368. void CPageChat::UpdateActivateAdminPage()
  369. {
  370. bool bAdminPageMonitored = m_Prefs.IsAdminPageMonitored();
  371. if (!m_bAdminPageActivated != !bAdminPageMonitored)
  372. {
  373. // Activate/deactivate the event notification
  374. if (bAdminPageMonitored)
  375. GetSheet()->GetSession()->ActivateEvents(EventID_AdminPage, -1);
  376. else
  377. GetSheet()->GetSession()->DeactivateEvents(EventID_AdminPage, -1);
  378. m_bAdminPageActivated = bAdminPageMonitored;
  379. }
  380. }
  381. void CPageChat::UpdateActivateChatMessage()
  382. {
  383. bool bChatMonitored = m_Prefs.IsChatMonitored();
  384. if (!m_bChatActivated != !bChatMonitored)
  385. {
  386. // Activate/deactivate the event notification
  387. if (bChatMonitored)
  388. GetSheet()->GetSession()->ActivateEvents(EventID_ChatMessage, -1);
  389. else
  390. GetSheet()->GetSession()->DeactivateEvents(EventID_ChatMessage, -1);
  391. m_bChatActivated = bChatMonitored;
  392. }
  393. }
  394. void CPageChat::UpdateUI(bool bUpdateData)
  395. {
  396. // Update data members from fields, if specified
  397. if (bUpdateData)
  398. UpdateData();
  399. // Determine if a game is in progress or not
  400. bool bGameInProgress = NULL != GetSheet()->GetGame();
  401. // Enable/disable the controls as needed
  402. m_staticSendChat.EnableWindow(bGameInProgress);
  403. m_comboSendChat.EnableWindow(bGameInProgress);
  404. }
  405. void CPageChat::SendChat()
  406. {
  407. // Update data members from fields
  408. UpdateData();
  409. // Send the chat message to the game
  410. m_strSendChat.TrimLeft();
  411. m_strSendChat.TrimRight();
  412. if (!m_strSendChat.IsEmpty())
  413. {
  414. // Look for the text in the MRU list
  415. int iFound = m_comboSendChat.FindStringExact(-1, m_strSendChat);
  416. if (iFound >= 0)
  417. m_comboSendChat.DeleteString(iFound);
  418. // Insert the string at the top of the combo box list
  419. m_comboSendChat.InsertString(0, m_strSendChat);
  420. // Limit the number of chats in the MRU combo
  421. int cStrings;
  422. do
  423. {
  424. cStrings = m_comboSendChat.GetCount();
  425. if (cStrings > c_cMaxChatsInRegistry)
  426. {
  427. m_comboSendChat.DeleteString(cStrings - 1);
  428. }
  429. } while (cStrings > c_cMaxChatsInRegistry);
  430. // Send the chat to current game or all games, as specified
  431. CComBSTR bstrText(m_strSendChat);
  432. if (m_bSendChatAllGames && GetSheet()->IsServerInMultiMode())
  433. GetSheet()->GetServer()->SendMsg(bstrText);
  434. else
  435. GetSheet()->GetGame()->SendChat(bstrText, -1);
  436. // Clear the string
  437. m_strSendChat.Empty();
  438. UpdateData(false);
  439. // Update the MRU list
  440. SaveSendChatMRUToRegistry();
  441. }
  442. }
  443. UINT CPageChat::AdminPageMsgThreadThunk(void* pvParam)
  444. {
  445. // Enter this thread into a COM STA
  446. CoInitialize(NULL);
  447. // Reinterpret the specified parameter as a 'this' pointer
  448. CPageChat* pThis = reinterpret_cast<CPageChat*>(pvParam);
  449. // Call through the pointer
  450. pThis->AdminPageMsgThreadProc();
  451. // Shutdown the STA
  452. CoUninitialize();
  453. // Obligatory return code
  454. return 0;
  455. }
  456. UINT CPageChat::AdminPageRunThreadThunk(void* pvParam)
  457. {
  458. // Enter this thread into a COM STA
  459. CoInitialize(NULL);
  460. // Reinterpret the specified parameter as a 'this' pointer
  461. CPageChat* pThis = reinterpret_cast<CPageChat*>(pvParam);
  462. // Call through the pointer
  463. pThis->AdminPageRunThreadProc();
  464. // Shutdown the STA
  465. CoUninitialize();
  466. // Obligatory return code
  467. return 0;
  468. }
  469. void CPageChat::AdminPageMsgThreadProc()
  470. {
  471. // Get the main window handle
  472. HWND hwnd = GetSafeHwnd();
  473. // Create a window on this thread
  474. CAdminPageThreadWnd wnd;
  475. wnd.Create();
  476. m_pWndAdminPageMsgThread = &wnd;
  477. // Signal that we've initialized
  478. m_evtAdminPageMsgThreadStartup.SetEvent();
  479. // Enter a message loop
  480. MSG msg;
  481. while (::GetMessage(&msg, NULL, 0, 0))
  482. {
  483. ::TranslateMessage(&msg);
  484. ::DispatchMessage(&msg);
  485. }
  486. // Clear the window pointer
  487. m_pWndAdminPageMsgThread = NULL;
  488. }
  489. void CPageChat::AdminPageRunThreadProc()
  490. {
  491. // Get the main window handle
  492. HWND hwnd = GetSafeHwnd();
  493. // Create a window on this thread
  494. CAdminPageThreadWnd wnd;
  495. wnd.Create(m_Prefs.m_strShortcutPath);
  496. m_pWndAdminPageRunThread = &wnd;
  497. // Signal that we've initialized
  498. m_evtAdminPageRunThreadStartup.SetEvent();
  499. // Enter a message loop
  500. MSG msg;
  501. while (::GetMessage(&msg, NULL, 0, 0))
  502. {
  503. ::TranslateMessage(&msg);
  504. ::DispatchMessage(&msg);
  505. }
  506. // Clear the window pointer
  507. m_pWndAdminPageRunThread = NULL;
  508. }
  509. /////////////////////////////////////////////////////////////////////////////
  510. // Message Handlers
  511. BOOL CPageChat::OnInitDialog()
  512. {
  513. // Register for events of interest
  514. GetSheet()->GetSession()->ActivateEvents(EventID_GameDestroyed, -1);
  515. // Perform default processing
  516. CPropertyPage::OnInitDialog();
  517. // Initialize the AutoSize object
  518. m_AutoSizer.SetWindowAndRules(*this, _AutoSizerMap);
  519. // Show/hide buttons depending on server mode
  520. bool bMultiMode = GetSheet()->IsServerInMultiMode();
  521. m_btnSendChatAllGames.ShowWindow(bMultiMode ? SW_SHOW : SW_HIDE);
  522. m_btnSendChatAllGames.EnableWindow(bMultiMode);
  523. // Create worker threads
  524. m_pthAdminPageMsg = AfxBeginThread(AdminPageMsgThreadThunk, this,
  525. THREAD_PRIORITY_NORMAL, 4096);
  526. m_pthAdminPageRun = AfxBeginThread(AdminPageRunThreadThunk, this,
  527. THREAD_PRIORITY_NORMAL, 4096);
  528. _ASSERTE(m_pthAdminPageMsg);
  529. _ASSERTE(m_pthAdminPageRun);
  530. // Allow threads time to get our window handle and initialize USER32
  531. HANDLE phEvents[] =
  532. {
  533. m_evtAdminPageMsgThreadStartup,
  534. m_evtAdminPageRunThreadStartup,
  535. };
  536. const DWORD c_cEvents = sizeofArray(phEvents);
  537. WaitForMultipleObjects(c_cEvents, phEvents, true, INFINITE);
  538. // Set the list view control extended styles
  539. DWORD dwExStyle = LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP;
  540. m_listChat.SetExtendedStyle(dwExStyle);
  541. // Add columns to the list view control
  542. m_listChat.InsertColumn(0, CString((LPCSTR)IDS_COLUMN_SENDER ));
  543. m_listChat.InsertColumn(1, CString((LPCSTR)IDS_COLUMN_TARGET ));
  544. m_listChat.InsertColumn(2, CString((LPCSTR)IDS_COLUMN_MESSAGE));
  545. // Load previous values from registry
  546. LoadFromRegistry();
  547. // Register for necessary admin/chat events
  548. UpdateActivateAdminPage();
  549. UpdateActivateChatMessage();
  550. // Update fields from data members
  551. UpdateData(false);
  552. // Update the UI
  553. UpdateUI();
  554. // Set the focus to the SendChat combo box
  555. m_comboSendChat.SetFocus();
  556. return false;
  557. }
  558. void CPageChat::OnEndDragChatList(NMHDR* pNMHDR, LRESULT* pResult)
  559. {
  560. HD_NOTIFY* phdn = (HD_NOTIFY*)pNMHDR;
  561. if (pNMHDR->hwndFrom != m_listChat.GetHeaderCtrl()->GetSafeHwnd())
  562. return;
  563. // Defer saving the new column ordering until controls have updated
  564. KillTimer(c_idTimerReorder);
  565. SetTimer(c_idTimerReorder, c_dwDelayReorder, NULL);
  566. *pResult = 0;
  567. }
  568. void CPageChat::OnEndTrackChatList(NMHDR* pNMHDR, LRESULT* pResult)
  569. {
  570. HD_NOTIFY* phdn = (HD_NOTIFY*)pNMHDR;
  571. if (pNMHDR->hwndFrom != m_listChat.GetHeaderCtrl()->GetSafeHwnd())
  572. return;
  573. // Defer saving the new column widths until controls have updated
  574. KillTimer(c_idTimerResize);
  575. SetTimer(c_idTimerResize, c_dwDelayResize, NULL);
  576. *pResult = 0;
  577. }
  578. void CPageChat::OnChatPreferences()
  579. {
  580. // Display the Chat Preferences dialog box
  581. int nResponse = m_Prefs.DoModal();
  582. if (IDCANCEL == nResponse)
  583. return;
  584. // Trim the size of the list if it has more than new limit
  585. TrimExcessChats();
  586. // Register for necessary admin/chat events
  587. UpdateActivateAdminPage();
  588. UpdateActivateChatMessage();
  589. }
  590. void CPageChat::OnChatListClear()
  591. {
  592. m_listChat.SetRedraw(false);
  593. m_listChat.DeleteAllItems();
  594. m_listChat.SetRedraw(true);
  595. m_listChat.Invalidate();
  596. }
  597. void CPageChat::OnDestroy()
  598. {
  599. // Get the worker thread handles
  600. HANDLE phObjects[] =
  601. {
  602. m_pthAdminPageMsg->m_hThread,
  603. m_pthAdminPageRun->m_hThread,
  604. };
  605. const DWORD c_cObjects = sizeofArray(phObjects);
  606. // Tell each thread to exit
  607. m_pthAdminPageMsg->PostThreadMessage(WM_QUIT, 0, 0);
  608. m_pthAdminPageRun->PostThreadMessage(WM_QUIT, 0, 0);
  609. // Wait a reasonable amount of time for the threads to exit
  610. const DWORD c_dwTimeout = 5000;
  611. WaitForMultipleObjects(c_cObjects, phObjects, true, c_dwTimeout);
  612. // Perform default processing
  613. CPropertyPage::OnDestroy();
  614. }
  615. void CPageChat::OnTimer(UINT nIDEvent)
  616. {
  617. switch (nIDEvent)
  618. {
  619. case c_idTimerReorder:
  620. KillTimer(nIDEvent);
  621. SaveChatListColumnOrderToRegistry();
  622. return;
  623. case c_idTimerResize:
  624. KillTimer(nIDEvent);
  625. SaveChatListColumnWidthsToRegistry();
  626. return;
  627. }
  628. // Perform default processing
  629. CPropertyPage::OnTimer(nIDEvent);
  630. }
  631. void CPageChat::OnSendChatAllGames()
  632. {
  633. // Update data members from fields
  634. UpdateData();
  635. // Update the registry
  636. SaveSendChatAllGames();
  637. }