/[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 1235 - (show annotations)
Tue May 30 10:39:11 2006 UTC (17 years, 11 months ago) by ossman_
File MIME type: text/plain
File size: 11082 byte(s)
Use a polled system to detect when clients reconnect. This way we can support
Windows 2000 as well.

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 if (styles & WS_POPUP)
109 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
110 else
111 parent = NULL;
112
113 GetWindowThreadProcessId(hwnd, &pid);
114
115 flags = 0;
116 if (styles & DS_MODALFRAME)
117 flags |= SEAMLESS_CREATE_MODAL;
118
119 vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x", (long) hwnd, (long) pid,
120 (long) parent, flags);
121
122 if (!GetWindowRect(hwnd, &rect))
123 {
124 debug("GetWindowRect failed!");
125 return TRUE;
126 }
127
128 vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x",
129 hwnd,
130 rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
131
132 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
133
134 vchannel_write("TITLE", "0x%x,%s,0x%x", hwnd, vchannel_strfilter_unicode(title), 0);
135
136 if (styles & WS_MAXIMIZE)
137 state = 2;
138 else if (styles & WS_MINIMIZE)
139 state = 1;
140 else
141 state = 0;
142
143 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd, state, 0);
144
145 return TRUE;
146 }
147
148 static void
149 do_sync(void)
150 {
151 vchannel_block();
152
153 vchannel_write("SYNCBEGIN", "0x0");
154
155 EnumWindows(enum_cb, 0);
156
157 vchannel_write("SYNCEND", "0x0");
158
159 vchannel_unblock();
160 }
161
162 static void
163 do_state(unsigned int serial, HWND hwnd, int state)
164 {
165 g_set_state_fn(serial, hwnd, state);
166 }
167
168 static void
169 do_position(unsigned int serial, HWND hwnd, int x, int y, int width, int height)
170 {
171 g_move_window_fn(serial, hwnd, x, y, width, height);
172 }
173
174 static void
175 do_zchange(unsigned int serial, HWND hwnd, HWND behind)
176 {
177 g_zchange_fn(serial, hwnd, behind);
178 }
179
180 static void
181 do_focus(unsigned int serial, HWND hwnd)
182 {
183 g_focus_fn(serial, hwnd);
184 }
185
186 static void
187 process_cmds(void)
188 {
189 char line[VCHANNEL_MAX_LINE];
190 int size;
191
192 char *p, *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8;
193
194 while ((size = vchannel_read(line, sizeof(line))) >= 0)
195 {
196 p = line;
197
198 tok1 = get_token(&p);
199 tok2 = get_token(&p);
200 tok3 = get_token(&p);
201 tok4 = get_token(&p);
202 tok5 = get_token(&p);
203 tok6 = get_token(&p);
204 tok7 = get_token(&p);
205 tok8 = get_token(&p);
206
207 if (strcmp(tok1, "SYNC") == 0)
208 do_sync();
209 else if (strcmp(tok1, "STATE") == 0)
210 do_state(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0),
211 strtol(tok4, NULL, 0));
212 else if (strcmp(tok1, "POSITION") == 0)
213 do_position(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0),
214 strtol(tok4, NULL, 0), strtol(tok5, NULL, 0), strtol(tok6, NULL,
215 0),
216 strtol(tok7, NULL, 0));
217 else if (strcmp(tok1, "ZCHANGE") == 0)
218 do_zchange(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0),
219 (HWND) strtoul(tok4, NULL, 0));
220 else if (strcmp(tok1, "FOCUS") == 0)
221 do_focus(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0));
222 }
223 }
224
225 static BOOL
226 build_startup_procs(void)
227 {
228 PWTS_PROCESS_INFO pinfo;
229 DWORD i, j, count;
230
231 if (!WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pinfo, &count))
232 return FALSE;
233
234 g_startup_num_procs = 0;
235
236 for (i = 0; i < count; i++)
237 {
238 if (pinfo[i].SessionId != g_session_id)
239 continue;
240
241 g_startup_num_procs++;
242 }
243
244 g_startup_procs = malloc(sizeof(DWORD) * g_startup_num_procs);
245
246 j = 0;
247 for (i = 0; i < count; i++)
248 {
249 if (pinfo[i].SessionId != g_session_id)
250 continue;
251
252 g_startup_procs[j] = pinfo[i].ProcessId;
253 j++;
254 }
255
256 WTSFreeMemory(pinfo);
257
258 return TRUE;
259 }
260
261 static void
262 free_startup_procs(void)
263 {
264 free(g_startup_procs);
265
266 g_startup_procs = NULL;
267 g_startup_num_procs = 0;
268 }
269
270 static BOOL
271 should_terminate(void)
272 {
273 PWTS_PROCESS_INFO pinfo;
274 DWORD i, j, count;
275
276 if (!WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pinfo, &count))
277 return TRUE;
278
279 for (i = 0; i < count; i++)
280 {
281 if (pinfo[i].SessionId != g_session_id)
282 continue;
283
284 for (j = 0; j < g_startup_num_procs; j++)
285 {
286 if (pinfo[i].ProcessId == g_startup_procs[j])
287 break;
288 }
289
290 if (j == g_startup_num_procs)
291 {
292 WTSFreeMemory(pinfo);
293 return FALSE;
294 }
295 }
296
297 WTSFreeMemory(pinfo);
298
299 return TRUE;
300 }
301
302 static BOOL
303 is_connected(void)
304 {
305 BOOL res;
306 INT *state;
307 DWORD size;
308
309 res = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
310 WTS_CURRENT_SESSION, WTSConnectState, (LPTSTR *) & state,
311 &size);
312 if (!res)
313 return TRUE;
314
315 res = *state == WTSActive;
316
317 WTSFreeMemory(state);
318
319 return res;
320 }
321
322 static BOOL
323 is_desktop_hidden(void)
324 {
325 HDESK desk;
326
327 /* We cannot get current desktop. But we can try to open the current
328 desktop, which will most likely be a secure desktop (if it isn't
329 ours), and will thus fail. */
330 desk = OpenInputDesktop(0, FALSE, GENERIC_READ);
331 if (desk)
332 CloseDesktop(desk);
333
334 return desk == NULL;
335 }
336
337 int WINAPI
338 WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmdline, int cmdshow)
339 {
340 HMODULE hookdll;
341
342 set_hooks_proc_t set_hooks_fn;
343 remove_hooks_proc_t remove_hooks_fn;
344 get_instance_count_proc_t instance_count_fn;
345
346 g_instance = instance;
347
348 hookdll = LoadLibrary("seamlessrdp.dll");
349 if (!hookdll)
350 {
351 message("Could not load hook DLL. Unable to continue.");
352 return -1;
353 }
354
355 set_hooks_fn = (set_hooks_proc_t) GetProcAddress(hookdll, "SetHooks");
356 remove_hooks_fn = (remove_hooks_proc_t) GetProcAddress(hookdll, "RemoveHooks");
357 instance_count_fn = (get_instance_count_proc_t) GetProcAddress(hookdll, "GetInstanceCount");
358 g_move_window_fn = (move_window_proc_t) GetProcAddress(hookdll, "SafeMoveWindow");
359 g_zchange_fn = (zchange_proc_t) GetProcAddress(hookdll, "SafeZChange");
360 g_focus_fn = (focus_proc_t) GetProcAddress(hookdll, "SafeFocus");
361 g_set_state_fn = (set_state_proc_t) GetProcAddress(hookdll, "SafeSetState");
362
363 if (!set_hooks_fn || !remove_hooks_fn || !instance_count_fn || !g_move_window_fn
364 || !g_zchange_fn || !g_focus_fn || !g_set_state_fn)
365 {
366 FreeLibrary(hookdll);
367 message("Hook DLL doesn't contain the correct functions. Unable to continue.");
368 return -1;
369 }
370
371 /* Check if the DLL is already loaded */
372 if (instance_count_fn() != 1)
373 {
374 FreeLibrary(hookdll);
375 message("Another running instance of Seamless RDP detected.");
376 return -1;
377 }
378
379 ProcessIdToSessionId(GetCurrentProcessId(), &g_session_id);
380
381 build_startup_procs();
382
383 vchannel_open();
384
385 g_connected = is_connected();
386 g_desktop_hidden = is_desktop_hidden();
387
388 vchannel_write("HELLO", "0x%08x", g_desktop_hidden ? SEAMLESS_HELLO_HIDDEN : 0);
389
390 set_hooks_fn();
391
392 /* Since we don't see the entire desktop we must resize windows
393 immediatly. */
394 SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0);
395
396 /* Disable screen saver since we cannot catch its windows. */
397 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
398
399 /* We don't want windows denying requests to activate windows. */
400 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0);
401
402 if (strlen(cmdline) == 0)
403 {
404 message("No command line specified.");
405 return -1;
406 }
407 else
408 {
409 BOOL result;
410 PROCESS_INFORMATION proc_info;
411 STARTUPINFO startup_info;
412 MSG msg;
413
414 memset(&startup_info, 0, sizeof(STARTUPINFO));
415 startup_info.cb = sizeof(STARTUPINFO);
416
417 result = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0,
418 NULL, NULL, &startup_info, &proc_info);
419 // Release handles
420 CloseHandle(proc_info.hProcess);
421 CloseHandle(proc_info.hThread);
422
423 if (result)
424 {
425 int check_counter;
426
427 check_counter = 5;
428 while (check_counter-- || !should_terminate())
429 {
430 BOOL connected;
431
432 connected = is_connected();
433 if (connected && !g_connected)
434 {
435 int flags;
436 /* These get reset on each reconnect */
437 SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0);
438 SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL,
439 0);
440 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0);
441
442 flags = SEAMLESS_HELLO_RECONNECT;
443 if (g_desktop_hidden)
444 flags |= SEAMLESS_HELLO_HIDDEN;
445 vchannel_write("HELLO", "0x%08x", flags);
446 }
447
448 g_connected = connected;
449
450 if (check_counter < 0)
451 {
452 BOOL hidden;
453
454 hidden = is_desktop_hidden();
455 if (hidden && !g_desktop_hidden)
456 vchannel_write("HIDE", "0x%08x", 0);
457 else if (!hidden && g_desktop_hidden)
458 vchannel_write("UNHIDE", "0x%08x", 0);
459
460 g_desktop_hidden = hidden;
461
462 check_counter = 5;
463 }
464
465 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
466 {
467 TranslateMessage(&msg);
468 DispatchMessage(&msg);
469 }
470 process_cmds();
471 Sleep(100);
472 }
473 }
474 else
475 {
476 // CreateProcess failed.
477 char msg[256];
478 _snprintf(msg, sizeof(msg),
479 "Unable to launch the requested application:\n%s", cmdline);
480 message(msg);
481 }
482 }
483
484 remove_hooks_fn();
485
486 FreeLibrary(hookdll);
487
488 vchannel_close();
489
490 free_startup_procs();
491
492 return 1;
493 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26