/[rdesktop]/sourceforge.net/trunk/seamlessrdp/ServerExe/main.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/seamlessrdp/ServerExe/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1455 - (show annotations)
Fri Mar 14 11:24:33 2008 UTC (16 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 11697 byte(s)
Ignore cmd.exe during enumeration.

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Seamless windows - Remote server executable
4
5 Based on code copyright (C) 2004-2005 Martin Wickett
6
7 Copyright (C) Peter Åstrand <astrand@cendio.se> 2005-2006
8 Copyright (C) Pierre Ossman <ossman@cendio.se> 2006
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #define WINVER 0x0501
26
27 #include <windows.h>
28 #include <stdio.h>
29 #include <wtsapi32.h>
30 #include <cchannel.h>
31
32 #include "vchannel.h"
33
34 #include "resource.h"
35
36 #define APP_NAME "SeamlessRDP Shell"
37
38 /* Global data */
39 static HINSTANCE g_instance;
40
41 static DWORD g_session_id;
42 static DWORD *g_startup_procs;
43 static int g_startup_num_procs;
44
45 static BOOL g_connected;
46 static BOOL g_desktop_hidden;
47
48 typedef void (*set_hooks_proc_t) ();
49 typedef void (*remove_hooks_proc_t) ();
50 typedef int (*get_instance_count_proc_t) ();
51
52 typedef void (*move_window_proc_t) (unsigned int serial, HWND hwnd, int x, int y, int width,
53 int height);
54 typedef void (*zchange_proc_t) (unsigned int serial, HWND hwnd, HWND behind);
55 typedef void (*focus_proc_t) (unsigned int serial, HWND hwnd);
56 typedef void (*set_state_proc_t) (unsigned int serial, HWND hwnd, int state);
57
58 static move_window_proc_t g_move_window_fn = NULL;
59 static zchange_proc_t g_zchange_fn = NULL;
60 static focus_proc_t g_focus_fn = NULL;
61 static set_state_proc_t g_set_state_fn = NULL;
62
63 static void
64 message(const char *text)
65 {
66 MessageBox(GetDesktopWindow(), text, "SeamlessRDP Shell", MB_OK);
67 }
68
69 static char *
70 get_token(char **s)
71 {
72 char *comma, *head;
73 head = *s;
74
75 if (!head)
76 return NULL;
77
78 comma = strchr(head, ',');
79 if (comma)
80 {
81 *comma = '\0';
82 *s = comma + 1;
83 }
84 else
85 {
86 *s = NULL;
87 }
88
89 return head;
90 }
91
92 static BOOL CALLBACK
93 enum_cb(HWND hwnd, LPARAM lparam)
94 {
95 RECT rect;
96 unsigned short title[150];
97 LONG styles;
98 int state;
99 HWND parent;
100 DWORD pid;
101 int flags;
102
103 styles = GetWindowLong(hwnd, GWL_STYLE);
104
105 if (!(styles & WS_VISIBLE))
106 return TRUE;
107
108 /* Since WH_CALLWNDPROC is not effective on cmd.exe, make sure
109 we ignore it during enumeration as well. Make sure to
110 remove this when cmd.exe support has been added, though. */
111 char classname[32];
112 if (GetClassName(hwnd, classname, sizeof(classname))
113 && !strcmp(classname, "ConsoleWindowClass"))
114 return TRUE;
115
116 if (styles & WS_POPUP)
117 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
118 else
119 parent = NULL;
120
121 GetWindowThreadProcessId(hwnd, &pid);
122
123 flags = 0;
124 if (styles & DS_MODALFRAME)
125 flags |= SEAMLESS_CREATE_MODAL;
126
127 vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x", (long) hwnd, (long) pid,
128 (long) parent, flags);
129
130 if (!GetWindowRect(hwnd, &rect))
131 {
132 debug("GetWindowRect failed!");
133 return TRUE;
134 }
135
136 vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x",
137 hwnd,
138 rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
139
140 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
141
142 vchannel_write("TITLE", "0x%x,%s,0x%x", hwnd, vchannel_strfilter_unicode(title), 0);
143
144 if (styles & WS_MAXIMIZE)
145 state = 2;
146 else if (styles & WS_MINIMIZE)
147 state = 1;
148 else
149 state = 0;
150
151 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd, state, 0);
152
153 return TRUE;
154 }
155
156 static void
157 do_sync(void)
158 {
159 vchannel_block();
160
161 vchannel_write("SYNCBEGIN", "0x0");
162
163 EnumWindows(enum_cb, 0);
164
165 vchannel_write("SYNCEND", "0x0");
166
167 vchannel_unblock();
168 }
169
170 static void
171 do_state(unsigned int serial, HWND hwnd, int state)
172 {
173 g_set_state_fn(serial, hwnd, state);
174 }
175
176 static void
177 do_position(unsigned int serial, HWND hwnd, int x, int y, int width, int height)
178 {
179 g_move_window_fn(serial, hwnd, x, y, width, height);
180 }
181
182 static void
183 do_zchange(unsigned int serial, HWND hwnd, HWND behind)
184 {
185 g_zchange_fn(serial, hwnd, behind);
186 }
187
188 static void
189 do_focus(unsigned int serial, HWND hwnd)
190 {
191 g_focus_fn(serial, hwnd);
192 }
193
194 /* No need for locking, since this is a request rather than a message
195 that needs to indicate what has already happened. */
196 static void
197 do_destroy(HWND hwnd)
198 {
199 SendMessage(hwnd, WM_CLOSE, 0, 0);
200 }
201
202 static void
203 process_cmds(void)
204 {
205 char line[VCHANNEL_MAX_LINE];
206 int size;
207
208 char *p, *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8;
209
210 while ((size = vchannel_read(line, sizeof(line))) >= 0)
211 {
212 p = line;
213
214 tok1 = get_token(&p);
215 tok2 = get_token(&p);
216 tok3 = get_token(&p);
217 tok4 = get_token(&p);
218 tok5 = get_token(&p);
219 tok6 = get_token(&p);
220 tok7 = get_token(&p);
221 tok8 = get_token(&p);
222
223 if (strcmp(tok1, "SYNC") == 0)
224 do_sync();
225 else if (strcmp(tok1, "STATE") == 0)
226 do_state(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0),
227 strtol(tok4, NULL, 0));
228 else if (strcmp(tok1, "POSITION") == 0)
229 do_position(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0),
230 strtol(tok4, NULL, 0), strtol(tok5, NULL, 0), strtol(tok6, NULL,
231 0),
232 strtol(tok7, NULL, 0));
233 else if (strcmp(tok1, "ZCHANGE") == 0)
234 do_zchange(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0),
235 (HWND) strtoul(tok4, NULL, 0));
236 else if (strcmp(tok1, "FOCUS") == 0)
237 do_focus(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0));
238 else if (strcmp(tok1, "DESTROY") == 0)
239 do_destroy((HWND) strtoul(tok3, NULL, 0));
240 }
241 }
242
243 static BOOL
244 build_startup_procs(void)
245 {
246 PWTS_PROCESS_INFO pinfo;
247 DWORD i, j, count;
248
249 if (!WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pinfo, &count))
250 return FALSE;
251
252 g_startup_num_procs = 0;
253
254 for (i = 0; i < count; i++)
255 {
256 if (pinfo[i].SessionId != g_session_id)
257 continue;
258
259 g_startup_num_procs++;
260 }
261
262 g_startup_procs = malloc(sizeof(DWORD) * g_startup_num_procs);
263
264 j = 0;
265 for (i = 0; i < count; i++)
266 {
267 if (pinfo[i].SessionId != g_session_id)
268 continue;
269
270 g_startup_procs[j] = pinfo[i].ProcessId;
271 j++;
272 }
273
274 WTSFreeMemory(pinfo);
275
276 return TRUE;
277 }
278
279 static void
280 free_startup_procs(void)
281 {
282 free(g_startup_procs);
283
284 g_startup_procs = NULL;
285 g_startup_num_procs = 0;
286 }
287
288 static BOOL
289 should_terminate(void)
290 {
291 PWTS_PROCESS_INFO pinfo;
292 DWORD i, j, count;
293
294 if (!WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pinfo, &count))
295 return TRUE;
296
297 for (i = 0; i < count; i++)
298 {
299 if (pinfo[i].SessionId != g_session_id)
300 continue;
301
302 for (j = 0; j < g_startup_num_procs; j++)
303 {
304 if (pinfo[i].ProcessId == g_startup_procs[j])
305 break;
306 }
307
308 if (j == g_startup_num_procs)
309 {
310 WTSFreeMemory(pinfo);
311 return FALSE;
312 }
313 }
314
315 WTSFreeMemory(pinfo);
316
317 return TRUE;
318 }
319
320 static BOOL
321 is_connected(void)
322 {
323 BOOL res;
324 INT *state;
325 DWORD size;
326
327 res = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
328 WTS_CURRENT_SESSION, WTSConnectState, (LPTSTR *) & state,
329 &size);
330 if (!res)
331 return TRUE;
332
333 res = *state == WTSActive;
334
335 WTSFreeMemory(state);
336
337 return res;
338 }
339
340 static BOOL
341 is_desktop_hidden(void)
342 {
343 HDESK desk;
344
345 /* We cannot get current desktop. But we can try to open the current
346 desktop, which will most likely be a secure desktop (if it isn't
347 ours), and will thus fail. */
348 desk = OpenInputDesktop(0, FALSE, GENERIC_READ);
349 if (desk)
350 CloseDesktop(desk);
351
352 return desk == NULL;
353 }
354
355 int WINAPI
356 WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmdline, int cmdshow)
357 {
358 HMODULE hookdll;
359
360 set_hooks_proc_t set_hooks_fn;
361 remove_hooks_proc_t remove_hooks_fn;
362 get_instance_count_proc_t instance_count_fn;
363
364 g_instance = instance;
365
366 hookdll = LoadLibrary("seamlessrdp.dll");
367 if (!hookdll)
368 {
369 message("Could not load hook DLL. Unable to continue.");
370 return -1;
371 }
372
373 set_hooks_fn = (set_hooks_proc_t) GetProcAddress(hookdll, "SetHooks");
374 remove_hooks_fn = (remove_hooks_proc_t) GetProcAddress(hookdll, "RemoveHooks");
375 instance_count_fn = (get_instance_count_proc_t) GetProcAddress(hookdll, "GetInstanceCount");
376 g_move_window_fn = (move_window_proc_t) GetProcAddress(hookdll, "SafeMoveWindow");
377 g_zchange_fn = (zchange_proc_t) GetProcAddress(hookdll, "SafeZChange");
378 g_focus_fn = (focus_proc_t) GetProcAddress(hookdll, "SafeFocus");
379 g_set_state_fn = (set_state_proc_t) GetProcAddress(hookdll, "SafeSetState");
380
381 if (!set_hooks_fn || !remove_hooks_fn || !instance_count_fn || !g_move_window_fn
382 || !g_zchange_fn || !g_focus_fn || !g_set_state_fn)
383 {
384 FreeLibrary(hookdll);
385 message("Hook DLL doesn't contain the correct functions. Unable to continue.");
386 return -1;
387 }
388
389 /* Check if the DLL is already loaded */
390 if (instance_count_fn() != 1)
391 {
392 FreeLibrary(hookdll);
393 message("Another running instance of Seamless RDP detected.");
394 return -1;
395 }
396
397 ProcessIdToSessionId(GetCurrentProcessId(), &g_session_id);
398
399 build_startup_procs();
400
401 vchannel_open();
402
403 g_connected = is_connected();
404 g_desktop_hidden = is_desktop_hidden();
405
406 vchannel_write("HELLO", "0x%08x", g_desktop_hidden ? SEAMLESS_HELLO_HIDDEN : 0);
407
408 set_hooks_fn();
409
410 /* Since we don't see the entire desktop we must resize windows
411 immediatly. */
412 SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0);
413
414 /* Disable screen saver since we cannot catch its windows. */
415 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
416
417 /* We don't want windows denying requests to activate windows. */
418 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0);
419
420 if (strlen(cmdline) == 0)
421 {
422 message("No command line specified.");
423 return -1;
424 }
425 else
426 {
427 BOOL result;
428 PROCESS_INFORMATION proc_info;
429 STARTUPINFO startup_info;
430 MSG msg;
431
432 memset(&startup_info, 0, sizeof(STARTUPINFO));
433 startup_info.cb = sizeof(STARTUPINFO);
434
435 result = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0,
436 NULL, NULL, &startup_info, &proc_info);
437 // Release handles
438 CloseHandle(proc_info.hProcess);
439 CloseHandle(proc_info.hThread);
440
441 if (result)
442 {
443 int check_counter;
444
445 check_counter = 5;
446 while (check_counter-- || !should_terminate())
447 {
448 BOOL connected;
449
450 connected = is_connected();
451 if (connected && !g_connected)
452 {
453 int flags;
454 /* These get reset on each reconnect */
455 SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0);
456 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL,
457 0);
458 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0);
459
460 flags = SEAMLESS_HELLO_RECONNECT;
461 if (g_desktop_hidden)
462 flags |= SEAMLESS_HELLO_HIDDEN;
463 vchannel_write("HELLO", "0x%08x", flags);
464 }
465
466 g_connected = connected;
467
468 if (check_counter < 0)
469 {
470 BOOL hidden;
471
472 hidden = is_desktop_hidden();
473 if (hidden && !g_desktop_hidden)
474 vchannel_write("HIDE", "0x%08x", 0);
475 else if (!hidden && g_desktop_hidden)
476 vchannel_write("UNHIDE", "0x%08x", 0);
477
478 g_desktop_hidden = hidden;
479
480 check_counter = 5;
481 }
482
483 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
484 {
485 TranslateMessage(&msg);
486 DispatchMessage(&msg);
487 }
488 process_cmds();
489 Sleep(100);
490 }
491 }
492 else
493 {
494 // CreateProcess failed.
495 char msg[256];
496 _snprintf(msg, sizeof(msg),
497 "Unable to launch the requested application:\n%s", cmdline);
498 message(msg);
499 }
500 }
501
502 remove_hooks_fn();
503
504 FreeLibrary(hookdll);
505
506 vchannel_close();
507
508 free_startup_procs();
509
510 return 1;
511 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26