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