/* * 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 struct file_info { ULONG type; WCHAR *info; }; struct version { USHORT major; USHORT minor; USHORT build; USHORT revision; }; struct assembly_identity { WCHAR *name; struct version version; }; enum assembly_type { APPLICATION_MANIFEST, ASSEMBLY_MANIFEST }; struct assembly { enum assembly_type type; struct assembly_identity id; struct file_info manifest; }; typedef struct _ACTIVATION_CONTEXT { ULONG magic; int ref_count; struct file_info config; struct file_info appdir; struct assembly *assemblies; unsigned int num_assemblies; unsigned int allocated_assemblies; } ACTIVATION_CONTEXT; static WCHAR *strdupW(const WCHAR* str) { WCHAR* ptr; if (!str) return NULL; if (!(ptr = RtlAllocateHeap(GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR)))) return NULL; return strcpyW(ptr, str); } static struct assembly *add_assembly(ACTIVATION_CONTEXT *actctx, enum assembly_type at) { struct assembly *assembly; if (actctx->num_assemblies == actctx->allocated_assemblies) { void *ptr; unsigned int new_count; if (actctx->assemblies) { new_count = actctx->allocated_assemblies * 2; ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, actctx->assemblies, new_count * sizeof(*assembly) ); } else { new_count = 4; ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*assembly) ); } if (!ptr) return NULL; actctx->assemblies = ptr; actctx->allocated_assemblies = new_count; } assembly = &actctx->assemblies[actctx->num_assemblies++]; assembly->type = at; return assembly; } static void free_assembly_identity(struct assembly_identity *ai) { RtlFreeHeap( GetProcessHeap(), 0, ai->name ); } 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) { unsigned int i; for (i = 0; i < actctx->num_assemblies; i++) { RtlFreeHeap( GetProcessHeap(), 0, actctx->assemblies[i].manifest.info ); free_assembly_identity(&actctx->assemblies[i].id); } RtlFreeHeap( GetProcessHeap(), 0, actctx->config.info ); RtlFreeHeap( GetProcessHeap(), 0, actctx->appdir.info ); RtlFreeHeap( GetProcessHeap(), 0, actctx->assemblies ); 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; struct assembly *assembly; 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(), HEAP_ZERO_MEMORY, sizeof(*actctx) ))) return STATUS_NO_MEMORY; actctx->magic = ACTCTX_MAGIC; actctx->ref_count = 1; if (!(assembly = add_assembly( actctx, APPLICATION_MANIFEST ))) goto error; if (!(assembly->id.name = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) ))) goto error; assembly->id.version.major = 1; assembly->id.version.minor = 0; assembly->id.version.build = 0; assembly->id.version.revision = 0; assembly->manifest.type = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE; assembly->manifest.info = NULL; actctx->config.type = ACTIVATION_CONTEXT_PATH_TYPE_NONE; actctx->config.info = NULL; actctx->appdir.type = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE; if (pActCtx->dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID) actctx->appdir.info = strdupW( pActCtx->lpApplicationName ); *handle = actctx; return STATUS_SUCCESS; error: RtlFreeHeap( GetProcessHeap(), 0, assembly ); RtlFreeHeap( GetProcessHeap(), 0, actctx ); return STATUS_NO_MEMORY; } /*********************************************************************** * 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; }