mirror of
https://github.com/reactos/reactos.git
synced 2024-10-30 11:35:58 +00:00
486 lines
14 KiB
C
486 lines
14 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: dll/win32/kernel32/client/actctx.c
|
|
* PURPOSE: Activation contexts - NT-compatible helpers
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*
|
|
* NOTE: See also kernel32/wine/actctx.c
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <k32.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#define QUERY_ACTCTX_FLAG_VALID (QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX | \
|
|
QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE | \
|
|
QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS | \
|
|
QUERY_ACTCTX_FLAG_NO_ADDREF)
|
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
VOID
|
|
NTAPI
|
|
BasepFreeActivationContextActivationBlock(IN PBASEP_ACTCTX_BLOCK ActivationBlock)
|
|
{
|
|
/* Exit if there was nothing passed in */
|
|
if (!ActivationBlock) return;
|
|
|
|
/* Do we have a context? */
|
|
if (ActivationBlock->ActivationContext)
|
|
{
|
|
/* Release and clear it */
|
|
RtlReleaseActivationContext(ActivationBlock->ActivationContext);
|
|
ActivationBlock->ActivationContext = NULL;
|
|
}
|
|
|
|
/* Free the block */
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, ActivationBlock);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
BasepAllocateActivationContextActivationBlock(IN DWORD Flags,
|
|
IN PVOID CompletionRoutine,
|
|
IN PVOID CompletionContext,
|
|
OUT PBASEP_ACTCTX_BLOCK *ActivationBlock)
|
|
{
|
|
NTSTATUS Status;
|
|
ACTIVATION_CONTEXT_BASIC_INFORMATION ContextInfo;
|
|
|
|
/* Clear the info structure */
|
|
ContextInfo.dwFlags = 0;
|
|
ContextInfo.hActCtx = NULL;
|
|
|
|
/* Assume failure */
|
|
if (ActivationBlock) *ActivationBlock = NULL;
|
|
|
|
/* Only support valid flags */
|
|
if (Flags & ~(1 | 2)) // FIXME: What are they? 2 looks like BASEP_ACTCTX_FORCE_BLOCK
|
|
{
|
|
/* Fail if unknown flags are passed in */
|
|
Status = STATUS_INVALID_PARAMETER_1;
|
|
goto Quickie;
|
|
}
|
|
|
|
/* Caller should have passed in an activation block */
|
|
if (!ActivationBlock)
|
|
{
|
|
/* Fail otherwise */
|
|
Status = STATUS_INVALID_PARAMETER_4;
|
|
goto Quickie;
|
|
}
|
|
|
|
/* Query RTL for information on the current activation context */
|
|
Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT,
|
|
NULL,
|
|
NULL,
|
|
ActivationContextBasicInformation,
|
|
&ContextInfo,
|
|
sizeof(ContextInfo),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Failed -- bail out */
|
|
DPRINT1("SXS: %s - Failure getting active activation context; ntstatus %08lx\n",
|
|
__FUNCTION__, Status);
|
|
goto Quickie;
|
|
}
|
|
|
|
/* Check if the current one should be freed */
|
|
if (ContextInfo.dwFlags & 1)
|
|
{
|
|
/* Release and clear it */
|
|
RtlReleaseActivationContext(ContextInfo.hActCtx);
|
|
ContextInfo.hActCtx = NULL;
|
|
}
|
|
|
|
/* Check if there's an active context, or if the caller is forcing one */
|
|
if (!(Flags & 2) || (ContextInfo.hActCtx))
|
|
{
|
|
/* Allocate the block */
|
|
*ActivationBlock = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
0,
|
|
sizeof(BASEP_ACTCTX_BLOCK));
|
|
if (!(*ActivationBlock))
|
|
{
|
|
/* Ran out of memory, fail */
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Quickie;
|
|
}
|
|
|
|
/* Fill it out */
|
|
(*ActivationBlock)->ActivationContext = ContextInfo.hActCtx;
|
|
(*ActivationBlock)->Flags = 0;
|
|
if (Flags & 1) (*ActivationBlock)->Flags |= 1; // Not sure about this flag
|
|
(*ActivationBlock)->CompletionRoutine = CompletionRoutine;
|
|
(*ActivationBlock)->CompletionContext = CompletionContext;
|
|
|
|
/* Tell Quickie below not to free anything, since this is success */
|
|
ContextInfo.hActCtx = NULL;
|
|
}
|
|
|
|
/* Set success status */
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Quickie:
|
|
/* Failure or success path, return to caller and free on failure */
|
|
if (ContextInfo.hActCtx) RtlReleaseActivationContext(ContextInfo.hActCtx);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
BasepProbeForDllManifest(IN PVOID DllHandle,
|
|
IN PCWSTR FullDllName,
|
|
OUT PVOID *ActCtx)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
LDR_RESOURCE_INFO Info;
|
|
IMAGE_RESOURCE_DATA_ENTRY *Entry;
|
|
ACTCTXW Context;
|
|
HANDLE Result;
|
|
|
|
/* Check if activation context parameter is provided */
|
|
if (!ActCtx)
|
|
{
|
|
ASSERT(FALSE);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Zero it out */
|
|
*ActCtx = NULL;
|
|
|
|
/* Check whether the image has manifest resource associated with it */
|
|
Info.Type = (ULONG_PTR)RT_MANIFEST;
|
|
Info.Name = (ULONG_PTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
|
|
Info.Language = 0;
|
|
if (!(Status = LdrFindResource_U(DllHandle, &Info, 3, &Entry)))
|
|
{
|
|
/* Create the activation context */
|
|
Context.cbSize = sizeof(Context);
|
|
Context.lpSource = FullDllName;
|
|
Context.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
|
|
Context.hModule = DllHandle;
|
|
Context.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
|
|
|
|
Status = RtlCreateActivationContext(0, (PVOID)&Context, 0, NULL, NULL, &Result);
|
|
|
|
/* Store activation context pointer if it was created successfully */
|
|
if (NT_SUCCESS(Status)) *ActCtx = Result;
|
|
|
|
/* CORE-10843: Windows always returns this since we pass the wrong struct */
|
|
if (Status == STATUS_SXS_INVALID_ACTCTXDATA_FORMAT)
|
|
{
|
|
/* Fake "Manifest not found" so the load doesn't fail */
|
|
static int Once;
|
|
if (Once++)
|
|
{
|
|
DPRINT1("HACK: Passed invalid ACTIVATION_CONTEXT_DATA!\n");
|
|
}
|
|
Status = STATUS_RESOURCE_DATA_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
AddRefActCtx(IN HANDLE hActCtx)
|
|
{
|
|
/* Call the native API */
|
|
RtlAddRefActivationContext(hActCtx);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
ReleaseActCtx(IN HANDLE hActCtx)
|
|
{
|
|
/* Call the native API */
|
|
RtlReleaseActivationContext(hActCtx);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
ZombifyActCtx(HANDLE hActCtx)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Call the native API */
|
|
Status = RtlZombifyActivationContext(hActCtx);
|
|
if (NT_SUCCESS(Status)) return TRUE;
|
|
|
|
/* Set last error if we failed */
|
|
BaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
ActivateActCtx(IN HANDLE hActCtx,
|
|
OUT PULONG_PTR ulCookie)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Check if the handle was invalid */
|
|
if (hActCtx == INVALID_HANDLE_VALUE)
|
|
{
|
|
/* Set error and bail out */
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Call the native API */
|
|
Status = RtlActivateActivationContext(0, hActCtx, ulCookie);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Set error and bail out */
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
/* It worked */
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
DeactivateActCtx(IN DWORD dwFlags,
|
|
IN ULONG_PTR ulCookie)
|
|
{
|
|
ULONG NativeFlags;
|
|
|
|
/* Check if the flags are invalid */
|
|
if ((dwFlags & ~DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION) != 0)
|
|
{
|
|
/* Set error and bail out */
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Convert flags */
|
|
NativeFlags = 0;
|
|
if (dwFlags & DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION)
|
|
{
|
|
NativeFlags = RTL_DEACTIVATE_ACTIVATION_CONTEXT_FLAG_FORCE_EARLY_DEACTIVATION;
|
|
}
|
|
|
|
/* Call the native API -- it can never fail */
|
|
RtlDeactivateActivationContext(NativeFlags, ulCookie);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCurrentActCtx(OUT PHANDLE phActCtx)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* Check if the output handle pointer was invalid */
|
|
if (phActCtx == NULL)
|
|
{
|
|
/* Set error and bail out */
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Call the native API */
|
|
Status = RtlGetActiveActivationContext(phActCtx);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Set error and bail out */
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
/* It worked */
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
QueryActCtxW(IN DWORD dwFlags,
|
|
IN HANDLE hActCtx,
|
|
IN PVOID pvSubInstance,
|
|
IN ULONG ulInfoClass,
|
|
IN PVOID pvBuffer,
|
|
IN SIZE_T cbBuffer,
|
|
IN OUT SIZE_T *pcbWrittenOrRequired OPTIONAL)
|
|
{
|
|
ULONG NativeFlags = 0;
|
|
NTSTATUS Status;
|
|
|
|
/* Assume failure */
|
|
if (pcbWrittenOrRequired) *pcbWrittenOrRequired = 0;
|
|
|
|
/* Check if native flags were passed in to the Win32 function */
|
|
switch (dwFlags & 3)
|
|
{
|
|
case RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT:
|
|
dwFlags |= QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX;
|
|
break;
|
|
case RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE:
|
|
dwFlags |= QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE;
|
|
break;
|
|
case (RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS - 1): // Yep, not sure why
|
|
dwFlags |= QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS;
|
|
break;
|
|
}
|
|
|
|
/* Now mask out the native flags */
|
|
dwFlags &= ~3;
|
|
|
|
/* Check if any invalid flags are left */
|
|
if (dwFlags & ~QUERY_ACTCTX_FLAG_VALID)
|
|
{
|
|
/* Yep, bail out */
|
|
DPRINT1("SXS: %s() bad flags(passed: 0x%lx, allowed: 0x%lx, bad: 0x%lx)\n",
|
|
__FUNCTION__,
|
|
dwFlags,
|
|
QUERY_ACTCTX_FLAG_VALID,
|
|
dwFlags & ~QUERY_ACTCTX_FLAG_VALID);
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
|
|
return FALSE;
|
|
}
|
|
|
|
/* See if additional parameters are required */
|
|
switch (ulInfoClass)
|
|
{
|
|
case ActivationContextBasicInformation:
|
|
case ActivationContextDetailedInformation:
|
|
case CompatibilityInformationInActivationContext:
|
|
case RunlevelInformationInActivationContext:
|
|
|
|
/* Nothing to check */
|
|
break;
|
|
|
|
case AssemblyDetailedInformationInActivationContext:
|
|
case FileInformationInAssemblyOfAssemblyInActivationContext:
|
|
|
|
/* We need a subinstance for these queries*/
|
|
if (!pvSubInstance)
|
|
{
|
|
/* None present, bail out */
|
|
DPRINT1("SXS: %s() InfoClass 0x%lx requires SubInstance != NULL\n",
|
|
__FUNCTION__,
|
|
ulInfoClass);
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_3);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Invalid class, bail out */
|
|
DPRINT1("SXS: %s() bad InfoClass(0x%lx)\n",
|
|
__FUNCTION__,
|
|
ulInfoClass);
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_2);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Check if no buffer was passed in*/
|
|
if (!pvBuffer)
|
|
{
|
|
/* But a non-zero length was? */
|
|
if (cbBuffer)
|
|
{
|
|
/* This is bogus... */
|
|
DPRINT1("SXS: %s() (pvBuffer == NULL) && ((cbBuffer=0x%lu) != 0)\n",
|
|
__FUNCTION__,
|
|
cbBuffer);
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_4);
|
|
return FALSE;
|
|
}
|
|
|
|
/* But the caller doesn't want to know how big to make it? */
|
|
if (!pcbWrittenOrRequired)
|
|
{
|
|
/* That's bogus */
|
|
DPRINT1("SXS: %s() (pvBuffer == NULL) && (pcbWrittenOrRequired == NULL)\n",
|
|
__FUNCTION__);
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_5);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* These 3 flags are mutually exclusive -- only one should be present */
|
|
switch (dwFlags & (QUERY_ACTCTX_FLAG_VALID & ~QUERY_ACTCTX_FLAG_NO_ADDREF))
|
|
{
|
|
/* Convert into native format */
|
|
case QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX:
|
|
NativeFlags = RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT;
|
|
break;
|
|
case QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE:
|
|
NativeFlags = RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE;
|
|
break;
|
|
case QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS:
|
|
NativeFlags = RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS;
|
|
break;
|
|
case 0:
|
|
break;
|
|
|
|
/* More than one flag is set... */
|
|
default:
|
|
/* Bail out */
|
|
DPRINT1("SXS: %s(dwFlags=0x%lx) more than one flag in 0x%lx was passed\n",
|
|
__FUNCTION__,
|
|
dwFlags,
|
|
0x1C);
|
|
BaseSetLastNTError(STATUS_INVALID_PARAMETER_1);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Convert this last flag */
|
|
if (dwFlags & QUERY_ACTCTX_FLAG_NO_ADDREF)
|
|
{
|
|
NativeFlags |= RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF;
|
|
}
|
|
|
|
/* Now call the native API */
|
|
DPRINT("SXS: %s() Calling Native API with Native Flags %lx for Win32 Flags %lx\n",
|
|
__FUNCTION__,
|
|
NativeFlags,
|
|
dwFlags);
|
|
Status = RtlQueryInformationActivationContext(NativeFlags,
|
|
hActCtx,
|
|
pvSubInstance,
|
|
ulInfoClass,
|
|
pvBuffer,
|
|
cbBuffer,
|
|
pcbWrittenOrRequired);
|
|
if (NT_SUCCESS(Status)) return TRUE;
|
|
|
|
/* Failed, set error and return */
|
|
BaseSetLastNTError(Status);
|
|
return FALSE;
|
|
}
|
|
|
|
/* EOF */
|