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