[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / client / actctx.c
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)RT_MANIFEST;
158 Info.Name = (ULONG)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
378 /* Nothing to check */
379 break;
380
381 case AssemblyDetailedInformationInActivationContext:
382 case FileInformationInAssemblyOfAssemblyInActivationContext:
383
384 /* We need a subinstance for these queries*/
385 if (!pvSubInstance)
386 {
387 /* None present, bail out */
388 DPRINT1("SXS: %s() InfoClass 0x%lx requires SubInstance != NULL\n",
389 __FUNCTION__,
390 ulInfoClass);
391 BaseSetLastNTError(STATUS_INVALID_PARAMETER_3);
392 return FALSE;
393 }
394 break;
395
396 default:
397
398 /* Invalid class, bail out */
399 DPRINT1("SXS: %s() bad InfoClass(0x%lx)\n",
400 __FUNCTION__,
401 ulInfoClass);
402 BaseSetLastNTError(STATUS_INVALID_PARAMETER_2);
403 return FALSE;
404 }
405
406 /* Check if no buffer was passed in*/
407 if (!pvBuffer)
408 {
409 /* But a non-zero length was? */
410 if (cbBuffer)
411 {
412 /* This is bogus... */
413 DPRINT1("SXS: %s() (pvBuffer == NULL) && ((cbBuffer=0x%lu) != 0)\n",
414 __FUNCTION__,
415 cbBuffer);
416 BaseSetLastNTError(STATUS_INVALID_PARAMETER_4);
417 return FALSE;
418 }
419
420 /* But the caller doesn't want to know how big to make it? */
421 if (!pcbWrittenOrRequired)
422 {
423 /* That's bogus */
424 DPRINT1("SXS: %s() (pvBuffer == NULL) && (pcbWrittenOrRequired == NULL)\n",
425 __FUNCTION__);
426 BaseSetLastNTError(STATUS_INVALID_PARAMETER_5);
427 return FALSE;
428 }
429 }
430
431 /* These 3 flags are mutually exclusive -- only one should be present */
432 switch (dwFlags & (QUERY_ACTCTX_FLAG_VALID & ~QUERY_ACTCTX_FLAG_NO_ADDREF))
433 {
434 /* Convert into native format */
435 case QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX:
436 NativeFlags = RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT;
437 break;
438 case QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE:
439 NativeFlags = RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE;
440 break;
441 case QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS:
442 NativeFlags = RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS;
443 break;
444 case 0:
445 break;
446
447 /* More than one flag is set... */
448 default:
449 /* Bail out */
450 DPRINT1("SXS: %s(dwFlags=0x%lx) more than one flag in 0x%lx was passed\n",
451 __FUNCTION__,
452 dwFlags,
453 0x1C);
454 BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
455 return FALSE;
456 }
457
458 /* Convert this last flag */
459 if (dwFlags & QUERY_ACTCTX_FLAG_NO_ADDREF)
460 {
461 NativeFlags |= RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF;
462 }
463
464 /* Now call the native API */
465 DPRINT("SXS: %s() Calling Native API with Native Flags %lx for Win32 Flags %lx\n",
466 __FUNCTION__,
467 NativeFlags,
468 dwFlags);
469 Status = RtlQueryInformationActivationContext(NativeFlags,
470 hActCtx,
471 pvSubInstance,
472 ulInfoClass,
473 pvBuffer,
474 cbBuffer,
475 pcbWrittenOrRequired);
476 if (NT_SUCCESS(Status)) return TRUE;
477
478 /* Failed, set error and return */
479 BaseSetLastNTError(Status);
480 return FALSE;
481 }
482
483 /* EOF */