FSMon.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. #define INITGUID
  2. #include <windows.h>
  3. #include <windowsx.h>
  4. #include <dplobby.h>
  5. #include "resource.h"
  6. // {81662310-FCB4-11d0-A88A-006097B58FBF}
  7. DEFINE_GUID(FEDSRV_GUID,
  8. 0x81662310, 0xfcb4, 0x11d0, 0xa8, 0x8a, 0x0, 0x60, 0x97, 0xb5, 0x8f, 0xbf);
  9. #define WM_MOUSEINTRAY WM_USER + 1
  10. HICON hIconUp, hIconDown, hIconInit, hIconBoth;
  11. HINSTANCE hInst;
  12. const int c_cSrvMax = 10;
  13. int g_cSrv = 0; // how many servers we're monitoring
  14. int g_iSrvDlg = 0; // what the current server in the dialog is
  15. int g_iSrvCur = 0; // what the current server is that we're querying
  16. const int c_cbServer = 32;
  17. char rgszServer[c_cSrvMax][c_cbServer];
  18. int secInterval = 60; // I'm sorry, but I'm not going to have separate intervals for each server
  19. const char * const SzAppName = "FSMon";
  20. HWND hWnd;
  21. NOTIFYICONDATA nid;
  22. IDirectPlay3A * pDirectPlay3A[c_cSrvMax];
  23. IDirectPlayLobby * pDirectPlayLobbyA;
  24. bool fDPInit[c_cSrvMax];
  25. char * const gszMsgInit = "Initializing...";
  26. char * gszMsg = gszMsgInit;
  27. enum State {FS_UP, FS_DOWN, FS_INIT, FS_BOTH};
  28. State gState[c_cSrvMax];
  29. DWORD gdwCurrentPlayers[c_cSrvMax];
  30. char g_rgszDesc[c_cSrvMax][1000];
  31. void CheckConnection();
  32. /****************************************************************************\
  33. *
  34. * FUNCTION: DlgProcSettings
  35. *
  36. * PURPOSE: Handles Settings dialog box
  37. *
  38. *\***************************************************************************/
  39. BOOL CALLBACK DlgProcSettings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  40. {
  41. switch (message)
  42. {
  43. case WM_INITDIALOG:
  44. {
  45. SetDlgItemText(hDlg, IDC_EDIT_SERVER, rgszServer[g_iSrvDlg]);
  46. SetDlgItemInt( hDlg, IDC_EDIT_INTERVAL, secInterval, FALSE);
  47. return 0; // set focus on first control
  48. }
  49. case WM_COMMAND: // message: received a command
  50. {
  51. switch (LOWORD(wParam))
  52. {
  53. case IDOK:
  54. {
  55. GetDlgItemText(hDlg, IDC_EDIT_SERVER, rgszServer[g_iSrvDlg], sizeof(rgszServer[0]));
  56. secInterval = GetDlgItemInt( hDlg, IDC_EDIT_INTERVAL, NULL, FALSE);
  57. if (secInterval < 10)
  58. secInterval = 10;
  59. if (secInterval < 3 * g_cSrv)
  60. secInterval = 3 * g_cSrv;
  61. // Force reconnection
  62. if (fDPInit[g_iSrvDlg])
  63. {
  64. if (pDirectPlay3A[g_iSrvDlg])
  65. {
  66. pDirectPlay3A[g_iSrvDlg]->Release();
  67. pDirectPlay3A[g_iSrvDlg] = NULL;
  68. }
  69. fDPInit[g_iSrvDlg] = false;
  70. }
  71. EndDialog(hDlg, TRUE);
  72. PostMessage(hWnd, WM_TIMER, 0, 0);
  73. KillTimer(hWnd, 1);
  74. SetTimer(hWnd, 1, 1000 * secInterval, NULL);
  75. lstrcpy(g_rgszDesc[g_iSrvDlg], gszMsgInit);
  76. return (TRUE);
  77. }
  78. case IDCANCEL:
  79. {
  80. EndDialog(hDlg, TRUE);
  81. return (TRUE);
  82. }
  83. case ID_BTN_UNLOAD:
  84. {
  85. if (IDYES == MessageBox(hDlg, "Are you sure you want to cancel all server monitoring and kill FSMon?",
  86. "FSMon", MB_YESNO | MB_ICONQUESTION))
  87. {
  88. EndDialog(hDlg, TRUE);
  89. PostQuitMessage(0);
  90. return (TRUE);
  91. }
  92. }
  93. }
  94. }
  95. break;
  96. }
  97. return (FALSE);
  98. }
  99. /****************************************************************************\
  100. *
  101. * FUNCTION: EnumSessionsCallback2
  102. *
  103. * PURPOSE: Called by IDirectPlay3A::EnumSessions.
  104. *
  105. *\***************************************************************************/
  106. BOOL FAR PASCAL EnumSessionsCallback2(LPCDPSESSIONDESC2 lpThisSD,
  107. LPDWORD lpdwTimeOut,
  108. DWORD dwFlags,
  109. LPVOID lpContext)
  110. {
  111. // We're not actually going to open this session, so let's just remember that we have one
  112. if (dwFlags & DPESC_TIMEDOUT)
  113. return (FALSE);
  114. if (lpThisSD) // will be null if we timed out
  115. {
  116. *(bool *)lpContext = true;
  117. gState[g_iSrvCur] = FS_UP;
  118. gdwCurrentPlayers[g_iSrvCur] = lpThisSD->dwCurrentPlayers - 1;
  119. wsprintf(g_rgszDesc[g_iSrvCur], "Players: %d", (int) (gdwCurrentPlayers[g_iSrvCur]));
  120. }
  121. return FALSE;
  122. }
  123. /****************************************************************************\
  124. *
  125. * FUNCTION: CheckConnection
  126. *
  127. * PURPOSE: Check the connection and update the taskbar
  128. *
  129. *\***************************************************************************/
  130. void CheckConnection()
  131. {
  132. HRESULT hr = E_FAIL;
  133. if (!fDPInit[g_iSrvCur])
  134. {
  135. // setup dplay stuff
  136. hr = CoCreateInstance(CLSID_DirectPlay, NULL, CLSCTX_INPROC_SERVER,
  137. IID_IDirectPlay3A, (void**)&pDirectPlay3A[g_iSrvCur]);
  138. if (FAILED(hr))
  139. {
  140. MessageBox(NULL, "DPlay5+ is not properly installed. (IID_IDirectPlay3A)", "FSMon", MB_OK);
  141. exit(1);
  142. }
  143. // Create an IDirectPlayLobby interface, just so I can create an address.
  144. hr = DirectPlayLobbyCreate(NULL, &pDirectPlayLobbyA, NULL, NULL, 0);
  145. if (FAILED(hr))
  146. {
  147. MessageBox(NULL, "DPlay5 is not properly installed. (DirectPlayLobbyCreate)", "FSMon", MB_OK);
  148. exit(1);
  149. }
  150. void * pvAddress = NULL; // dplay address of server
  151. // Create an IDirectPlay3 interface
  152. DWORD dwAddressSize;
  153. // Find out how big the address buffer needs to be--intentional fail 1st time
  154. hr = pDirectPlayLobbyA->CreateAddress(DPSPGUID_TCPIP, DPAID_INet, rgszServer[g_iSrvCur],
  155. lstrlen(rgszServer[g_iSrvCur]) + 1, pvAddress, &dwAddressSize);
  156. if (DPERR_BUFFERTOOSMALL != hr)
  157. {
  158. MessageBox(NULL, "DPlay5 is not properly installed. (CreateAddress)", "FSMon", MB_OK);
  159. exit(1);
  160. }
  161. pvAddress = GlobalAllocPtr(GMEM_MOVEABLE, dwAddressSize);
  162. hr = pDirectPlayLobbyA->CreateAddress(DPSPGUID_TCPIP, DPAID_INet, rgszServer[g_iSrvCur],
  163. lstrlen(rgszServer[g_iSrvCur]) + 1, pvAddress, &dwAddressSize);
  164. pDirectPlayLobbyA->Release();
  165. pDirectPlayLobbyA = NULL;
  166. if (FAILED(hr))
  167. {
  168. MessageBox(NULL, "DPlay5 is not properly installed. (CreateAddress)", "FSMon", MB_OK);
  169. exit(1);
  170. }
  171. hr = pDirectPlay3A[g_iSrvCur]->InitializeConnection(pvAddress, 0);
  172. GlobalFreePtr(pvAddress);
  173. if (FAILED(hr))
  174. {
  175. gszMsg = "Can't initialize connection to specified machine";
  176. wsprintf(g_rgszDesc[g_iSrvCur], "Can't initialize connection", (int) (gdwCurrentPlayers[g_iSrvCur]));
  177. goto CLEANUP;
  178. }
  179. fDPInit[g_iSrvCur] = true;
  180. }
  181. {
  182. // try and find the session
  183. bool fFoundOne = false;
  184. DPSESSIONDESC2 sessionDesc;
  185. ZeroMemory(&sessionDesc, sizeof(DPSESSIONDESC2));
  186. sessionDesc.dwSize = sizeof(DPSESSIONDESC2);
  187. sessionDesc.guidApplication = FEDSRV_GUID;
  188. hr = pDirectPlay3A[g_iSrvCur]->EnumSessions(&sessionDesc, 2000, EnumSessionsCallback2, &fFoundOne, 0); //DPENUMSESSIONS_ASYNC);
  189. if ((FAILED(hr) || !fFoundOne) && (gState[g_iSrvCur] != FS_DOWN))
  190. {
  191. gState[g_iSrvCur] = FS_DOWN;
  192. gdwCurrentPlayers[g_iSrvCur] = 0;
  193. wsprintf(g_rgszDesc[g_iSrvCur], "DOWN", (int) (gdwCurrentPlayers[g_iSrvCur]));
  194. goto CLEANUP;
  195. }
  196. }
  197. CLEANUP:
  198. // save connection, so we can use it over and over
  199. if (!fDPInit[g_iSrvCur])
  200. {
  201. if (pDirectPlay3A[g_iSrvCur])
  202. {
  203. pDirectPlay3A[g_iSrvCur]->Release();
  204. pDirectPlay3A[g_iSrvCur] = NULL;
  205. }
  206. }
  207. }
  208. void UpdateMessage()
  209. {
  210. int cUp = 0, cDown = 0, cInit = 0;
  211. for (int iSrv = 0; iSrv < g_cSrv; iSrv++)
  212. {
  213. if (gState[iSrv] == FS_UP)
  214. cUp++;
  215. else if (gState[iSrv] == FS_DOWN)
  216. cDown++;
  217. else if (gState[iSrv] == FS_INIT)
  218. cInit++;
  219. }
  220. nid.hIcon = cInit > 0 ? hIconInit :
  221. cUp > 0 ? (cDown > 0 ? hIconBoth : hIconUp) : hIconDown;
  222. Shell_NotifyIcon(NIM_MODIFY, &nid);
  223. }
  224. /****************************************************************************\
  225. *
  226. * FUNCTION: MainWndProc
  227. *
  228. * PURPOSE: Processes notification messages
  229. *
  230. *\***************************************************************************/
  231. LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  232. {
  233. switch (message)
  234. {
  235. case WM_MOUSEINTRAY:
  236. {
  237. if (WM_LBUTTONDBLCLK == (UINT) lParam)
  238. {
  239. if (IDYES == MessageBox(NULL, "Are you sure you want to cancel all server monitoring and kill FSMon?",
  240. "FSMon", MB_YESNO | MB_ICONQUESTION | MB_SYSTEMMODAL))
  241. {
  242. PostQuitMessage(0);
  243. }
  244. //g_iSrvDlg = wParam;
  245. //DialogBox(hInst, MAKEINTRESOURCE(IDD_DLG_PROPS), NULL, (DLGPROC) DlgProcSettings);
  246. }
  247. else if (WM_LBUTTONDOWN == (UINT) lParam)
  248. {
  249. char szMsg[5000];
  250. char szTitle[100];
  251. int cPlayers = 0;
  252. int cServersUp = 0;
  253. int cServersDown = 0;
  254. szMsg[0] = 0;
  255. for (int iSrv = 0; iSrv < g_cSrv; iSrv++)
  256. {
  257. lstrcat(szMsg, rgszServer[iSrv]);
  258. lstrcat(szMsg, ": ");
  259. lstrcat(szMsg, g_rgszDesc[iSrv]);
  260. lstrcat(szMsg, "\n");
  261. cPlayers+=gdwCurrentPlayers[iSrv];
  262. if (gState[iSrv] == FS_UP)
  263. cServersUp++;
  264. if (gState[iSrv] == FS_DOWN)
  265. cServersDown++;
  266. }
  267. wsprintf(szTitle, "FSMon: %d players on %d servers. %d servers down.",
  268. cPlayers, cServersUp, cServersDown);
  269. MessageBox(NULL, szMsg, szTitle, MB_OK | MB_SYSTEMMODAL);
  270. }
  271. break;
  272. }
  273. case WM_DESTROY:
  274. {
  275. PostQuitMessage(0);
  276. break;
  277. }
  278. case WM_TIMER:
  279. {
  280. for (g_iSrvCur = 0; g_iSrvCur < g_cSrv; g_iSrvCur++)
  281. {
  282. CheckConnection();
  283. UpdateMessage();
  284. }
  285. break;
  286. }
  287. default:
  288. return DefWindowProc(hWnd, message, wParam, lParam);
  289. }
  290. return 0;
  291. }
  292. /****************************************************************************
  293. *
  294. * FUNCTION: WinMain
  295. *
  296. * PURPOSE: calls initialization function, processes message loop
  297. *
  298. *\***************************************************************************/
  299. WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nCmdShow)
  300. {
  301. MSG msg;
  302. WNDCLASSEX wcx;
  303. HRESULT hr = CoInitialize(NULL);
  304. wcx.cbSize = sizeof(wcx);
  305. wcx.style = 0;
  306. wcx.lpfnWndProc = MainWndProc;
  307. wcx.cbClsExtra = 0;
  308. wcx.cbWndExtra = 0;
  309. wcx.hInstance = hInst = hInstance;
  310. wcx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_FSMON));
  311. wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
  312. wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  313. wcx.lpszMenuName = 0;
  314. wcx.lpszClassName = SzAppName;
  315. wcx.hIconSm = NULL;
  316. RegisterClassEx(&wcx);
  317. // Create an invisible window to receive notification messages
  318. hWnd = CreateWindow(SzAppName, "FedSrv Monitor", WS_OVERLAPPEDWINDOW,
  319. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
  320. hIconUp = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_FS_RUNNING), IMAGE_ICON, 16, 16, 0);
  321. hIconDown = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_FS_STOPPED), IMAGE_ICON, 16, 16, 0);
  322. hIconBoth = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_FSMON), IMAGE_ICON, 16, 16, 0);
  323. hIconInit = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_FS_CONNECTING), IMAGE_ICON, 16, 16, 0);
  324. nid.cbSize = sizeof(nid);
  325. nid.hWnd = hWnd;
  326. nid.uID = 0;
  327. nid.uFlags = NIF_ICON | NIF_MESSAGE;
  328. nid.uCallbackMessage = WM_MOUSEINTRAY;
  329. nid.hIcon = hIconInit;
  330. if (!Shell_NotifyIcon(NIM_ADD, &nid))
  331. {
  332. MessageBox(hWnd, "Couldn't put FSMon Icon into the taskbar\n\n\tAborting",
  333. "FSMon: FATAL Error", MB_OK | MB_ICONEXCLAMATION);
  334. Shell_NotifyIcon(NIM_DELETE, &nid); // just in case it's somehow there anyway
  335. exit(1);
  336. }
  337. // Now let's see what other servers they want to monitor
  338. bool fMore = true;
  339. for (; *szCmdLine; fMore)
  340. {
  341. // skip any extraneous spaces
  342. while (*szCmdLine && *szCmdLine == ' ')
  343. szCmdLine++;
  344. // look for end of token
  345. char * szTokenStart = szCmdLine;
  346. while (*szCmdLine && *szCmdLine != ' ')
  347. szCmdLine++;
  348. fMore = !!*szCmdLine;
  349. if (fMore)
  350. *szCmdLine++ = '\0'; // NULL terminate the string, and skip space
  351. if (szTokenStart != szCmdLine)
  352. {
  353. // make sure it's not a dupe
  354. int iSrv ;
  355. for (iSrv = 0; iSrv < g_cSrv && stricmp(rgszServer[iSrv], szTokenStart); iSrv++)
  356. ;
  357. if (iSrv == g_cSrv) // we have a winner
  358. {
  359. lstrcpy(rgszServer[g_cSrv], szTokenStart);
  360. gState[g_cSrv] = FS_INIT;
  361. gdwCurrentPlayers[g_cSrv] = 0;
  362. fDPInit[g_cSrv] = false;
  363. pDirectPlay3A[g_cSrv] = NULL;
  364. g_cSrv++;
  365. }
  366. }
  367. }
  368. if (secInterval < 3 * g_cSrv)
  369. secInterval = 3 * g_cSrv;
  370. for (g_iSrvCur = 0; g_iSrvCur < g_cSrv; g_iSrvCur++)
  371. {
  372. CheckConnection();
  373. }
  374. UpdateMessage();
  375. SetTimer(hWnd, 1, 1000 * secInterval, NULL);
  376. while (GetMessage(&msg, NULL, 0, 0))
  377. {
  378. TranslateMessage(&msg);
  379. DispatchMessage(&msg);
  380. }
  381. Shell_NotifyIcon(NIM_DELETE, &nid);
  382. for (g_iSrvCur = 0; g_iSrvCur < g_cSrv; g_iSrvCur++)
  383. {
  384. if (!fDPInit[g_iSrvCur])
  385. {
  386. if (pDirectPlay3A[g_iSrvCur])
  387. {
  388. pDirectPlay3A[g_iSrvCur]->Release();
  389. pDirectPlay3A[g_iSrvCur] = NULL;
  390. }
  391. }
  392. }
  393. return (msg.wParam);
  394. }