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