1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: dll/win32/kernel32/client/actctx.c 5 * PURPOSE: Activation contexts - NT-compatible helpers 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * 8 * NOTE: See also kernel32/wine/actctx.c 9 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include <k32.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 #define QUERY_ACTCTX_FLAG_VALID (QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX | \ 18 QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE | \ 19 QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS | \ 20 QUERY_ACTCTX_FLAG_NO_ADDREF) 21 22 /* PRIVATE FUNCTIONS *********************************************************/ 23 24 VOID 25 NTAPI 26 BasepFreeActivationContextActivationBlock(IN PBASEP_ACTCTX_BLOCK ActivationBlock) 27 { 28 /* Exit if there was nothing passed in */ 29 if (!ActivationBlock) return; 30 31 /* Do we have a context? */ 32 if (ActivationBlock->ActivationContext) 33 { 34 /* Release and clear it */ 35 RtlReleaseActivationContext(ActivationBlock->ActivationContext); 36 ActivationBlock->ActivationContext = NULL; 37 } 38 39 /* Free the block */ 40 RtlFreeHeap(RtlGetProcessHeap(), 0, ActivationBlock); 41 } 42 43 NTSTATUS 44 NTAPI 45 BasepAllocateActivationContextActivationBlock(IN DWORD Flags, 46 IN PVOID CompletionRoutine, 47 IN PVOID CompletionContext, 48 OUT PBASEP_ACTCTX_BLOCK *ActivationBlock) 49 { 50 NTSTATUS Status; 51 ACTIVATION_CONTEXT_BASIC_INFORMATION ContextInfo; 52 53 /* Clear the info structure */ 54 ContextInfo.dwFlags = 0; 55 ContextInfo.hActCtx = NULL; 56 57 /* Assume failure */ 58 if (ActivationBlock) *ActivationBlock = NULL; 59 60 /* Only support valid flags */ 61 if (Flags & ~(1 | 2)) // FIXME: What are they? 2 looks like BASEP_ACTCTX_FORCE_BLOCK 62 { 63 /* Fail if unknown flags are passed in */ 64 Status = STATUS_INVALID_PARAMETER_1; 65 goto Quickie; 66 } 67 68 /* Caller should have passed in an activation block */ 69 if (!ActivationBlock) 70 { 71 /* Fail otherwise */ 72 Status = STATUS_INVALID_PARAMETER_4; 73 goto Quickie; 74 } 75 76 /* Query RTL for information on the current activation context */ 77 Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT, 78 NULL, 79 NULL, 80 ActivationContextBasicInformation, 81 &ContextInfo, 82 sizeof(ContextInfo), 83 NULL); 84 if (!NT_SUCCESS(Status)) 85 { 86 /* Failed -- bail out */ 87 DPRINT1("SXS: %s - Failure getting active activation context; ntstatus %08lx\n", 88 __FUNCTION__, Status); 89 goto Quickie; 90 } 91 92 /* Check if the current one should be freed */ 93 if (ContextInfo.dwFlags & 1) 94 { 95 /* Release and clear it */ 96 RtlReleaseActivationContext(ContextInfo.hActCtx); 97 ContextInfo.hActCtx = NULL; 98 } 99 100 /* Check if there's an active context, or if the caller is forcing one */ 101 if (!(Flags & 2) || (ContextInfo.hActCtx)) 102 { 103 /* Allocate the block */ 104 *ActivationBlock = RtlAllocateHeap(RtlGetProcessHeap(), 105 0, 106 sizeof(BASEP_ACTCTX_BLOCK)); 107 if (!(*ActivationBlock)) 108 { 109 /* Ran out of memory, fail */ 110 Status = STATUS_NO_MEMORY; 111 goto Quickie; 112 } 113 114 /* Fill it out */ 115 (*ActivationBlock)->ActivationContext = ContextInfo.hActCtx; 116 (*ActivationBlock)->Flags = 0; 117 if (Flags & 1) (*ActivationBlock)->Flags |= 1; // Not sure about this flag 118 (*ActivationBlock)->CompletionRoutine = CompletionRoutine; 119 (*ActivationBlock)->CompletionContext = CompletionContext; 120 121 /* Tell Quickie below not to free anything, since this is success */ 122 ContextInfo.hActCtx = NULL; 123 } 124 125 /* Set success status */ 126 Status = STATUS_SUCCESS; 127 128 Quickie: 129 /* Failure or success path, return to caller and free on failure */ 130 if (ContextInfo.hActCtx) RtlReleaseActivationContext(ContextInfo.hActCtx); 131 return Status; 132 } 133 134 NTSTATUS 135 NTAPI 136 BasepProbeForDllManifest(IN PVOID DllHandle, 137 IN PCWSTR FullDllName, 138 OUT PVOID *ActCtx) 139 { 140 NTSTATUS Status = STATUS_SUCCESS; 141 LDR_RESOURCE_INFO Info; 142 IMAGE_RESOURCE_DATA_ENTRY *Entry; 143 ACTCTXW Context; 144 HANDLE Result; 145 146 /* Check if activation context parameter is provided */ 147 if (!ActCtx) 148 { 149 ASSERT(FALSE); 150 return STATUS_INVALID_PARAMETER; 151 } 152 153 /* Zero it out */ 154 *ActCtx = NULL; 155 156 /* Check whether the image has manifest resource associated with it */ 157 Info.Type = (ULONG_PTR)RT_MANIFEST; 158 Info.Name = (ULONG_PTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID; 159 Info.Language = 0; 160 if (!(Status = LdrFindResource_U(DllHandle, &Info, 3, &Entry))) 161 { 162 /* Create the activation context */ 163 Context.cbSize = sizeof(Context); 164 Context.lpSource = FullDllName; 165 Context.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID; 166 Context.hModule = DllHandle; 167 Context.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID; 168 169 Status = RtlCreateActivationContext(0, (PVOID)&Context, 0, NULL, NULL, &Result); 170 171 /* Store activation context pointer if it was created successfully */ 172 if (NT_SUCCESS(Status)) *ActCtx = Result; 173 174 /* CORE-10843: Windows always returns this since we pass the wrong struct */ 175 if (Status == STATUS_SXS_INVALID_ACTCTXDATA_FORMAT) 176 { 177 /* Fake "Manifest not found" so the load doesn't fail */ 178 static int Once; 179 if (Once++) 180 { 181 DPRINT1("HACK: Passed invalid ACTIVATION_CONTEXT_DATA!\n"); 182 } 183 Status = STATUS_RESOURCE_DATA_NOT_FOUND; 184 } 185 } 186 187 return Status; 188 } 189 190 /* PUBLIC FUNCTIONS **********************************************************/ 191 192 /* 193 * @implemented 194 */ 195 VOID 196 WINAPI 197 AddRefActCtx(IN HANDLE hActCtx) 198 { 199 /* Call the native API */ 200 RtlAddRefActivationContext(hActCtx); 201 } 202 203 /* 204 * @implemented 205 */ 206 VOID 207 WINAPI 208 ReleaseActCtx(IN HANDLE hActCtx) 209 { 210 /* Call the native API */ 211 RtlReleaseActivationContext(hActCtx); 212 } 213 214 /* 215 * @implemented 216 */ 217 BOOL 218 WINAPI 219 ZombifyActCtx(HANDLE hActCtx) 220 { 221 NTSTATUS Status; 222 223 /* Call the native API */ 224 Status = RtlZombifyActivationContext(hActCtx); 225 if (NT_SUCCESS(Status)) return TRUE; 226 227 /* Set last error if we failed */ 228 BaseSetLastNTError(Status); 229 return FALSE; 230 } 231 232 /* 233 * @implemented 234 */ 235 BOOL 236 WINAPI 237 ActivateActCtx(IN HANDLE hActCtx, 238 OUT PULONG_PTR ulCookie) 239 { 240 NTSTATUS Status; 241 242 /* Check if the handle was invalid */ 243 if (hActCtx == INVALID_HANDLE_VALUE) 244 { 245 /* Set error and bail out */ 246 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 247 return FALSE; 248 } 249 250 /* Call the native API */ 251 Status = RtlActivateActivationContext(0, hActCtx, ulCookie); 252 if (!NT_SUCCESS(Status)) 253 { 254 /* Set error and bail out */ 255 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 256 return FALSE; 257 } 258 259 /* It worked */ 260 return TRUE; 261 } 262 263 /* 264 * @implemented 265 */ 266 BOOL 267 WINAPI 268 DeactivateActCtx(IN DWORD dwFlags, 269 IN ULONG_PTR ulCookie) 270 { 271 ULONG NativeFlags; 272 273 /* Check if the flags are invalid */ 274 if ((dwFlags & ~DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION) != 0) 275 { 276 /* Set error and bail out */ 277 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 278 return FALSE; 279 } 280 281 /* Convert flags */ 282 NativeFlags = 0; 283 if (dwFlags & DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION) 284 { 285 NativeFlags = RTL_DEACTIVATE_ACTIVATION_CONTEXT_FLAG_FORCE_EARLY_DEACTIVATION; 286 } 287 288 /* Call the native API -- it can never fail */ 289 RtlDeactivateActivationContext(NativeFlags, ulCookie); 290 return TRUE; 291 } 292 293 /* 294 * @implemented 295 */ 296 BOOL 297 WINAPI 298 GetCurrentActCtx(OUT PHANDLE phActCtx) 299 { 300 NTSTATUS Status; 301 302 /* Check if the output handle pointer was invalid */ 303 if (phActCtx == NULL) 304 { 305 /* Set error and bail out */ 306 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 307 return FALSE; 308 } 309 310 /* Call the native API */ 311 Status = RtlGetActiveActivationContext(phActCtx); 312 if (!NT_SUCCESS(Status)) 313 { 314 /* Set error and bail out */ 315 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 316 return FALSE; 317 } 318 319 /* It worked */ 320 return TRUE; 321 } 322 323 /* 324 * @implemented 325 */ 326 BOOL 327 WINAPI 328 QueryActCtxW(IN DWORD dwFlags, 329 IN HANDLE hActCtx, 330 IN PVOID pvSubInstance, 331 IN ULONG ulInfoClass, 332 IN PVOID pvBuffer, 333 IN SIZE_T cbBuffer, 334 IN OUT SIZE_T *pcbWrittenOrRequired OPTIONAL) 335 { 336 ULONG NativeFlags = 0; 337 NTSTATUS Status; 338 339 /* Assume failure */ 340 if (pcbWrittenOrRequired) *pcbWrittenOrRequired = 0; 341 342 /* Check if native flags were passed in to the Win32 function */ 343 switch (dwFlags & 3) 344 { 345 case RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT: 346 dwFlags |= QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX; 347 break; 348 case RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE: 349 dwFlags |= QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE; 350 break; 351 case (RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS - 1): // Yep, not sure why 352 dwFlags |= QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS; 353 break; 354 } 355 356 /* Now mask out the native flags */ 357 dwFlags &= ~3; 358 359 /* Check if any invalid flags are left */ 360 if (dwFlags & ~QUERY_ACTCTX_FLAG_VALID) 361 { 362 /* Yep, bail out */ 363 DPRINT1("SXS: %s() bad flags(passed: 0x%lx, allowed: 0x%lx, bad: 0x%lx)\n", 364 __FUNCTION__, 365 dwFlags, 366 QUERY_ACTCTX_FLAG_VALID, 367 dwFlags & ~QUERY_ACTCTX_FLAG_VALID); 368 BaseSetLastNTError(STATUS_INVALID_PARAMETER_1); 369 return FALSE; 370 } 371 372 /* See if additional parameters are required */ 373 switch (ulInfoClass) 374 { 375 case ActivationContextBasicInformation: 376 case ActivationContextDetailedInformation: 377 case CompatibilityInformationInActivationContext: 378 case RunlevelInformationInActivationContext: 379 380 /* Nothing to check */ 381 break; 382 383 case AssemblyDetailedInformationInActivationContext: 384 case FileInformationInAssemblyOfAssemblyInActivationContext: 385 386 /* We need a subinstance for these queries*/ 387 if (!pvSubInstance) 388 { 389 /* None present, bail out */ 390 DPRINT1("SXS: %s() InfoClass 0x%lx requires SubInstance != NULL\n", 391 __FUNCTION__, 392 ulInfoClass); 393 BaseSetLastNTError(STATUS_INVALID_PARAMETER_3); 394 return FALSE; 395 } 396 break; 397 398 default: 399 400 /* Invalid class, bail out */ 401 DPRINT1("SXS: %s() bad InfoClass(0x%lx)\n", 402 __FUNCTION__, 403 ulInfoClass); 404 BaseSetLastNTError(STATUS_INVALID_PARAMETER_2); 405 return FALSE; 406 } 407 408 /* Check if no buffer was passed in*/ 409 if (!pvBuffer) 410 { 411 /* But a non-zero length was? */ 412 if (cbBuffer) 413 { 414 /* This is bogus... */ 415 DPRINT1("SXS: %s() (pvBuffer == NULL) && ((cbBuffer=0x%lu) != 0)\n", 416 __FUNCTION__, 417 cbBuffer); 418 BaseSetLastNTError(STATUS_INVALID_PARAMETER_4); 419 return FALSE; 420 } 421 422 /* But the caller doesn't want to know how big to make it? */ 423 if (!pcbWrittenOrRequired) 424 { 425 /* That's bogus */ 426 DPRINT1("SXS: %s() (pvBuffer == NULL) && (pcbWrittenOrRequired == NULL)\n", 427 __FUNCTION__); 428 BaseSetLastNTError(STATUS_INVALID_PARAMETER_5); 429 return FALSE; 430 } 431 } 432 433 /* These 3 flags are mutually exclusive -- only one should be present */ 434 switch (dwFlags & (QUERY_ACTCTX_FLAG_VALID & ~QUERY_ACTCTX_FLAG_NO_ADDREF)) 435 { 436 /* Convert into native format */ 437 case QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX: 438 NativeFlags = RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT; 439 break; 440 case QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE: 441 NativeFlags = RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE; 442 break; 443 case QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS: 444 NativeFlags = RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS; 445 break; 446 case 0: 447 break; 448 449 /* More than one flag is set... */ 450 default: 451 /* Bail out */ 452 DPRINT1("SXS: %s(dwFlags=0x%lx) more than one flag in 0x%lx was passed\n", 453 __FUNCTION__, 454 dwFlags, 455 0x1C); 456 BaseSetLastNTError(STATUS_INVALID_PARAMETER_1); 457 return FALSE; 458 } 459 460 /* Convert this last flag */ 461 if (dwFlags & QUERY_ACTCTX_FLAG_NO_ADDREF) 462 { 463 NativeFlags |= RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF; 464 } 465 466 /* Now call the native API */ 467 DPRINT("SXS: %s() Calling Native API with Native Flags %lx for Win32 Flags %lx\n", 468 __FUNCTION__, 469 NativeFlags, 470 dwFlags); 471 Status = RtlQueryInformationActivationContext(NativeFlags, 472 hActCtx, 473 pvSubInstance, 474 ulInfoClass, 475 pvBuffer, 476 cbBuffer, 477 pcbWrittenOrRequired); 478 if (NT_SUCCESS(Status)) return TRUE; 479 480 /* Failed, set error and return */ 481 BaseSetLastNTError(Status); 482 return FALSE; 483 } 484 485 /* EOF */ 486