/* * Activation contexts * * Copyright 2004 Jon Griffiths * Copyright 2007 Eric Pouech * Copyright 2007 Jacek Caban for CodeWeavers * Copyright 2007 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #include #define NONAMELESSUNION #define NONAMELESSSTRUCT #include "ntstatus.h" #define WIN32_NO_STATUS #include "winternl.h" #include "ntdll_misc.h" #include "wine/debug.h" #include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(actctx); #define ACTCTX_FLAGS_ALL (\ ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID |\ ACTCTX_FLAG_LANGID_VALID |\ ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID |\ ACTCTX_FLAG_RESOURCE_NAME_VALID |\ ACTCTX_FLAG_SET_PROCESS_DEFAULT |\ ACTCTX_FLAG_APPLICATION_NAME_VALID |\ ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF |\ ACTCTX_FLAG_HMODULE_VALID ) #define ACTCTX_MAGIC 0xC07E3E11 typedef struct _ACTIVATION_CONTEXT { ULONG magic; int ref_count; } ACTIVATION_CONTEXT; static ACTIVATION_CONTEXT *check_actctx( HANDLE h ) { ACTIVATION_CONTEXT *actctx = h; if (!h || h == INVALID_HANDLE_VALUE) return NULL; switch (actctx->magic) { case ACTCTX_MAGIC: return actctx; default: return NULL; } } static inline void actctx_addref( ACTIVATION_CONTEXT *actctx ) { interlocked_xchg_add( &actctx->ref_count, 1 ); } static void actctx_release( ACTIVATION_CONTEXT *actctx ) { if (interlocked_xchg_add( &actctx->ref_count, -1 ) == 1) { actctx->magic = 0; RtlFreeHeap( GetProcessHeap(), 0, actctx ); } } /*********************************************************************** * RtlCreateActivationContext (NTDLL.@) * * Create an activation context. * * FIXME: function signature/prototype is wrong */ NTSTATUS WINAPI RtlCreateActivationContext( HANDLE *handle, const void *ptr ) { const ACTCTXW *pActCtx = ptr; /* FIXME: not the right structure */ ACTIVATION_CONTEXT *actctx; TRACE("%p %08x\n", pActCtx, pActCtx ? pActCtx->dwFlags : 0); if (!pActCtx || pActCtx->cbSize != sizeof(*pActCtx) || (pActCtx->dwFlags & ~ACTCTX_FLAGS_ALL)) return STATUS_INVALID_PARAMETER; if (!(actctx = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*actctx) ))) return STATUS_NO_MEMORY; actctx->magic = ACTCTX_MAGIC; actctx->ref_count = 1; *handle = actctx; return STATUS_SUCCESS; } /*********************************************************************** * RtlAddRefActivationContext (NTDLL.@) */ void WINAPI RtlAddRefActivationContext( HANDLE handle ) { ACTIVATION_CONTEXT *actctx; if ((actctx = check_actctx( handle ))) actctx_addref( actctx ); } /****************************************************************** * RtlReleaseActivationContext (NTDLL.@) */ void WINAPI RtlReleaseActivationContext( HANDLE handle ) { ACTIVATION_CONTEXT *actctx; if ((actctx = check_actctx( handle ))) actctx_release( actctx ); } /****************************************************************** * RtlActivateActivationContext (NTDLL.@) */ NTSTATUS WINAPI RtlActivateActivationContext( ULONG unknown, HANDLE handle, ULONG_PTR *cookie ) { RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame; TRACE( "%p %p\n", handle, cookie ); if (!(frame = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*frame) ))) return STATUS_NO_MEMORY; frame->Previous = NtCurrentTeb()->ActivationContextStack.ActiveFrame; frame->ActivationContext = handle; frame->Flags = 0; NtCurrentTeb()->ActivationContextStack.ActiveFrame = frame; RtlAddRefActivationContext( handle ); *cookie = (ULONG_PTR)frame; return STATUS_SUCCESS; } /*********************************************************************** * RtlDeactivateActivationContext (NTDLL.@) */ void WINAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie ) { RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame, *top; TRACE( "%x %lx\n", flags, cookie ); /* find the right frame */ top = NtCurrentTeb()->ActivationContextStack.ActiveFrame; for (frame = top; frame; frame = frame->Previous) if ((ULONG_PTR)frame == cookie) break; if (!frame) RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION ); if (frame != top && !(flags & DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION)) RtlRaiseStatus( STATUS_SXS_EARLY_DEACTIVATION ); /* pop everything up to and including frame */ NtCurrentTeb()->ActivationContextStack.ActiveFrame = frame->Previous; while (top != NtCurrentTeb()->ActivationContextStack.ActiveFrame) { frame = top->Previous; RtlReleaseActivationContext( top->ActivationContext ); RtlFreeHeap( GetProcessHeap(), 0, top ); top = frame; } } /****************************************************************** * RtlFreeThreadActivationContextStack (NTDLL.@) */ void WINAPI RtlFreeThreadActivationContextStack(void) { RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame; frame = NtCurrentTeb()->ActivationContextStack.ActiveFrame; while (frame) { RTL_ACTIVATION_CONTEXT_STACK_FRAME *prev = frame->Previous; RtlReleaseActivationContext( frame->ActivationContext ); RtlFreeHeap( GetProcessHeap(), 0, frame ); frame = prev; } NtCurrentTeb()->ActivationContextStack.ActiveFrame = NULL; } /****************************************************************** * RtlGetActiveActivationContext (NTDLL.@) */ NTSTATUS WINAPI RtlGetActiveActivationContext( HANDLE *handle ) { if (NtCurrentTeb()->ActivationContextStack.ActiveFrame) { *handle = NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext; RtlAddRefActivationContext( *handle ); } else *handle = 0; return STATUS_SUCCESS; } /****************************************************************** * RtlIsActivationContextActive (NTDLL.@) */ BOOLEAN WINAPI RtlIsActivationContextActive( HANDLE handle ) { RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame; for (frame = NtCurrentTeb()->ActivationContextStack.ActiveFrame; frame; frame = frame->Previous) if (frame->ActivationContext == handle) return TRUE; return FALSE; }