1 /* 2 * PROJECT: ReactOS user32.dll 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Window stations 5 * COPYRIGHT: Copyright 2001-2018 Casper S. Hornstrup (chorns@users.sourceforge.net) 6 * Copyright 2011-2018 Giannis Adamopoulos 7 */ 8 9 #include <user32.h> 10 11 WINE_DEFAULT_DEBUG_CHANNEL(winsta); 12 13 /* 14 * @implemented 15 */ 16 HWINSTA 17 WINAPI 18 CreateWindowStationA( 19 IN LPCSTR lpwinsta OPTIONAL, 20 IN DWORD dwReserved, 21 IN ACCESS_MASK dwDesiredAccess, 22 IN LPSECURITY_ATTRIBUTES lpsa OPTIONAL) 23 { 24 HWINSTA hWinSta; 25 UNICODE_STRING WindowStationNameU; 26 27 if (lpwinsta) 28 { 29 /* After conversion, the buffer is zero-terminated */ 30 RtlCreateUnicodeStringFromAsciiz(&WindowStationNameU, lpwinsta); 31 } 32 else 33 { 34 RtlInitUnicodeString(&WindowStationNameU, NULL); 35 } 36 37 hWinSta = CreateWindowStationW(WindowStationNameU.Buffer, 38 dwReserved, 39 dwDesiredAccess, 40 lpsa); 41 42 /* Free the string if it was allocated */ 43 if (lpwinsta) RtlFreeUnicodeString(&WindowStationNameU); 44 45 return hWinSta; 46 } 47 48 49 /* 50 * @implemented 51 */ 52 HWINSTA 53 WINAPI 54 CreateWindowStationW( 55 IN LPCWSTR lpwinsta OPTIONAL, 56 IN DWORD dwReserved, 57 IN ACCESS_MASK dwDesiredAccess, 58 IN LPSECURITY_ATTRIBUTES lpsa OPTIONAL) 59 { 60 NTSTATUS Status; 61 HWINSTA hWinSta; 62 UNICODE_STRING WindowStationName; 63 // FIXME: We should cache a per-session directory (see ntuser\winsta.c!UserCreateWinstaDirectory). 64 UNICODE_STRING WindowStationsDir = RTL_CONSTANT_STRING(L"\\Windows\\WindowStations"); 65 OBJECT_ATTRIBUTES ObjectAttributes; 66 HANDLE hWindowStationsDir; 67 68 /* 69 * If provided, the window station name is always relative to the 70 * current user session's WindowStations directory. 71 * Otherwise (the window station name is NULL or an empty string), 72 * pass both an empty string and no WindowStations directory handle 73 * to win32k, so that it will create a window station whose name 74 * is based on the logon session identifier for the calling process. 75 */ 76 if (lpwinsta && *lpwinsta) 77 { 78 /* Open WindowStations directory */ 79 InitializeObjectAttributes(&ObjectAttributes, 80 &WindowStationsDir, 81 OBJ_CASE_INSENSITIVE, 82 NULL, 83 NULL); 84 85 Status = NtOpenDirectoryObject(&hWindowStationsDir, 86 DIRECTORY_CREATE_OBJECT, 87 &ObjectAttributes); 88 if (!NT_SUCCESS(Status)) 89 { 90 ERR("Failed to open WindowStations directory\n"); 91 return NULL; 92 } 93 94 RtlInitUnicodeString(&WindowStationName, lpwinsta); 95 } 96 else 97 { 98 lpwinsta = NULL; 99 hWindowStationsDir = NULL; 100 } 101 102 /* Create the window station object */ 103 InitializeObjectAttributes(&ObjectAttributes, 104 lpwinsta ? &WindowStationName : NULL, 105 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 106 hWindowStationsDir, 107 NULL); 108 109 /* Check if the handle should be inheritable */ 110 if (lpsa && lpsa->bInheritHandle) 111 { 112 ObjectAttributes.Attributes |= OBJ_INHERIT; 113 } 114 115 hWinSta = NtUserCreateWindowStation(&ObjectAttributes, 116 dwDesiredAccess, 117 0, 0, 0, 0, 0); 118 119 if (hWindowStationsDir) 120 NtClose(hWindowStationsDir); 121 122 return hWinSta; 123 } 124 125 /* 126 * Common code for EnumDesktopsA/W and EnumWindowStationsA/W 127 */ 128 BOOL 129 FASTCALL 130 EnumNamesW(HWINSTA WindowStation, 131 NAMEENUMPROCW EnumFunc, 132 LPARAM Context, 133 BOOL Desktops) 134 { 135 CHAR Buffer[256]; 136 PVOID NameList; 137 PWCHAR Name; 138 NTSTATUS Status; 139 ULONG RequiredSize; 140 ULONG CurrentEntry, EntryCount; 141 BOOL Ret; 142 143 /* Check parameters */ 144 if (WindowStation == NULL && Desktops) 145 { 146 WindowStation = GetProcessWindowStation(); 147 } 148 149 /* Try with fixed-size buffer */ 150 Status = NtUserBuildNameList(WindowStation, sizeof(Buffer), Buffer, &RequiredSize); 151 if (NT_SUCCESS(Status)) 152 { 153 /* Fixed-size buffer is large enough */ 154 NameList = (PWCHAR) Buffer; 155 } 156 else if (Status == STATUS_BUFFER_TOO_SMALL) 157 { 158 /* Allocate a larger buffer */ 159 NameList = HeapAlloc(GetProcessHeap(), 0, RequiredSize); 160 if (NameList == NULL) 161 return FALSE; 162 163 /* Try again */ 164 Status = NtUserBuildNameList(WindowStation, RequiredSize, NameList, NULL); 165 if (!NT_SUCCESS(Status)) 166 { 167 HeapFree(GetProcessHeap(), 0, NameList); 168 SetLastError(RtlNtStatusToDosError(Status)); 169 return FALSE; 170 } 171 } 172 else 173 { 174 /* Some unrecognized error occured */ 175 SetLastError(RtlNtStatusToDosError(Status)); 176 return FALSE; 177 } 178 179 /* Enum the names one by one */ 180 EntryCount = *((DWORD *) NameList); 181 Name = (PWCHAR) ((PCHAR) NameList + sizeof(DWORD)); 182 Ret = TRUE; 183 for (CurrentEntry = 0; CurrentEntry < EntryCount && Ret; ++CurrentEntry) 184 { 185 Ret = (*EnumFunc)(Name, Context); 186 Name += wcslen(Name) + 1; 187 } 188 189 /* Cleanup */ 190 if (NameList != Buffer) 191 { 192 HeapFree(GetProcessHeap(), 0, NameList); 193 } 194 195 return Ret; 196 } 197 198 /* For W->A conversion */ 199 typedef struct tagENUMNAMESASCIICONTEXT 200 { 201 NAMEENUMPROCA UserEnumFunc; 202 LPARAM UserContext; 203 } ENUMNAMESASCIICONTEXT, *PENUMNAMESASCIICONTEXT; 204 205 /* 206 * Callback used by Ascii versions. Converts the Unicode name to 207 * Ascii and then calls the user callback 208 */ 209 BOOL 210 CALLBACK 211 EnumNamesCallback(LPWSTR Name, LPARAM Param) 212 { 213 PENUMNAMESASCIICONTEXT Context = (PENUMNAMESASCIICONTEXT) Param; 214 CHAR FixedNameA[32]; 215 LPSTR NameA; 216 INT Len; 217 BOOL Ret; 218 219 /* 220 * Determine required size of Ascii string and see 221 * if we can use fixed buffer. 222 */ 223 Len = WideCharToMultiByte(CP_ACP, 0, Name, -1, NULL, 0, NULL, NULL); 224 if (Len <= 0) 225 { 226 /* Some strange error occured */ 227 return FALSE; 228 } 229 else if (Len <= sizeof(FixedNameA)) 230 { 231 /* Fixed-size buffer is large enough */ 232 NameA = FixedNameA; 233 } 234 else 235 { 236 /* Allocate a larger buffer */ 237 NameA = HeapAlloc(GetProcessHeap(), 0, Len); 238 if (NULL == NameA) 239 { 240 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 241 return FALSE; 242 } 243 } 244 245 /* Do the Unicode ->Ascii conversion */ 246 if (0 == WideCharToMultiByte(CP_ACP, 0, Name, -1, NameA, Len, NULL, NULL)) 247 { 248 /* Something went wrong, clean up */ 249 if (NameA != FixedNameA) 250 { 251 HeapFree(GetProcessHeap(), 0, NameA); 252 } 253 return FALSE; 254 } 255 256 /* Call user callback */ 257 Ret = Context->UserEnumFunc(NameA, Context->UserContext); 258 259 /* Cleanup */ 260 if (NameA != FixedNameA) 261 { 262 HeapFree(GetProcessHeap(), 0, NameA); 263 } 264 265 return Ret; 266 } 267 268 /* 269 * Common code for EnumDesktopsA and EnumWindowStationsA 270 */ 271 BOOL 272 FASTCALL 273 EnumNamesA(HWINSTA WindowStation, 274 NAMEENUMPROCA EnumFunc, 275 LPARAM Context, 276 BOOL Desktops) 277 { 278 ENUMNAMESASCIICONTEXT PrivateContext; 279 280 PrivateContext.UserEnumFunc = EnumFunc; 281 PrivateContext.UserContext = Context; 282 283 return EnumNamesW(WindowStation, EnumNamesCallback, (LPARAM) &PrivateContext, Desktops); 284 } 285 286 /* 287 * @implemented 288 */ 289 BOOL 290 WINAPI 291 EnumWindowStationsA( 292 IN WINSTAENUMPROCA EnumFunc, 293 IN LPARAM Context) 294 { 295 return EnumNamesA(NULL, EnumFunc, Context, FALSE); 296 } 297 298 299 /* 300 * @implemented 301 */ 302 BOOL 303 WINAPI 304 EnumWindowStationsW( 305 IN WINSTAENUMPROCW EnumFunc, 306 IN LPARAM Context) 307 { 308 return EnumNamesW(NULL, EnumFunc, Context, FALSE); 309 } 310 311 312 /* 313 * @unimplemented on Win32k side 314 */ 315 BOOL 316 WINAPI 317 GetWinStationInfo(PVOID pUnknown) 318 { 319 return (BOOL)NtUserCallOneParam((DWORD_PTR)pUnknown, ONEPARAM_ROUTINE_GETWINSTAINFO); 320 } 321 322 323 /* 324 * @implemented 325 */ 326 HWINSTA 327 WINAPI 328 OpenWindowStationA( 329 IN LPCSTR lpszWinSta, 330 IN BOOL fInherit, 331 IN ACCESS_MASK dwDesiredAccess) 332 { 333 HWINSTA hWinSta; 334 UNICODE_STRING WindowStationNameU; 335 336 if (lpszWinSta) 337 { 338 /* After conversion, the buffer is zero-terminated */ 339 RtlCreateUnicodeStringFromAsciiz(&WindowStationNameU, lpszWinSta); 340 } 341 else 342 { 343 RtlInitUnicodeString(&WindowStationNameU, NULL); 344 } 345 346 hWinSta = OpenWindowStationW(WindowStationNameU.Buffer, 347 fInherit, 348 dwDesiredAccess); 349 350 /* Free the string if it was allocated */ 351 if (lpszWinSta) RtlFreeUnicodeString(&WindowStationNameU); 352 353 return hWinSta; 354 } 355 356 357 /* 358 * @implemented 359 */ 360 HWINSTA 361 WINAPI 362 OpenWindowStationW( 363 IN LPCWSTR lpszWinSta, 364 IN BOOL fInherit, 365 IN ACCESS_MASK dwDesiredAccess) 366 { 367 NTSTATUS Status; 368 HWINSTA hWinSta; 369 UNICODE_STRING WindowStationName; 370 // FIXME: We should cache a per-session directory (see ntuser\winsta.c!UserCreateWinstaDirectory). 371 UNICODE_STRING WindowStationsDir = RTL_CONSTANT_STRING(L"\\Windows\\WindowStations"); 372 OBJECT_ATTRIBUTES ObjectAttributes; 373 HANDLE hWindowStationsDir; 374 375 /* Open WindowStations directory */ 376 InitializeObjectAttributes(&ObjectAttributes, 377 &WindowStationsDir, 378 OBJ_CASE_INSENSITIVE, 379 NULL, 380 NULL); 381 382 Status = NtOpenDirectoryObject(&hWindowStationsDir, 383 DIRECTORY_TRAVERSE, 384 &ObjectAttributes); 385 if(!NT_SUCCESS(Status)) 386 { 387 ERR("Failed to open WindowStations directory\n"); 388 return NULL; 389 } 390 391 /* Open the window station object */ 392 RtlInitUnicodeString(&WindowStationName, lpszWinSta); 393 394 InitializeObjectAttributes(&ObjectAttributes, 395 &WindowStationName, 396 OBJ_CASE_INSENSITIVE, 397 hWindowStationsDir, 398 NULL); 399 400 /* Check if the handle should be inheritable */ 401 if (fInherit) 402 { 403 ObjectAttributes.Attributes |= OBJ_INHERIT; 404 } 405 406 hWinSta = NtUserOpenWindowStation(&ObjectAttributes, dwDesiredAccess); 407 408 NtClose(hWindowStationsDir); 409 410 return hWinSta; 411 } 412 413 414 /* 415 * @implemented 416 */ 417 BOOL 418 WINAPI 419 SetWindowStationUser( 420 IN HWINSTA hWindowStation, 421 IN PLUID pluid, 422 IN PSID psid OPTIONAL, 423 IN DWORD size) 424 { 425 BOOL Success; 426 427 Success = NtUserSetWindowStationUser(hWindowStation, pluid, psid, size); 428 if (Success) 429 { 430 /* Signal log-on/off to WINSRV */ 431 432 /* User is logging on if *pluid != LuidNone, otherwise it is a log-off */ 433 LUID LuidNone = {0, 0}; 434 BOOL IsLogon = (pluid && !RtlEqualLuid(pluid, &LuidNone)); 435 436 Logon(IsLogon); 437 } 438 439 return Success; 440 } 441 442 /* EOF */ 443