xref: /reactos/sdk/lib/rtl/actctx.c (revision 019f21ee)
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.ginsberg@reactos.org)
12  *                  Samuel Serapi�n
13  */
14 
15 /* Based on Wine 3.2-37c98396 */
16 
17 #include <rtl.h>
18 #include <ntstrsafe.h>
19 #include <compat_undoc.h>
20 
21 #define NDEBUG
22 #include <debug.h>
23 
24 #include <wine/unicode.h>
25 
26 BOOLEAN RtlpNotAllowingMultipleActivation;
27 
28 #define ACTCTX_FLAGS_ALL (\
29  ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID |\
30  ACTCTX_FLAG_LANGID_VALID |\
31  ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID |\
32  ACTCTX_FLAG_RESOURCE_NAME_VALID |\
33  ACTCTX_FLAG_SET_PROCESS_DEFAULT |\
34  ACTCTX_FLAG_APPLICATION_NAME_VALID |\
35  ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF |\
36  ACTCTX_FLAG_HMODULE_VALID )
37 
38 #define STRSECTION_MAGIC   0x64487353 /* dHsS */
39 #define GUIDSECTION_MAGIC  0x64487347 /* dHsG */
40 
41 #define ACTCTX_MAGIC_MARKER (PVOID)'gMcA'
42 
43 #define ACTCTX_FAKE_HANDLE ((HANDLE) 0xf00baa)
44 #define ACTCTX_FAKE_COOKIE ((ULONG_PTR) 0xf00bad)
45 
46 
47 
48 typedef struct
49 {
50     const WCHAR        *ptr;
51     unsigned int        len;
52 } xmlstr_t;
53 
54 typedef struct
55 {
56     const WCHAR        *ptr;
57     const WCHAR        *end;
58 } xmlbuf_t;
59 
60 struct file_info
61 {
62     ULONG               type;
63     WCHAR              *info;
64 };
65 
66 struct assembly_version
67 {
68     USHORT              major;
69     USHORT              minor;
70     USHORT              build;
71     USHORT              revision;
72 };
73 
74 struct assembly_identity
75 {
76     WCHAR                *name;
77     WCHAR                *arch;
78     WCHAR                *public_key;
79     WCHAR                *language;
80     WCHAR                *type;
81     struct assembly_version version;
82     BOOL                  optional;
83     BOOL                  delayed;
84 };
85 
86 struct strsection_header
87 {
88     DWORD magic;
89     ULONG size;
90     DWORD unk1[3];
91     ULONG count;
92     ULONG index_offset;
93     DWORD unk2[2];
94     ULONG global_offset;
95     ULONG global_len;
96 };
97 
98 struct string_index
99 {
100     ULONG hash;        /* key string hash */
101     ULONG name_offset;
102     ULONG name_len;
103     ULONG data_offset; /* redirect data offset */
104     ULONG data_len;
105     ULONG rosterindex;
106 };
107 
108 struct guidsection_header
109 {
110     DWORD magic;
111     ULONG size;
112     DWORD unk[3];
113     ULONG count;
114     ULONG index_offset;
115     DWORD unk2;
116     ULONG names_offset;
117     ULONG names_len;
118 };
119 
120 struct guid_index
121 {
122     GUID  guid;
123     ULONG data_offset;
124     ULONG data_len;
125     ULONG rosterindex;
126 };
127 
128 struct wndclass_redirect_data
129 {
130     ULONG size;
131     DWORD res;
132     ULONG name_len;
133     ULONG name_offset;  /* versioned name offset */
134     ULONG module_len;
135     ULONG module_offset;/* container name offset */
136 };
137 
138 struct dllredirect_data
139 {
140     ULONG size;
141     ULONG unk;
142     DWORD res[3];
143 };
144 
145 struct tlibredirect_data
146 {
147     ULONG  size;
148     DWORD  res;
149     ULONG  name_len;
150     ULONG  name_offset;
151     LANGID langid;
152     WORD   flags;
153     ULONG  help_len;
154     ULONG  help_offset;
155     WORD   major_version;
156     WORD   minor_version;
157 };
158 
159 enum comclass_threadingmodel
160 {
161     ThreadingModel_Apartment = 1,
162     ThreadingModel_Free      = 2,
163     ThreadingModel_No        = 3,
164     ThreadingModel_Both      = 4,
165     ThreadingModel_Neutral   = 5
166 };
167 
168 enum comclass_miscfields
169 {
170     MiscStatus          = 1,
171     MiscStatusIcon      = 2,
172     MiscStatusContent   = 4,
173     MiscStatusThumbnail = 8,
174     MiscStatusDocPrint  = 16
175 };
176 
177 struct comclassredirect_data
178 {
179     ULONG size;
180     BYTE  res;
181     BYTE  miscmask;
182     BYTE  res1[2];
183     DWORD model;
184     GUID  clsid;
185     GUID  alias;
186     GUID  clsid2;
187     GUID  tlbid;
188     ULONG name_len;
189     ULONG name_offset;
190     ULONG progid_len;
191     ULONG progid_offset;
192     ULONG clrdata_len;
193     ULONG clrdata_offset;
194     DWORD miscstatus;
195     DWORD miscstatuscontent;
196     DWORD miscstatusthumbnail;
197     DWORD miscstatusicon;
198     DWORD miscstatusdocprint;
199 };
200 
201 enum ifaceps_mask
202 {
203     NumMethods = 1,
204     BaseIface  = 2
205 };
206 
207 struct ifacepsredirect_data
208 {
209     ULONG size;
210     DWORD mask;
211     GUID  iid;
212     ULONG nummethods;
213     GUID  tlbid;
214     GUID  base;
215     ULONG name_len;
216     ULONG name_offset;
217 };
218 
219 struct clrsurrogate_data
220 {
221     ULONG size;
222     DWORD res;
223     GUID  clsid;
224     ULONG version_offset;
225     ULONG version_len;
226     ULONG name_offset;
227     ULONG name_len;
228 };
229 
230 struct clrclass_data
231 {
232     ULONG size;
233     DWORD res[2];
234     ULONG module_len;
235     ULONG module_offset;
236     ULONG name_len;
237     ULONG name_offset;
238     ULONG version_len;
239     ULONG version_offset;
240     DWORD res2[2];
241 };
242 
243 struct progidredirect_data
244 {
245     ULONG size;
246     DWORD reserved;
247     ULONG clsid_offset;
248 };
249 
250 /*
251 
252    Sections structure.
253 
254    Sections are accessible by string or guid key, that defines two types of sections.
255    All sections of each type have same magic value and header structure, index
256    data could be of two possible types too. So every string based section uses
257    the same index format, same applies to guid sections - they share same guid index
258    format.
259 
260    - window class redirection section is a plain buffer with following format:
261 
262    <section header>
263    <index[]>
264    <data[]> --- <original name>
265                 <redirect data>
266                 <versioned name>
267                 <module name>
268 
269    Header is fixed length structure - struct strsection_header,
270    contains redirected classes count;
271 
272    Index is an array of fixed length index records, each record is
273    struct string_index.
274 
275    All strings in data itself are WCHAR, null terminated, 4-bytes aligned.
276 
277    Versioned name offset is relative to redirect data structure (struct wndclass_redirect_data),
278    others are relative to section itself.
279 
280    - dll redirect section format:
281 
282    <section header>
283    <index[]>
284    <data[]> --- <dll name>
285                 <data>
286 
287    This section doesn't seem to carry any payload data except dll names.
288 
289    - typelib section format:
290 
291    <section header>
292    <module names[]>
293    <index[]>
294    <data[]> --- <data>
295                 <helpstring>
296 
297    Header is fixed length, index is an array of fixed length 'struct guid_index'.
298    All strings are WCHAR, null terminated, 4-bytes aligned. Module names part is
299    4-bytes aligned as a whole.
300 
301    Module name offsets are relative to section, helpstring offset is relative to data
302    structure itself.
303 
304    - comclass section format:
305 
306    <section header>
307    <module names[]>
308    <index[]>
309    <data[]> --- <data>   --- <data>
310                 <progid>     <clrdata>
311                              <name>
312                              <version>
313                              <progid>
314 
315    This section uses two index records per comclass, one entry contains original guid
316    as specified by context, another one has a generated guid. Index and strings handling
317    is similar to typelib sections.
318 
319    For CLR classes additional data is stored after main COM class data, it contains
320    class name and runtime version string, see 'struct clrclass_data'.
321 
322    Module name offsets are relative to section, progid offset is relative to data
323    structure itself.
324 
325    - COM interface section format:
326 
327    <section header>
328    <index[]>
329    <data[]> --- <data>
330                 <name>
331 
332    Interface section contains data for proxy/stubs and external proxy/stubs. External
333    ones are defined at assembly level, so this section has no module information.
334    All records are indexed with 'iid' value from manifest. There an exception for
335    external variants - if 'proxyStubClsid32' is specified, it's stored as iid in
336    redirect data, but index is still 'iid' from manifest.
337 
338    Interface name offset is relative to data structure itself.
339 
340    - CLR surrogates section format:
341 
342    <section header>
343    <index[]>
344    <data[]> --- <data>
345                 <name>
346                 <version>
347 
348     There's nothing special about this section, same way to store strings is used,
349     no modules part as it belongs to assembly level, not a file.
350 
351    - ProgID section format:
352 
353    <section header>
354    <guids[]>
355    <index[]>
356    <data[]> --- <progid>
357                 <data>
358 
359    This sections uses generated alias guids from COM server section. This way
360    ProgID -> CLSID mapping returns generated guid, not the real one. ProgID string
361    is stored too, aligned.
362 */
363 
364 struct progids
365 {
366     WCHAR        **progids;
367     unsigned int   num;
368     unsigned int   allocated;
369 };
370 
371 struct entity
372 {
373     DWORD kind;
374     union
375     {
376         struct
377         {
378             WCHAR *tlbid;
379             WCHAR *helpdir;
380             WORD   flags;
381             WORD   major;
382             WORD   minor;
383 	} typelib;
384         struct
385         {
386             WCHAR *clsid;
387             WCHAR *tlbid;
388             WCHAR *progid;
389             WCHAR *name;    /* clrClass: class name */
390             WCHAR *version; /* clrClass: CLR runtime version */
391             DWORD  model;
392             DWORD  miscstatus;
393             DWORD  miscstatuscontent;
394             DWORD  miscstatusthumbnail;
395             DWORD  miscstatusicon;
396             DWORD  miscstatusdocprint;
397             struct progids progids;
398 	} comclass;
399 	struct {
400             WCHAR *iid;
401             WCHAR *base;
402             WCHAR *tlib;
403             WCHAR *name;
404             WCHAR *ps32; /* only stored for 'comInterfaceExternalProxyStub' */
405             DWORD  mask;
406             ULONG  nummethods;
407 	} ifaceps;
408         struct
409         {
410             WCHAR *name;
411             BOOL   versioned;
412         } class;
413         struct
414         {
415             WCHAR *name;
416             WCHAR *clsid;
417             WCHAR *version;
418         } clrsurrogate;
419     } u;
420 };
421 
422 struct entity_array
423 {
424     struct entity        *base;
425     unsigned int          num;
426     unsigned int          allocated;
427 };
428 
429 struct dll_redirect
430 {
431     WCHAR                *name;
432     WCHAR                *hash;
433     struct entity_array   entities;
434 };
435 
436 enum assembly_type
437 {
438     APPLICATION_MANIFEST,
439     ASSEMBLY_MANIFEST,
440     ASSEMBLY_SHARED_MANIFEST,
441 };
442 
443 struct assembly
444 {
445     enum assembly_type             type;
446     struct assembly_identity       id;
447     struct file_info               manifest;
448     WCHAR                         *directory;
449     BOOL                           no_inherit;
450     struct dll_redirect           *dlls;
451     unsigned int                   num_dlls;
452     unsigned int                   allocated_dlls;
453     struct entity_array            entities;
454     COMPATIBILITY_CONTEXT_ELEMENT *compat_contexts;
455     ULONG                          num_compat_contexts;
456     ACTCTX_REQUESTED_RUN_LEVEL     run_level;
457     ULONG                          ui_access;
458 };
459 
460 enum context_sections
461 {
462     WINDOWCLASS_SECTION    = 1,
463     DLLREDIRECT_SECTION    = 2,
464     TLIBREDIRECT_SECTION   = 4,
465     SERVERREDIRECT_SECTION = 8,
466     IFACEREDIRECT_SECTION  = 16,
467     CLRSURROGATES_SECTION  = 32,
468     PROGIDREDIRECT_SECTION = 64
469 };
470 
471 typedef struct _ASSEMBLY_STORAGE_MAP_ENTRY
472 {
473     ULONG Flags;
474     UNICODE_STRING DosPath;
475     HANDLE Handle;
476 } ASSEMBLY_STORAGE_MAP_ENTRY, *PASSEMBLY_STORAGE_MAP_ENTRY;
477 
478 typedef struct _ASSEMBLY_STORAGE_MAP
479 {
480     ULONG Flags;
481     ULONG AssemblyCount;
482     PASSEMBLY_STORAGE_MAP_ENTRY *AssemblyArray;
483 } ASSEMBLY_STORAGE_MAP, *PASSEMBLY_STORAGE_MAP;
484 
485 typedef struct _ACTIVATION_CONTEXT
486 {
487     LONG RefCount;
488     ULONG Flags;
489     LIST_ENTRY Links;
490     PACTIVATION_CONTEXT_DATA ActivationContextData;
491     PVOID NotificationRoutine;
492     PVOID NotificationContext;
493     ULONG SentNotifications[8];
494     ULONG DisabledNotifications[8];
495     ASSEMBLY_STORAGE_MAP StorageMap;
496     PASSEMBLY_STORAGE_MAP_ENTRY InlineStorageMapEntries;
497     ULONG StackTraceIndex;
498     PVOID StackTraces[4][4];
499     struct file_info config;
500     struct file_info appdir;
501     struct assembly *assemblies;
502     unsigned int num_assemblies;
503     unsigned int allocated_assemblies;
504     /* section data */
505     DWORD sections;
506     struct strsection_header *wndclass_section;
507     struct strsection_header *dllredirect_section;
508     struct strsection_header *progid_section;
509     struct guidsection_header *tlib_section;
510     struct guidsection_header *comserver_section;
511     struct guidsection_header *ifaceps_section;
512     struct guidsection_header *clrsurrogate_section;
513 } ACTIVATION_CONTEXT, *PIACTIVATION_CONTEXT;
514 
515 struct actctx_loader
516 {
517     ACTIVATION_CONTEXT       *actctx;
518     struct assembly_identity *dependencies;
519     unsigned int              num_dependencies;
520     unsigned int              allocated_dependencies;
521 };
522 
523 static const WCHAR asmv1W[] = {'a','s','m','v','1',':',0};
524 static const WCHAR asmv2W[] = {'a','s','m','v','2',':',0};
525 
526 typedef struct _ACTIVATION_CONTEXT_WRAPPED
527 {
528     PVOID MagicMarker;
529     ACTIVATION_CONTEXT ActivationContext;
530 } ACTIVATION_CONTEXT_WRAPPED, *PACTIVATION_CONTEXT_WRAPPED;
531 
532 VOID
533 NTAPI
534 RtlpSxsBreakOnInvalidMarker(IN PACTIVATION_CONTEXT ActCtx,
535                             IN ULONG FailureCode)
536 {
537     EXCEPTION_RECORD ExceptionRecord;
538 
539     /* Fatal SxS exception header */
540     ExceptionRecord.ExceptionRecord = NULL;
541     ExceptionRecord.ExceptionCode = STATUS_SXS_CORRUPTION;
542     ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
543 
544     /* With SxS-specific information plus the context itself */
545     ExceptionRecord.ExceptionInformation[0] = 1;
546     ExceptionRecord.ExceptionInformation[1] = FailureCode;
547     ExceptionRecord.ExceptionInformation[2] = (ULONG_PTR)ActCtx;
548     ExceptionRecord.NumberParameters = 3;
549 
550     /* Raise it */
551     RtlRaiseException(&ExceptionRecord);
552 }
553 
554 FORCEINLINE
555 VOID
556 RtlpValidateActCtx(IN PACTIVATION_CONTEXT ActCtx)
557 {
558     PACTIVATION_CONTEXT_WRAPPED pActual;
559 
560     /* Get the caller-opaque header */
561     pActual = CONTAINING_RECORD(ActCtx,
562                                 ACTIVATION_CONTEXT_WRAPPED,
563                                 ActivationContext);
564 
565     /* Check if the header matches as expected */
566     if (pActual->MagicMarker != ACTCTX_MAGIC_MARKER)
567     {
568         /* Nope, print out a warning, assert, and then throw an exception */
569         DbgPrint("%s : Invalid activation context marker %p found in activation context %p\n"
570                  "     This means someone stepped on the allocation, or someone is using a\n"
571                  "     deallocated activation context\n",
572                  __FUNCTION__,
573                  pActual->MagicMarker,
574                  ActCtx);
575         ASSERT(pActual->MagicMarker == ACTCTX_MAGIC_MARKER);
576         RtlpSxsBreakOnInvalidMarker(ActCtx, 1);
577     }
578 }
579 
580 static const WCHAR assemblyW[] = {'a','s','s','e','m','b','l','y',0};
581 static const WCHAR assemblyIdentityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
582 static const WCHAR bindingRedirectW[] = {'b','i','n','d','i','n','g','R','e','d','i','r','e','c','t',0};
583 static const WCHAR clrClassW[] = {'c','l','r','C','l','a','s','s',0};
584 static const WCHAR clrSurrogateW[] = {'c','l','r','S','u','r','r','o','g','a','t','e',0};
585 static const WCHAR comClassW[] = {'c','o','m','C','l','a','s','s',0};
586 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};
587 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};
588 static const WCHAR dependencyW[] = {'d','e','p','e','n','d','e','n','c','y',0};
589 static const WCHAR dependentAssemblyW[] = {'d','e','p','e','n','d','e','n','t','A','s','s','e','m','b','l','y',0};
590 static const WCHAR descriptionW[] = {'d','e','s','c','r','i','p','t','i','o','n',0};
591 static const WCHAR fileW[] = {'f','i','l','e',0};
592 static const WCHAR hashW[] = {'h','a','s','h',0};
593 static const WCHAR noInheritW[] = {'n','o','I','n','h','e','r','i','t',0};
594 static const WCHAR noInheritableW[] = {'n','o','I','n','h','e','r','i','t','a','b','l','e',0};
595 static const WCHAR typelibW[] = {'t','y','p','e','l','i','b',0};
596 static const WCHAR windowClassW[] = {'w','i','n','d','o','w','C','l','a','s','s',0};
597 
598 static const WCHAR clsidW[] = {'c','l','s','i','d',0};
599 static const WCHAR hashalgW[] = {'h','a','s','h','a','l','g',0};
600 static const WCHAR helpdirW[] = {'h','e','l','p','d','i','r',0};
601 static const WCHAR iidW[] = {'i','i','d',0};
602 static const WCHAR languageW[] = {'l','a','n','g','u','a','g','e',0};
603 static const WCHAR manifestVersionW[] = {'m','a','n','i','f','e','s','t','V','e','r','s','i','o','n',0};
604 static const WCHAR g_nameW[] = {'n','a','m','e',0};
605 static const WCHAR neutralW[] = {'n','e','u','t','r','a','l',0};
606 static const WCHAR newVersionW[] = {'n','e','w','V','e','r','s','i','o','n',0};
607 static const WCHAR oldVersionW[] = {'o','l','d','V','e','r','s','i','o','n',0};
608 static const WCHAR optionalW[] = {'o','p','t','i','o','n','a','l',0};
609 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};
610 static const WCHAR progidW[] = {'p','r','o','g','i','d',0};
611 static const WCHAR publicKeyTokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
612 static const WCHAR threadingmodelW[] = {'t','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
613 static const WCHAR tlbidW[] = {'t','l','b','i','d',0};
614 static const WCHAR typeW[] = {'t','y','p','e',0};
615 static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
616 static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
617 static const WCHAR versionedW[] = {'v','e','r','s','i','o','n','e','d',0};
618 static const WCHAR yesW[] = {'y','e','s',0};
619 static const WCHAR noW[] = {'n','o',0};
620 static const WCHAR restrictedW[] = {'R','E','S','T','R','I','C','T','E','D',0};
621 static const WCHAR controlW[] = {'C','O','N','T','R','O','L',0};
622 static const WCHAR hiddenW[] = {'H','I','D','D','E','N',0};
623 static const WCHAR hasdiskimageW[] = {'H','A','S','D','I','S','K','I','M','A','G','E',0};
624 static const WCHAR flagsW[] = {'f','l','a','g','s',0};
625 static const WCHAR miscstatusW[] = {'m','i','s','c','S','t','a','t','u','s',0};
626 static const WCHAR miscstatusiconW[] = {'m','i','s','c','S','t','a','t','u','s','I','c','o','n',0};
627 static const WCHAR miscstatuscontentW[] = {'m','i','s','c','S','t','a','t','u','s','C','o','n','t','e','n','t',0};
628 static const WCHAR miscstatusthumbnailW[] = {'m','i','s','c','S','t','a','t','u','s','T','h','u','m','b','n','a','i','l',0};
629 static const WCHAR miscstatusdocprintW[] = {'m','i','s','c','S','t','a','t','u','s','D','o','c','P','r','i','n','t',0};
630 static const WCHAR baseInterfaceW[] = {'b','a','s','e','I','n','t','e','r','f','a','c','e',0};
631 static const WCHAR nummethodsW[] = {'n','u','m','M','e','t','h','o','d','s',0};
632 static const WCHAR proxyStubClsid32W[] = {'p','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
633 static const WCHAR runtimeVersionW[] = {'r','u','n','t','i','m','e','V','e','r','s','i','o','n',0};
634 static const WCHAR mscoreeW[] = {'M','S','C','O','R','E','E','.','D','L','L',0};
635 static const WCHAR mscoree2W[] = {'m','s','c','o','r','e','e','.','d','l','l',0};
636 
637 static const WCHAR activatewhenvisibleW[] = {'a','c','t','i','v','a','t','e','w','h','e','n','v','i','s','i','b','l','e',0};
638 static const WCHAR actslikebuttonW[] = {'a','c','t','s','l','i','k','e','b','u','t','t','o','n',0};
639 static const WCHAR actslikelabelW[] = {'a','c','t','s','l','i','k','e','l','a','b','e','l',0};
640 static const WCHAR alignableW[] = {'a','l','i','g','n','a','b','l','e',0};
641 static const WCHAR alwaysrunW[] = {'a','l','w','a','y','s','r','u','n',0};
642 static const WCHAR canlinkbyole1W[] = {'c','a','n','l','i','n','k','b','y','o','l','e','1',0};
643 static const WCHAR cantlinkinsideW[] = {'c','a','n','t','l','i','n','k','i','n','s','i','d','e',0};
644 static const WCHAR ignoreactivatewhenvisibleW[] = {'i','g','n','o','r','e','a','c','t','i','v','a','t','e','w','h','e','n','v','i','s','i','b','l','e',0};
645 static const WCHAR imemodeW[] = {'i','m','e','m','o','d','e',0};
646 static const WCHAR insertnotreplaceW[] = {'i','n','s','e','r','t','n','o','t','r','e','p','l','a','c','e',0};
647 static const WCHAR insideoutW[] = {'i','n','s','i','d','e','o','u','t',0};
648 static const WCHAR invisibleatruntimeW[] = {'i','n','v','i','s','i','b','l','e','a','t','r','u','n','t','i','m','e',0};
649 static const WCHAR islinkobjectW[] = {'i','s','l','i','n','k','o','b','j','e','c','t',0};
650 static const WCHAR nouiactivateW[] = {'n','o','u','i','a','c','t','i','v','a','t','e',0};
651 static const WCHAR onlyiconicW[] = {'o','n','l','y','i','c','o','n','i','c',0};
652 static const WCHAR recomposeonresizeW[] = {'r','e','c','o','m','p','o','s','e','o','n','r','e','s','i','z','e',0};
653 static const WCHAR renderingisdeviceindependentW[] = {'r','e','n','d','e','r','i','n','g','i','s','d','e','v','i','c','e','i','n','d','e','p','e','n','d','e','n','t',0};
654 static const WCHAR setclientsitefirstW[] = {'s','e','t','c','l','i','e','n','t','s','i','t','e','f','i','r','s','t',0};
655 static const WCHAR simpleframeW[] = {'s','i','m','p','l','e','f','r','a','m','e',0};
656 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
657 static const WCHAR supportsmultilevelundoW[] = {'s','u','p','p','o','r','t','s','m','u','l','t','i','l','e','v','e','l','u','n','d','o',0};
658 static const WCHAR wantstomenumergeW[] = {'w','a','n','t','s','t','o','m','e','n','u','m','e','r','g','e',0};
659 
660 static const WCHAR compatibilityW[] = {'c','o','m','p','a','t','i','b','i','l','i','t','y',0};
661 static const WCHAR compatibilityNSW[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','c','o','m','p','a','t','i','b','i','l','i','t','y','.','v','1',0};
662 static const WCHAR applicationW[] = {'a','p','p','l','i','c','a','t','i','o','n',0};
663 static const WCHAR supportedOSW[] = {'s','u','p','p','o','r','t','e','d','O','S',0};
664 static const WCHAR IdW[] = {'I','d',0};
665 static const WCHAR requestedExecutionLevelW[] = {'r','e','q','u','e','s','t','e','d','E','x','e','c','u','t','i','o','n','L','e','v','e','l',0};
666 static const WCHAR requestedPrivilegesW[] = {'r','e','q','u','e','s','t','e','d','P','r','i','v','i','l','e','g','e','s',0};
667 static const WCHAR securityW[] = {'s','e','c','u','r','i','t','y',0};
668 static const WCHAR trustInfoW[] = {'t','r','u','s','t','I','n','f','o',0};
669 
670 struct olemisc_entry
671 {
672     const WCHAR *name;
673     OLEMISC value;
674 };
675 
676 static const struct olemisc_entry olemisc_values[] =
677 {
678     { activatewhenvisibleW,          OLEMISC_ACTIVATEWHENVISIBLE },
679     { actslikebuttonW,               OLEMISC_ACTSLIKEBUTTON },
680     { actslikelabelW,                OLEMISC_ACTSLIKELABEL },
681     { alignableW,                    OLEMISC_ALIGNABLE },
682     { alwaysrunW,                    OLEMISC_ALWAYSRUN },
683     { canlinkbyole1W,                OLEMISC_CANLINKBYOLE1 },
684     { cantlinkinsideW,               OLEMISC_CANTLINKINSIDE },
685     { ignoreactivatewhenvisibleW,    OLEMISC_IGNOREACTIVATEWHENVISIBLE },
686     { imemodeW,                      OLEMISC_IMEMODE },
687     { insertnotreplaceW,             OLEMISC_INSERTNOTREPLACE },
688     { insideoutW,                    OLEMISC_INSIDEOUT },
689     { invisibleatruntimeW,           OLEMISC_INVISIBLEATRUNTIME },
690     { islinkobjectW,                 OLEMISC_ISLINKOBJECT },
691     { nouiactivateW,                 OLEMISC_NOUIACTIVATE },
692     { onlyiconicW,                   OLEMISC_ONLYICONIC },
693     { recomposeonresizeW,            OLEMISC_RECOMPOSEONRESIZE },
694     { renderingisdeviceindependentW, OLEMISC_RENDERINGISDEVICEINDEPENDENT },
695     { setclientsitefirstW,           OLEMISC_SETCLIENTSITEFIRST },
696     { simpleframeW,                  OLEMISC_SIMPLEFRAME },
697     { staticW,                       OLEMISC_STATIC },
698     { supportsmultilevelundoW,       OLEMISC_SUPPORTSMULTILEVELUNDO },
699     { wantstomenumergeW,             OLEMISC_WANTSTOMENUMERGE }
700 };
701 
702 static const WCHAR g_xmlW[] = {'?','x','m','l',0};
703 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};
704 static const WCHAR manifestv2W[] = {'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','2',0};
705 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};
706 
707 static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
708 static const WCHAR version_formatW[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
709 static const WCHAR wildcardW[] = {'*',0};
710 
711 static ACTIVATION_CONTEXT_WRAPPED system_actctx = { ACTCTX_MAGIC_MARKER, { 1 } };
712 static ACTIVATION_CONTEXT *process_actctx = &system_actctx.ActivationContext;
713 static ACTIVATION_CONTEXT *implicit_actctx = &system_actctx.ActivationContext;
714 
715 static WCHAR *strdupW(const WCHAR* str)
716 {
717     WCHAR*      ptr;
718 
719     if (!(ptr = RtlAllocateHeap(RtlGetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR))))
720         return NULL;
721     return strcpyW(ptr, str);
722 }
723 
724 static WCHAR *xmlstrdupW(const xmlstr_t* str)
725 {
726     WCHAR *strW;
727 
728     if ((strW = RtlAllocateHeap(RtlGetProcessHeap(), 0, (str->len + 1) * sizeof(WCHAR))))
729     {
730         memcpy( strW, str->ptr, str->len * sizeof(WCHAR) );
731         strW[str->len] = 0;
732     }
733     return strW;
734 }
735 
736 static inline BOOL xmlstr_cmp(const xmlstr_t* xmlstr, const WCHAR *str)
737 {
738     return !strncmpW(xmlstr->ptr, str, xmlstr->len) && !str[xmlstr->len];
739 }
740 
741 static inline BOOL xmlstr_cmpi(const xmlstr_t* xmlstr, const WCHAR *str)
742 {
743     return !strncmpiW(xmlstr->ptr, str, xmlstr->len) && !str[xmlstr->len];
744 }
745 
746 static inline BOOL xmlstr_cmp_end(const xmlstr_t* xmlstr, const WCHAR *str)
747 {
748     return (xmlstr->len && xmlstr->ptr[0] == '/' &&
749             !strncmpW(xmlstr->ptr + 1, str, xmlstr->len - 1) && !str[xmlstr->len - 1]);
750 }
751 
752 static inline BOOL xml_elem_cmp(const xmlstr_t *elem, const WCHAR *str, const WCHAR *namespace)
753 {
754     UINT len = strlenW( namespace );
755 
756     if (!strncmpW(elem->ptr, str, elem->len) && !str[elem->len]) return TRUE;
757     return (elem->len > len && !strncmpW(elem->ptr, namespace, len) &&
758             !strncmpW(elem->ptr + len, str, elem->len - len) && !str[elem->len - len]);
759 }
760 
761 static inline BOOL xml_elem_cmp_end(const xmlstr_t *elem, const WCHAR *str, const WCHAR *namespace)
762 {
763     if (elem->len && elem->ptr[0] == '/')
764     {
765         xmlstr_t elem_end;
766         elem_end.ptr = elem->ptr + 1;
767         elem_end.len = elem->len - 1;
768         return xml_elem_cmp( &elem_end, str, namespace );
769     }
770     return FALSE;
771 }
772 
773 static inline BOOL isxmlspace( WCHAR ch )
774 {
775     return (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t');
776 }
777 
778 static UNICODE_STRING xmlstr2unicode(const xmlstr_t *xmlstr)
779 {
780     UNICODE_STRING res;
781 
782     res.Buffer = (PWSTR)xmlstr->ptr;
783     res.Length = res.MaximumLength = (USHORT)xmlstr->len * sizeof(WCHAR);
784 
785     return res;
786 }
787 
788 static struct assembly *add_assembly(ACTIVATION_CONTEXT *actctx, enum assembly_type at)
789 {
790     struct assembly *assembly;
791 
792     DPRINT("add_assembly() actctx %p, activeframe ??\n", actctx);
793 
794     if (actctx->num_assemblies == actctx->allocated_assemblies)
795     {
796         void *ptr;
797         unsigned int new_count;
798         if (actctx->assemblies)
799         {
800             new_count = actctx->allocated_assemblies * 2;
801             ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
802                                      actctx->assemblies, new_count * sizeof(*assembly) );
803         }
804         else
805         {
806             new_count = 4;
807             ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*assembly) );
808         }
809         if (!ptr) return NULL;
810         actctx->assemblies = ptr;
811         actctx->allocated_assemblies = new_count;
812     }
813 
814     assembly = &actctx->assemblies[actctx->num_assemblies++];
815     assembly->type = at;
816     return assembly;
817 }
818 
819 static struct dll_redirect* add_dll_redirect(struct assembly* assembly)
820 {
821     DPRINT("add_dll_redirect() to assembly %p, num_dlls %d\n", assembly, assembly->allocated_dlls);
822 
823     if (assembly->num_dlls == assembly->allocated_dlls)
824     {
825         void *ptr;
826         unsigned int new_count;
827         if (assembly->dlls)
828         {
829             new_count = assembly->allocated_dlls * 2;
830             ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
831                                      assembly->dlls, new_count * sizeof(*assembly->dlls) );
832         }
833         else
834         {
835             new_count = 4;
836             ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*assembly->dlls) );
837         }
838         if (!ptr) return NULL;
839         assembly->dlls = ptr;
840         assembly->allocated_dlls = new_count;
841     }
842     return &assembly->dlls[assembly->num_dlls++];
843 }
844 
845 static PCOMPATIBILITY_CONTEXT_ELEMENT add_compat_context(struct assembly* assembly)
846 {
847     void *ptr;
848     if (assembly->num_compat_contexts)
849     {
850         unsigned int new_count = assembly->num_compat_contexts + 1;
851         ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
852                                  assembly->compat_contexts,
853                                  new_count * sizeof(COMPATIBILITY_CONTEXT_ELEMENT) );
854     }
855     else
856     {
857         ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMPATIBILITY_CONTEXT_ELEMENT) );
858     }
859     if (!ptr) return NULL;
860     assembly->compat_contexts = ptr;
861     return &assembly->compat_contexts[assembly->num_compat_contexts++];
862 }
863 
864 static void free_assembly_identity(struct assembly_identity *ai)
865 {
866     RtlFreeHeap( RtlGetProcessHeap(), 0, ai->name );
867     RtlFreeHeap( RtlGetProcessHeap(), 0, ai->arch );
868     RtlFreeHeap( RtlGetProcessHeap(), 0, ai->public_key );
869     RtlFreeHeap( RtlGetProcessHeap(), 0, ai->language );
870     RtlFreeHeap( RtlGetProcessHeap(), 0, ai->type );
871 }
872 
873 static struct entity* add_entity(struct entity_array *array, DWORD kind)
874 {
875     struct entity*      entity;
876 
877     if (array->num == array->allocated)
878     {
879         void *ptr;
880         unsigned int new_count;
881         if (array->base)
882         {
883             new_count = array->allocated * 2;
884             ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
885                                      array->base, new_count * sizeof(*array->base) );
886         }
887         else
888         {
889             new_count = 4;
890             ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*array->base) );
891         }
892         if (!ptr) return NULL;
893         array->base = ptr;
894         array->allocated = new_count;
895     }
896     entity = &array->base[array->num++];
897     entity->kind = kind;
898     return entity;
899 }
900 
901 static void free_entity_array(struct entity_array *array)
902 {
903     unsigned int i, j;
904     for (i = 0; i < array->num; i++)
905     {
906         struct entity *entity = &array->base[i];
907         switch (entity->kind)
908         {
909         case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
910             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.clsid);
911             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.tlbid);
912             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.progid);
913             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.name);
914             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.version);
915             for (j = 0; j < entity->u.comclass.progids.num; j++)
916                 RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.progids.progids[j]);
917             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.comclass.progids.progids);
918             break;
919         case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
920             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.ifaceps.iid);
921             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.ifaceps.base);
922             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.ifaceps.ps32);
923             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.ifaceps.name);
924             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.ifaceps.tlib);
925             break;
926         case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION:
927             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.typelib.tlbid);
928             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.typelib.helpdir);
929             break;
930         case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION:
931             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.class.name);
932             break;
933         case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES:
934             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrsurrogate.name);
935             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrsurrogate.clsid);
936             RtlFreeHeap(RtlGetProcessHeap(), 0, entity->u.clrsurrogate.version);
937             break;
938         default:
939             DPRINT1("Unknown entity kind %u\n", entity->kind);
940         }
941     }
942     RtlFreeHeap( RtlGetProcessHeap(), 0, array->base );
943 }
944 
945 static BOOL is_matching_string( const WCHAR *str1, const WCHAR *str2 )
946 {
947     if (!str1) return !str2;
948     return str2 && !strcmpiW( str1, str2 );
949 }
950 
951 static BOOL is_matching_identity( const struct assembly_identity *id1,
952                                   const struct assembly_identity *id2 )
953 {
954     if (!is_matching_string( id1->name, id2->name )) return FALSE;
955     if (!is_matching_string( id1->arch, id2->arch )) return FALSE;
956     if (!is_matching_string( id1->public_key, id2->public_key )) return FALSE;
957 
958     if (id1->language && id2->language && strcmpiW( id1->language, id2->language ))
959     {
960         if (strcmpW( wildcardW, id1->language ) && strcmpW( wildcardW, id2->language ))
961             return FALSE;
962     }
963     if (id1->version.major != id2->version.major) return FALSE;
964     if (id1->version.minor != id2->version.minor) return FALSE;
965     if (id1->version.build > id2->version.build) return FALSE;
966     if (id1->version.build == id2->version.build &&
967         id1->version.revision > id2->version.revision) return FALSE;
968     return TRUE;
969 }
970 
971 static BOOL add_dependent_assembly_id(struct actctx_loader* acl,
972                                       struct assembly_identity* ai)
973 {
974     unsigned int i;
975 
976     /* check if we already have that assembly */
977 
978     for (i = 0; i < acl->actctx->num_assemblies; i++)
979         if (is_matching_identity( ai, &acl->actctx->assemblies[i].id ))
980         {
981             DPRINT( "reusing existing assembly for %S arch %S version %u.%u.%u.%u\n",
982                    ai->name, ai->arch, ai->version.major, ai->version.minor,
983                    ai->version.build, ai->version.revision );
984             return TRUE;
985         }
986 
987     for (i = 0; i < acl->num_dependencies; i++)
988         if (is_matching_identity( ai, &acl->dependencies[i] ))
989         {
990             DPRINT( "reusing existing dependency for %S arch %S version %u.%u.%u.%u\n",
991                    ai->name, ai->arch, ai->version.major, ai->version.minor,
992                    ai->version.build, ai->version.revision );
993             return TRUE;
994         }
995 
996     if (acl->num_dependencies == acl->allocated_dependencies)
997     {
998         void *ptr;
999         unsigned int new_count;
1000         if (acl->dependencies)
1001         {
1002             new_count = acl->allocated_dependencies * 2;
1003             ptr = RtlReAllocateHeap(RtlGetProcessHeap(), 0, acl->dependencies,
1004                                     new_count * sizeof(acl->dependencies[0]));
1005         }
1006         else
1007         {
1008             new_count = 4;
1009             ptr = RtlAllocateHeap(RtlGetProcessHeap(), 0, new_count * sizeof(acl->dependencies[0]));
1010         }
1011         if (!ptr) return FALSE;
1012         acl->dependencies = ptr;
1013         acl->allocated_dependencies = new_count;
1014     }
1015     acl->dependencies[acl->num_dependencies++] = *ai;
1016 
1017     return TRUE;
1018 }
1019 
1020 static void free_depend_manifests(struct actctx_loader* acl)
1021 {
1022     unsigned int i;
1023     for (i = 0; i < acl->num_dependencies; i++)
1024         free_assembly_identity(&acl->dependencies[i]);
1025     RtlFreeHeap(RtlGetProcessHeap(), 0, acl->dependencies);
1026 }
1027 
1028 static WCHAR *build_assembly_dir(struct assembly_identity* ai)
1029 {
1030     static const WCHAR undW[] = {'_',0};
1031     static const WCHAR noneW[] = {'n','o','n','e',0};
1032     static const WCHAR mskeyW[] = {'d','e','a','d','b','e','e','f',0};
1033 
1034     const WCHAR *arch = ai->arch ? ai->arch : noneW;
1035     const WCHAR *key = ai->public_key ? ai->public_key : noneW;
1036     const WCHAR *lang = ai->language ? ai->language : noneW;
1037     const WCHAR *name = ai->name ? ai->name : noneW;
1038     SIZE_T size = (strlenW(arch) + 1 + strlenW(name) + 1 + strlenW(key) + 24 + 1 +
1039 		    strlenW(lang) + 1) * sizeof(WCHAR) + sizeof(mskeyW);
1040     WCHAR *ret;
1041 
1042     if (!(ret = RtlAllocateHeap( RtlGetProcessHeap(), 0, size ))) return NULL;
1043 
1044     strcpyW( ret, arch );
1045     strcatW( ret, undW );
1046     strcatW( ret, name );
1047     strcatW( ret, undW );
1048     strcatW( ret, key );
1049     strcatW( ret, undW );
1050     sprintfW( ret + strlenW(ret), version_formatW,
1051               ai->version.major, ai->version.minor, ai->version.build, ai->version.revision );
1052     strcatW( ret, undW );
1053     strcatW( ret, lang );
1054     strcatW( ret, undW );
1055     strcatW( ret, mskeyW );
1056     return ret;
1057 }
1058 
1059 static inline void append_string( WCHAR *buffer, const WCHAR *prefix, const WCHAR *str )
1060 {
1061     WCHAR *p = buffer;
1062 
1063     if (!str) return;
1064     strcatW( buffer, prefix );
1065     p += strlenW(p);
1066     *p++ = '"';
1067     strcpyW( p, str );
1068     p += strlenW(p);
1069     *p++ = '"';
1070     *p = 0;
1071 }
1072 
1073 static WCHAR *build_assembly_id( const struct assembly_identity *ai )
1074 {
1075     static const WCHAR archW[] =
1076         {',','p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e','=',0};
1077     static const WCHAR public_keyW[] =
1078         {',','p','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
1079     static const WCHAR typeW2[] =
1080         {',','t','y','p','e','=',0};
1081     static const WCHAR versionW2[] =
1082         {',','v','e','r','s','i','o','n','=',0};
1083 
1084     WCHAR version[64], *ret;
1085     SIZE_T size = 0;
1086 
1087     sprintfW( version, version_formatW,
1088               ai->version.major, ai->version.minor, ai->version.build, ai->version.revision );
1089     if (ai->name) size += strlenW(ai->name) * sizeof(WCHAR);
1090     if (ai->arch) size += strlenW(archW) + strlenW(ai->arch) + 2;
1091     if (ai->public_key) size += strlenW(public_keyW) + strlenW(ai->public_key) + 2;
1092     if (ai->type) size += strlenW(typeW2) + strlenW(ai->type) + 2;
1093     size += strlenW(versionW2) + strlenW(version) + 2;
1094 
1095     if (!(ret = RtlAllocateHeap( RtlGetProcessHeap(), 0, (size + 1) * sizeof(WCHAR) )))
1096         return NULL;
1097 
1098     if (ai->name) strcpyW( ret, ai->name );
1099     else *ret = 0;
1100     append_string( ret, archW, ai->arch );
1101     append_string( ret, public_keyW, ai->public_key );
1102     append_string( ret, typeW2, ai->type );
1103     append_string( ret, versionW2, version );
1104     return ret;
1105 }
1106 
1107 static ACTIVATION_CONTEXT *check_actctx( HANDLE h )
1108 {
1109     ACTIVATION_CONTEXT *ret = NULL, *actctx = h;
1110     PACTIVATION_CONTEXT_WRAPPED pActual;
1111 
1112     if (!h || h == INVALID_HANDLE_VALUE) return NULL;
1113     _SEH2_TRY
1114     {
1115         if (actctx)
1116         {
1117             pActual = CONTAINING_RECORD(actctx, ACTIVATION_CONTEXT_WRAPPED, ActivationContext);
1118             if (pActual->MagicMarker == ACTCTX_MAGIC_MARKER) ret = &pActual->ActivationContext;
1119         }
1120     }
1121     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1122     {
1123         DPRINT1("Invalid activation context handle!\n");
1124     }
1125     _SEH2_END;
1126     return ret;
1127 }
1128 
1129 static inline void actctx_addref( ACTIVATION_CONTEXT *actctx )
1130 {
1131     InterlockedExchangeAdd( &actctx->RefCount, 1 );
1132 }
1133 
1134 static void actctx_release( ACTIVATION_CONTEXT *actctx )
1135 {
1136     PACTIVATION_CONTEXT_WRAPPED pActual;
1137 
1138     if (InterlockedExchangeAdd(&actctx->RefCount, -1) == 1)
1139     {
1140         unsigned int i, j;
1141 
1142         for (i = 0; i < actctx->num_assemblies; i++)
1143         {
1144             struct assembly *assembly = &actctx->assemblies[i];
1145             for (j = 0; j < assembly->num_dlls; j++)
1146             {
1147                 struct dll_redirect *dll = &assembly->dlls[j];
1148                 free_entity_array( &dll->entities );
1149                 RtlFreeHeap( RtlGetProcessHeap(), 0, dll->name );
1150                 RtlFreeHeap( RtlGetProcessHeap(), 0, dll->hash );
1151             }
1152             RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->dlls );
1153             RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->manifest.info );
1154             RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->directory );
1155             RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->compat_contexts );
1156             free_entity_array( &assembly->entities );
1157             free_assembly_identity(&assembly->id);
1158         }
1159         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->config.info );
1160         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->appdir.info );
1161         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->assemblies );
1162         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->dllredirect_section );
1163         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->wndclass_section );
1164         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->tlib_section );
1165         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->comserver_section );
1166         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->ifaceps_section );
1167         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->clrsurrogate_section );
1168         RtlFreeHeap( RtlGetProcessHeap(), 0, actctx->progid_section );
1169 
1170         pActual = CONTAINING_RECORD(actctx, ACTIVATION_CONTEXT_WRAPPED, ActivationContext);
1171         pActual->MagicMarker = 0;
1172         RtlFreeHeap(RtlGetProcessHeap(), 0, pActual);
1173     }
1174 }
1175 
1176 static BOOL next_xml_attr(xmlbuf_t* xmlbuf, xmlstr_t* name, xmlstr_t* value,
1177                           BOOL* error, BOOL* end)
1178 {
1179     const WCHAR* ptr;
1180 
1181     *error = TRUE;
1182 
1183     while (xmlbuf->ptr < xmlbuf->end && isxmlspace(*xmlbuf->ptr))
1184         xmlbuf->ptr++;
1185 
1186     if (xmlbuf->ptr == xmlbuf->end) return FALSE;
1187 
1188     if (*xmlbuf->ptr == '/')
1189     {
1190         xmlbuf->ptr++;
1191         if (xmlbuf->ptr == xmlbuf->end || *xmlbuf->ptr != '>')
1192             return FALSE;
1193 
1194         xmlbuf->ptr++;
1195         *end = TRUE;
1196         *error = FALSE;
1197         return FALSE;
1198     }
1199 
1200     if (*xmlbuf->ptr == '>')
1201     {
1202         xmlbuf->ptr++;
1203         *error = FALSE;
1204         return FALSE;
1205     }
1206 
1207     ptr = xmlbuf->ptr;
1208     while (ptr < xmlbuf->end && *ptr != '=' && *ptr != '>' && !isxmlspace(*ptr)) ptr++;
1209 
1210     if (ptr == xmlbuf->end) return FALSE;
1211 
1212     name->ptr = xmlbuf->ptr;
1213     name->len = ptr-xmlbuf->ptr;
1214     xmlbuf->ptr = ptr;
1215 
1216     /* skip spaces before '=' */
1217     while (ptr < xmlbuf->end && *ptr != '=' && isxmlspace(*ptr)) ptr++;
1218     if (ptr == xmlbuf->end || *ptr != '=') return FALSE;
1219 
1220     /* skip '=' itself */
1221     ptr++;
1222     if (ptr == xmlbuf->end) return FALSE;
1223 
1224     /* skip spaces after '=' */
1225     while (ptr < xmlbuf->end && *ptr != '"' && *ptr != '\'' && isxmlspace(*ptr)) ptr++;
1226 
1227     if (ptr == xmlbuf->end || (*ptr != '"' && *ptr != '\'')) return FALSE;
1228 
1229     value->ptr = ++ptr;
1230     if (ptr == xmlbuf->end) return FALSE;
1231 
1232     ptr = memchrW(ptr, ptr[-1], xmlbuf->end - ptr);
1233     if (!ptr)
1234     {
1235         xmlbuf->ptr = xmlbuf->end;
1236         return FALSE;
1237     }
1238 
1239     value->len = ptr - value->ptr;
1240     xmlbuf->ptr = ptr + 1;
1241 
1242     if (xmlbuf->ptr == xmlbuf->end) return FALSE;
1243 
1244     *error = FALSE;
1245     return TRUE;
1246 }
1247 
1248 static BOOL next_xml_elem(xmlbuf_t* xmlbuf, xmlstr_t* elem)
1249 {
1250     const WCHAR* ptr;
1251 
1252     for (;;)
1253     {
1254         ptr = memchrW(xmlbuf->ptr, '<', xmlbuf->end - xmlbuf->ptr);
1255         if (!ptr)
1256         {
1257             xmlbuf->ptr = xmlbuf->end;
1258             return FALSE;
1259         }
1260         ptr++;
1261         if (ptr + 3 < xmlbuf->end && ptr[0] == '!' && ptr[1] == '-' && ptr[2] == '-') /* skip comment */
1262         {
1263             for (ptr += 3; ptr + 3 <= xmlbuf->end; ptr++)
1264                 if (ptr[0] == '-' && ptr[1] == '-' && ptr[2] == '>') break;
1265 
1266             if (ptr + 3 > xmlbuf->end)
1267             {
1268                 xmlbuf->ptr = xmlbuf->end;
1269                 return FALSE;
1270             }
1271             xmlbuf->ptr = ptr + 3;
1272         }
1273         else break;
1274     }
1275 
1276     xmlbuf->ptr = ptr;
1277     while (ptr < xmlbuf->end && !isxmlspace(*ptr) && *ptr != '>' && (*ptr != '/' || ptr == xmlbuf->ptr))
1278         ptr++;
1279 
1280     elem->ptr = xmlbuf->ptr;
1281     elem->len = ptr - xmlbuf->ptr;
1282     xmlbuf->ptr = ptr;
1283     return xmlbuf->ptr != xmlbuf->end;
1284 }
1285 
1286 static BOOL parse_xml_header(xmlbuf_t* xmlbuf)
1287 {
1288     /* FIXME: parse attributes */
1289     const WCHAR *ptr;
1290 
1291     for (ptr = xmlbuf->ptr; ptr < xmlbuf->end - 1; ptr++)
1292     {
1293         if (ptr[0] == '?' && ptr[1] == '>')
1294         {
1295             xmlbuf->ptr = ptr + 2;
1296             return TRUE;
1297         }
1298     }
1299     return FALSE;
1300 }
1301 
1302 static BOOL parse_text_content(xmlbuf_t* xmlbuf, xmlstr_t* content)
1303 {
1304     const WCHAR *ptr = memchrW(xmlbuf->ptr, '<', xmlbuf->end - xmlbuf->ptr);
1305 
1306     if (!ptr) return FALSE;
1307 
1308     content->ptr = xmlbuf->ptr;
1309     content->len = ptr - xmlbuf->ptr;
1310     xmlbuf->ptr = ptr;
1311 
1312     return TRUE;
1313 }
1314 
1315 static BOOL parse_version(const xmlstr_t *str, struct assembly_version *version)
1316 {
1317     unsigned int ver[4];
1318     unsigned int pos;
1319     const WCHAR *curr;
1320     UNICODE_STRING strU;
1321 
1322     /* major.minor.build.revision */
1323     ver[0] = ver[1] = ver[2] = ver[3] = pos = 0;
1324     for (curr = str->ptr; curr < str->ptr + str->len; curr++)
1325     {
1326         if (*curr >= '0' && *curr <= '9')
1327         {
1328             ver[pos] = ver[pos] * 10 + *curr - '0';
1329             if (ver[pos] >= 0x10000) goto error;
1330         }
1331         else if (*curr == '.')
1332         {
1333             if (++pos >= 4) goto error;
1334         }
1335         else goto error;
1336     }
1337     version->major = ver[0];
1338     version->minor = ver[1];
1339     version->build = ver[2];
1340     version->revision = ver[3];
1341     return TRUE;
1342 
1343 error:
1344     strU = xmlstr2unicode(str);
1345     DPRINT1( "Wrong version definition in manifest file (%wZ)\n", &strU );
1346     return FALSE;
1347 }
1348 
1349 static BOOL parse_expect_elem(xmlbuf_t* xmlbuf, const WCHAR* name, const WCHAR *namespace)
1350 {
1351     xmlstr_t    elem;
1352     UNICODE_STRING elemU;
1353     if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
1354     if (xml_elem_cmp(&elem, name, namespace)) return TRUE;
1355     elemU = xmlstr2unicode(&elem);
1356     DPRINT1( "unexpected element %wZ\n", &elemU );
1357     return FALSE;
1358 }
1359 
1360 static BOOL parse_expect_no_attr(xmlbuf_t* xmlbuf, BOOL* end)
1361 {
1362     xmlstr_t    attr_name, attr_value;
1363     UNICODE_STRING attr_nameU, attr_valueU;
1364     BOOL        error;
1365 
1366     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, end))
1367     {
1368         attr_nameU = xmlstr2unicode(&attr_name);
1369         attr_valueU = xmlstr2unicode(&attr_value);
1370         DPRINT1( "unexpected attr %wZ=%wZ\n", &attr_nameU,
1371              &attr_valueU);
1372     }
1373     return !error;
1374 }
1375 
1376 static BOOL parse_end_element(xmlbuf_t *xmlbuf)
1377 {
1378     BOOL end = FALSE;
1379     return parse_expect_no_attr(xmlbuf, &end) && !end;
1380 }
1381 
1382 static BOOL parse_expect_end_elem(xmlbuf_t *xmlbuf, const WCHAR *name, const WCHAR *namespace)
1383 {
1384     xmlstr_t    elem;
1385     UNICODE_STRING elemU;
1386     if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
1387     if (!xml_elem_cmp_end(&elem, name, namespace))
1388     {
1389         elemU = xmlstr2unicode(&elem);
1390         DPRINT1( "unexpected element %wZ\n", &elemU );
1391         return FALSE;
1392     }
1393     return parse_end_element(xmlbuf);
1394 }
1395 
1396 static BOOL parse_unknown_elem(xmlbuf_t *xmlbuf, const xmlstr_t *unknown_elem)
1397 {
1398     xmlstr_t attr_name, attr_value, elem;
1399     BOOL end = FALSE, error, ret = TRUE;
1400 
1401     while(next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end));
1402     if(error || end) return end;
1403 
1404     while(ret && (ret = next_xml_elem(xmlbuf, &elem)))
1405     {
1406         if(*elem.ptr == '/' && elem.len - 1 == unknown_elem->len &&
1407            !strncmpW(elem.ptr+1, unknown_elem->ptr, unknown_elem->len))
1408             break;
1409         else
1410             ret = parse_unknown_elem(xmlbuf, &elem);
1411     }
1412 
1413     return ret && parse_end_element(xmlbuf);
1414 }
1415 
1416 static BOOL parse_assembly_identity_elem(xmlbuf_t* xmlbuf, ACTIVATION_CONTEXT* actctx,
1417                                          struct assembly_identity* ai)
1418 {
1419     xmlstr_t    attr_name, attr_value;
1420     BOOL        end = FALSE, error;
1421     UNICODE_STRING  attr_valueU, attr_nameU;
1422 
1423     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1424     {
1425         if (xmlstr_cmp(&attr_name, g_nameW))
1426         {
1427             if (!(ai->name = xmlstrdupW(&attr_value))) return FALSE;
1428         }
1429         else if (xmlstr_cmp(&attr_name, typeW))
1430         {
1431             if (!(ai->type = xmlstrdupW(&attr_value))) return FALSE;
1432         }
1433         else if (xmlstr_cmp(&attr_name, versionW))
1434         {
1435             if (!parse_version(&attr_value, &ai->version)) return FALSE;
1436         }
1437         else if (xmlstr_cmp(&attr_name, processorArchitectureW))
1438         {
1439             if (!(ai->arch = xmlstrdupW(&attr_value))) return FALSE;
1440         }
1441         else if (xmlstr_cmp(&attr_name, publicKeyTokenW))
1442         {
1443             if (!(ai->public_key = xmlstrdupW(&attr_value))) return FALSE;
1444         }
1445         else if (xmlstr_cmp(&attr_name, languageW))
1446         {
1447             DPRINT("Unsupported yet language attribute (%.*S)\n",
1448                    attr_value.len, attr_value.ptr);
1449             if (!(ai->language = xmlstrdupW(&attr_value))) return FALSE;
1450         }
1451         else
1452         {
1453             attr_nameU = xmlstr2unicode(&attr_name);
1454             attr_valueU = xmlstr2unicode(&attr_value);
1455             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1456         }
1457     }
1458 
1459     if (error || end) return end;
1460     return parse_expect_end_elem(xmlbuf, assemblyIdentityW, asmv1W);
1461 }
1462 
1463 static enum comclass_threadingmodel parse_com_class_threadingmodel(xmlstr_t *value)
1464 {
1465     static const WCHAR apartW[] = {'A','p','a','r','t','m','e','n','t',0};
1466     static const WCHAR neutralW[] = {'N','e','u','t','r','a','l',0};
1467     static const WCHAR freeW[] = {'F','r','e','e',0};
1468     static const WCHAR bothW[] = {'B','o','t','h',0};
1469 
1470     if (value->len == 0) return ThreadingModel_No;
1471     if (xmlstr_cmp(value, apartW))
1472         return ThreadingModel_Apartment;
1473     else if (xmlstr_cmp(value, freeW))
1474         return ThreadingModel_Free;
1475     else if (xmlstr_cmp(value, bothW))
1476         return ThreadingModel_Both;
1477     else if (xmlstr_cmp(value, neutralW))
1478         return ThreadingModel_Neutral;
1479     else
1480         return ThreadingModel_No;
1481 };
1482 
1483 static OLEMISC get_olemisc_value(const WCHAR *str, int len)
1484 {
1485     int min, max;
1486 
1487     min = 0;
1488     max = sizeof(olemisc_values)/sizeof(struct olemisc_entry) - 1;
1489 
1490     while (min <= max)
1491     {
1492         int n, c;
1493 
1494         n = (min+max)/2;
1495 
1496         c = strncmpW(olemisc_values[n].name, str, len);
1497         if (!c && !olemisc_values[n].name[len])
1498             return olemisc_values[n].value;
1499 
1500         if (c >= 0)
1501             max = n-1;
1502         else
1503             min = n+1;
1504     }
1505 
1506     DPRINT1("unknown flag %S\n", str);
1507     return 0;
1508 }
1509 
1510 static DWORD parse_com_class_misc(const xmlstr_t *value)
1511 {
1512     const WCHAR *str = value->ptr, *start;
1513     DWORD flags = 0;
1514     int i = 0;
1515 
1516     /* it's comma separated list of flags */
1517     while (i < value->len)
1518     {
1519         start = str;
1520         while (*str != ',' && (i++ < value->len)) str++;
1521 
1522         flags |= get_olemisc_value(start, str-start);
1523 
1524         /* skip separator */
1525         str++;
1526         i++;
1527     }
1528 
1529     return flags;
1530 }
1531 
1532 static BOOL com_class_add_progid(const xmlstr_t *progid, struct entity *entity)
1533 {
1534     struct progids *progids = &entity->u.comclass.progids;
1535 
1536     if (progids->allocated == 0)
1537     {
1538         progids->allocated = 4;
1539         if (!(progids->progids = RtlAllocateHeap(RtlGetProcessHeap(), 0, progids->allocated * sizeof(WCHAR*)))) return FALSE;
1540     }
1541 
1542     if (progids->allocated == progids->num)
1543     {
1544         WCHAR **new_progids = RtlReAllocateHeap(RtlGetProcessHeap(), 0, progids->progids,
1545                                                 2 * progids->allocated * sizeof(WCHAR*));
1546         if (!new_progids) return FALSE;
1547         progids->allocated *= 2;
1548         progids->progids = new_progids;
1549     }
1550 
1551     if (!(progids->progids[progids->num] = xmlstrdupW(progid))) return FALSE;
1552     progids->num++;
1553 
1554     return TRUE;
1555 }
1556 
1557 static BOOL parse_com_class_progid(xmlbuf_t* xmlbuf, struct entity *entity)
1558 {
1559     xmlstr_t content;
1560     BOOL end = FALSE;
1561 
1562     if (!parse_expect_no_attr(xmlbuf, &end) || end || !parse_text_content(xmlbuf, &content))
1563         return FALSE;
1564 
1565     if (!com_class_add_progid(&content, entity)) return FALSE;
1566     return parse_expect_end_elem(xmlbuf, progidW, asmv1W);
1567 }
1568 
1569 static BOOL parse_com_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader *acl)
1570 {
1571     xmlstr_t elem, attr_name, attr_value;
1572     BOOL ret = TRUE, end = FALSE, error;
1573     struct entity*      entity;
1574     UNICODE_STRING  attr_valueU, attr_nameU;
1575 
1576     if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)))
1577         return FALSE;
1578 
1579     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1580     {
1581         if (xmlstr_cmp(&attr_name, clsidW))
1582         {
1583             if (!(entity->u.comclass.clsid = xmlstrdupW(&attr_value))) return FALSE;
1584         }
1585         else if (xmlstr_cmp(&attr_name, progidW))
1586         {
1587             if (!(entity->u.comclass.progid = xmlstrdupW(&attr_value))) return FALSE;
1588         }
1589         else if (xmlstr_cmp(&attr_name, tlbidW))
1590         {
1591             if (!(entity->u.comclass.tlbid = xmlstrdupW(&attr_value))) return FALSE;
1592         }
1593         else if (xmlstr_cmp(&attr_name, threadingmodelW))
1594         {
1595             entity->u.comclass.model = parse_com_class_threadingmodel(&attr_value);
1596         }
1597         else if (xmlstr_cmp(&attr_name, miscstatusW))
1598         {
1599             entity->u.comclass.miscstatus = parse_com_class_misc(&attr_value);
1600         }
1601         else if (xmlstr_cmp(&attr_name, miscstatuscontentW))
1602         {
1603             entity->u.comclass.miscstatuscontent = parse_com_class_misc(&attr_value);
1604         }
1605         else if (xmlstr_cmp(&attr_name, miscstatusthumbnailW))
1606         {
1607             entity->u.comclass.miscstatusthumbnail = parse_com_class_misc(&attr_value);
1608         }
1609         else if (xmlstr_cmp(&attr_name, miscstatusiconW))
1610         {
1611             entity->u.comclass.miscstatusicon = parse_com_class_misc(&attr_value);
1612         }
1613         else if (xmlstr_cmp(&attr_name, miscstatusdocprintW))
1614         {
1615             entity->u.comclass.miscstatusdocprint = parse_com_class_misc(&attr_value);
1616         }
1617         else if (xmlstr_cmp(&attr_name, descriptionW))
1618         {
1619             /* not stored */
1620         }
1621         else
1622         {
1623             attr_nameU = xmlstr2unicode(&attr_name);
1624             attr_valueU = xmlstr2unicode(&attr_value);
1625             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1626         }
1627     }
1628 
1629     if (error) return FALSE;
1630 
1631     acl->actctx->sections |= SERVERREDIRECT_SECTION;
1632     if (entity->u.comclass.progid)
1633         acl->actctx->sections |= PROGIDREDIRECT_SECTION;
1634 
1635     if (end) return TRUE;
1636 
1637     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
1638     {
1639         if (xmlstr_cmp_end(&elem, comClassW))
1640         {
1641             ret = parse_end_element(xmlbuf);
1642             break;
1643         }
1644         else if (xmlstr_cmp(&elem, progidW))
1645         {
1646             ret = parse_com_class_progid(xmlbuf, entity);
1647         }
1648         else
1649         {
1650             attr_nameU = xmlstr2unicode(&elem);
1651             DPRINT1("unknown elem %wZ\n", &attr_nameU);
1652             ret = parse_unknown_elem(xmlbuf, &elem);
1653         }
1654     }
1655 
1656     if (entity->u.comclass.progids.num)
1657         acl->actctx->sections |= PROGIDREDIRECT_SECTION;
1658 
1659     return ret;
1660 }
1661 
1662 static BOOL parse_nummethods(const xmlstr_t *str, struct entity *entity)
1663 {
1664     const WCHAR *curr;
1665     ULONG num = 0;
1666 
1667     for (curr = str->ptr; curr < str->ptr + str->len; curr++)
1668     {
1669         if (*curr >= '0' && *curr <= '9')
1670             num = num * 10 + *curr - '0';
1671         else
1672         {
1673             UNICODE_STRING strU = xmlstr2unicode(str);
1674             DPRINT1("wrong numeric value %wZ\n", &strU);
1675             return FALSE;
1676         }
1677     }
1678     entity->u.ifaceps.nummethods = num;
1679 
1680     return TRUE;
1681 }
1682 
1683 static BOOL parse_cominterface_proxy_stub_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader* acl)
1684 {
1685     xmlstr_t    attr_name, attr_value;
1686     BOOL        end = FALSE, error;
1687     struct entity*      entity;
1688     UNICODE_STRING  attr_valueU, attr_nameU;
1689 
1690     if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)))
1691         return FALSE;
1692 
1693     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1694     {
1695         if (xmlstr_cmp(&attr_name, iidW))
1696         {
1697             if (!(entity->u.ifaceps.iid = xmlstrdupW(&attr_value))) return FALSE;
1698         }
1699         else if (xmlstr_cmp(&attr_name, g_nameW))
1700         {
1701             if (!(entity->u.ifaceps.name = xmlstrdupW(&attr_value))) return FALSE;
1702         }
1703         else if (xmlstr_cmp(&attr_name, baseInterfaceW))
1704         {
1705             if (!(entity->u.ifaceps.base = xmlstrdupW(&attr_value))) return FALSE;
1706             entity->u.ifaceps.mask |= BaseIface;
1707         }
1708         else if (xmlstr_cmp(&attr_name, nummethodsW))
1709         {
1710             if (!(parse_nummethods(&attr_value, entity))) return FALSE;
1711             entity->u.ifaceps.mask |= NumMethods;
1712         }
1713         else if (xmlstr_cmp(&attr_name, tlbidW))
1714         {
1715             if (!(entity->u.ifaceps.tlib = xmlstrdupW(&attr_value))) return FALSE;
1716         }
1717         /* not used */
1718         else if (xmlstr_cmp(&attr_name, proxyStubClsid32W) || xmlstr_cmp(&attr_name, threadingmodelW))
1719         {
1720         }
1721         else
1722         {
1723             attr_nameU = xmlstr2unicode(&attr_name);
1724             attr_valueU = xmlstr2unicode(&attr_value);
1725             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1726         }
1727     }
1728 
1729     if (error) return FALSE;
1730     acl->actctx->sections |= IFACEREDIRECT_SECTION;
1731     if (end) return TRUE;
1732 
1733     return parse_expect_end_elem(xmlbuf, comInterfaceProxyStubW, asmv1W);
1734 }
1735 
1736 static BOOL parse_typelib_flags(const xmlstr_t *value, struct entity *entity)
1737 {
1738     WORD *flags = &entity->u.typelib.flags;
1739     const WCHAR *str = value->ptr, *start;
1740     int i = 0;
1741 
1742     *flags = 0;
1743 
1744     /* it's comma separated list of flags */
1745     while (i < value->len)
1746     {
1747         start = str;
1748         while (*str != ',' && (i++ < value->len)) str++;
1749 
1750         if (!strncmpiW(start, restrictedW, str-start))
1751             *flags |= LIBFLAG_FRESTRICTED;
1752         else if (!strncmpiW(start, controlW, str-start))
1753             *flags |= LIBFLAG_FCONTROL;
1754         else if (!strncmpiW(start, hiddenW, str-start))
1755             *flags |= LIBFLAG_FHIDDEN;
1756         else if (!strncmpiW(start, hasdiskimageW, str-start))
1757             *flags |= LIBFLAG_FHASDISKIMAGE;
1758         else
1759         {
1760             UNICODE_STRING valueU = xmlstr2unicode(value);
1761             DPRINT1("unknown flags value %wZ\n", &valueU);
1762             return FALSE;
1763         }
1764 
1765         /* skip separator */
1766         str++;
1767         i++;
1768     }
1769 
1770     return TRUE;
1771 }
1772 
1773 static BOOL parse_typelib_version(const xmlstr_t *str, struct entity *entity)
1774 {
1775     unsigned int ver[2];
1776     unsigned int pos;
1777     const WCHAR *curr;
1778     UNICODE_STRING strW;
1779 
1780     /* major.minor */
1781     ver[0] = ver[1] = pos = 0;
1782     for (curr = str->ptr; curr < str->ptr + str->len; curr++)
1783     {
1784         if (*curr >= '0' && *curr <= '9')
1785         {
1786             ver[pos] = ver[pos] * 10 + *curr - '0';
1787             if (ver[pos] >= 0x10000) goto error;
1788         }
1789         else if (*curr == '.')
1790         {
1791             if (++pos >= 2) goto error;
1792         }
1793         else goto error;
1794     }
1795     entity->u.typelib.major = ver[0];
1796     entity->u.typelib.minor = ver[1];
1797     return TRUE;
1798 
1799 error:
1800     strW = xmlstr2unicode(str);
1801     DPRINT1("FIXME: wrong typelib version value (%wZ)\n", &strW);
1802     return FALSE;
1803 }
1804 
1805 static BOOL parse_typelib_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader* acl)
1806 {
1807     xmlstr_t    attr_name, attr_value;
1808     BOOL        end = FALSE, error;
1809     struct entity*      entity;
1810     UNICODE_STRING  attr_valueU, attr_nameU;
1811 
1812     if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)))
1813         return FALSE;
1814 
1815     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1816     {
1817         if (xmlstr_cmp(&attr_name, tlbidW))
1818         {
1819             if (!(entity->u.typelib.tlbid = xmlstrdupW(&attr_value))) return FALSE;
1820         }
1821         else if (xmlstr_cmp(&attr_name, versionW))
1822         {
1823             if (!parse_typelib_version(&attr_value, entity)) return FALSE;
1824         }
1825         else if (xmlstr_cmp(&attr_name, helpdirW))
1826         {
1827             if (!(entity->u.typelib.helpdir = xmlstrdupW(&attr_value))) return FALSE;
1828         }
1829         else if (xmlstr_cmp(&attr_name, flagsW))
1830         {
1831             if (!parse_typelib_flags(&attr_value, entity)) return FALSE;
1832         }
1833         else
1834         {
1835             attr_nameU = xmlstr2unicode(&attr_name);
1836             attr_valueU = xmlstr2unicode(&attr_value);
1837             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1838         }
1839     }
1840 
1841     if (error) return FALSE;
1842 
1843     acl->actctx->sections |= TLIBREDIRECT_SECTION;
1844 
1845     if (end) return TRUE;
1846 
1847     return parse_expect_end_elem(xmlbuf, typelibW, asmv1W);
1848 }
1849 
1850 static inline int aligned_string_len(int len)
1851 {
1852     return (len + 3) & ~3;
1853 }
1854 
1855 static int get_assembly_version(struct assembly *assembly, WCHAR *ret)
1856 {
1857     static const WCHAR fmtW[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
1858     struct assembly_version *ver = &assembly->id.version;
1859     WCHAR buff[25];
1860 
1861     if (!ret) ret = buff;
1862     return sprintfW(ret, fmtW, ver->major, ver->minor, ver->build, ver->revision);
1863 }
1864 
1865 static BOOL parse_window_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader* acl)
1866 {
1867     xmlstr_t elem, content, attr_name, attr_value;
1868     BOOL end = FALSE, ret = TRUE, error;
1869     struct entity*      entity;
1870     UNICODE_STRING elemU, attr_nameU, attr_valueU;
1871 
1872     if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)))
1873         return FALSE;
1874 
1875     entity->u.class.versioned = TRUE;
1876     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1877     {
1878         if (xmlstr_cmp(&attr_name, versionedW))
1879         {
1880             if (xmlstr_cmpi(&attr_value, noW))
1881                 entity->u.class.versioned = FALSE;
1882             else if (!xmlstr_cmpi(&attr_value, yesW))
1883                return FALSE;
1884         }
1885         else
1886         {
1887             attr_nameU = xmlstr2unicode(&attr_name);
1888             attr_valueU = xmlstr2unicode(&attr_value);
1889             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1890         }
1891     }
1892 
1893     if (error || end) return end;
1894 
1895     if (!parse_text_content(xmlbuf, &content)) return FALSE;
1896 
1897     if (!(entity->u.class.name = xmlstrdupW(&content))) return FALSE;
1898 
1899     acl->actctx->sections |= WINDOWCLASS_SECTION;
1900 
1901     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
1902     {
1903         if (xmlstr_cmp_end(&elem, windowClassW))
1904         {
1905             ret = parse_end_element(xmlbuf);
1906             break;
1907         }
1908         else
1909         {
1910             elemU = xmlstr2unicode(&elem);
1911             DPRINT1("unknown elem %wZ\n", &elemU);
1912             ret = parse_unknown_elem(xmlbuf, &elem);
1913         }
1914     }
1915 
1916     return ret;
1917 }
1918 
1919 static BOOL parse_binding_redirect_elem(xmlbuf_t* xmlbuf)
1920 {
1921     xmlstr_t    attr_name, attr_value;
1922     UNICODE_STRING  attr_valueU, attr_nameU;
1923     BOOL        end = FALSE, error;
1924 
1925     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1926     {
1927         attr_nameU = xmlstr2unicode(&attr_name);
1928         attr_valueU = xmlstr2unicode(&attr_value);
1929 
1930         if (xmlstr_cmp(&attr_name, oldVersionW))
1931         {
1932             DPRINT1("Not stored yet oldVersion=%wZ\n", &attr_valueU);
1933         }
1934         else if (xmlstr_cmp(&attr_name, newVersionW))
1935         {
1936             DPRINT1("Not stored yet newVersion=%wZ\n", &attr_valueU);
1937         }
1938         else
1939         {
1940             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
1941         }
1942     }
1943 
1944     if (error || end) return end;
1945     return parse_expect_end_elem(xmlbuf, bindingRedirectW, asmv1W);
1946 }
1947 
1948 static BOOL parse_description_elem(xmlbuf_t* xmlbuf)
1949 {
1950     xmlstr_t    elem, content, attr_name, attr_value;
1951     BOOL        end = FALSE, ret = TRUE, error = FALSE;
1952 
1953     UNICODE_STRING elem1U, elem2U;
1954 
1955     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
1956     {
1957         elem1U = xmlstr2unicode(&attr_name);
1958         elem2U = xmlstr2unicode(&attr_value);
1959         DPRINT1("unknown attr %s=%s\n", &elem1U, &elem2U);
1960     }
1961 
1962     if (error) return FALSE;
1963     if (end) return TRUE;
1964 
1965     if (!parse_text_content(xmlbuf, &content))
1966         return FALSE;
1967 
1968     elem1U = xmlstr2unicode(&content);
1969     DPRINT("Got description %wZ\n", &elem1U);
1970 
1971     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
1972     {
1973         if (xmlstr_cmp_end(&elem, descriptionW))
1974         {
1975             ret = parse_end_element(xmlbuf);
1976             break;
1977         }
1978         else
1979         {
1980             elem1U = xmlstr2unicode(&elem);
1981             DPRINT1("unknown elem %wZ\n", &elem1U);
1982             ret = parse_unknown_elem(xmlbuf, &elem);
1983         }
1984     }
1985 
1986     return ret;
1987 }
1988 
1989 static BOOL parse_com_interface_external_proxy_stub_elem(xmlbuf_t* xmlbuf,
1990                                                          struct assembly* assembly,
1991                                                          struct actctx_loader* acl)
1992 {
1993     xmlstr_t            attr_name, attr_value;
1994     UNICODE_STRING      attr_nameU, attr_valueU;
1995     BOOL                end = FALSE, error;
1996     struct entity*      entity;
1997 
1998     entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION);
1999     if (!entity) return FALSE;
2000 
2001     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
2002     {
2003         if (xmlstr_cmp(&attr_name, iidW))
2004         {
2005             if (!(entity->u.ifaceps.iid = xmlstrdupW(&attr_value))) return FALSE;
2006         }
2007         else if (xmlstr_cmp(&attr_name, g_nameW))
2008         {
2009             if (!(entity->u.ifaceps.name = xmlstrdupW(&attr_value))) return FALSE;
2010         }
2011         else if (xmlstr_cmp(&attr_name, baseInterfaceW))
2012         {
2013             if (!(entity->u.ifaceps.base = xmlstrdupW(&attr_value))) return FALSE;
2014             entity->u.ifaceps.mask |= BaseIface;
2015         }
2016         else if (xmlstr_cmp(&attr_name, nummethodsW))
2017         {
2018             if (!(parse_nummethods(&attr_value, entity))) return FALSE;
2019             entity->u.ifaceps.mask |= NumMethods;
2020         }
2021         else if (xmlstr_cmp(&attr_name, proxyStubClsid32W))
2022         {
2023             if (!(entity->u.ifaceps.ps32 = xmlstrdupW(&attr_value))) return FALSE;
2024         }
2025         else if (xmlstr_cmp(&attr_name, tlbidW))
2026         {
2027             if (!(entity->u.ifaceps.tlib = xmlstrdupW(&attr_value))) return FALSE;
2028         }
2029         else
2030         {
2031             attr_nameU = xmlstr2unicode(&attr_name);
2032             attr_valueU = xmlstr2unicode(&attr_value);
2033             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
2034         }
2035     }
2036 
2037     if (error) return FALSE;
2038     acl->actctx->sections |= IFACEREDIRECT_SECTION;
2039     if (end) return TRUE;
2040 
2041     return parse_expect_end_elem(xmlbuf, comInterfaceExternalProxyStubW, asmv1W);
2042 }
2043 
2044 static BOOL parse_clr_class_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl)
2045 {
2046     xmlstr_t    attr_name, attr_value, elem;
2047     BOOL        end = FALSE, error, ret = TRUE;
2048     struct entity*      entity;
2049 
2050     entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION);
2051     if (!entity) return FALSE;
2052 
2053     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
2054     {
2055         if (xmlstr_cmp(&attr_name, g_nameW))
2056         {
2057             if (!(entity->u.comclass.name = xmlstrdupW(&attr_value))) return FALSE;
2058         }
2059         else if (xmlstr_cmp(&attr_name, clsidW))
2060         {
2061             if (!(entity->u.comclass.clsid = xmlstrdupW(&attr_value))) return FALSE;
2062         }
2063         else if (xmlstr_cmp(&attr_name, progidW))
2064         {
2065             if (!(entity->u.comclass.progid = xmlstrdupW(&attr_value))) return FALSE;
2066         }
2067         else if (xmlstr_cmp(&attr_name, tlbidW))
2068         {
2069             if (!(entity->u.comclass.tlbid = xmlstrdupW(&attr_value))) return FALSE;
2070         }
2071         else if (xmlstr_cmp(&attr_name, threadingmodelW))
2072         {
2073             entity->u.comclass.model = parse_com_class_threadingmodel(&attr_value);
2074         }
2075         else if (xmlstr_cmp(&attr_name, runtimeVersionW))
2076         {
2077             if (!(entity->u.comclass.version = xmlstrdupW(&attr_value))) return FALSE;
2078         }
2079         else
2080         {
2081             UNICODE_STRING attr_nameU, attr_valueU;
2082             attr_nameU = xmlstr2unicode(&attr_name);
2083             attr_valueU = xmlstr2unicode(&attr_value);
2084             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
2085         }
2086     }
2087 
2088     if (error) return FALSE;
2089     acl->actctx->sections |= SERVERREDIRECT_SECTION;
2090     if (entity->u.comclass.progid)
2091         acl->actctx->sections |= PROGIDREDIRECT_SECTION;
2092     if (end) return TRUE;
2093 
2094     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2095     {
2096         if (xmlstr_cmp_end(&elem, clrClassW))
2097         {
2098             ret = parse_end_element(xmlbuf);
2099             break;
2100         }
2101         else if (xmlstr_cmp(&elem, progidW))
2102         {
2103             ret = parse_com_class_progid(xmlbuf, entity);
2104         }
2105         else
2106         {
2107             UNICODE_STRING elemU = xmlstr2unicode(&elem);
2108             DPRINT1("unknown elem %wZ\n", &elemU);
2109             ret = parse_unknown_elem(xmlbuf, &elem);
2110         }
2111     }
2112 
2113     if (entity->u.comclass.progids.num)
2114         acl->actctx->sections |= PROGIDREDIRECT_SECTION;
2115 
2116     return ret;
2117 }
2118 
2119 static BOOL parse_clr_surrogate_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl)
2120 {
2121     xmlstr_t    attr_name, attr_value;
2122     UNICODE_STRING attr_nameU, attr_valueU;
2123     BOOL        end = FALSE, error;
2124     struct entity*      entity;
2125 
2126     entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES);
2127     if (!entity) return FALSE;
2128 
2129     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
2130     {
2131         if (xmlstr_cmp(&attr_name, g_nameW))
2132         {
2133             if (!(entity->u.clrsurrogate.name = xmlstrdupW(&attr_value))) return FALSE;
2134         }
2135         else if (xmlstr_cmp(&attr_name, clsidW))
2136         {
2137             if (!(entity->u.clrsurrogate.clsid = xmlstrdupW(&attr_value))) return FALSE;
2138         }
2139         else if (xmlstr_cmp(&attr_name, runtimeVersionW))
2140         {
2141             if (!(entity->u.clrsurrogate.version = xmlstrdupW(&attr_value))) return FALSE;
2142         }
2143         else
2144         {
2145             attr_nameU = xmlstr2unicode(&attr_name);
2146             attr_valueU = xmlstr2unicode(&attr_value);
2147             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
2148         }
2149     }
2150 
2151     if (error) return FALSE;
2152     acl->actctx->sections |= CLRSURROGATES_SECTION;
2153     if (end) return TRUE;
2154 
2155     return parse_expect_end_elem(xmlbuf, clrSurrogateW, asmv1W);
2156 }
2157 
2158 static BOOL parse_dependent_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl, BOOL optional)
2159 {
2160     struct assembly_identity    ai;
2161     xmlstr_t                    elem, attr_name, attr_value;
2162     BOOL                        end = FALSE, error = FALSE, ret = TRUE, delayed = FALSE;
2163 
2164     UNICODE_STRING elem1U, elem2U;
2165 
2166     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
2167     {
2168         static const WCHAR allowDelayedBindingW[] = {'a','l','l','o','w','D','e','l','a','y','e','d','B','i','n','d','i','n','g',0};
2169         static const WCHAR trueW[] = {'t','r','u','e',0};
2170 
2171         if (xmlstr_cmp(&attr_name, allowDelayedBindingW))
2172             delayed = xmlstr_cmp(&attr_value, trueW);
2173         else
2174         {
2175             elem1U = xmlstr2unicode(&attr_name);
2176             elem2U = xmlstr2unicode(&attr_value);
2177             DPRINT1("unknown attr %s=%s\n", &elem1U, &elem2U);
2178         }
2179     }
2180 
2181     if (error || end) return end;
2182 
2183     memset(&ai, 0, sizeof(ai));
2184     ai.optional = optional;
2185     ai.delayed = delayed;
2186 
2187     if (!parse_expect_elem(xmlbuf, assemblyIdentityW, asmv1W) ||
2188         !parse_assembly_identity_elem(xmlbuf, acl->actctx, &ai))
2189         return FALSE;
2190 
2191     //TRACE( "adding name=%s version=%s arch=%s\n", debugstr_w(ai.name), debugstr_version(&ai.version), debugstr_w(ai.arch) );
2192 
2193     /* store the newly found identity for later loading */
2194     if (!add_dependent_assembly_id(acl, &ai)) return FALSE;
2195 
2196     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2197     {
2198         if (xmlstr_cmp_end(&elem, dependentAssemblyW))
2199         {
2200             ret = parse_end_element(xmlbuf);
2201             break;
2202         }
2203         else if (xmlstr_cmp(&elem, bindingRedirectW))
2204         {
2205             ret = parse_binding_redirect_elem(xmlbuf);
2206         }
2207         else
2208         {
2209             DPRINT1("unknown elem %S\n", elem.ptr);
2210             ret = parse_unknown_elem(xmlbuf, &elem);
2211         }
2212     }
2213 
2214     return ret;
2215 }
2216 
2217 static BOOL parse_dependency_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl)
2218 {
2219     xmlstr_t attr_name, attr_value, elem;
2220     UNICODE_STRING attr_nameU, attr_valueU;
2221     BOOL end = FALSE, ret = TRUE, error, optional = FALSE;
2222 
2223     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
2224     {
2225         attr_nameU = xmlstr2unicode(&attr_name);
2226         attr_valueU = xmlstr2unicode(&attr_value);
2227 
2228         if (xmlstr_cmp(&attr_name, optionalW))
2229         {
2230             optional = xmlstr_cmpi( &attr_value, yesW );
2231             DPRINT1("optional=%wZ\n", &attr_valueU);
2232         }
2233         else
2234         {
2235             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
2236         }
2237     }
2238 
2239     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2240     {
2241         if (xmlstr_cmp_end(&elem, dependencyW))
2242         {
2243             ret = parse_end_element(xmlbuf);
2244             break;
2245         }
2246         else if (xmlstr_cmp(&elem, dependentAssemblyW))
2247         {
2248             ret = parse_dependent_assembly_elem(xmlbuf, acl, optional);
2249         }
2250         else
2251         {
2252             attr_nameU = xmlstr2unicode(&elem);
2253             DPRINT1("unknown element %wZ\n", &attr_nameU);
2254             ret = parse_unknown_elem(xmlbuf, &elem);
2255         }
2256     }
2257 
2258     return ret;
2259 }
2260 
2261 static BOOL parse_noinherit_elem(xmlbuf_t* xmlbuf)
2262 {
2263     BOOL end = FALSE;
2264 
2265     if (!parse_expect_no_attr(xmlbuf, &end)) return FALSE;
2266     return end || parse_expect_end_elem(xmlbuf, noInheritW, asmv1W);
2267 }
2268 
2269 static BOOL parse_noinheritable_elem(xmlbuf_t* xmlbuf)
2270 {
2271     BOOL end = FALSE;
2272 
2273     if (!parse_expect_no_attr(xmlbuf, &end)) return FALSE;
2274     return end || parse_expect_end_elem(xmlbuf, noInheritableW, asmv1W);
2275 }
2276 
2277 static BOOL parse_file_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader* acl)
2278 {
2279     xmlstr_t    attr_name, attr_value, elem;
2280     UNICODE_STRING attr_nameU, attr_valueU;
2281     BOOL        end = FALSE, error, ret = TRUE;
2282     struct dll_redirect* dll;
2283 
2284     if (!(dll = add_dll_redirect(assembly))) return FALSE;
2285 
2286     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
2287     {
2288         attr_nameU = xmlstr2unicode(&attr_name);
2289         attr_valueU = xmlstr2unicode(&attr_value);
2290 
2291         if (xmlstr_cmp(&attr_name, g_nameW))
2292         {
2293             if (!(dll->name = xmlstrdupW(&attr_value))) return FALSE;
2294             DPRINT("name=%wZ\n", &attr_valueU);
2295         }
2296         else if (xmlstr_cmp(&attr_name, hashW))
2297         {
2298             if (!(dll->hash = xmlstrdupW(&attr_value))) return FALSE;
2299         }
2300         else if (xmlstr_cmp(&attr_name, hashalgW))
2301         {
2302             static const WCHAR sha1W[] = {'S','H','A','1',0};
2303             if (!xmlstr_cmpi(&attr_value, sha1W))
2304                 DPRINT1("hashalg should be SHA1, got %wZ\n", &attr_valueU);
2305         }
2306         else
2307         {
2308             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
2309         }
2310     }
2311 
2312     if (error || !dll->name) return FALSE;
2313 
2314     acl->actctx->sections |= DLLREDIRECT_SECTION;
2315 
2316     if (end) return TRUE;
2317 
2318     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2319     {
2320         if (xmlstr_cmp_end(&elem, fileW))
2321         {
2322             ret = parse_end_element(xmlbuf);
2323             break;
2324         }
2325         else if (xmlstr_cmp(&elem, comClassW))
2326         {
2327             ret = parse_com_class_elem(xmlbuf, dll, acl);
2328         }
2329         else if (xmlstr_cmp(&elem, comInterfaceProxyStubW))
2330         {
2331             ret = parse_cominterface_proxy_stub_elem(xmlbuf, dll, acl);
2332         }
2333         else if (xml_elem_cmp(&elem, hashW, asmv2W))
2334         {
2335             DPRINT1("asmv2hash (undocumented) not supported\n");
2336             ret = parse_unknown_elem(xmlbuf, &elem);
2337         }
2338         else if (xmlstr_cmp(&elem, typelibW))
2339         {
2340             ret = parse_typelib_elem(xmlbuf, dll, acl);
2341         }
2342         else if (xmlstr_cmp(&elem, windowClassW))
2343         {
2344             ret = parse_window_class_elem(xmlbuf, dll, acl);
2345         }
2346         else
2347         {
2348             attr_nameU = xmlstr2unicode(&elem);
2349             DPRINT1("unknown elem %wZ\n", &attr_nameU);
2350             ret = parse_unknown_elem( xmlbuf, &elem );
2351         }
2352     }
2353 
2354     return ret;
2355 }
2356 
2357 static BOOL parse_supportedos_elem(xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader *acl)
2358 {
2359     xmlstr_t attr_name, attr_value;
2360     BOOL end = FALSE, error;
2361 
2362     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
2363     {
2364         if (xmlstr_cmp(&attr_name, IdW))
2365         {
2366             COMPATIBILITY_CONTEXT_ELEMENT *compat;
2367             UNICODE_STRING str;
2368             GUID compat_id;
2369 
2370             str.Buffer = (PWSTR)attr_value.ptr;
2371             str.Length = str.MaximumLength = (USHORT)attr_value.len * sizeof(WCHAR);
2372             if (RtlGUIDFromString(&str, &compat_id) == STATUS_SUCCESS)
2373             {
2374                 if (!(compat = add_compat_context(assembly))) return FALSE;
2375                 compat->Type = ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS;
2376                 compat->Id = compat_id;
2377             }
2378             else
2379             {
2380                 UNICODE_STRING attr_valueU = xmlstr2unicode(&attr_value);
2381                 DPRINT1("Invalid guid %wZ\n", &attr_valueU);
2382             }
2383         }
2384         else
2385         {
2386             UNICODE_STRING attr_nameU = xmlstr2unicode(&attr_name);
2387             UNICODE_STRING attr_valueU = xmlstr2unicode(&attr_value);
2388             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
2389         }
2390     }
2391 
2392     if (error) return FALSE;
2393     if (end) return TRUE;
2394 
2395     return parse_expect_end_elem(xmlbuf, supportedOSW, asmv1W);
2396 }
2397 
2398 static BOOL parse_compatibility_application_elem(xmlbuf_t* xmlbuf, struct assembly* assembly,
2399                                                  struct actctx_loader* acl)
2400 {
2401     BOOL ret = TRUE;
2402     xmlstr_t elem;
2403 
2404     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2405     {
2406         if (xmlstr_cmp_end(&elem, applicationW))
2407         {
2408             ret = parse_end_element(xmlbuf);
2409             break;
2410         }
2411         else if (xmlstr_cmp(&elem, supportedOSW))
2412         {
2413             ret = parse_supportedos_elem(xmlbuf, assembly, acl);
2414         }
2415         else
2416         {
2417             UNICODE_STRING elemU = xmlstr2unicode(&elem);
2418             DPRINT1("unknown elem %wZ\n", &elemU);
2419             ret = parse_unknown_elem(xmlbuf, &elem);
2420         }
2421     }
2422 
2423     return ret;
2424 }
2425 
2426 static BOOL parse_compatibility_elem(xmlbuf_t* xmlbuf, struct assembly* assembly,
2427                                      struct actctx_loader* acl)
2428 {
2429     xmlstr_t elem;
2430     BOOL ret = TRUE;
2431 
2432     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2433     {
2434         if (xmlstr_cmp_end(&elem, compatibilityW))
2435         {
2436             ret = parse_end_element(xmlbuf);
2437             break;
2438         }
2439         else if (xmlstr_cmp(&elem, applicationW))
2440         {
2441             ret = parse_compatibility_application_elem(xmlbuf, assembly, acl);
2442         }
2443         else
2444         {
2445             UNICODE_STRING elemU = xmlstr2unicode(&elem);
2446             DPRINT1("unknown elem %wZ\n", &elemU);
2447             ret = parse_unknown_elem(xmlbuf, &elem);
2448         }
2449     }
2450     return ret;
2451 }
2452 
2453 static BOOL parse_requested_execution_level_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl)
2454 {
2455     static const WCHAR levelW[] = {'l','e','v','e','l',0};
2456     static const WCHAR asInvokerW[] = {'a','s','I','n','v','o','k','e','r',0};
2457     static const WCHAR requireAdministratorW[] = {'r','e','q','u','i','r','e','A','d','m','i','n','i','s','t','r','a','t','o','r',0};
2458     static const WCHAR highestAvailableW[] = {'h','i','g','h','e','s','t','A','v','a','i','l','a','b','l','e',0};
2459     static const WCHAR uiAccessW[] = {'u','i','A','c','c','e','s','s',0};
2460     static const WCHAR falseW[] = {'f','a','l','s','e',0};
2461     static const WCHAR trueW[] = {'t','r','u','e',0};
2462 
2463     xmlstr_t attr_name, attr_value, elem;
2464     BOOL end = FALSE, ret = TRUE, error;
2465 
2466     /* Multiple requestedExecutionLevel elements are not supported. */
2467     if (assembly->run_level != ACTCTX_RUN_LEVEL_UNSPECIFIED)
2468         return FALSE;
2469 
2470     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
2471     {
2472         UNICODE_STRING attr_nameU = xmlstr2unicode(&attr_name);
2473         UNICODE_STRING attr_valueU = xmlstr2unicode(&attr_value);
2474         if (xmlstr_cmp(&attr_name, levelW))
2475         {
2476             if (xmlstr_cmpi(&attr_value, asInvokerW))
2477                 assembly->run_level = ACTCTX_RUN_LEVEL_AS_INVOKER;
2478             else if (xmlstr_cmpi(&attr_value, highestAvailableW))
2479                 assembly->run_level = ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE;
2480             else if (xmlstr_cmpi(&attr_value, requireAdministratorW))
2481                 assembly->run_level = ACTCTX_RUN_LEVEL_REQUIRE_ADMIN;
2482             else
2483                 DPRINT1("unknown execution level: %wZ\n", &attr_valueU);
2484         }
2485         else if (xmlstr_cmp(&attr_name, uiAccessW))
2486         {
2487             if (xmlstr_cmpi(&attr_value, falseW))
2488                 assembly->ui_access = FALSE;
2489             else if (xmlstr_cmpi(&attr_value, trueW))
2490                 assembly->ui_access = TRUE;
2491             else
2492                 DPRINT1("unknown uiAccess value: %wZ\n", &attr_valueU);
2493         }
2494         else
2495             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
2496     }
2497 
2498     if (error) return FALSE;
2499     if (end) return TRUE;
2500 
2501     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2502     {
2503         if (xml_elem_cmp_end(&elem, requestedExecutionLevelW, asmv2W))
2504         {
2505             ret = parse_end_element(xmlbuf);
2506             break;
2507         }
2508         else
2509         {
2510             UNICODE_STRING elemU = xmlstr2unicode(&elem);
2511             DPRINT1("unknown element %wZ\n", &elemU);
2512             ret = parse_unknown_elem(xmlbuf, &elem);
2513         }
2514     }
2515 
2516     return ret;
2517 }
2518 
2519 static BOOL parse_requested_privileges_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl)
2520 {
2521     xmlstr_t elem;
2522     BOOL ret = TRUE;
2523 
2524     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2525     {
2526         if (xml_elem_cmp_end(&elem, requestedPrivilegesW, asmv2W))
2527         {
2528             ret = parse_end_element(xmlbuf);
2529             break;
2530         }
2531         else if (xml_elem_cmp(&elem, requestedExecutionLevelW, asmv2W))
2532             ret = parse_requested_execution_level_elem(xmlbuf, assembly, acl);
2533         else
2534         {
2535             UNICODE_STRING elemU = xmlstr2unicode(&elem);
2536             DPRINT1("unknown elem %wZ\n", &elemU);
2537             ret = parse_unknown_elem(xmlbuf, &elem);
2538         }
2539     }
2540 
2541     return ret;
2542 }
2543 
2544 static BOOL parse_security_elem(xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader *acl)
2545 {
2546     xmlstr_t elem;
2547     BOOL ret = TRUE;
2548 
2549     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2550     {
2551         if (xml_elem_cmp_end(&elem, securityW, asmv2W))
2552         {
2553             ret = parse_end_element(xmlbuf);
2554             break;
2555         }
2556         else if (xml_elem_cmp(&elem, requestedPrivilegesW, asmv2W))
2557             ret = parse_requested_privileges_elem(xmlbuf, assembly, acl);
2558         else
2559         {
2560             UNICODE_STRING elemU = xmlstr2unicode(&elem);
2561             DPRINT1("unknown elem %wZ\n", &elemU);
2562             ret = parse_unknown_elem(xmlbuf, &elem);
2563         }
2564     }
2565 
2566     return ret;
2567 }
2568 
2569 static BOOL parse_trust_info_elem(xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader *acl)
2570 {
2571     xmlstr_t elem;
2572     BOOL ret = TRUE;
2573 
2574     while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
2575     {
2576         if (xml_elem_cmp_end(&elem, trustInfoW, asmv2W))
2577         {
2578             ret = parse_end_element(xmlbuf);
2579             break;
2580         }
2581         else if (xml_elem_cmp(&elem, securityW, asmv2W))
2582             ret = parse_security_elem(xmlbuf, assembly, acl);
2583         else
2584         {
2585             UNICODE_STRING elemU = xmlstr2unicode(&elem);
2586             DPRINT1("unknown elem %wZ\n", &elemU);
2587             ret = parse_unknown_elem(xmlbuf, &elem);
2588         }
2589     }
2590 
2591     return ret;
2592 }
2593 
2594 static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl,
2595                                 struct assembly* assembly,
2596                                 struct assembly_identity* expected_ai)
2597 {
2598     xmlstr_t    attr_name, attr_value, elem;
2599     UNICODE_STRING attr_nameU, attr_valueU;
2600     BOOL        end = FALSE, error, version = FALSE, xmlns = FALSE, ret = TRUE;
2601 
2602     DPRINT("(%p)\n", xmlbuf);
2603 
2604     while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
2605     {
2606         attr_nameU = xmlstr2unicode(&attr_name);
2607         attr_valueU = xmlstr2unicode(&attr_value);
2608 
2609         if (xmlstr_cmp(&attr_name, manifestVersionW))
2610         {
2611             static const WCHAR v10W[] = {'1','.','0',0};
2612             if (!xmlstr_cmp(&attr_value, v10W))
2613             {
2614                 DPRINT1("wrong version %wZ\n", &attr_valueU);
2615                 return FALSE;
2616             }
2617             version = TRUE;
2618         }
2619         else if (xmlstr_cmp(&attr_name, xmlnsW))
2620         {
2621             if (!xmlstr_cmp(&attr_value, manifestv1W) &&
2622                 !xmlstr_cmp(&attr_value, manifestv2W) &&
2623                 !xmlstr_cmp(&attr_value, manifestv3W))
2624             {
2625                 DPRINT1("wrong namespace %wZ\n", &attr_valueU);
2626                 return FALSE;
2627             }
2628             xmlns = TRUE;
2629         }
2630         else
2631         {
2632             DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
2633         }
2634     }
2635 
2636     if (error || end || !xmlns || !version) return FALSE;
2637     if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
2638 
2639     if (assembly->type == APPLICATION_MANIFEST && xmlstr_cmp(&elem, noInheritW))
2640     {
2641         if (!parse_noinherit_elem(xmlbuf) || !next_xml_elem(xmlbuf, &elem))
2642             return FALSE;
2643         assembly->no_inherit = TRUE;
2644     }
2645 
2646     if (xml_elem_cmp(&elem, noInheritableW, asmv1W))
2647     {
2648         if (!parse_noinheritable_elem(xmlbuf) || !next_xml_elem(xmlbuf, &elem))
2649             return FALSE;
2650     }
2651     else if ((assembly->type == ASSEMBLY_MANIFEST || assembly->type == ASSEMBLY_SHARED_MANIFEST) &&
2652              assembly->no_inherit)
2653         return FALSE;
2654 
2655     while (ret)
2656     {
2657         if (xml_elem_cmp_end(&elem, assemblyW, asmv1W))
2658         {
2659             ret = parse_end_element(xmlbuf);
2660             break;
2661         }
2662         else if (xml_elem_cmp(&elem, descriptionW, asmv1W))
2663         {
2664             ret = parse_description_elem(xmlbuf);
2665         }
2666         else if (xml_elem_cmp(&elem, comInterfaceExternalProxyStubW, asmv1W))
2667         {
2668             ret = parse_com_interface_external_proxy_stub_elem(xmlbuf, assembly, acl);
2669         }
2670         else if (xml_elem_cmp(&elem, dependencyW, asmv1W))
2671         {
2672             ret = parse_dependency_elem(xmlbuf, acl);
2673         }
2674         else if (xml_elem_cmp(&elem, fileW, asmv1W))
2675         {
2676             ret = parse_file_elem(xmlbuf, assembly, acl);
2677         }
2678         else if (xml_elem_cmp(&elem, clrClassW, asmv1W))
2679         {
2680             ret = parse_clr_class_elem(xmlbuf, assembly, acl);
2681         }
2682         else if (xml_elem_cmp(&elem, clrSurrogateW, asmv1W))
2683         {
2684             ret = parse_clr_surrogate_elem(xmlbuf, assembly, acl);
2685         }
2686         else if (xml_elem_cmp(&elem, trustInfoW, asmv2W) ||
2687                  xml_elem_cmp(&elem, trustInfoW, asmv1W))
2688         {
2689             ret = parse_trust_info_elem(xmlbuf, assembly, acl);
2690         }
2691         else if (xml_elem_cmp(&elem, assemblyIdentityW, asmv1W))
2692         {
2693             if (!parse_assembly_identity_elem(xmlbuf, acl->actctx, &assembly->id)) return FALSE;
2694 
2695             if (expected_ai)
2696             {
2697                 /* FIXME: more tests */
2698                 if (assembly->type == ASSEMBLY_MANIFEST &&
2699                     memcmp(&assembly->id.version, &expected_ai->version, sizeof(assembly->id.version)))
2700                 {
2701                     DPRINT1("wrong version for assembly manifest: %u.%u.%u.%u / %u.%u.%u.%u\n",
2702                           expected_ai->version.major, expected_ai->version.minor,
2703                           expected_ai->version.build, expected_ai->version.revision,
2704                           assembly->id.version.major, assembly->id.version.minor,
2705                           assembly->id.version.build, assembly->id.version.revision);
2706                     ret = FALSE;
2707                 }
2708                 else if (assembly->type == ASSEMBLY_SHARED_MANIFEST &&
2709                          (assembly->id.version.major != expected_ai->version.major ||
2710                           assembly->id.version.minor != expected_ai->version.minor ||
2711                           assembly->id.version.build < expected_ai->version.build ||
2712                           (assembly->id.version.build == expected_ai->version.build &&
2713                            assembly->id.version.revision < expected_ai->version.revision)))
2714                 {
2715                     DPRINT1("wrong version for shared assembly manifest\n");
2716                     ret = FALSE;
2717                 }
2718             }
2719         }
2720         else if (xml_elem_cmp(&elem, compatibilityW, compatibilityNSW))
2721         {
2722             ret = parse_compatibility_elem(xmlbuf, assembly, acl);
2723         }
2724         else
2725         {
2726             attr_nameU = xmlstr2unicode(&elem);
2727             DPRINT1("unknown element %wZ\n", &attr_nameU);
2728             ret = parse_unknown_elem(xmlbuf, &elem);
2729         }
2730         if (ret) ret = next_xml_elem(xmlbuf, &elem);
2731     }
2732 
2733     return ret;
2734 }
2735 
2736 static NTSTATUS parse_manifest_buffer( struct actctx_loader* acl, struct assembly *assembly,
2737                                        struct assembly_identity* ai, xmlbuf_t *xmlbuf )
2738 {
2739     xmlstr_t elem;
2740     UNICODE_STRING elemU;
2741 
2742     if (!next_xml_elem(xmlbuf, &elem)) return STATUS_SXS_CANT_GEN_ACTCTX;
2743 
2744     if (xmlstr_cmp(&elem, g_xmlW) &&
2745         (!parse_xml_header(xmlbuf) || !next_xml_elem(xmlbuf, &elem)))
2746         return STATUS_SXS_CANT_GEN_ACTCTX;
2747 
2748     if (!xml_elem_cmp(&elem, assemblyW, asmv1W))
2749     {
2750         elemU = xmlstr2unicode(&elem);
2751         DPRINT1("root element is %wZ, not <assembly>\n", &elemU);
2752         return STATUS_SXS_CANT_GEN_ACTCTX;
2753     }
2754 
2755     if (!parse_assembly_elem(xmlbuf, acl, assembly, ai))
2756     {
2757         DPRINT1("failed to parse manifest %S\n", assembly->manifest.info );
2758         return STATUS_SXS_CANT_GEN_ACTCTX;
2759     }
2760 
2761     if (next_xml_elem(xmlbuf, &elem))
2762     {
2763         elemU = xmlstr2unicode(&elem);
2764         DPRINT1("unexpected element %wZ\n", &elemU);
2765         return STATUS_SXS_CANT_GEN_ACTCTX;
2766     }
2767 
2768     if (xmlbuf->ptr != xmlbuf->end)
2769     {
2770         DPRINT1("parse error\n");
2771         return STATUS_SXS_CANT_GEN_ACTCTX;
2772     }
2773     return STATUS_SUCCESS;
2774 }
2775 
2776 static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
2777                                 LPCWSTR filename, LPCWSTR directory, BOOL shared,
2778                                 const void *buffer, SIZE_T size )
2779 {
2780     xmlbuf_t xmlbuf;
2781     NTSTATUS status;
2782     struct assembly *assembly;
2783     int unicode_tests;
2784 
2785     DPRINT( "parsing manifest loaded from %S base dir %S\n", filename, directory );
2786 
2787     if (!(assembly = add_assembly(acl->actctx, shared ? ASSEMBLY_SHARED_MANIFEST : ASSEMBLY_MANIFEST)))
2788         return STATUS_SXS_CANT_GEN_ACTCTX;
2789 
2790     if (directory && !(assembly->directory = strdupW(directory)))
2791         return STATUS_NO_MEMORY;
2792 
2793     if (filename) assembly->manifest.info = strdupW( filename + 4 /* skip \??\ prefix */ );
2794     assembly->manifest.type = assembly->manifest.info ? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
2795                                                       : ACTIVATION_CONTEXT_PATH_TYPE_NONE;
2796 
2797     unicode_tests = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE;
2798     if (RtlIsTextUnicode(buffer, size, &unicode_tests ))
2799     {
2800         xmlbuf.ptr = buffer;
2801         xmlbuf.end = xmlbuf.ptr + size / sizeof(WCHAR);
2802         status = parse_manifest_buffer( acl, assembly, ai, &xmlbuf );
2803     }
2804     else if (unicode_tests & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
2805     {
2806         const WCHAR *buf = buffer;
2807         WCHAR *new_buff;
2808         unsigned int i;
2809 
2810         if (!(new_buff = RtlAllocateHeap( RtlGetProcessHeap(), 0, size )))
2811             return STATUS_NO_MEMORY;
2812         for (i = 0; i < size / sizeof(WCHAR); i++)
2813             new_buff[i] = RtlUshortByteSwap( buf[i] );
2814         xmlbuf.ptr = new_buff;
2815         xmlbuf.end = xmlbuf.ptr + size / sizeof(WCHAR);
2816         status = parse_manifest_buffer( acl, assembly, ai, &xmlbuf );
2817         RtlFreeHeap( RtlGetProcessHeap(), 0, new_buff );
2818     }
2819     else
2820     {
2821         /* TODO: this doesn't handle arbitrary encodings */
2822         WCHAR *new_buff;
2823         ULONG sizeU;
2824 
2825         status = RtlMultiByteToUnicodeSize(&sizeU, buffer, size);
2826         if (!NT_SUCCESS(status))
2827         {
2828             DPRINT1("RtlMultiByteToUnicodeSize failed with %lx\n", status);
2829             return STATUS_SXS_CANT_GEN_ACTCTX;
2830         }
2831 
2832         new_buff = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeU);
2833         if (!new_buff)
2834             return STATUS_NO_MEMORY;
2835 
2836         status = RtlMultiByteToUnicodeN(new_buff, sizeU, &sizeU, buffer, size);
2837         if (!NT_SUCCESS(status))
2838         {
2839             DPRINT1("RtlMultiByteToUnicodeN failed with %lx\n", status);
2840             return STATUS_SXS_CANT_GEN_ACTCTX;
2841         }
2842 
2843         xmlbuf.ptr = new_buff;
2844         xmlbuf.end = xmlbuf.ptr + sizeU / sizeof(WCHAR);
2845         status = parse_manifest_buffer(acl, assembly, ai, &xmlbuf);
2846         RtlFreeHeap(RtlGetProcessHeap(), 0, new_buff);
2847     }
2848     return status;
2849 }
2850 
2851 static NTSTATUS open_nt_file( HANDLE *handle, UNICODE_STRING *name )
2852 {
2853     OBJECT_ATTRIBUTES attr;
2854     IO_STATUS_BLOCK io;
2855 
2856     attr.Length = sizeof(attr);
2857     attr.RootDirectory = 0;
2858     attr.Attributes = OBJ_CASE_INSENSITIVE;
2859     attr.ObjectName = name;
2860     attr.SecurityDescriptor = NULL;
2861     attr.SecurityQualityOfService = NULL;
2862     return NtOpenFile( handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
2863 }
2864 
2865 static NTSTATUS get_module_filename( HMODULE module, UNICODE_STRING *str, USHORT extra_len )
2866 {
2867     NTSTATUS status;
2868     ULONG_PTR magic;
2869     LDR_DATA_TABLE_ENTRY *pldr;
2870 
2871     LdrLockLoaderLock(0, NULL, &magic);
2872     status = LdrFindEntryForAddress( module, &pldr );
2873     if (status == STATUS_SUCCESS)
2874     {
2875         if ((str->Buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0,
2876                                             pldr->FullDllName.Length + extra_len + sizeof(WCHAR) )))
2877         {
2878             memcpy( str->Buffer, pldr->FullDllName.Buffer, pldr->FullDllName.Length + sizeof(WCHAR) );
2879             str->Length = pldr->FullDllName.Length;
2880             str->MaximumLength = pldr->FullDllName.Length + extra_len + sizeof(WCHAR);
2881         }
2882         else status = STATUS_NO_MEMORY;
2883     }
2884     LdrUnlockLoaderLock(0, magic);
2885     return status;
2886 }
2887 
2888 static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai,
2889                                         LPCWSTR filename, LPCWSTR directory, BOOL shared,
2890                                         HANDLE hModule, LPCWSTR resname, ULONG lang )
2891 {
2892     NTSTATUS status;
2893     UNICODE_STRING nameW;
2894     LDR_RESOURCE_INFO info;
2895     IMAGE_RESOURCE_DATA_ENTRY* entry = NULL;
2896     void *ptr;
2897 
2898     //DPRINT( "looking for res %s in module %p %s\n", resname,
2899     //                hModule, filename );
2900     DPRINT("get_manifest_in_module %p\n", hModule);
2901 
2902 #if 0
2903     if (TRACE_ON(actctx))
2904     {
2905         if (!filename && !get_module_filename( hModule, &nameW, 0 ))
2906         {
2907             DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname),
2908                    hModule, debugstr_w(nameW.Buffer) );
2909             RtlFreeUnicodeString( &nameW );
2910         }
2911         else DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname),
2912                     hModule, debugstr_w(filename) );
2913     }
2914 #endif
2915 
2916     if (!resname) return STATUS_INVALID_PARAMETER;
2917 
2918     info.Type = (ULONG_PTR)RT_MANIFEST;
2919     info.Language = lang;
2920     if (!((ULONG_PTR)resname >> 16))
2921     {
2922         info.Name = (ULONG_PTR)resname;
2923         status = LdrFindResource_U(hModule, &info, 3, &entry);
2924     }
2925     else if (resname[0] == '#')
2926     {
2927         ULONG value;
2928         RtlInitUnicodeString(&nameW, resname + 1);
2929         if (RtlUnicodeStringToInteger(&nameW, 10, &value) != STATUS_SUCCESS || HIWORD(value))
2930             return STATUS_INVALID_PARAMETER;
2931         info.Name = value;
2932         status = LdrFindResource_U(hModule, &info, 3, &entry);
2933     }
2934     else
2935     {
2936         RtlCreateUnicodeString(&nameW, resname);
2937         RtlUpcaseUnicodeString(&nameW, &nameW, FALSE);
2938         info.Name = (ULONG_PTR)nameW.Buffer;
2939         status = LdrFindResource_U(hModule, &info, 3, &entry);
2940         RtlFreeUnicodeString(&nameW);
2941     }
2942     if (status == STATUS_SUCCESS) status = LdrAccessResource(hModule, entry, &ptr, NULL);
2943 
2944     if (status == STATUS_SUCCESS)
2945         status = parse_manifest(acl, ai, filename, directory, shared, ptr, entry->Size);
2946 
2947     return status;
2948 }
2949 
2950 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
2951                                              LPCWSTR name, void *root,
2952                                              int want_dir );
2953 
2954 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
2955                                             void *root, int want_dir );
2956 
2957 
2958 static IMAGE_RESOURCE_DIRECTORY *find_first_id_entry( IMAGE_RESOURCE_DIRECTORY *dir,
2959                                            void *root, int want_dir )
2960 {
2961     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
2962     int pos;
2963 
2964     for (pos = dir->NumberOfNamedEntries; pos < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; pos++)
2965     {
2966         if (!entry[pos].DataIsDirectory == !want_dir)
2967             return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].OffsetToDirectory);
2968     }
2969     return NULL;
2970 }
2971 
2972 
2973 static NTSTATUS search_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai,
2974                                        LPCWSTR filename, LPCWSTR directory, BOOL shared,
2975                                        HANDLE hModule, ULONG lang )
2976 {
2977     ULONG size;
2978     PVOID root, ptr;
2979     IMAGE_RESOURCE_DIRECTORY *resdirptr;
2980     IMAGE_RESOURCE_DATA_ENTRY *entry;
2981     NTSTATUS status;
2982 
2983     root = RtlImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size);
2984     if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
2985     if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND;
2986     resdirptr = root;
2987 
2988     if (!(ptr = find_entry_by_name(resdirptr, (LPCWSTR)RT_MANIFEST, root, 1)))
2989         return STATUS_RESOURCE_TYPE_NOT_FOUND;
2990 
2991     resdirptr = ptr;
2992     if (!(ptr = find_first_id_entry(resdirptr, root, 1)))
2993         return STATUS_RESOURCE_TYPE_NOT_FOUND;
2994 
2995     resdirptr = ptr;
2996     if (!(ptr = find_first_entry(resdirptr, root, 0)))
2997         return STATUS_RESOURCE_TYPE_NOT_FOUND;
2998 
2999     entry = ptr;
3000     status = LdrAccessResource(hModule, entry, &ptr, NULL);
3001 
3002     if (status == STATUS_SUCCESS)
3003         status = parse_manifest(acl, ai, filename, directory, shared, ptr, entry->Size);
3004 
3005     return status;
3006 }
3007 
3008 
3009 static NTSTATUS get_manifest_in_pe_file( struct actctx_loader* acl, struct assembly_identity* ai,
3010                                          LPCWSTR filename, LPCWSTR directory, BOOL shared,
3011                                          HANDLE file, LPCWSTR resname, ULONG lang )
3012 {
3013     HANDLE              mapping;
3014     OBJECT_ATTRIBUTES   attr;
3015     LARGE_INTEGER       size;
3016     LARGE_INTEGER       offset;
3017     NTSTATUS            status;
3018     SIZE_T              count;
3019     void               *base;
3020     WCHAR resnameBuf[20];
3021     LPCWSTR resptr = resname;
3022 
3023     if ((!((ULONG_PTR)resname >> 16)))
3024     {
3025         sprintfW(resnameBuf, L"#%u", PtrToUlong(resname));
3026         resptr = resnameBuf;
3027     }
3028 
3029     DPRINT( "looking for res %S in %S\n", resptr, filename ? filename : L"<NULL>");
3030 
3031     attr.Length                   = sizeof(attr);
3032     attr.RootDirectory            = 0;
3033     attr.ObjectName               = NULL;
3034     attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
3035     attr.SecurityDescriptor       = NULL;
3036     attr.SecurityQualityOfService = NULL;
3037 
3038     size.QuadPart = 0;
3039     status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
3040                               &attr, &size, PAGE_READONLY, SEC_COMMIT, file );
3041     if (status != STATUS_SUCCESS) return status;
3042 
3043     offset.QuadPart = 0;
3044     count = 0;
3045     base = NULL;
3046     status = NtMapViewOfSection( mapping, NtCurrentProcess(), &base, 0, 0, &offset,
3047                                  &count, ViewShare, 0, PAGE_READONLY );
3048     NtClose( mapping );
3049     if (status != STATUS_SUCCESS) return status;
3050 
3051     if (RtlImageNtHeader(base)) /* we got a PE file */
3052     {
3053         HANDLE module = (HMODULE)((ULONG_PTR)base | 1);  /* make it a LOAD_LIBRARY_AS_DATAFILE handle */
3054         if (resname)
3055             status = get_manifest_in_module( acl, ai, filename, directory, shared, module, resname, lang );
3056         else
3057             status = search_manifest_in_module(acl, ai, filename, directory, shared, module, lang);
3058     }
3059     else status = STATUS_INVALID_IMAGE_FORMAT;
3060 
3061     NtUnmapViewOfSection( NtCurrentProcess(), base );
3062     return status;
3063 }
3064 
3065 static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct assembly_identity* ai,
3066                                                LPCWSTR filename, LPCWSTR directory, BOOL shared, HANDLE file )
3067 {
3068     FILE_STANDARD_INFORMATION info;
3069     IO_STATUS_BLOCK io;
3070     HANDLE              mapping;
3071     OBJECT_ATTRIBUTES   attr;
3072     LARGE_INTEGER       size;
3073     LARGE_INTEGER       offset;
3074     NTSTATUS            status;
3075     SIZE_T              count;
3076     void               *base;
3077 
3078     DPRINT( "loading manifest file %S\n", filename );
3079 
3080     attr.Length                   = sizeof(attr);
3081     attr.RootDirectory            = 0;
3082     attr.ObjectName               = NULL;
3083     attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
3084     attr.SecurityDescriptor       = NULL;
3085     attr.SecurityQualityOfService = NULL;
3086 
3087     size.QuadPart = 0;
3088     status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
3089                               &attr, &size, PAGE_READONLY, SEC_COMMIT, file );
3090 
3091     if (status != STATUS_SUCCESS) return status;
3092 
3093     offset.QuadPart = 0;
3094     count = 0;
3095     base = NULL;
3096     status = NtMapViewOfSection( mapping, NtCurrentProcess(), &base, 0, 0, &offset,
3097                                  &count, ViewShare, 0, PAGE_READONLY );
3098     NtClose( mapping );
3099     if (status != STATUS_SUCCESS) return status;
3100 
3101     /* Fixme: WINE uses FileEndOfFileInformation with NtQueryInformationFile. */
3102     status = NtQueryInformationFile( file, &io, &info, sizeof(info), FileStandardInformation);
3103 
3104     if (status == STATUS_SUCCESS)
3105         status = parse_manifest(acl, ai, filename, directory, shared, base, (SIZE_T)info.EndOfFile.QuadPart);
3106 
3107     NtUnmapViewOfSection( NtCurrentProcess(), base );
3108     return status;
3109 }
3110 
3111 /* try to load the .manifest file associated to the file */
3112 static NTSTATUS get_manifest_in_associated_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
3113                                                      LPCWSTR filename, LPCWSTR directory, HMODULE module, LPCWSTR resname )
3114 {
3115     static const WCHAR fmtW[] = { '.','%','l','u',0 };
3116     WCHAR *buffer;
3117     NTSTATUS status;
3118     UNICODE_STRING nameW;
3119     HANDLE file;
3120     ULONG_PTR resid = (ULONG_PTR)CREATEPROCESS_MANIFEST_RESOURCE_ID;
3121 
3122     if (!((ULONG_PTR)resname >> 16)) resid = (ULONG_PTR)resname & 0xffff;
3123 
3124     DPRINT( "looking for manifest associated with %S id %lu\n", filename, resid );
3125 
3126     if (module) /* use the module filename */
3127     {
3128         UNICODE_STRING name;
3129 
3130         if (!(status = get_module_filename( module, &name, sizeof(dotManifestW) + 10*sizeof(WCHAR) )))
3131         {
3132             if (resid != 1) sprintfW( name.Buffer + strlenW(name.Buffer), fmtW, resid );
3133             strcatW( name.Buffer, dotManifestW );
3134             if (!RtlDosPathNameToNtPathName_U( name.Buffer, &nameW, NULL, NULL ))
3135                 status = STATUS_RESOURCE_DATA_NOT_FOUND;
3136             RtlFreeUnicodeString( &name );
3137         }
3138         if (status) return status;
3139     }
3140     else
3141     {
3142         if (!(buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0,
3143                                         (strlenW(filename) + 10) * sizeof(WCHAR) + sizeof(dotManifestW) )))
3144             return STATUS_NO_MEMORY;
3145         strcpyW( buffer, filename );
3146         if (resid != 1) sprintfW( buffer + strlenW(buffer), fmtW, resid );
3147         strcatW( buffer, dotManifestW );
3148         RtlInitUnicodeString( &nameW, buffer );
3149     }
3150 
3151     if (!open_nt_file( &file, &nameW ))
3152     {
3153         status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, FALSE, file );
3154         NtClose( file );
3155     }
3156     else status = STATUS_RESOURCE_TYPE_NOT_FOUND;
3157     RtlFreeUnicodeString( &nameW );
3158     return status;
3159 }
3160 
3161 static WCHAR *lookup_manifest_file( HANDLE dir, struct assembly_identity *ai )
3162 {
3163     static const WCHAR lookup_fmtW[] =
3164         {'%','s','_','%','s','_','%','s','_','%','u','.','%','u','.','*','.','*','_',
3165          '%','s','_','*','.','m','a','n','i','f','e','s','t',0};
3166     static const WCHAR wine_trailerW[] = {'d','e','a','d','b','e','e','f','.','m','a','n','i','f','e','s','t'};
3167 
3168     WCHAR *lookup, *ret = NULL;
3169     UNICODE_STRING lookup_us;
3170     IO_STATUS_BLOCK io;
3171     const WCHAR *lang = ai->language;
3172     unsigned int data_pos = 0, data_len;
3173     char buffer[8192];
3174 
3175     if (!(lookup = RtlAllocateHeap( RtlGetProcessHeap(), 0,
3176                                     (strlenW(ai->arch) + strlenW(ai->name)
3177                                      + strlenW(ai->public_key) + 20) * sizeof(WCHAR)
3178                                     + sizeof(lookup_fmtW) )))
3179         return NULL;
3180 
3181     if (!lang || !strcmpiW( lang, neutralW )) lang = wildcardW;
3182     sprintfW( lookup, lookup_fmtW, ai->arch, ai->name, ai->public_key,
3183               ai->version.major, ai->version.minor, lang );
3184     RtlInitUnicodeString( &lookup_us, lookup );
3185 
3186     if (!NtQueryDirectoryFile( dir, 0, NULL, NULL, &io, buffer, sizeof(buffer),
3187                                FileBothDirectoryInformation, FALSE, &lookup_us, TRUE ))
3188     {
3189         ULONG min_build = ai->version.build, min_revision = ai->version.revision;
3190         FILE_BOTH_DIR_INFORMATION *dir_info;
3191         WCHAR *tmp;
3192         ULONG build, revision;
3193 
3194         data_len = (ULONG)io.Information;
3195 
3196         for (;;)
3197         {
3198             if (data_pos >= data_len)
3199             {
3200                 if (NtQueryDirectoryFile( dir, 0, NULL, NULL, &io, buffer, sizeof(buffer),
3201                                           FileBothDirectoryInformation, FALSE, &lookup_us, FALSE ))
3202                     break;
3203                 data_len = (ULONG)io.Information;
3204                 data_pos = 0;
3205             }
3206             dir_info = (FILE_BOTH_DIR_INFORMATION*)(buffer + data_pos);
3207 
3208             if (dir_info->NextEntryOffset) data_pos += dir_info->NextEntryOffset;
3209             else data_pos = data_len;
3210 
3211             tmp = (WCHAR *)dir_info->FileName + (strchrW(lookup, '*') - lookup);
3212             build = atoiW(tmp);
3213             if (build < min_build) continue;
3214             tmp = strchrW(tmp, '.') + 1;
3215             revision = atoiW(tmp);
3216             if (build == min_build && revision < min_revision) continue;
3217             tmp = strchrW(tmp, '_') + 1;
3218             tmp = strchrW(tmp, '_') + 1;
3219             if (dir_info->FileNameLength - (tmp - dir_info->FileName) * sizeof(WCHAR) == sizeof(wine_trailerW) &&
3220                 !memicmpW( tmp, wine_trailerW, sizeof(wine_trailerW) / sizeof(WCHAR) ))
3221             {
3222                 /* prefer a non-Wine manifest if we already have one */
3223                 /* we'll still load the builtin dll if specified through DllOverrides */
3224                 if (ret) continue;
3225             }
3226             else
3227             {
3228                 min_build = build;
3229                 min_revision = revision;
3230             }
3231             ai->version.build = build;
3232             ai->version.revision = revision;
3233             RtlFreeHeap( RtlGetProcessHeap(), 0, ret );
3234             if ((ret = RtlAllocateHeap( RtlGetProcessHeap(), 0, dir_info->FileNameLength + sizeof(WCHAR) )))
3235             {
3236                 memcpy( ret, dir_info->FileName, dir_info->FileNameLength );
3237                 ret[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
3238             }
3239         }
3240     }
3241     else DPRINT1("no matching file for %S\n", lookup);
3242     RtlFreeHeap( RtlGetProcessHeap(), 0, lookup );
3243     return ret;
3244 }
3245 
3246 static NTSTATUS lookup_winsxs(struct actctx_loader* acl, struct assembly_identity* ai)
3247 {
3248     struct assembly_identity    sxs_ai;
3249     UNICODE_STRING              path_us;
3250     OBJECT_ATTRIBUTES           attr;
3251     IO_STATUS_BLOCK             io;
3252     WCHAR *path, *file = NULL;
3253     HANDLE handle;
3254 
3255     static const WCHAR manifest_dirW[] =
3256         {'\\','w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s',0};
3257 
3258     if (!ai->arch || !ai->name || !ai->public_key) return STATUS_NO_SUCH_FILE;
3259 
3260     if (!(path = RtlAllocateHeap( RtlGetProcessHeap(), 0,
3261                                   ((strlenW(SharedUserData->NtSystemRoot) + 1) *sizeof(WCHAR)) + sizeof(manifest_dirW) )))
3262         return STATUS_NO_MEMORY;
3263 
3264     memcpy( path, SharedUserData->NtSystemRoot, strlenW(SharedUserData->NtSystemRoot) * sizeof(WCHAR) );
3265     memcpy( path + strlenW(SharedUserData->NtSystemRoot), manifest_dirW, sizeof(manifest_dirW) );
3266 
3267     if (!RtlDosPathNameToNtPathName_U( path, &path_us, NULL, NULL ))
3268     {
3269         RtlFreeHeap( RtlGetProcessHeap(), 0, path );
3270         return STATUS_NO_SUCH_FILE;
3271     }
3272     RtlFreeHeap( RtlGetProcessHeap(), 0, path );
3273 
3274     attr.Length = sizeof(attr);
3275     attr.RootDirectory = 0;
3276     attr.Attributes = OBJ_CASE_INSENSITIVE;
3277     attr.ObjectName = &path_us;
3278     attr.SecurityDescriptor = NULL;
3279     attr.SecurityQualityOfService = NULL;
3280 
3281     if (!NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
3282                      FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))
3283     {
3284         sxs_ai = *ai;
3285         file = lookup_manifest_file( handle, &sxs_ai );
3286         NtClose( handle );
3287     }
3288     if (!file)
3289     {
3290         RtlFreeUnicodeString( &path_us );
3291         return STATUS_NO_SUCH_FILE;
3292     }
3293 
3294     /* append file name to directory path */
3295     if (!(path = RtlReAllocateHeap( RtlGetProcessHeap(), 0, path_us.Buffer,
3296                                     path_us.Length + (strlenW(file) + 2) * sizeof(WCHAR) )))
3297     {
3298         RtlFreeHeap( RtlGetProcessHeap(), 0, file );
3299         RtlFreeUnicodeString( &path_us );
3300         return STATUS_NO_MEMORY;
3301     }
3302 
3303     path[path_us.Length/sizeof(WCHAR)] = '\\';
3304     strcpyW( path + path_us.Length/sizeof(WCHAR) + 1, file );
3305     RtlInitUnicodeString( &path_us, path );
3306     *strrchrW(file, '.') = 0;  /* remove .manifest extension */
3307 
3308     if (!open_nt_file( &handle, &path_us ))
3309     {
3310         io.Status = get_manifest_in_manifest_file(acl, &sxs_ai, path_us.Buffer, file, TRUE, handle);
3311         NtClose( handle );
3312     }
3313     else io.Status = STATUS_NO_SUCH_FILE;
3314 
3315     RtlFreeHeap( RtlGetProcessHeap(), 0, file );
3316     RtlFreeUnicodeString( &path_us );
3317     return io.Status;
3318 }
3319 
3320 static NTSTATUS lookup_assembly(struct actctx_loader* acl,
3321                                 struct assembly_identity* ai)
3322 {
3323     static const WCHAR dotDllW[] = {'.','d','l','l',0};
3324     unsigned int i;
3325     WCHAR *buffer, *p, *directory;
3326     NTSTATUS status;
3327     UNICODE_STRING nameW;
3328     HANDLE file;
3329     DWORD len;
3330 
3331     DPRINT( "looking for name=%S version=%u.%u.%u.%u arch=%S\n",
3332             ai->name, ai->version.major, ai->version.minor, ai->version.build, ai->version.revision, ai->arch );
3333 
3334     if ((status = lookup_winsxs(acl, ai)) != STATUS_NO_SUCH_FILE) return status;
3335 
3336     /* FIXME: add support for language specific lookup */
3337 
3338     len = max(RtlGetFullPathName_U(acl->actctx->assemblies->manifest.info, 0, NULL, NULL) / sizeof(WCHAR),
3339         strlenW(acl->actctx->appdir.info));
3340 
3341     nameW.Buffer = NULL;
3342     if (!(buffer = RtlAllocateHeap( RtlGetProcessHeap(), 0,
3343                                     (len + 2 * strlenW(ai->name) + 2) * sizeof(WCHAR) + sizeof(dotManifestW) )))
3344         return STATUS_NO_MEMORY;
3345 
3346     if (!(directory = build_assembly_dir( ai )))
3347     {
3348         RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
3349         return STATUS_NO_MEMORY;
3350     }
3351 
3352     /* Lookup in <dir>\name.dll
3353      *           <dir>\name.manifest
3354      *           <dir>\name\name.dll
3355      *           <dir>\name\name.manifest
3356      *
3357      * First 'appdir' is used as <dir>, if that failed
3358      * it tries application manifest file path.
3359      */
3360     strcpyW( buffer, acl->actctx->appdir.info );
3361     p = buffer + strlenW(buffer);
3362     for (i = 0; i < 4; i++)
3363     {
3364         if (i == 2)
3365         {
3366             struct assembly *assembly = acl->actctx->assemblies;
3367             if (!RtlGetFullPathName_U(assembly->manifest.info, len * sizeof(WCHAR), buffer, &p)) break;
3368         }
3369         else *p++ = '\\';
3370 
3371         strcpyW( p, ai->name );
3372         p += strlenW(p);
3373 
3374         strcpyW( p, dotDllW );
3375         if (RtlDosPathNameToNtPathName_U( buffer, &nameW, NULL, NULL ))
3376         {
3377             status = open_nt_file( &file, &nameW );
3378             if (!status)
3379             {
3380                 status = get_manifest_in_pe_file( acl, ai, nameW.Buffer, directory, FALSE, file,
3381                                                   (LPCWSTR)0, 0 );
3382                 NtClose( file );
3383                 break;
3384             }
3385             RtlFreeUnicodeString( &nameW );
3386         }
3387 
3388         strcpyW( p, dotManifestW );
3389         if (RtlDosPathNameToNtPathName_U( buffer, &nameW, NULL, NULL ))
3390         {
3391             status = open_nt_file( &file, &nameW );
3392             if (!status)
3393             {
3394                 status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, FALSE, file );
3395                 NtClose( file );
3396                 break;
3397             }
3398             RtlFreeUnicodeString( &nameW );
3399         }
3400         status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
3401     }
3402     RtlFreeUnicodeString( &nameW );
3403     RtlFreeHeap( RtlGetProcessHeap(), 0, directory );
3404     RtlFreeHeap( RtlGetProcessHeap(), 0, buffer );
3405     return status;
3406 }
3407 
3408 static NTSTATUS parse_depend_manifests(struct actctx_loader* acl)
3409 {
3410     NTSTATUS status = STATUS_SUCCESS;
3411     unsigned int i;
3412 
3413     for (i = 0; i < acl->num_dependencies; i++)
3414     {
3415         if (lookup_assembly(acl, &acl->dependencies[i]) != STATUS_SUCCESS)
3416         {
3417             if (!acl->dependencies[i].optional && !acl->dependencies[i].delayed)
3418             {
3419                 const struct assembly_version *ver = &acl->dependencies[i].version;
3420                 DPRINT1( "Could not find dependent assembly %S (%u.%u.%u.%u)\n",
3421                     acl->dependencies[i].name,
3422                     ver->major, ver->minor, ver->build, ver->revision );
3423                 status = STATUS_SXS_CANT_GEN_ACTCTX;
3424                 break;
3425             }
3426         }
3427     }
3428     /* FIXME should now iterate through all refs */
3429     return status;
3430 }
3431 
3432 /* find the appropriate activation context for RtlQueryInformationActivationContext */
3433 static NTSTATUS find_query_actctx( HANDLE *handle, DWORD flags, ULONG class )
3434 {
3435     NTSTATUS status = STATUS_SUCCESS;
3436 
3437     if (flags & RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT)
3438     {
3439         if (*handle) return STATUS_INVALID_PARAMETER;
3440 
3441         if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
3442             *handle = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext;
3443     }
3444     else if (flags & (RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS | RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE))
3445     {
3446         ULONG_PTR magic;
3447         LDR_DATA_TABLE_ENTRY *pldr;
3448 
3449         if (!*handle) return STATUS_INVALID_PARAMETER;
3450 
3451         LdrLockLoaderLock( 0, NULL, &magic );
3452         if (!LdrFindEntryForAddress( *handle, &pldr ))
3453         {
3454             if ((flags & RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE) && *handle != pldr->DllBase)
3455                 status = STATUS_DLL_NOT_FOUND;
3456             else
3457                 *handle = pldr->EntryPointActivationContext;
3458         }
3459         else status = STATUS_DLL_NOT_FOUND;
3460         LdrUnlockLoaderLock( 0, magic );
3461     }
3462     else if (!*handle && (class != ActivationContextBasicInformation))
3463         *handle = process_actctx;
3464 
3465     return status;
3466 }
3467 
3468 static NTSTATUS build_dllredirect_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
3469 {
3470     unsigned int i, j, total_len = 0, dll_count = 0;
3471     struct strsection_header *header;
3472     struct dllredirect_data *data;
3473     struct string_index *index;
3474     ULONG name_offset;
3475 
3476     DPRINT("actctx %p, num_assemblies %d\n", actctx, actctx->num_assemblies);
3477 
3478     /* compute section length */
3479     for (i = 0; i < actctx->num_assemblies; i++)
3480     {
3481         struct assembly *assembly = &actctx->assemblies[i];
3482         for (j = 0; j < assembly->num_dlls; j++)
3483         {
3484             struct dll_redirect *dll = &assembly->dlls[j];
3485 
3486             /* each entry needs index, data and string data */
3487             total_len += sizeof(*index);
3488             total_len += sizeof(*data);
3489             total_len += aligned_string_len((strlenW(dll->name)+1)*sizeof(WCHAR));
3490 
3491             DPRINT("assembly %d (%p), dll %d: dll name %S\n", i, assembly, j, dll->name);
3492         }
3493 
3494         dll_count += assembly->num_dlls;
3495     }
3496 
3497     total_len += sizeof(*header);
3498 
3499     header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
3500     if (!header) return STATUS_NO_MEMORY;
3501 
3502     memset(header, 0, sizeof(*header));
3503     header->magic = STRSECTION_MAGIC;
3504     header->size  = sizeof(*header);
3505     header->count = dll_count;
3506     header->index_offset = sizeof(*header);
3507     index = (struct string_index*)((BYTE*)header + header->index_offset);
3508     name_offset = header->index_offset + header->count*sizeof(*index);
3509 
3510     for (i = 0; i < actctx->num_assemblies; i++)
3511     {
3512         struct assembly *assembly = &actctx->assemblies[i];
3513 
3514         DPRINT("assembly->num_dlls %d\n", assembly->num_dlls);
3515 
3516         for (j = 0; j < assembly->num_dlls; j++)
3517         {
3518             struct dll_redirect *dll = &assembly->dlls[j];
3519             UNICODE_STRING str;
3520             WCHAR *ptrW;
3521 
3522             DPRINT("%d: dll name %S\n", j, dll->name);
3523             /* setup new index entry */
3524             str.Buffer = dll->name;
3525             str.Length = (USHORT)strlenW(dll->name)*sizeof(WCHAR);
3526             str.MaximumLength = str.Length + sizeof(WCHAR);
3527             /* hash original class name */
3528             RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &index->hash);
3529 
3530             index->name_offset = name_offset;
3531             index->name_len = str.Length;
3532             index->data_offset = index->name_offset + aligned_string_len(str.MaximumLength);
3533             index->data_len = sizeof(*data);
3534             index->rosterindex = i + 1;
3535 
3536             /* setup data */
3537             data = (struct dllredirect_data*)((BYTE*)header + index->data_offset);
3538             data->size = sizeof(*data);
3539             data->unk = 2; /* FIXME: seems to be constant */
3540             memset(data->res, 0, sizeof(data->res));
3541 
3542             /* dll name */
3543             ptrW = (WCHAR*)((BYTE*)header + index->name_offset);
3544             memcpy(ptrW, dll->name, index->name_len);
3545             ptrW[index->name_len/sizeof(WCHAR)] = 0;
3546 
3547             name_offset += sizeof(*data) + aligned_string_len(str.MaximumLength);
3548 
3549             index++;
3550         }
3551     }
3552 
3553     *section = header;
3554 
3555     return STATUS_SUCCESS;
3556 }
3557 
3558 static struct string_index *find_string_index(const struct strsection_header *section, const UNICODE_STRING *name)
3559 {
3560     struct string_index *iter, *index = NULL;
3561     ULONG hash = 0, i;
3562 
3563     DPRINT("section %p, name %wZ\n", section, name);
3564     RtlHashUnicodeString(name, TRUE, HASH_STRING_ALGORITHM_X65599, &hash);
3565     iter = (struct string_index*)((BYTE*)section + section->index_offset);
3566 
3567     for (i = 0; i < section->count; i++)
3568     {
3569         DPRINT("iter->hash 0x%x ?= 0x%x\n", iter->hash, hash);
3570         DPRINT("iter->name %S\n", (WCHAR*)((BYTE*)section + iter->name_offset));
3571         if (iter->hash == hash)
3572         {
3573             const WCHAR *nameW = (WCHAR*)((BYTE*)section + iter->name_offset);
3574 
3575             if (!_wcsnicmp(nameW, name->Buffer, name->Length / sizeof(WCHAR)) &&
3576                 wcslen(nameW) == name->Length / sizeof(WCHAR))
3577             {
3578                 index = iter;
3579                 break;
3580             }
3581             else
3582                 DPRINT1("hash collision 0x%08x, %wZ, %S\n", hash, name, nameW);
3583         }
3584         iter++;
3585     }
3586 
3587     return index;
3588 }
3589 
3590 static struct guid_index *find_guid_index(const struct guidsection_header *section, const GUID *guid)
3591 {
3592     struct guid_index *iter, *index = NULL;
3593     ULONG i;
3594 
3595     iter = (struct guid_index*)((BYTE*)section + section->index_offset);
3596 
3597     for (i = 0; i < section->count; i++)
3598     {
3599         if (!memcmp(guid, &iter->guid, sizeof(*guid)))
3600         {
3601             index = iter;
3602             break;
3603         }
3604         iter++;
3605     }
3606 
3607     return index;
3608 }
3609 
3610 static inline struct dllredirect_data *get_dllredirect_data(ACTIVATION_CONTEXT *ctxt, struct string_index *index)
3611 {
3612     return (struct dllredirect_data*)((BYTE*)ctxt->dllredirect_section + index->data_offset);
3613 }
3614 
3615 static NTSTATUS find_dll_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
3616                                      PACTCTX_SECTION_KEYED_DATA data)
3617 {
3618     struct dllredirect_data *dll;
3619     struct string_index *index;
3620 
3621     DPRINT("sections: 0x%08X\n", actctx->sections);
3622     if (!(actctx->sections & DLLREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
3623 
3624     DPRINT("actctx->dllredirect_section: %p\n", actctx->dllredirect_section);
3625     if (!actctx->dllredirect_section)
3626     {
3627         struct strsection_header *section;
3628 
3629         NTSTATUS status = build_dllredirect_section(actctx, &section);
3630         if (status) return status;
3631 
3632         if (InterlockedCompareExchangePointer((void**)&actctx->dllredirect_section, section, NULL))
3633             RtlFreeHeap(RtlGetProcessHeap(), 0, section);
3634     }
3635 
3636     index = find_string_index(actctx->dllredirect_section, name);
3637     DPRINT("index: %d\n", index);
3638     if (!index) return STATUS_SXS_KEY_NOT_FOUND;
3639 
3640     if (data)
3641     {
3642         dll = get_dllredirect_data(actctx, index);
3643 
3644         data->ulDataFormatVersion = 1;
3645         data->lpData = dll;
3646         data->ulLength = dll->size;
3647         data->lpSectionGlobalData = NULL;
3648         data->ulSectionGlobalDataLength = 0;
3649         data->lpSectionBase = actctx->dllredirect_section;
3650         data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->dllredirect_section );
3651         data->hActCtx = NULL;
3652 
3653         if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
3654             data->ulAssemblyRosterIndex = index->rosterindex;
3655     }
3656 
3657     return STATUS_SUCCESS;
3658 }
3659 
3660 static inline struct string_index *get_wndclass_first_index(ACTIVATION_CONTEXT *actctx)
3661 {
3662     return (struct string_index*)((BYTE*)actctx->wndclass_section + actctx->wndclass_section->index_offset);
3663 }
3664 
3665 static inline struct wndclass_redirect_data *get_wndclass_data(ACTIVATION_CONTEXT *ctxt, struct string_index *index)
3666 {
3667     return (struct wndclass_redirect_data*)((BYTE*)ctxt->wndclass_section + index->data_offset);
3668 }
3669 
3670 static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
3671 {
3672     unsigned int i, j, k, total_len = 0, class_count = 0;
3673     struct wndclass_redirect_data *data;
3674     struct strsection_header *header;
3675     struct string_index *index;
3676     ULONG name_offset;
3677 
3678     /* compute section length */
3679     for (i = 0; i < actctx->num_assemblies; i++)
3680     {
3681         struct assembly *assembly = &actctx->assemblies[i];
3682         for (j = 0; j < assembly->num_dlls; j++)
3683         {
3684             struct dll_redirect *dll = &assembly->dlls[j];
3685             for (k = 0; k < dll->entities.num; k++)
3686             {
3687                 struct entity *entity = &dll->entities.base[k];
3688                 if (entity->kind == ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)
3689                 {
3690                     int class_len = strlenW(entity->u.class.name) + 1;
3691                     int len;
3692 
3693                     /* each class entry needs index, data and string data */
3694                     total_len += sizeof(*index);
3695                     total_len += sizeof(*data);
3696                     /* original name is stored separately */
3697                     total_len += aligned_string_len(class_len*sizeof(WCHAR));
3698                     /* versioned name and module name are stored one after another */
3699                     if (entity->u.class.versioned)
3700                         len = get_assembly_version(assembly, NULL) + class_len + 1 /* '!' separator */;
3701                     else
3702                         len = class_len;
3703                     len += strlenW(dll->name) + 1;
3704                     total_len += aligned_string_len(len*sizeof(WCHAR));
3705 
3706                     class_count++;
3707                 }
3708             }
3709         }
3710     }
3711 
3712     total_len += sizeof(*header);
3713 
3714     header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
3715     if (!header) return STATUS_NO_MEMORY;
3716 
3717     memset(header, 0, sizeof(*header));
3718     header->magic = STRSECTION_MAGIC;
3719     header->size  = sizeof(*header);
3720     header->count = class_count;
3721     header->index_offset = sizeof(*header);
3722     index = (struct string_index*)((BYTE*)header + header->index_offset);
3723     name_offset = header->index_offset + header->count*sizeof(*index);
3724 
3725     for (i = 0; i < actctx->num_assemblies; i++)
3726     {
3727         struct assembly *assembly = &actctx->assemblies[i];
3728         for (j = 0; j < assembly->num_dlls; j++)
3729         {
3730             struct dll_redirect *dll = &assembly->dlls[j];
3731             for (k = 0; k < dll->entities.num; k++)
3732             {
3733                 struct entity *entity = &dll->entities.base[k];
3734                 if (entity->kind == ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)
3735                 {
3736                     static const WCHAR exclW[] = {'!',0};
3737                     ULONG versioned_len, module_len;
3738                     UNICODE_STRING str;
3739                     WCHAR *ptrW;
3740 
3741                     /* setup new index entry */
3742                     str.Buffer = entity->u.class.name;
3743                     str.Length = (USHORT)strlenW(entity->u.class.name)*sizeof(WCHAR);
3744                     str.MaximumLength = str.Length + sizeof(WCHAR);
3745                     /* hash original class name */
3746                     RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &index->hash);
3747 
3748                     /* include '!' separator too */
3749                     if (entity->u.class.versioned)
3750                         versioned_len = (get_assembly_version(assembly, NULL) + 1)*sizeof(WCHAR) + str.Length;
3751                     else
3752                         versioned_len = str.Length;
3753                     module_len = strlenW(dll->name)*sizeof(WCHAR);
3754 
3755                     index->name_offset = name_offset;
3756                     index->name_len = str.Length;
3757                     index->data_offset = index->name_offset + aligned_string_len(str.MaximumLength);
3758                     index->data_len = sizeof(*data) + versioned_len + module_len + 2*sizeof(WCHAR) /* two nulls */;
3759                     index->rosterindex = i + 1;
3760 
3761                     /* setup data */
3762                     data = (struct wndclass_redirect_data*)((BYTE*)header + index->data_offset);
3763                     data->size = sizeof(*data);
3764                     data->res = 0;
3765                     data->name_len = versioned_len;
3766                     data->name_offset = sizeof(*data);
3767                     data->module_len = module_len;
3768                     data->module_offset = index->data_offset + data->name_offset + data->name_len + sizeof(WCHAR);
3769 
3770                     /* original class name */
3771                     ptrW = (WCHAR*)((BYTE*)header + index->name_offset);
3772                     memcpy(ptrW, entity->u.class.name, index->name_len);
3773                     ptrW[index->name_len/sizeof(WCHAR)] = 0;
3774 
3775                     /* module name */
3776                     ptrW = (WCHAR*)((BYTE*)header + data->module_offset);
3777                     memcpy(ptrW, dll->name, data->module_len);
3778                     ptrW[data->module_len/sizeof(WCHAR)] = 0;
3779 
3780                     /* versioned name */
3781                     ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
3782                     if (entity->u.class.versioned)
3783                     {
3784                         get_assembly_version(assembly, ptrW);
3785                         strcatW(ptrW, exclW);
3786                         strcatW(ptrW, entity->u.class.name);
3787                     }
3788                     else
3789                     {
3790                         memcpy(ptrW, entity->u.class.name, index->name_len);
3791                         ptrW[index->name_len/sizeof(WCHAR)] = 0;
3792                     }
3793 
3794                     name_offset += sizeof(*data);
3795                     name_offset += aligned_string_len(str.MaximumLength) + aligned_string_len(versioned_len + module_len + 2*sizeof(WCHAR));
3796 
3797                     index++;
3798                 }
3799             }
3800         }
3801     }
3802 
3803     *section = header;
3804 
3805     return STATUS_SUCCESS;
3806 }
3807 
3808 static NTSTATUS find_window_class(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
3809                                   PACTCTX_SECTION_KEYED_DATA data)
3810 {
3811     struct string_index *iter, *index = NULL;
3812     struct wndclass_redirect_data *class;
3813     ULONG hash;
3814     int i;
3815 
3816     if (!(actctx->sections & WINDOWCLASS_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
3817 
3818     if (!actctx->wndclass_section)
3819     {
3820         struct strsection_header *section;
3821 
3822         NTSTATUS status = build_wndclass_section(actctx, &section);
3823         if (status) return status;
3824 
3825         if (InterlockedCompareExchangePointer((void**)&actctx->wndclass_section, section, NULL))
3826             RtlFreeHeap(RtlGetProcessHeap(), 0, section);
3827     }
3828 
3829     hash = 0;
3830     RtlHashUnicodeString(name, TRUE, HASH_STRING_ALGORITHM_X65599, &hash);
3831     iter = get_wndclass_first_index(actctx);
3832 
3833     for (i = 0; i < actctx->wndclass_section->count; i++)
3834     {
3835         if (iter->hash == hash)
3836         {
3837             const WCHAR *nameW = (WCHAR*)((BYTE*)actctx->wndclass_section + iter->name_offset);
3838 
3839             if (!strcmpiW(nameW, name->Buffer))
3840             {
3841                 index = iter;
3842                 break;
3843             }
3844             else
3845                 DPRINT1("hash collision 0x%08x, %wZ, %S\n", hash, name, nameW);
3846         }
3847         iter++;
3848     }
3849 
3850     if (!index) return STATUS_SXS_KEY_NOT_FOUND;
3851 
3852     if (data)
3853     {
3854         class = get_wndclass_data(actctx, index);
3855 
3856         data->ulDataFormatVersion = 1;
3857         data->lpData = class;
3858         /* full length includes string length with nulls */
3859         data->ulLength = class->size + class->name_len + class->module_len + 2*sizeof(WCHAR);
3860         data->lpSectionGlobalData = NULL;
3861         data->ulSectionGlobalDataLength = 0;
3862         data->lpSectionBase = actctx->wndclass_section;
3863         data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->wndclass_section );
3864         data->hActCtx = NULL;
3865 
3866         if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
3867             data->ulAssemblyRosterIndex = index->rosterindex;
3868     }
3869 
3870     return STATUS_SUCCESS;
3871 }
3872 
3873 static NTSTATUS build_tlib_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
3874 {
3875     unsigned int i, j, k, total_len = 0, tlib_count = 0, names_len = 0;
3876     struct guidsection_header *header;
3877     ULONG module_offset, data_offset;
3878     struct tlibredirect_data *data;
3879     struct guid_index *index;
3880 
3881     /* compute section length */
3882     for (i = 0; i < actctx->num_assemblies; i++)
3883     {
3884         struct assembly *assembly = &actctx->assemblies[i];
3885         for (j = 0; j < assembly->num_dlls; j++)
3886         {
3887             struct dll_redirect *dll = &assembly->dlls[j];
3888             for (k = 0; k < dll->entities.num; k++)
3889             {
3890                 struct entity *entity = &dll->entities.base[k];
3891                 if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)
3892                 {
3893                     /* each entry needs index, data and string data for module name and help string */
3894                     total_len += sizeof(*index);
3895                     total_len += sizeof(*data);
3896                     /* help string is stored separately */
3897                     if (*entity->u.typelib.helpdir)
3898                         total_len += aligned_string_len((strlenW(entity->u.typelib.helpdir)+1)*sizeof(WCHAR));
3899 
3900                     /* module names are packed one after another */
3901                     names_len += (strlenW(dll->name)+1)*sizeof(WCHAR);
3902 
3903                     tlib_count++;
3904                 }
3905             }
3906         }
3907     }
3908 
3909     total_len += aligned_string_len(names_len);
3910     total_len += sizeof(*header);
3911 
3912     header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
3913     if (!header) return STATUS_NO_MEMORY;
3914 
3915     memset(header, 0, sizeof(*header));
3916     header->magic = GUIDSECTION_MAGIC;
3917     header->size  = sizeof(*header);
3918     header->count = tlib_count;
3919     header->index_offset = sizeof(*header) + aligned_string_len(names_len);
3920     index = (struct guid_index*)((BYTE*)header + header->index_offset);
3921     module_offset = sizeof(*header);
3922     data_offset = header->index_offset + tlib_count*sizeof(*index);
3923 
3924     for (i = 0; i < actctx->num_assemblies; i++)
3925     {
3926         struct assembly *assembly = &actctx->assemblies[i];
3927         for (j = 0; j < assembly->num_dlls; j++)
3928         {
3929             struct dll_redirect *dll = &assembly->dlls[j];
3930             for (k = 0; k < dll->entities.num; k++)
3931             {
3932                 struct entity *entity = &dll->entities.base[k];
3933                 if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)
3934                 {
3935                     ULONG module_len, help_len;
3936                     UNICODE_STRING str;
3937                     WCHAR *ptrW;
3938 
3939                     if (*entity->u.typelib.helpdir)
3940                         help_len = strlenW(entity->u.typelib.helpdir)*sizeof(WCHAR);
3941                     else
3942                         help_len = 0;
3943 
3944                     module_len = strlenW(dll->name)*sizeof(WCHAR);
3945 
3946                     /* setup new index entry */
3947                     RtlInitUnicodeString(&str, entity->u.typelib.tlbid);
3948                     RtlGUIDFromString(&str, &index->guid);
3949                     index->data_offset = data_offset;
3950                     index->data_len = sizeof(*data) + aligned_string_len(help_len);
3951                     index->rosterindex = i + 1;
3952 
3953                     /* setup data */
3954                     data = (struct tlibredirect_data*)((BYTE*)header + index->data_offset);
3955                     data->size = sizeof(*data);
3956                     data->res = 0;
3957                     data->name_len = module_len;
3958                     data->name_offset = module_offset;
3959                     /* FIXME: resourceid handling is really weird, and it doesn't seem to be useful */
3960                     data->langid = 0;
3961                     data->flags = entity->u.typelib.flags;
3962                     data->help_len = help_len;
3963                     data->help_offset = sizeof(*data);
3964                     data->major_version = entity->u.typelib.major;
3965                     data->minor_version = entity->u.typelib.minor;
3966 
3967                     /* module name */
3968                     ptrW = (WCHAR*)((BYTE*)header + data->name_offset);
3969                     memcpy(ptrW, dll->name, data->name_len);
3970                     ptrW[data->name_len/sizeof(WCHAR)] = 0;
3971 
3972                     /* help string */
3973                     if (data->help_len)
3974                     {
3975                         ptrW = (WCHAR*)((BYTE*)data + data->help_offset);
3976                         memcpy(ptrW, entity->u.typelib.helpdir, data->help_len);
3977                         ptrW[data->help_len/sizeof(WCHAR)] = 0;
3978                     }
3979 
3980                     data_offset += sizeof(*data);
3981                     if (help_len)
3982                         data_offset += aligned_string_len(help_len + sizeof(WCHAR));
3983 
3984                     module_offset += module_len + sizeof(WCHAR);
3985 
3986                     index++;
3987                 }
3988             }
3989         }
3990     }
3991 
3992     *section = header;
3993 
3994     return STATUS_SUCCESS;
3995 }
3996 
3997 static inline struct tlibredirect_data *get_tlib_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
3998 {
3999     return (struct tlibredirect_data*)((BYTE*)actctx->tlib_section + index->data_offset);
4000 }
4001 
4002 static NTSTATUS find_tlib_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
4003 {
4004     struct guid_index *index = NULL;
4005     struct tlibredirect_data *tlib;
4006 
4007     if (!(actctx->sections & TLIBREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
4008 
4009     if (!actctx->tlib_section)
4010     {
4011         struct guidsection_header *section;
4012 
4013         NTSTATUS status = build_tlib_section(actctx, &section);
4014         if (status) return status;
4015 
4016         if (InterlockedCompareExchangePointer((void**)&actctx->tlib_section, section, NULL))
4017             RtlFreeHeap(RtlGetProcessHeap(), 0, section);
4018     }
4019 
4020     index = find_guid_index(actctx->tlib_section, guid);
4021     if (!index) return STATUS_SXS_KEY_NOT_FOUND;
4022 
4023     tlib = get_tlib_data(actctx, index);
4024 
4025     data->ulDataFormatVersion = 1;
4026     data->lpData = tlib;
4027     /* full length includes string length with nulls */
4028     data->ulLength = tlib->size + tlib->help_len + sizeof(WCHAR);
4029     data->lpSectionGlobalData = (BYTE*)actctx->tlib_section + actctx->tlib_section->names_offset;
4030     data->ulSectionGlobalDataLength = actctx->tlib_section->names_len;
4031     data->lpSectionBase = actctx->tlib_section;
4032     data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->tlib_section );
4033     data->hActCtx = NULL;
4034 
4035     if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
4036         data->ulAssemblyRosterIndex = index->rosterindex;
4037 
4038     return STATUS_SUCCESS;
4039 }
4040 
4041 static void generate_uuid(ULONG *seed, GUID *guid)
4042 {
4043     ULONG *ptr = (ULONG*)guid;
4044     int i;
4045 
4046     /* GUID is 16 bytes long */
4047     for (i = 0; i < sizeof(GUID)/sizeof(ULONG); i++, ptr++)
4048         *ptr = RtlUniform(seed);
4049 
4050     guid->Data3 &= 0x0fff;
4051     guid->Data3 |= (4 << 12);
4052     guid->Data4[0] &= 0x3f;
4053     guid->Data4[0] |= 0x80;
4054 }
4055 
4056 static void get_comserver_datalen(const struct entity_array *entities, const struct dll_redirect *dll,
4057     unsigned int *count, unsigned int *len, unsigned int *module_len)
4058 {
4059     unsigned int i;
4060 
4061     for (i = 0; i < entities->num; i++)
4062     {
4063         struct entity *entity = &entities->base[i];
4064         if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
4065         {
4066             /* each entry needs two index entries, extra one goes for alias GUID */
4067             *len += 2*sizeof(struct guid_index);
4068             /* To save some memory we don't allocated two data structures,
4069                instead alias index and normal index point to the same data structure. */
4070             *len += sizeof(struct comclassredirect_data);
4071 
4072             /* for clrClass store some more */
4073             if (entity->u.comclass.name)
4074             {
4075                 unsigned int str_len;
4076 
4077                 /* all string data is stored together in aligned block */
4078                 str_len = strlenW(entity->u.comclass.name)+1;
4079                 if (entity->u.comclass.progid)
4080                     str_len += strlenW(entity->u.comclass.progid)+1;
4081                 if (entity->u.comclass.version)
4082                     str_len += strlenW(entity->u.comclass.version)+1;
4083 
4084                 *len += sizeof(struct clrclass_data);
4085                 *len += aligned_string_len(str_len*sizeof(WCHAR));
4086 
4087                 /* module name is forced to mscoree.dll, and stored two times with different case */
4088                 *module_len += sizeof(mscoreeW) + sizeof(mscoree2W);
4089             }
4090             else
4091             {
4092                 /* progid string is stored separately */
4093                 if (entity->u.comclass.progid)
4094                     *len += aligned_string_len((strlenW(entity->u.comclass.progid)+1)*sizeof(WCHAR));
4095 
4096                 *module_len += (strlenW(dll->name)+1)*sizeof(WCHAR);
4097             }
4098 
4099             *count += 1;
4100         }
4101     }
4102 }
4103 
4104 static void add_comserver_record(const struct guidsection_header *section, const struct entity_array *entities,
4105     const struct dll_redirect *dll, struct guid_index **index, ULONG *data_offset, ULONG *module_offset,
4106     ULONG *seed, ULONG rosterindex)
4107 {
4108     unsigned int i;
4109 
4110     for (i = 0; i < entities->num; i++)
4111     {
4112         struct entity *entity = &entities->base[i];
4113         if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
4114         {
4115             ULONG module_len, progid_len, str_len = 0;
4116             struct comclassredirect_data *data;
4117             struct guid_index *alias_index;
4118             struct clrclass_data *clrdata;
4119             UNICODE_STRING str;
4120             WCHAR *ptrW;
4121 
4122             if (entity->u.comclass.progid)
4123                 progid_len = strlenW(entity->u.comclass.progid)*sizeof(WCHAR);
4124             else
4125                 progid_len = 0;
4126 
4127             module_len = dll ? strlenW(dll->name)*sizeof(WCHAR) : strlenW(mscoreeW)*sizeof(WCHAR);
4128 
4129             /* setup new index entry */
4130             RtlInitUnicodeString(&str, entity->u.comclass.clsid);
4131             RtlGUIDFromString(&str, &(*index)->guid);
4132 
4133             (*index)->data_offset = *data_offset;
4134             (*index)->data_len = sizeof(*data); /* additional length added later */
4135             (*index)->rosterindex = rosterindex;
4136 
4137             /* Setup new index entry for alias guid. Alias index records are placed after
4138                normal records, so normal guids are hit first on search. Note that class count
4139                is doubled. */
4140             alias_index = (*index) + section->count/2;
4141             generate_uuid(seed, &alias_index->guid);
4142             alias_index->data_offset = (*index)->data_offset;
4143             alias_index->data_len = 0;
4144             alias_index->rosterindex = (*index)->rosterindex;
4145 
4146             /* setup data */
4147             data = (struct comclassredirect_data*)((BYTE*)section + (*index)->data_offset);
4148             data->size = sizeof(*data);
4149             data->res = 0;
4150             data->res1[0] = 0;
4151             data->res1[1] = 0;
4152             data->model = entity->u.comclass.model;
4153             data->clsid = (*index)->guid;
4154             data->alias = alias_index->guid;
4155             data->clsid2 = data->clsid;
4156             if (entity->u.comclass.tlbid)
4157             {
4158                 RtlInitUnicodeString(&str, entity->u.comclass.tlbid);
4159                 RtlGUIDFromString(&str, &data->tlbid);
4160             }
4161             else
4162                 memset(&data->tlbid, 0, sizeof(data->tlbid));
4163             data->name_len = module_len;
4164             data->name_offset = *module_offset;
4165             data->progid_len = progid_len;
4166             data->progid_offset = data->progid_len ? data->size : 0; /* in case of clrClass additional offset is added later */
4167             data->clrdata_len = 0; /* will be set later */
4168             data->clrdata_offset = entity->u.comclass.name ? sizeof(*data) : 0;
4169             data->miscstatus = entity->u.comclass.miscstatus;
4170             data->miscstatuscontent = entity->u.comclass.miscstatuscontent;
4171             data->miscstatusthumbnail = entity->u.comclass.miscstatusthumbnail;
4172             data->miscstatusicon = entity->u.comclass.miscstatusicon;
4173             data->miscstatusdocprint = entity->u.comclass.miscstatusdocprint;
4174 
4175             /* mask describes which misc* data is available */
4176             data->miscmask = 0;
4177             if (data->miscstatus)
4178                 data->miscmask |= MiscStatus;
4179             if (data->miscstatuscontent)
4180                 data->miscmask |= MiscStatusContent;
4181             if (data->miscstatusthumbnail)
4182                 data->miscmask |= MiscStatusThumbnail;
4183             if (data->miscstatusicon)
4184                 data->miscmask |= MiscStatusIcon;
4185             if (data->miscstatusdocprint)
4186                 data->miscmask |= MiscStatusDocPrint;
4187 
4188             if (data->clrdata_offset)
4189             {
4190                 clrdata = (struct clrclass_data*)((BYTE*)data + data->clrdata_offset);
4191 
4192                 clrdata->size = sizeof(*clrdata);
4193                 clrdata->res[0] = 0;
4194                 clrdata->res[1] = 2; /* FIXME: unknown field */
4195                 clrdata->module_len = strlenW(mscoreeW)*sizeof(WCHAR);
4196                 clrdata->module_offset = *module_offset + data->name_len + sizeof(WCHAR);
4197                 clrdata->name_len = strlenW(entity->u.comclass.name)*sizeof(WCHAR);
4198                 clrdata->name_offset = clrdata->size;
4199                 clrdata->version_len = entity->u.comclass.version ? strlenW(entity->u.comclass.version)*sizeof(WCHAR) : 0;
4200                 clrdata->version_offset = clrdata->version_len ? clrdata->name_offset + clrdata->name_len + sizeof(WCHAR) : 0;
4201                 clrdata->res2[0] = 0;
4202                 clrdata->res2[1] = 0;
4203 
4204                 data->clrdata_len = clrdata->size + clrdata->name_len + sizeof(WCHAR);
4205 
4206                 /* module name */
4207                 ptrW = (WCHAR*)((BYTE*)section + clrdata->module_offset);
4208                 memcpy(ptrW, mscoree2W, clrdata->module_len);
4209                 ptrW[clrdata->module_len/sizeof(WCHAR)] = 0;
4210 
4211                 ptrW = (WCHAR*)((BYTE*)section + data->name_offset);
4212                 memcpy(ptrW, mscoreeW, data->name_len);
4213                 ptrW[data->name_len/sizeof(WCHAR)] = 0;
4214 
4215                 /* class name */
4216                 ptrW = (WCHAR*)((BYTE*)clrdata + clrdata->name_offset);
4217                 memcpy(ptrW, entity->u.comclass.name, clrdata->name_len);
4218                 ptrW[clrdata->name_len/sizeof(WCHAR)] = 0;
4219 
4220                 /* runtime version, optional */
4221                 if (clrdata->version_len)
4222                 {
4223                     data->clrdata_len += clrdata->version_len + sizeof(WCHAR);
4224 
4225                     ptrW = (WCHAR*)((BYTE*)clrdata + clrdata->version_offset);
4226                     memcpy(ptrW, entity->u.comclass.version, clrdata->version_len);
4227                     ptrW[clrdata->version_len/sizeof(WCHAR)] = 0;
4228                 }
4229 
4230                 if (data->progid_len)
4231                     data->progid_offset += data->clrdata_len;
4232                 (*index)->data_len += sizeof(*clrdata);
4233             }
4234             else
4235             {
4236                 clrdata = NULL;
4237 
4238                 /* module name */
4239                 ptrW = (WCHAR*)((BYTE*)section + data->name_offset);
4240                 memcpy(ptrW, dll->name, data->name_len);
4241                 ptrW[data->name_len/sizeof(WCHAR)] = 0;
4242             }
4243 
4244             /* progid string */
4245             if (data->progid_len)
4246             {
4247                 ptrW = (WCHAR*)((BYTE*)data + data->progid_offset);
4248                 memcpy(ptrW, entity->u.comclass.progid, data->progid_len);
4249                 ptrW[data->progid_len/sizeof(WCHAR)] = 0;
4250             }
4251 
4252             /* string block length */
4253             str_len = 0;
4254             if (clrdata)
4255             {
4256                 str_len += clrdata->name_len + sizeof(WCHAR);
4257                 if (clrdata->version_len)
4258                     str_len += clrdata->version_len + sizeof(WCHAR);
4259             }
4260             if (progid_len)
4261                 str_len += progid_len + sizeof(WCHAR);
4262 
4263             (*index)->data_len += aligned_string_len(str_len);
4264             alias_index->data_len = (*index)->data_len;
4265 
4266             /* move to next data record */
4267             (*data_offset) += sizeof(*data) + aligned_string_len(str_len);
4268             (*module_offset) += module_len + sizeof(WCHAR);
4269 
4270             if (clrdata)
4271             {
4272                 (*data_offset) += sizeof(*clrdata);
4273                 (*module_offset) += clrdata->module_len + sizeof(WCHAR);
4274             }
4275             (*index) += 1;
4276         }
4277     }
4278 }
4279 
4280 static NTSTATUS build_comserver_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
4281 {
4282     unsigned int i, j, total_len = 0, class_count = 0, names_len = 0;
4283     struct guidsection_header *header;
4284     ULONG module_offset, data_offset;
4285     struct guid_index *index;
4286     ULONG seed;
4287 
4288     /* compute section length */
4289     for (i = 0; i < actctx->num_assemblies; i++)
4290     {
4291         struct assembly *assembly = &actctx->assemblies[i];
4292         get_comserver_datalen(&assembly->entities, NULL, &class_count, &total_len, &names_len);
4293         for (j = 0; j < assembly->num_dlls; j++)
4294         {
4295             struct dll_redirect *dll = &assembly->dlls[j];
4296             get_comserver_datalen(&dll->entities, dll, &class_count, &total_len, &names_len);
4297         }
4298     }
4299 
4300     total_len += aligned_string_len(names_len);
4301     total_len += sizeof(*header);
4302 
4303     header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
4304     if (!header) return STATUS_NO_MEMORY;
4305 
4306     memset(header, 0, sizeof(*header));
4307     header->magic = GUIDSECTION_MAGIC;
4308     header->size  = sizeof(*header);
4309     header->count = 2*class_count;
4310     header->index_offset = sizeof(*header) + aligned_string_len(names_len);
4311     index = (struct guid_index*)((BYTE*)header + header->index_offset);
4312     module_offset = sizeof(*header);
4313     data_offset = header->index_offset + 2*class_count*sizeof(*index);
4314 
4315     seed = NtGetTickCount();
4316     for (i = 0; i < actctx->num_assemblies; i++)
4317     {
4318         struct assembly *assembly = &actctx->assemblies[i];
4319         add_comserver_record(header, &assembly->entities, NULL, &index, &data_offset, &module_offset, &seed, i+1);
4320         for (j = 0; j < assembly->num_dlls; j++)
4321         {
4322             struct dll_redirect *dll = &assembly->dlls[j];
4323             add_comserver_record(header, &dll->entities, dll, &index, &data_offset, &module_offset, &seed, i+1);
4324         }
4325     }
4326 
4327     *section = header;
4328 
4329     return STATUS_SUCCESS;
4330 }
4331 
4332 static inline struct comclassredirect_data *get_comclass_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
4333 {
4334     return (struct comclassredirect_data*)((BYTE*)actctx->comserver_section + index->data_offset);
4335 }
4336 
4337 static NTSTATUS find_comserver_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
4338 {
4339     struct comclassredirect_data *comclass;
4340     struct guid_index *index = NULL;
4341 
4342     if (!(actctx->sections & SERVERREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
4343 
4344     if (!actctx->comserver_section)
4345     {
4346         struct guidsection_header *section;
4347 
4348         NTSTATUS status = build_comserver_section(actctx, &section);
4349         if (status) return status;
4350 
4351         if (InterlockedCompareExchangePointer((void**)&actctx->comserver_section, section, NULL))
4352             RtlFreeHeap(RtlGetProcessHeap(), 0, section);
4353     }
4354 
4355     index = find_guid_index(actctx->comserver_section, guid);
4356     if (!index) return STATUS_SXS_KEY_NOT_FOUND;
4357 
4358     comclass = get_comclass_data(actctx, index);
4359 
4360     data->ulDataFormatVersion = 1;
4361     data->lpData = comclass;
4362     /* full length includes string length with nulls */
4363     data->ulLength = comclass->size + comclass->clrdata_len;
4364     if (comclass->progid_len) data->ulLength += comclass->progid_len + sizeof(WCHAR);
4365     data->lpSectionGlobalData = (BYTE*)actctx->comserver_section + actctx->comserver_section->names_offset;
4366     data->ulSectionGlobalDataLength = actctx->comserver_section->names_len;
4367     data->lpSectionBase = actctx->comserver_section;
4368     data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->comserver_section );
4369     data->hActCtx = NULL;
4370 
4371     if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
4372         data->ulAssemblyRosterIndex = index->rosterindex;
4373 
4374     return STATUS_SUCCESS;
4375 }
4376 
4377 static void get_ifaceps_datalen(const struct entity_array *entities, unsigned int *count, unsigned int *len)
4378 {
4379     unsigned int i;
4380 
4381     for (i = 0; i < entities->num; i++)
4382     {
4383         struct entity *entity = &entities->base[i];
4384         if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)
4385         {
4386             *len += sizeof(struct guid_index) + sizeof(struct ifacepsredirect_data);
4387             if (entity->u.ifaceps.name)
4388                 *len += aligned_string_len((strlenW(entity->u.ifaceps.name)+1)*sizeof(WCHAR));
4389             *count += 1;
4390         }
4391     }
4392 }
4393 
4394 static void add_ifaceps_record(struct guidsection_header *section, struct entity_array *entities,
4395     struct guid_index **index, ULONG *data_offset, ULONG rosterindex)
4396 {
4397     unsigned int i;
4398 
4399     for (i = 0; i < entities->num; i++)
4400     {
4401         struct entity *entity = &entities->base[i];
4402         if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)
4403         {
4404             struct ifacepsredirect_data *data = (struct ifacepsredirect_data*)((BYTE*)section + *data_offset);
4405             UNICODE_STRING str;
4406             ULONG name_len;
4407 
4408             if (entity->u.ifaceps.name)
4409                 name_len = strlenW(entity->u.ifaceps.name)*sizeof(WCHAR);
4410             else
4411                 name_len = 0;
4412 
4413             /* setup index */
4414             RtlInitUnicodeString(&str, entity->u.ifaceps.iid);
4415             RtlGUIDFromString(&str, &(*index)->guid);
4416             (*index)->data_offset = *data_offset;
4417             (*index)->data_len = sizeof(*data) + name_len ? aligned_string_len(name_len + sizeof(WCHAR)) : 0;
4418             (*index)->rosterindex = rosterindex;
4419 
4420             /* setup data record */
4421             data->size = sizeof(*data);
4422             data->mask = entity->u.ifaceps.mask;
4423 
4424             /* proxyStubClsid32 value is only stored for external PS,
4425                if set it's used as iid, otherwise 'iid' attribute value is used */
4426             if (entity->u.ifaceps.ps32)
4427             {
4428                 RtlInitUnicodeString(&str, entity->u.ifaceps.ps32);
4429                 RtlGUIDFromString(&str, &data->iid);
4430             }
4431             else
4432                 data->iid = (*index)->guid;
4433 
4434             data->nummethods = entity->u.ifaceps.nummethods;
4435 
4436             if (entity->u.ifaceps.tlib)
4437             {
4438                 RtlInitUnicodeString(&str, entity->u.ifaceps.tlib);
4439                 RtlGUIDFromString(&str, &data->tlbid);
4440             }
4441             else
4442                 memset(&data->tlbid, 0, sizeof(data->tlbid));
4443 
4444             if (entity->u.ifaceps.base)
4445             {
4446                 RtlInitUnicodeString(&str, entity->u.ifaceps.base);
4447                 RtlGUIDFromString(&str, &data->base);
4448             }
4449             else
4450                 memset(&data->base, 0, sizeof(data->base));
4451 
4452             data->name_len = name_len;
4453             data->name_offset = data->name_len ? sizeof(*data) : 0;
4454 
4455             /* name string */
4456             if (data->name_len)
4457             {
4458                 WCHAR *ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
4459                 memcpy(ptrW, entity->u.ifaceps.name, data->name_len);
4460                 ptrW[data->name_len/sizeof(WCHAR)] = 0;
4461             }
4462 
4463             /* move to next record */
4464             (*index) += 1;
4465             *data_offset += sizeof(*data);
4466             if (data->name_len)
4467                 *data_offset += aligned_string_len(data->name_len + sizeof(WCHAR));
4468         }
4469     }
4470 }
4471 
4472 static NTSTATUS build_ifaceps_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
4473 {
4474     unsigned int i, j, total_len = 0, count = 0;
4475     struct guidsection_header *header;
4476     struct guid_index *index;
4477     ULONG data_offset;
4478 
4479     /* compute section length */
4480     for (i = 0; i < actctx->num_assemblies; i++)
4481     {
4482         struct assembly *assembly = &actctx->assemblies[i];
4483 
4484         get_ifaceps_datalen(&assembly->entities, &count, &total_len);
4485         for (j = 0; j < assembly->num_dlls; j++)
4486         {
4487             struct dll_redirect *dll = &assembly->dlls[j];
4488             get_ifaceps_datalen(&dll->entities, &count, &total_len);
4489         }
4490     }
4491 
4492     total_len += sizeof(*header);
4493 
4494     header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
4495     if (!header) return STATUS_NO_MEMORY;
4496 
4497     memset(header, 0, sizeof(*header));
4498     header->magic = GUIDSECTION_MAGIC;
4499     header->size  = sizeof(*header);
4500     header->count = count;
4501     header->index_offset = sizeof(*header);
4502     index = (struct guid_index*)((BYTE*)header + header->index_offset);
4503     data_offset = header->index_offset + count*sizeof(*index);
4504 
4505     for (i = 0; i < actctx->num_assemblies; i++)
4506     {
4507         struct assembly *assembly = &actctx->assemblies[i];
4508 
4509         add_ifaceps_record(header, &assembly->entities, &index, &data_offset, i + 1);
4510         for (j = 0; j < assembly->num_dlls; j++)
4511         {
4512             struct dll_redirect *dll = &assembly->dlls[j];
4513             add_ifaceps_record(header, &dll->entities, &index, &data_offset, i + 1);
4514         }
4515     }
4516 
4517     *section = header;
4518 
4519     return STATUS_SUCCESS;
4520 }
4521 
4522 static inline struct ifacepsredirect_data *get_ifaceps_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
4523 {
4524     return (struct ifacepsredirect_data*)((BYTE*)actctx->ifaceps_section + index->data_offset);
4525 }
4526 
4527 static NTSTATUS find_cominterface_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
4528 {
4529     struct ifacepsredirect_data *iface;
4530     struct guid_index *index = NULL;
4531 
4532     if (!(actctx->sections & IFACEREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
4533 
4534     if (!actctx->ifaceps_section)
4535     {
4536         struct guidsection_header *section;
4537 
4538         NTSTATUS status = build_ifaceps_section(actctx, &section);
4539         if (status) return status;
4540 
4541         if (InterlockedCompareExchangePointer((void**)&actctx->ifaceps_section, section, NULL))
4542             RtlFreeHeap(RtlGetProcessHeap(), 0, section);
4543     }
4544 
4545     index = find_guid_index(actctx->ifaceps_section, guid);
4546     if (!index) return STATUS_SXS_KEY_NOT_FOUND;
4547 
4548     iface = get_ifaceps_data(actctx, index);
4549 
4550     data->ulDataFormatVersion = 1;
4551     data->lpData = iface;
4552     data->ulLength = iface->size + (iface->name_len ? iface->name_len + sizeof(WCHAR) : 0);
4553     data->lpSectionGlobalData = NULL;
4554     data->ulSectionGlobalDataLength = 0;
4555     data->lpSectionBase = actctx->ifaceps_section;
4556     data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->ifaceps_section );
4557     data->hActCtx = NULL;
4558 
4559     if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
4560         data->ulAssemblyRosterIndex = index->rosterindex;
4561 
4562     return STATUS_SUCCESS;
4563 }
4564 
4565 static NTSTATUS build_clr_surrogate_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
4566 {
4567     unsigned int i, j, total_len = 0, count = 0;
4568     struct guidsection_header *header;
4569     struct clrsurrogate_data *data;
4570     struct guid_index *index;
4571     ULONG data_offset;
4572 
4573     /* compute section length */
4574     for (i = 0; i < actctx->num_assemblies; i++)
4575     {
4576         struct assembly *assembly = &actctx->assemblies[i];
4577         for (j = 0; j < assembly->entities.num; j++)
4578         {
4579             struct entity *entity = &assembly->entities.base[j];
4580             if (entity->kind == ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES)
4581             {
4582                 ULONG len;
4583 
4584                 total_len += sizeof(*index) + sizeof(*data);
4585                 len = strlenW(entity->u.clrsurrogate.name) + 1;
4586                 if (entity->u.clrsurrogate.version)
4587                    len += strlenW(entity->u.clrsurrogate.version) + 1;
4588                 total_len += aligned_string_len(len*sizeof(WCHAR));
4589 
4590                 count++;
4591             }
4592         }
4593     }
4594 
4595     total_len += sizeof(*header);
4596 
4597     header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
4598     if (!header) return STATUS_NO_MEMORY;
4599 
4600     memset(header, 0, sizeof(*header));
4601     header->magic = GUIDSECTION_MAGIC;
4602     header->size  = sizeof(*header);
4603     header->count = count;
4604     header->index_offset = sizeof(*header);
4605     index = (struct guid_index*)((BYTE*)header + header->index_offset);
4606     data_offset = header->index_offset + count*sizeof(*index);
4607 
4608     for (i = 0; i < actctx->num_assemblies; i++)
4609     {
4610         struct assembly *assembly = &actctx->assemblies[i];
4611         for (j = 0; j < assembly->entities.num; j++)
4612         {
4613             struct entity *entity = &assembly->entities.base[j];
4614             if (entity->kind == ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES)
4615             {
4616                 ULONG version_len, name_len;
4617                 UNICODE_STRING str;
4618                 WCHAR *ptrW;
4619 
4620                 if (entity->u.clrsurrogate.version)
4621                     version_len = strlenW(entity->u.clrsurrogate.version)*sizeof(WCHAR);
4622                 else
4623                     version_len = 0;
4624                 name_len = strlenW(entity->u.clrsurrogate.name)*sizeof(WCHAR);
4625 
4626                 /* setup new index entry */
4627                 RtlInitUnicodeString(&str, entity->u.clrsurrogate.clsid);
4628                 RtlGUIDFromString(&str, &index->guid);
4629 
4630                 index->data_offset = data_offset;
4631                 index->data_len = sizeof(*data) + aligned_string_len(name_len + sizeof(WCHAR) + (version_len ? version_len + sizeof(WCHAR) : 0));
4632                 index->rosterindex = i + 1;
4633 
4634                 /* setup data */
4635                 data = (struct clrsurrogate_data*)((BYTE*)header + index->data_offset);
4636                 data->size = sizeof(*data);
4637                 data->res = 0;
4638                 data->clsid = index->guid;
4639                 data->version_offset = version_len ? data->size : 0;
4640                 data->version_len = version_len;
4641                 data->name_offset = data->size + version_len;
4642                 if (version_len)
4643                     data->name_offset += sizeof(WCHAR);
4644                 data->name_len = name_len;
4645 
4646                 /* surrogate name */
4647                 ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
4648                 memcpy(ptrW, entity->u.clrsurrogate.name, data->name_len);
4649                 ptrW[data->name_len/sizeof(WCHAR)] = 0;
4650 
4651                 /* runtime version */
4652                 if (data->version_len)
4653                 {
4654                     ptrW = (WCHAR*)((BYTE*)data + data->version_offset);
4655                     memcpy(ptrW, entity->u.clrsurrogate.version, data->version_len);
4656                     ptrW[data->version_len/sizeof(WCHAR)] = 0;
4657                 }
4658 
4659                 data_offset += index->data_offset;
4660                 index++;
4661             }
4662         }
4663     }
4664 
4665     *section = header;
4666 
4667     return STATUS_SUCCESS;
4668 }
4669 
4670 static inline struct clrsurrogate_data *get_surrogate_data(ACTIVATION_CONTEXT *actctx, const struct guid_index *index)
4671 {
4672     return (struct clrsurrogate_data*)((BYTE*)actctx->clrsurrogate_section + index->data_offset);
4673 }
4674 
4675 static NTSTATUS find_clr_surrogate(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
4676 {
4677     struct clrsurrogate_data *surrogate;
4678     struct guid_index *index = NULL;
4679 
4680     if (!(actctx->sections & CLRSURROGATES_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
4681 
4682     if (!actctx->clrsurrogate_section)
4683     {
4684         struct guidsection_header *section;
4685 
4686         NTSTATUS status = build_clr_surrogate_section(actctx, &section);
4687         if (status) return status;
4688 
4689         if (InterlockedCompareExchangePointer((void**)&actctx->clrsurrogate_section, section, NULL))
4690             RtlFreeHeap(RtlGetProcessHeap(), 0, section);
4691     }
4692 
4693     index = find_guid_index(actctx->clrsurrogate_section, guid);
4694     if (!index) return STATUS_SXS_KEY_NOT_FOUND;
4695 
4696     surrogate = get_surrogate_data(actctx, index);
4697 
4698     data->ulDataFormatVersion = 1;
4699     data->lpData = surrogate;
4700     /* full length includes string length with nulls */
4701     data->ulLength = surrogate->size + surrogate->name_len + sizeof(WCHAR);
4702     if (surrogate->version_len)
4703         data->ulLength += surrogate->version_len + sizeof(WCHAR);
4704 
4705     data->lpSectionGlobalData = NULL;
4706     data->ulSectionGlobalDataLength = 0;
4707     data->lpSectionBase = actctx->clrsurrogate_section;
4708     data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->clrsurrogate_section );
4709     data->hActCtx = NULL;
4710 
4711     if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
4712         data->ulAssemblyRosterIndex = index->rosterindex;
4713 
4714     return STATUS_SUCCESS;
4715 }
4716 
4717 static void get_progid_datalen(struct entity_array *entities, unsigned int *count, unsigned int *total_len)
4718 {
4719     unsigned int i, j, single_len;
4720 
4721     single_len = sizeof(struct progidredirect_data) + sizeof(struct string_index) + sizeof(GUID);
4722     for (i = 0; i < entities->num; i++)
4723     {
4724         struct entity *entity = &entities->base[i];
4725         if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
4726         {
4727             if (entity->u.comclass.progid)
4728             {
4729                 *total_len += single_len + aligned_string_len((strlenW(entity->u.comclass.progid)+1)*sizeof(WCHAR));
4730                 *count += 1;
4731             }
4732 
4733             for (j = 0; j < entity->u.comclass.progids.num; j++)
4734                 *total_len += aligned_string_len((strlenW(entity->u.comclass.progids.progids[j])+1)*sizeof(WCHAR));
4735 
4736             *total_len += single_len*entity->u.comclass.progids.num;
4737             *count += entity->u.comclass.progids.num;
4738         }
4739     }
4740 }
4741 
4742 static void write_progid_record(struct strsection_header *section, const WCHAR *progid, const GUID *alias,
4743     struct string_index **index, ULONG *data_offset, ULONG *global_offset, ULONG rosterindex)
4744 {
4745     struct progidredirect_data *data;
4746     UNICODE_STRING str;
4747     GUID *guid_ptr;
4748     WCHAR *ptrW;
4749 
4750     /* setup new index entry */
4751 
4752     /* hash progid name */
4753     RtlInitUnicodeString(&str, progid);
4754     RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &(*index)->hash);
4755 
4756     (*index)->name_offset = *data_offset;
4757     (*index)->name_len = str.Length;
4758     (*index)->data_offset = (*index)->name_offset + aligned_string_len(str.MaximumLength);
4759     (*index)->data_len = sizeof(*data);
4760     (*index)->rosterindex = rosterindex;
4761 
4762     *data_offset += aligned_string_len(str.MaximumLength);
4763 
4764     /* setup data structure */
4765     data = (struct progidredirect_data*)((BYTE*)section + *data_offset);
4766     data->size = sizeof(*data);
4767     data->reserved = 0;
4768     data->clsid_offset = *global_offset;
4769 
4770     /* write progid string */
4771     ptrW = (WCHAR*)((BYTE*)section + (*index)->name_offset);
4772     memcpy(ptrW, progid, (*index)->name_len);
4773     ptrW[(*index)->name_len/sizeof(WCHAR)] = 0;
4774 
4775     /* write guid to global area */
4776     guid_ptr = (GUID*)((BYTE*)section + data->clsid_offset);
4777     *guid_ptr = *alias;
4778 
4779     /* to next entry */
4780     *global_offset += sizeof(GUID);
4781     *data_offset += data->size;
4782     (*index) += 1;
4783 }
4784 
4785 static void add_progid_record(ACTIVATION_CONTEXT* actctx, struct strsection_header *section, const struct entity_array *entities,
4786     struct string_index **index, ULONG *data_offset, ULONG *global_offset, ULONG rosterindex)
4787 {
4788     unsigned int i, j;
4789 
4790     for (i = 0; i < entities->num; i++)
4791     {
4792         struct entity *entity = &entities->base[i];
4793         if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
4794         {
4795             const struct progids *progids = &entity->u.comclass.progids;
4796             struct comclassredirect_data *comclass;
4797             struct guid_index *guid_index;
4798             UNICODE_STRING str;
4799             GUID clsid;
4800 
4801             RtlInitUnicodeString(&str, entity->u.comclass.clsid);
4802             RtlGUIDFromString(&str, &clsid);
4803 
4804             guid_index = find_guid_index(actctx->comserver_section, &clsid);
4805             comclass = get_comclass_data(actctx, guid_index);
4806 
4807             if (entity->u.comclass.progid)
4808                 write_progid_record(section, entity->u.comclass.progid, &comclass->alias,
4809                      index, data_offset, global_offset, rosterindex);
4810 
4811             for (j = 0; j < progids->num; j++)
4812                 write_progid_record(section, progids->progids[j], &comclass->alias,
4813                      index, data_offset, global_offset, rosterindex);
4814         }
4815     }
4816 }
4817 
4818 static NTSTATUS build_progid_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
4819 {
4820     unsigned int i, j, total_len = 0, count = 0;
4821     struct strsection_header *header;
4822     ULONG data_offset, global_offset;
4823     struct string_index *index;
4824 
4825     /* compute section length */
4826     for (i = 0; i < actctx->num_assemblies; i++)
4827     {
4828         struct assembly *assembly = &actctx->assemblies[i];
4829 
4830         get_progid_datalen(&assembly->entities, &count, &total_len);
4831         for (j = 0; j < assembly->num_dlls; j++)
4832         {
4833             struct dll_redirect *dll = &assembly->dlls[j];
4834             get_progid_datalen(&dll->entities, &count, &total_len);
4835         }
4836     }
4837 
4838     total_len += sizeof(*header);
4839 
4840     header = RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len);
4841     if (!header) return STATUS_NO_MEMORY;
4842 
4843     memset(header, 0, sizeof(*header));
4844     header->magic = STRSECTION_MAGIC;
4845     header->size  = sizeof(*header);
4846     header->count = count;
4847     header->global_offset = header->size;
4848     header->global_len = count*sizeof(GUID);
4849     header->index_offset = header->size + header->global_len;
4850 
4851     index = (struct string_index*)((BYTE*)header + header->index_offset);
4852     data_offset = header->index_offset + count*sizeof(*index);
4853     global_offset = header->global_offset;
4854 
4855     for (i = 0; i < actctx->num_assemblies; i++)
4856     {
4857         struct assembly *assembly = &actctx->assemblies[i];
4858 
4859         add_progid_record(actctx, header, &assembly->entities, &index, &data_offset, &global_offset, i + 1);
4860         for (j = 0; j < assembly->num_dlls; j++)
4861         {
4862             struct dll_redirect *dll = &assembly->dlls[j];
4863             add_progid_record(actctx, header, &dll->entities, &index, &data_offset, &global_offset, i + 1);
4864         }
4865     }
4866 
4867     *section = header;
4868 
4869     return STATUS_SUCCESS;
4870 }
4871 
4872 static inline struct progidredirect_data *get_progid_data(ACTIVATION_CONTEXT *actctx, const struct string_index *index)
4873 {
4874     return (struct progidredirect_data*)((BYTE*)actctx->progid_section + index->data_offset);
4875 }
4876 
4877 static NTSTATUS find_progid_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
4878                                      PACTCTX_SECTION_KEYED_DATA data)
4879 {
4880     struct progidredirect_data *progid;
4881     struct string_index *index;
4882 
4883     if (!(actctx->sections & PROGIDREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
4884 
4885     if (!actctx->comserver_section)
4886     {
4887         struct guidsection_header *section;
4888 
4889         NTSTATUS status = build_comserver_section(actctx, &section);
4890         if (status) return status;
4891 
4892         if (InterlockedCompareExchangePointer((void**)&actctx->comserver_section, section, NULL))
4893             RtlFreeHeap(RtlGetProcessHeap(), 0, section);
4894     }
4895 
4896     if (!actctx->progid_section)
4897     {
4898         struct strsection_header *section;
4899 
4900         NTSTATUS status = build_progid_section(actctx, &section);
4901         if (status) return status;
4902 
4903         if (InterlockedCompareExchangePointer((void**)&actctx->progid_section, section, NULL))
4904             RtlFreeHeap(RtlGetProcessHeap(), 0, section);
4905     }
4906 
4907     index = find_string_index(actctx->progid_section, name);
4908     if (!index) return STATUS_SXS_KEY_NOT_FOUND;
4909 
4910     if (data)
4911     {
4912         progid = get_progid_data(actctx, index);
4913 
4914         data->ulDataFormatVersion = 1;
4915         data->lpData = progid;
4916         data->ulLength = progid->size;
4917         data->lpSectionGlobalData = (BYTE*)actctx->progid_section + actctx->progid_section->global_offset;
4918         data->ulSectionGlobalDataLength = actctx->progid_section->global_len;
4919         data->lpSectionBase = actctx->progid_section;
4920         data->ulSectionTotalLength = RtlSizeHeap( RtlGetProcessHeap(), 0, actctx->progid_section );
4921         data->hActCtx = NULL;
4922 
4923         if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
4924             data->ulAssemblyRosterIndex = index->rosterindex;
4925     }
4926 
4927     return STATUS_SUCCESS;
4928 }
4929 
4930 static NTSTATUS find_string(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
4931                             const UNICODE_STRING *section_name,
4932                             DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
4933 {
4934     NTSTATUS status;
4935 
4936     switch (section_kind)
4937     {
4938     case ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION:
4939         DPRINT1("Unsupported yet section_kind %x\n", section_kind);
4940         return STATUS_SXS_KEY_NOT_FOUND;
4941     case ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION:
4942         status = find_dll_redirection(actctx, section_name, data);
4943         break;
4944     case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION:
4945         status = find_window_class(actctx, section_name, data);
4946         break;
4947     case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION:
4948         status = find_progid_redirection(actctx, section_name, data);
4949         break;
4950     case ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE:
4951         DPRINT1("Unsupported yet section_kind %x\n", section_kind);
4952         return STATUS_SXS_SECTION_NOT_FOUND;
4953     default:
4954         DPRINT1("Unknown section_kind %x\n", section_kind);
4955         return STATUS_SXS_SECTION_NOT_FOUND;
4956     }
4957 
4958     if (status != STATUS_SUCCESS) return status;
4959 
4960     if (data && (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX))
4961     {
4962         actctx_addref(actctx);
4963         data->hActCtx = actctx;
4964     }
4965     return STATUS_SUCCESS;
4966 }
4967 
4968 static NTSTATUS find_guid(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
4969                           const GUID *guid, DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
4970 {
4971     NTSTATUS status;
4972 
4973     switch (section_kind)
4974     {
4975     case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION:
4976         status = find_tlib_redirection(actctx, guid, data);
4977         break;
4978     case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
4979         status = find_comserver_redirection(actctx, guid, data);
4980         break;
4981     case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
4982         status = find_cominterface_redirection(actctx, guid, data);
4983         break;
4984     case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES:
4985         status = find_clr_surrogate(actctx, guid, data);
4986         break;
4987     default:
4988         DPRINT("Unknown section_kind %x\n", section_kind);
4989         return STATUS_SXS_SECTION_NOT_FOUND;
4990     }
4991 
4992     if (status != STATUS_SUCCESS) return status;
4993 
4994     if (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
4995     {
4996         actctx_addref(actctx);
4997         data->hActCtx = actctx;
4998     }
4999     return STATUS_SUCCESS;
5000 }
5001 
5002 /* initialize the activation context for the current process */
5003 void actctx_init(PVOID* pOldShimData)
5004 {
5005     ACTCTXW ctx;
5006     HANDLE handle;
5007     WCHAR buffer[1024];
5008     NTSTATUS Status;
5009 
5010     ctx.cbSize   = sizeof(ctx);
5011     ctx.lpSource = NULL;
5012     ctx.dwFlags  = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
5013     ctx.hModule  = NtCurrentTeb()->ProcessEnvironmentBlock->ImageBaseAddress;
5014     ctx.lpResourceName = (LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID;
5015 
5016     if (NT_SUCCESS(RtlCreateActivationContext(0, (PVOID)&ctx, 0, NULL, NULL, &handle)))
5017     {
5018         process_actctx = check_actctx(handle);
5019     }
5020 
5021     /* ReactOS specific:
5022        Now that we have found the process_actctx we can initialize the process compat subsystem */
5023     LdrpInitializeProcessCompat(process_actctx, pOldShimData);
5024 
5025 
5026     ctx.dwFlags  = 0;
5027     ctx.hModule  = NULL;
5028     ctx.lpResourceName = NULL;
5029     ctx.lpSource = buffer;
5030     RtlStringCchCopyW(buffer, RTL_NUMBER_OF(buffer), SharedUserData->NtSystemRoot);
5031 
5032     if (RosGetProcessCompatVersion())
5033     {
5034         RtlStringCchCatW(buffer, RTL_NUMBER_OF(buffer), L"\\winsxs\\manifests\\forwardcompatible.manifest");
5035     }
5036     else
5037     {
5038         RtlStringCchCatW(buffer, RTL_NUMBER_OF(buffer), L"\\winsxs\\manifests\\systemcompatible.manifest");
5039     }
5040 
5041     Status = RtlCreateActivationContext(0, (PVOID)&ctx, 0, NULL, NULL, &handle);
5042     if (NT_SUCCESS(Status))
5043     {
5044         implicit_actctx = check_actctx(handle);
5045     }
5046     else
5047     {
5048         DPRINT1("Failed to create the implicit act ctx. Status: 0x%x!!!\n", Status);
5049     }
5050 }
5051 
5052 /* FUNCTIONS ***************************************************************/
5053 
5054 /***********************************************************************
5055  * RtlCreateActivationContext (NTDLL.@)
5056  *
5057  * Create an activation context.
5058  */
5059 NTSTATUS
5060 NTAPI
5061 RtlCreateActivationContext(IN ULONG Flags,
5062                            IN PACTIVATION_CONTEXT_DATA ActivationContextData,
5063                            IN ULONG ExtraBytes,
5064                            IN PVOID NotificationRoutine,
5065                            IN PVOID NotificationContext,
5066                            OUT PACTIVATION_CONTEXT *ActCtx)
5067 {
5068     const ACTCTXW *pActCtx = (PVOID)ActivationContextData;
5069     const WCHAR *directory = NULL;
5070     PACTIVATION_CONTEXT_WRAPPED ActualActCtx;
5071     ACTIVATION_CONTEXT *actctx;
5072     UNICODE_STRING nameW;
5073     ULONG lang = 0;
5074     NTSTATUS status = STATUS_NO_MEMORY;
5075     HANDLE file = 0;
5076     struct actctx_loader acl;
5077 
5078     DPRINT("RtlCreateActivationContext %p %08x, Image Base: %p\n", pActCtx, pActCtx ? pActCtx->dwFlags : 0, ((ACTCTXW*)ActivationContextData)->hModule);
5079 
5080     if (!pActCtx || pActCtx->cbSize < sizeof(*pActCtx) ||
5081         (pActCtx->dwFlags & ~ACTCTX_FLAGS_ALL))
5082         return STATUS_INVALID_PARAMETER;
5083 
5084 
5085     if (!(ActualActCtx = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ActualActCtx))))
5086         return STATUS_NO_MEMORY;
5087 
5088     ActualActCtx->MagicMarker = ACTCTX_MAGIC_MARKER;
5089 
5090     actctx = &ActualActCtx->ActivationContext;
5091     actctx->RefCount = 1;
5092     actctx->config.type = ACTIVATION_CONTEXT_PATH_TYPE_NONE;
5093     actctx->config.info = NULL;
5094     actctx->appdir.type = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
5095     if (pActCtx->dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID)
5096     {
5097         if (!(actctx->appdir.info = strdupW( pActCtx->lpApplicationName ))) goto error;
5098     }
5099     else
5100     {
5101         UNICODE_STRING dir;
5102         WCHAR *p;
5103         HMODULE module;
5104 
5105         if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID) module = pActCtx->hModule;
5106         else module = NtCurrentTeb()->ProcessEnvironmentBlock->ImageBaseAddress;
5107 
5108         status = get_module_filename( module, &dir, 0 );
5109         if (!NT_SUCCESS(status)) goto error;
5110         if ((p = strrchrW( dir.Buffer, '\\' ))) p[1] = 0;
5111         actctx->appdir.info = dir.Buffer;
5112     }
5113 
5114     nameW.Buffer = NULL;
5115 
5116     /* open file only if it's going to be used */
5117     if (pActCtx->lpSource && !((pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) &&
5118                                (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)))
5119     {
5120         WCHAR *source = NULL;
5121         BOOLEAN ret;
5122 
5123         if (pActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID &&
5124             RtlDetermineDosPathNameType_U(pActCtx->lpSource) == RtlPathTypeRelative)
5125         {
5126             DWORD dir_len, source_len;
5127 
5128             dir_len = strlenW(pActCtx->lpAssemblyDirectory);
5129             source_len = strlenW(pActCtx->lpSource);
5130             if (!(source = RtlAllocateHeap( RtlGetProcessHeap(), 0, (dir_len+source_len+2)*sizeof(WCHAR))))
5131             {
5132                 status = STATUS_NO_MEMORY;
5133                 goto error;
5134             }
5135 
5136             memcpy(source, pActCtx->lpAssemblyDirectory, dir_len*sizeof(WCHAR));
5137             source[dir_len] = '\\';
5138             memcpy(source+dir_len+1, pActCtx->lpSource, (source_len+1)*sizeof(WCHAR));
5139         }
5140 
5141         ret = RtlDosPathNameToNtPathName_U(source ? source : pActCtx->lpSource, &nameW, NULL, NULL);
5142         RtlFreeHeap( RtlGetProcessHeap(), 0, source );
5143         if (!ret)
5144         {
5145             status = STATUS_NO_SUCH_FILE;
5146             goto error;
5147         }
5148         status = open_nt_file( &file, &nameW );
5149         if (!NT_SUCCESS(status))
5150         {
5151             RtlFreeUnicodeString( &nameW );
5152             goto error;
5153         }
5154     }
5155 
5156     acl.actctx = actctx;
5157     acl.dependencies = NULL;
5158     acl.num_dependencies = 0;
5159     acl.allocated_dependencies = 0;
5160 
5161     if (pActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID) lang = pActCtx->wLangId;
5162     if (pActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) directory = pActCtx->lpAssemblyDirectory;
5163 
5164     if (pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID)
5165     {
5166         /* if we have a resource it's a PE file */
5167         if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)
5168         {
5169             status = get_manifest_in_module( &acl, NULL, NULL, directory, FALSE, pActCtx->hModule,
5170                                              pActCtx->lpResourceName, lang );
5171             if (status && status != STATUS_SXS_CANT_GEN_ACTCTX)
5172                 /* FIXME: what to do if pActCtx->lpSource is set */
5173                 status = get_manifest_in_associated_manifest( &acl, NULL, NULL, directory,
5174                                                               pActCtx->hModule, pActCtx->lpResourceName );
5175         }
5176         else if (pActCtx->lpSource && pActCtx->lpResourceName)
5177         {
5178             status = get_manifest_in_pe_file( &acl, NULL, nameW.Buffer, directory, FALSE,
5179                                               file, pActCtx->lpResourceName, lang );
5180             if (status && status != STATUS_SXS_CANT_GEN_ACTCTX)
5181                 status = get_manifest_in_associated_manifest( &acl, NULL, nameW.Buffer, directory,
5182                                                               NULL, pActCtx->lpResourceName );
5183         }
5184         else status = STATUS_INVALID_PARAMETER;
5185     }
5186     else
5187     {
5188         status = get_manifest_in_manifest_file( &acl, NULL, nameW.Buffer, directory, FALSE, file );
5189     }
5190 
5191     if (file) NtClose( file );
5192     RtlFreeUnicodeString( &nameW );
5193 
5194     if (NT_SUCCESS(status)) status = parse_depend_manifests(&acl);
5195     free_depend_manifests( &acl );
5196 
5197     if (NT_SUCCESS(status))
5198         *ActCtx = actctx;
5199     else actctx_release( actctx );
5200     return status;
5201 
5202 error:
5203     if (file) NtClose( file );
5204     actctx_release( actctx );
5205     return status;
5206 }
5207 
5208 #if 0
5209 #define ACT_CTX_VALID(p)    ((((ULONG_PTR)p - 1) | 7) != -1)
5210 
5211 VOID
5212 NTAPI
5213 RtlAddRefActivationContext(IN PACTIVATION_CONTEXT Handle)
5214 {
5215     PIACTIVATION_CONTEXT ActCtx = (PIACTIVATION_CONTEXT)Handle;
5216     LONG OldRefCount, NewRefCount;
5217 
5218     if ((ActCtx) && (ACT_CTX_VALID(ActCtx)) && (ActCtx->RefCount != LONG_MAX))
5219     {
5220         RtlpValidateActCtx(ActCtx);
5221 
5222         while (TRUE)
5223         {
5224             OldRefCount = ActCtx->RefCount;
5225             ASSERT(OldRefCount > 0);
5226 
5227             if (OldRefCount == LONG_MAX) break;
5228 
5229             NewRefCount = OldRefCount + 1;
5230             if (InterlockedCompareExchange(&ActCtx->RefCount,
5231                                            NewRefCount,
5232                                            OldRefCount) == OldRefCount)
5233             {
5234                 break;
5235             }
5236         }
5237 
5238         NewRefCount = LONG_MAX;
5239         ASSERT(NewRefCount > 0);
5240     }
5241 }
5242 
5243 VOID
5244 NTAPI
5245 RtlReleaseActivationContext( HANDLE handle )
5246 {
5247     PIACTIVATION_CONTEXT ActCtx = (PIACTIVATION_CONTEXT) Handle;
5248 
5249     if ((ActCtx) && (ACT_CTX_VALID(ActCtx)) && (ActCtx->RefCount != LONG_MAX))
5250     {
5251         RtlpValidateActCtx(ActCtx);
5252 
5253         actctx_release(ActCtx);
5254     }
5255 }
5256 #else
5257 
5258 /***********************************************************************
5259  *		RtlAddRefActivationContext (NTDLL.@)
5260  */
5261 VOID NTAPI RtlAddRefActivationContext( HANDLE handle )
5262 {
5263     ACTIVATION_CONTEXT *actctx;
5264 
5265     if ((actctx = check_actctx( handle ))) actctx_addref( actctx );
5266 }
5267 
5268 
5269 /******************************************************************
5270  *		RtlReleaseActivationContext (NTDLL.@)
5271  */
5272 VOID NTAPI RtlReleaseActivationContext( HANDLE handle )
5273 {
5274     ACTIVATION_CONTEXT *actctx;
5275 
5276     if ((actctx = check_actctx( handle ))) actctx_release( actctx );
5277 }
5278 
5279 #endif
5280 
5281 /******************************************************************
5282  *              RtlZombifyActivationContext (NTDLL.@)
5283  *
5284  */
5285 NTSTATUS NTAPI RtlZombifyActivationContext(PVOID Context)
5286 {
5287     UNIMPLEMENTED;
5288 
5289     if (Context == ACTCTX_FAKE_HANDLE)
5290         return STATUS_SUCCESS;
5291 
5292     return STATUS_NOT_IMPLEMENTED;
5293 }
5294 
5295 NTSTATUS
5296 NTAPI RtlActivateActivationContextEx( ULONG flags, PTEB tebAddress, HANDLE handle, PULONG_PTR cookie )
5297 {
5298     RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
5299 
5300     if (!(frame = RtlAllocateHeap( RtlGetProcessHeap(), 0, sizeof(*frame) )))
5301         return STATUS_NO_MEMORY;
5302 
5303     frame->Previous = tebAddress->ActivationContextStackPointer->ActiveFrame;
5304     frame->ActivationContext = handle;
5305     frame->Flags = 0;
5306 
5307     DPRINT("ActiveSP %p: ACTIVATE (ActiveFrame %p -> NewFrame %p, Context %p)\n",
5308         tebAddress->ActivationContextStackPointer, tebAddress->ActivationContextStackPointer->ActiveFrame,
5309         frame, handle);
5310 
5311     tebAddress->ActivationContextStackPointer->ActiveFrame = frame;
5312     RtlAddRefActivationContext( handle );
5313 
5314     *cookie = (ULONG_PTR)frame;
5315     DPRINT( "%p cookie=%lx\n", handle, *cookie );
5316     return STATUS_SUCCESS;
5317 }
5318 
5319 /******************************************************************
5320  *		RtlActivateActivationContext (NTDLL.@)
5321  */
5322 NTSTATUS NTAPI RtlActivateActivationContext( ULONG flags, HANDLE handle, PULONG_PTR cookie )
5323 {
5324     return RtlActivateActivationContextEx(flags, NtCurrentTeb(), handle, cookie);
5325 }
5326 
5327 /***********************************************************************
5328  *		RtlDeactivateActivationContext (NTDLL.@)
5329  */
5330 NTSTATUS NTAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie )
5331 {
5332     RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame, *top;
5333 
5334     DPRINT( "%x cookie=%lx\n", flags, cookie );
5335 
5336     /* find the right frame */
5337     top = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
5338     for (frame = top; frame; frame = frame->Previous)
5339         if ((ULONG_PTR)frame == cookie) break;
5340 
5341     if (!frame)
5342         RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION );
5343 
5344     if (frame != top && !(flags & RTL_DEACTIVATE_ACTIVATION_CONTEXT_FLAG_FORCE_EARLY_DEACTIVATION))
5345         RtlRaiseStatus( STATUS_SXS_EARLY_DEACTIVATION );
5346 
5347     DPRINT("ActiveSP %p: DEACTIVATE (ActiveFrame %p -> PreviousFrame %p)\n",
5348         NtCurrentTeb()->ActivationContextStackPointer,
5349         NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame,
5350         frame->Previous);
5351 
5352     /* pop everything up to and including frame */
5353     NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = frame->Previous;
5354 
5355     while (top != NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
5356     {
5357         frame = top->Previous;
5358         RtlReleaseActivationContext( top->ActivationContext );
5359         RtlFreeHeap( RtlGetProcessHeap(), 0, top );
5360         top = frame;
5361     }
5362 
5363     return STATUS_SUCCESS;
5364 }
5365 
5366 VOID
5367 NTAPI
5368 RtlFreeActivationContextStack(IN PACTIVATION_CONTEXT_STACK Stack)
5369 {
5370     PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame, PrevFrame;
5371 
5372     /* Nothing to do if there is no stack */
5373     if (!Stack) return;
5374 
5375     /* Get the current active frame */
5376     ActiveFrame = Stack->ActiveFrame;
5377 
5378     /* Go through them in backwards order and release */
5379     while (ActiveFrame)
5380     {
5381         PrevFrame = ActiveFrame->Previous;
5382         RtlReleaseActivationContext(ActiveFrame->ActivationContext);
5383         RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveFrame);
5384         ActiveFrame = PrevFrame;
5385     }
5386 
5387     /* Zero out the active frame */
5388     Stack->ActiveFrame = NULL;
5389 
5390     /* TODO: Empty the Frame List Cache */
5391     ASSERT(IsListEmpty(&Stack->FrameListCache));
5392 
5393     /* Free activation stack memory */
5394     RtlFreeHeap(RtlGetProcessHeap(), 0, Stack);
5395 }
5396 
5397 /******************************************************************
5398  *		RtlFreeThreadActivationContextStack (NTDLL.@)
5399  */
5400 VOID NTAPI RtlFreeThreadActivationContextStack(VOID)
5401 {
5402     RtlFreeActivationContextStack(NtCurrentTeb()->ActivationContextStackPointer);
5403     NtCurrentTeb()->ActivationContextStackPointer = NULL;
5404 }
5405 
5406 
5407 /******************************************************************
5408  *		RtlGetActiveActivationContext (NTDLL.@)
5409  */
5410 NTSTATUS NTAPI RtlGetActiveActivationContext( HANDLE *handle )
5411 {
5412     if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
5413     {
5414         *handle = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext;
5415         RtlAddRefActivationContext( *handle );
5416     }
5417     else
5418         *handle = 0;
5419 
5420     return STATUS_SUCCESS;
5421 }
5422 
5423 
5424 /******************************************************************
5425  *		RtlIsActivationContextActive (NTDLL.@)
5426  */
5427 BOOLEAN NTAPI RtlIsActivationContextActive( HANDLE handle )
5428 {
5429     RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
5430 
5431     for (frame = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame; frame; frame = frame->Previous)
5432         if (frame->ActivationContext == handle) return TRUE;
5433     return FALSE;
5434 }
5435 
5436 
5437 /***********************************************************************
5438  *		RtlQueryInformationActivationContext (NTDLL.@)
5439  *
5440  * Get information about an activation context.
5441  * FIXME: function signature/prototype may be wrong
5442  */
5443 NTSTATUS NTAPI RtlQueryInformationActivationContext( ULONG flags, HANDLE handle, PVOID subinst,
5444                                                      ULONG class, PVOID buffer,
5445                                                      SIZE_T bufsize, SIZE_T *retlen )
5446 {
5447     ACTIVATION_CONTEXT *actctx;
5448     NTSTATUS status;
5449 
5450     DPRINT("%08x %p %p %u %p %Iu %p\n", flags, handle,
5451           subinst, class, buffer, bufsize, retlen);
5452 
5453     if (retlen) *retlen = 0;
5454     if ((status = find_query_actctx( &handle, flags, class ))) return status;
5455 
5456     switch (class)
5457     {
5458     case ActivationContextBasicInformation:
5459         {
5460             ACTIVATION_CONTEXT_BASIC_INFORMATION *info = buffer;
5461 
5462             if (retlen) *retlen = sizeof(*info);
5463             if (!info || bufsize < sizeof(*info)) return STATUS_BUFFER_TOO_SMALL;
5464 
5465             info->hActCtx = handle;
5466             info->dwFlags = 0;  /* FIXME */
5467             if (!(flags & RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF)) RtlAddRefActivationContext(handle);
5468         }
5469         break;
5470 
5471     case ActivationContextDetailedInformation:
5472         {
5473             ACTIVATION_CONTEXT_DETAILED_INFORMATION *acdi = buffer;
5474             struct assembly *assembly = NULL;
5475             SIZE_T len, manifest_len = 0, config_len = 0, appdir_len = 0;
5476             LPWSTR ptr;
5477 
5478             if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
5479 
5480             if (actctx->num_assemblies) assembly = actctx->assemblies;
5481 
5482             if (assembly && assembly->manifest.info)
5483                 manifest_len = strlenW(assembly->manifest.info) + 1;
5484             if (actctx->config.info) config_len = strlenW(actctx->config.info) + 1;
5485             if (actctx->appdir.info) appdir_len = strlenW(actctx->appdir.info) + 1;
5486             len = sizeof(*acdi) + (manifest_len + config_len + appdir_len) * sizeof(WCHAR);
5487 
5488             if (retlen) *retlen = len;
5489             if (!buffer || bufsize < len) return STATUS_BUFFER_TOO_SMALL;
5490 
5491             acdi->dwFlags = 0;
5492             acdi->ulFormatVersion = assembly ? 1 : 0; /* FIXME */
5493             acdi->ulAssemblyCount = actctx->num_assemblies;
5494             acdi->ulRootManifestPathType = assembly ? assembly->manifest.type : 0 /* FIXME */;
5495             acdi->ulRootManifestPathChars = assembly && assembly->manifest.info ? (DWORD)manifest_len - 1 : 0;
5496             acdi->ulRootConfigurationPathType = actctx->config.type;
5497             acdi->ulRootConfigurationPathChars = actctx->config.info ? (DWORD)config_len - 1 : 0;
5498             acdi->ulAppDirPathType = actctx->appdir.type;
5499             acdi->ulAppDirPathChars = actctx->appdir.info ? (DWORD)appdir_len - 1 : 0;
5500             ptr = (LPWSTR)(acdi + 1);
5501             if (manifest_len)
5502             {
5503                 acdi->lpRootManifestPath = ptr;
5504                 memcpy(ptr, assembly->manifest.info, manifest_len * sizeof(WCHAR));
5505                 ptr += manifest_len;
5506             }
5507             else acdi->lpRootManifestPath = NULL;
5508             if (config_len)
5509             {
5510                 acdi->lpRootConfigurationPath = ptr;
5511                 memcpy(ptr, actctx->config.info, config_len * sizeof(WCHAR));
5512                 ptr += config_len;
5513             }
5514             else acdi->lpRootConfigurationPath = NULL;
5515             if (appdir_len)
5516             {
5517                 acdi->lpAppDirPath = ptr;
5518                 memcpy(ptr, actctx->appdir.info, appdir_len * sizeof(WCHAR));
5519             }
5520             else acdi->lpAppDirPath = NULL;
5521         }
5522         break;
5523 
5524     case AssemblyDetailedInformationInActivationContext:
5525         {
5526             ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *afdi = buffer;
5527             struct assembly *assembly;
5528             WCHAR *assembly_id;
5529             DWORD index;
5530             SIZE_T len, id_len = 0, ad_len = 0, path_len = 0;
5531             LPWSTR ptr;
5532 
5533             if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
5534             if (!subinst) return STATUS_INVALID_PARAMETER;
5535 
5536             index = *(DWORD*)subinst;
5537             if (!index || index > actctx->num_assemblies) return STATUS_INVALID_PARAMETER;
5538 
5539             assembly = &actctx->assemblies[index - 1];
5540 
5541             if (!(assembly_id = build_assembly_id( &assembly->id ))) return STATUS_NO_MEMORY;
5542             id_len = strlenW(assembly_id) + 1;
5543             if (assembly->directory) ad_len = strlenW(assembly->directory) + 1;
5544 
5545             if (assembly->manifest.info &&
5546                 (assembly->type == ASSEMBLY_MANIFEST || assembly->type == ASSEMBLY_SHARED_MANIFEST))
5547                 path_len  = strlenW(assembly->manifest.info) + 1;
5548 
5549             len = sizeof(*afdi) + (id_len + ad_len + path_len) * sizeof(WCHAR);
5550 
5551             if (retlen) *retlen = len;
5552             if (!buffer || bufsize < len)
5553             {
5554                 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id );
5555                 return STATUS_BUFFER_TOO_SMALL;
5556             }
5557 
5558             afdi->ulFlags = 0;  /* FIXME */
5559             afdi->ulEncodedAssemblyIdentityLength = (DWORD)(id_len - 1) * sizeof(WCHAR);
5560             afdi->ulManifestPathType = assembly->manifest.type;
5561             afdi->ulManifestPathLength = assembly->manifest.info ? (DWORD)(path_len - 1) * sizeof(WCHAR) : 0;
5562             /* FIXME afdi->liManifestLastWriteTime = 0; */
5563             afdi->ulPolicyPathType = ACTIVATION_CONTEXT_PATH_TYPE_NONE; /* FIXME */
5564             afdi->ulPolicyPathLength = 0;
5565             /* FIXME afdi->liPolicyLastWriteTime = 0; */
5566             afdi->ulMetadataSatelliteRosterIndex = 0; /* FIXME */
5567             afdi->ulManifestVersionMajor = 1;
5568             afdi->ulManifestVersionMinor = 0;
5569             afdi->ulPolicyVersionMajor = 0; /* FIXME */
5570             afdi->ulPolicyVersionMinor = 0; /* FIXME */
5571             afdi->ulAssemblyDirectoryNameLength = ad_len ? (DWORD)(ad_len - 1) * sizeof(WCHAR) : 0;
5572             ptr = (LPWSTR)(afdi + 1);
5573             afdi->lpAssemblyEncodedAssemblyIdentity = ptr;
5574             memcpy( ptr, assembly_id, id_len * sizeof(WCHAR) );
5575             ptr += id_len;
5576             if (path_len)
5577             {
5578                 afdi->lpAssemblyManifestPath = ptr;
5579                 memcpy(ptr, assembly->manifest.info, path_len * sizeof(WCHAR));
5580                 ptr += path_len;
5581             } else afdi->lpAssemblyManifestPath = NULL;
5582             afdi->lpAssemblyPolicyPath = NULL; /* FIXME */
5583             if (ad_len)
5584             {
5585                 afdi->lpAssemblyDirectoryName = ptr;
5586                 memcpy(ptr, assembly->directory, ad_len * sizeof(WCHAR));
5587             }
5588             else afdi->lpAssemblyDirectoryName = NULL;
5589             RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id );
5590         }
5591         break;
5592 
5593     case FileInformationInAssemblyOfAssemblyInActivationContext:
5594         {
5595             const ACTIVATION_CONTEXT_QUERY_INDEX *acqi = subinst;
5596             ASSEMBLY_FILE_DETAILED_INFORMATION *afdi = buffer;
5597             struct assembly *assembly;
5598             struct dll_redirect *dll;
5599             SIZE_T len, dll_len = 0;
5600             LPWSTR ptr;
5601 
5602             if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
5603             if (!acqi) return STATUS_INVALID_PARAMETER;
5604 
5605             if (acqi->ulAssemblyIndex >= actctx->num_assemblies)
5606                 return STATUS_INVALID_PARAMETER;
5607             assembly = &actctx->assemblies[acqi->ulAssemblyIndex];
5608 
5609             if (acqi->ulFileIndexInAssembly >= assembly->num_dlls)
5610                 return STATUS_INVALID_PARAMETER;
5611             dll = &assembly->dlls[acqi->ulFileIndexInAssembly];
5612 
5613             if (dll->name) dll_len = strlenW(dll->name) + 1;
5614             len = sizeof(*afdi) + dll_len * sizeof(WCHAR);
5615 
5616             if (!buffer || bufsize < len)
5617             {
5618                 if (retlen) *retlen = len;
5619                 return STATUS_BUFFER_TOO_SMALL;
5620             }
5621             if (retlen) *retlen = 0; /* yes that's what native does !! */
5622             afdi->ulFlags = ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION;
5623             afdi->ulFilenameLength = dll_len ? (DWORD)(dll_len - 1) * sizeof(WCHAR) : 0;
5624             afdi->ulPathLength = 0; /* FIXME */
5625             ptr = (LPWSTR)(afdi + 1);
5626             if (dll_len)
5627             {
5628                 afdi->lpFileName = ptr;
5629                 memcpy( ptr, dll->name, dll_len * sizeof(WCHAR) );
5630             } else afdi->lpFileName = NULL;
5631             afdi->lpFilePath = NULL; /* FIXME */
5632         }
5633         break;
5634 
5635     case CompatibilityInformationInActivationContext:
5636         {
5637             /*ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*/DWORD *acci = buffer;
5638             COMPATIBILITY_CONTEXT_ELEMENT *elements;
5639             struct assembly *assembly = NULL;
5640             ULONG num_compat_contexts = 0, n;
5641             SIZE_T len;
5642 
5643             if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
5644 
5645             if (actctx->num_assemblies) assembly = actctx->assemblies;
5646 
5647             if (assembly)
5648                 num_compat_contexts = assembly->num_compat_contexts;
5649             len = sizeof(*acci) + num_compat_contexts * sizeof(COMPATIBILITY_CONTEXT_ELEMENT);
5650 
5651             if (retlen) *retlen = len;
5652             if (!buffer || bufsize < len) return STATUS_BUFFER_TOO_SMALL;
5653 
5654             *acci = num_compat_contexts;
5655             elements = (COMPATIBILITY_CONTEXT_ELEMENT*)(acci + 1);
5656             for (n = 0; n < num_compat_contexts; ++n)
5657             {
5658                 elements[n] = assembly->compat_contexts[n];
5659             }
5660         }
5661         break;
5662 
5663     case RunlevelInformationInActivationContext:
5664         {
5665             ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION *acrli = buffer;
5666             struct assembly *assembly;
5667             SIZE_T len;
5668 
5669             if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
5670 
5671             len = sizeof(*acrli);
5672             if (retlen) *retlen = len;
5673             if (!buffer || bufsize < len)
5674                 return STATUS_BUFFER_TOO_SMALL;
5675 
5676             assembly = actctx->assemblies;
5677 
5678             acrli->ulFlags  = 0;
5679             acrli->RunLevel = assembly ? assembly->run_level : ACTCTX_RUN_LEVEL_UNSPECIFIED;
5680             acrli->UiAccess = assembly ? assembly->ui_access : 0;
5681         }
5682         break;
5683 
5684     default:
5685         DPRINT( "class %u not implemented\n", class );
5686         return STATUS_NOT_IMPLEMENTED;
5687     }
5688     return STATUS_SUCCESS;
5689 }
5690 
5691 NTSTATUS
5692 NTAPI
5693 RtlQueryInformationActiveActivationContext(ULONG ulInfoClass,
5694                                            PVOID pvBuffer,
5695                                            SIZE_T cbBuffer OPTIONAL,
5696                                            SIZE_T *pcbWrittenOrRequired OPTIONAL)
5697 {
5698     return RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT,
5699                                                 NULL,
5700                                                 NULL,
5701                                                 ulInfoClass,
5702                                                 pvBuffer,
5703                                                 cbBuffer,
5704                                                 pcbWrittenOrRequired);
5705 }
5706 
5707 #define FIND_ACTCTX_RETURN_FLAGS 0x00000002
5708 #define FIND_ACTCTX_RETURN_ASSEMBLY_METADATA 0x00000004
5709 #define FIND_ACTCTX_VALID_MASK (FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX | FIND_ACTCTX_RETURN_FLAGS | FIND_ACTCTX_RETURN_ASSEMBLY_METADATA)
5710 
5711 NTSTATUS
5712 NTAPI
5713 RtlpFindActivationContextSection_CheckParameters( ULONG flags, const GUID *guid, ULONG section_kind,
5714                                                   const UNICODE_STRING *section_name, PACTCTX_SECTION_KEYED_DATA data )
5715 {
5716     /* Check general parameter combinations */
5717     if (!section_name ||  !section_name->Buffer ||
5718         (flags & ~FIND_ACTCTX_VALID_MASK) ||
5719         ((flags & FIND_ACTCTX_VALID_MASK) && !data) ||
5720         (data && data->cbSize < offsetof(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex)))
5721     {
5722         DPRINT1("invalid parameter\n");
5723         return STATUS_INVALID_PARAMETER;
5724     }
5725 
5726     /* TODO */
5727     if (flags & FIND_ACTCTX_RETURN_FLAGS ||
5728         flags & FIND_ACTCTX_RETURN_ASSEMBLY_METADATA)
5729     {
5730         DPRINT1("unknown flags %08x\n", flags);
5731         return STATUS_INVALID_PARAMETER;
5732     }
5733 
5734     return STATUS_SUCCESS;
5735 }
5736 
5737 /***********************************************************************
5738  *		RtlFindActivationContextSectionString (NTDLL.@)
5739  *
5740  * Find information about a string in an activation context.
5741  * FIXME: function signature/prototype may be wrong
5742  */
5743 NTSTATUS NTAPI RtlFindActivationContextSectionString( ULONG flags, const GUID *guid, ULONG section_kind,
5744                                                       const UNICODE_STRING *section_name, PVOID ptr )
5745 {
5746     PACTCTX_SECTION_KEYED_DATA data = ptr;
5747     NTSTATUS status;
5748 
5749     DPRINT("RtlFindActivationContextSectionString(%x %p %x %wZ %p)\n", flags, guid, section_kind, section_name, ptr);
5750     status = RtlpFindActivationContextSection_CheckParameters(flags, guid, section_kind, section_name, data);
5751     if (!NT_SUCCESS(status))
5752     {
5753         DPRINT1("RtlFindActivationContextSectionString() failed with status %x\n", status);
5754         return status;
5755     }
5756 
5757     status = STATUS_SXS_KEY_NOT_FOUND;
5758 
5759     /* if there is no data, but params are valid,
5760        we return that sxs key is not found to be at least somehow compatible */
5761     if (!data)
5762     {
5763         DPRINT("RtlFindActivationContextSectionString() failed with status %x\n", status);
5764         return status;
5765     }
5766 
5767     ASSERT(NtCurrentTeb());
5768     ASSERT(NtCurrentTeb()->ActivationContextStackPointer);
5769 
5770     DPRINT("ActiveFrame: %p\n",NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame);
5771     if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
5772     {
5773         ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext);
5774         if (actctx) status = find_string( actctx, section_kind, section_name, flags, data );
5775     }
5776 
5777     DPRINT("status %x\n", status);
5778     if (status != STATUS_SUCCESS)
5779         status = find_string( process_actctx, section_kind, section_name, flags, data );
5780 
5781     if (status != STATUS_SUCCESS)
5782         status = find_string( implicit_actctx, section_kind, section_name, flags, data );
5783 
5784     DPRINT("RtlFindActivationContextSectionString() returns status %x\n", status);
5785     return status;
5786 }
5787 
5788 /***********************************************************************
5789  *		RtlFindActivationContextSectionGuid (NTDLL.@)
5790  *
5791  * Find information about a GUID in an activation context.
5792  * FIXME: function signature/prototype may be wrong
5793  */
5794 NTSTATUS WINAPI RtlFindActivationContextSectionGuid( ULONG flags, const GUID *extguid, ULONG section_kind,
5795                                                      const GUID *guid, void *ptr )
5796 {
5797     ACTCTX_SECTION_KEYED_DATA *data = ptr;
5798     NTSTATUS status = STATUS_SXS_KEY_NOT_FOUND;
5799 
5800     if (extguid)
5801     {
5802         DPRINT1("expected extguid == NULL\n");
5803         return STATUS_INVALID_PARAMETER;
5804     }
5805 
5806     if (flags & ~FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
5807     {
5808         DPRINT1("unknown flags %08x\n", flags);
5809         return STATUS_INVALID_PARAMETER;
5810     }
5811 
5812     if (!data || data->cbSize < FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) || !guid)
5813         return STATUS_INVALID_PARAMETER;
5814 
5815     if (NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame)
5816     {
5817         ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame->ActivationContext);
5818         if (actctx) status = find_guid( actctx, section_kind, guid, flags, data );
5819     }
5820 
5821     if (status != STATUS_SUCCESS)
5822         status = find_guid( process_actctx, section_kind, guid, flags, data );
5823 
5824     if (status != STATUS_SUCCESS)
5825         status = find_guid( implicit_actctx, section_kind, guid, flags, data );
5826 
5827     return status;
5828 }
5829 
5830 /* Stubs */
5831 
5832 NTSTATUS
5833 NTAPI
5834 RtlAllocateActivationContextStack(IN PACTIVATION_CONTEXT_STACK *Stack)
5835 {
5836     PACTIVATION_CONTEXT_STACK ContextStack;
5837 
5838     /* Check if it's already allocated */
5839     if (*Stack) return STATUS_SUCCESS;
5840 
5841     /* Allocate space for the context stack */
5842     ContextStack = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACTIVATION_CONTEXT_STACK));
5843     if (!ContextStack)
5844     {
5845         return STATUS_NO_MEMORY;
5846     }
5847 
5848     /* Initialize the context stack */
5849     ContextStack->Flags = 0;
5850     ContextStack->ActiveFrame = NULL;
5851     InitializeListHead(&ContextStack->FrameListCache);
5852     ContextStack->NextCookieSequenceNumber = 1;
5853     ContextStack->StackId = 1; //TODO: Timer-based
5854 
5855     *Stack = ContextStack;
5856 
5857     return STATUS_SUCCESS;
5858 }
5859 
5860 PRTL_ACTIVATION_CONTEXT_STACK_FRAME
5861 FASTCALL
5862 RtlActivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame,
5863                                        IN PVOID Context)
5864 {
5865     RTL_ACTIVATION_CONTEXT_STACK_FRAME *NewFrame;
5866     RTL_ACTIVATION_CONTEXT_STACK_FRAME *ActiveFrame;
5867 
5868     /* Get the current active frame */
5869     ActiveFrame = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
5870 
5871     DPRINT("ActiveSP %p: ACTIVATE (ActiveFrame %p -> NewFrame %p, Context %p)\n",
5872         NtCurrentTeb()->ActivationContextStackPointer, ActiveFrame,
5873         &Frame->Frame, Context);
5874 
5875     /* Ensure it's in the right format and at least fits basic info */
5876     ASSERT(Frame->Format == RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER);
5877     ASSERT(Frame->Size >= sizeof(RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_BASIC));
5878 
5879     /* Set debug info if size allows*/
5880     if (Frame->Size >= sizeof(RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED))
5881     {
5882         Frame->Extra1 = (PVOID)(~(ULONG_PTR)ActiveFrame);
5883         Frame->Extra2 = (PVOID)(~(ULONG_PTR)Context);
5884         //Frame->Extra3 = ...;
5885     }
5886 
5887     if (ActiveFrame)
5888     {
5889         /*ASSERT((ActiveFrame->Flags &
5890             (RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ACTIVATED |
5891              RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_DEACTIVATED |
5892              RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NOT_REALLY_ACTIVATED)) == RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ACTIVATED);*/
5893 
5894         if (!(ActiveFrame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED))
5895         {
5896             // TODO: Perform some additional checks if it was not heap allocated
5897         }
5898     }
5899 
5900     /* Save pointer to the new activation frame */
5901     NewFrame = &Frame->Frame;
5902 
5903     /* Actually activate it */
5904     Frame->Frame.Previous = ActiveFrame;
5905     Frame->Frame.ActivationContext = Context;
5906     Frame->Frame.Flags = RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ACTIVATED;
5907 
5908     /* Check if we can activate this context */
5909     if ((ActiveFrame && (ActiveFrame->ActivationContext != Context)) ||
5910         Context)
5911     {
5912         /* Set new active frame */
5913         DPRINT("Setting new active frame %p instead of old %p\n", NewFrame, ActiveFrame);
5914         NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NewFrame;
5915         return NewFrame;
5916     }
5917 
5918     /* We can get here only one way: it was already activated */
5919     DPRINT("Trying to activate already activated activation context\n");
5920 
5921     /* Activate only if we are allowing multiple activation */
5922 #if 0
5923     if (!RtlpNotAllowingMultipleActivation)
5924     {
5925         Frame->Frame.Flags = RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ACTIVATED | RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NOT_REALLY_ACTIVATED;
5926         NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NewFrame;
5927     }
5928 #else
5929     // Activate it anyway
5930     NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NewFrame;
5931 #endif
5932 
5933     /* Return pointer to the activation frame */
5934     return NewFrame;
5935 }
5936 
5937 PRTL_ACTIVATION_CONTEXT_STACK_FRAME
5938 FASTCALL
5939 RtlDeactivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame)
5940 {
5941     PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame, NewFrame;
5942 
5943     ActiveFrame = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
5944 
5945     /* Ensure it's in the right format and at least fits basic info */
5946     ASSERT(Frame->Format == RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER);
5947     ASSERT(Frame->Size >= sizeof(RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_BASIC));
5948 
5949     /* Make sure it is not deactivated and it is activated */
5950     ASSERT((Frame->Frame.Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_DEACTIVATED) == 0);
5951     ASSERT(Frame->Frame.Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ACTIVATED);
5952     ASSERT((Frame->Frame.Flags & (RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ACTIVATED | RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_DEACTIVATED)) == RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ACTIVATED);
5953 
5954     /* Check debug info if it is present */
5955     if (Frame->Size >= sizeof(RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED))
5956     {
5957         ASSERT(Frame->Extra1 == (PVOID)(~(ULONG_PTR)Frame->Frame.Previous));
5958         ASSERT(Frame->Extra2 == (PVOID)(~(ULONG_PTR)Frame->Frame.ActivationContext));
5959         //Frame->Extra3 = ...;
5960     }
5961 
5962     if (ActiveFrame)
5963     {
5964         // TODO: Perform some additional checks here
5965     }
5966 
5967     /* Special handling for not-really-activated */
5968     if (Frame->Frame.Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NOT_REALLY_ACTIVATED)
5969     {
5970         DPRINT1("Deactivating not really activated activation context\n");
5971         Frame->Frame.Flags |= RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_DEACTIVATED;
5972         return &Frame->Frame;
5973     }
5974 
5975     /* find the right frame */
5976     NewFrame = &Frame->Frame;
5977     if (ActiveFrame != NewFrame)
5978     {
5979         DPRINT1("Deactivating wrong active frame: %p != %p\n", ActiveFrame, NewFrame);
5980     }
5981 
5982     DPRINT("ActiveSP %p: DEACTIVATE (ActiveFrame %p -> PreviousFrame %p)\n",
5983         NtCurrentTeb()->ActivationContextStackPointer, NewFrame, NewFrame->Previous);
5984 
5985     /* Pop everything up to and including frame */
5986     NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame = NewFrame->Previous;
5987 
5988     Frame->Frame.Flags |= RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_DEACTIVATED;
5989     return NewFrame->Previous;
5990 }
5991