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