ntdll: Implemented handling of the per-thread activation context stack.
[wine] / dlls / ntdll / actctx.c
1 /*
2  * Activation contexts
3  *
4  * Copyright 2004 Jon Griffiths
5  * Copyright 2007 Eric Pouech
6  * Copyright 2007 Jacek Caban for CodeWeavers
7  * Copyright 2007 Alexandre Julliard
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "winternl.h"
35 #include "ntdll_misc.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(actctx);
40
41 #define ACTCTX_FLAGS_ALL (\
42  ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID |\
43  ACTCTX_FLAG_LANGID_VALID |\
44  ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID |\
45  ACTCTX_FLAG_RESOURCE_NAME_VALID |\
46  ACTCTX_FLAG_SET_PROCESS_DEFAULT |\
47  ACTCTX_FLAG_APPLICATION_NAME_VALID |\
48  ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF |\
49  ACTCTX_FLAG_HMODULE_VALID )
50
51 #define ACTCTX_MAGIC       0xC07E3E11
52
53 typedef struct _ACTIVATION_CONTEXT
54 {
55     ULONG               magic;
56     int                 ref_count;
57 } ACTIVATION_CONTEXT;
58
59
60 static ACTIVATION_CONTEXT *check_actctx( HANDLE h )
61 {
62     ACTIVATION_CONTEXT *actctx = h;
63
64     if (!h || h == INVALID_HANDLE_VALUE) return NULL;
65     switch (actctx->magic)
66     {
67     case ACTCTX_MAGIC:
68         return actctx;
69     default:
70         return NULL;
71     }
72 }
73
74 static inline void actctx_addref( ACTIVATION_CONTEXT *actctx )
75 {
76     interlocked_xchg_add( &actctx->ref_count, 1 );
77 }
78
79 static void actctx_release( ACTIVATION_CONTEXT *actctx )
80 {
81     if (interlocked_xchg_add( &actctx->ref_count, -1 ) == 1)
82     {
83         actctx->magic = 0;
84         RtlFreeHeap( GetProcessHeap(), 0, actctx );
85     }
86 }
87
88
89 /***********************************************************************
90  * RtlCreateActivationContext (NTDLL.@)
91  *
92  * Create an activation context.
93  *
94  * FIXME: function signature/prototype is wrong
95  */
96 NTSTATUS WINAPI RtlCreateActivationContext( HANDLE *handle, const void *ptr )
97 {
98     const ACTCTXW *pActCtx = ptr;  /* FIXME: not the right structure */
99     ACTIVATION_CONTEXT *actctx;
100
101     TRACE("%p %08x\n", pActCtx, pActCtx ? pActCtx->dwFlags : 0);
102
103     if (!pActCtx || pActCtx->cbSize != sizeof(*pActCtx) ||
104         (pActCtx->dwFlags & ~ACTCTX_FLAGS_ALL))
105         return STATUS_INVALID_PARAMETER;
106
107     if (!(actctx = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*actctx) )))
108         return STATUS_NO_MEMORY;
109
110     actctx->magic = ACTCTX_MAGIC;
111     actctx->ref_count = 1;
112
113     *handle = actctx;
114     return STATUS_SUCCESS;
115 }
116
117
118 /***********************************************************************
119  *              RtlAddRefActivationContext (NTDLL.@)
120  */
121 void WINAPI RtlAddRefActivationContext( HANDLE handle )
122 {
123     ACTIVATION_CONTEXT *actctx;
124
125     if ((actctx = check_actctx( handle ))) actctx_addref( actctx );
126 }
127
128
129 /******************************************************************
130  *              RtlReleaseActivationContext (NTDLL.@)
131  */
132 void WINAPI RtlReleaseActivationContext( HANDLE handle )
133 {
134     ACTIVATION_CONTEXT *actctx;
135
136     if ((actctx = check_actctx( handle ))) actctx_release( actctx );
137 }
138
139
140 /******************************************************************
141  *              RtlActivateActivationContext (NTDLL.@)
142  */
143 NTSTATUS WINAPI RtlActivateActivationContext( ULONG unknown, HANDLE handle, ULONG_PTR *cookie )
144 {
145     RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
146
147     TRACE( "%p %p\n", handle, cookie );
148
149     if (!(frame = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*frame) )))
150         return STATUS_NO_MEMORY;
151
152     frame->Previous = NtCurrentTeb()->ActivationContextStack.ActiveFrame;
153     frame->ActivationContext = handle;
154     frame->Flags = 0;
155     NtCurrentTeb()->ActivationContextStack.ActiveFrame = frame;
156     RtlAddRefActivationContext( handle );
157
158     *cookie = (ULONG_PTR)frame;
159     return STATUS_SUCCESS;
160 }
161
162
163 /***********************************************************************
164  *              RtlDeactivateActivationContext (NTDLL.@)
165  */
166 void WINAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie )
167 {
168     RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame, *top;
169
170     TRACE( "%x %lx\n", flags, cookie );
171
172     /* find the right frame */
173     top = NtCurrentTeb()->ActivationContextStack.ActiveFrame;
174     for (frame = top; frame; frame = frame->Previous)
175         if ((ULONG_PTR)frame == cookie) break;
176
177     if (!frame)
178         RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION );
179
180     if (frame != top && !(flags & DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION))
181         RtlRaiseStatus( STATUS_SXS_EARLY_DEACTIVATION );
182
183     /* pop everything up to and including frame */
184     NtCurrentTeb()->ActivationContextStack.ActiveFrame = frame->Previous;
185
186     while (top != NtCurrentTeb()->ActivationContextStack.ActiveFrame)
187     {
188         frame = top->Previous;
189         RtlReleaseActivationContext( top->ActivationContext );
190         RtlFreeHeap( GetProcessHeap(), 0, top );
191         top = frame;
192     }
193 }
194
195
196 /******************************************************************
197  *              RtlFreeThreadActivationContextStack (NTDLL.@)
198  */
199 void WINAPI RtlFreeThreadActivationContextStack(void)
200 {
201     RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
202
203     frame = NtCurrentTeb()->ActivationContextStack.ActiveFrame;
204     while (frame)
205     {
206         RTL_ACTIVATION_CONTEXT_STACK_FRAME *prev = frame->Previous;
207         RtlReleaseActivationContext( frame->ActivationContext );
208         RtlFreeHeap( GetProcessHeap(), 0, frame );
209         frame = prev;
210     }
211     NtCurrentTeb()->ActivationContextStack.ActiveFrame = NULL;
212 }
213
214
215 /******************************************************************
216  *              RtlGetActiveActivationContext (NTDLL.@)
217  */
218 NTSTATUS WINAPI RtlGetActiveActivationContext( HANDLE *handle )
219 {
220     if (NtCurrentTeb()->ActivationContextStack.ActiveFrame)
221     {
222         *handle = NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext;
223         RtlAddRefActivationContext( *handle );
224     }
225     else
226         *handle = 0;
227
228     return STATUS_SUCCESS;
229 }
230
231
232 /******************************************************************
233  *              RtlIsActivationContextActive (NTDLL.@)
234  */
235 BOOLEAN WINAPI RtlIsActivationContextActive( HANDLE handle )
236 {
237     RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
238
239     for (frame = NtCurrentTeb()->ActivationContextStack.ActiveFrame; frame; frame = frame->Previous)
240         if (frame->ActivationContext == handle) return TRUE;
241     return FALSE;
242 }