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