vncMenu.cpp
Upload User: sbftbdw
Upload Date: 2007-01-03
Package Size: 379k
Code Size: 12k
Category:

Remote Control

Development Platform:

Visual C++

  1. //  Copyright (C) 1997, 1998 Olivetti & Oracle Research Laboratory
  2. //
  3. //  This file is part of the VNC system.
  4. //
  5. //  The VNC system is free software; you can redistribute it and/or modify
  6. //  it under the terms of the GNU General Public License as published by
  7. //  the Free Software Foundation; either version 2 of the License, or
  8. //  (at your option) any later version.
  9. //
  10. //  This program is distributed in the hope that it will be useful,
  11. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. //  GNU General Public License for more details.
  14. //
  15. //  You should have received a copy of the GNU General Public License
  16. //  along with this program; if not, write to the Free Software
  17. //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  18. //  USA.
  19. //
  20. // If the source code for the VNC system is not available from the place 
  21. // whence you received this file, check http://www.orl.co.uk/vnc or contact
  22. // the authors on vnc@orl.co.uk for information on obtaining it.
  23. // vncMenu
  24. // Implementation of a system tray icon & menu for WinVNC
  25. #include "stdhdrs.h"
  26. #include "WinVNC.h"
  27. #include "vncService.h"
  28. #include <lmcons.h>
  29. // Header
  30. #include "vncMenu.h"
  31. // Constants
  32. const UINT MENU_PROPERTIES_SHOW = RegisterWindowMessage("WinVNC.Properties.Show");
  33. const UINT MENU_ABOUTBOX_SHOW = RegisterWindowMessage("WinVNC.AboutBox.Show");
  34. const char *MENU_CLASS_NAME = "WinVNC Tray Icon";
  35. // Implementation
  36. vncMenu::vncMenu(vncServer *server)
  37. {
  38. // Save the server pointer
  39. m_server = server;
  40. // Set the initial user name to something sensible...
  41. vncService::CurrentUser((char *)&m_username, sizeof(m_username));
  42. // Create a dummy window to handle tray icon messages
  43. WNDCLASSEX wndclass;
  44. wndclass.cbSize = sizeof(wndclass);
  45. wndclass.style = 0;
  46. wndclass.lpfnWndProc = vncMenu::WndProc;
  47. wndclass.cbClsExtra = 0;
  48. wndclass.cbWndExtra = 0;
  49. wndclass.hInstance = hAppInstance;
  50. wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  51. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  52. wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  53. wndclass.lpszMenuName = (const char *) NULL;
  54. wndclass.lpszClassName = MENU_CLASS_NAME;
  55. wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  56. RegisterClassEx(&wndclass);
  57. m_hwnd = CreateWindow(MENU_CLASS_NAME,
  58. MENU_CLASS_NAME,
  59. WS_OVERLAPPEDWINDOW,
  60. CW_USEDEFAULT,
  61. CW_USEDEFAULT,
  62. 200, 200,
  63. NULL,
  64. NULL,
  65. hAppInstance,
  66. NULL);
  67. if (m_hwnd == NULL)
  68. {
  69. PostQuitMessage(0);
  70. return;
  71. }
  72. // *** HACK for running servicified on WinNT
  73. if (vncService::IsWinNT() && vncService::RunningAsService())
  74. SetTimer(m_hwnd, 1, 5000, NULL);
  75. // record which client created this window
  76. SetWindowLong(m_hwnd, GWL_USERDATA, (LONG) this);
  77. // Ask the server object to notify us of stuff
  78. server->AddNotify(m_hwnd);
  79. // Initialise the properties dialog object
  80. if (!m_properties.Init(m_server))
  81. {
  82. PostQuitMessage(0);
  83. return;
  84. }
  85. // Load the icons for the tray
  86. m_winvnc_icon = LoadIcon(hAppInstance, MAKEINTRESOURCE(IDI_WINVNC));
  87. m_flash_icon = LoadIcon(hAppInstance, MAKEINTRESOURCE(IDI_FLASH));
  88. // Load the popup menu
  89. m_hmenu = LoadMenu(hAppInstance, MAKEINTRESOURCE(IDR_TRAYMENU));
  90. // Install the tray icon!
  91. AddTrayIcon();
  92. }
  93. vncMenu::~vncMenu()
  94. {
  95. // Remove the tray icon
  96. DelTrayIcon();
  97. // Destroy the loaded menu
  98. if (m_hmenu != NULL)
  99. DestroyMenu(m_hmenu);
  100. // Tell the server to stop notifying us!
  101. if (m_server != NULL)
  102. m_server->RemNotify(m_hwnd);
  103. }
  104. void
  105. vncMenu::AddTrayIcon()
  106. {
  107. // If the user name is non-null then we have a user!
  108. if (strcmp(m_username, "") != 0)
  109. SendTrayMsg(NIM_ADD, FALSE);
  110. }
  111. void
  112. vncMenu::DelTrayIcon()
  113. {
  114. SendTrayMsg(NIM_DELETE, FALSE);
  115. }
  116. void
  117. vncMenu::FlashTrayIcon(BOOL flash)
  118. {
  119. SendTrayMsg(NIM_MODIFY, flash);
  120. }
  121. // Get the local ip addresses as a human-readable string.
  122. // If more than one, then with n between them.
  123. // If not available, then gets a message to that effect.
  124. void GetIPAddrString(char *buffer, int buflen) {
  125.     char namebuf[256];
  126.     if (gethostname(namebuf, 256) != 0) {
  127. strncpy(buffer, "Host name unavailable", buflen);
  128. return;
  129.     };
  130.     HOSTENT *ph = gethostbyname(namebuf);
  131.     if (!ph) {
  132. strncpy(buffer, "IP address unavailable", buflen);
  133. return;
  134.     };
  135.     *buffer = '';
  136.     char digtxt[5];
  137.     for (int i = 0; ph->h_addr_list[i]; i++) {
  138.      for (int j = 0; j < ph->h_length; j++) {
  139.     sprintf(digtxt, "%d.", (unsigned char) ph->h_addr_list[i][j]);
  140.     strncat(buffer, digtxt, (buflen-1)-strlen(buffer));
  141. }
  142. buffer[strlen(buffer)-1] = '';
  143. if (ph->h_addr_list[i+1] != 0)
  144.     strncat(buffer, ", ", (buflen-1)-strlen(buffer));
  145.     }
  146. }
  147. void
  148. vncMenu::SendTrayMsg(DWORD msg, BOOL flash)
  149. {
  150. // Create the tray icon message
  151. m_nid.hWnd = m_hwnd;
  152. m_nid.cbSize = sizeof(m_nid);
  153. m_nid.uID = IDI_WINVNC; // never changes after construction
  154. m_nid.hIcon = flash ? m_flash_icon : m_winvnc_icon;
  155. m_nid.uFlags = NIF_ICON | NIF_MESSAGE;
  156. m_nid.uCallbackMessage = WM_TRAYNOTIFY;
  157. // Use resource string as tip if there is one
  158. if (LoadString(hAppInstance, IDI_WINVNC, m_nid.szTip, sizeof(m_nid.szTip)))
  159. {
  160.     m_nid.uFlags |= NIF_TIP;
  161. }
  162. // Try to add the server's IP addresses to the tip string, if possible
  163. if (m_nid.uFlags & NIF_TIP)
  164. {
  165.     strncat(m_nid.szTip, " - ", (sizeof(m_nid.szTip)-1)-strlen(m_nid.szTip));
  166.     if (m_server->SockConnected())
  167.     {
  168. unsigned long tiplen = strlen(m_nid.szTip);
  169. char *tipptr = ((char *)&m_nid.szTip) + tiplen;
  170. GetIPAddrString(tipptr, sizeof(m_nid.szTip) - tiplen);
  171.     }
  172.     else
  173.     {
  174. strncat(m_nid.szTip, "Not listening", (sizeof(m_nid.szTip)-1)-strlen(m_nid.szTip));
  175.     }
  176. }
  177. // Send the message
  178. if (Shell_NotifyIcon(msg, &m_nid))
  179. {
  180. // Set the enabled/disabled state of the menu items
  181. log.Print(LL_INTINFO, VNCLOG("tray icon added okn"));
  182. EnableMenuItem(m_hmenu, ID_PROPERTIES,
  183. m_properties.AllowProperties() ? MF_ENABLED : MF_GRAYED);
  184. EnableMenuItem(m_hmenu, ID_CLOSE,
  185. m_properties.AllowShutdown() ? MF_ENABLED : MF_GRAYED);
  186. } else {
  187. if (!vncService::RunningAsService())
  188. {
  189. if (msg == NIM_ADD)
  190. {
  191. // The tray icon couldn't be created, so use the Properties dialog
  192. // as the main program window
  193. log.Print(LL_INTINFO, VNCLOG("opening dialog boxn"));
  194. m_properties.Show(TRUE);
  195. PostQuitMessage(0);
  196. }
  197. }
  198. }
  199. }
  200. // Process window messages
  201. LRESULT CALLBACK vncMenu::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  202. {
  203. // This is a static method, so we don't know which instantiation we're 
  204. // dealing with. We use Allen Hadden's (ahadden@taratec.com) suggestion 
  205. // from a newsgroup to get the pseudo-this.
  206. vncMenu *_this = (vncMenu *) GetWindowLong(hwnd, GWL_USERDATA);
  207. switch (iMsg)
  208. {
  209. // *** HACK
  210. // This timer message is used to cause the current user to be checked
  211. // every five seconds...
  212. case WM_TIMER:
  213. _this->AddTrayIcon();
  214. PostMessage(hwnd, WM_USERCHANGED, 0, 0);
  215. break;
  216. // DEAL WITH NOTIFICATIONS FROM THE SERVER:
  217. case WM_SRV_CLIENT_AUTHENTICATED:
  218. case WM_SRV_CLIENT_DISCONNECT:
  219. // Adjust the icon accordingly
  220. _this->FlashTrayIcon(_this->m_server->AuthClientCount() != 0);
  221. return 0;
  222. // STANDARD MESSAGE HANDLING
  223. case WM_CREATE:
  224. return 0;
  225. case WM_COMMAND:
  226. // User has clicked an item on the tray menu
  227. switch (LOWORD(wParam))
  228. {
  229. case ID_PROPERTIES:
  230. // Show the properties dialog, unless it is already displayed
  231. log.Print(LL_INTINFO, VNCLOG("show properties requestedn"));
  232. _this->m_properties.Show(TRUE);
  233. _this->FlashTrayIcon(_this->m_server->AuthClientCount() != 0);
  234. break;
  235. case ID_KILLCLIENTS:
  236. // Disconnect all currently connected clients
  237. _this->m_server->KillAll();
  238. break;
  239. case ID_ABOUT:
  240. // Show the About box
  241. _this->m_about.Show(TRUE);
  242. break;
  243. case ID_CLOSE:
  244. // User selected Close from the tray menu
  245. PostMessage(hwnd, WM_CLOSE, 0, 0);
  246. break;
  247. }
  248. return 0;
  249. case WM_TRAYNOTIFY:
  250. // User has clicked on the tray icon or the menu
  251. {
  252. // Get the submenu to use as a pop-up menu
  253. HMENU submenu = GetSubMenu(_this->m_hmenu, 0);
  254. // What event are we responding to, RMB click?
  255. if (lParam==WM_RBUTTONUP)
  256. {
  257. if (submenu == NULL)
  258. log.Print(LL_INTERR, VNCLOG("no submenu availablen"));
  259. return 0;
  260. }
  261. // Make the first menu item the default (bold font)
  262. SetMenuDefaultItem(submenu, 0, TRUE);
  263. // Get the current cursor position, to display the menu at
  264. POINT mouse;
  265. GetCursorPos(&mouse);
  266. // There's a "bug"
  267. // (Microsoft calls it a feature) in Windows 95 that requires calling
  268. // SetForegroundWindow. To find out more, search for Q135788 in MSDN.
  269. //
  270. SetForegroundWindow(_this->m_nid.hWnd);
  271. // Display the menu at the desired position
  272. TrackPopupMenu(submenu,
  273. 0, mouse.x, mouse.y, 0,
  274. _this->m_nid.hWnd, NULL);
  275. return 0;
  276. }
  277. // Or was there a LMB double click?
  278. if (lParam==WM_LBUTTONDBLCLK)
  279. {
  280. // double click: execute first menu item
  281. SendMessage(_this->m_nid.hWnd,
  282. WM_COMMAND, 
  283. GetMenuItemID(submenu, 0),
  284. 0);
  285. }
  286. return 0;
  287. }
  288. case WM_CLOSE:
  289. // Only accept WM_CLOSE if the logged on user has AllowShutdown set
  290. if (!_this->m_properties.AllowShutdown())
  291. return 0;
  292. break;
  293. case WM_DESTROY:
  294. // The user wants WinVNC to quit cleanly...
  295. PostQuitMessage(0);
  296. return 0;
  297. case WM_QUERYENDSESSION:
  298. // Are we running as a system service?
  299. // Or is the system shutting down (in which case we should check anyway!)
  300. if ((!vncService::RunningAsService()) || (lParam == 0))
  301. {
  302. // No, so we are about to be killed
  303. // If there are remote connections then we should verify
  304. // that the user is happy about killing them.
  305. if (_this->m_server->AuthClientCount() > 0)
  306. {
  307. if (MessageBox(NULL,
  308. "There are remote clients connected to this computer.n"
  309. "Ending the session will disconnect them and close down WinVNC.n"
  310. "Are you sure you want to do this?",
  311. "WinVNC Warning",
  312. MB_OKCANCEL | MB_ICONWARNING) == IDCANCEL)
  313. {
  314. // User doesn't want to log-out, so stop the logout.
  315. return FALSE;
  316. }
  317. }
  318. // The user wishes to log out (or no users are connected)
  319. // Try to clean ourselves up nicely, if possible...
  320. // Firstly, disable incoming CORBA or socket connections
  321. _this->m_server->SockConnect(FALSE);
  322. _this->m_server->CORBAConnect(FALSE);
  323. // Now kill all the server's clients
  324. _this->m_server->KillAll();
  325. _this->m_server->WaitUntilAuthEmpty();
  326. // Finally, post a quit message, just in case
  327. PostQuitMessage(0);
  328. return TRUE;
  329. }
  330. // Tell the OS that we've handled it anyway
  331. return TRUE;
  332. case WM_USERCHANGED:
  333. // The current user may have changed.
  334. {
  335. char newuser[UNLEN+1];
  336. if (vncService::CurrentUser((char *) &newuser, sizeof(newuser)))
  337. {
  338. log.Print(LL_INTINFO,
  339. VNCLOG("usernames : old="%s", new="%s"n"),
  340. _this->m_username, newuser);
  341. // Check whether the user name has changed!
  342. if (strcmp(newuser, _this->m_username) != 0)
  343. {
  344. log.Print(LL_INTINFO,
  345. VNCLOG("user name has changedn"));
  346. // User has changed!
  347. strcpy(_this->m_username, newuser);
  348. // Redraw the tray icon and set it's state
  349. _this->DelTrayIcon();
  350. _this->AddTrayIcon();
  351. _this->FlashTrayIcon(_this->m_server->AuthClientCount() != 0);
  352. // We should load in the prefs for the new user
  353. _this->m_properties.Load();
  354. }
  355. }
  356. }
  357. return 0;
  358. default:
  359. // Deal with any of our custom message types
  360. if (iMsg == MENU_PROPERTIES_SHOW)
  361. {
  362. // External request to show our Properties dialog
  363. PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_PROPERTIES, 0), 0);
  364. return 0;
  365. }
  366. if (iMsg == MENU_ABOUTBOX_SHOW)
  367. {
  368. // External request to show our About dialog
  369. PostMessage(hwnd, WM_COMMAND, MAKELONG(ID_ABOUT, 0), 0);
  370. return 0;
  371. }
  372. }
  373. // Message not recognised
  374. return DefWindowProc(hwnd, iMsg, wParam, lParam);
  375. }