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.

439 lines
10 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Rcontrol Main
  5. Abstract:
  6. This includes WinMain and the WndProc for the system tray icon.
  7. Author:
  8. Marc Reyhner 7/5/2000
  9. --*/
  10. #include "stdafx.h"
  11. #include <initguid.h>
  12. #ifdef TRC_FILE
  13. #undef TRC_FILE
  14. #endif
  15. #define TRC_FILE "rcm"
  16. #include "rcontrol.h"
  17. #include "resource.h"
  18. #include "exception.h"
  19. #include "DirectPlayConnection.h"
  20. #include "RemoteDesktopClientSession.h"
  21. #include "RemoteDesktopServer.h"
  22. #include "RemoteDesktopServerEventSink.h"
  23. // This is the message that will will get when someone does something to the
  24. // taskbar icon.
  25. #define WM_SYSICONMESSAGE (WM_USER + 1)
  26. //
  27. //
  28. //
  29. #define MUTEX_NAME (TEXT("Local\\MICROSOFT_SALEM_IM_MUTEX"))
  30. // This is a pointer to our instance so that we can pass it off to some
  31. // of the menu functions.
  32. HINSTANCE g_hInstance;
  33. // This is the structure for setting parameters for the taskbar icon. We keep one copy
  34. // of it around that we can pass in to Shell_NotifyIcon
  35. NOTIFYICONDATA g_iconData;
  36. // This is a global pointer to the direct play connection so that
  37. // the server can close the DP connection on connect.
  38. CDirectPlayConnection *g_DpConnection;
  39. // This helper function lauches the executable for the gui passing it the
  40. // connection parameters on the command line.
  41. static VOID
  42. LaunchClient(
  43. HINSTANCE hInstance,
  44. BSTR parms
  45. );
  46. // This helper function runs the system tray icon if this is a server.
  47. static VOID
  48. DoSystemTray(
  49. );
  50. // This is the WndProc for the taskbar icon
  51. static LRESULT CALLBACK
  52. SysTrayWndProc(
  53. HWND hwnd,
  54. UINT uMsg,
  55. WPARAM wParam,
  56. LPARAM lParam
  57. );
  58. INT WINAPI
  59. WinMain(
  60. IN HINSTANCE hInstance,
  61. IN HINSTANCE hPrevInstance,
  62. IN LPSTR lpCmdLine,
  63. IN INT nShowCmd)
  64. /*++
  65. Routine Description:
  66. The entry point for the application. This figures out
  67. if we are a server or client and then behaves accordingly.
  68. Arguments:
  69. hInstance - The instance for this application.
  70. hPrevInstance - Previous instance, should be NULL
  71. lpCmdLine - Command line for the application.
  72. nShowCmd - Flags for how to show the application.
  73. Return value:
  74. INT - The return code for the application.
  75. --*/
  76. {
  77. HANDLE lpMutex = NULL;
  78. DWORD error;
  79. BSTR serverParms, clientParms;
  80. DC_BEGIN_FN("WinMain");
  81. serverParms = NULL;
  82. clientParms = NULL;
  83. g_hInstance = hInstance;
  84. CoInitialize(NULL);
  85. try {
  86. CDirectPlayConnection connection;
  87. g_DpConnection = &connection;
  88. connection.ConnectToRemoteApplication();
  89. if (connection.IsServer()) {
  90. // we are a server
  91. CRemoteDesktopServer server;
  92. CRemoteDesktopServerEventSink sink;
  93. HRESULT hr;
  94. lpMutex = CreateMutex(NULL,TRUE,MUTEX_NAME);
  95. if (!lpMutex) {
  96. throw CException(IDS_INITERRORMUTEX);
  97. }
  98. error = GetLastError();
  99. if (error == ERROR_ALREADY_EXISTS) {
  100. throw CException(IDS_INITALREADYEXISTS);
  101. }
  102. serverParms = server.StartListening();
  103. hr = server.EventSinkAdvise(&sink);
  104. if (hr != S_OK) {
  105. throw CException(IDS_ADVISEERROR);
  106. }
  107. connection.SendConnectionParameters(serverParms);
  108. DoSystemTray();
  109. try {
  110. server.StopListening();
  111. } catch (CException e) {
  112. TRC_ERR((TB,TEXT("Caught Exception: %s"),e.GetErrorStr()));
  113. // We are shutting down so just suppress the error.
  114. }
  115. CloseHandle(lpMutex);
  116. } else {
  117. // we are the client
  118. clientParms = connection.ReceiveConnectionParameters();
  119. connection.DisconnectRemoteApplication();
  120. LaunchClient(hInstance,clientParms);
  121. }
  122. } catch (CException e) {
  123. TCHAR dlgTitle[MAX_STR_LEN];
  124. TRC_ERR((TB,TEXT("Caught Exception: %s"),e.GetErrorStr()));
  125. LoadStringSimple(IDS_ERRORDDLGTITLE,dlgTitle);
  126. MessageBox(NULL,e.GetErrorStr(),dlgTitle,MB_OK|MB_ICONERROR);
  127. }
  128. if (clientParms) {
  129. delete clientParms;
  130. }
  131. CoUninitialize();
  132. DC_END_FN();
  133. return 0;
  134. }
  135. static VOID
  136. LaunchClient(
  137. IN OUT HINSTANCE hInstance,
  138. IN BSTR parms
  139. )
  140. /*++
  141. Routine Description:
  142. This starts (and does) the client GUI side of the application.
  143. DoClientSession will not returne until the client GUI is totally
  144. done.
  145. Arguments:
  146. hInstance - The instance for this application
  147. parms - The connection parameters for connecting to the server.
  148. Return value:
  149. None
  150. --*/
  151. {
  152. DC_BEGIN_FN("LaunchClient");
  153. CRemoteDesktopClientSession clientSession(hInstance);
  154. clientSession.DoClientSession(parms);
  155. DC_END_FN();
  156. }
  157. static VOID
  158. DoSystemTray(
  159. )
  160. /*++
  161. Routine Description:
  162. This creates the system tray and enters the event loop
  163. until the a WM_QUIT message is generated.
  164. Arguments:
  165. None
  166. Return value:
  167. None
  168. --*/
  169. {
  170. MSG msg;
  171. WNDCLASS wndClass;
  172. ATOM className;
  173. HWND hWnd;
  174. TCHAR tipText[MAX_STR_LEN];
  175. DC_BEGIN_FN("DoSystemTray");
  176. wndClass.style = 0;
  177. wndClass.lpfnWndProc = SysTrayWndProc;
  178. wndClass.cbClsExtra = 0;
  179. wndClass.cbWndExtra = 0;
  180. wndClass.hInstance = g_hInstance;
  181. wndClass.hIcon = NULL;
  182. wndClass.hCursor = NULL;
  183. wndClass.hbrBackground = NULL;
  184. wndClass.lpszMenuName = NULL;
  185. // This is an internal name so we don't need to localize this.
  186. wndClass.lpszClassName = TEXT("SysTrayWindowClass");
  187. className = RegisterClass(&wndClass);
  188. hWnd = CreateWindow((LPCTSTR)className,TEXT(""),0,0,0,0,0,/*HWND_MESSAGE*/0,NULL,NULL,NULL);
  189. if (hWnd == NULL) {
  190. throw "Failed to create system tray icon.";
  191. }
  192. g_iconData.cbSize = sizeof(g_iconData);
  193. g_iconData.hIcon = ::LoadIcon(g_hInstance,MAKEINTRESOURCE(IDI_TRAYICON));
  194. g_iconData.hWnd = hWnd;
  195. LoadStringSimple(IDS_TRAYTOOLTIPDISCONNECTED,tipText);
  196. // The buffer is only 128 chars.
  197. _tcsncpy(g_iconData.szTip,tipText,128 - 1);
  198. g_iconData.uCallbackMessage = WM_SYSICONMESSAGE;
  199. g_iconData.uFlags = NIF_ICON|NIF_MESSAGE |NIF_TIP;
  200. g_iconData.uID = 0;
  201. g_iconData.uVersion = NOTIFYICON_VERSION;
  202. Shell_NotifyIcon(NIM_ADD,&g_iconData);
  203. g_iconData.uFlags = 0;
  204. Shell_NotifyIcon(NIM_SETVERSION,&g_iconData);
  205. // Do our message loop.
  206. while (GetMessage(&msg, (HWND) NULL, 0, 0)>0)
  207. {
  208. TranslateMessage(&msg);
  209. DispatchMessage(&msg);
  210. }
  211. Shell_NotifyIcon(NIM_DELETE,&g_iconData);
  212. DC_END_FN();
  213. }
  214. static LRESULT CALLBACK
  215. SysTrayWndProc(
  216. IN HWND hWnd,
  217. IN UINT uMsg,
  218. IN WPARAM wParam,
  219. IN LPARAM lParam
  220. )
  221. /*++
  222. Routine Description:
  223. Callback for our taskbar icon. This handles all the window messages
  224. related to the icon.
  225. Arguments:
  226. hWnd - Window the message is for
  227. uMsg - The message code
  228. wParam - First message flag
  229. lParam - Second message flag
  230. Return value:
  231. LRESULT - The result of processing the message
  232. --*/
  233. {
  234. // This is the window message for when the taskbar
  235. // is recreated. We will just initialize it once on
  236. // WM_CREATE
  237. static UINT g_wmTaskbarCreated = 0;
  238. // This is the code we will return. We will initialize it to 1.
  239. LRESULT result = 1;
  240. DC_BEGIN_FN("SysTrayWndProc");
  241. // If the taskbar is recreates (i.e. explorer crashed) it will
  242. // give us this message. When that happens we want to re-create
  243. // the taskbar icon.
  244. if (uMsg == g_wmTaskbarCreated) {
  245. g_iconData.uFlags = NIF_ICON|NIF_MESSAGE |NIF_TIP;
  246. Shell_NotifyIcon(NIM_ADD,&g_iconData);
  247. g_iconData.uFlags = 0;
  248. Shell_NotifyIcon(NIM_SETVERSION,&g_iconData);
  249. DC_END_FN();
  250. return 0;
  251. }
  252. switch (uMsg) {
  253. case WM_CREATE:
  254. g_wmTaskbarCreated = RegisterWindowMessage(TEXT("TaskbarCreated"));
  255. if (!g_wmTaskbarCreated) {
  256. result = -1;
  257. } else {
  258. result = 0;
  259. }
  260. case WM_SYSICONMESSAGE:
  261. switch (lParam) {
  262. case WM_CONTEXTMENU:
  263. POINT pos;
  264. HMENU hMenu, hSubmenu;
  265. GetCursorPos(&pos);
  266. hMenu = LoadMenu(g_hInstance,MAKEINTRESOURCE(IDR_TRAYMENU));
  267. hSubmenu = GetSubMenu(hMenu,0);
  268. SetForegroundWindow(hWnd);
  269. TrackPopupMenu(hSubmenu,TPM_VERNEGANIMATION,pos.x,pos.y,0,hWnd,NULL);
  270. // this also destroys the submenu
  271. DestroyMenu(hMenu);
  272. g_iconData.uFlags = 0;
  273. Shell_NotifyIcon(NIM_SETFOCUS,&g_iconData);
  274. result = 0;
  275. break;
  276. case WM_LBUTTONDOWN:
  277. PostMessage(hWnd,WM_COMMAND,ID_QUIT,NULL);
  278. result = 0;
  279. break;
  280. default:
  281. // Any other messages we will ignore
  282. result = 0;
  283. }
  284. break;
  285. case WM_COMMAND:
  286. switch (wParam) {
  287. case ID_QUIT:
  288. TCHAR dlgText[MAX_STR_LEN], dlgTitle[MAX_STR_LEN];
  289. LoadStringSimple(IDS_TRAYEXITDLGTEXT,dlgText);
  290. LoadStringSimple(IDS_TRAYEXITDLGTITLE,dlgTitle);
  291. if (IDYES == MessageBox(hWnd,dlgText,dlgTitle,MB_YESNO)) {
  292. PostQuitMessage(0);
  293. }
  294. result = 0;
  295. break;
  296. }
  297. break;
  298. default:
  299. // We don't understand this message so do the default.
  300. result = DefWindowProc(hWnd,uMsg,wParam,lParam);
  301. }
  302. DC_END_FN();
  303. return result;
  304. }
  305. INT
  306. LoadStringSimple(
  307. IN UINT uID,
  308. OUT LPTSTR lpBuffer
  309. )
  310. /*++
  311. Routine Description:
  312. This will load the given string from the applications string table. If
  313. it is longer than MAX_STR_LEN it is truncated. lpBuffer should be at least
  314. MAX_STR_LEN characters long. If the string does not exist we return 0
  315. and set the buffer to IDS_STRINGMISSING, if that failes then we set it to the
  316. hard coded STR_RES_MISSING.
  317. Arguments:
  318. uID - Id of the resource to load.
  319. lpBuffer - Buffer of MAX_STR_LEN to hold the string
  320. Return value:
  321. 0 - String resource could not be loaded.
  322. postive integer - length of the string loaded.
  323. --*/
  324. {
  325. INT length;
  326. DC_BEGIN_FN("LoadStringSimple");
  327. length = LoadString(g_hInstance,uID,lpBuffer,MAX_STR_LEN);
  328. if (length == 0) {
  329. length = LoadString(g_hInstance,IDS_STRINGMISSING,lpBuffer,MAX_STR_LEN);
  330. if (length == 0) {
  331. _tcscpy(lpBuffer,STR_RES_MISSING);
  332. }
  333. length = 0;
  334. }
  335. DC_END_FN();
  336. return length;
  337. }