[BRANCHES]
[reactos.git] / reactos / lib / rtl / actctx.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Runtime Library
4 * PURPOSE: Activation Context Support
5 * FILE: lib/rtl/actctx.c
6 * PROGRAMERS:
7 * Jon Griffiths
8 * Eric Pouech
9 * Jacek Caban for CodeWeavers
10 * Alexandre Julliard
11 * Stefan Ginsberg (stefan__100__@hotmail.com)
12 * Samuel SerapiĆ³n
13 */
14
15 /* Based on Wine 1.1.26 */
16
17 #include <rtl.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22 #include <wine/unicode.h>
23
24 BOOLEAN RtlpNotAllowingMultipleActivation;
25
26 #define ACTCTX_FLAGS_ALL (\
27 ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID |\
28 ACTCTX_FLAG_LANGID_VALID |\
29 ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID |\
30 ACTCTX_FLAG_RESOURCE_NAME_VALID |\
31 ACTCTX_FLAG_SET_PROCESS_DEFAULT |\
32 ACTCTX_FLAG_APPLICATION_NAME_VALID |\
33 ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF |\
34 ACTCTX_FLAG_HMODULE_VALID )
35
36 #define ACTCTX_MAGIC_MARKER (PVOID)'gMcA'
37
38 #define ACTCTX_FAKE_HANDLE ((HANDLE) 0xf00baa)
39 #define ACTCTX_FAKE_COOKIE ((ULONG_PTR) 0xf00bad)
40
41
42
43 typedef struct
44 {
45 const WCHAR *ptr;
46 unsigned int len;
47 } xmlstr_t;
48
49 typedef struct
50 {
51 const WCHAR *ptr;
52 const WCHAR *end;
53 } xmlbuf_t;
54
55 struct file_info
56 {
57 ULONG type;
58 WCHAR *info;
59 };
60
61 struct assembly_version
62 {
63 USHORT major;
64 USHORT minor;
65 USHORT build;
66 USHORT revision;
67 };
68
69 struct assembly_identity
70 {
71 WCHAR *name;
72 WCHAR *arch;
73 WCHAR *public_key;
74 WCHAR *language;
75 WCHAR *type;
76 struct assembly_version version;
77 BOOL optional;
78 };
79
80 struct entity
81 {
82 DWORD kind;
83 union
84 {
85 struct
86 {
87 WCHAR *tlbid;
88 WCHAR *version;
89 WCHAR *helpdir;
90 } typelib;
91 struct
92 {
93 WCHAR *clsid;
94 } comclass;
95 struct {
96 WCHAR *iid;
97 WCHAR *name;
98 } proxy;
99 struct
100 {
101 WCHAR *name;
102 } class;
103 struct
104 {
105 WCHAR *name;
106 WCHAR *clsid;
107 } clrclass;
108 struct
109 {
110 WCHAR *name;
111 WCHAR *clsid;
112 } clrsurrogate;
113 } u;
114 };
115
116 struct entity_array
117 {
118 struct entity *base;
119 unsigned int num;
120 unsigned int allocated;
121 };
122
123 struct dll_redirect
124 {
125 WCHAR *name;
126 WCHAR *hash;
127 struct entity_array entities;
128 };
129
130 enum assembly_type
131 {
132 APPLICATION_MANIFEST,
133 ASSEMBLY_MANIFEST,
134 ASSEMBLY_SHARED_MANIFEST,
135 };
136
137 struct assembly
138 {
139 enum assembly_type type;
140 struct assembly_identity id;
141 struct file_info manifest;
142 WCHAR *directory;
143 BOOL no_inherit;
144 struct dll_redirect *dlls;
145 unsigned int num_dlls;
146 unsigned int allocated_dlls;
147 struct entity_array entities;
148 };
149
150 typedef struct _ASSEMBLY_STORAGE_MAP_ENTRY
151 {
152 ULONG Flags;
153 UNICODE_STRING DosPath;
154 HANDLE Handle;
155 } ASSEMBLY_STORAGE_MAP_ENTRY, *PASSEMBLY_STORAGE_MAP_ENTRY;
156
157 typedef struct _ASSEMBLY_STORAGE_MAP
158 {
159 ULONG Flags;
160 ULONG AssemblyCount;
161 PASSEMBLY_STORAGE_MAP_ENTRY *AssemblyArray;
162 } ASSEMBLY_STORAGE_MAP, *PASSEMBLY_STORAGE_MAP;
163
164 typedef struct _ACTIVATION_CONTEXT
165 {
166 LONG RefCount;
167 ULONG Flags;
168 LIST_ENTRY Links;
169 PACTIVATION_CONTEXT_DATA ActivationContextData;
170 PVOID NotificationRoutine;
171 PVOID NotificationContext;
172 ULONG SentNotifications[8];
173 ULONG DisabledNotifications[8];
174 ASSEMBLY_STORAGE_MAP StorageMap;
175 PASSEMBLY_STORAGE_MAP_ENTRY InlineStorageMapEntries;
176 ULONG StackTraceIndex;
177 PVOID StackTraces[4][4];
178 struct file_info config;
179 struct file_info appdir;
180 struct assembly *assemblies;
181 unsigned int num_assemblies;
182 unsigned int allocated_assemblies;
183 } ACTIVATION_CONTEXT, *PIACTIVATION_CONTEXT;
184
185 struct actctx_loader
186 {
187 ACTIVATION_CONTEXT *actctx;
188 struct assembly_identity *dependencies;
189 unsigned int num_dependencies;
190 unsigned int allocated_dependencies;
191 };
192
193 static const WCHAR asmv1W[] = {'a','s','m','v','1',':',0};
194 static const WCHAR asmv2W[] = {'a','s','m','v','2',':',0};
195
196 typedef struct _ACTIVATION_CONTEXT_WRAPPED
197 {
198 PVOID MagicMarker;
199 ACTIVATION_CONTEXT ActivationContext;
200 } ACTIVATION_CONTEXT_WRAPPED, *PACTIVATION_CONTEXT_WRAPPED;
201
202 VOID
203 NTAPI
204 RtlpSxsBreakOnInvalidMarker(IN PACTIVATION_CONTEXT ActCtx,
205 IN ULONG FailureCode)
206 {
207 EXCEPTION_RECORD ExceptionRecord;
208
209 /* Fatal SxS exception header */
210 ExceptionRecord.ExceptionRecord = NULL;
211 ExceptionRecord.ExceptionCode = STATUS_SXS_CORRUPTION;
212 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
213
214 /* With SxS-specific information plus the context itself */
215 ExceptionRecord.ExceptionInformation[0] = 1;
216 ExceptionRecord.ExceptionInformation[1] = FailureCode;
217 ExceptionRecord.ExceptionInformation[2] = (ULONG_PTR)ActCtx;
218 ExceptionRecord.NumberParameters = 3;
219
220 /* Raise it */
221 RtlRaiseException(&ExceptionRecord);
222 }
223
224 FORCEINLINE
225 VOID
226 RtlpValidateActCtx(IN PACTIVATION_CONTEXT ActCtx)
227 {
228 PACTIVATION_CONTEXT_WRAPPED pActual;
229
230 /* Get the caller-opaque header */
231 pActual = CONTAINING_RECORD(ActCtx,
232 ACTIVATION_CONTEXT_WRAPPED,
233 ActivationContext);
234
235 /* Check if the header matches as expected */
236 if (pActual->MagicMarker != ACTCTX_MAGIC_MARKER)
237 {
238 /* Nope, print out a warning, assert, and then throw an exception */
239 DbgPrint("%s : Invalid activation context marker %p found in activation context %p\n"
240 " This means someone stepped on the allocation, or someone is using a\n"
241 " deallocated activation context\n",
242 __FUNCTION__,
243 pActual->MagicMarker,
244 ActCtx);
245 ASSERT(pActual->MagicMarker == ACTCTX_MAGIC_MARKER);
246 RtlpSxsBreakOnInvalidMarker(ActCtx, 1);
247 }
248 }
249
250 static const WCHAR assemblyW[] = {'a','s','s','e','m','b','l','y',0};
251 static const WCHAR assemblyIdentityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
252 static const WCHAR bindingRedirectW[] = {'b','i','n','d','i','n','g','R','e','d','i','r','e','c','t',0};
253 static const WCHAR clrClassW[] = {'c','l','r','C','l','a','s','s',0};
254 static const WCHAR clrSurrogateW[] = {'c','l','r','S','u','r','r','o','g','a','t','e',0};
255 static const WCHAR comClassW[] = {'c','o','m','C','l','a','s','s',0};
256 static const WCHAR comInterfaceExternalProxyStubW[] = {'c','o','m','I','n','t','e','r','f','a','c','e','E','x','t','e','r','n','a','l','P','r','o','x','y','S','t','u','b',0};
257 static const WCHAR comInterfaceProxyStubW[] = {'c','o','m','I','n','t','e','r','f','a','c','e','P','r','o','x','y','S','t','u','b',0};
258 static const WCHAR dependencyW[] = {'d','e','p','e','n','d','e','n','c','y',0};
259 static const WCHAR dependentAssemblyW[] = {'d','e','p','e','n','d','e','n','t','A','s','s','e','m','b','l','y',0};
260 static const WCHAR descriptionW[] = {'d','e','s','c','r','i','p','t','i','o','n',0};
261 static const WCHAR fileW[] = {'f','i','l','e',0};
262 static const WCHAR asmv2hashW[] = {'a','s','m','v','2',':','h','a','s','h',0};
263 static const WCHAR noInheritW[] = {'n','o','I','n','h','e','r','i','t',0};
264 static const WCHAR noInheritableW[] = {'n','o','I','n','h','e','r','i','t','a','b','l','e',0};
265 static const WCHAR typelibW[] = {'t','y','p','e','l','i','b',0};
266 static const WCHAR windowClassW[] = {'w','i','n','d','o','w','C','l','a','s','s',0};
267
268 static const WCHAR clsidW[] = {'c','l','s','i','d',0};
269 static const WCHAR hashW[] = {'h','a','s','h',0};
270 static const WCHAR hashalgW[] = {'h','a','s','h','a','l','g',0};
271 static const WCHAR helpdirW[] = {'h','e','l','p','d','i','r',0};
272 static const WCHAR iidW[] = {'i','i','d',0};
273 static const WCHAR languageW[] = {'l','a','n','g','u','a','g','e',0};
274 static const WCHAR manifestVersionW[] = {'m','a','n','i','f','e','s','t','V','e','r','s','i','o','n',0};
275 static const WCHAR g_nameW[] = {'n','a','m','e',0};
276 static const WCHAR neutralW[] = {'n','e','u','t','r','a','l',0};
277 static const WCHAR newVersionW[] = {'n','e','w','V','e','r','s','i','o','n',0};
278 static const WCHAR oldVersionW[] = {'o','l','d','V','e','r','s','i','o','n',0};
279 static const WCHAR optionalW[] = {'o','p','t','i','o','n','a','l',0};
280 static const WCHAR processorArchitectureW[] = {'p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e',0};
281 static const WCHAR publicKeyTokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
282 static const WCHAR tlbidW[] = {'t','l','b','i','d',0};
283 static const WCHAR typeW[] = {'t','y','p','e',0};
284 static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
285 static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
286
287 static const WCHAR g_xmlW[] = {'?','x','m','l',0};
288 static const WCHAR manifestv1W[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','a','s','m','.','v','1',0};
289 static const WCHAR manifestv3W[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','a','s','m','.','v','3',0};
290
291 static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
292 static const WCHAR version_formatW[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
293 static const WCHAR wildcardW[] = {'*',0};
294
295 static ACTIVATION_CONTEXT_WRAPPED system_actctx = { ACTCTX_MAGIC_MARKER, { 1 } };
296 static ACTIVATION_CONTEXT *process_actctx = &system_actctx.ActivationContext;
297
298 static WCHAR *strdupW(const WCHAR* str)
299 {
300 WCHAR* ptr;
301
302 if (!(ptr = RtlAllocateHeap(RtlGetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR))))
303 return NULL;
304 return strcpyW(ptr, str);
305 }
306
307 static WCHAR *xmlstrdupW(const xmlstr_t* str)
308 {
309 WCHAR *strW;
310
311 if ((strW = RtlAllocateHeap(RtlGetProcessHeap(), 0, (str->len + 1) * sizeof(WCHAR))))
312 {
313 memcpy( strW, str->ptr, str->len * sizeof(WCHAR) );
314 strW[str->len] = 0;
315 }
316 return strW;
317 }
318
319 static inline BOOL xmlstr_cmp(const xmlstr_t* xmlstr, const WCHAR *str)
320 {
321 return !strncmpW(xmlstr->ptr, str, xmlstr->len) && !str[xmlstr->len];
322 }
323
324 static inline BOOL xmlstr_cmpi(const xmlstr_t* xmlstr, const WCHAR *str)
325 {
326 return !strncmpiW(xmlstr->ptr, str, xmlstr->len) && !str[xmlstr->len];
327 }
328
329 static inline BOOL xmlstr_cmp_end(const xmlstr_t* xmlstr, const WCHAR *str)
330 {
331 return (xmlstr->len && xmlstr->ptr[0] == '/' &&
332 !strncmpW(xmlstr->ptr + 1, str, xmlstr->len - 1) && !str[xmlstr->len - 1]);
333 }
334
335 static inline BOOL xml_elem_cmp(const xmlstr_t *elem, const WCHAR *str, const WCHAR *namespace)
336 {
337 UINT len = strlenW( namespace );
338
339 if (!strncmpW(elem->ptr, str, elem->len) && !str[elem->len]) return TRUE;
340 return (elem->len > len && !strncmpW(elem->ptr, namespace, len) &&
341 !strncmpW(elem->ptr + len, str, elem->len - len) && !str[elem->len - len]);
342 }
343
344 static inline BOOL xml_elem_cmp_end(const xmlstr_t *elem, const WCHAR *str, const WCHAR *namespace)
345 {
346 if (elem->len && elem->ptr[0] == '/')
347 {
348 xmlstr_t elem_end;
349 elem_end.ptr = elem->ptr + 1;
350 elem_end.len = elem->len - 1;
351 return xml_elem_cmp( &elem_end, str, namespace );
352 }
353 return FALSE;
354 }
355
356 static inline BOOL isxmlspace( WCHAR ch )
357 {
358 return (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t');
359 }
360
361 static UNICODE_STRING xmlstr2unicode(const xmlstr_t *xmlstr)
362 {
363 UNICODE_STRING res;
364
365 res.Buffer = (PWSTR)xmlstr->ptr;
366 res.Length = res.MaximumLength = (USHORT)xmlstr->len * sizeof(WCHAR);
367
368 return res;
369 }
370
371 static struct assembly *add_assembly(ACTIVATION_CONTEXT *actctx, enum assembly_type at)
372 {
373 struct assembly *assembly;
374
375 if (actctx->num_assemblies == actctx->allocated_assemblies)
376 {
377 void *ptr;
378 unsigned int new_count;
379 if (actctx->assemblies)
380 {
381 new_count = actctx->allocated_assemblies * 2;
382 ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
383 actctx->assemblies, new_count * sizeof(*assembly) );
384 }
385 else
386 {
387 new_count = 4;
388 ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*assembly) );
389 }
390 if (!ptr) return NULL;
391 actctx->assemblies = ptr;
392 actctx->allocated_assemblies = new_count;
393 }
394
395 assembly = &actctx->assemblies[actctx->num_assemblies++];
396 assembly->type = at;
397 return assembly;
398 }
399
400 static struct dll_redirect* add_dll_redirect(struct assembly* assembly)
401 {
402 if (assembly->num_dlls == assembly->allocated_dlls)
403 {
404 void *ptr;
405 unsigned int new_count;
406 if (assembly->dlls)
407 {
408 new_count = assembly->allocated_dlls * 2;
409 ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
410 assembly->dlls, new_count * sizeof(*assembly->dlls) );
411 }
412 else
413 {
414 new_count = 4;
415 ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*assembly->dlls) );
416 }
417 if (!ptr) return NULL;
418 assembly->dlls = ptr;
419 assembly->allocated_dlls = new_count;
420 }
421 return &assembly->dlls[assembly->num_dlls++];
422 }
423
424 static void free_assembly_identity(struct assembly_identity *ai)
425 {
426 RtlFreeHeap( RtlGetProcessHeap(), 0, ai->name );
427 RtlFreeHeap( RtlGetProcessHeap(), 0, ai->arch );
428 RtlFreeHeap( RtlGetProcessHeap(), 0, ai->public_key );
429 RtlFreeHeap( RtlGetProcessHeap(), 0, ai->language );
430 RtlFreeHeap( RtlGetProcessHeap(), 0, ai->type );
431 }
432
433 static struct entity* add_entity(struct entity_array *array, DWORD kind)
434 {
435 struct entity* entity;
436
437 if (array->num == array->allocated)
438 {
439 void *ptr;
440 unsigned int new_count;
441 if (array->base)
442 {
443 new_count = array->allocated * 2;
444 ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
445 array->base, new_count * sizeof(*array->base) );
446 }
447 else
448 {
449 new_count = 4;
450 ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*array->base) );
451 }
452 if (!ptr) return NULL;
453 array->base = ptr;
454 array->allocated = new_count;
455 }
456 entity = &array->base[array->num++];
457 entity->kind = kind;
458 return entity;
459 }
460
461 static void free_entity_array(struct entity_array *array)
462 {
463 unsigned int i;
464 for (i = 0; i < array->num; i++)
465 {
466 struct entity *entity = &array->base[i];
467 switch (entity->kind)
468 {
469 case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
470 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.clsid);
471 break;
472 case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
473 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.proxy.iid);
474 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.proxy.name);
475 break;
476 case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION:
477 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.typelib.tlbid);
478 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.typelib.version);
479 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.typelib.helpdir);
480 break;
481 case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION:
482 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.class.name);
483 break;
484 case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION:
485 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrclass.name);
486 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrclass.clsid);
487 break;
488 case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES:
489 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrsurrogate.name);
490 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrsurrogate.clsid);
491 break;
492 default:
493 DPRINT1("Unknown entity kind %u\n", entity->kind);
494 }
495 }
496 RtlFreeHeap( RtlGetProcessHeap(), 0, array->base );
497 }
498
499 static BOOL is_matching_string( const WCHAR *str1, const WCHAR *str2 )
500 {
501 if (!str1) return !str2;
502 return str2 && !strcmpiW( str1, str2 );
503 }
504
505 static BOOL is_matching_identity( const struct assembly_identity *id1,
506 const struct assembly_identity *id2 )
507 {
508 if (!is_matching_string( id1->name, id2->name )) return FALSE;
509 if (!is_matching_string( id1->arch, id2->arch )) return FALSE;
510 if (!is_matching_string( id1->public_key, id2->public_key )) return FALSE;
511
512 if (id1->language && id2->language && strcmpiW( id1->language, id2->language ))
513 {
514 if (strcmpW( wildcardW, id1->language ) && strcmpW( wildcardW, id2->language ))
515 return FALSE;
516 }
517 if (id1->version.major != id2->version.major) return FALSE;
518 if (id1->version.minor != id2->version.minor) return FALSE;
519 if (id1->version.build > id2->version.build) return FALSE;
520 if (id1->version.build == id2->version.build &&
521 id1->version.revision > id2->version.revision) return FALSE;
522 return TRUE;
523 }
524
525 static BOOL add_dependent_assembly_id(struct actctx_loader* acl,
526 struct assembly_identity* ai)
527 {
528 unsigned int i;
529
530 /* check if we already have that assembly */
531
532 for (i = 0; i < acl->actctx->num_assemblies; i++)
533 if (is_matching_identity( ai, &acl->actctx->assemblies[i].id ))
534 {
535 DPRINT( "reusing existing assembly for %S arch %S version %u.%u.%u.%u\n",
536 ai->name, ai->arch, ai->version.major, ai->version.minor,
537 ai->version.build, ai->version.revision );
538 return TRUE;
539 }
540
541 for (i = 0; i < acl->num_dependencies; i++)
542 if (is_matching_identity( ai, &acl->dependencies[i] ))
543 {
544 DPRINT( "reusing existing dependency for %S arch %S version %u.%u.%u.%u\n",
545 ai->name, ai->arch, ai->version.major, ai->version.minor,
546 ai->version.build, ai->version.revision );
547 return TRUE;
548 }
549
550 if (acl->num_dependencies == acl->allocated_dependencies)
551 {
552 void *ptr;
553 unsigned int new_count;
554 if (acl->dependencies)
555 {
556 new_count = acl->allocated_dependencies * 2;
557 ptr = RtlReAllocateHeap(RtlGetProcessHeap(), 0, acl->dependencies,
558 new_count * sizeof(acl->dependencies[0]));
559 }
560 else
561 {
562 new_count = 4;
563 ptr = RtlAllocateHeap(RtlGetProcessHeap(), 0, new_count * sizeof(acl->dependencies[0]));
564 }
565 if (!ptr) return FALSE;
566 acl->dependencies = ptr;
567 acl->allocated_dependencies = new_count;
568 }
569 acl->dependencies[acl->num_dependencies++] = *ai;
570
571 return TRUE;
572 }
573
574 static void free_depend_manifests(struct actctx_loader* acl)
575 {
576 unsigned int i;
577 for (i = 0; i < acl->num_dependencies; i++)
578 free_assembly_identity(&acl->dependencies[i]);
579 RtlFreeHeap(RtlGetProcessHeap(), 0, acl->dependencies);
580 }
581
582 static WCHAR *build_assembly_dir(struct assembly_identity* ai)
583 {
584 static const WCHAR undW[] = {'_',0};
585 static const WCHAR noneW[] = {'n','o','n','e',0};
586 static const WCHAR mskeyW[] = {'d','e','a','d','b','e','e','f',0};
587
588 const WCHAR *arch = ai->arch ? ai->arch : noneW;
589 const WCHAR *key = ai->public_key ? ai->public_key : noneW;
590 const WCHAR *lang = ai->language ? ai->language : noneW;
591 const WCHAR *name = ai->name ? ai->name : noneW;
592 SIZE_T size = (strlenW(arch) + 1 + strlenW(name) + 1 + strlenW(key) + 24 + 1 +
593 strlenW(lang) + 1) * sizeof(WCHAR) + sizeof(mskeyW);
594 WCHAR *ret;
595
596 if (!(ret = RtlAllocateHeap( RtlGetProcessHeap(), 0, size ))) return NULL;
597
598 strcpyW( ret, arch );
599 strcatW( ret, undW );
600 strcatW( ret, name );
601 strcatW( ret, undW );
602 strcatW( ret, key );
603 strcatW( ret, undW );
604 sprintfW( ret + strlenW(ret), version_formatW,
605 ai->version.major, ai->version.minor, ai->version.build, ai->version.revision );
606 strcatW( ret, undW );
607 strcatW( ret, lang );
608 strcatW( ret, undW );
609 strcatW( ret, mskeyW );
610 return ret;
611 }
612
613 static inline void append_string( WCHAR *buffer, const WCHAR *prefix, const WCHAR *str )
614 {
615 WCHAR *p = buffer;
616
617 if (!str) return;
618 strcatW( buffer, prefix );
619 p += strlenW(p);
620 *p++ = '"';
621 strcpyW( p, str );
622 p += strlenW(p);
623 *p++ = '"';
624 *p = 0;
625 }
626
627 static WCHAR *build_assembly_id( const struct assembly_identity *ai )
628 {
629 static const WCHAR archW[] =
630 {',','p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e','=',0};
631 static const WCHAR public_keyW[] =
632 {',','p','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
633 static const WCHAR typeW2[] =
634 {',','t','y','p','e','=',0};
635 static const WCHAR versionW2[] =
636 {',','v','e','r','s','i','o','n','=',0};
637
638 WCHAR version[64], *ret;
639 SIZE_T size = 0;
640
641 sprintfW( version, version_formatW,
642 ai->version.major, ai->version.minor, ai->version.build, ai->version.revision );
643 if (ai->name) size += strlenW(ai->name) * sizeof(WCHAR);
644 if (ai->arch) size += strlenW(archW) + strlenW(ai->arch) + 2;
645 if (ai->public_key) size += strlenW(public_keyW) + strlenW(ai->public_key) + 2;
646 if (ai->type) size += strlenW(typeW2) + strlenW(ai->type) + 2;
647 size += strlenW(versionW2) + strlenW(version) + 2;
648
649 if (!(ret = RtlAllocateHeap( RtlGetProcessHeap(), 0, (size + 1) * sizeof(WCHAR) )))
650 return NULL;
651
652 if (ai->name) strcpyW( ret, ai->name );
653 else *ret = 0;
654 append_string( ret, archW, ai->arch );
655 append_string( ret, public_keyW, ai->public_key );
656 append_string( ret, typeW2, ai->type );
657 append_string( ret, versionW2, version );
658 return ret;
659 }
660 static ACTIVATION_CONTEXT *check_actctx( HANDLE h )
661 {
662 ACTIVATION_CONTEXT *ret = NULL, *actctx = h;
663 PACTIVATION_CONTEXT_WRAPPED pActual;
664
665 if (!h || h == INVALID_HANDLE_VALUE) return NULL;
666 _SEH2_TRY
667 {
668 if (actctx)
669 {
670 pActual = CONTAINING_RECORD(actctx, ACTIVATION_CONTEXT_WRAPPED, ActivationContext);
671 if (pActual->MagicMarker == ACTCTX_MAGIC_MARKER) ret = &pActual->ActivationContext;
672 }
673 }
674 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
675 {
676 DPRINT1("Invalid activation context handle!\n");
677 }
678 _SEH2_END;
679 return ret;
680 }
681
682 static inline void actctx_addref( ACTIVATION_CONTEXT *actctx )
683 {
684 InterlockedExchangeAdd( &actctx->RefCount, 1 );
685 }
686
687 static void actctx_release( ACTIVATION_CONTEXT *actctx )
688 {
689 PACTIVATION_CONTEXT_WRAPPED pActual;
690
691 if (InterlockedExchangeAdd(&actctx->RefCount, -1) == 1)
692 {
693 unsigned int i, j;
694
695 for (i = 0; i < actctx->num_assemblies; i++)
696 {
697 struct assembly *assembly = &actctx->assemblies[i];
698 for (j = 0; j < assembly->num_dlls; j++)
699 {
700 struct dll_redirect *dll = &assembly->dlls[j];
701 free_entity_array( &dll->entities );
702 RtlFreeHeap( RtlGetProcessHeap(), 0, dll->name );
703 RtlFreeHeap( RtlGetProcessHeap(), 0, dll->hash );
704 }
705 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->dlls );
706 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->manifest.info );
707 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->directory );
708 free_entity_array( &assembly->entities );
709 free_assembly_identity(&assembly->id);
710 }
711 RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->config.info );
712 RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->appdir.info );
713 RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->assemblies );
714 pActual = CONTAINING_RECORD(actctx, ACTIVATION_CONTEXT_WRAPPED, ActivationContext);
715 pActual->MagicMarker = 0;
716 RtlFreeHeap(RtlGetProcessHeap(), 0, pActual);
717 }
718 }
719
720 static BOOL next_xml_attr(xmlbuf_t* xmlbuf, xmlstr_t* name, xmlstr_t* value,
721 BOOL* error, BOOL* end)
722 {
723 const WCHAR* ptr;
724
725 *error = TRUE;
726
727 while (xmlbuf->ptr < xmlbuf->end && isxmlspace(*xmlbuf->ptr))
728 xmlbuf->ptr++;
729
730 if (xmlbuf->ptr == xmlbuf->end) return FALSE;
731
732 if (*xmlbuf->ptr == '/')
733 {
734 xmlbuf->ptr++;
735 if (xmlbuf->ptr == xmlbuf->end || *xmlbuf->ptr != '>')
736 return FALSE;
737
738 xmlbuf->ptr++;
739 *end = TRUE;
740 *error = FALSE;
741 return FALSE;
742 }
743
744 if (*xmlbuf->ptr == '>')
745 {
746 xmlbuf->ptr++;
747 *error = FALSE;
748 return FALSE;
749 }
750
751 ptr = xmlbuf->ptr;
752 while (ptr < xmlbuf->end && *ptr != '=' && *ptr != '>' && !isxmlspace(*ptr)) ptr++;
753
754 if (ptr == xmlbuf->end) return FALSE;
755
756 name->ptr = xmlbuf->ptr;
757 name->len = ptr-xmlbuf->ptr;
758 xmlbuf->ptr = ptr;
759
760 /* skip spaces before '=' */
761 while (ptr < xmlbuf->end && *ptr != '=' && isxmlspace(*ptr)) ptr++;
762 if (ptr == xmlbuf->end || *ptr != '=') return FALSE;
763
764 /* skip '=' itself */
765 ptr++;
766 if (ptr == xmlbuf->end) return FALSE;
767
768 /* skip spaces after '=' */
769 while (ptr < xmlbuf->end && *ptr != '"' && *ptr != '\'' && isxmlspace(*ptr)) ptr++;
770
771 if (ptr == xmlbuf->end || (*ptr != '"' && *ptr != '\'')) return FALSE;
772
773 value->ptr = ++ptr;
774 if (ptr == xmlbuf->end) return FALSE;
775
776 ptr = memchrW(ptr, ptr[-1], xmlbuf->end - ptr);
777 if (!ptr)
778 {
779 xmlbuf->ptr = xmlbuf->end;
780 return FALSE;
781 }
782
783 value->len = ptr - value->ptr;
784 xmlbuf->ptr = ptr + 1;
785
786 if (xmlbuf->ptr == xmlbuf->end) return FALSE;
787
788 *error = FALSE;
789 return TRUE;
790 }
791
792 static BOOL next_xml_elem(xmlbuf_t* xmlbuf, xmlstr_t* elem)
793 {
794 const WCHAR* ptr;
795
796 for (;;)
797 {
798 ptr = memchrW(xmlbuf->ptr, '<', xmlbuf->end - xmlbuf->ptr);
799 if (!ptr)
800 {
801 xmlbuf->ptr = xmlbuf->end;
802 return FALSE;
803 }
804 ptr++;
805 if (ptr + 3 < xmlbuf->end && ptr[0] == '!' && ptr[1] == '-' && ptr[2] == '-') /* skip comment */
806 {
807 for (ptr += 3; ptr + 3 <= xmlbuf->end; ptr++)
808 if (ptr[0] == '-' && ptr[1] == '-' && ptr[2] == '>') break;
809
810 if (ptr + 3 > xmlbuf->end)
811 {
812 xmlbuf->ptr = xmlbuf->end;
813 return FALSE;
814 }
815 xmlbuf->ptr = ptr + 3;
816 }
817 else break;
818 }
819
820 xmlbuf->ptr = ptr;
821 while (ptr < xmlbuf->end && !isxmlspace(*ptr) && *ptr != '>' && (*ptr != '/' || ptr == xmlbuf->ptr))
822 ptr++;
823
824 elem->ptr = xmlbuf->ptr;
825 elem->len = ptr - xmlbuf->ptr;
826 xmlbuf->ptr = ptr;
827 return xmlbuf->ptr != xmlbuf->end;
828 }
829
830 static BOOL parse_xml_header(xmlbuf_t* xmlbuf)
831 {
832 /* FIXME: parse attributes */
833 const WCHAR *ptr;
834
835 for (ptr = xmlbuf->ptr; ptr < xmlbuf->end - 1; ptr++)
836 {
837 if (ptr[0] == '?' && ptr[1] == '>')
838 {
839 xmlbuf->ptr = ptr + 2;
840 return TRUE;
841 }
842 }
843 return FALSE;
844 }
845
846 static BOOL parse_text_content(xmlbuf_t* xmlbuf, xmlstr_t* content)
847 {
848 const WCHAR *ptr = memchrW(xmlbuf->ptr, '<', xmlbuf->end - xmlbuf->ptr);
849
850 if (!ptr) return FALSE;
851
852 content->ptr = xmlbuf->ptr;
853 content->len = ptr - xmlbuf->ptr;
854 xmlbuf->ptr = ptr;
855
856 return TRUE;
857 }
858
859 static BOOL parse_version(const xmlstr_t *str, struct assembly_version *version)
860 {
861 unsigned int ver[4];
862 unsigned int pos;
863 const WCHAR *curr;
864 UNICODE_STRING strU;
865
866 /* major.minor.build.revision */
867 ver[0] = ver[1] = ver[2] = ver[3] = pos = 0;
868 for (curr = str->ptr; curr < str->ptr + str->len; curr++)
869 {
870 if (*curr >= '0' && *curr <= '9')
871 {
872 ver[pos] = ver[pos] * 10 + *curr - '0';
873 if (ver[pos] >= 0x10000) goto error;
874 }
875 else if (*curr == '.')
876 {
877 if (++pos >= 4) goto error;
878 }
879 else goto error;
880 }
881 version->major = ver[0];
882 version->minor = ver[1];
883 version->build = ver[2];
884 version->revision = ver[3];
885 return TRUE;
886
887 error:
888 strU = xmlstr2unicode(str);
889 DPRINT1( "Wrong version definition in manifest file (%wZ)\n", &strU );
890 return FALSE;
891 }
892
893 static BOOL parse_expect_elem(xmlbuf_t* xmlbuf, const WCHAR* name, const WCHAR *namespace)
894 {
895 xmlstr_t elem;
896 UNICODE_STRING elemU;
897 if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
898 if (xml_elem_cmp(&elem, name, namespace)) return TRUE;
899 elemU = xmlstr2unicode(&elem);
900 DPRINT1( "unexpected element %wZ\n", &elemU );
901 return FALSE;
902 }
903
904 static BOOL parse_expect_no_attr(xmlbuf_t* xmlbuf, BOOL* end)
905 {
906 xmlstr_t attr_name, attr_value;
907 UNICODE_STRING attr_nameU, attr_valueU;
908 BOOL error;
909
910 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, end))
911 {
912 attr_nameU = xmlstr2unicode(&attr_name);
913 attr_valueU = xmlstr2unicode(&attr_value);
914 DPRINT1( "unexpected attr %wZ=%wZ\n", &attr_nameU,
915 &attr_valueU);
916 }
917 return !error;
918 }
919
920 static BOOL parse_end_element(xmlbuf_t *xmlbuf)
921 {
922 BOOL end = FALSE;
923 return parse_expect_no_attr(xmlbuf, &end) && !end;
924 }
925
926 static BOOL parse_expect_end_elem(xmlbuf_t *xmlbuf, const WCHAR *name, const WCHAR *namespace)
927 {
928 xmlstr_t elem;
929 UNICODE_STRING elemU;
930 if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
931 if (!xml_elem_cmp_end(&elem, name, namespace))
932 {
933 elemU = xmlstr2unicode(&elem);
934 DPRINT1( "unexpected element %wZ\n", &elemU );
935 return FALSE;
936 }
937 return parse_end_element(xmlbuf);
938 }
939
940 static BOOL parse_unknown_elem(xmlbuf_t *xmlbuf, const xmlstr_t *unknown_elem)
941 {
942 xmlstr_t attr_name, attr_value, elem;
943 BOOL end = FALSE, error, ret = TRUE;
944
945 while(next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end));
946 if(error || end) return end;
947
948 while(ret && (ret = next_xml_elem(xmlbuf, &elem)))
949 {
950 if(*elem.ptr == '/' && elem.len - 1 == unknown_elem->len &&
951 !strncmpW(elem.ptr+1, unknown_elem->ptr, unknown_elem->len))
952 break;
953 else
954 ret = parse_unknown_elem(xmlbuf, &elem);
955 }
956
957 return ret && parse_end_element(xmlbuf);
958 }
959
960 static BOOL parse_assembly_identity_elem(xmlbuf_t* xmlbuf, ACTIVATION_CONTEXT* actctx,
961 struct assembly_identity* ai)
962 {
963 xmlstr_t attr_name, attr_value;
964 BOOL end = FALSE, error;
965 UNICODE_STRING attr_valueU, attr_nameU;
966
967 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
968 {
969 if (xmlstr_cmp(&attr_name, g_nameW))
970 {
971 if (!(ai->name = xmlstrdupW(&attr_value))) return FALSE;
972 }
973 else if (xmlstr_cmp(&attr_name, typeW))
974 {
975 if (!(ai->type = xmlstrdupW(&attr_value))) return FALSE;
976 }
977 else if (xmlstr_cmp(&attr_name, versionW))
978 {
979 if (!parse_version(&attr_value, &ai->version)) return FALSE;
980 }
981 else if (xmlstr_cmp(&attr_name, processorArchitectureW))
982 {
983 if (!(ai->arch = xmlstrdupW(&attr_value))) return FALSE;
984 }
985 else if (xmlstr_cmp(&attr_name, publicKeyTokenW))
986 {
987 if (!(ai->public_key = xmlstrdupW(&attr_value))) return FALSE;
988 }
989 else if (xmlstr_cmp(&attr_name, languageW))
990 {
991 DPRINT1("Unsupported yet language attribute (%S)\n",
992 ai->language);
993 if (!(ai->language = xmlstrdupW(&attr_value))) return FALSE;
994 }
995 else
996 {
997 attr_nameU = xmlstr2unicode(&attr_name);
998 attr_valueU = xmlstr2unicode(&attr_value);
999 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1000 }
1001 }
1002
1003 if (error || end) return end;
1004 return parse_expect_end_elem(xmlbuf, assemblyIdentityW, asmv1W);
1005 }
1006
1007 static BOOL parse_com_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll)
1008 {
1009 xmlstr_t elem, attr_name, attr_value;
1010 BOOL ret = TRUE, end = FALSE, error;
1011 struct entity* entity;
1012 UNICODE_STRING attr_valueU, attr_nameU;
1013
1014 if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)))
1015 return FALSE;
1016
1017 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1018 {
1019 if (xmlstr_cmp(&attr_name, clsidW))
1020 {
1021 if (!(entity->u.comclass.clsid = xmlstrdupW(&attr_value))) return FALSE;
1022 }
1023 else
1024 {
1025 attr_nameU = xmlstr2unicode(&attr_name);
1026 attr_valueU = xmlstr2unicode(&attr_value);
1027 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1028 }
1029 }
1030
1031 if (error || end) return end;
1032
1033 while ((ret = next_xml_elem(xmlbuf, &elem)))
1034 {
1035 if (xmlstr_cmp_end(&elem, comClassW))
1036 {
1037 ret = parse_end_element(xmlbuf);
1038 break;
1039 }
1040 else
1041 {
1042 attr_nameU = xmlstr2unicode(&elem);
1043 DPRINT1("unknown elem %wZ\n", &attr_nameU);
1044 ret = parse_unknown_elem(xmlbuf, &elem);
1045 }
1046 }
1047 return ret;
1048 }
1049
1050 static BOOL parse_cominterface_proxy_stub_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll)
1051 {
1052 xmlstr_t attr_name, attr_value;
1053 BOOL end = FALSE, error;
1054 struct entity* entity;
1055 UNICODE_STRING attr_valueU, attr_nameU;
1056
1057 if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)))
1058 return FALSE;
1059
1060 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1061 {
1062 if (xmlstr_cmp(&attr_name, iidW))
1063 {
1064 if (!(entity->u.proxy.iid = xmlstrdupW(&attr_value))) return FALSE;
1065 }
1066 if (xmlstr_cmp(&attr_name, g_nameW))
1067 {
1068 if (!(entity->u.proxy.name = xmlstrdupW(&attr_value))) return FALSE;
1069 }
1070 else
1071 {
1072 attr_nameU = xmlstr2unicode(&attr_name);
1073 attr_valueU = xmlstr2unicode(&attr_value);
1074 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1075 }
1076 }
1077
1078 if (error || end) return end;
1079 return parse_expect_end_elem(xmlbuf, comInterfaceProxyStubW, asmv1W);
1080 }
1081
1082 static BOOL parse_typelib_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll)
1083 {
1084 xmlstr_t attr_name, attr_value;
1085 BOOL end = FALSE, error;
1086 struct entity* entity;
1087 UNICODE_STRING attr_valueU, attr_nameU;
1088
1089 if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)))
1090 return FALSE;
1091
1092 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1093 {
1094 if (xmlstr_cmp(&attr_name, tlbidW))
1095 {
1096 if (!(entity->u.typelib.tlbid = xmlstrdupW(&attr_value))) return FALSE;
1097 }
1098 if (xmlstr_cmp(&attr_name, versionW))
1099 {
1100 if (!(entity->u.typelib.version = xmlstrdupW(&attr_value))) return FALSE;
1101 }
1102 if (xmlstr_cmp(&attr_name, helpdirW))
1103 {
1104 if (!(entity->u.typelib.helpdir = xmlstrdupW(&attr_value))) return FALSE;
1105 }
1106 else
1107 {
1108 attr_nameU = xmlstr2unicode(&attr_name);
1109 attr_valueU = xmlstr2unicode(&attr_value);
1110 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1111 }
1112 }
1113
1114 if (error || end) return end;
1115 return parse_expect_end_elem(xmlbuf, typelibW, asmv1W);
1116 }
1117
1118 static BOOL parse_window_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll)
1119 {
1120 xmlstr_t elem, content;
1121 BOOL end = FALSE, ret = TRUE;
1122 struct entity* entity;
1123 UNICODE_STRING elemU;
1124
1125 if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)))
1126 return FALSE;
1127
1128 if (!parse_expect_no_attr(xmlbuf, &end)) return FALSE;
1129 if (end) return FALSE;
1130
1131 if (!parse_text_content(xmlbuf, &content)) return FALSE;
1132
1133 if (!(entity->u.class.name = xmlstrdupW(&content))) return FALSE;
1134
1135 while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
1136 {
1137 if (xmlstr_cmp_end(&elem, windowClassW))
1138 {
1139 ret = parse_end_element(xmlbuf);
1140 break;
1141 }
1142 else
1143 {
1144 elemU = xmlstr2unicode(&elem);
1145 DPRINT1("unknown elem %wZ\n", &elemU);
1146 ret = parse_unknown_elem(xmlbuf, &elem);
1147 }
1148 }
1149
1150 return ret;
1151 }
1152
1153 static BOOL parse_binding_redirect_elem(xmlbuf_t* xmlbuf)
1154 {
1155 xmlstr_t attr_name, attr_value;
1156 UNICODE_STRING attr_valueU, attr_nameU;
1157 BOOL end = FALSE, error;
1158
1159 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1160 {
1161 attr_nameU = xmlstr2unicode(&attr_name);
1162 attr_valueU = xmlstr2unicode(&attr_value);
1163
1164 if (xmlstr_cmp(&attr_name, oldVersionW))
1165 {
1166 DPRINT1("Not stored yet oldVersion=%wZ\n", &attr_valueU);
1167 }
1168 else if (xmlstr_cmp(&attr_name, newVersionW))
1169 {
1170 DPRINT1("Not stored yet newVersion=%wZ\n", &attr_valueU);
1171 }
1172 else
1173 {
1174 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1175 }
1176 }
1177
1178 if (error || end) return end;
1179 return parse_expect_end_elem(xmlbuf, bindingRedirectW, asmv1W);
1180 }
1181
1182 static BOOL parse_description_elem(xmlbuf_t* xmlbuf)
1183 {
1184 xmlstr_t elem, content;
1185 UNICODE_STRING elemU;
1186 BOOL end = FALSE, ret = TRUE;
1187
1188 if (!parse_expect_no_attr(xmlbuf, &end) || end ||
1189 !parse_text_content(xmlbuf, &content))
1190 return FALSE;
1191
1192 elemU = xmlstr2unicode(&content);
1193 DPRINT("Got description %wZ\n", &elemU);
1194
1195 while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
1196 {
1197 if (xmlstr_cmp_end(&elem, descriptionW))
1198 {
1199 ret = parse_end_element(xmlbuf);
1200 break;
1201 }
1202 else
1203 {
1204 elemU = xmlstr2unicode(&elem);
1205 DPRINT1("unknown elem %wZ\n", &elemU);
1206 ret = parse_unknown_elem(xmlbuf, &elem);
1207 }
1208 }
1209
1210 return ret;
1211 }
1212
1213 static BOOL parse_com_interface_external_proxy_stub_elem(xmlbuf_t* xmlbuf,
1214 struct assembly* assembly)
1215 {
1216 xmlstr_t attr_name, attr_value;
1217 UNICODE_STRING attr_nameU, attr_valueU;
1218 BOOL end = FALSE, error;
1219 struct entity* entity;
1220
1221 entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION);
1222 if (!entity) return FALSE;
1223
1224 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1225 {
1226 if (xmlstr_cmp(&attr_name, iidW))
1227 {
1228 if (!(entity->u.proxy.iid = xmlstrdupW(&attr_value))) return FALSE;
1229 }
1230 if (xmlstr_cmp(&attr_name, g_nameW))
1231 {
1232 if (!(entity->u.proxy.name = xmlstrdupW(&attr_value))) return FALSE;
1233 }
1234 else
1235 {
1236 attr_nameU = xmlstr2unicode(&attr_name);
1237 attr_valueU = xmlstr2unicode(&attr_value);
1238 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1239 }
1240 }
1241
1242 if (error || end) return end;
1243 return parse_expect_end_elem(xmlbuf, comInterfaceExternalProxyStubW, asmv1W);
1244 }
1245
1246 static BOOL parse_clr_class_elem(xmlbuf_t* xmlbuf, struct assembly* assembly)
1247 {
1248 xmlstr_t attr_name, attr_value;
1249 UNICODE_STRING attr_nameU, attr_valueU;
1250 BOOL end = FALSE, error;
1251 struct entity* entity;
1252
1253 entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION);
1254 if (!entity) return FALSE;
1255
1256 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1257 {
1258 if (xmlstr_cmp(&attr_name, g_nameW))
1259 {
1260 if (!(entity->u.clrclass.name = xmlstrdupW(&attr_value))) return FALSE;
1261 }
1262 else if (xmlstr_cmp(&attr_name, clsidW))
1263 {
1264 if (!(entity->u.clrclass.clsid = xmlstrdupW(&attr_value))) return FALSE;
1265 }
1266 else
1267 {
1268 attr_nameU = xmlstr2unicode(&attr_name);
1269 attr_valueU = xmlstr2unicode(&attr_value);
1270 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1271 }
1272 }
1273
1274 if (error || end) return end;
1275 return parse_expect_end_elem(xmlbuf, clrClassW, asmv1W);
1276 }
1277
1278 static BOOL parse_clr_surrogate_elem(xmlbuf_t* xmlbuf, struct assembly* assembly)
1279 {
1280 xmlstr_t attr_name, attr_value;
1281 UNICODE_STRING attr_nameU, attr_valueU;
1282 BOOL end = FALSE, error;
1283 struct entity* entity;
1284
1285 entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES);
1286 if (!entity) return FALSE;
1287
1288 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1289 {
1290 if (xmlstr_cmp(&attr_name, g_nameW))
1291 {
1292 if (!(entity->u.clrsurrogate.name = xmlstrdupW(&attr_value))) return FALSE;
1293 }
1294 else if (xmlstr_cmp(&attr_name, clsidW))
1295 {
1296 if (!(entity->u.clrsurrogate.clsid = xmlstrdupW(&attr_value))) return FALSE;
1297 }
1298 else
1299 {
1300 attr_nameU = xmlstr2unicode(&attr_name);
1301 attr_valueU = xmlstr2unicode(&attr_value);
1302 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1303 }
1304 }
1305
1306 if (error || end) return end;
1307 return parse_expect_end_elem(xmlbuf, clrSurrogateW, asmv1W);
1308 }
1309
1310 static BOOL parse_dependent_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl, BOOL optional)
1311 {
1312 struct assembly_identity ai;
1313 xmlstr_t elem;
1314 BOOL end = FALSE, ret = TRUE;
1315
1316 if (!parse_expect_no_attr(xmlbuf, &end) || end) return end;
1317
1318 memset(&ai, 0, sizeof(ai));
1319 ai.optional = optional;
1320
1321 if (!parse_expect_elem(xmlbuf, assemblyIdentityW, asmv1W) ||
1322 !parse_assembly_identity_elem(xmlbuf, acl->actctx, &ai))
1323 return FALSE;
1324
1325 /* store the newly found identity for later loading */
1326 if (!add_dependent_assembly_id(acl, &ai)) return FALSE;
1327
1328 while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
1329 {
1330 if (xmlstr_cmp_end(&elem, dependentAssemblyW))
1331 {
1332 ret = parse_end_element(xmlbuf);
1333 break;
1334 }
1335 else if (xmlstr_cmp(&elem, bindingRedirectW))
1336 {
1337 ret = parse_binding_redirect_elem(xmlbuf);
1338 }
1339 else
1340 {
1341 DPRINT1("unknown elem %S\n", elem.ptr);
1342 ret = parse_unknown_elem(xmlbuf, &elem);
1343 }
1344 }
1345
1346 return ret;
1347 }
1348
1349 static BOOL parse_dependency_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl)
1350 {
1351 xmlstr_t attr_name, attr_value, elem;
1352 UNICODE_STRING attr_nameU, attr_valueU;
1353 BOOL end = FALSE, ret = TRUE, error, optional = FALSE;
1354
1355 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1356 {
1357 attr_nameU = xmlstr2unicode(&attr_name);
1358 attr_valueU = xmlstr2unicode(&attr_value);
1359
1360 if (xmlstr_cmp(&attr_name, optionalW))
1361 {
1362 static const WCHAR yesW[] = {'y','e','s',0};
1363 optional = xmlstr_cmpi( &attr_value, yesW );
1364 DPRINT1("optional=%wZ\n", &attr_valueU);
1365 }
1366 else
1367 {
1368 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1369 }
1370 }
1371
1372 while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
1373 {
1374 if (xmlstr_cmp_end(&elem, dependencyW))
1375 {
1376 ret = parse_end_element(xmlbuf);
1377 break;
1378 }
1379 else if (xmlstr_cmp(&elem, dependentAssemblyW))
1380 {
1381 ret = parse_dependent_assembly_elem(xmlbuf, acl, optional);
1382 }
1383 else
1384 {
1385 attr_nameU = xmlstr2unicode(&elem);
1386 DPRINT1("unknown element %wZ\n", &attr_nameU);
1387 ret = parse_unknown_elem(xmlbuf, &elem);
1388 }
1389 }
1390
1391 return ret;
1392 }
1393
1394 static BOOL parse_noinherit_elem(xmlbuf_t* xmlbuf)
1395 {
1396 BOOL end = FALSE;
1397
1398 if (!parse_expect_no_attr(xmlbuf, &end)) return FALSE;
1399 return end || parse_expect_end_elem(xmlbuf, noInheritW, asmv1W);
1400 }
1401
1402 static BOOL parse_noinheritable_elem(xmlbuf_t* xmlbuf)
1403 {
1404 BOOL end = FALSE;
1405
1406 if (!parse_expect_no_attr(xmlbuf, &end)) return FALSE;
1407 return end || parse_expect_end_elem(xmlbuf, noInheritableW, asmv1W);
1408 }
1409
1410 static BOOL parse_file_elem(xmlbuf_t* xmlbuf, struct assembly* assembly)
1411 {
1412 xmlstr_t attr_name, attr_value, elem;
1413 UNICODE_STRING attr_nameU, attr_valueU;
1414 BOOL end = FALSE, error, ret = TRUE;
1415 struct dll_redirect* dll;
1416
1417 if (!(dll = add_dll_redirect(assembly))) return FALSE;
1418
1419 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1420 {
1421 attr_nameU = xmlstr2unicode(&attr_name);
1422 attr_valueU = xmlstr2unicode(&attr_value);
1423
1424 if (xmlstr_cmp(&attr_name, g_nameW))
1425 {
1426 if (!(dll->name = xmlstrdupW(&attr_value))) return FALSE;
1427 DPRINT("name=%wZ\n", &attr_valueU);
1428 }
1429 else if (xmlstr_cmp(&attr_name, hashW))
1430 {
1431 if (!(dll->hash = xmlstrdupW(&attr_value))) return FALSE;
1432 }
1433 else if (xmlstr_cmp(&attr_name, hashalgW))
1434 {
1435 static const WCHAR sha1W[] = {'S','H','A','1',0};
1436 if (!xmlstr_cmpi(&attr_value, sha1W))
1437 DPRINT1("hashalg should be SHA1, got %wZ\n", &attr_valueU);
1438 }
1439 else
1440 {
1441 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1442 }
1443 }
1444
1445 if (error || !dll->name) return FALSE;
1446 if (end) return TRUE;
1447
1448 while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
1449 {
1450 if (xmlstr_cmp_end(&elem, fileW))
1451 {
1452 ret = parse_end_element(xmlbuf);
1453 break;
1454 }
1455 else if (xmlstr_cmp(&elem, comClassW))
1456 {
1457 ret = parse_com_class_elem(xmlbuf, dll);
1458 }
1459 else if (xmlstr_cmp(&elem, comInterfaceProxyStubW))
1460 {
1461 ret = parse_cominterface_proxy_stub_elem(xmlbuf, dll);
1462 }
1463 else if (xmlstr_cmp(&elem, asmv2hashW))
1464 {
1465 DPRINT1("asmv2hash (undocumented) not supported\n");
1466 ret = parse_unknown_elem(xmlbuf, &elem);
1467 }
1468 else if (xmlstr_cmp(&elem, typelibW))
1469 {
1470 ret = parse_typelib_elem(xmlbuf, dll);
1471 }
1472 else if (xmlstr_cmp(&elem, windowClassW))
1473 {
1474 ret = parse_window_class_elem(xmlbuf, dll);
1475 }
1476 else
1477 {
1478 attr_nameU = xmlstr2unicode(&elem);
1479 DPRINT1("unknown elem %wZ\n", &attr_nameU);
1480 ret = parse_unknown_elem( xmlbuf, &elem );
1481 }
1482 }
1483
1484 return ret;
1485 }
1486
1487 static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl,
1488 struct assembly* assembly,
1489 struct assembly_identity* expected_ai)
1490 {
1491 xmlstr_t attr_name, attr_value, elem;
1492 UNICODE_STRING attr_nameU, attr_valueU;
1493 BOOL end = FALSE, error, version = FALSE, xmlns = FALSE, ret = TRUE;
1494
1495 while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1496 {
1497 attr_nameU = xmlstr2unicode(&attr_name);
1498 attr_valueU = xmlstr2unicode(&attr_value);
1499
1500 if (xmlstr_cmp(&attr_name, manifestVersionW))
1501 {
1502 static const WCHAR v10W[] = {'1','.','0',0};
1503 if (!xmlstr_cmp(&attr_value, v10W))
1504 {
1505 DPRINT1("wrong version %wZ\n", &attr_valueU);
1506 return FALSE;
1507 }
1508 version = TRUE;
1509 }
1510 else if (xmlstr_cmp(&attr_name, xmlnsW))
1511 {
1512 if (!xmlstr_cmp(&attr_value, manifestv1W) && !xmlstr_cmp(&attr_value, manifestv3W))
1513 {
1514 DPRINT1("wrong namespace %wZ\n", &attr_valueU);
1515 return FALSE;
1516 }
1517 xmlns = TRUE;
1518 }
1519 else
1520 {
1521 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1522 }
1523 }
1524
1525 if (error || end || !xmlns || !version) return FALSE;
1526 if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
1527
1528 if (assembly->type == APPLICATION_MANIFEST && xmlstr_cmp(&elem, noInheritW))
1529 {
1530 if (!parse_noinherit_elem(xmlbuf) || !next_xml_elem(xmlbuf, &elem))
1531 return FALSE;
1532 assembly->no_inherit = TRUE;
1533 }
1534
1535 if (xmlstr_cmp(&elem, noInheritableW))
1536 {
1537 if (!parse_noinheritable_elem(xmlbuf) || !next_xml_elem(xmlbuf, &elem))
1538 return FALSE;
1539 }
1540 else if ((assembly->type == ASSEMBLY_MANIFEST || assembly->type == ASSEMBLY_SHARED_MANIFEST) &&
1541 assembly->no_inherit)
1542 return FALSE;
1543
1544 while (ret)
1545 {
1546 if (xmlstr_cmp_end(&elem, assemblyW))
1547 {
1548 ret = parse_end_element(xmlbuf);
1549 break;
1550 }
1551 else if (xmlstr_cmp(&elem, descriptionW))
1552 {
1553 ret = parse_description_elem(xmlbuf);
1554 }
1555 else if (xmlstr_cmp(&elem, comInterfaceExternalProxyStubW))
1556 {
1557 ret = parse_com_interface_external_proxy_stub_elem(xmlbuf, assembly);
1558 }
1559 else if (xmlstr_cmp(&elem, dependencyW))
1560 {
1561 ret = parse_dependency_elem(xmlbuf, acl);
1562 }
1563 else if (xmlstr_cmp(&elem, fileW))
1564 {
1565 ret = parse_file_elem(xmlbuf, assembly);
1566 }
1567 else if (xmlstr_cmp(&elem, clrClassW))
1568 {
1569 ret = parse_clr_class_elem(xmlbuf, assembly);
1570 }
1571 else if (xmlstr_cmp(&elem, clrSurrogateW))
1572 {
1573 ret = parse_clr_surrogate_elem(xmlbuf, assembly);
1574 }
1575 else if (xmlstr_cmp(&elem, assemblyIdentityW))
1576 {
1577 if (!parse_assembly_identity_elem(xmlbuf, acl->actctx, &assembly->id)) return FALSE;
1578
1579 if (expected_ai)
1580 {
1581 /* FIXME: more tests */
1582 if (assembly->type == ASSEMBLY_MANIFEST &&
1583 memcmp(&assembly->id.version, &expected_ai->version, sizeof(assembly->id.version)))
1584 {
1585 DPRINT1("wrong version for assembly manifest: %u.%u.%u.%u / %u.%u.%u.%u\n",
1586 expected_ai->version.major, expected_ai->version.minor,
1587 expected_ai->version.build, expected_ai->version.revision,
1588 assembly->id.version.major, assembly->id.version.minor,
1589 assembly->id.version.build, assembly->id.version.revision);
1590 ret = FALSE;
1591 }
1592 else if (assembly->type == ASSEMBLY_SHARED_MANIFEST &&
1593 (assembly->id.version.major != expected_ai->version.major ||
1594 assembly->id.version.minor != expected_ai->version.minor ||
1595 assembly->id.version.build < expected_ai->version.build ||
1596 (assembly->id.version.build == expected_ai->version.build &&
1597 assembly->id.version.revision < expected_ai->version.revision)))
1598 {
1599 DPRINT1("wrong version for shared assembly manifest\n");
1600 ret = FALSE;
1601 }
1602 }
1603 }
1604 else
1605 {
1606 attr_nameU = xmlstr2unicode(&elem);
1607 DPRINT1("unknown element %wZ\n", &attr_nameU);
1608 ret = parse_unknown_elem(xmlbuf, &elem);
1609 }
1610 if (ret) ret = next_xml_elem(xmlbuf, &elem);
1611 }
1612
1613 return ret;
1614 }
1615
1616 static NTSTATUS parse_manifest_buffer( struct actctx_loader* acl, struct assembly *assembly,
1617 struct assembly_identity* ai, xmlbuf_t *xmlbuf )
1618 {
1619 xmlstr_t elem;
1620 UNICODE_STRING elemU;
1621
1622 if (!next_xml_elem(xmlbuf, &elem)) return STATUS_SXS_CANT_GEN_ACTCTX;
1623
1624 if (xmlstr_cmp(&elem, g_xmlW) &&
1625 (!parse_xml_header(xmlbuf) || !next_xml_elem(xmlbuf, &elem)))
1626 return STATUS_SXS_CANT_GEN_ACTCTX;
1627
1628 if (!xmlstr_cmp(&elem, assemblyW))
1629 {
1630 elemU = xmlstr2unicode(&elem);
1631 DPRINT1("root element is %wZ, not <assembly>\n", &elemU);
1632 return STATUS_SXS_CANT_GEN_ACTCTX;
1633 }
1634
1635 if (!parse_assembly_elem(xmlbuf, acl, assembly, ai))
1636 {
1637 DPRINT1("failed to parse manifest %S\n", assembly->manifest.info );
1638 return STATUS_SXS_CANT_GEN_ACTCTX;
1639 }
1640
1641 if (next_xml_elem(xmlbuf, &elem))
1642 {
1643 elemU = xmlstr2unicode(&elem);
1644 DPRINT1("unexpected element %wZ\n", &elemU);
1645 return STATUS_SXS_CANT_GEN_ACTCTX;
1646 }
1647
1648 if (xmlbuf->ptr != xmlbuf->end)
1649 {
1650 DPRINT1("parse error\n");
1651 return STATUS_SXS_CANT_GEN_ACTCTX;
1652 }
1653 return STATUS_SUCCESS;
1654 }
1655
1656 static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
1657 LPCWSTR filename, LPCWSTR directory, BOOL shared,
1658 const void *buffer, SIZE_T size )
1659 {
1660 xmlbuf_t xmlbuf;
1661 NTSTATUS status;
1662 struct assembly *assembly;
1663 int unicode_tests;
1664
1665 DPRINT( "parsing manifest loaded from %S base dir %S\n", filename, directory );
1666
1667 if (!(assembly = add_assembly(acl->actctx, shared ? ASSEMBLY_SHARED_MANIFEST : ASSEMBLY_MANIFEST)))
1668 return STATUS_SXS_CANT_GEN_ACTCTX;
1669
1670 if (directory && !(assembly->directory = strdupW(directory)))
1671 return STATUS_NO_MEMORY;
1672
1673 if (filename) assembly->manifest.info = strdupW( filename + 4 /* skip \??\ prefix */ );
1674 assembly->manifest.type = assembly->manifest.info ? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
1675 : ACTIVATION_CONTEXT_PATH_TYPE_NONE;
1676
1677 unicode_tests = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1678 if (RtlIsTextUnicode((PVOID)buffer, (ULONG)size, &unicode_tests ))
1679 {
1680 xmlbuf.ptr = buffer;
1681 xmlbuf.end = xmlbuf.ptr + size / sizeof(WCHAR);
1682 status = parse_manifest_buffer( acl, assembly, ai, &xmlbuf );
1683 }
1684 else if (unicode_tests & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
1685 {
1686 const WCHAR *buf = buffer;
1687 WCHAR *new_buff;
1688 unsigned int i;
1689
1690 if (!(new_buff = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
1691 return STATUS_NO_MEMORY;
1692 for (i = 0; i < size / sizeof(WCHAR); i++)
1693 new_buff[i] = RtlUshortByteSwap( buf[i] );
1694 xmlbuf.ptr = new_buff;
1695 xmlbuf.end = xmlbuf.ptr + size / sizeof(WCHAR);
1696 status = parse_manifest_buffer( acl, assembly, ai, &xmlbuf );
1697 RtlFreeHeap( RtlGetProcessHeap(), 0, new_buff );
1698 }
1699 else
1700 {
1701 /* TODO: this doesn't handle arbitrary encodings */
1702 WCHAR *new_buff;
1703 ULONG sizeU;
1704
1705 status = RtlMultiByteToUnicodeSize(&sizeU, buffer, size);
1706 if (!NT_SUCCESS(status))
1707 {
1708 DPRINT1("RtlMultiByteToUnicodeSize failed with %lx\n", status);
1709 return STATUS_SXS_CANT_GEN_ACTCTX;
1710 }
1711
1712 new_buff = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeU);
1713 if (!new_buff)
1714 return STATUS_NO_MEMORY;
1715
1716 status = RtlMultiByteToUnicodeN(new_buff, sizeU, &sizeU, buffer, size);
1717 if (!NT_SUCCESS(status))
1718 {
1719 DPRINT1("RtlMultiByteToUnicodeN failed with %lx\n", status);
1720 return STATUS_SXS_CANT_GEN_ACTCTX;
1721 }
1722
1723 xmlbuf.ptr = new_buff;
1724 xmlbuf.end = xmlbuf.ptr + sizeU / sizeof(WCHAR);
1725 status = parse_manifest_buffer(acl, assembly, ai, &xmlbuf);
1726 RtlFreeHeap(RtlGetProcessHeap(), 0, new_buff);
1727 }
1728 return status;
1729 }
1730
1731 static NTSTATUS open_nt_file( HANDLE *handle, UNICODE_STRING *name )
1732 {
1733 OBJECT_ATTRIBUTES attr;
1734 IO_STATUS_BLOCK io;
1735
1736 attr.Length = sizeof(attr);
1737 attr.RootDirectory = 0;
1738 attr.Attributes = OBJ_CASE_INSENSITIVE;
1739 attr.ObjectName = name;
1740 attr.SecurityDescriptor = NULL;
1741 attr.SecurityQualityOfService = NULL;
1742 return NtOpenFile(handle,
1743 GENERIC_READ | SYNCHRONIZE,
1744 &attr, &io,
1745 FILE_SHARE_READ,
1746 FILE_SYNCHRONOUS_IO_ALERT);
1747 }
1748
1749 static NTSTATUS get_module_filename( HMODULE module, UNICODE_STRING *str, USHORT extra_len )
1750 {
1751 NTSTATUS status;
1752 ULONG magic;
1753 LDR_DATA_TABLE_ENTRY *pldr;
1754
1755 LdrLockLoaderLock(0, NULL, &magic);
1756 status = LdrFindEntryForAddress( module, &pldr );
1757 if (status == STATUS_SUCCESS)
1758 {
1759 if ((str->Buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0,
1760 pldr->FullDllName.Length + extra_len + sizeof(WCHAR) )))
1761 {
1762 memcpy( str->Buffer, pldr->FullDllName.Buffer, pldr->FullDllName.Length + sizeof(WCHAR) );
1763 str->Length = pldr->FullDllName.Length;
1764 str->MaximumLength = pldr->FullDllName.Length + extra_len + sizeof(WCHAR);
1765 }
1766 else status = STATUS_NO_MEMORY;
1767 }
1768 LdrUnlockLoaderLock(0, magic);
1769 return status;
1770 }
1771
1772 static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai,
1773 LPCWSTR filename, LPCWSTR directory, BOOL shared,
1774 HANDLE hModule, LPCWSTR resname, ULONG lang )
1775 {
1776 NTSTATUS status;
1777 UNICODE_STRING nameW;
1778 LDR_RESOURCE_INFO info;
1779 IMAGE_RESOURCE_DATA_ENTRY* entry = NULL;
1780 void *ptr;
1781
1782 //DPRINT( "looking for res %s in module %p %s\n", resname,
1783 // hModule, filename );
1784
1785 #if 0
1786 if (TRACE_ON(actctx))
1787 {
1788 if (!filename && !get_module_filename( hModule, &nameW, 0 ))
1789 {
1790 DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname),
1791 hModule, debugstr_w(nameW.Buffer) );
1792 RtlFreeUnicodeString( &nameW );
1793 }
1794 else DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname),
1795 hModule, debugstr_w(filename) );
1796 }
1797 #endif
1798
1799 if (!resname) return STATUS_INVALID_PARAMETER;
1800
1801 info.Type = (ULONG_PTR)RT_MANIFEST;
1802 info.Language = lang;
1803 if (!((ULONG_PTR)resname >> 16))
1804 {
1805 info.Name = (ULONG_PTR)resname;
1806 status = LdrFindResource_U(hModule, &info, 3, &entry);
1807 }
1808 else if (resname[0] == '#')
1809 {
1810 ULONG value;
1811 RtlInitUnicodeString(&nameW, resname + 1);
1812 if (RtlUnicodeStringToInteger(&nameW, 10, &value) != STATUS_SUCCESS || HIWORD(value))
1813 return STATUS_INVALID_PARAMETER;
1814 info.Name = value;
1815 status = LdrFindResource_U(hModule, &info, 3, &entry);
1816 }
1817 else
1818 {
1819 RtlCreateUnicodeString(&nameW, resname);
1820 RtlUpcaseUnicodeString(&nameW, &nameW, FALSE);
1821 info.Name = (ULONG_PTR)nameW.Buffer;
1822 status = LdrFindResource_U(hModule, &info, 3, &entry);
1823 RtlFreeUnicodeString(&nameW);
1824 }
1825 if (status == STATUS_SUCCESS) status = LdrAccessResource(hModule, entry, &ptr, NULL);
1826
1827 if (status == STATUS_SUCCESS)
1828 status = parse_manifest(acl, ai, filename, directory, shared, ptr, entry->Size);
1829
1830 return status;
1831 }
1832
1833 static NTSTATUS get_manifest_in_pe_file( struct actctx_loader* acl, struct assembly_identity* ai,
1834 LPCWSTR filename, LPCWSTR directory, BOOL shared,
1835 HANDLE file, LPCWSTR resname, ULONG lang )
1836 {
1837 HANDLE mapping;
1838 OBJECT_ATTRIBUTES attr;
1839 LARGE_INTEGER size;
1840 LARGE_INTEGER offset;
1841 NTSTATUS status;
1842 SIZE_T count;
1843 void *base;
1844
1845 DPRINT( "looking for res %S in %S\n", resname, filename );
1846
1847 attr.Length = sizeof(attr);
1848 attr.RootDirectory = 0;
1849 attr.ObjectName = NULL;
1850 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1851 attr.SecurityDescriptor = NULL;
1852 attr.SecurityQualityOfService = NULL;
1853
1854 size.QuadPart = 0;
1855 status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
1856 &attr, &size, PAGE_READONLY, SEC_COMMIT, file );
1857 if (status != STATUS_SUCCESS) return status;
1858
1859 offset.QuadPart = 0;
1860 count = 0;
1861 base = NULL;
1862 status = NtMapViewOfSection( mapping, NtCurrentProcess(), &base, 0, 0, &offset,
1863 &count, ViewShare, 0, PAGE_READONLY );
1864 NtClose( mapping );
1865 if (status != STATUS_SUCCESS) return status;
1866
1867 if (RtlImageNtHeader(base)) /* we got a PE file */
1868 {
1869 HANDLE module = (HMODULE)((ULONG_PTR)base | 1); /* make it a LOAD_LIBRARY_AS_DATAFILE handle */
1870 status = get_manifest_in_module( acl, ai, filename, directory, shared, module, resname, lang );
1871 }
1872 else status = STATUS_INVALID_IMAGE_FORMAT;
1873
1874 NtUnmapViewOfSection( NtCurrentProcess(), base );
1875 return status;
1876 }
1877
1878 static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct assembly_identity* ai,
1879 LPCWSTR filename, LPCWSTR directory, BOOL shared, HANDLE file )
1880 {
1881 FILE_STANDARD_INFORMATION info;
1882 IO_STATUS_BLOCK io;
1883 HANDLE mapping;
1884 OBJECT_ATTRIBUTES attr;
1885 LARGE_INTEGER size;
1886 LARGE_INTEGER offset;
1887 NTSTATUS status;
1888 SIZE_T count;
1889 void *base;
1890
1891 DPRINT( "loading manifest file %S\n", filename );
1892
1893 attr.Length = sizeof(attr);
1894 attr.RootDirectory = 0;
1895 attr.ObjectName = NULL;
1896 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1897 attr.SecurityDescriptor = NULL;
1898 attr.SecurityQualityOfService = NULL;
1899
1900 size.QuadPart = 0;
1901 status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
1902 &attr, &size, PAGE_READONLY, SEC_COMMIT, file );
1903
1904 if (status != STATUS_SUCCESS) return status;
1905
1906 offset.QuadPart = 0;
1907 count = 0;
1908 base = NULL;
1909 status = NtMapViewOfSection( mapping, NtCurrentProcess(), &base, 0, 0, &offset,
1910 &count, ViewShare, 0, PAGE_READONLY );
1911 NtClose( mapping );
1912 if (status != STATUS_SUCCESS) return status;
1913
1914 /* Fixme: WINE uses FileEndOfFileInformation with NtQueryInformationFile. */
1915 status = NtQueryInformationFile( file, &io, &info, sizeof(info), FileStandardInformation);
1916
1917 if (status == STATUS_SUCCESS)
1918 status = parse_manifest(acl, ai, filename, directory, shared, base, (SIZE_T)info.EndOfFile.QuadPart);
1919
1920 NtUnmapViewOfSection( NtCurrentProcess(), base );
1921 return status;
1922 }
1923
1924 /* try to load the .manifest file associated to the file */
1925 static NTSTATUS get_manifest_in_associated_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
1926 LPCWSTR filename, LPCWSTR directory, HMODULE module, LPCWSTR resname )
1927 {
1928 static const WCHAR fmtW[] = { '.','%','l','u',0 };
1929 WCHAR *buffer;
1930 NTSTATUS status;
1931 UNICODE_STRING nameW;
1932 HANDLE file;
1933 ULONG_PTR resid = (ULONG_PTR)CREATEPROCESS_MANIFEST_RESOURCE_ID;
1934
1935 if (!((ULONG_PTR)resname >> 16)) resid = (ULONG_PTR)resname & 0xffff;
1936
1937 DPRINT( "looking for manifest associated with %S id %lu\n", filename, resid );
1938
1939 if (module) /* use the module filename */
1940 {
1941 UNICODE_STRING name;
1942
1943 if (!(status = get_module_filename( module, &name, sizeof(dotManifestW) + 10*sizeof(WCHAR) )))
1944 {
1945 if (resid != 1) sprintfW( name.Buffer + strlenW(name.Buffer), fmtW, resid );
1946 strcatW( name.Buffer, dotManifestW );
1947 if (!RtlDosPathNameToNtPathName_U( name.Buffer, &nameW, NULL, NULL ))
1948 status = STATUS_RESOURCE_DATA_NOT_FOUND;
1949 RtlFreeUnicodeString( &name );
1950 }
1951 if (status) return status;
1952 }
1953 else
1954 {
1955 if (!(buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0,
1956 (strlenW(filename) + 10) * sizeof(WCHAR) + sizeof(dotManifestW) )))
1957 return STATUS_NO_MEMORY;
1958 strcpyW( buffer, filename );
1959 if (resid != 1) sprintfW( buffer + strlenW(buffer), fmtW, resid );
1960 strcatW( buffer, dotManifestW );
1961 RtlInitUnicodeString( &nameW, buffer );
1962 }
1963
1964 if (!open_nt_file( &file, &nameW ))
1965 {
1966 status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, FALSE, file );
1967 NtClose( file );
1968 }
1969 else status = STATUS_RESOURCE_TYPE_NOT_FOUND;
1970 RtlFreeUnicodeString( &nameW );
1971 return status;
1972 }
1973
1974 static WCHAR *lookup_manifest_file( HANDLE dir, struct assembly_identity *ai )
1975 {
1976 static const WCHAR lookup_fmtW[] =
1977 {'%','s','_','%','s','_','%','s','_','%','u','.','%','u','.','*','.','*','_',
1978 '*', /* FIXME */
1979 '.','m','a','n','i','f','e','s','t',0};
1980
1981 WCHAR *lookup, *ret = NULL;
1982 UNICODE_STRING lookup_us;
1983 IO_STATUS_BLOCK io;
1984 const WCHAR *lang = ai->language;
1985 unsigned int data_pos = 0, data_len;
1986 char buffer[8192];
1987
1988 if (!(lookup = RtlAllocateHeap( RtlGetProcessHeap(), 0,
1989 (strlenW(ai->arch) + strlenW(ai->name)
1990 + strlenW(ai->public_key) + 20) * sizeof(WCHAR)
1991 + sizeof(lookup_fmtW) )))
1992 return NULL;
1993
1994 if (!lang || !strcmpiW( lang, neutralW )) lang = wildcardW;
1995 sprintfW( lookup, lookup_fmtW, ai->arch, ai->name, ai->public_key,
1996 ai->version.major, ai->version.minor, lang );
1997 RtlInitUnicodeString( &lookup_us, lookup );
1998
1999 NtQueryDirectoryFile( dir, 0, NULL, NULL, &io, buffer, sizeof(buffer),
2000 FileBothDirectoryInformation, FALSE, &lookup_us, TRUE );
2001 if (io.Status == STATUS_SUCCESS)
2002 {
2003 FILE_BOTH_DIR_INFORMATION *dir_info;
2004 WCHAR *tmp;
2005 ULONG build, revision;
2006
2007 data_len = (ULONG)io.Information;
2008
2009 for (;;)
2010 {
2011 if (data_pos >= data_len)
2012 {
2013 NtQueryDirectoryFile( dir, 0, NULL, NULL, &io, buffer, sizeof(buffer),
2014 FileBothDirectoryInformation, FALSE, &lookup_us, FALSE );
2015 if (io.Status != STATUS_SUCCESS) break;
2016 data_len = (ULONG)io.Information;
2017 data_pos = 0;
2018 }
2019 dir_info = (FILE_BOTH_DIR_INFORMATION*)(buffer + data_pos);
2020
2021 if (dir_info->NextEntryOffset) data_pos += dir_info->NextEntryOffset;
2022 else data_pos = data_len;
2023
2024 tmp = (WCHAR *)dir_info->FileName + (strchrW(lookup, '*') - lookup);
2025 build = atoiW(tmp);
2026 if (build < ai->version.build) continue;
2027 tmp = strchrW(tmp, '.') + 1;
2028 revision = atoiW(tmp);
2029 if (build == ai->version.build && revision < ai->version.revision)
2030 continue;
2031 ai->version.build = (USHORT)build;
2032 ai->version.revision = (USHORT)revision;
2033
2034 if ((ret = RtlAllocateHeap( RtlGetProcessHeap(), 0, dir_info->FileNameLength * sizeof(WCHAR) )))
2035 {
2036 memcpy( ret, dir_info->FileName, dir_info->FileNameLength );
2037 ret[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
2038 }
2039 break;
2040 }
2041 }
2042 else DPRINT1("no matching file for %S\n", lookup);
2043 RtlFreeHeap( RtlGetProcessHeap(), 0, lookup );
2044 return ret;
2045 }
2046
2047 static NTSTATUS lookup_winsxs(struct actctx_loader* acl, struct assembly_identity* ai)
2048 {
2049 struct assembly_identity sxs_ai;
2050 UNICODE_STRING path_us;
2051 OBJECT_ATTRIBUTES attr;
2052 IO_STATUS_BLOCK io;
2053 WCHAR *path, *file = NULL;
2054 HANDLE handle;
2055
2056 static const WCHAR manifest_dirW[] =
2057 {'\\','w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s',0};
2058
2059 if (!ai->arch || !ai->name || !ai->public_key) return STATUS_NO_SUCH_FILE;
2060
2061 if (!(path = RtlAllocateHeap( RtlGetProcessHeap(), 0,
2062 ((strlenW(SharedUserData->NtSystemRoot) + 1) *sizeof(WCHAR)) + sizeof(manifest_dirW) )))
2063 return STATUS_NO_MEMORY;
2064
2065 memcpy( path, SharedUserData->NtSystemRoot, strlenW(SharedUserData->NtSystemRoot) * sizeof(WCHAR) );
2066 memcpy( path + strlenW(SharedUserData->NtSystemRoot), manifest_dirW, sizeof(manifest_dirW) );
2067
2068 if (!RtlDosPathNameToNtPathName_U( path, &path_us, NULL, NULL ))
2069 {
2070 RtlFreeHeap( RtlGetProcessHeap(), 0, path );
2071 return STATUS_NO_SUCH_FILE;
2072 }
2073 RtlFreeHeap( RtlGetProcessHeap(), 0, path );
2074
2075 attr.Length = sizeof(attr);
2076 attr.RootDirectory = 0;
2077 attr.Attributes = OBJ_CASE_INSENSITIVE;
2078 attr.ObjectName = &path_us;
2079 attr.SecurityDescriptor = NULL;
2080 attr.SecurityQualityOfService = NULL;
2081
2082 if (!NtOpenFile(&handle,
2083 GENERIC_READ | SYNCHRONIZE,
2084 &attr, &io,
2085 FILE_SHARE_READ | FILE_SHARE_WRITE,
2086 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT))
2087 {
2088 sxs_ai = *ai;
2089 file = lookup_manifest_file( handle, &sxs_ai );
2090 NtClose( handle );
2091 }
2092 if (!file)
2093 {
2094 RtlFreeUnicodeString( &path_us );
2095 return STATUS_NO_SUCH_FILE;
2096 }
2097
2098 /* append file name to directory path */
2099 if (!(path = RtlReAllocateHeap( RtlGetProcessHeap(), 0, path_us.Buffer,
2100 path_us.Length + (strlenW(file) + 2) * sizeof(WCHAR) )))
2101 {
2102 RtlFreeHeap( RtlGetProcessHeap(), 0, file );
2103 RtlFreeUnicodeString( &path_us );
2104 return STATUS_NO_MEMORY;
2105 }
2106
2107 path[path_us.Length/sizeof(WCHAR)] = '\\';
2108 strcpyW( path + path_us.Length/sizeof(WCHAR) + 1, file );
2109 RtlInitUnicodeString( &path_us, path );
2110 *strrchrW(file, '.') = 0; /* remove .manifest extension */
2111
2112 if (!open_nt_file( &handle, &path_us ))
2113 {
2114 io.Status = get_manifest_in_manifest_file(acl, &sxs_ai, path_us.Buffer, file, TRUE, handle);
2115 NtClose( handle );
2116 }
2117 else io.Status = STATUS_NO_SUCH_FILE;
2118
2119 RtlFreeHeap( RtlGetProcessHeap(), 0, file );
2120 RtlFreeUnicodeString( &path_us );
2121 return io.Status;
2122 }
2123
2124 static NTSTATUS lookup_assembly(struct actctx_loader* acl,
2125 struct assembly_identity* ai)
2126 {
2127 static const WCHAR dotDllW[] = {'.','d','l','l',0};
2128 unsigned int i;
2129 WCHAR *buffer, *p, *directory;
2130 NTSTATUS status;
2131 UNICODE_STRING nameW;
2132 HANDLE file;
2133 DWORD len;
2134
2135 DPRINT( "looking for name=%S version=%u.%u.%u.%u arch=%S\n",
2136 ai->name, ai->version.major, ai->version.minor, ai->version.build, ai->version.revision, ai->arch );
2137
2138 if ((status = lookup_winsxs(acl, ai)) != STATUS_NO_SUCH_FILE) return status;
2139
2140 /* FIXME: add support for language specific lookup */
2141
2142 len = max(RtlGetFullPathName_U(acl->actctx->assemblies->manifest.info, 0, NULL, NULL) / sizeof(WCHAR),
2143 strlenW(acl->actctx->appdir.info));
2144
2145 nameW.Buffer = NULL;
2146 if (!(buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0,
2147 (len + 2 * strlenW(ai->name) + 2) * sizeof(WCHAR) + sizeof(dotManifestW) )))
2148 return STATUS_NO_MEMORY;
2149
2150 if (!(directory = build_assembly_dir( ai )))
2151 {
2152 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
2153 return STATUS_NO_MEMORY;
2154 }
2155
2156 /* Lookup in <dir>\name.dll
2157 * <dir>\name.manifest
2158 * <dir>\name\name.dll
2159 * <dir>\name\name.manifest
2160 *
2161 * First 'appdir' is used as <dir>, if that failed
2162 * it tries application manifest file path.
2163 */
2164 strcpyW( buffer, acl->actctx->appdir.info );
2165 p = buffer + strlenW(buffer);
2166 for (i = 0; i < 4; i++)
2167 {
2168 if (i == 2)
2169 {
2170 struct assembly *assembly = acl->actctx->assemblies;
2171 if (!RtlGetFullPathName_U(assembly->manifest.info, len * sizeof(WCHAR), buffer, &p)) break;
2172 }
2173 else *p++ = '\\';
2174
2175 strcpyW( p, ai->name );
2176 p += strlenW(p);
2177
2178 strcpyW( p, dotDllW );
2179 if (RtlDosPathNameToNtPathName_U( buffer, &nameW, NULL, NULL ))
2180 {
2181 status = open_nt_file( &file, &nameW );
2182 if (!status)
2183 {
2184 status = get_manifest_in_pe_file( acl, ai, nameW.Buffer, directory, FALSE, file,
2185 (LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID, 0 );
2186 NtClose( file );
2187 break;
2188 }
2189 RtlFreeUnicodeString( &nameW );
2190 }
2191
2192 strcpyW( p, dotManifestW );
2193 if (RtlDosPathNameToNtPathName_U( buffer, &nameW, NULL, NULL ))
2194 {
2195 status = open_nt_file( &file, &nameW );
2196 if (!status)
2197 {
2198 status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, FALSE, file );
2199 NtClose( file );
2200 break;
2201 }
2202 RtlFreeUnicodeString( &nameW );
2203 }
2204 status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
2205 }
2206 RtlFreeUnicodeString( &nameW );
2207 RtlFreeHeap( RtlGetProcessHeap(), 0, directory );
2208 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
2209 return status;
2210 }
2211
2212 static NTSTATUS parse_depend_manifests(struct actctx_loader* acl)
2213 {
2214 NTSTATUS status = STATUS_SUCCESS;
2215 unsigned int i;
2216
2217 for (i = 0; i < acl->num_dependencies; i++)
2218 {
2219 if (lookup_assembly(acl, &acl->dependencies[i]) != STATUS_SUCCESS)
2220 {
2221 if (!acl->dependencies[i].optional)
2222 {
2223 DPRINT1( "Could not find dependent assembly %S\n", acl->dependencies[i].name );
2224 status = STATUS_SXS_CANT_GEN_ACTCTX;
2225 break;
2226 }
2227 }
2228 }
2229 /* FIXME should now iterate through all refs */
2230 return status;
2231 }
2232
2233 /* find the appropriate activation context for RtlQueryInformationActivationContext */
2234 static NTSTATUS find_query_actctx( HANDLE *handle, DWORD flags, ULONG class )
2235 {
2236 NTSTATUS status = STATUS_SUCCESS;
2237
2238 if (flags & RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT)
2239 {
2240 if (*handle) return STATUS_INVALID_PARAMETER;
2241
2242 if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
2243 *handle = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext;
2244 }
2245 else if (flags & (RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS | RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE))
2246 {
2247 ULONG magic;
2248 LDR_DATA_TABLE_ENTRY *pldr;
2249
2250 if (!*handle) return STATUS_INVALID_PARAMETER;
2251
2252 LdrLockLoaderLock( 0, NULL, &magic );
2253 if (!LdrFindEntryForAddress( *handle, &pldr ))
2254 {
2255 if ((flags & RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE) && *handle != pldr->DllBase)
2256 status = STATUS_DLL_NOT_FOUND;
2257 else
2258 *handle = pldr->EntryPointActivationContext;
2259 }
2260 else status = STATUS_DLL_NOT_FOUND;
2261 LdrUnlockLoaderLock( 0, magic );
2262 }
2263 else if (!*handle && (class != ActivationContextBasicInformation))
2264 *handle = process_actctx;
2265
2266 return status;
2267 }
2268
2269 static NTSTATUS fill_keyed_data(PACTCTX_SECTION_KEYED_DATA data, PVOID v1, PVOID v2, unsigned int i)
2270 {
2271 data->ulDataFormatVersion = 1;
2272 data->lpData = v1;
2273 data->ulLength = 20; /* FIXME */
2274 data->lpSectionGlobalData = NULL; /* FIXME */
2275 data->ulSectionGlobalDataLength = 0; /* FIXME */
2276 data->lpSectionBase = v2;
2277 data->ulSectionTotalLength = 0; /* FIXME */
2278 data->hActCtx = NULL;
2279 if (data->cbSize >= offsetof(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
2280 data->ulAssemblyRosterIndex = i + 1;
2281
2282 return STATUS_SUCCESS;
2283 }
2284
2285 static NTSTATUS find_dll_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *section_name,
2286 PACTCTX_SECTION_KEYED_DATA data)
2287 {
2288 unsigned int i, j, snlen = section_name->Length / sizeof(WCHAR);
2289
2290 for (i = 0; i < actctx->num_assemblies; i++)
2291 {
2292 struct assembly *assembly = &actctx->assemblies[i];
2293 for (j = 0; j < assembly->num_dlls; j++)
2294 {
2295 struct dll_redirect *dll = &assembly->dlls[j];
2296 if (!strncmpiW(section_name->Buffer, dll->name, snlen) && !dll->name[snlen])
2297 return fill_keyed_data(data, dll, assembly, i);
2298 }
2299 }
2300 return STATUS_SXS_KEY_NOT_FOUND;
2301 }
2302
2303 static NTSTATUS find_window_class(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *section_name,
2304 PACTCTX_SECTION_KEYED_DATA data)
2305 {
2306 unsigned int i, j, k, snlen = section_name->Length / sizeof(WCHAR);
2307
2308 for (i = 0; i < actctx->num_assemblies; i++)
2309 {
2310 struct assembly *assembly = &actctx->assemblies[i];
2311 for (j = 0; j < assembly->num_dlls; j++)
2312 {
2313 struct dll_redirect *dll = &assembly->dlls[j];
2314 for (k = 0; k < dll->entities.num; k++)
2315 {
2316 struct entity *entity = &dll->entities.base[k];
2317 if (entity->kind == ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)
2318 {
2319 if (!strncmpiW(section_name->Buffer, entity->u.class.name, snlen) && !entity->u.class.name[snlen])
2320 return fill_keyed_data(data, entity, dll, i);
2321 }
2322 }
2323 }
2324 }
2325 return STATUS_SXS_KEY_NOT_FOUND;
2326 }
2327
2328 static NTSTATUS find_string(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
2329 const UNICODE_STRING *section_name,
2330 DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
2331 {
2332 NTSTATUS status;
2333
2334 switch (section_kind)
2335 {
2336 case ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION:
2337 status = find_dll_redirection(actctx, section_name, data);
2338 break;
2339 case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION:
2340 status = find_window_class(actctx, section_name, data);
2341 break;
2342 case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
2343 case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
2344 case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION:
2345 case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION:
2346 case ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE:
2347 case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES:
2348 DPRINT1("Unsupported yet section_kind %x\n", section_kind);
2349 return STATUS_SXS_SECTION_NOT_FOUND;
2350 default:
2351 DPRINT1("Unknown section_kind %x\n", section_kind);
2352 return STATUS_SXS_SECTION_NOT_FOUND;
2353 }
2354
2355 if (status != STATUS_SUCCESS) return status;
2356
2357 if (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
2358 {
2359 actctx_addref(actctx);
2360 data->hActCtx = actctx;
2361 }
2362 return STATUS_SUCCESS;
2363 }
2364
2365 static NTSTATUS find_guid(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
2366 const GUID *guid, DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
2367 {
2368 NTSTATUS status;
2369
2370 switch (section_kind)
2371 {
2372 default:
2373 DPRINT("Unknown section_kind %x\n", section_kind);
2374 return STATUS_SXS_SECTION_NOT_FOUND;
2375 }
2376
2377 if (status != STATUS_SUCCESS) return status;
2378
2379 if (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
2380 {
2381 actctx_addref(actctx);
2382 data->hActCtx = actctx;
2383 }
2384 return STATUS_SUCCESS;
2385 }
2386
2387 /* initialize the activation context for the current process */
2388 void actctx_init(void)
2389 {
2390 ACTCTXW ctx;
2391 HANDLE handle;
2392
2393 ctx.cbSize = sizeof(ctx);
2394 ctx.lpSource = NULL;
2395 ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
2396 ctx.hModule = NtCurrentTeb()->ProcessEnvironmentBlock->ImageBaseAddress;
2397 ctx.lpResourceName = (LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID;
2398
2399 if (NT_SUCCESS(RtlCreateActivationContext(0, (PVOID)&ctx, 0, NULL, NULL, &handle)))
2400 {
2401 process_actctx = check_actctx(handle);
2402 }
2403 }
2404
2405 /* FUNCTIONS ***************************************************************/
2406
2407 NTSTATUS
2408 NTAPI
2409 RtlCreateActivationContext(IN ULONG Flags,
2410 IN PACTIVATION_CONTEXT_DATA ActivationContextData,
2411 IN ULONG ExtraBytes,
2412 IN PVOID NotificationRoutine,
2413 IN PVOID NotificationContext,
2414 OUT PACTIVATION_CONTEXT *ActCtx)
2415 {
2416 const ACTCTXW *pActCtx = (PVOID)ActivationContextData;
2417 const WCHAR *directory = NULL;
2418 PACTIVATION_CONTEXT_WRAPPED ActualActCtx;
2419 ACTIVATION_CONTEXT *actctx;
2420 UNICODE_STRING nameW;
2421 ULONG lang = 0;
2422 NTSTATUS status = STATUS_NO_MEMORY;
2423 HANDLE file = 0;
2424 struct actctx_loader acl;
2425
2426 DPRINT("%p %08x\n", pActCtx, pActCtx ? pActCtx->dwFlags : 0);
2427
2428 if (!pActCtx || pActCtx->cbSize < sizeof(*pActCtx) ||
2429 (pActCtx->dwFlags & ~ACTCTX_FLAGS_ALL))
2430 return STATUS_INVALID_PARAMETER;
2431
2432
2433 if (!(ActualActCtx = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ActualActCtx))))
2434 return STATUS_NO_MEMORY;
2435
2436 ActualActCtx->MagicMarker = ACTCTX_MAGIC_MARKER;
2437
2438 actctx = &ActualActCtx->ActivationContext;
2439 actctx->RefCount = 1;
2440 actctx->config.type = ACTIVATION_CONTEXT_PATH_TYPE_NONE;
2441 actctx->config.info = NULL;
2442 actctx->appdir.type = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
2443 if (pActCtx->dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID)
2444 {
2445 if (!(actctx->appdir.info = strdupW( pActCtx->lpApplicationName ))) goto error;
2446 }
2447 else
2448 {
2449 UNICODE_STRING dir;
2450 WCHAR *p;
2451 HMODULE module;
2452
2453 if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID) module = pActCtx->hModule;
2454 else module = NtCurrentTeb()->ProcessEnvironmentBlock->ImageBaseAddress;
2455
2456 status = get_module_filename(module, &dir, 0);
2457 if (!NT_SUCCESS(status)) goto error;
2458 if ((p = strrchrW( dir.Buffer, '\\' ))) p[1] = 0;
2459 actctx->appdir.info = dir.Buffer;
2460 }
2461
2462 nameW.Buffer = NULL;
2463
2464 /* open file only if it's going to be used */
2465 if (pActCtx->lpSource && !((pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) &&
2466 (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)))
2467 {
2468 if (!RtlDosPathNameToNtPathName_U(pActCtx->lpSource, &nameW, NULL, NULL))
2469 {
2470 status = STATUS_NO_SUCH_FILE;
2471 goto error;
2472 }
2473 status = open_nt_file( &file, &nameW );
2474 if (!NT_SUCCESS(status))
2475 {
2476 RtlFreeUnicodeString( &nameW );
2477 goto error;
2478 }
2479 }
2480
2481 acl.actctx = actctx;
2482 acl.dependencies = NULL;
2483 acl.num_dependencies = 0;
2484 acl.allocated_dependencies = 0;
2485
2486 if (pActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID) lang = pActCtx->wLangId;
2487 if (pActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) directory = pActCtx->lpAssemblyDirectory;
2488
2489 if (pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID)
2490 {
2491 /* if we have a resource it's a PE file */
2492 if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)
2493 {
2494 status = get_manifest_in_module( &acl, NULL, NULL, directory, FALSE, pActCtx->hModule,
2495 pActCtx->lpResourceName, lang );
2496 if (status && status != STATUS_SXS_CANT_GEN_ACTCTX)
2497 /* FIXME: what to do if pActCtx->lpSource is set */
2498 status = get_manifest_in_associated_manifest( &acl, NULL, NULL, directory,
2499 pActCtx->hModule, pActCtx->lpResourceName );
2500 }
2501 else if (pActCtx->lpSource)
2502 {
2503 status = get_manifest_in_pe_file( &acl, NULL, nameW.Buffer, directory, FALSE,
2504 file, pActCtx->lpResourceName, lang );
2505 if (status && status != STATUS_SXS_CANT_GEN_ACTCTX)
2506 status = get_manifest_in_associated_manifest( &acl, NULL, nameW.Buffer, directory,
2507 NULL, pActCtx->lpResourceName );
2508 }
2509 else status = STATUS_INVALID_PARAMETER;
2510 }
2511 else
2512 {
2513 status = get_manifest_in_manifest_file( &acl, NULL, nameW.Buffer, directory, FALSE, file );
2514 }
2515
2516 if (file) NtClose( file );
2517 RtlFreeUnicodeString( &nameW );
2518
2519 if (NT_SUCCESS(status)) status = parse_depend_manifests(&acl);
2520 free_depend_manifests( &acl );
2521
2522 if (NT_SUCCESS(status))
2523 *ActCtx = actctx;
2524 else actctx_release( actctx );
2525 return status;
2526
2527 error:
2528 if (file) NtClose( file );
2529 actctx_release( actctx );
2530 return status;
2531 }
2532
2533 #if 0
2534 #define ACT_CTX_VALID(p) ((((ULONG_PTR)p - 1) | 7) != -1)
2535
2536 VOID
2537 NTAPI
2538 RtlAddRefActivationContext(IN PACTIVATION_CONTEXT Handle)
2539 {
2540 PIACTIVATION_CONTEXT ActCtx = (PIACTIVATION_CONTEXT)Handle;
2541 LONG OldRefCount, NewRefCount;
2542
2543 if ((ActCtx) && (ACT_CTX_VALID(ActCtx)) && (ActCtx->RefCount != LONG_MAX))
2544 {
2545 RtlpValidateActCtx(ActCtx);
2546
2547 while (TRUE)
2548 {
2549 OldRefCount = ActCtx->RefCount;
2550 ASSERT(OldRefCount > 0);
2551
2552 if (OldRefCount == LONG_MAX) break;
2553
2554 NewRefCount = OldRefCount + 1;
2555 if (InterlockedCompareExchange(&ActCtx->RefCount,
2556 NewRefCount,
2557 OldRefCount) == OldRefCount)
2558 {
2559 break;
2560 }
2561 }
2562
2563 NewRefCount = LONG_MAX;
2564 ASSERT(NewRefCount > 0);
2565 }
2566 }
2567
2568 VOID
2569 NTAPI
2570 RtlReleaseActivationContext( HANDLE handle )
2571 {
2572 PIACTIVATION_CONTEXT ActCtx = (PIACTIVATION_CONTEXT) Handle;
2573
2574 if ((ActCtx) && (ACT_CTX_VALID(ActCtx)) && (ActCtx->RefCount != LONG_MAX))
2575 {
2576 RtlpValidateActCtx(ActCtx);
2577
2578 actctx_release(ActCtx);
2579 }
2580 }
2581 #else
2582 VOID
2583 NTAPI
2584 RtlAddRefActivationContext( HANDLE handle )
2585 {
2586 ACTIVATION_CONTEXT *actctx;
2587
2588 if ((actctx = check_actctx(handle))) actctx_addref(actctx);
2589 }
2590
2591 VOID
2592 NTAPI
2593 RtlReleaseActivationContext( HANDLE handle )
2594 {
2595 ACTIVATION_CONTEXT *actctx;
2596
2597 if ((actctx = check_actctx(handle))) actctx_release(actctx);
2598 }
2599 #endif
2600
2601 NTSTATUS
2602 NTAPI RtlActivateActivationContextEx( ULONG flags, PTEB tebAddress, HANDLE handle, PULONG_PTR cookie )
2603 {
2604 RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
2605
2606 if (!(frame = RtlAllocateHeap( RtlGetProcessHeap(), 0, sizeof(*frame) )))
2607 return STATUS_NO_MEMORY;
2608
2609 frame->Previous = tebAddress->ActivationContextStackPointer->ActiveFrame;
2610 frame->ActivationContext = handle;
2611 frame->Flags = 0;
2612
2613 tebAddress->ActivationContextStackPointer->ActiveFrame = frame;
2614 RtlAddRefActivationContext( handle );
2615
2616 *cookie = (ULONG_PTR)frame;
2617 DPRINT( "%p cookie=%lx\n", handle, *cookie );
2618 return STATUS_SUCCESS;
2619 }
2620
2621
2622 NTSTATUS
2623 NTAPI RtlActivateActivationContext( ULONG flags, HANDLE handle, PULONG_PTR cookie )
2624 {
2625 return RtlActivateActivationContextEx(flags, NtCurrentTeb(), handle, cookie);
2626 }
2627
2628 NTSTATUS
2629 NTAPI
2630 RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie )
2631 {
2632 RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame, *top;
2633
2634 DPRINT( "%x cookie=%lx\n", flags, cookie );
2635
2636 /* find the right frame */
2637 top = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
2638 for (frame = top; frame; frame = frame->Previous)
2639 if ((ULONG_PTR)frame == cookie) break;
2640
2641 if (!frame)
2642 RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION );
2643
2644 if (frame != top && !(flags & RTL_DEACTIVATE_ACTIVATION_CONTEXT_FLAG_FORCE_EARLY_DEACTIVATION))
2645 RtlRaiseStatus( STATUS_SXS_EARLY_DEACTIVATION );
2646
2647 /* pop everything up to and including frame */
2648 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = frame->Previous;
2649
2650 while (top != NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
2651 {
2652 frame = top->Previous;
2653 RtlReleaseActivationContext( top->ActivationContext );
2654 RtlFreeHeap( RtlGetProcessHeap(), 0, top );
2655 top = frame;
2656 }
2657
2658 return STATUS_SUCCESS;
2659 }
2660
2661 VOID
2662 NTAPI
2663 RtlFreeActivationContextStack(IN PACTIVATION_CONTEXT_STACK Stack)
2664 {
2665 PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame, PrevFrame;
2666
2667 /* Nothing to do if there is no stack */
2668 if (!Stack) return;
2669
2670 /* Get the current active frame */
2671 ActiveFrame = Stack->ActiveFrame;
2672
2673 /* Go through them in backwards order and release */
2674 while (ActiveFrame)
2675 {
2676 PrevFrame = ActiveFrame->Previous;
2677 RtlReleaseActivationContext(ActiveFrame->ActivationContext);
2678 RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveFrame);
2679 ActiveFrame = PrevFrame;
2680 }
2681
2682 /* Zero out the active frame */
2683 Stack->ActiveFrame = NULL;
2684
2685 /* TODO: Empty the Frame List Cache */
2686 ASSERT(IsListEmpty(&Stack->FrameListCache));
2687
2688 /* Free activation stack memory */
2689 RtlFreeHeap(RtlGetProcessHeap(), 0, Stack);
2690 }
2691
2692 VOID
2693 NTAPI RtlFreeThreadActivationContextStack(VOID)
2694 {
2695 RtlFreeActivationContextStack(NtCurrentTeb()->ActivationContextStackPointer);
2696 NtCurrentTeb()->ActivationContextStackPointer = NULL;
2697 }
2698
2699
2700 NTSTATUS
2701 NTAPI RtlGetActiveActivationContext( HANDLE *handle )
2702 {
2703 if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
2704 {
2705 *handle = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext;
2706 RtlAddRefActivationContext( *handle );
2707 }
2708 else
2709 *handle = 0;
2710
2711 return STATUS_SUCCESS;
2712 }
2713
2714
2715 BOOLEAN
2716 NTAPI RtlIsActivationContextActive( HANDLE handle )
2717 {
2718 RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
2719
2720 for (frame = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame; frame; frame = frame->Previous)
2721 if (frame->ActivationContext == handle) return TRUE;
2722 return FALSE;
2723 }
2724
2725 NTSTATUS
2726 NTAPI
2727 RtlQueryInformationActivationContext( ULONG flags, HANDLE handle, PVOID subinst,
2728 ULONG class, PVOID buffer,
2729 SIZE_T bufsize, SIZE_T *retlen )
2730 {
2731 ACTIVATION_CONTEXT *actctx;
2732 NTSTATUS status;
2733
2734 DPRINT("%08x %p %p %u %p %Iu %p\n", flags, handle,
2735 subinst, class, buffer, bufsize, retlen);
2736
2737 if (retlen) *retlen = 0;
2738 if ((status = find_query_actctx( &handle, flags, class ))) return status;
2739
2740 switch (class)
2741 {
2742 case ActivationContextBasicInformation:
2743 {
2744 ACTIVATION_CONTEXT_BASIC_INFORMATION *info = buffer;
2745
2746 if (retlen) *retlen = sizeof(*info);
2747 if (!info || bufsize < sizeof(*info)) return STATUS_BUFFER_TOO_SMALL;
2748
2749 info->hActCtx = handle;
2750 info->dwFlags = 0; /* FIXME */
2751 if (!(flags & RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF)) RtlAddRefActivationContext(handle);
2752 }
2753 break;
2754
2755 case ActivationContextDetailedInformation:
2756 {
2757 ACTIVATION_CONTEXT_DETAILED_INFORMATION *acdi = buffer;
2758 struct assembly *assembly = NULL;
2759 SIZE_T len, manifest_len = 0, config_len = 0, appdir_len = 0;
2760 LPWSTR ptr;
2761
2762 if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
2763
2764 if (actctx->num_assemblies) assembly = actctx->assemblies;
2765
2766 if (assembly && assembly->manifest.info)
2767 manifest_len = strlenW(assembly->manifest.info) + 1;
2768 if (actctx->config.info) config_len = strlenW(actctx->config.info) + 1;
2769 if (actctx->appdir.info) appdir_len = strlenW(actctx->appdir.info) + 1;
2770 len = sizeof(*acdi) + (manifest_len + config_len + appdir_len) * sizeof(WCHAR);
2771
2772 if (retlen) *retlen = len;
2773 if (!buffer || bufsize < len) return STATUS_BUFFER_TOO_SMALL;
2774
2775 acdi->dwFlags = 0;
2776 acdi->ulFormatVersion = assembly ? 1 : 0; /* FIXME */
2777 acdi->ulAssemblyCount = actctx->num_assemblies;
2778 acdi->ulRootManifestPathType = assembly ? assembly->manifest.type : 0 /* FIXME */;
2779 acdi->ulRootManifestPathChars = assembly && assembly->manifest.info ? (DWORD)manifest_len - 1 : 0;
2780 acdi->ulRootConfigurationPathType = actctx->config.type;
2781 acdi->ulRootConfigurationPathChars = actctx->config.info ? (DWORD)config_len - 1 : 0;
2782 acdi->ulAppDirPathType = actctx->appdir.type;
2783 acdi->ulAppDirPathChars = actctx->appdir.info ? (DWORD)appdir_len - 1 : 0;
2784 ptr = (LPWSTR)(acdi + 1);
2785 if (manifest_len)
2786 {
2787 acdi->lpRootManifestPath = ptr;
2788 memcpy(ptr, assembly->manifest.info, manifest_len * sizeof(WCHAR));
2789 ptr += manifest_len;
2790 }
2791 else acdi->lpRootManifestPath = NULL;
2792 if (config_len)
2793 {
2794 acdi->lpRootConfigurationPath = ptr;
2795 memcpy(ptr, actctx->config.info, config_len * sizeof(WCHAR));
2796 ptr += config_len;
2797 }
2798 else acdi->lpRootConfigurationPath = NULL;
2799 if (appdir_len)
2800 {
2801 acdi->lpAppDirPath = ptr;
2802 memcpy(ptr, actctx->appdir.info, appdir_len * sizeof(WCHAR));
2803 }
2804 else acdi->lpAppDirPath = NULL;
2805 }
2806 break;
2807
2808 case AssemblyDetailedInformationInActivationContext:
2809 {
2810 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *afdi = buffer;
2811 struct assembly *assembly;
2812 WCHAR *assembly_id;
2813 DWORD index;
2814 SIZE_T len, id_len = 0, ad_len = 0, path_len = 0;
2815 LPWSTR ptr;
2816
2817 if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
2818 if (!subinst) return STATUS_INVALID_PARAMETER;
2819
2820 index = *(DWORD*)subinst;
2821 if (!index || index > actctx->num_assemblies) return STATUS_INVALID_PARAMETER;
2822
2823 assembly = &actctx->assemblies[index - 1];
2824
2825 if (!(assembly_id = build_assembly_id( &assembly->id ))) return STATUS_NO_MEMORY;
2826 id_len = strlenW(assembly_id) + 1;
2827 if (assembly->directory) ad_len = strlenW(assembly->directory) + 1;
2828
2829 if (assembly->manifest.info &&
2830 (assembly->type == ASSEMBLY_MANIFEST || assembly->type == ASSEMBLY_SHARED_MANIFEST))
2831 path_len = strlenW(assembly->manifest.info) + 1;
2832
2833 len = sizeof(*afdi) + (id_len + ad_len + path_len) * sizeof(WCHAR);
2834
2835 if (retlen) *retlen = len;
2836 if (!buffer || bufsize < len)
2837 {
2838 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id );
2839 return STATUS_BUFFER_TOO_SMALL;
2840 }
2841
2842 afdi->ulFlags = 0; /* FIXME */
2843 afdi->ulEncodedAssemblyIdentityLength = (DWORD)(id_len - 1) * sizeof(WCHAR);
2844 afdi->ulManifestPathType = assembly->manifest.type;
2845 afdi->ulManifestPathLength = assembly->manifest.info ? (DWORD)(path_len - 1) * sizeof(WCHAR) : 0;
2846 /* FIXME afdi->liManifestLastWriteTime = 0; */
2847 afdi->ulPolicyPathType = ACTIVATION_CONTEXT_PATH_TYPE_NONE; /* FIXME */
2848 afdi->ulPolicyPathLength = 0;
2849 /* FIXME afdi->liPolicyLastWriteTime = 0; */
2850 afdi->ulMetadataSatelliteRosterIndex = 0; /* FIXME */
2851 afdi->ulManifestVersionMajor = 1;
2852 afdi->ulManifestVersionMinor = 0;
2853 afdi->ulPolicyVersionMajor = 0; /* FIXME */
2854 afdi->ulPolicyVersionMinor = 0; /* FIXME */
2855 afdi->ulAssemblyDirectoryNameLength = ad_len ? (DWORD)(ad_len - 1) * sizeof(WCHAR) : 0;
2856 ptr = (LPWSTR)(afdi + 1);
2857 afdi->lpAssemblyEncodedAssemblyIdentity = ptr;
2858 memcpy( ptr, assembly_id, id_len * sizeof(WCHAR) );
2859 ptr += id_len;
2860 if (path_len)
2861 {
2862 afdi->lpAssemblyManifestPath = ptr;
2863 memcpy(ptr, assembly->manifest.info, path_len * sizeof(WCHAR));
2864 ptr += path_len;
2865 } else afdi->lpAssemblyManifestPath = NULL;
2866 afdi->lpAssemblyPolicyPath = NULL; /* FIXME */
2867 if (ad_len)
2868 {
2869 afdi->lpAssemblyDirectoryName = ptr;
2870 memcpy(ptr, assembly->directory, ad_len * sizeof(WCHAR));
2871 }
2872 else afdi->lpAssemblyDirectoryName = NULL;
2873 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id );
2874 }
2875 break;
2876
2877 case FileInformationInAssemblyOfAssemblyInActivationContext:
2878 {
2879 const ACTIVATION_CONTEXT_QUERY_INDEX *acqi = subinst;
2880 ASSEMBLY_FILE_DETAILED_INFORMATION *afdi = buffer;
2881 struct assembly *assembly;
2882 struct dll_redirect *dll;
2883 SIZE_T len, dll_len = 0;
2884 LPWSTR ptr;
2885
2886 if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
2887 if (!acqi) return STATUS_INVALID_PARAMETER;
2888
2889 if (acqi->ulAssemblyIndex >= actctx->num_assemblies)
2890 return STATUS_INVALID_PARAMETER;
2891 assembly = &actctx->assemblies[acqi->ulAssemblyIndex];
2892
2893 if (acqi->ulFileIndexInAssembly >= assembly->num_dlls)
2894 return STATUS_INVALID_PARAMETER;
2895 dll = &assembly->dlls[acqi->ulFileIndexInAssembly];
2896
2897 if (dll->name) dll_len = strlenW(dll->name) + 1;
2898 len = sizeof(*afdi) + dll_len * sizeof(WCHAR);
2899
2900 if (!buffer || bufsize < len)
2901 {
2902 if (retlen) *retlen = len;
2903 return STATUS_BUFFER_TOO_SMALL;
2904 }
2905 if (retlen) *retlen = 0; /* yes that's what native does !! */
2906 afdi->ulFlags = ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION;
2907 afdi->ulFilenameLength = dll_len ? (DWORD)(dll_len - 1) * sizeof(WCHAR) : 0;
2908 afdi->ulPathLength = 0; /* FIXME */
2909 ptr = (LPWSTR)(afdi + 1);
2910 if (dll_len)
2911 {
2912 afdi->lpFileName = ptr;
2913 memcpy( ptr, dll->name, dll_len * sizeof(WCHAR) );
2914 } else afdi->lpFileName = NULL;
2915 afdi->lpFilePath = NULL; /* FIXME */
2916 }
2917 break;
2918
2919 default:
2920 DPRINT( "class %u not implemented\n", class );
2921 return STATUS_NOT_IMPLEMENTED;
2922 }
2923 return STATUS_SUCCESS;
2924 }
2925
2926 NTSTATUS
2927 NTAPI
2928 RtlQueryInformationActiveActivationContext(ULONG ulInfoClass,
2929 PVOID pvBuffer,
2930 SIZE_T cbBuffer OPTIONAL,
2931 SIZE_T *pcbWrittenOrRequired OPTIONAL)
2932 {
2933 return RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT,
2934 NULL,
2935 NULL,
2936 ulInfoClass,
2937 pvBuffer,
2938 cbBuffer,
2939 pcbWrittenOrRequired);
2940 }
2941
2942 #define FIND_ACTCTX_RETURN_FLAGS 0x00000002
2943 #define FIND_ACTCTX_RETURN_ASSEMBLY_METADATA 0x00000004
2944 #define FIND_ACTCTX_VALID_MASK (FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX | FIND_ACTCTX_RETURN_FLAGS | FIND_ACTCTX_RETURN_ASSEMBLY_METADATA)
2945
2946 NTSTATUS
2947 NTAPI
2948 RtlpFindActivationContextSection_CheckParameters( ULONG flags, const GUID *guid, ULONG section_kind,
2949 UNICODE_STRING *section_name, PACTCTX_SECTION_KEYED_DATA data )
2950 {
2951 /* Check general parameter combinations */
2952 if (!section_name ||
2953 (flags & ~FIND_ACTCTX_VALID_MASK) ||
2954 ((flags & FIND_ACTCTX_VALID_MASK) && !data) ||
2955 (data && data->cbSize < offsetof(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex)))
2956 {
2957 DPRINT1("invalid parameter\n");
2958 return STATUS_INVALID_PARAMETER;
2959 }
2960
2961 /* TODO */
2962 if (flags & FIND_ACTCTX_RETURN_FLAGS ||
2963 flags & FIND_ACTCTX_RETURN_ASSEMBLY_METADATA)
2964 {
2965 DPRINT1("unknown flags %08x\n", flags);
2966 return STATUS_INVALID_PARAMETER;
2967 }
2968
2969 return STATUS_SUCCESS;
2970 }
2971
2972 NTSTATUS
2973 NTAPI
2974 RtlFindActivationContextSectionString( ULONG flags, const GUID *guid, ULONG section_kind,
2975 UNICODE_STRING *section_name, PVOID ptr )
2976 {
2977 PACTCTX_SECTION_KEYED_DATA data = ptr;
2978 NTSTATUS status;
2979
2980 status = RtlpFindActivationContextSection_CheckParameters(flags, guid, section_kind, section_name, data);
2981 if (!NT_SUCCESS(status)) return status;
2982
2983 status = STATUS_SXS_KEY_NOT_FOUND;
2984
2985 /* if there is no data, but params are valid,
2986 we return that sxs key is not found to be at least somehow compatible */
2987 if (!data) return status;
2988
2989 ASSERT(NtCurrentTeb());
2990 ASSERT(NtCurrentTeb()->ActivationContextStackPointer);
2991
2992 if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
2993 {
2994 ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext);
2995 if (actctx) status = find_string( actctx, section_kind, section_name, flags, data );
2996 }
2997
2998 if (status != STATUS_SUCCESS)
2999 status = find_string( process_actctx, section_kind, section_name, flags, data );
3000
3001 return status;
3002 }
3003
3004 NTSTATUS WINAPI RtlFindActivationContextSectionGuid( ULONG flags, const GUID *extguid, ULONG section_kind,
3005 const GUID *guid, void *ptr )
3006 {
3007 ACTCTX_SECTION_KEYED_DATA *data = ptr;
3008 NTSTATUS status = STATUS_SXS_KEY_NOT_FOUND;
3009
3010 if (extguid)
3011 {
3012 DPRINT1("expected extguid == NULL\n");
3013 return STATUS_INVALID_PARAMETER;
3014 }
3015
3016 if (flags & ~FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
3017 {
3018 DPRINT1("unknown flags %08x\n", flags);
3019 return STATUS_INVALID_PARAMETER;
3020 }
3021
3022 if (!data || data->cbSize < FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) || !guid)
3023 return STATUS_INVALID_PARAMETER;
3024
3025 if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
3026 {
3027 ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext);
3028 if (actctx) status = find_guid( actctx, section_kind, guid, flags, data );
3029 }
3030
3031 if (status != STATUS_SUCCESS)
3032 status = find_guid( process_actctx, section_kind, guid, flags, data );
3033
3034 return status;
3035 }
3036
3037 /* Stubs */
3038
3039 NTSTATUS
3040 NTAPI
3041 RtlAllocateActivationContextStack(IN PACTIVATION_CONTEXT_STACK *Stack)
3042 {
3043 PACTIVATION_CONTEXT_STACK ContextStack;
3044
3045 /* Check if it's already allocated */
3046 if (*Stack) return STATUS_SUCCESS;
3047
3048 /* Allocate space for the context stack */
3049 ContextStack = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACTIVATION_CONTEXT_STACK));
3050 if (!ContextStack)
3051 {
3052 return STATUS_NO_MEMORY;
3053 }
3054
3055 /* Initialize the context stack */
3056 ContextStack->Flags = 0;
3057 ContextStack->ActiveFrame = NULL;
3058 InitializeListHead(&ContextStack->FrameListCache);
3059 ContextStack->NextCookieSequenceNumber = 1;
3060 ContextStack->StackId = 1; //TODO: Timer-based
3061
3062 *Stack = ContextStack;
3063
3064 return STATUS_SUCCESS;
3065 }
3066
3067 PRTL_ACTIVATION_CONTEXT_STACK_FRAME
3068 FASTCALL
3069 RtlActivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame,
3070 IN PVOID Context)
3071 {
3072 #if NEW_NTDLL_LOADER
3073 RTL_ACTIVATION_CONTEXT_STACK_FRAME *ActiveFrame;
3074
3075 /* Get the curren active frame */
3076 ActiveFrame = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
3077
3078 DPRINT1("ActiveFrame %p, &Frame->Frame %p, Context %p\n", ActiveFrame, &Frame->Frame, Context);
3079
3080 /* Actually activate it */
3081 Frame->Frame.Previous = ActiveFrame;
3082 Frame->Frame.ActivationContext = Context;
3083 Frame->Frame.Flags = 0;
3084
3085 /* Check if we can activate this context */
3086 if ((ActiveFrame && (ActiveFrame->ActivationContext != Context)) ||
3087 Context)
3088 {
3089 /* Set new active frame */
3090 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = &Frame->Frame;
3091 return &Frame->Frame;
3092 }
3093
3094 /* We can get here only one way: it was already activated */
3095 DPRINT1("Trying to activate improper activation context\n");
3096
3097 /* Activate only if we are allowing multiple activation */
3098 if (!RtlpNotAllowingMultipleActivation)
3099 {
3100 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = &Frame->Frame;
3101 }
3102 else
3103 {
3104 /* Set flag */
3105 Frame->Frame.Flags = 0x30;
3106 }
3107
3108 /* Return pointer to the activation frame */
3109 return &Frame->Frame;
3110 #else
3111
3112 RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame = &Frame->Frame;
3113
3114 frame->Previous = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
3115 frame->ActivationContext = Context;
3116 frame->Flags = 0;
3117
3118 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = frame;
3119
3120 return STATUS_SUCCESS;
3121 #endif
3122 }
3123
3124 PRTL_ACTIVATION_CONTEXT_STACK_FRAME
3125 FASTCALL
3126 RtlDeactivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame)
3127 {
3128 RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
3129 //RTL_ACTIVATION_CONTEXT_STACK_FRAME *top;
3130
3131 /* find the right frame */
3132 //top = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
3133 frame = &Frame->Frame;
3134
3135 if (!frame)
3136 {
3137 DPRINT1("No top frame!\n");
3138 RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION );
3139 }
3140
3141 /* pop everything up to and including frame */
3142 NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = frame->Previous;
3143
3144 return frame;
3145 }
3146
3147
3148 NTSTATUS
3149 NTAPI
3150 RtlZombifyActivationContext(PVOID Context)
3151 {
3152 UNIMPLEMENTED;
3153
3154 if (Context == ACTCTX_FAKE_HANDLE)
3155 return STATUS_SUCCESS;
3156
3157 return STATUS_NOT_IMPLEMENTED;
3158 }
3159