winstation.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. /*
  2. * Server-side window stations and desktops handling
  3. *
  4. * Copyright (C) 2002, 2005 Alexandre Julliard
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include "config.h"
  21. #include "wine/port.h"
  22. #include <stdio.h>
  23. #include <stdarg.h>
  24. #include "ntstatus.h"
  25. #define WIN32_NO_STATUS
  26. #include "windef.h"
  27. #include "winbase.h"
  28. #include "winuser.h"
  29. #include "winternl.h"
  30. #include "object.h"
  31. #include "handle.h"
  32. #include "request.h"
  33. #include "process.h"
  34. #include "user.h"
  35. #include "file.h"
  36. #include "security.h"
  37. #include "unicode.h"
  38. static struct list winstation_list = LIST_INIT(winstation_list);
  39. static void winstation_dump( struct object *obj, int verbose );
  40. static struct object_type *winstation_get_type( struct object *obj );
  41. static int winstation_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
  42. static struct object *winstation_lookup_name( struct object *obj, struct unicode_str *name,
  43. unsigned int attr );
  44. static void winstation_destroy( struct object *obj );
  45. static unsigned int winstation_map_access( struct object *obj, unsigned int access );
  46. static void desktop_dump( struct object *obj, int verbose );
  47. static struct object_type *desktop_get_type( struct object *obj );
  48. static int desktop_link_name( struct object *obj, struct object_name *name, struct object *parent );
  49. static void desktop_alloc_handle( struct object *obj, struct process *process, obj_handle_t handle );
  50. static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
  51. static void desktop_destroy( struct object *obj );
  52. static unsigned int desktop_map_access( struct object *obj, unsigned int access );
  53. static const struct object_ops winstation_ops =
  54. {
  55. sizeof(struct winstation), /* size */
  56. winstation_dump, /* dump */
  57. winstation_get_type, /* get_type */
  58. no_add_queue, /* add_queue */
  59. NULL, /* remove_queue */
  60. NULL, /* signaled */
  61. NULL, /* get_esync_fd */
  62. NULL, /* satisfied */
  63. no_signal, /* signal */
  64. no_get_fd, /* get_fd */
  65. winstation_map_access, /* map_access */
  66. default_get_sd, /* get_sd */
  67. default_set_sd, /* set_sd */
  68. winstation_lookup_name, /* lookup_name */
  69. directory_link_name, /* link_name */
  70. default_unlink_name, /* unlink_name */
  71. no_open_file, /* open_file */
  72. no_kernel_obj_list, /* get_kernel_obj_list */
  73. no_alloc_handle, /* alloc_handle */
  74. winstation_close_handle, /* close_handle */
  75. winstation_destroy /* destroy */
  76. };
  77. static const struct object_ops desktop_ops =
  78. {
  79. sizeof(struct desktop), /* size */
  80. desktop_dump, /* dump */
  81. desktop_get_type, /* get_type */
  82. no_add_queue, /* add_queue */
  83. NULL, /* remove_queue */
  84. NULL, /* signaled */
  85. NULL, /* get_esync_fd */
  86. NULL, /* satisfied */
  87. no_signal, /* signal */
  88. no_get_fd, /* get_fd */
  89. desktop_map_access, /* map_access */
  90. default_get_sd, /* get_sd */
  91. default_set_sd, /* set_sd */
  92. no_lookup_name, /* lookup_name */
  93. desktop_link_name, /* link_name */
  94. default_unlink_name, /* unlink_name */
  95. no_open_file, /* open_file */
  96. no_kernel_obj_list, /* get_kernel_obj_list */
  97. desktop_alloc_handle, /* alloc_handle */
  98. desktop_close_handle, /* close_handle */
  99. desktop_destroy /* destroy */
  100. };
  101. #define DESKTOP_ALL_ACCESS 0x01ff
  102. /* create a winstation object */
  103. static struct winstation *create_winstation( struct object *root, const struct unicode_str *name,
  104. unsigned int attr, unsigned int flags )
  105. {
  106. static unsigned int id = 0x10000;
  107. struct winstation *winstation;
  108. struct unicode_str default_name;
  109. char buffer[32];
  110. if (name->len)
  111. {
  112. winstation = create_named_object( root, &winstation_ops, name, attr, NULL );
  113. goto done;
  114. }
  115. do
  116. {
  117. if (!++id) id = 1; /* avoid an id of 0 */
  118. sprintf( buffer, "Service-0x0-%x$", id);
  119. ascii_to_unicode_str( buffer, &default_name );
  120. winstation = create_named_object( root, &winstation_ops, &default_name, attr & ~OBJ_OPENIF, NULL );
  121. }
  122. while (!winstation && get_error() == STATUS_OBJECT_NAME_COLLISION);
  123. done:
  124. if (winstation)
  125. {
  126. if (get_error() != STATUS_OBJECT_NAME_EXISTS)
  127. {
  128. /* initialize it if it didn't already exist */
  129. winstation->flags = flags;
  130. winstation->clipboard = NULL;
  131. winstation->atom_table = NULL;
  132. list_add_tail( &winstation_list, &winstation->entry );
  133. list_init( &winstation->desktops );
  134. if (!(winstation->desktop_names = create_namespace( 7 )))
  135. {
  136. release_object( winstation );
  137. return NULL;
  138. }
  139. }
  140. else clear_error();
  141. }
  142. return winstation;
  143. }
  144. static void winstation_dump( struct object *obj, int verbose )
  145. {
  146. struct winstation *winstation = (struct winstation *)obj;
  147. fprintf( stderr, "Winstation flags=%x clipboard=%p atoms=%p\n",
  148. winstation->flags, winstation->clipboard, winstation->atom_table );
  149. }
  150. static struct object_type *winstation_get_type( struct object *obj )
  151. {
  152. static const struct unicode_str str = { type_WindowStation, sizeof(type_WindowStation) };
  153. return get_object_type( &str );
  154. }
  155. static int winstation_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
  156. {
  157. return (process->winstation != handle);
  158. }
  159. static struct object *winstation_lookup_name( struct object *obj, struct unicode_str *name,
  160. unsigned int attr )
  161. {
  162. struct winstation *winstation = (struct winstation *)obj;
  163. struct object *found;
  164. assert( obj->ops == &winstation_ops );
  165. if (!name) return NULL; /* open the winstation itself */
  166. if (get_path_element( name->str, name->len ) < name->len) /* no backslash allowed in name */
  167. {
  168. set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
  169. return NULL;
  170. }
  171. if ((found = find_object( winstation->desktop_names, name, attr )))
  172. name->len = 0;
  173. return found;
  174. }
  175. static void winstation_destroy( struct object *obj )
  176. {
  177. struct winstation *winstation = (struct winstation *)obj;
  178. list_remove( &winstation->entry );
  179. if (winstation->clipboard) release_object( winstation->clipboard );
  180. if (winstation->atom_table) release_object( winstation->atom_table );
  181. free( winstation->desktop_names );
  182. }
  183. static unsigned int winstation_map_access( struct object *obj, unsigned int access )
  184. {
  185. if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES |
  186. WINSTA_ENUMERATE | WINSTA_READSCREEN;
  187. if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP |
  188. WINSTA_WRITEATTRIBUTES;
  189. if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS;
  190. if (access & GENERIC_ALL) access |= STANDARD_RIGHTS_REQUIRED | WINSTA_ALL_ACCESS;
  191. return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
  192. }
  193. /* retrieve the process window station, checking the handle access rights */
  194. struct winstation *get_process_winstation( struct process *process, unsigned int access )
  195. {
  196. return (struct winstation *)get_handle_obj( process, process->winstation,
  197. access, &winstation_ops );
  198. }
  199. /* retrieve a pointer to a desktop object */
  200. struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, unsigned int access )
  201. {
  202. return (struct desktop *)get_handle_obj( process, handle, access, &desktop_ops );
  203. }
  204. /* create a desktop object */
  205. static struct desktop *create_desktop( const struct unicode_str *name, unsigned int attr,
  206. unsigned int flags, struct winstation *winstation )
  207. {
  208. struct desktop *desktop;
  209. if ((desktop = create_named_object( &winstation->obj, &desktop_ops, name, attr, NULL )))
  210. {
  211. if (get_error() != STATUS_OBJECT_NAME_EXISTS)
  212. {
  213. /* initialize it if it didn't already exist */
  214. desktop->flags = flags;
  215. desktop->winstation = (struct winstation *)grab_object( winstation );
  216. desktop->top_window = NULL;
  217. desktop->msg_window = NULL;
  218. desktop->global_hooks = NULL;
  219. desktop->close_timeout = NULL;
  220. desktop->foreground_input = NULL;
  221. desktop->users = 0;
  222. memset( &desktop->cursor, 0, sizeof(desktop->cursor) );
  223. memset( desktop->keystate, 0, sizeof(desktop->keystate) );
  224. list_add_tail( &winstation->desktops, &desktop->entry );
  225. list_init( &desktop->hotkeys );
  226. }
  227. else clear_error();
  228. }
  229. return desktop;
  230. }
  231. static void desktop_dump( struct object *obj, int verbose )
  232. {
  233. struct desktop *desktop = (struct desktop *)obj;
  234. fprintf( stderr, "Desktop flags=%x winstation=%p top_win=%p hooks=%p\n",
  235. desktop->flags, desktop->winstation, desktop->top_window, desktop->global_hooks );
  236. }
  237. static struct object_type *desktop_get_type( struct object *obj )
  238. {
  239. static const struct unicode_str str = { type_Desktop, sizeof(type_Desktop) };
  240. return get_object_type( &str );
  241. }
  242. static int desktop_link_name( struct object *obj, struct object_name *name, struct object *parent )
  243. {
  244. struct winstation *winstation = (struct winstation *)parent;
  245. if (parent->ops != &winstation_ops)
  246. {
  247. set_error( STATUS_OBJECT_TYPE_MISMATCH );
  248. return 0;
  249. }
  250. if (get_path_element( name->name, name->len ) < name->len) /* no backslash allowed in name */
  251. {
  252. set_error( STATUS_OBJECT_PATH_SYNTAX_BAD );
  253. return 0;
  254. }
  255. namespace_add( winstation->desktop_names, name );
  256. return 1;
  257. }
  258. static void close_desktop_timeout( void *private )
  259. {
  260. struct desktop *desktop = private;
  261. desktop->close_timeout = NULL;
  262. unlink_named_object( &desktop->obj ); /* make sure no other process can open it */
  263. post_desktop_message( desktop, WM_CLOSE, 0, 0 ); /* and signal the owner to quit */
  264. }
  265. /* remove a user of the desktop and start the close timeout if necessary */
  266. static void remove_desktop_user( struct desktop *desktop )
  267. {
  268. assert( desktop->users > 0 );
  269. desktop->users--;
  270. if (!desktop->users && get_top_window_owner( desktop ))
  271. {
  272. assert( !desktop->close_timeout );
  273. desktop->close_timeout = add_timeout_user( -TICKS_PER_SEC, close_desktop_timeout, desktop );
  274. }
  275. }
  276. static void desktop_alloc_handle( struct object *obj, struct process *process, obj_handle_t handle )
  277. {
  278. struct desktop *desktop = (struct desktop *)obj;
  279. if (process->is_system) return;
  280. desktop->users++;
  281. if (desktop->close_timeout)
  282. {
  283. remove_timeout_user( desktop->close_timeout );
  284. desktop->close_timeout = NULL;
  285. }
  286. }
  287. static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
  288. {
  289. struct desktop *desktop = (struct desktop *)obj;
  290. struct thread *thread;
  291. /* check if the handle is currently used by the process or one of its threads */
  292. if (process->desktop == handle) return 0;
  293. LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
  294. if (thread->desktop == handle) return 0;
  295. if (!process->is_system)
  296. remove_desktop_user( desktop );
  297. return 1;
  298. }
  299. static void desktop_destroy( struct object *obj )
  300. {
  301. struct desktop *desktop = (struct desktop *)obj;
  302. assert( !desktop->users );
  303. free_hotkeys( desktop, 0 );
  304. if (desktop->top_window) destroy_window( desktop->top_window );
  305. if (desktop->msg_window) destroy_window( desktop->msg_window );
  306. if (desktop->global_hooks) release_object( desktop->global_hooks );
  307. if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout );
  308. list_remove( &desktop->entry );
  309. release_object( desktop->winstation );
  310. }
  311. static unsigned int desktop_map_access( struct object *obj, unsigned int access )
  312. {
  313. if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | DESKTOP_READOBJECTS | DESKTOP_ENUMERATE;
  314. if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE | DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
  315. DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK |
  316. DESKTOP_WRITEOBJECTS;
  317. if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE | DESKTOP_SWITCHDESKTOP;
  318. if (access & GENERIC_ALL) access |= STANDARD_RIGHTS_REQUIRED | DESKTOP_ALL_ACCESS;
  319. return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
  320. }
  321. /* retrieve the thread desktop, checking the handle access rights */
  322. struct desktop *get_thread_desktop( struct thread *thread, unsigned int access )
  323. {
  324. return get_desktop_obj( thread->process, thread->desktop, access );
  325. }
  326. /* set the process default desktop handle */
  327. void set_process_default_desktop( struct process *process, struct desktop *desktop,
  328. obj_handle_t handle )
  329. {
  330. struct thread *thread;
  331. struct desktop *old_desktop;
  332. if (process->desktop == handle) return; /* nothing to do */
  333. if (!(old_desktop = get_desktop_obj( process, process->desktop, 0 ))) clear_error();
  334. process->desktop = handle;
  335. /* set desktop for threads that don't have one yet */
  336. LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
  337. if (!thread->desktop) thread->desktop = handle;
  338. if (old_desktop) release_object( old_desktop );
  339. }
  340. /* connect a process to its window station */
  341. void connect_process_winstation( struct process *process, struct thread *parent_thread,
  342. struct process *parent_process )
  343. {
  344. struct winstation *winstation = NULL;
  345. struct desktop *desktop = NULL;
  346. obj_handle_t handle;
  347. /* check for an inherited winstation handle (don't ask...) */
  348. if ((handle = find_inherited_handle( process, &winstation_ops )))
  349. {
  350. winstation = (struct winstation *)get_handle_obj( process, handle, 0, &winstation_ops );
  351. }
  352. else if (parent_process->winstation)
  353. {
  354. handle = duplicate_handle( parent_process, parent_process->winstation,
  355. process, 0, 0, DUP_HANDLE_SAME_ACCESS );
  356. winstation = (struct winstation *)get_handle_obj( process, handle, 0, &winstation_ops );
  357. }
  358. if (!winstation) goto done;
  359. process->winstation = handle;
  360. if ((handle = find_inherited_handle( process, &desktop_ops )))
  361. {
  362. desktop = get_desktop_obj( process, handle, 0 );
  363. if (!desktop || desktop->winstation != winstation) goto done;
  364. }
  365. else
  366. {
  367. if (parent_thread && parent_thread->desktop)
  368. handle = parent_thread->desktop;
  369. else if (parent_process->desktop)
  370. handle = parent_process->desktop;
  371. else
  372. goto done;
  373. desktop = get_desktop_obj( parent_process, handle, 0 );
  374. if (!desktop || desktop->winstation != winstation) goto done;
  375. handle = duplicate_handle( parent_process, handle, process, 0, 0, DUP_HANDLE_SAME_ACCESS );
  376. }
  377. if (handle) set_process_default_desktop( process, desktop, handle );
  378. done:
  379. if (desktop) release_object( desktop );
  380. if (winstation) release_object( winstation );
  381. clear_error();
  382. }
  383. /* close the desktop of a given process */
  384. void close_process_desktop( struct process *process )
  385. {
  386. struct desktop *desktop;
  387. unsigned int i = 0;
  388. while (enumerate_handles( process, &desktop_ops, &i, (struct object **)&desktop ))
  389. {
  390. remove_desktop_user( desktop );
  391. release_object( desktop );
  392. }
  393. clear_error(); /* ignore errors */
  394. }
  395. /* close the desktop of a given thread */
  396. void close_thread_desktop( struct thread *thread )
  397. {
  398. obj_handle_t handle = thread->desktop;
  399. thread->desktop = 0;
  400. if (handle) close_handle( thread->process, handle );
  401. }
  402. /* create a window station */
  403. DECL_HANDLER(create_winstation)
  404. {
  405. struct winstation *winstation;
  406. struct unicode_str name = get_req_unicode_str();
  407. struct object *root = NULL;
  408. reply->handle = 0;
  409. if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir ))) return;
  410. if ((winstation = create_winstation( root, &name, req->attributes, req->flags )))
  411. {
  412. reply->handle = alloc_handle( current->process, winstation, req->access, req->attributes );
  413. release_object( winstation );
  414. }
  415. if (root) release_object( root );
  416. }
  417. /* open a handle to a window station */
  418. DECL_HANDLER(open_winstation)
  419. {
  420. struct unicode_str name = get_req_unicode_str();
  421. reply->handle = open_object( current->process, req->rootdir, req->access,
  422. &winstation_ops, &name, req->attributes );
  423. }
  424. /* close a window station */
  425. DECL_HANDLER(close_winstation)
  426. {
  427. struct winstation *winstation;
  428. if ((winstation = (struct winstation *)get_handle_obj( current->process, req->handle,
  429. 0, &winstation_ops )))
  430. {
  431. if (close_handle( current->process, req->handle )) set_error( STATUS_ACCESS_DENIED );
  432. release_object( winstation );
  433. }
  434. }
  435. /* get the process current window station */
  436. DECL_HANDLER(get_process_winstation)
  437. {
  438. reply->handle = current->process->winstation;
  439. }
  440. /* set the process current window station */
  441. DECL_HANDLER(set_process_winstation)
  442. {
  443. struct winstation *winstation;
  444. if ((winstation = (struct winstation *)get_handle_obj( current->process, req->handle,
  445. 0, &winstation_ops )))
  446. {
  447. /* FIXME: should we close the old one? */
  448. current->process->winstation = req->handle;
  449. release_object( winstation );
  450. }
  451. }
  452. /* create a desktop */
  453. DECL_HANDLER(create_desktop)
  454. {
  455. struct desktop *desktop;
  456. struct winstation *winstation;
  457. struct unicode_str name = get_req_unicode_str();
  458. reply->handle = 0;
  459. if ((winstation = get_process_winstation( current->process, WINSTA_CREATEDESKTOP )))
  460. {
  461. if ((desktop = create_desktop( &name, req->attributes, req->flags, winstation )))
  462. {
  463. reply->handle = alloc_handle( current->process, desktop, req->access, req->attributes );
  464. release_object( desktop );
  465. }
  466. release_object( winstation );
  467. }
  468. }
  469. /* open a handle to a desktop */
  470. DECL_HANDLER(open_desktop)
  471. {
  472. struct winstation *winstation;
  473. struct object *obj;
  474. struct unicode_str name = get_req_unicode_str();
  475. /* FIXME: check access rights */
  476. if (!req->winsta)
  477. winstation = get_process_winstation( current->process, 0 );
  478. else
  479. winstation = (struct winstation *)get_handle_obj( current->process, req->winsta, 0, &winstation_ops );
  480. if (!winstation) return;
  481. if ((obj = open_named_object( &winstation->obj, &desktop_ops, &name, req->attributes )))
  482. {
  483. reply->handle = alloc_handle( current->process, obj, req->access, req->attributes );
  484. release_object( obj );
  485. }
  486. release_object( winstation );
  487. }
  488. /* open a handle to current input desktop */
  489. DECL_HANDLER(open_input_desktop)
  490. {
  491. /* FIXME: check access rights */
  492. struct winstation *winstation = get_process_winstation( current->process, 0 );
  493. struct desktop *desktop;
  494. if (!winstation) return;
  495. if (!(winstation->flags & WSF_VISIBLE))
  496. {
  497. set_error( STATUS_ILLEGAL_FUNCTION );
  498. release_object( winstation );
  499. return;
  500. }
  501. if ((desktop = get_desktop_obj( current->process, current->process->desktop, 0 )))
  502. {
  503. reply->handle = alloc_handle( current->process, desktop, req->access, req->attributes );
  504. release_object( desktop );
  505. }
  506. release_object( winstation );
  507. }
  508. /* close a desktop */
  509. DECL_HANDLER(close_desktop)
  510. {
  511. struct desktop *desktop;
  512. /* make sure it is a desktop handle */
  513. if ((desktop = (struct desktop *)get_handle_obj( current->process, req->handle,
  514. 0, &desktop_ops )))
  515. {
  516. if (close_handle( current->process, req->handle )) set_error( STATUS_DEVICE_BUSY );
  517. release_object( desktop );
  518. }
  519. }
  520. /* get the thread current desktop */
  521. DECL_HANDLER(get_thread_desktop)
  522. {
  523. struct thread *thread;
  524. if (!(thread = get_thread_from_id( req->tid ))) return;
  525. reply->handle = thread->desktop;
  526. release_object( thread );
  527. }
  528. /* set the thread current desktop */
  529. DECL_HANDLER(set_thread_desktop)
  530. {
  531. struct desktop *old_desktop, *new_desktop;
  532. struct winstation *winstation;
  533. if (!(winstation = get_process_winstation( current->process, 0 /* FIXME: access rights? */ )))
  534. return;
  535. if (!(new_desktop = get_desktop_obj( current->process, req->handle, 0 )))
  536. {
  537. release_object( winstation );
  538. return;
  539. }
  540. if (new_desktop->winstation != winstation)
  541. {
  542. set_error( STATUS_ACCESS_DENIED );
  543. release_object( new_desktop );
  544. release_object( winstation );
  545. return;
  546. }
  547. /* check if we are changing to a new desktop */
  548. if (!(old_desktop = get_desktop_obj( current->process, current->desktop, 0)))
  549. clear_error(); /* ignore error */
  550. /* when changing desktop, we can't have any users on the current one */
  551. if (old_desktop != new_desktop && current->desktop_users > 0)
  552. set_error( STATUS_DEVICE_BUSY );
  553. else
  554. current->desktop = req->handle; /* FIXME: should we close the old one? */
  555. if (!current->process->desktop)
  556. set_process_default_desktop( current->process, new_desktop, req->handle );
  557. if (old_desktop != new_desktop && current->queue) detach_thread_input( current );
  558. if (old_desktop) release_object( old_desktop );
  559. release_object( new_desktop );
  560. release_object( winstation );
  561. }
  562. /* get/set information about a user object (window station or desktop) */
  563. DECL_HANDLER(set_user_object_info)
  564. {
  565. struct object *obj;
  566. data_size_t len;
  567. if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL ))) return;
  568. if (obj->ops == &desktop_ops)
  569. {
  570. struct desktop *desktop = (struct desktop *)obj;
  571. reply->is_desktop = 1;
  572. reply->old_obj_flags = desktop->flags;
  573. if (req->flags & SET_USER_OBJECT_SET_FLAGS) desktop->flags = req->obj_flags;
  574. }
  575. else if (obj->ops == &winstation_ops)
  576. {
  577. struct winstation *winstation = (struct winstation *)obj;
  578. reply->is_desktop = 0;
  579. reply->old_obj_flags = winstation->flags;
  580. if (req->flags & SET_USER_OBJECT_SET_FLAGS) winstation->flags = req->obj_flags;
  581. }
  582. else
  583. {
  584. set_error( STATUS_OBJECT_TYPE_MISMATCH );
  585. release_object( obj );
  586. return;
  587. }
  588. if (obj->ops == &desktop_ops && get_reply_max_size() && (req->flags & SET_USER_OBJECT_GET_FULL_NAME))
  589. {
  590. struct desktop *desktop = (struct desktop *)obj;
  591. data_size_t winstation_len, desktop_len;
  592. const WCHAR *winstation_name = get_object_name( &desktop->winstation->obj, &winstation_len );
  593. const WCHAR *desktop_name = get_object_name( obj, &desktop_len );
  594. WCHAR *full_name;
  595. if (!winstation_name) winstation_len = 0;
  596. if (!desktop_name) desktop_len = 0;
  597. len = winstation_len + desktop_len + sizeof(WCHAR);
  598. if ((full_name = mem_alloc( len )))
  599. {
  600. memcpy( full_name, winstation_name, winstation_len );
  601. full_name[winstation_len / sizeof(WCHAR)] = '\\';
  602. memcpy( full_name + winstation_len / sizeof(WCHAR) + 1, desktop_name, desktop_len );
  603. set_reply_data_ptr( full_name, min( len, get_reply_max_size() ));
  604. }
  605. }
  606. else
  607. {
  608. const WCHAR *name = get_object_name( obj, &len );
  609. if (name) set_reply_data( name, min( len, get_reply_max_size() ));
  610. }
  611. release_object( obj );
  612. }
  613. /* enumerate window stations */
  614. DECL_HANDLER(enum_winstation)
  615. {
  616. unsigned int index = 0;
  617. struct winstation *winsta;
  618. const WCHAR *name;
  619. data_size_t len;
  620. LIST_FOR_EACH_ENTRY( winsta, &winstation_list, struct winstation, entry )
  621. {
  622. unsigned int access = WINSTA_ENUMERATE;
  623. if (req->index > index++) continue;
  624. if (!check_object_access( &winsta->obj, &access )) continue;
  625. clear_error();
  626. reply->next = index;
  627. if ((name = get_object_name( &winsta->obj, &len )))
  628. set_reply_data( name, min( len, get_reply_max_size() ));
  629. return;
  630. }
  631. set_error( STATUS_NO_MORE_ENTRIES );
  632. }
  633. /* enumerate desktops */
  634. DECL_HANDLER(enum_desktop)
  635. {
  636. struct winstation *winstation;
  637. struct desktop *desktop;
  638. unsigned int index = 0;
  639. const WCHAR *name;
  640. data_size_t len;
  641. if (!(winstation = (struct winstation *)get_handle_obj( current->process, req->winstation,
  642. WINSTA_ENUMDESKTOPS, &winstation_ops )))
  643. return;
  644. LIST_FOR_EACH_ENTRY( desktop, &winstation->desktops, struct desktop, entry )
  645. {
  646. unsigned int access = DESKTOP_ENUMERATE;
  647. if (req->index > index++) continue;
  648. if (!desktop->obj.name) continue;
  649. if (!check_object_access( &desktop->obj, &access )) continue;
  650. if ((name = get_object_name( &desktop->obj, &len )))
  651. set_reply_data( name, min( len, get_reply_max_size() ));
  652. release_object( winstation );
  653. clear_error();
  654. reply->next = index;
  655. return;
  656. }
  657. release_object( winstation );
  658. set_error( STATUS_NO_MORE_ENTRIES );
  659. }