xref: /reactos/dll/win32/kernel32/client/actctx.c (revision 1734f297)
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