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
9 * Jacek Caban for CodeWeavers
11 * Stefan Ginsberg (stefan__100__@hotmail.com)
15 /* Based on Wine 1.7.17 */
22 #include <wine/unicode.h>
24 BOOLEAN RtlpNotAllowingMultipleActivation
;
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 )
36 #define STRSECTION_MAGIC 0x64487353 /* dHsS */
37 #define GUIDSECTION_MAGIC 0x64487347 /* dHsG */
39 #define ACTCTX_MAGIC_MARKER (PVOID)'gMcA'
41 #define ACTCTX_FAKE_HANDLE ((HANDLE) 0xf00baa)
42 #define ACTCTX_FAKE_COOKIE ((ULONG_PTR) 0xf00bad)
64 struct assembly_version
72 struct assembly_identity
79 struct assembly_version version
;
83 struct strsection_header
97 ULONG hash
; /* key string hash */
100 ULONG data_offset
; /* redirect data offset */
105 struct guidsection_header
125 struct wndclass_redirect_data
130 ULONG name_offset
; /* versioned name offset */
132 ULONG module_offset
;/* container name offset */
135 struct dllredirect_data
142 struct tlibredirect_data
156 enum comclass_threadingmodel
158 ThreadingModel_Apartment
= 1,
159 ThreadingModel_Free
= 2,
160 ThreadingModel_No
= 3,
161 ThreadingModel_Both
= 4,
162 ThreadingModel_Neutral
= 5
165 enum comclass_miscfields
169 MiscStatusContent
= 4,
170 MiscStatusThumbnail
= 8,
171 MiscStatusDocPrint
= 16
174 struct comclassredirect_data
190 ULONG clrdata_offset
;
192 DWORD miscstatuscontent
;
193 DWORD miscstatusthumbnail
;
194 DWORD miscstatusicon
;
195 DWORD miscstatusdocprint
;
204 struct ifacepsredirect_data
216 struct clrsurrogate_data
221 ULONG version_offset
;
236 ULONG version_offset
;
240 struct progidredirect_data
251 Sections are accessible by string or guid key, that defines two types of sections.
252 All sections of each type have same magic value and header structure, index
253 data could be of two possible types too. So every string based section uses
254 the same index format, same applies to guid sections - they share same guid index
257 - window class redirection section is a plain buffer with following format:
261 <data[]> --- <original name>
266 Header is fixed length structure - struct strsection_header,
267 contains redirected classes count;
269 Index is an array of fixed length index records, each record is
272 All strings in data itself are WCHAR, null terminated, 4-bytes aligned.
274 Versioned name offset is relative to redirect data structure (struct wndclass_redirect_data),
275 others are relative to section itself.
277 - dll redirect section format:
281 <data[]> --- <dll name>
284 This section doesn't seem to carry any payload data except dll names.
286 - typelib section format:
294 Header is fixed length, index is an array of fixed length 'struct guid_index'.
295 All strings are WCHAR, null terminated, 4-bytes aligned. Module names part is
296 4-bytes aligned as a whole.
298 Module name offsets are relative to section, helpstring offset is relative to data
301 - comclass section format:
306 <data[]> --- <data> --- <data>
312 This section uses two index records per comclass, one entry contains original guid
313 as specified by context, another one has a generated guid. Index and strings handling
314 is similar to typelib sections.
316 For CLR classes additional data is stored after main COM class data, it contains
317 class name and runtime version string, see 'struct clrclass_data'.
319 Module name offsets are relative to section, progid offset is relative to data
322 - COM interface section format:
329 Interface section contains data for proxy/stubs and external proxy/stubs. External
330 ones are defined at assembly level, so this section has no module information.
331 All records are indexed with 'iid' value from manifest. There an exception for
332 external variants - if 'proxyStubClsid32' is specified, it's stored as iid in
333 redirect data, but index is still 'iid' from manifest.
335 Interface name offset is relative to data structure itself.
337 - CLR surrogates section format:
345 There's nothing special about this section, same way to store strings is used,
346 no modules part as it belongs to assembly level, not a file.
348 - ProgID section format:
353 <data[]> --- <progid>
356 This sections uses generated alias guids from COM server section. This way
357 ProgID -> CLSID mapping returns generated guid, not the real one. ProgID string
358 is stored too, aligned.
365 unsigned int allocated
;
386 WCHAR
*name
; /* clrClass: class name */
387 WCHAR
*version
; /* clrClass: CLR runtime version */
390 DWORD miscstatuscontent
;
391 DWORD miscstatusthumbnail
;
392 DWORD miscstatusicon
;
393 DWORD miscstatusdocprint
;
394 struct progids progids
;
401 WCHAR
*ps32
; /* only stored for 'comInterfaceExternalProxyStub' */
423 unsigned int allocated
;
430 struct entity_array entities
;
435 APPLICATION_MANIFEST
,
437 ASSEMBLY_SHARED_MANIFEST
,
442 enum assembly_type type
;
443 struct assembly_identity id
;
444 struct file_info manifest
;
447 struct dll_redirect
*dlls
;
448 unsigned int num_dlls
;
449 unsigned int allocated_dlls
;
450 struct entity_array entities
;
453 enum context_sections
455 WINDOWCLASS_SECTION
= 1,
456 DLLREDIRECT_SECTION
= 2,
457 TLIBREDIRECT_SECTION
= 4,
458 SERVERREDIRECT_SECTION
= 8,
459 IFACEREDIRECT_SECTION
= 16,
460 CLRSURROGATES_SECTION
= 32,
461 PROGIDREDIRECT_SECTION
= 64
464 typedef struct _ASSEMBLY_STORAGE_MAP_ENTRY
467 UNICODE_STRING DosPath
;
469 } ASSEMBLY_STORAGE_MAP_ENTRY
, *PASSEMBLY_STORAGE_MAP_ENTRY
;
471 typedef struct _ASSEMBLY_STORAGE_MAP
475 PASSEMBLY_STORAGE_MAP_ENTRY
*AssemblyArray
;
476 } ASSEMBLY_STORAGE_MAP
, *PASSEMBLY_STORAGE_MAP
;
478 typedef struct _ACTIVATION_CONTEXT
483 PACTIVATION_CONTEXT_DATA ActivationContextData
;
484 PVOID NotificationRoutine
;
485 PVOID NotificationContext
;
486 ULONG SentNotifications
[8];
487 ULONG DisabledNotifications
[8];
488 ASSEMBLY_STORAGE_MAP StorageMap
;
489 PASSEMBLY_STORAGE_MAP_ENTRY InlineStorageMapEntries
;
490 ULONG StackTraceIndex
;
491 PVOID StackTraces
[4][4];
492 struct file_info config
;
493 struct file_info appdir
;
494 struct assembly
*assemblies
;
495 unsigned int num_assemblies
;
496 unsigned int allocated_assemblies
;
499 struct strsection_header
*wndclass_section
;
500 struct strsection_header
*dllredirect_section
;
501 struct strsection_header
*progid_section
;
502 struct guidsection_header
*tlib_section
;
503 struct guidsection_header
*comserver_section
;
504 struct guidsection_header
*ifaceps_section
;
505 struct guidsection_header
*clrsurrogate_section
;
506 } ACTIVATION_CONTEXT
, *PIACTIVATION_CONTEXT
;
510 ACTIVATION_CONTEXT
*actctx
;
511 struct assembly_identity
*dependencies
;
512 unsigned int num_dependencies
;
513 unsigned int allocated_dependencies
;
516 static const WCHAR asmv1W
[] = {'a','s','m','v','1',':',0};
517 static const WCHAR asmv2W
[] = {'a','s','m','v','2',':',0};
519 typedef struct _ACTIVATION_CONTEXT_WRAPPED
522 ACTIVATION_CONTEXT ActivationContext
;
523 } ACTIVATION_CONTEXT_WRAPPED
, *PACTIVATION_CONTEXT_WRAPPED
;
527 RtlpSxsBreakOnInvalidMarker(IN PACTIVATION_CONTEXT ActCtx
,
528 IN ULONG FailureCode
)
530 EXCEPTION_RECORD ExceptionRecord
;
532 /* Fatal SxS exception header */
533 ExceptionRecord
.ExceptionRecord
= NULL
;
534 ExceptionRecord
.ExceptionCode
= STATUS_SXS_CORRUPTION
;
535 ExceptionRecord
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
537 /* With SxS-specific information plus the context itself */
538 ExceptionRecord
.ExceptionInformation
[0] = 1;
539 ExceptionRecord
.ExceptionInformation
[1] = FailureCode
;
540 ExceptionRecord
.ExceptionInformation
[2] = (ULONG_PTR
)ActCtx
;
541 ExceptionRecord
.NumberParameters
= 3;
544 RtlRaiseException(&ExceptionRecord
);
549 RtlpValidateActCtx(IN PACTIVATION_CONTEXT ActCtx
)
551 PACTIVATION_CONTEXT_WRAPPED pActual
;
553 /* Get the caller-opaque header */
554 pActual
= CONTAINING_RECORD(ActCtx
,
555 ACTIVATION_CONTEXT_WRAPPED
,
558 /* Check if the header matches as expected */
559 if (pActual
->MagicMarker
!= ACTCTX_MAGIC_MARKER
)
561 /* Nope, print out a warning, assert, and then throw an exception */
562 DbgPrint("%s : Invalid activation context marker %p found in activation context %p\n"
563 " This means someone stepped on the allocation, or someone is using a\n"
564 " deallocated activation context\n",
566 pActual
->MagicMarker
,
568 ASSERT(pActual
->MagicMarker
== ACTCTX_MAGIC_MARKER
);
569 RtlpSxsBreakOnInvalidMarker(ActCtx
, 1);
573 static const WCHAR assemblyW
[] = {'a','s','s','e','m','b','l','y',0};
574 static const WCHAR assemblyIdentityW
[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
575 static const WCHAR bindingRedirectW
[] = {'b','i','n','d','i','n','g','R','e','d','i','r','e','c','t',0};
576 static const WCHAR clrClassW
[] = {'c','l','r','C','l','a','s','s',0};
577 static const WCHAR clrSurrogateW
[] = {'c','l','r','S','u','r','r','o','g','a','t','e',0};
578 static const WCHAR comClassW
[] = {'c','o','m','C','l','a','s','s',0};
579 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};
580 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};
581 static const WCHAR dependencyW
[] = {'d','e','p','e','n','d','e','n','c','y',0};
582 static const WCHAR dependentAssemblyW
[] = {'d','e','p','e','n','d','e','n','t','A','s','s','e','m','b','l','y',0};
583 static const WCHAR descriptionW
[] = {'d','e','s','c','r','i','p','t','i','o','n',0};
584 static const WCHAR fileW
[] = {'f','i','l','e',0};
585 static const WCHAR noInheritW
[] = {'n','o','I','n','h','e','r','i','t',0};
586 static const WCHAR noInheritableW
[] = {'n','o','I','n','h','e','r','i','t','a','b','l','e',0};
587 static const WCHAR typelibW
[] = {'t','y','p','e','l','i','b',0};
588 static const WCHAR windowClassW
[] = {'w','i','n','d','o','w','C','l','a','s','s',0};
590 static const WCHAR clsidW
[] = {'c','l','s','i','d',0};
591 static const WCHAR hashW
[] = {'h','a','s','h',0};
592 static const WCHAR hashalgW
[] = {'h','a','s','h','a','l','g',0};
593 static const WCHAR helpdirW
[] = {'h','e','l','p','d','i','r',0};
594 static const WCHAR iidW
[] = {'i','i','d',0};
595 static const WCHAR languageW
[] = {'l','a','n','g','u','a','g','e',0};
596 static const WCHAR manifestVersionW
[] = {'m','a','n','i','f','e','s','t','V','e','r','s','i','o','n',0};
597 static const WCHAR g_nameW
[] = {'n','a','m','e',0};
598 static const WCHAR neutralW
[] = {'n','e','u','t','r','a','l',0};
599 static const WCHAR newVersionW
[] = {'n','e','w','V','e','r','s','i','o','n',0};
600 static const WCHAR oldVersionW
[] = {'o','l','d','V','e','r','s','i','o','n',0};
601 static const WCHAR optionalW
[] = {'o','p','t','i','o','n','a','l',0};
602 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};
603 static const WCHAR progidW
[] = {'p','r','o','g','i','d',0};
604 static const WCHAR publicKeyTokenW
[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
605 static const WCHAR threadingmodelW
[] = {'t','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
606 static const WCHAR tlbidW
[] = {'t','l','b','i','d',0};
607 static const WCHAR typeW
[] = {'t','y','p','e',0};
608 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
609 static const WCHAR xmlnsW
[] = {'x','m','l','n','s',0};
610 static const WCHAR versionedW
[] = {'v','e','r','s','i','o','n','e','d',0};
611 static const WCHAR yesW
[] = {'y','e','s',0};
612 static const WCHAR noW
[] = {'n','o',0};
613 static const WCHAR restrictedW
[] = {'R','E','S','T','R','I','C','T','E','D',0};
614 static const WCHAR controlW
[] = {'C','O','N','T','R','O','L',0};
615 static const WCHAR hiddenW
[] = {'H','I','D','D','E','N',0};
616 static const WCHAR hasdiskimageW
[] = {'H','A','S','D','I','S','K','I','M','A','G','E',0};
617 static const WCHAR flagsW
[] = {'f','l','a','g','s',0};
618 static const WCHAR miscstatusW
[] = {'m','i','s','c','S','t','a','t','u','s',0};
619 static const WCHAR miscstatusiconW
[] = {'m','i','s','c','S','t','a','t','u','s','I','c','o','n',0};
620 static const WCHAR miscstatuscontentW
[] = {'m','i','s','c','S','t','a','t','u','s','C','o','n','t','e','n','t',0};
621 static const WCHAR miscstatusthumbnailW
[] = {'m','i','s','c','S','t','a','t','u','s','T','h','u','m','b','n','a','i','l',0};
622 static const WCHAR miscstatusdocprintW
[] = {'m','i','s','c','S','t','a','t','u','s','D','o','c','P','r','i','n','t',0};
623 static const WCHAR baseInterfaceW
[] = {'b','a','s','e','I','n','t','e','r','f','a','c','e',0};
624 static const WCHAR nummethodsW
[] = {'n','u','m','M','e','t','h','o','d','s',0};
625 static const WCHAR proxyStubClsid32W
[] = {'p','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
626 static const WCHAR runtimeVersionW
[] = {'r','u','n','t','i','m','e','V','e','r','s','i','o','n',0};
627 static const WCHAR mscoreeW
[] = {'M','S','C','O','R','E','E','.','D','L','L',0};
628 static const WCHAR mscoree2W
[] = {'m','s','c','o','r','e','e','.','d','l','l',0};
630 static const WCHAR activatewhenvisibleW
[] = {'a','c','t','i','v','a','t','e','w','h','e','n','v','i','s','i','b','l','e',0};
631 static const WCHAR actslikebuttonW
[] = {'a','c','t','s','l','i','k','e','b','u','t','t','o','n',0};
632 static const WCHAR actslikelabelW
[] = {'a','c','t','s','l','i','k','e','l','a','b','e','l',0};
633 static const WCHAR alignableW
[] = {'a','l','i','g','n','a','b','l','e',0};
634 static const WCHAR alwaysrunW
[] = {'a','l','w','a','y','s','r','u','n',0};
635 static const WCHAR canlinkbyole1W
[] = {'c','a','n','l','i','n','k','b','y','o','l','e','1',0};
636 static const WCHAR cantlinkinsideW
[] = {'c','a','n','t','l','i','n','k','i','n','s','i','d','e',0};
637 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};
638 static const WCHAR imemodeW
[] = {'i','m','e','m','o','d','e',0};
639 static const WCHAR insertnotreplaceW
[] = {'i','n','s','e','r','t','n','o','t','r','e','p','l','a','c','e',0};
640 static const WCHAR insideoutW
[] = {'i','n','s','i','d','e','o','u','t',0};
641 static const WCHAR invisibleatruntimeW
[] = {'i','n','v','i','s','i','b','l','e','a','t','r','u','n','t','i','m','e',0};
642 static const WCHAR islinkobjectW
[] = {'i','s','l','i','n','k','o','b','j','e','c','t',0};
643 static const WCHAR nouiactivateW
[] = {'n','o','u','i','a','c','t','i','v','a','t','e',0};
644 static const WCHAR onlyiconicW
[] = {'o','n','l','y','i','c','o','n','i','c',0};
645 static const WCHAR recomposeonresizeW
[] = {'r','e','c','o','m','p','o','s','e','o','n','r','e','s','i','z','e',0};
646 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};
647 static const WCHAR setclientsitefirstW
[] = {'s','e','t','c','l','i','e','n','t','s','i','t','e','f','i','r','s','t',0};
648 static const WCHAR simpleframeW
[] = {'s','i','m','p','l','e','f','r','a','m','e',0};
649 static const WCHAR staticW
[] = {'s','t','a','t','i','c',0};
650 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};
651 static const WCHAR wantstomenumergeW
[] = {'w','a','n','t','s','t','o','m','e','n','u','m','e','r','g','e',0};
659 static const struct olemisc_entry olemisc_values
[] =
661 { activatewhenvisibleW
, OLEMISC_ACTIVATEWHENVISIBLE
},
662 { actslikebuttonW
, OLEMISC_ACTSLIKEBUTTON
},
663 { actslikelabelW
, OLEMISC_ACTSLIKELABEL
},
664 { alignableW
, OLEMISC_ALIGNABLE
},
665 { alwaysrunW
, OLEMISC_ALWAYSRUN
},
666 { canlinkbyole1W
, OLEMISC_CANLINKBYOLE1
},
667 { cantlinkinsideW
, OLEMISC_CANTLINKINSIDE
},
668 { ignoreactivatewhenvisibleW
, OLEMISC_IGNOREACTIVATEWHENVISIBLE
},
669 { imemodeW
, OLEMISC_IMEMODE
},
670 { insertnotreplaceW
, OLEMISC_INSERTNOTREPLACE
},
671 { insideoutW
, OLEMISC_INSIDEOUT
},
672 { invisibleatruntimeW
, OLEMISC_INVISIBLEATRUNTIME
},
673 { islinkobjectW
, OLEMISC_ISLINKOBJECT
},
674 { nouiactivateW
, OLEMISC_NOUIACTIVATE
},
675 { onlyiconicW
, OLEMISC_ONLYICONIC
},
676 { recomposeonresizeW
, OLEMISC_RECOMPOSEONRESIZE
},
677 { renderingisdeviceindependentW
, OLEMISC_RENDERINGISDEVICEINDEPENDENT
},
678 { setclientsitefirstW
, OLEMISC_SETCLIENTSITEFIRST
},
679 { simpleframeW
, OLEMISC_SIMPLEFRAME
},
680 { staticW
, OLEMISC_STATIC
},
681 { supportsmultilevelundoW
, OLEMISC_SUPPORTSMULTILEVELUNDO
},
682 { wantstomenumergeW
, OLEMISC_WANTSTOMENUMERGE
}
685 static const WCHAR g_xmlW
[] = {'?','x','m','l',0};
686 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};
687 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};
689 static const WCHAR dotManifestW
[] = {'.','m','a','n','i','f','e','s','t',0};
690 static const WCHAR version_formatW
[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
691 static const WCHAR wildcardW
[] = {'*',0};
693 static ACTIVATION_CONTEXT_WRAPPED system_actctx
= { ACTCTX_MAGIC_MARKER
, { 1 } };
694 static ACTIVATION_CONTEXT
*process_actctx
= &system_actctx
.ActivationContext
;
696 static WCHAR
*strdupW(const WCHAR
* str
)
700 if (!(ptr
= RtlAllocateHeap(RtlGetProcessHeap(), 0, (strlenW(str
) + 1) * sizeof(WCHAR
))))
702 return strcpyW(ptr
, str
);
705 static WCHAR
*xmlstrdupW(const xmlstr_t
* str
)
709 if ((strW
= RtlAllocateHeap(RtlGetProcessHeap(), 0, (str
->len
+ 1) * sizeof(WCHAR
))))
711 memcpy( strW
, str
->ptr
, str
->len
* sizeof(WCHAR
) );
717 static inline BOOL
xmlstr_cmp(const xmlstr_t
* xmlstr
, const WCHAR
*str
)
719 return !strncmpW(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
722 static inline BOOL
xmlstr_cmpi(const xmlstr_t
* xmlstr
, const WCHAR
*str
)
724 return !strncmpiW(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
727 static inline BOOL
xmlstr_cmp_end(const xmlstr_t
* xmlstr
, const WCHAR
*str
)
729 return (xmlstr
->len
&& xmlstr
->ptr
[0] == '/' &&
730 !strncmpW(xmlstr
->ptr
+ 1, str
, xmlstr
->len
- 1) && !str
[xmlstr
->len
- 1]);
733 static inline BOOL
xml_elem_cmp(const xmlstr_t
*elem
, const WCHAR
*str
, const WCHAR
*namespace)
735 UINT len
= strlenW( namespace );
737 if (!strncmpW(elem
->ptr
, str
, elem
->len
) && !str
[elem
->len
]) return TRUE
;
738 return (elem
->len
> len
&& !strncmpW(elem
->ptr
, namespace, len
) &&
739 !strncmpW(elem
->ptr
+ len
, str
, elem
->len
- len
) && !str
[elem
->len
- len
]);
742 static inline BOOL
xml_elem_cmp_end(const xmlstr_t
*elem
, const WCHAR
*str
, const WCHAR
*namespace)
744 if (elem
->len
&& elem
->ptr
[0] == '/')
747 elem_end
.ptr
= elem
->ptr
+ 1;
748 elem_end
.len
= elem
->len
- 1;
749 return xml_elem_cmp( &elem_end
, str
, namespace );
754 static inline BOOL
isxmlspace( WCHAR ch
)
756 return (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== '\t');
759 static UNICODE_STRING
xmlstr2unicode(const xmlstr_t
*xmlstr
)
763 res
.Buffer
= (PWSTR
)xmlstr
->ptr
;
764 res
.Length
= res
.MaximumLength
= (USHORT
)xmlstr
->len
* sizeof(WCHAR
);
769 static struct assembly
*add_assembly(ACTIVATION_CONTEXT
*actctx
, enum assembly_type at
)
771 struct assembly
*assembly
;
773 if (actctx
->num_assemblies
== actctx
->allocated_assemblies
)
776 unsigned int new_count
;
777 if (actctx
->assemblies
)
779 new_count
= actctx
->allocated_assemblies
* 2;
780 ptr
= RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
781 actctx
->assemblies
, new_count
* sizeof(*assembly
) );
786 ptr
= RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* sizeof(*assembly
) );
788 if (!ptr
) return NULL
;
789 actctx
->assemblies
= ptr
;
790 actctx
->allocated_assemblies
= new_count
;
793 assembly
= &actctx
->assemblies
[actctx
->num_assemblies
++];
798 static struct dll_redirect
* add_dll_redirect(struct assembly
* assembly
)
800 if (assembly
->num_dlls
== assembly
->allocated_dlls
)
803 unsigned int new_count
;
806 new_count
= assembly
->allocated_dlls
* 2;
807 ptr
= RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
808 assembly
->dlls
, new_count
* sizeof(*assembly
->dlls
) );
813 ptr
= RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* sizeof(*assembly
->dlls
) );
815 if (!ptr
) return NULL
;
816 assembly
->dlls
= ptr
;
817 assembly
->allocated_dlls
= new_count
;
819 return &assembly
->dlls
[assembly
->num_dlls
++];
822 static void free_assembly_identity(struct assembly_identity
*ai
)
824 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->name
);
825 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->arch
);
826 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->public_key
);
827 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->language
);
828 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->type
);
831 static struct entity
* add_entity(struct entity_array
*array
, DWORD kind
)
833 struct entity
* entity
;
835 if (array
->num
== array
->allocated
)
838 unsigned int new_count
;
841 new_count
= array
->allocated
* 2;
842 ptr
= RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
843 array
->base
, new_count
* sizeof(*array
->base
) );
848 ptr
= RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* sizeof(*array
->base
) );
850 if (!ptr
) return NULL
;
852 array
->allocated
= new_count
;
854 entity
= &array
->base
[array
->num
++];
859 static void free_entity_array(struct entity_array
*array
)
862 for (i
= 0; i
< array
->num
; i
++)
864 struct entity
*entity
= &array
->base
[i
];
865 switch (entity
->kind
)
867 case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
:
868 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.clsid
);
869 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.tlbid
);
870 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.progid
);
871 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.name
);
872 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.version
);
873 for (j
= 0; j
< entity
->u
.comclass
.progids
.num
; j
++)
874 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.progids
.progids
[j
]);
875 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.progids
.progids
);
877 case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
:
878 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.ifaceps
.iid
);
879 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.ifaceps
.base
);
880 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.ifaceps
.ps32
);
881 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.ifaceps
.name
);
883 case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
:
884 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.typelib
.tlbid
);
885 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.typelib
.helpdir
);
887 case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
:
888 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.class.name
);
890 case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
:
891 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.clrsurrogate
.name
);
892 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.clrsurrogate
.clsid
);
893 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.clrsurrogate
.version
);
896 DPRINT1("Unknown entity kind %u\n", entity
->kind
);
899 RtlFreeHeap( RtlGetProcessHeap(), 0, array
->base
);
902 static BOOL
is_matching_string( const WCHAR
*str1
, const WCHAR
*str2
)
904 if (!str1
) return !str2
;
905 return str2
&& !strcmpiW( str1
, str2
);
908 static BOOL
is_matching_identity( const struct assembly_identity
*id1
,
909 const struct assembly_identity
*id2
)
911 if (!is_matching_string( id1
->name
, id2
->name
)) return FALSE
;
912 if (!is_matching_string( id1
->arch
, id2
->arch
)) return FALSE
;
913 if (!is_matching_string( id1
->public_key
, id2
->public_key
)) return FALSE
;
915 if (id1
->language
&& id2
->language
&& strcmpiW( id1
->language
, id2
->language
))
917 if (strcmpW( wildcardW
, id1
->language
) && strcmpW( wildcardW
, id2
->language
))
920 if (id1
->version
.major
!= id2
->version
.major
) return FALSE
;
921 if (id1
->version
.minor
!= id2
->version
.minor
) return FALSE
;
922 if (id1
->version
.build
> id2
->version
.build
) return FALSE
;
923 if (id1
->version
.build
== id2
->version
.build
&&
924 id1
->version
.revision
> id2
->version
.revision
) return FALSE
;
928 static BOOL
add_dependent_assembly_id(struct actctx_loader
* acl
,
929 struct assembly_identity
* ai
)
933 /* check if we already have that assembly */
935 for (i
= 0; i
< acl
->actctx
->num_assemblies
; i
++)
936 if (is_matching_identity( ai
, &acl
->actctx
->assemblies
[i
].id
))
938 DPRINT( "reusing existing assembly for %S arch %S version %u.%u.%u.%u\n",
939 ai
->name
, ai
->arch
, ai
->version
.major
, ai
->version
.minor
,
940 ai
->version
.build
, ai
->version
.revision
);
944 for (i
= 0; i
< acl
->num_dependencies
; i
++)
945 if (is_matching_identity( ai
, &acl
->dependencies
[i
] ))
947 DPRINT( "reusing existing dependency for %S arch %S version %u.%u.%u.%u\n",
948 ai
->name
, ai
->arch
, ai
->version
.major
, ai
->version
.minor
,
949 ai
->version
.build
, ai
->version
.revision
);
953 if (acl
->num_dependencies
== acl
->allocated_dependencies
)
956 unsigned int new_count
;
957 if (acl
->dependencies
)
959 new_count
= acl
->allocated_dependencies
* 2;
960 ptr
= RtlReAllocateHeap(RtlGetProcessHeap(), 0, acl
->dependencies
,
961 new_count
* sizeof(acl
->dependencies
[0]));
966 ptr
= RtlAllocateHeap(RtlGetProcessHeap(), 0, new_count
* sizeof(acl
->dependencies
[0]));
968 if (!ptr
) return FALSE
;
969 acl
->dependencies
= ptr
;
970 acl
->allocated_dependencies
= new_count
;
972 acl
->dependencies
[acl
->num_dependencies
++] = *ai
;
977 static void free_depend_manifests(struct actctx_loader
* acl
)
980 for (i
= 0; i
< acl
->num_dependencies
; i
++)
981 free_assembly_identity(&acl
->dependencies
[i
]);
982 RtlFreeHeap(RtlGetProcessHeap(), 0, acl
->dependencies
);
985 static WCHAR
*build_assembly_dir(struct assembly_identity
* ai
)
987 static const WCHAR undW
[] = {'_',0};
988 static const WCHAR noneW
[] = {'n','o','n','e',0};
989 static const WCHAR mskeyW
[] = {'d','e','a','d','b','e','e','f',0};
991 const WCHAR
*arch
= ai
->arch
? ai
->arch
: noneW
;
992 const WCHAR
*key
= ai
->public_key
? ai
->public_key
: noneW
;
993 const WCHAR
*lang
= ai
->language
? ai
->language
: noneW
;
994 const WCHAR
*name
= ai
->name
? ai
->name
: noneW
;
995 SIZE_T size
= (strlenW(arch
) + 1 + strlenW(name
) + 1 + strlenW(key
) + 24 + 1 +
996 strlenW(lang
) + 1) * sizeof(WCHAR
) + sizeof(mskeyW
);
999 if (!(ret
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
))) return NULL
;
1001 strcpyW( ret
, arch
);
1002 strcatW( ret
, undW
);
1003 strcatW( ret
, name
);
1004 strcatW( ret
, undW
);
1005 strcatW( ret
, key
);
1006 strcatW( ret
, undW
);
1007 sprintfW( ret
+ strlenW(ret
), version_formatW
,
1008 ai
->version
.major
, ai
->version
.minor
, ai
->version
.build
, ai
->version
.revision
);
1009 strcatW( ret
, undW
);
1010 strcatW( ret
, lang
);
1011 strcatW( ret
, undW
);
1012 strcatW( ret
, mskeyW
);
1016 static inline void append_string( WCHAR
*buffer
, const WCHAR
*prefix
, const WCHAR
*str
)
1021 strcatW( buffer
, prefix
);
1030 static WCHAR
*build_assembly_id( const struct assembly_identity
*ai
)
1032 static const WCHAR archW
[] =
1033 {',','p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e','=',0};
1034 static const WCHAR public_keyW
[] =
1035 {',','p','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
1036 static const WCHAR typeW2
[] =
1037 {',','t','y','p','e','=',0};
1038 static const WCHAR versionW2
[] =
1039 {',','v','e','r','s','i','o','n','=',0};
1041 WCHAR version
[64], *ret
;
1044 sprintfW( version
, version_formatW
,
1045 ai
->version
.major
, ai
->version
.minor
, ai
->version
.build
, ai
->version
.revision
);
1046 if (ai
->name
) size
+= strlenW(ai
->name
) * sizeof(WCHAR
);
1047 if (ai
->arch
) size
+= strlenW(archW
) + strlenW(ai
->arch
) + 2;
1048 if (ai
->public_key
) size
+= strlenW(public_keyW
) + strlenW(ai
->public_key
) + 2;
1049 if (ai
->type
) size
+= strlenW(typeW2
) + strlenW(ai
->type
) + 2;
1050 size
+= strlenW(versionW2
) + strlenW(version
) + 2;
1052 if (!(ret
= RtlAllocateHeap( RtlGetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
) )))
1055 if (ai
->name
) strcpyW( ret
, ai
->name
);
1057 append_string( ret
, archW
, ai
->arch
);
1058 append_string( ret
, public_keyW
, ai
->public_key
);
1059 append_string( ret
, typeW2
, ai
->type
);
1060 append_string( ret
, versionW2
, version
);
1063 static ACTIVATION_CONTEXT
*check_actctx( HANDLE h
)
1065 ACTIVATION_CONTEXT
*ret
= NULL
, *actctx
= h
;
1066 PACTIVATION_CONTEXT_WRAPPED pActual
;
1068 if (!h
|| h
== INVALID_HANDLE_VALUE
) return NULL
;
1073 pActual
= CONTAINING_RECORD(actctx
, ACTIVATION_CONTEXT_WRAPPED
, ActivationContext
);
1074 if (pActual
->MagicMarker
== ACTCTX_MAGIC_MARKER
) ret
= &pActual
->ActivationContext
;
1077 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1079 DPRINT1("Invalid activation context handle!\n");
1085 static inline void actctx_addref( ACTIVATION_CONTEXT
*actctx
)
1087 InterlockedExchangeAdd( &actctx
->RefCount
, 1 );
1090 static void actctx_release( ACTIVATION_CONTEXT
*actctx
)
1092 PACTIVATION_CONTEXT_WRAPPED pActual
;
1094 if (InterlockedExchangeAdd(&actctx
->RefCount
, -1) == 1)
1098 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
1100 struct assembly
*assembly
= &actctx
->assemblies
[i
];
1101 for (j
= 0; j
< assembly
->num_dlls
; j
++)
1103 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
1104 free_entity_array( &dll
->entities
);
1105 RtlFreeHeap( RtlGetProcessHeap(), 0, dll
->name
);
1106 RtlFreeHeap( RtlGetProcessHeap(), 0, dll
->hash
);
1108 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly
->dlls
);
1109 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly
->manifest
.info
);
1110 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly
->directory
);
1111 free_entity_array( &assembly
->entities
);
1112 free_assembly_identity(&assembly
->id
);
1114 RtlFreeHeap( RtlGetProcessHeap(), 0, actctx
->config
.info
);
1115 RtlFreeHeap( RtlGetProcessHeap(), 0, actctx
->appdir
.info
);
1116 RtlFreeHeap( RtlGetProcessHeap(), 0, actctx
->assemblies
);
1117 pActual
= CONTAINING_RECORD(actctx
, ACTIVATION_CONTEXT_WRAPPED
, ActivationContext
);
1118 pActual
->MagicMarker
= 0;
1119 RtlFreeHeap(RtlGetProcessHeap(), 0, pActual
);
1123 static BOOL
next_xml_attr(xmlbuf_t
* xmlbuf
, xmlstr_t
* name
, xmlstr_t
* value
,
1124 BOOL
* error
, BOOL
* end
)
1130 while (xmlbuf
->ptr
< xmlbuf
->end
&& isxmlspace(*xmlbuf
->ptr
))
1133 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
1135 if (*xmlbuf
->ptr
== '/')
1138 if (xmlbuf
->ptr
== xmlbuf
->end
|| *xmlbuf
->ptr
!= '>')
1147 if (*xmlbuf
->ptr
== '>')
1155 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && *ptr
!= '>' && !isxmlspace(*ptr
)) ptr
++;
1157 if (ptr
== xmlbuf
->end
) return FALSE
;
1159 name
->ptr
= xmlbuf
->ptr
;
1160 name
->len
= ptr
-xmlbuf
->ptr
;
1163 /* skip spaces before '=' */
1164 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && isxmlspace(*ptr
)) ptr
++;
1165 if (ptr
== xmlbuf
->end
|| *ptr
!= '=') return FALSE
;
1167 /* skip '=' itself */
1169 if (ptr
== xmlbuf
->end
) return FALSE
;
1171 /* skip spaces after '=' */
1172 while (ptr
< xmlbuf
->end
&& *ptr
!= '"' && *ptr
!= '\'' && isxmlspace(*ptr
)) ptr
++;
1174 if (ptr
== xmlbuf
->end
|| (*ptr
!= '"' && *ptr
!= '\'')) return FALSE
;
1177 if (ptr
== xmlbuf
->end
) return FALSE
;
1179 ptr
= memchrW(ptr
, ptr
[-1], xmlbuf
->end
- ptr
);
1182 xmlbuf
->ptr
= xmlbuf
->end
;
1186 value
->len
= ptr
- value
->ptr
;
1187 xmlbuf
->ptr
= ptr
+ 1;
1189 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
1195 static BOOL
next_xml_elem(xmlbuf_t
* xmlbuf
, xmlstr_t
* elem
)
1201 ptr
= memchrW(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
1204 xmlbuf
->ptr
= xmlbuf
->end
;
1208 if (ptr
+ 3 < xmlbuf
->end
&& ptr
[0] == '!' && ptr
[1] == '-' && ptr
[2] == '-') /* skip comment */
1210 for (ptr
+= 3; ptr
+ 3 <= xmlbuf
->end
; ptr
++)
1211 if (ptr
[0] == '-' && ptr
[1] == '-' && ptr
[2] == '>') break;
1213 if (ptr
+ 3 > xmlbuf
->end
)
1215 xmlbuf
->ptr
= xmlbuf
->end
;
1218 xmlbuf
->ptr
= ptr
+ 3;
1224 while (ptr
< xmlbuf
->end
&& !isxmlspace(*ptr
) && *ptr
!= '>' && (*ptr
!= '/' || ptr
== xmlbuf
->ptr
))
1227 elem
->ptr
= xmlbuf
->ptr
;
1228 elem
->len
= ptr
- xmlbuf
->ptr
;
1230 return xmlbuf
->ptr
!= xmlbuf
->end
;
1233 static BOOL
parse_xml_header(xmlbuf_t
* xmlbuf
)
1235 /* FIXME: parse attributes */
1238 for (ptr
= xmlbuf
->ptr
; ptr
< xmlbuf
->end
- 1; ptr
++)
1240 if (ptr
[0] == '?' && ptr
[1] == '>')
1242 xmlbuf
->ptr
= ptr
+ 2;
1249 static BOOL
parse_text_content(xmlbuf_t
* xmlbuf
, xmlstr_t
* content
)
1251 const WCHAR
*ptr
= memchrW(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
1253 if (!ptr
) return FALSE
;
1255 content
->ptr
= xmlbuf
->ptr
;
1256 content
->len
= ptr
- xmlbuf
->ptr
;
1262 static BOOL
parse_version(const xmlstr_t
*str
, struct assembly_version
*version
)
1264 unsigned int ver
[4];
1267 UNICODE_STRING strU
;
1269 /* major.minor.build.revision */
1270 ver
[0] = ver
[1] = ver
[2] = ver
[3] = pos
= 0;
1271 for (curr
= str
->ptr
; curr
< str
->ptr
+ str
->len
; curr
++)
1273 if (*curr
>= '0' && *curr
<= '9')
1275 ver
[pos
] = ver
[pos
] * 10 + *curr
- '0';
1276 if (ver
[pos
] >= 0x10000) goto error
;
1278 else if (*curr
== '.')
1280 if (++pos
>= 4) goto error
;
1284 version
->major
= ver
[0];
1285 version
->minor
= ver
[1];
1286 version
->build
= ver
[2];
1287 version
->revision
= ver
[3];
1291 strU
= xmlstr2unicode(str
);
1292 DPRINT1( "Wrong version definition in manifest file (%wZ)\n", &strU
);
1296 static BOOL
parse_expect_elem(xmlbuf_t
* xmlbuf
, const WCHAR
* name
, const WCHAR
*namespace)
1299 UNICODE_STRING elemU
;
1300 if (!next_xml_elem(xmlbuf
, &elem
)) return FALSE
;
1301 if (xml_elem_cmp(&elem
, name
, namespace)) return TRUE
;
1302 elemU
= xmlstr2unicode(&elem
);
1303 DPRINT1( "unexpected element %wZ\n", &elemU
);
1307 static BOOL
parse_expect_no_attr(xmlbuf_t
* xmlbuf
, BOOL
* end
)
1309 xmlstr_t attr_name
, attr_value
;
1310 UNICODE_STRING attr_nameU
, attr_valueU
;
1313 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, end
))
1315 attr_nameU
= xmlstr2unicode(&attr_name
);
1316 attr_valueU
= xmlstr2unicode(&attr_value
);
1317 DPRINT1( "unexpected attr %wZ=%wZ\n", &attr_nameU
,
1323 static BOOL
parse_end_element(xmlbuf_t
*xmlbuf
)
1326 return parse_expect_no_attr(xmlbuf
, &end
) && !end
;
1329 static BOOL
parse_expect_end_elem(xmlbuf_t
*xmlbuf
, const WCHAR
*name
, const WCHAR
*namespace)
1332 UNICODE_STRING elemU
;
1333 if (!next_xml_elem(xmlbuf
, &elem
)) return FALSE
;
1334 if (!xml_elem_cmp_end(&elem
, name
, namespace))
1336 elemU
= xmlstr2unicode(&elem
);
1337 DPRINT1( "unexpected element %wZ\n", &elemU
);
1340 return parse_end_element(xmlbuf
);
1343 static BOOL
parse_unknown_elem(xmlbuf_t
*xmlbuf
, const xmlstr_t
*unknown_elem
)
1345 xmlstr_t attr_name
, attr_value
, elem
;
1346 BOOL end
= FALSE
, error
, ret
= TRUE
;
1348 while(next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
));
1349 if(error
|| end
) return end
;
1351 while(ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
1353 if(*elem
.ptr
== '/' && elem
.len
- 1 == unknown_elem
->len
&&
1354 !strncmpW(elem
.ptr
+1, unknown_elem
->ptr
, unknown_elem
->len
))
1357 ret
= parse_unknown_elem(xmlbuf
, &elem
);
1360 return ret
&& parse_end_element(xmlbuf
);
1363 static BOOL
parse_assembly_identity_elem(xmlbuf_t
* xmlbuf
, ACTIVATION_CONTEXT
* actctx
,
1364 struct assembly_identity
* ai
)
1366 xmlstr_t attr_name
, attr_value
;
1367 BOOL end
= FALSE
, error
;
1368 UNICODE_STRING attr_valueU
, attr_nameU
;
1370 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1372 if (xmlstr_cmp(&attr_name
, g_nameW
))
1374 if (!(ai
->name
= xmlstrdupW(&attr_value
))) return FALSE
;
1376 else if (xmlstr_cmp(&attr_name
, typeW
))
1378 if (!(ai
->type
= xmlstrdupW(&attr_value
))) return FALSE
;
1380 else if (xmlstr_cmp(&attr_name
, versionW
))
1382 if (!parse_version(&attr_value
, &ai
->version
)) return FALSE
;
1384 else if (xmlstr_cmp(&attr_name
, processorArchitectureW
))
1386 if (!(ai
->arch
= xmlstrdupW(&attr_value
))) return FALSE
;
1388 else if (xmlstr_cmp(&attr_name
, publicKeyTokenW
))
1390 if (!(ai
->public_key
= xmlstrdupW(&attr_value
))) return FALSE
;
1392 else if (xmlstr_cmp(&attr_name
, languageW
))
1394 DPRINT1("Unsupported yet language attribute (%S)\n",
1396 if (!(ai
->language
= xmlstrdupW(&attr_value
))) return FALSE
;
1400 attr_nameU
= xmlstr2unicode(&attr_name
);
1401 attr_valueU
= xmlstr2unicode(&attr_value
);
1402 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1406 if (error
|| end
) return end
;
1407 return parse_expect_end_elem(xmlbuf
, assemblyIdentityW
, asmv1W
);
1410 static enum comclass_threadingmodel
parse_com_class_threadingmodel(xmlstr_t
*value
)
1412 static const WCHAR apartW
[] = {'A','p','a','r','t','m','e','n','t',0};
1413 static const WCHAR neutralW
[] = {'N','e','u','t','r','a','l',0};
1414 static const WCHAR freeW
[] = {'F','r','e','e',0};
1415 static const WCHAR bothW
[] = {'B','o','t','h',0};
1417 if (value
->len
== 0) return ThreadingModel_No
;
1418 if (xmlstr_cmp(value
, apartW
))
1419 return ThreadingModel_Apartment
;
1420 else if (xmlstr_cmp(value
, freeW
))
1421 return ThreadingModel_Free
;
1422 else if (xmlstr_cmp(value
, bothW
))
1423 return ThreadingModel_Both
;
1424 else if (xmlstr_cmp(value
, neutralW
))
1425 return ThreadingModel_Neutral
;
1427 return ThreadingModel_No
;
1430 static OLEMISC
get_olemisc_value(const WCHAR
*str
, int len
)
1435 max
= sizeof(olemisc_values
)/sizeof(struct olemisc_entry
) - 1;
1443 c
= strncmpW(olemisc_values
[n
].name
, str
, len
);
1444 if (!c
&& !olemisc_values
[n
].name
[len
])
1445 return olemisc_values
[n
].value
;
1453 DPRINT1("unknown flag %S\n", str
);
1457 static DWORD
parse_com_class_misc(const xmlstr_t
*value
)
1459 const WCHAR
*str
= value
->ptr
, *start
;
1463 /* it's comma separated list of flags */
1464 while (i
< value
->len
)
1467 while (*str
!= ',' && (i
++ < value
->len
)) str
++;
1469 flags
|= get_olemisc_value(start
, str
-start
);
1471 /* skip separator */
1479 static BOOL
com_class_add_progid(const xmlstr_t
*progid
, struct entity
*entity
)
1481 struct progids
*progids
= &entity
->u
.comclass
.progids
;
1483 if (progids
->allocated
== 0)
1485 progids
->allocated
= 4;
1486 if (!(progids
->progids
= RtlAllocateHeap(RtlGetProcessHeap(), 0, progids
->allocated
* sizeof(WCHAR
*)))) return FALSE
;
1489 if (progids
->allocated
== progids
->num
)
1491 progids
->allocated
*= 2;
1492 progids
->progids
= RtlReAllocateHeap(RtlGetProcessHeap(), 0, progids
->progids
, progids
->allocated
* sizeof(WCHAR
*));
1495 if (!(progids
->progids
[progids
->num
] = xmlstrdupW(progid
))) return FALSE
;
1501 static BOOL
parse_com_class_progid(xmlbuf_t
* xmlbuf
, struct entity
*entity
)
1506 if (!parse_expect_no_attr(xmlbuf
, &end
) || end
|| !parse_text_content(xmlbuf
, &content
))
1509 if (!com_class_add_progid(&content
, entity
)) return FALSE
;
1510 return parse_expect_end_elem(xmlbuf
, progidW
, asmv1W
);
1513 static BOOL
parse_com_class_elem(xmlbuf_t
* xmlbuf
, struct dll_redirect
* dll
, struct actctx_loader
*acl
)
1515 xmlstr_t elem
, attr_name
, attr_value
;
1516 BOOL ret
= TRUE
, end
= FALSE
, error
;
1517 struct entity
* entity
;
1518 UNICODE_STRING attr_valueU
, attr_nameU
;
1520 if (!(entity
= add_entity(&dll
->entities
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)))
1523 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1525 if (xmlstr_cmp(&attr_name
, clsidW
))
1527 if (!(entity
->u
.comclass
.clsid
= xmlstrdupW(&attr_value
))) return FALSE
;
1529 else if (xmlstr_cmp(&attr_name
, progidW
))
1531 if (!(entity
->u
.comclass
.progid
= xmlstrdupW(&attr_value
))) return FALSE
;
1533 else if (xmlstr_cmp(&attr_name
, tlbidW
))
1535 if (!(entity
->u
.comclass
.tlbid
= xmlstrdupW(&attr_value
))) return FALSE
;
1537 else if (xmlstr_cmp(&attr_name
, threadingmodelW
))
1539 entity
->u
.comclass
.model
= parse_com_class_threadingmodel(&attr_value
);
1541 else if (xmlstr_cmp(&attr_name
, miscstatusW
))
1543 entity
->u
.comclass
.miscstatus
= parse_com_class_misc(&attr_value
);
1545 else if (xmlstr_cmp(&attr_name
, miscstatuscontentW
))
1547 entity
->u
.comclass
.miscstatuscontent
= parse_com_class_misc(&attr_value
);
1549 else if (xmlstr_cmp(&attr_name
, miscstatusthumbnailW
))
1551 entity
->u
.comclass
.miscstatusthumbnail
= parse_com_class_misc(&attr_value
);
1553 else if (xmlstr_cmp(&attr_name
, miscstatusiconW
))
1555 entity
->u
.comclass
.miscstatusicon
= parse_com_class_misc(&attr_value
);
1557 else if (xmlstr_cmp(&attr_name
, miscstatusdocprintW
))
1559 entity
->u
.comclass
.miscstatusdocprint
= parse_com_class_misc(&attr_value
);
1561 else if (xmlstr_cmp(&attr_name
, descriptionW
))
1567 attr_nameU
= xmlstr2unicode(&attr_name
);
1568 attr_valueU
= xmlstr2unicode(&attr_value
);
1569 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1573 if (error
) return FALSE
;
1575 acl
->actctx
->sections
|= SERVERREDIRECT_SECTION
;
1576 if (entity
->u
.comclass
.progid
)
1577 acl
->actctx
->sections
|= PROGIDREDIRECT_SECTION
;
1579 if (end
) return TRUE
;
1581 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
1583 if (xmlstr_cmp_end(&elem
, comClassW
))
1585 ret
= parse_end_element(xmlbuf
);
1588 else if (xmlstr_cmp(&elem
, progidW
))
1590 ret
= parse_com_class_progid(xmlbuf
, entity
);
1594 attr_nameU
= xmlstr2unicode(&elem
);
1595 DPRINT1("unknown elem %wZ\n", &attr_nameU
);
1596 ret
= parse_unknown_elem(xmlbuf
, &elem
);
1600 if (entity
->u
.comclass
.progids
.num
)
1601 acl
->actctx
->sections
|= PROGIDREDIRECT_SECTION
;
1606 static BOOL
parse_nummethods(const xmlstr_t
*str
, struct entity
*entity
)
1611 for (curr
= str
->ptr
; curr
< str
->ptr
+ str
->len
; curr
++)
1613 if (*curr
>= '0' && *curr
<= '9')
1614 num
= num
* 10 + *curr
- '0';
1617 UNICODE_STRING strU
= xmlstr2unicode(str
);
1618 DPRINT1("wrong numeric value %wZ\n", &strU
);
1622 entity
->u
.ifaceps
.nummethods
= num
;
1627 static BOOL
parse_cominterface_proxy_stub_elem(xmlbuf_t
* xmlbuf
, struct dll_redirect
* dll
, struct actctx_loader
* acl
)
1629 xmlstr_t attr_name
, attr_value
;
1630 BOOL end
= FALSE
, error
;
1631 struct entity
* entity
;
1632 UNICODE_STRING attr_valueU
, attr_nameU
;
1634 if (!(entity
= add_entity(&dll
->entities
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
)))
1637 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1639 if (xmlstr_cmp(&attr_name
, iidW
))
1641 if (!(entity
->u
.ifaceps
.iid
= xmlstrdupW(&attr_value
))) return FALSE
;
1643 else if (xmlstr_cmp(&attr_name
, g_nameW
))
1645 if (!(entity
->u
.ifaceps
.name
= xmlstrdupW(&attr_value
))) return FALSE
;
1647 else if (xmlstr_cmp(&attr_name
, baseInterfaceW
))
1649 if (!(entity
->u
.ifaceps
.base
= xmlstrdupW(&attr_value
))) return FALSE
;
1650 entity
->u
.ifaceps
.mask
|= BaseIface
;
1652 else if (xmlstr_cmp(&attr_name
, nummethodsW
))
1654 if (!(parse_nummethods(&attr_value
, entity
))) return FALSE
;
1655 entity
->u
.ifaceps
.mask
|= NumMethods
;
1657 else if (xmlstr_cmp(&attr_name
, tlbidW
))
1659 if (!(entity
->u
.ifaceps
.tlib
= xmlstrdupW(&attr_value
))) return FALSE
;
1662 else if (xmlstr_cmp(&attr_name
, proxyStubClsid32W
) || xmlstr_cmp(&attr_name
, threadingmodelW
))
1667 attr_nameU
= xmlstr2unicode(&attr_name
);
1668 attr_valueU
= xmlstr2unicode(&attr_value
);
1669 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1673 if (error
) return FALSE
;
1674 acl
->actctx
->sections
|= IFACEREDIRECT_SECTION
;
1675 if (end
) return TRUE
;
1677 return parse_expect_end_elem(xmlbuf
, comInterfaceProxyStubW
, asmv1W
);
1680 static BOOL
parse_typelib_flags(const xmlstr_t
*value
, struct entity
*entity
)
1682 WORD
*flags
= &entity
->u
.typelib
.flags
;
1683 const WCHAR
*str
= value
->ptr
, *start
;
1688 /* it's comma separated list of flags */
1689 while (i
< value
->len
)
1692 while (*str
!= ',' && (i
++ < value
->len
)) str
++;
1694 if (!strncmpiW(start
, restrictedW
, str
-start
))
1695 *flags
|= LIBFLAG_FRESTRICTED
;
1696 else if (!strncmpiW(start
, controlW
, str
-start
))
1697 *flags
|= LIBFLAG_FCONTROL
;
1698 else if (!strncmpiW(start
, hiddenW
, str
-start
))
1699 *flags
|= LIBFLAG_FHIDDEN
;
1700 else if (!strncmpiW(start
, hasdiskimageW
, str
-start
))
1701 *flags
|= LIBFLAG_FHASDISKIMAGE
;
1704 UNICODE_STRING valueU
= xmlstr2unicode(value
);
1705 DPRINT1("unknown flags value %wZ\n", &valueU
);
1709 /* skip separator */
1717 static BOOL
parse_typelib_version(const xmlstr_t
*str
, struct entity
*entity
)
1719 unsigned int ver
[2];
1722 UNICODE_STRING strW
;
1725 ver
[0] = ver
[1] = pos
= 0;
1726 for (curr
= str
->ptr
; curr
< str
->ptr
+ str
->len
; curr
++)
1728 if (*curr
>= '0' && *curr
<= '9')
1730 ver
[pos
] = ver
[pos
] * 10 + *curr
- '0';
1731 if (ver
[pos
] >= 0x10000) goto error
;
1733 else if (*curr
== '.')
1735 if (++pos
>= 2) goto error
;
1739 entity
->u
.typelib
.major
= ver
[0];
1740 entity
->u
.typelib
.minor
= ver
[1];
1744 strW
= xmlstr2unicode(str
);
1745 DPRINT1("FIXME: wrong typelib version value (%wZ)\n", &strW
);
1749 static BOOL
parse_typelib_elem(xmlbuf_t
* xmlbuf
, struct dll_redirect
* dll
, struct actctx_loader
* acl
)
1751 xmlstr_t attr_name
, attr_value
;
1752 BOOL end
= FALSE
, error
;
1753 struct entity
* entity
;
1754 UNICODE_STRING attr_valueU
, attr_nameU
;
1756 if (!(entity
= add_entity(&dll
->entities
, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
)))
1759 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1761 if (xmlstr_cmp(&attr_name
, tlbidW
))
1763 if (!(entity
->u
.typelib
.tlbid
= xmlstrdupW(&attr_value
))) return FALSE
;
1765 else if (xmlstr_cmp(&attr_name
, versionW
))
1767 if (!parse_typelib_version(&attr_value
, entity
)) return FALSE
;
1769 else if (xmlstr_cmp(&attr_name
, helpdirW
))
1771 if (!(entity
->u
.typelib
.helpdir
= xmlstrdupW(&attr_value
))) return FALSE
;
1773 else if (xmlstr_cmp(&attr_name
, flagsW
))
1775 if (!parse_typelib_flags(&attr_value
, entity
)) return FALSE
;
1779 attr_nameU
= xmlstr2unicode(&attr_name
);
1780 attr_valueU
= xmlstr2unicode(&attr_value
);
1781 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1785 if (error
) return FALSE
;
1787 acl
->actctx
->sections
|= TLIBREDIRECT_SECTION
;
1789 if (end
) return TRUE
;
1791 return parse_expect_end_elem(xmlbuf
, typelibW
, asmv1W
);
1794 static inline int aligned_string_len(int len
)
1796 return (len
+ 3) & ~3;
1799 static int get_assembly_version(struct assembly
*assembly
, WCHAR
*ret
)
1801 static const WCHAR fmtW
[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
1802 struct assembly_version
*ver
= &assembly
->id
.version
;
1805 if (!ret
) ret
= buff
;
1806 return sprintfW(ret
, fmtW
, ver
->major
, ver
->minor
, ver
->build
, ver
->revision
);
1809 static BOOL
parse_window_class_elem(xmlbuf_t
* xmlbuf
, struct dll_redirect
* dll
, struct actctx_loader
* acl
)
1811 xmlstr_t elem
, content
, attr_name
, attr_value
;
1812 BOOL end
= FALSE
, ret
= TRUE
, error
;
1813 struct entity
* entity
;
1814 UNICODE_STRING elemU
, attr_nameU
, attr_valueU
;
1816 if (!(entity
= add_entity(&dll
->entities
, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
)))
1819 entity
->u
.class.versioned
= TRUE
;
1820 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1822 if (xmlstr_cmp(&attr_name
, versionedW
))
1824 if (xmlstr_cmpi(&attr_value
, noW
))
1825 entity
->u
.class.versioned
= FALSE
;
1826 else if (!xmlstr_cmpi(&attr_value
, yesW
))
1831 attr_nameU
= xmlstr2unicode(&attr_name
);
1832 attr_valueU
= xmlstr2unicode(&attr_value
);
1833 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1837 if (error
|| end
) return end
;
1839 if (!parse_text_content(xmlbuf
, &content
)) return FALSE
;
1841 if (!(entity
->u
.class.name
= xmlstrdupW(&content
))) return FALSE
;
1843 acl
->actctx
->sections
|= WINDOWCLASS_SECTION
;
1845 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
1847 if (xmlstr_cmp_end(&elem
, windowClassW
))
1849 ret
= parse_end_element(xmlbuf
);
1854 elemU
= xmlstr2unicode(&elem
);
1855 DPRINT1("unknown elem %wZ\n", &elemU
);
1856 ret
= parse_unknown_elem(xmlbuf
, &elem
);
1863 static BOOL
parse_binding_redirect_elem(xmlbuf_t
* xmlbuf
)
1865 xmlstr_t attr_name
, attr_value
;
1866 UNICODE_STRING attr_valueU
, attr_nameU
;
1867 BOOL end
= FALSE
, error
;
1869 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1871 attr_nameU
= xmlstr2unicode(&attr_name
);
1872 attr_valueU
= xmlstr2unicode(&attr_value
);
1874 if (xmlstr_cmp(&attr_name
, oldVersionW
))
1876 DPRINT1("Not stored yet oldVersion=%wZ\n", &attr_valueU
);
1878 else if (xmlstr_cmp(&attr_name
, newVersionW
))
1880 DPRINT1("Not stored yet newVersion=%wZ\n", &attr_valueU
);
1884 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1888 if (error
|| end
) return end
;
1889 return parse_expect_end_elem(xmlbuf
, bindingRedirectW
, asmv1W
);
1892 static BOOL
parse_description_elem(xmlbuf_t
* xmlbuf
)
1894 xmlstr_t elem
, content
;
1895 UNICODE_STRING elemU
;
1896 BOOL end
= FALSE
, ret
= TRUE
;
1898 if (!parse_expect_no_attr(xmlbuf
, &end
) || end
||
1899 !parse_text_content(xmlbuf
, &content
))
1902 elemU
= xmlstr2unicode(&content
);
1903 DPRINT("Got description %wZ\n", &elemU
);
1905 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
1907 if (xmlstr_cmp_end(&elem
, descriptionW
))
1909 ret
= parse_end_element(xmlbuf
);
1914 elemU
= xmlstr2unicode(&elem
);
1915 DPRINT1("unknown elem %wZ\n", &elemU
);
1916 ret
= parse_unknown_elem(xmlbuf
, &elem
);
1923 static BOOL
parse_com_interface_external_proxy_stub_elem(xmlbuf_t
* xmlbuf
,
1924 struct assembly
* assembly
,
1925 struct actctx_loader
* acl
)
1927 xmlstr_t attr_name
, attr_value
;
1928 UNICODE_STRING attr_nameU
, attr_valueU
;
1929 BOOL end
= FALSE
, error
;
1930 struct entity
* entity
;
1932 entity
= add_entity(&assembly
->entities
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
);
1933 if (!entity
) return FALSE
;
1935 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1937 if (xmlstr_cmp(&attr_name
, iidW
))
1939 if (!(entity
->u
.ifaceps
.iid
= xmlstrdupW(&attr_value
))) return FALSE
;
1941 else if (xmlstr_cmp(&attr_name
, g_nameW
))
1943 if (!(entity
->u
.ifaceps
.name
= xmlstrdupW(&attr_value
))) return FALSE
;
1945 else if (xmlstr_cmp(&attr_name
, baseInterfaceW
))
1947 if (!(entity
->u
.ifaceps
.base
= xmlstrdupW(&attr_value
))) return FALSE
;
1948 entity
->u
.ifaceps
.mask
|= BaseIface
;
1950 else if (xmlstr_cmp(&attr_name
, nummethodsW
))
1952 if (!(parse_nummethods(&attr_value
, entity
))) return FALSE
;
1953 entity
->u
.ifaceps
.mask
|= NumMethods
;
1955 else if (xmlstr_cmp(&attr_name
, proxyStubClsid32W
))
1957 if (!(entity
->u
.ifaceps
.ps32
= xmlstrdupW(&attr_value
))) return FALSE
;
1959 else if (xmlstr_cmp(&attr_name
, tlbidW
))
1961 if (!(entity
->u
.ifaceps
.tlib
= xmlstrdupW(&attr_value
))) return FALSE
;
1965 attr_nameU
= xmlstr2unicode(&attr_name
);
1966 attr_valueU
= xmlstr2unicode(&attr_value
);
1967 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1971 if (error
) return FALSE
;
1972 acl
->actctx
->sections
|= IFACEREDIRECT_SECTION
;
1973 if (end
) return TRUE
;
1975 return parse_expect_end_elem(xmlbuf
, comInterfaceExternalProxyStubW
, asmv1W
);
1978 static BOOL
parse_clr_class_elem(xmlbuf_t
* xmlbuf
, struct assembly
* assembly
, struct actctx_loader
*acl
)
1980 xmlstr_t attr_name
, attr_value
, elem
;
1981 BOOL end
= FALSE
, error
, ret
= TRUE
;
1982 struct entity
* entity
;
1984 entity
= add_entity(&assembly
->entities
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
);
1985 if (!entity
) return FALSE
;
1987 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1989 if (xmlstr_cmp(&attr_name
, g_nameW
))
1991 if (!(entity
->u
.comclass
.name
= xmlstrdupW(&attr_value
))) return FALSE
;
1993 else if (xmlstr_cmp(&attr_name
, clsidW
))
1995 if (!(entity
->u
.comclass
.clsid
= xmlstrdupW(&attr_value
))) return FALSE
;
1997 else if (xmlstr_cmp(&attr_name
, progidW
))
1999 if (!(entity
->u
.comclass
.progid
= xmlstrdupW(&attr_value
))) return FALSE
;
2001 else if (xmlstr_cmp(&attr_name
, tlbidW
))
2003 if (!(entity
->u
.comclass
.tlbid
= xmlstrdupW(&attr_value
))) return FALSE
;
2005 else if (xmlstr_cmp(&attr_name
, threadingmodelW
))
2007 entity
->u
.comclass
.model
= parse_com_class_threadingmodel(&attr_value
);
2009 else if (xmlstr_cmp(&attr_name
, runtimeVersionW
))
2011 if (!(entity
->u
.comclass
.version
= xmlstrdupW(&attr_value
))) return FALSE
;
2015 UNICODE_STRING attr_nameU
, attr_valueU
;
2016 attr_nameU
= xmlstr2unicode(&attr_name
);
2017 attr_valueU
= xmlstr2unicode(&attr_value
);
2018 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2022 if (error
) return FALSE
;
2023 acl
->actctx
->sections
|= SERVERREDIRECT_SECTION
;
2024 if (entity
->u
.comclass
.progid
)
2025 acl
->actctx
->sections
|= PROGIDREDIRECT_SECTION
;
2026 if (end
) return TRUE
;
2028 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
2030 if (xmlstr_cmp_end(&elem
, clrClassW
))
2032 ret
= parse_end_element(xmlbuf
);
2035 else if (xmlstr_cmp(&elem
, progidW
))
2037 ret
= parse_com_class_progid(xmlbuf
, entity
);
2041 UNICODE_STRING elemU
= xmlstr2unicode(&elem
);
2042 DPRINT1("unknown elem %wZ\n", &elemU
);
2043 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2047 if (entity
->u
.comclass
.progids
.num
)
2048 acl
->actctx
->sections
|= PROGIDREDIRECT_SECTION
;
2053 static BOOL
parse_clr_surrogate_elem(xmlbuf_t
* xmlbuf
, struct assembly
* assembly
, struct actctx_loader
*acl
)
2055 xmlstr_t attr_name
, attr_value
;
2056 UNICODE_STRING attr_nameU
, attr_valueU
;
2057 BOOL end
= FALSE
, error
;
2058 struct entity
* entity
;
2060 entity
= add_entity(&assembly
->entities
, ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
);
2061 if (!entity
) return FALSE
;
2063 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
2065 if (xmlstr_cmp(&attr_name
, g_nameW
))
2067 if (!(entity
->u
.clrsurrogate
.name
= xmlstrdupW(&attr_value
))) return FALSE
;
2069 else if (xmlstr_cmp(&attr_name
, clsidW
))
2071 if (!(entity
->u
.clrsurrogate
.clsid
= xmlstrdupW(&attr_value
))) return FALSE
;
2073 else if (xmlstr_cmp(&attr_name
, runtimeVersionW
))
2075 if (!(entity
->u
.clrsurrogate
.version
= xmlstrdupW(&attr_value
))) return FALSE
;
2079 attr_nameU
= xmlstr2unicode(&attr_name
);
2080 attr_valueU
= xmlstr2unicode(&attr_value
);
2081 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2085 if (error
) return FALSE
;
2086 acl
->actctx
->sections
|= CLRSURROGATES_SECTION
;
2087 if (end
) return TRUE
;
2089 return parse_expect_end_elem(xmlbuf
, clrSurrogateW
, asmv1W
);
2092 static BOOL
parse_dependent_assembly_elem(xmlbuf_t
* xmlbuf
, struct actctx_loader
* acl
, BOOL optional
)
2094 struct assembly_identity ai
;
2096 BOOL end
= FALSE
, ret
= TRUE
;
2098 if (!parse_expect_no_attr(xmlbuf
, &end
) || end
) return end
;
2100 memset(&ai
, 0, sizeof(ai
));
2101 ai
.optional
= optional
;
2103 if (!parse_expect_elem(xmlbuf
, assemblyIdentityW
, asmv1W
) ||
2104 !parse_assembly_identity_elem(xmlbuf
, acl
->actctx
, &ai
))
2107 //TRACE( "adding name=%s version=%s arch=%s\n", debugstr_w(ai.name), debugstr_version(&ai.version), debugstr_w(ai.arch) );
2109 /* store the newly found identity for later loading */
2110 if (!add_dependent_assembly_id(acl
, &ai
)) return FALSE
;
2112 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
2114 if (xmlstr_cmp_end(&elem
, dependentAssemblyW
))
2116 ret
= parse_end_element(xmlbuf
);
2119 else if (xmlstr_cmp(&elem
, bindingRedirectW
))
2121 ret
= parse_binding_redirect_elem(xmlbuf
);
2125 DPRINT1("unknown elem %S\n", elem
.ptr
);
2126 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2133 static BOOL
parse_dependency_elem(xmlbuf_t
* xmlbuf
, struct actctx_loader
* acl
)
2135 xmlstr_t attr_name
, attr_value
, elem
;
2136 UNICODE_STRING attr_nameU
, attr_valueU
;
2137 BOOL end
= FALSE
, ret
= TRUE
, error
, optional
= FALSE
;
2139 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
2141 attr_nameU
= xmlstr2unicode(&attr_name
);
2142 attr_valueU
= xmlstr2unicode(&attr_value
);
2144 if (xmlstr_cmp(&attr_name
, optionalW
))
2146 optional
= xmlstr_cmpi( &attr_value
, yesW
);
2147 DPRINT1("optional=%wZ\n", &attr_valueU
);
2151 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2155 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
2157 if (xmlstr_cmp_end(&elem
, dependencyW
))
2159 ret
= parse_end_element(xmlbuf
);
2162 else if (xmlstr_cmp(&elem
, dependentAssemblyW
))
2164 ret
= parse_dependent_assembly_elem(xmlbuf
, acl
, optional
);
2168 attr_nameU
= xmlstr2unicode(&elem
);
2169 DPRINT1("unknown element %wZ\n", &attr_nameU
);
2170 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2177 static BOOL
parse_noinherit_elem(xmlbuf_t
* xmlbuf
)
2181 if (!parse_expect_no_attr(xmlbuf
, &end
)) return FALSE
;
2182 return end
|| parse_expect_end_elem(xmlbuf
, noInheritW
, asmv1W
);
2185 static BOOL
parse_noinheritable_elem(xmlbuf_t
* xmlbuf
)
2189 if (!parse_expect_no_attr(xmlbuf
, &end
)) return FALSE
;
2190 return end
|| parse_expect_end_elem(xmlbuf
, noInheritableW
, asmv1W
);
2193 static BOOL
parse_file_elem(xmlbuf_t
* xmlbuf
, struct assembly
* assembly
, struct actctx_loader
* acl
)
2195 xmlstr_t attr_name
, attr_value
, elem
;
2196 UNICODE_STRING attr_nameU
, attr_valueU
;
2197 BOOL end
= FALSE
, error
, ret
= TRUE
;
2198 struct dll_redirect
* dll
;
2200 if (!(dll
= add_dll_redirect(assembly
))) return FALSE
;
2202 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
2204 attr_nameU
= xmlstr2unicode(&attr_name
);
2205 attr_valueU
= xmlstr2unicode(&attr_value
);
2207 if (xmlstr_cmp(&attr_name
, g_nameW
))
2209 if (!(dll
->name
= xmlstrdupW(&attr_value
))) return FALSE
;
2210 DPRINT("name=%wZ\n", &attr_valueU
);
2212 else if (xmlstr_cmp(&attr_name
, hashW
))
2214 if (!(dll
->hash
= xmlstrdupW(&attr_value
))) return FALSE
;
2216 else if (xmlstr_cmp(&attr_name
, hashalgW
))
2218 static const WCHAR sha1W
[] = {'S','H','A','1',0};
2219 if (!xmlstr_cmpi(&attr_value
, sha1W
))
2220 DPRINT1("hashalg should be SHA1, got %wZ\n", &attr_valueU
);
2224 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2228 if (error
|| !dll
->name
) return FALSE
;
2230 acl
->actctx
->sections
|= DLLREDIRECT_SECTION
;
2232 if (end
) return TRUE
;
2234 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
2236 if (xmlstr_cmp_end(&elem
, fileW
))
2238 ret
= parse_end_element(xmlbuf
);
2241 else if (xmlstr_cmp(&elem
, comClassW
))
2243 ret
= parse_com_class_elem(xmlbuf
, dll
, acl
);
2245 else if (xmlstr_cmp(&elem
, comInterfaceProxyStubW
))
2247 ret
= parse_cominterface_proxy_stub_elem(xmlbuf
, dll
, acl
);
2249 else if (xml_elem_cmp(&elem
, hashW
, asmv2W
))
2251 DPRINT1("asmv2hash (undocumented) not supported\n");
2252 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2254 else if (xmlstr_cmp(&elem
, typelibW
))
2256 ret
= parse_typelib_elem(xmlbuf
, dll
, acl
);
2258 else if (xmlstr_cmp(&elem
, windowClassW
))
2260 ret
= parse_window_class_elem(xmlbuf
, dll
, acl
);
2264 attr_nameU
= xmlstr2unicode(&elem
);
2265 DPRINT1("unknown elem %wZ\n", &attr_nameU
);
2266 ret
= parse_unknown_elem( xmlbuf
, &elem
);
2273 static BOOL
parse_assembly_elem(xmlbuf_t
* xmlbuf
, struct actctx_loader
* acl
,
2274 struct assembly
* assembly
,
2275 struct assembly_identity
* expected_ai
)
2277 xmlstr_t attr_name
, attr_value
, elem
;
2278 UNICODE_STRING attr_nameU
, attr_valueU
;
2279 BOOL end
= FALSE
, error
, version
= FALSE
, xmlns
= FALSE
, ret
= TRUE
;
2281 DPRINT("(%p)\n", xmlbuf
);
2283 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
2285 attr_nameU
= xmlstr2unicode(&attr_name
);
2286 attr_valueU
= xmlstr2unicode(&attr_value
);
2288 if (xmlstr_cmp(&attr_name
, manifestVersionW
))
2290 static const WCHAR v10W
[] = {'1','.','0',0};
2291 if (!xmlstr_cmp(&attr_value
, v10W
))
2293 DPRINT1("wrong version %wZ\n", &attr_valueU
);
2298 else if (xmlstr_cmp(&attr_name
, xmlnsW
))
2300 if (!xmlstr_cmp(&attr_value
, manifestv1W
) && !xmlstr_cmp(&attr_value
, manifestv3W
))
2302 DPRINT1("wrong namespace %wZ\n", &attr_valueU
);
2309 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2313 if (error
|| end
|| !xmlns
|| !version
) return FALSE
;
2314 if (!next_xml_elem(xmlbuf
, &elem
)) return FALSE
;
2316 if (assembly
->type
== APPLICATION_MANIFEST
&& xmlstr_cmp(&elem
, noInheritW
))
2318 if (!parse_noinherit_elem(xmlbuf
) || !next_xml_elem(xmlbuf
, &elem
))
2320 assembly
->no_inherit
= TRUE
;
2323 if (xml_elem_cmp(&elem
, noInheritableW
, asmv1W
))
2325 if (!parse_noinheritable_elem(xmlbuf
) || !next_xml_elem(xmlbuf
, &elem
))
2328 else if ((assembly
->type
== ASSEMBLY_MANIFEST
|| assembly
->type
== ASSEMBLY_SHARED_MANIFEST
) &&
2329 assembly
->no_inherit
)
2334 if (xml_elem_cmp_end(&elem
, assemblyW
, asmv1W
))
2336 ret
= parse_end_element(xmlbuf
);
2339 else if (xml_elem_cmp(&elem
, descriptionW
, asmv1W
))
2341 ret
= parse_description_elem(xmlbuf
);
2343 else if (xml_elem_cmp(&elem
, comInterfaceExternalProxyStubW
, asmv1W
))
2345 ret
= parse_com_interface_external_proxy_stub_elem(xmlbuf
, assembly
, acl
);
2347 else if (xml_elem_cmp(&elem
, dependencyW
, asmv1W
))
2349 ret
= parse_dependency_elem(xmlbuf
, acl
);
2351 else if (xml_elem_cmp(&elem
, fileW
, asmv1W
))
2353 ret
= parse_file_elem(xmlbuf
, assembly
, acl
);
2355 else if (xml_elem_cmp(&elem
, clrClassW
, asmv1W
))
2357 ret
= parse_clr_class_elem(xmlbuf
, assembly
, acl
);
2359 else if (xml_elem_cmp(&elem
, clrSurrogateW
, asmv1W
))
2361 ret
= parse_clr_surrogate_elem(xmlbuf
, assembly
, acl
);
2363 else if (xml_elem_cmp(&elem
, assemblyIdentityW
, asmv1W
))
2365 if (!parse_assembly_identity_elem(xmlbuf
, acl
->actctx
, &assembly
->id
)) return FALSE
;
2369 /* FIXME: more tests */
2370 if (assembly
->type
== ASSEMBLY_MANIFEST
&&
2371 memcmp(&assembly
->id
.version
, &expected_ai
->version
, sizeof(assembly
->id
.version
)))
2373 DPRINT1("wrong version for assembly manifest: %u.%u.%u.%u / %u.%u.%u.%u\n",
2374 expected_ai
->version
.major
, expected_ai
->version
.minor
,
2375 expected_ai
->version
.build
, expected_ai
->version
.revision
,
2376 assembly
->id
.version
.major
, assembly
->id
.version
.minor
,
2377 assembly
->id
.version
.build
, assembly
->id
.version
.revision
);
2380 else if (assembly
->type
== ASSEMBLY_SHARED_MANIFEST
&&
2381 (assembly
->id
.version
.major
!= expected_ai
->version
.major
||
2382 assembly
->id
.version
.minor
!= expected_ai
->version
.minor
||
2383 assembly
->id
.version
.build
< expected_ai
->version
.build
||
2384 (assembly
->id
.version
.build
== expected_ai
->version
.build
&&
2385 assembly
->id
.version
.revision
< expected_ai
->version
.revision
)))
2387 DPRINT1("wrong version for shared assembly manifest\n");
2394 attr_nameU
= xmlstr2unicode(&elem
);
2395 DPRINT1("unknown element %wZ\n", &attr_nameU
);
2396 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2398 if (ret
) ret
= next_xml_elem(xmlbuf
, &elem
);
2404 static NTSTATUS
parse_manifest_buffer( struct actctx_loader
* acl
, struct assembly
*assembly
,
2405 struct assembly_identity
* ai
, xmlbuf_t
*xmlbuf
)
2408 UNICODE_STRING elemU
;
2410 if (!next_xml_elem(xmlbuf
, &elem
)) return STATUS_SXS_CANT_GEN_ACTCTX
;
2412 if (xmlstr_cmp(&elem
, g_xmlW
) &&
2413 (!parse_xml_header(xmlbuf
) || !next_xml_elem(xmlbuf
, &elem
)))
2414 return STATUS_SXS_CANT_GEN_ACTCTX
;
2416 if (!xml_elem_cmp(&elem
, assemblyW
, asmv1W
))
2418 elemU
= xmlstr2unicode(&elem
);
2419 DPRINT1("root element is %wZ, not <assembly>\n", &elemU
);
2420 return STATUS_SXS_CANT_GEN_ACTCTX
;
2423 if (!parse_assembly_elem(xmlbuf
, acl
, assembly
, ai
))
2425 DPRINT1("failed to parse manifest %S\n", assembly
->manifest
.info
);
2426 return STATUS_SXS_CANT_GEN_ACTCTX
;
2429 if (next_xml_elem(xmlbuf
, &elem
))
2431 elemU
= xmlstr2unicode(&elem
);
2432 DPRINT1("unexpected element %wZ\n", &elemU
);
2433 return STATUS_SXS_CANT_GEN_ACTCTX
;
2436 if (xmlbuf
->ptr
!= xmlbuf
->end
)
2438 DPRINT1("parse error\n");
2439 return STATUS_SXS_CANT_GEN_ACTCTX
;
2441 return STATUS_SUCCESS
;
2444 static NTSTATUS
parse_manifest( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2445 LPCWSTR filename
, LPCWSTR directory
, BOOL shared
,
2446 const void *buffer
, SIZE_T size
)
2450 struct assembly
*assembly
;
2453 DPRINT( "parsing manifest loaded from %S base dir %S\n", filename
, directory
);
2455 if (!(assembly
= add_assembly(acl
->actctx
, shared
? ASSEMBLY_SHARED_MANIFEST
: ASSEMBLY_MANIFEST
)))
2456 return STATUS_SXS_CANT_GEN_ACTCTX
;
2458 if (directory
&& !(assembly
->directory
= strdupW(directory
)))
2459 return STATUS_NO_MEMORY
;
2461 if (filename
) assembly
->manifest
.info
= strdupW( filename
+ 4 /* skip \??\ prefix */ );
2462 assembly
->manifest
.type
= assembly
->manifest
.info
? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
2463 : ACTIVATION_CONTEXT_PATH_TYPE_NONE
;
2465 unicode_tests
= IS_TEXT_UNICODE_SIGNATURE
| IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
2466 if (RtlIsTextUnicode((PVOID
)buffer
, (ULONG
)size
, &unicode_tests
))
2468 xmlbuf
.ptr
= buffer
;
2469 xmlbuf
.end
= xmlbuf
.ptr
+ size
/ sizeof(WCHAR
);
2470 status
= parse_manifest_buffer( acl
, assembly
, ai
, &xmlbuf
);
2472 else if (unicode_tests
& IS_TEXT_UNICODE_REVERSE_SIGNATURE
)
2474 const WCHAR
*buf
= buffer
;
2478 if (!(new_buff
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
2479 return STATUS_NO_MEMORY
;
2480 for (i
= 0; i
< size
/ sizeof(WCHAR
); i
++)
2481 new_buff
[i
] = RtlUshortByteSwap( buf
[i
] );
2482 xmlbuf
.ptr
= new_buff
;
2483 xmlbuf
.end
= xmlbuf
.ptr
+ size
/ sizeof(WCHAR
);
2484 status
= parse_manifest_buffer( acl
, assembly
, ai
, &xmlbuf
);
2485 RtlFreeHeap( RtlGetProcessHeap(), 0, new_buff
);
2489 /* TODO: this doesn't handle arbitrary encodings */
2493 status
= RtlMultiByteToUnicodeSize(&sizeU
, buffer
, size
);
2494 if (!NT_SUCCESS(status
))
2496 DPRINT1("RtlMultiByteToUnicodeSize failed with %lx\n", status
);
2497 return STATUS_SXS_CANT_GEN_ACTCTX
;
2500 new_buff
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeU
);
2502 return STATUS_NO_MEMORY
;
2504 status
= RtlMultiByteToUnicodeN(new_buff
, sizeU
, &sizeU
, buffer
, size
);
2505 if (!NT_SUCCESS(status
))
2507 DPRINT1("RtlMultiByteToUnicodeN failed with %lx\n", status
);
2508 return STATUS_SXS_CANT_GEN_ACTCTX
;
2511 xmlbuf
.ptr
= new_buff
;
2512 xmlbuf
.end
= xmlbuf
.ptr
+ sizeU
/ sizeof(WCHAR
);
2513 status
= parse_manifest_buffer(acl
, assembly
, ai
, &xmlbuf
);
2514 RtlFreeHeap(RtlGetProcessHeap(), 0, new_buff
);
2519 static NTSTATUS
open_nt_file( HANDLE
*handle
, UNICODE_STRING
*name
)
2521 OBJECT_ATTRIBUTES attr
;
2524 attr
.Length
= sizeof(attr
);
2525 attr
.RootDirectory
= 0;
2526 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2527 attr
.ObjectName
= name
;
2528 attr
.SecurityDescriptor
= NULL
;
2529 attr
.SecurityQualityOfService
= NULL
;
2530 return NtOpenFile(handle
,
2531 GENERIC_READ
| SYNCHRONIZE
,
2534 FILE_SYNCHRONOUS_IO_ALERT
);
2537 static NTSTATUS
get_module_filename( HMODULE module
, UNICODE_STRING
*str
, USHORT extra_len
)
2541 LDR_DATA_TABLE_ENTRY
*pldr
;
2543 LdrLockLoaderLock(0, NULL
, &magic
);
2544 status
= LdrFindEntryForAddress( module
, &pldr
);
2545 if (status
== STATUS_SUCCESS
)
2547 if ((str
->Buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2548 pldr
->FullDllName
.Length
+ extra_len
+ sizeof(WCHAR
) )))
2550 memcpy( str
->Buffer
, pldr
->FullDllName
.Buffer
, pldr
->FullDllName
.Length
+ sizeof(WCHAR
) );
2551 str
->Length
= pldr
->FullDllName
.Length
;
2552 str
->MaximumLength
= pldr
->FullDllName
.Length
+ extra_len
+ sizeof(WCHAR
);
2554 else status
= STATUS_NO_MEMORY
;
2556 LdrUnlockLoaderLock(0, magic
);
2560 static NTSTATUS
get_manifest_in_module( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2561 LPCWSTR filename
, LPCWSTR directory
, BOOL shared
,
2562 HANDLE hModule
, LPCWSTR resname
, ULONG lang
)
2565 UNICODE_STRING nameW
;
2566 LDR_RESOURCE_INFO info
;
2567 IMAGE_RESOURCE_DATA_ENTRY
* entry
= NULL
;
2570 //DPRINT( "looking for res %s in module %p %s\n", resname,
2571 // hModule, filename );
2574 if (TRACE_ON(actctx
))
2576 if (!filename
&& !get_module_filename( hModule
, &nameW
, 0 ))
2578 DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname
),
2579 hModule
, debugstr_w(nameW
.Buffer
) );
2580 RtlFreeUnicodeString( &nameW
);
2582 else DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname
),
2583 hModule
, debugstr_w(filename
) );
2587 if (!resname
) return STATUS_INVALID_PARAMETER
;
2589 info
.Type
= (ULONG_PTR
)RT_MANIFEST
;
2590 info
.Language
= lang
;
2591 if (!((ULONG_PTR
)resname
>> 16))
2593 info
.Name
= (ULONG_PTR
)resname
;
2594 status
= LdrFindResource_U(hModule
, &info
, 3, &entry
);
2596 else if (resname
[0] == '#')
2599 RtlInitUnicodeString(&nameW
, resname
+ 1);
2600 if (RtlUnicodeStringToInteger(&nameW
, 10, &value
) != STATUS_SUCCESS
|| HIWORD(value
))
2601 return STATUS_INVALID_PARAMETER
;
2603 status
= LdrFindResource_U(hModule
, &info
, 3, &entry
);
2607 RtlCreateUnicodeString(&nameW
, resname
);
2608 RtlUpcaseUnicodeString(&nameW
, &nameW
, FALSE
);
2609 info
.Name
= (ULONG_PTR
)nameW
.Buffer
;
2610 status
= LdrFindResource_U(hModule
, &info
, 3, &entry
);
2611 RtlFreeUnicodeString(&nameW
);
2613 if (status
== STATUS_SUCCESS
) status
= LdrAccessResource(hModule
, entry
, &ptr
, NULL
);
2615 if (status
== STATUS_SUCCESS
)
2616 status
= parse_manifest(acl
, ai
, filename
, directory
, shared
, ptr
, entry
->Size
);
2621 static NTSTATUS
get_manifest_in_pe_file( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2622 LPCWSTR filename
, LPCWSTR directory
, BOOL shared
,
2623 HANDLE file
, LPCWSTR resname
, ULONG lang
)
2626 OBJECT_ATTRIBUTES attr
;
2628 LARGE_INTEGER offset
;
2633 DPRINT( "looking for res %S in %S\n", resname
, filename
);
2635 attr
.Length
= sizeof(attr
);
2636 attr
.RootDirectory
= 0;
2637 attr
.ObjectName
= NULL
;
2638 attr
.Attributes
= OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
;
2639 attr
.SecurityDescriptor
= NULL
;
2640 attr
.SecurityQualityOfService
= NULL
;
2643 status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
| SECTION_MAP_READ
,
2644 &attr
, &size
, PAGE_READONLY
, SEC_COMMIT
, file
);
2645 if (status
!= STATUS_SUCCESS
) return status
;
2647 offset
.QuadPart
= 0;
2650 status
= NtMapViewOfSection( mapping
, NtCurrentProcess(), &base
, 0, 0, &offset
,
2651 &count
, ViewShare
, 0, PAGE_READONLY
);
2653 if (status
!= STATUS_SUCCESS
) return status
;
2655 if (RtlImageNtHeader(base
)) /* we got a PE file */
2657 HANDLE module
= (HMODULE
)((ULONG_PTR
)base
| 1); /* make it a LOAD_LIBRARY_AS_DATAFILE handle */
2658 status
= get_manifest_in_module( acl
, ai
, filename
, directory
, shared
, module
, resname
, lang
);
2660 else status
= STATUS_INVALID_IMAGE_FORMAT
;
2662 NtUnmapViewOfSection( NtCurrentProcess(), base
);
2666 static NTSTATUS
get_manifest_in_manifest_file( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2667 LPCWSTR filename
, LPCWSTR directory
, BOOL shared
, HANDLE file
)
2669 FILE_STANDARD_INFORMATION info
;
2672 OBJECT_ATTRIBUTES attr
;
2674 LARGE_INTEGER offset
;
2679 DPRINT( "loading manifest file %S\n", filename
);
2681 attr
.Length
= sizeof(attr
);
2682 attr
.RootDirectory
= 0;
2683 attr
.ObjectName
= NULL
;
2684 attr
.Attributes
= OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
;
2685 attr
.SecurityDescriptor
= NULL
;
2686 attr
.SecurityQualityOfService
= NULL
;
2689 status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
| SECTION_MAP_READ
,
2690 &attr
, &size
, PAGE_READONLY
, SEC_COMMIT
, file
);
2692 if (status
!= STATUS_SUCCESS
) return status
;
2694 offset
.QuadPart
= 0;
2697 status
= NtMapViewOfSection( mapping
, NtCurrentProcess(), &base
, 0, 0, &offset
,
2698 &count
, ViewShare
, 0, PAGE_READONLY
);
2700 if (status
!= STATUS_SUCCESS
) return status
;
2702 /* Fixme: WINE uses FileEndOfFileInformation with NtQueryInformationFile. */
2703 status
= NtQueryInformationFile( file
, &io
, &info
, sizeof(info
), FileStandardInformation
);
2705 if (status
== STATUS_SUCCESS
)
2706 status
= parse_manifest(acl
, ai
, filename
, directory
, shared
, base
, (SIZE_T
)info
.EndOfFile
.QuadPart
);
2708 NtUnmapViewOfSection( NtCurrentProcess(), base
);
2712 /* try to load the .manifest file associated to the file */
2713 static NTSTATUS
get_manifest_in_associated_manifest( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2714 LPCWSTR filename
, LPCWSTR directory
, HMODULE module
, LPCWSTR resname
)
2716 static const WCHAR fmtW
[] = { '.','%','l','u',0 };
2719 UNICODE_STRING nameW
;
2721 ULONG_PTR resid
= (ULONG_PTR
)CREATEPROCESS_MANIFEST_RESOURCE_ID
;
2723 if (!((ULONG_PTR
)resname
>> 16)) resid
= (ULONG_PTR
)resname
& 0xffff;
2725 DPRINT( "looking for manifest associated with %S id %lu\n", filename
, resid
);
2727 if (module
) /* use the module filename */
2729 UNICODE_STRING name
;
2731 if (!(status
= get_module_filename( module
, &name
, sizeof(dotManifestW
) + 10*sizeof(WCHAR
) )))
2733 if (resid
!= 1) sprintfW( name
.Buffer
+ strlenW(name
.Buffer
), fmtW
, resid
);
2734 strcatW( name
.Buffer
, dotManifestW
);
2735 if (!RtlDosPathNameToNtPathName_U( name
.Buffer
, &nameW
, NULL
, NULL
))
2736 status
= STATUS_RESOURCE_DATA_NOT_FOUND
;
2737 RtlFreeUnicodeString( &name
);
2739 if (status
) return status
;
2743 if (!(buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2744 (strlenW(filename
) + 10) * sizeof(WCHAR
) + sizeof(dotManifestW
) )))
2745 return STATUS_NO_MEMORY
;
2746 strcpyW( buffer
, filename
);
2747 if (resid
!= 1) sprintfW( buffer
+ strlenW(buffer
), fmtW
, resid
);
2748 strcatW( buffer
, dotManifestW
);
2749 RtlInitUnicodeString( &nameW
, buffer
);
2752 if (!open_nt_file( &file
, &nameW
))
2754 status
= get_manifest_in_manifest_file( acl
, ai
, nameW
.Buffer
, directory
, FALSE
, file
);
2757 else status
= STATUS_RESOURCE_TYPE_NOT_FOUND
;
2758 RtlFreeUnicodeString( &nameW
);
2762 static WCHAR
*lookup_manifest_file( HANDLE dir
, struct assembly_identity
*ai
)
2764 static const WCHAR lookup_fmtW
[] =
2765 {'%','s','_','%','s','_','%','s','_','%','u','.','%','u','.','*','.','*','_',
2767 '.','m','a','n','i','f','e','s','t',0};
2769 WCHAR
*lookup
, *ret
= NULL
;
2770 UNICODE_STRING lookup_us
;
2772 const WCHAR
*lang
= ai
->language
;
2773 unsigned int data_pos
= 0, data_len
;
2776 if (!(lookup
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2777 (strlenW(ai
->arch
) + strlenW(ai
->name
)
2778 + strlenW(ai
->public_key
) + 20) * sizeof(WCHAR
)
2779 + sizeof(lookup_fmtW
) )))
2782 if (!lang
|| !strcmpiW( lang
, neutralW
)) lang
= wildcardW
;
2783 sprintfW( lookup
, lookup_fmtW
, ai
->arch
, ai
->name
, ai
->public_key
,
2784 ai
->version
.major
, ai
->version
.minor
, lang
);
2785 RtlInitUnicodeString( &lookup_us
, lookup
);
2787 NtQueryDirectoryFile( dir
, 0, NULL
, NULL
, &io
, buffer
, sizeof(buffer
),
2788 FileBothDirectoryInformation
, FALSE
, &lookup_us
, TRUE
);
2789 if (io
.Status
== STATUS_SUCCESS
)
2791 FILE_BOTH_DIR_INFORMATION
*dir_info
;
2793 ULONG build
, revision
;
2795 data_len
= (ULONG
)io
.Information
;
2799 if (data_pos
>= data_len
)
2801 NtQueryDirectoryFile( dir
, 0, NULL
, NULL
, &io
, buffer
, sizeof(buffer
),
2802 FileBothDirectoryInformation
, FALSE
, &lookup_us
, FALSE
);
2803 if (io
.Status
!= STATUS_SUCCESS
) break;
2804 data_len
= (ULONG
)io
.Information
;
2807 dir_info
= (FILE_BOTH_DIR_INFORMATION
*)(buffer
+ data_pos
);
2809 if (dir_info
->NextEntryOffset
) data_pos
+= dir_info
->NextEntryOffset
;
2810 else data_pos
= data_len
;
2812 tmp
= (WCHAR
*)dir_info
->FileName
+ (strchrW(lookup
, '*') - lookup
);
2814 if (build
< ai
->version
.build
) continue;
2815 tmp
= strchrW(tmp
, '.') + 1;
2816 revision
= atoiW(tmp
);
2817 if (build
== ai
->version
.build
&& revision
< ai
->version
.revision
)
2819 ai
->version
.build
= (USHORT
)build
;
2820 ai
->version
.revision
= (USHORT
)revision
;
2822 if ((ret
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dir_info
->FileNameLength
* sizeof(WCHAR
) )))
2824 memcpy( ret
, dir_info
->FileName
, dir_info
->FileNameLength
);
2825 ret
[dir_info
->FileNameLength
/sizeof(WCHAR
)] = 0;
2830 else DPRINT1("no matching file for %S\n", lookup
);
2831 RtlFreeHeap( RtlGetProcessHeap(), 0, lookup
);
2835 static NTSTATUS
lookup_winsxs(struct actctx_loader
* acl
, struct assembly_identity
* ai
)
2837 struct assembly_identity sxs_ai
;
2838 UNICODE_STRING path_us
;
2839 OBJECT_ATTRIBUTES attr
;
2841 WCHAR
*path
, *file
= NULL
;
2844 static const WCHAR manifest_dirW
[] =
2845 {'\\','w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s',0};
2847 if (!ai
->arch
|| !ai
->name
|| !ai
->public_key
) return STATUS_NO_SUCH_FILE
;
2849 if (!(path
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2850 ((strlenW(SharedUserData
->NtSystemRoot
) + 1) *sizeof(WCHAR
)) + sizeof(manifest_dirW
) )))
2851 return STATUS_NO_MEMORY
;
2853 memcpy( path
, SharedUserData
->NtSystemRoot
, strlenW(SharedUserData
->NtSystemRoot
) * sizeof(WCHAR
) );
2854 memcpy( path
+ strlenW(SharedUserData
->NtSystemRoot
), manifest_dirW
, sizeof(manifest_dirW
) );
2856 if (!RtlDosPathNameToNtPathName_U( path
, &path_us
, NULL
, NULL
))
2858 RtlFreeHeap( RtlGetProcessHeap(), 0, path
);
2859 return STATUS_NO_SUCH_FILE
;
2861 RtlFreeHeap( RtlGetProcessHeap(), 0, path
);
2863 attr
.Length
= sizeof(attr
);
2864 attr
.RootDirectory
= 0;
2865 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2866 attr
.ObjectName
= &path_us
;
2867 attr
.SecurityDescriptor
= NULL
;
2868 attr
.SecurityQualityOfService
= NULL
;
2870 if (!NtOpenFile(&handle
,
2871 GENERIC_READ
| SYNCHRONIZE
,
2873 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2874 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
))
2877 file
= lookup_manifest_file( handle
, &sxs_ai
);
2882 RtlFreeUnicodeString( &path_us
);
2883 return STATUS_NO_SUCH_FILE
;
2886 /* append file name to directory path */
2887 if (!(path
= RtlReAllocateHeap( RtlGetProcessHeap(), 0, path_us
.Buffer
,
2888 path_us
.Length
+ (strlenW(file
) + 2) * sizeof(WCHAR
) )))
2890 RtlFreeHeap( RtlGetProcessHeap(), 0, file
);
2891 RtlFreeUnicodeString( &path_us
);
2892 return STATUS_NO_MEMORY
;
2895 path
[path_us
.Length
/sizeof(WCHAR
)] = '\\';
2896 strcpyW( path
+ path_us
.Length
/sizeof(WCHAR
) + 1, file
);
2897 RtlInitUnicodeString( &path_us
, path
);
2898 *strrchrW(file
, '.') = 0; /* remove .manifest extension */
2900 if (!open_nt_file( &handle
, &path_us
))
2902 io
.Status
= get_manifest_in_manifest_file(acl
, &sxs_ai
, path_us
.Buffer
, file
, TRUE
, handle
);
2905 else io
.Status
= STATUS_NO_SUCH_FILE
;
2907 RtlFreeHeap( RtlGetProcessHeap(), 0, file
);
2908 RtlFreeUnicodeString( &path_us
);
2912 static NTSTATUS
lookup_assembly(struct actctx_loader
* acl
,
2913 struct assembly_identity
* ai
)
2915 static const WCHAR dotDllW
[] = {'.','d','l','l',0};
2917 WCHAR
*buffer
, *p
, *directory
;
2919 UNICODE_STRING nameW
;
2923 DPRINT( "looking for name=%S version=%u.%u.%u.%u arch=%S\n",
2924 ai
->name
, ai
->version
.major
, ai
->version
.minor
, ai
->version
.build
, ai
->version
.revision
, ai
->arch
);
2926 if ((status
= lookup_winsxs(acl
, ai
)) != STATUS_NO_SUCH_FILE
) return status
;
2928 /* FIXME: add support for language specific lookup */
2930 len
= max(RtlGetFullPathName_U(acl
->actctx
->assemblies
->manifest
.info
, 0, NULL
, NULL
) / sizeof(WCHAR
),
2931 strlenW(acl
->actctx
->appdir
.info
));
2933 nameW
.Buffer
= NULL
;
2934 if (!(buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2935 (len
+ 2 * strlenW(ai
->name
) + 2) * sizeof(WCHAR
) + sizeof(dotManifestW
) )))
2936 return STATUS_NO_MEMORY
;
2938 if (!(directory
= build_assembly_dir( ai
)))
2940 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
2941 return STATUS_NO_MEMORY
;
2944 /* Lookup in <dir>\name.dll
2945 * <dir>\name.manifest
2946 * <dir>\name\name.dll
2947 * <dir>\name\name.manifest
2949 * First 'appdir' is used as <dir>, if that failed
2950 * it tries application manifest file path.
2952 strcpyW( buffer
, acl
->actctx
->appdir
.info
);
2953 p
= buffer
+ strlenW(buffer
);
2954 for (i
= 0; i
< 4; i
++)
2958 struct assembly
*assembly
= acl
->actctx
->assemblies
;
2959 if (!RtlGetFullPathName_U(assembly
->manifest
.info
, len
* sizeof(WCHAR
), buffer
, &p
)) break;
2963 strcpyW( p
, ai
->name
);
2966 strcpyW( p
, dotDllW
);
2967 if (RtlDosPathNameToNtPathName_U( buffer
, &nameW
, NULL
, NULL
))
2969 status
= open_nt_file( &file
, &nameW
);
2972 status
= get_manifest_in_pe_file( acl
, ai
, nameW
.Buffer
, directory
, FALSE
, file
,
2973 (LPCWSTR
)CREATEPROCESS_MANIFEST_RESOURCE_ID
, 0 );
2977 RtlFreeUnicodeString( &nameW
);
2980 strcpyW( p
, dotManifestW
);
2981 if (RtlDosPathNameToNtPathName_U( buffer
, &nameW
, NULL
, NULL
))
2983 status
= open_nt_file( &file
, &nameW
);
2986 status
= get_manifest_in_manifest_file( acl
, ai
, nameW
.Buffer
, directory
, FALSE
, file
);
2990 RtlFreeUnicodeString( &nameW
);
2992 status
= STATUS_SXS_ASSEMBLY_NOT_FOUND
;
2994 RtlFreeUnicodeString( &nameW
);
2995 RtlFreeHeap( RtlGetProcessHeap(), 0, directory
);
2996 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
3000 static NTSTATUS
parse_depend_manifests(struct actctx_loader
* acl
)
3002 NTSTATUS status
= STATUS_SUCCESS
;
3005 for (i
= 0; i
< acl
->num_dependencies
; i
++)
3007 if (lookup_assembly(acl
, &acl
->dependencies
[i
]) != STATUS_SUCCESS
)
3009 if (!acl
->dependencies
[i
].optional
)
3011 const struct assembly_version
*ver
= &acl
->dependencies
[i
].version
;
3012 DPRINT1( "Could not find dependent assembly %S (%u.%u.%u.%u)\n",
3013 acl
->dependencies
[i
].name
,
3014 ver
->major
, ver
->minor
, ver
->build
, ver
->revision
);
3015 status
= STATUS_SXS_CANT_GEN_ACTCTX
;
3020 /* FIXME should now iterate through all refs */
3024 /* find the appropriate activation context for RtlQueryInformationActivationContext */
3025 static NTSTATUS
find_query_actctx( HANDLE
*handle
, DWORD flags
, ULONG
class )
3027 NTSTATUS status
= STATUS_SUCCESS
;
3029 if (flags
& RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT
)
3031 if (*handle
) return STATUS_INVALID_PARAMETER
;
3033 if (NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
3034 *handle
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
->ActivationContext
;
3036 else if (flags
& (RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS
| RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE
))
3039 LDR_DATA_TABLE_ENTRY
*pldr
;
3041 if (!*handle
) return STATUS_INVALID_PARAMETER
;
3043 LdrLockLoaderLock( 0, NULL
, &magic
);
3044 if (!LdrFindEntryForAddress( *handle
, &pldr
))
3046 if ((flags
& RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE
) && *handle
!= pldr
->DllBase
)
3047 status
= STATUS_DLL_NOT_FOUND
;
3049 *handle
= pldr
->EntryPointActivationContext
;
3051 else status
= STATUS_DLL_NOT_FOUND
;
3052 LdrUnlockLoaderLock( 0, magic
);
3054 else if (!*handle
&& (class != ActivationContextBasicInformation
))
3055 *handle
= process_actctx
;
3060 static NTSTATUS
build_dllredirect_section(ACTIVATION_CONTEXT
* actctx
, struct strsection_header
**section
)
3062 unsigned int i
, j
, total_len
= 0, dll_count
= 0;
3063 struct strsection_header
*header
;
3064 struct dllredirect_data
*data
;
3065 struct string_index
*index
;
3068 /* compute section length */
3069 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3071 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3072 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3074 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3076 /* each entry needs index, data and string data */
3077 total_len
+= sizeof(*index
);
3078 total_len
+= sizeof(*data
);
3079 total_len
+= aligned_string_len((strlenW(dll
->name
)+1)*sizeof(WCHAR
));
3082 dll_count
+= assembly
->num_dlls
;
3085 total_len
+= sizeof(*header
);
3087 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
3088 if (!header
) return STATUS_NO_MEMORY
;
3090 memset(header
, 0, sizeof(*header
));
3091 header
->magic
= STRSECTION_MAGIC
;
3092 header
->size
= sizeof(*header
);
3093 header
->count
= dll_count
;
3094 header
->index_offset
= sizeof(*header
);
3095 index
= (struct string_index
*)((BYTE
*)header
+ header
->index_offset
);
3096 name_offset
= header
->index_offset
+ header
->count
*sizeof(*index
);
3098 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3100 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3101 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3103 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3107 /* setup new index entry */
3108 str
.Buffer
= dll
->name
;
3109 str
.Length
= strlenW(dll
->name
)*sizeof(WCHAR
);
3110 str
.MaximumLength
= str
.Length
+ sizeof(WCHAR
);
3111 /* hash original class name */
3112 RtlHashUnicodeString(&str
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &index
->hash
);
3114 index
->name_offset
= name_offset
;
3115 index
->name_len
= str
.Length
;
3116 index
->data_offset
= index
->name_offset
+ aligned_string_len(str
.MaximumLength
);
3117 index
->data_len
= sizeof(*data
);
3118 index
->rosterindex
= i
+ 1;
3121 data
= (struct dllredirect_data
*)((BYTE
*)header
+ index
->data_offset
);
3122 data
->size
= sizeof(*data
);
3123 data
->unk
= 2; /* FIXME: seems to be constant */
3124 memset(data
->res
, 0, sizeof(data
->res
));
3127 ptrW
= (WCHAR
*)((BYTE
*)header
+ index
->name_offset
);
3128 memcpy(ptrW
, dll
->name
, index
->name_len
);
3129 ptrW
[index
->name_len
/sizeof(WCHAR
)] = 0;
3131 name_offset
+= sizeof(*data
) + aligned_string_len(str
.MaximumLength
);
3139 return STATUS_SUCCESS
;
3142 static struct string_index
*find_string_index(const struct strsection_header
*section
, const UNICODE_STRING
*name
)
3144 struct string_index
*iter
, *index
= NULL
;
3147 RtlHashUnicodeString(name
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &hash
);
3148 iter
= (struct string_index
*)((BYTE
*)section
+ section
->index_offset
);
3150 for (i
= 0; i
< section
->count
; i
++)
3152 if (iter
->hash
== hash
)
3154 const WCHAR
*nameW
= (WCHAR
*)((BYTE
*)section
+ iter
->name_offset
);
3156 if (!strcmpiW(nameW
, name
->Buffer
))
3162 DPRINT1("hash collision 0x%08x, %wZ, %S\n", hash
, name
, nameW
);
3170 static struct guid_index
*find_guid_index(const struct guidsection_header
*section
, const GUID
*guid
)
3172 struct guid_index
*iter
, *index
= NULL
;
3175 iter
= (struct guid_index
*)((BYTE
*)section
+ section
->index_offset
);
3177 for (i
= 0; i
< section
->count
; i
++)
3179 if (!memcmp(guid
, &iter
->guid
, sizeof(*guid
)))
3190 static inline struct dllredirect_data
*get_dllredirect_data(ACTIVATION_CONTEXT
*ctxt
, struct string_index
*index
)
3192 return (struct dllredirect_data
*)((BYTE
*)ctxt
->dllredirect_section
+ index
->data_offset
);
3195 static NTSTATUS
find_dll_redirection(ACTIVATION_CONTEXT
* actctx
, const UNICODE_STRING
*name
,
3196 PACTCTX_SECTION_KEYED_DATA data
)
3198 struct dllredirect_data
*dll
;
3199 struct string_index
*index
;
3201 if (!(actctx
->sections
& DLLREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
3203 if (!actctx
->dllredirect_section
)
3205 struct strsection_header
*section
;
3207 NTSTATUS status
= build_dllredirect_section(actctx
, §ion
);
3208 if (status
) return status
;
3210 if (InterlockedCompareExchangePointer((void**)&actctx
->dllredirect_section
, section
, NULL
))
3211 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
3214 index
= find_string_index(actctx
->dllredirect_section
, name
);
3215 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
3217 dll
= get_dllredirect_data(actctx
, index
);
3219 data
->ulDataFormatVersion
= 1;
3221 data
->ulLength
= dll
->size
;
3222 data
->lpSectionGlobalData
= NULL
;
3223 data
->ulSectionGlobalDataLength
= 0;
3224 data
->lpSectionBase
= actctx
->dllredirect_section
;
3225 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->dllredirect_section
);
3226 data
->hActCtx
= NULL
;
3228 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
3229 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
3231 return STATUS_SUCCESS
;
3234 static inline struct string_index
*get_wndclass_first_index(ACTIVATION_CONTEXT
*actctx
)
3236 return (struct string_index
*)((BYTE
*)actctx
->wndclass_section
+ actctx
->wndclass_section
->index_offset
);
3239 static inline struct wndclass_redirect_data
*get_wndclass_data(ACTIVATION_CONTEXT
*ctxt
, struct string_index
*index
)
3241 return (struct wndclass_redirect_data
*)((BYTE
*)ctxt
->wndclass_section
+ index
->data_offset
);
3244 static NTSTATUS
build_wndclass_section(ACTIVATION_CONTEXT
* actctx
, struct strsection_header
**section
)
3246 unsigned int i
, j
, k
, total_len
= 0, class_count
= 0;
3247 struct wndclass_redirect_data
*data
;
3248 struct strsection_header
*header
;
3249 struct string_index
*index
;
3252 /* compute section length */
3253 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3255 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3256 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3258 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3259 for (k
= 0; k
< dll
->entities
.num
; k
++)
3261 struct entity
*entity
= &dll
->entities
.base
[k
];
3262 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
)
3264 int class_len
= strlenW(entity
->u
.class.name
) + 1;
3267 /* each class entry needs index, data and string data */
3268 total_len
+= sizeof(*index
);
3269 total_len
+= sizeof(*data
);
3270 /* original name is stored separately */
3271 total_len
+= aligned_string_len(class_len
*sizeof(WCHAR
));
3272 /* versioned name and module name are stored one after another */
3273 if (entity
->u
.class.versioned
)
3274 len
= get_assembly_version(assembly
, NULL
) + class_len
+ 1 /* '!' separator */;
3277 len
+= strlenW(dll
->name
) + 1;
3278 total_len
+= aligned_string_len(len
*sizeof(WCHAR
));
3286 total_len
+= sizeof(*header
);
3288 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
3289 if (!header
) return STATUS_NO_MEMORY
;
3291 memset(header
, 0, sizeof(*header
));
3292 header
->magic
= STRSECTION_MAGIC
;
3293 header
->size
= sizeof(*header
);
3294 header
->count
= class_count
;
3295 header
->index_offset
= sizeof(*header
);
3296 index
= (struct string_index
*)((BYTE
*)header
+ header
->index_offset
);
3297 name_offset
= header
->index_offset
+ header
->count
*sizeof(*index
);
3299 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3301 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3302 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3304 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3305 for (k
= 0; k
< dll
->entities
.num
; k
++)
3307 struct entity
*entity
= &dll
->entities
.base
[k
];
3308 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
)
3310 static const WCHAR exclW
[] = {'!',0};
3311 ULONG versioned_len
, module_len
;
3315 /* setup new index entry */
3316 str
.Buffer
= entity
->u
.class.name
;
3317 str
.Length
= strlenW(entity
->u
.class.name
)*sizeof(WCHAR
);
3318 str
.MaximumLength
= str
.Length
+ sizeof(WCHAR
);
3319 /* hash original class name */
3320 RtlHashUnicodeString(&str
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &index
->hash
);
3322 /* include '!' separator too */
3323 if (entity
->u
.class.versioned
)
3324 versioned_len
= (get_assembly_version(assembly
, NULL
) + 1)*sizeof(WCHAR
) + str
.Length
;
3326 versioned_len
= str
.Length
;
3327 module_len
= strlenW(dll
->name
)*sizeof(WCHAR
);
3329 index
->name_offset
= name_offset
;
3330 index
->name_len
= str
.Length
;
3331 index
->data_offset
= index
->name_offset
+ aligned_string_len(str
.MaximumLength
);
3332 index
->data_len
= sizeof(*data
) + versioned_len
+ module_len
+ 2*sizeof(WCHAR
) /* two nulls */;
3333 index
->rosterindex
= i
+ 1;
3336 data
= (struct wndclass_redirect_data
*)((BYTE
*)header
+ index
->data_offset
);
3337 data
->size
= sizeof(*data
);
3339 data
->name_len
= versioned_len
;
3340 data
->name_offset
= sizeof(*data
);
3341 data
->module_len
= module_len
;
3342 data
->module_offset
= index
->data_offset
+ data
->name_offset
+ data
->name_len
+ sizeof(WCHAR
);
3344 /* original class name */
3345 ptrW
= (WCHAR
*)((BYTE
*)header
+ index
->name_offset
);
3346 memcpy(ptrW
, entity
->u
.class.name
, index
->name_len
);
3347 ptrW
[index
->name_len
/sizeof(WCHAR
)] = 0;
3350 ptrW
= (WCHAR
*)((BYTE
*)header
+ data
->module_offset
);
3351 memcpy(ptrW
, dll
->name
, data
->module_len
);
3352 ptrW
[data
->module_len
/sizeof(WCHAR
)] = 0;
3354 /* versioned name */
3355 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->name_offset
);
3356 if (entity
->u
.class.versioned
)
3358 get_assembly_version(assembly
, ptrW
);
3359 strcatW(ptrW
, exclW
);
3360 strcatW(ptrW
, entity
->u
.class.name
);
3364 memcpy(ptrW
, entity
->u
.class.name
, index
->name_len
);
3365 ptrW
[index
->name_len
/sizeof(WCHAR
)] = 0;
3368 name_offset
+= sizeof(*data
);
3369 name_offset
+= aligned_string_len(str
.MaximumLength
) + aligned_string_len(versioned_len
+ module_len
+ 2*sizeof(WCHAR
));
3379 return STATUS_SUCCESS
;
3382 static NTSTATUS
find_window_class(ACTIVATION_CONTEXT
* actctx
, const UNICODE_STRING
*name
,
3383 PACTCTX_SECTION_KEYED_DATA data
)
3385 struct string_index
*iter
, *index
= NULL
;
3386 struct wndclass_redirect_data
*class;
3390 if (!(actctx
->sections
& WINDOWCLASS_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
3392 if (!actctx
->wndclass_section
)
3394 struct strsection_header
*section
;
3396 NTSTATUS status
= build_wndclass_section(actctx
, §ion
);
3397 if (status
) return status
;
3399 if (InterlockedCompareExchangePointer((void**)&actctx
->wndclass_section
, section
, NULL
))
3400 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
3404 RtlHashUnicodeString(name
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &hash
);
3405 iter
= get_wndclass_first_index(actctx
);
3407 for (i
= 0; i
< actctx
->wndclass_section
->count
; i
++)
3409 if (iter
->hash
== hash
)
3411 const WCHAR
*nameW
= (WCHAR
*)((BYTE
*)actctx
->wndclass_section
+ iter
->name_offset
);
3413 if (!strcmpW(nameW
, name
->Buffer
))
3419 DPRINT1("hash collision 0x%08x, %wZ, %S\n", hash
, name
, nameW
);
3424 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
3426 class = get_wndclass_data(actctx
, index
);
3428 data
->ulDataFormatVersion
= 1;
3429 data
->lpData
= class;
3430 /* full length includes string length with nulls */
3431 data
->ulLength
= class->size
+ class->name_len
+ class->module_len
+ 2*sizeof(WCHAR
);
3432 data
->lpSectionGlobalData
= NULL
;
3433 data
->ulSectionGlobalDataLength
= 0;
3434 data
->lpSectionBase
= actctx
->wndclass_section
;
3435 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->wndclass_section
);
3436 data
->hActCtx
= NULL
;
3438 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
3439 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
3441 return STATUS_SUCCESS
;
3444 static NTSTATUS
build_tlib_section(ACTIVATION_CONTEXT
* actctx
, struct guidsection_header
**section
)
3446 unsigned int i
, j
, k
, total_len
= 0, tlib_count
= 0, names_len
= 0;
3447 struct guidsection_header
*header
;
3448 ULONG module_offset
, data_offset
;
3449 struct tlibredirect_data
*data
;
3450 struct guid_index
*index
;
3452 /* compute section length */
3453 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3455 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3456 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3458 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3459 for (k
= 0; k
< dll
->entities
.num
; k
++)
3461 struct entity
*entity
= &dll
->entities
.base
[k
];
3462 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
)
3464 /* each entry needs index, data and string data for module name and help string */
3465 total_len
+= sizeof(*index
);
3466 total_len
+= sizeof(*data
);
3467 /* help string is stored separately */
3468 if (*entity
->u
.typelib
.helpdir
)
3469 total_len
+= aligned_string_len((strlenW(entity
->u
.typelib
.helpdir
)+1)*sizeof(WCHAR
));
3471 /* module names are packed one after another */
3472 names_len
+= (strlenW(dll
->name
)+1)*sizeof(WCHAR
);
3480 total_len
+= aligned_string_len(names_len
);
3481 total_len
+= sizeof(*header
);
3483 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
3484 if (!header
) return STATUS_NO_MEMORY
;
3486 memset(header
, 0, sizeof(*header
));
3487 header
->magic
= GUIDSECTION_MAGIC
;
3488 header
->size
= sizeof(*header
);
3489 header
->count
= tlib_count
;
3490 header
->index_offset
= sizeof(*header
) + aligned_string_len(names_len
);
3491 index
= (struct guid_index
*)((BYTE
*)header
+ header
->index_offset
);
3492 module_offset
= sizeof(*header
);
3493 data_offset
= header
->index_offset
+ tlib_count
*sizeof(*index
);
3495 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3497 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3498 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3500 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3501 for (k
= 0; k
< dll
->entities
.num
; k
++)
3503 struct entity
*entity
= &dll
->entities
.base
[k
];
3504 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
)
3506 ULONG module_len
, help_len
;
3510 if (*entity
->u
.typelib
.helpdir
)
3511 help_len
= strlenW(entity
->u
.typelib
.helpdir
)*sizeof(WCHAR
);
3515 module_len
= strlenW(dll
->name
)*sizeof(WCHAR
);
3517 /* setup new index entry */
3518 RtlInitUnicodeString(&str
, entity
->u
.typelib
.tlbid
);
3519 RtlGUIDFromString(&str
, &index
->guid
);
3520 index
->data_offset
= data_offset
;
3521 index
->data_len
= sizeof(*data
) + aligned_string_len(help_len
);
3522 index
->rosterindex
= i
+ 1;
3525 data
= (struct tlibredirect_data
*)((BYTE
*)header
+ index
->data_offset
);
3526 data
->size
= sizeof(*data
);
3528 data
->name_len
= module_len
;
3529 data
->name_offset
= module_offset
;
3530 /* FIXME: resourceid handling is really weird, and it doesn't seem to be useful */
3532 data
->flags
= entity
->u
.typelib
.flags
;
3533 data
->help_len
= help_len
;
3534 data
->help_offset
= sizeof(*data
);
3535 data
->major_version
= entity
->u
.typelib
.major
;
3536 data
->minor_version
= entity
->u
.typelib
.minor
;
3539 ptrW
= (WCHAR
*)((BYTE
*)header
+ data
->name_offset
);
3540 memcpy(ptrW
, dll
->name
, data
->name_len
);
3541 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
3546 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->help_offset
);
3547 memcpy(ptrW
, entity
->u
.typelib
.helpdir
, data
->help_len
);
3548 ptrW
[data
->help_len
/sizeof(WCHAR
)] = 0;
3551 data_offset
+= sizeof(*data
);
3553 data_offset
+= aligned_string_len(help_len
+ sizeof(WCHAR
));
3555 module_offset
+= module_len
+ sizeof(WCHAR
);
3565 return STATUS_SUCCESS
;
3568 static inline struct tlibredirect_data
*get_tlib_data(ACTIVATION_CONTEXT
*actctx
, struct guid_index
*index
)
3570 return (struct tlibredirect_data
*)((BYTE
*)actctx
->tlib_section
+ index
->data_offset
);
3573 static NTSTATUS
find_tlib_redirection(ACTIVATION_CONTEXT
* actctx
, const GUID
*guid
, ACTCTX_SECTION_KEYED_DATA
* data
)
3575 struct guid_index
*index
= NULL
;
3576 struct tlibredirect_data
*tlib
;
3578 if (!(actctx
->sections
& TLIBREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
3580 if (!actctx
->tlib_section
)
3582 struct guidsection_header
*section
;
3584 NTSTATUS status
= build_tlib_section(actctx
, §ion
);
3585 if (status
) return status
;
3587 if (InterlockedCompareExchangePointer((void**)&actctx
->tlib_section
, section
, NULL
))
3588 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
3591 index
= find_guid_index(actctx
->tlib_section
, guid
);
3592 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
3594 tlib
= get_tlib_data(actctx
, index
);
3596 data
->ulDataFormatVersion
= 1;
3597 data
->lpData
= tlib
;
3598 /* full length includes string length with nulls */
3599 data
->ulLength
= tlib
->size
+ tlib
->help_len
+ sizeof(WCHAR
);
3600 data
->lpSectionGlobalData
= (BYTE
*)actctx
->tlib_section
+ actctx
->tlib_section
->names_offset
;
3601 data
->ulSectionGlobalDataLength
= actctx
->tlib_section
->names_len
;
3602 data
->lpSectionBase
= actctx
->tlib_section
;
3603 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->tlib_section
);
3604 data
->hActCtx
= NULL
;
3606 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
3607 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
3609 return STATUS_SUCCESS
;
3612 static void generate_uuid(ULONG
*seed
, GUID
*guid
)
3614 ULONG
*ptr
= (ULONG
*)guid
;
3617 /* GUID is 16 bytes long */
3618 for (i
= 0; i
< sizeof(GUID
)/sizeof(ULONG
); i
++, ptr
++)
3619 *ptr
= RtlUniform(seed
);
3621 guid
->Data3
&= 0x0fff;
3622 guid
->Data3
|= (4 << 12);
3623 guid
->Data4
[0] &= 0x3f;
3624 guid
->Data4
[0] |= 0x80;
3627 static void get_comserver_datalen(const struct entity_array
*entities
, const struct dll_redirect
*dll
,
3628 unsigned int *count
, unsigned int *len
, unsigned int *module_len
)
3632 for (i
= 0; i
< entities
->num
; i
++)
3634 struct entity
*entity
= &entities
->base
[i
];
3635 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)
3637 /* each entry needs two index entries, extra one goes for alias GUID */
3638 *len
+= 2*sizeof(struct guid_index
);
3639 /* To save some memory we don't allocated two data structures,
3640 instead alias index and normal index point to the same data structure. */
3641 *len
+= sizeof(struct comclassredirect_data
);
3643 /* for clrClass store some more */
3644 if (entity
->u
.comclass
.name
)
3646 unsigned int str_len
;
3648 /* all string data is stored together in aligned block */
3649 str_len
= strlenW(entity
->u
.comclass
.name
)+1;
3650 if (entity
->u
.comclass
.progid
)
3651 str_len
+= strlenW(entity
->u
.comclass
.progid
)+1;
3652 if (entity
->u
.comclass
.version
)
3653 str_len
+= strlenW(entity
->u
.comclass
.version
)+1;
3655 *len
+= sizeof(struct clrclass_data
);
3656 *len
+= aligned_string_len(str_len
*sizeof(WCHAR
));
3658 /* module name is forced to mscoree.dll, and stored two times with different case */
3659 *module_len
+= sizeof(mscoreeW
) + sizeof(mscoree2W
);
3663 /* progid string is stored separately */
3664 if (entity
->u
.comclass
.progid
)
3665 *len
+= aligned_string_len((strlenW(entity
->u
.comclass
.progid
)+1)*sizeof(WCHAR
));
3667 *module_len
+= (strlenW(dll
->name
)+1)*sizeof(WCHAR
);
3675 static void add_comserver_record(const struct guidsection_header
*section
, const struct entity_array
*entities
,
3676 const struct dll_redirect
*dll
, struct guid_index
**index
, ULONG
*data_offset
, ULONG
*module_offset
,
3677 ULONG
*seed
, ULONG rosterindex
)
3681 for (i
= 0; i
< entities
->num
; i
++)
3683 struct entity
*entity
= &entities
->base
[i
];
3684 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)
3686 ULONG module_len
, progid_len
, str_len
= 0;
3687 struct comclassredirect_data
*data
;
3688 struct guid_index
*alias_index
;
3689 struct clrclass_data
*clrdata
;
3693 if (entity
->u
.comclass
.progid
)
3694 progid_len
= strlenW(entity
->u
.comclass
.progid
)*sizeof(WCHAR
);
3698 module_len
= dll
? strlenW(dll
->name
)*sizeof(WCHAR
) : strlenW(mscoreeW
)*sizeof(WCHAR
);
3700 /* setup new index entry */
3701 RtlInitUnicodeString(&str
, entity
->u
.comclass
.clsid
);
3702 RtlGUIDFromString(&str
, &(*index
)->guid
);
3704 (*index
)->data_offset
= *data_offset
;
3705 (*index
)->data_len
= sizeof(*data
); /* additional length added later */
3706 (*index
)->rosterindex
= rosterindex
;
3708 /* Setup new index entry for alias guid. Alias index records are placed after
3709 normal records, so normal guids are hit first on search. Note that class count
3711 alias_index
= (*index
) + section
->count
/2;
3712 generate_uuid(seed
, &alias_index
->guid
);
3713 alias_index
->data_offset
= (*index
)->data_offset
;
3714 alias_index
->data_len
= 0;
3715 alias_index
->rosterindex
= (*index
)->rosterindex
;
3718 data
= (struct comclassredirect_data
*)((BYTE
*)section
+ (*index
)->data_offset
);
3719 data
->size
= sizeof(*data
);
3723 data
->model
= entity
->u
.comclass
.model
;
3724 data
->clsid
= (*index
)->guid
;
3725 data
->alias
= alias_index
->guid
;
3726 data
->clsid2
= data
->clsid
;
3727 if (entity
->u
.comclass
.tlbid
)
3729 RtlInitUnicodeString(&str
, entity
->u
.comclass
.tlbid
);
3730 RtlGUIDFromString(&str
, &data
->tlbid
);
3733 memset(&data
->tlbid
, 0, sizeof(data
->tlbid
));
3734 data
->name_len
= module_len
;
3735 data
->name_offset
= *module_offset
;
3736 data
->progid_len
= progid_len
;
3737 data
->progid_offset
= data
->progid_len
? data
->size
: 0; /* in case of clrClass additional offset is added later */
3738 data
->clrdata_len
= 0; /* will be set later */
3739 data
->clrdata_offset
= entity
->u
.comclass
.name
? sizeof(*data
) : 0;
3740 data
->miscstatus
= entity
->u
.comclass
.miscstatus
;
3741 data
->miscstatuscontent
= entity
->u
.comclass
.miscstatuscontent
;
3742 data
->miscstatusthumbnail
= entity
->u
.comclass
.miscstatusthumbnail
;
3743 data
->miscstatusicon
= entity
->u
.comclass
.miscstatusicon
;
3744 data
->miscstatusdocprint
= entity
->u
.comclass
.miscstatusdocprint
;
3746 /* mask describes which misc* data is available */
3748 if (data
->miscstatus
)
3749 data
->miscmask
|= MiscStatus
;
3750 if (data
->miscstatuscontent
)
3751 data
->miscmask
|= MiscStatusContent
;
3752 if (data
->miscstatusthumbnail
)
3753 data
->miscmask
|= MiscStatusThumbnail
;
3754 if (data
->miscstatusicon
)
3755 data
->miscmask
|= MiscStatusIcon
;
3756 if (data
->miscstatusdocprint
)
3757 data
->miscmask
|= MiscStatusDocPrint
;
3759 if (data
->clrdata_offset
)
3761 clrdata
= (struct clrclass_data
*)((BYTE
*)data
+ data
->clrdata_offset
);
3763 clrdata
->size
= sizeof(*clrdata
);
3764 clrdata
->res
[0] = 0;
3765 clrdata
->res
[1] = 2; /* FIXME: unknown field */
3766 clrdata
->module_len
= strlenW(mscoreeW
)*sizeof(WCHAR
);
3767 clrdata
->module_offset
= *module_offset
+ data
->name_len
+ sizeof(WCHAR
);
3768 clrdata
->name_len
= strlenW(entity
->u
.comclass
.name
)*sizeof(WCHAR
);
3769 clrdata
->name_offset
= clrdata
->size
;
3770 clrdata
->version_len
= entity
->u
.comclass
.version
? strlenW(entity
->u
.comclass
.version
)*sizeof(WCHAR
) : 0;
3771 clrdata
->version_offset
= clrdata
->version_len
? clrdata
->name_offset
+ clrdata
->name_len
+ sizeof(WCHAR
) : 0;
3772 clrdata
->res2
[0] = 0;
3773 clrdata
->res2
[1] = 0;
3775 data
->clrdata_len
= clrdata
->size
+ clrdata
->name_len
+ sizeof(WCHAR
);
3778 ptrW
= (WCHAR
*)((BYTE
*)section
+ clrdata
->module_offset
);
3779 memcpy(ptrW
, mscoree2W
, clrdata
->module_len
);
3780 ptrW
[clrdata
->module_len
/sizeof(WCHAR
)] = 0;
3782 ptrW
= (WCHAR
*)((BYTE
*)section
+ data
->name_offset
);
3783 memcpy(ptrW
, mscoreeW
, data
->name_len
);
3784 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
3787 ptrW
= (WCHAR
*)((BYTE
*)clrdata
+ clrdata
->name_offset
);
3788 memcpy(ptrW
, entity
->u
.comclass
.name
, clrdata
->name_len
);
3789 ptrW
[clrdata
->name_len
/sizeof(WCHAR
)] = 0;
3791 /* runtime version, optional */
3792 if (clrdata
->version_len
)
3794 data
->clrdata_len
+= clrdata
->version_len
+ sizeof(WCHAR
);
3796 ptrW
= (WCHAR
*)((BYTE
*)clrdata
+ clrdata
->version_offset
);
3797 memcpy(ptrW
, entity
->u
.comclass
.version
, clrdata
->version_len
);
3798 ptrW
[clrdata
->version_len
/sizeof(WCHAR
)] = 0;
3801 if (data
->progid_len
)
3802 data
->progid_offset
+= data
->clrdata_len
;
3803 (*index
)->data_len
+= sizeof(*clrdata
);
3810 ptrW
= (WCHAR
*)((BYTE
*)section
+ data
->name_offset
);
3811 memcpy(ptrW
, dll
->name
, data
->name_len
);
3812 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
3816 if (data
->progid_len
)
3818 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->progid_offset
);
3819 memcpy(ptrW
, entity
->u
.comclass
.progid
, data
->progid_len
);
3820 ptrW
[data
->progid_len
/sizeof(WCHAR
)] = 0;
3823 /* string block length */
3827 str_len
+= clrdata
->name_len
+ sizeof(WCHAR
);
3828 if (clrdata
->version_len
)
3829 str_len
+= clrdata
->version_len
+ sizeof(WCHAR
);
3832 str_len
+= progid_len
+ sizeof(WCHAR
);
3834 (*index
)->data_len
+= aligned_string_len(str_len
);
3835 alias_index
->data_len
= (*index
)->data_len
;
3837 /* move to next data record */
3838 (*data_offset
) += sizeof(*data
) + aligned_string_len(str_len
);
3839 (*module_offset
) += module_len
+ sizeof(WCHAR
);
3843 (*data_offset
) += sizeof(*clrdata
);
3844 (*module_offset
) += clrdata
->module_len
+ sizeof(WCHAR
);
3851 static NTSTATUS
build_comserver_section(ACTIVATION_CONTEXT
* actctx
, struct guidsection_header
**section
)
3853 unsigned int i
, j
, total_len
= 0, class_count
= 0, names_len
= 0;
3854 struct guidsection_header
*header
;
3855 ULONG module_offset
, data_offset
;
3856 struct guid_index
*index
;
3859 /* compute section length */
3860 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3862 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3863 get_comserver_datalen(&assembly
->entities
, NULL
, &class_count
, &total_len
, &names_len
);
3864 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3866 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3867 get_comserver_datalen(&dll
->entities
, dll
, &class_count
, &total_len
, &names_len
);
3871 total_len
+= aligned_string_len(names_len
);
3872 total_len
+= sizeof(*header
);
3874 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
3875 if (!header
) return STATUS_NO_MEMORY
;
3877 memset(header
, 0, sizeof(*header
));
3878 header
->magic
= GUIDSECTION_MAGIC
;
3879 header
->size
= sizeof(*header
);
3880 header
->count
= 2*class_count
;
3881 header
->index_offset
= sizeof(*header
) + aligned_string_len(names_len
);
3882 index
= (struct guid_index
*)((BYTE
*)header
+ header
->index_offset
);
3883 module_offset
= sizeof(*header
);
3884 data_offset
= header
->index_offset
+ 2*class_count
*sizeof(*index
);
3886 seed
= NtGetTickCount();
3887 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3889 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3890 add_comserver_record(header
, &assembly
->entities
, NULL
, &index
, &data_offset
, &module_offset
, &seed
, i
+1);
3891 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3893 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3894 add_comserver_record(header
, &dll
->entities
, dll
, &index
, &data_offset
, &module_offset
, &seed
, i
+1);
3900 return STATUS_SUCCESS
;
3903 static inline struct comclassredirect_data
*get_comclass_data(ACTIVATION_CONTEXT
*actctx
, struct guid_index
*index
)
3905 return (struct comclassredirect_data
*)((BYTE
*)actctx
->comserver_section
+ index
->data_offset
);
3908 static NTSTATUS
find_comserver_redirection(ACTIVATION_CONTEXT
* actctx
, const GUID
*guid
, ACTCTX_SECTION_KEYED_DATA
* data
)
3910 struct comclassredirect_data
*comclass
;
3911 struct guid_index
*index
= NULL
;
3913 if (!(actctx
->sections
& SERVERREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
3915 if (!actctx
->comserver_section
)
3917 struct guidsection_header
*section
;
3919 NTSTATUS status
= build_comserver_section(actctx
, §ion
);
3920 if (status
) return status
;
3922 if (InterlockedCompareExchangePointer((void**)&actctx
->comserver_section
, section
, NULL
))
3923 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
3926 index
= find_guid_index(actctx
->comserver_section
, guid
);
3927 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
3929 comclass
= get_comclass_data(actctx
, index
);
3931 data
->ulDataFormatVersion
= 1;
3932 data
->lpData
= comclass
;
3933 /* full length includes string length with nulls */
3934 data
->ulLength
= comclass
->size
+ comclass
->clrdata_len
;
3935 if (comclass
->progid_len
) data
->ulLength
+= comclass
->progid_len
+ sizeof(WCHAR
);
3936 data
->lpSectionGlobalData
= (BYTE
*)actctx
->comserver_section
+ actctx
->comserver_section
->names_offset
;
3937 data
->ulSectionGlobalDataLength
= actctx
->comserver_section
->names_len
;
3938 data
->lpSectionBase
= actctx
->comserver_section
;
3939 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->comserver_section
);
3940 data
->hActCtx
= NULL
;
3942 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
3943 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
3945 return STATUS_SUCCESS
;
3948 static void get_ifaceps_datalen(const struct entity_array
*entities
, unsigned int *count
, unsigned int *len
)
3952 for (i
= 0; i
< entities
->num
; i
++)
3954 struct entity
*entity
= &entities
->base
[i
];
3955 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
)
3957 *len
+= sizeof(struct guid_index
) + sizeof(struct ifacepsredirect_data
);
3958 if (entity
->u
.ifaceps
.name
)
3959 *len
+= aligned_string_len((strlenW(entity
->u
.ifaceps
.name
)+1)*sizeof(WCHAR
));
3965 static void add_ifaceps_record(struct guidsection_header
*section
, struct entity_array
*entities
,
3966 struct guid_index
**index
, ULONG
*data_offset
, ULONG rosterindex
)
3970 for (i
= 0; i
< entities
->num
; i
++)
3972 struct entity
*entity
= &entities
->base
[i
];
3973 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
)
3975 struct ifacepsredirect_data
*data
= (struct ifacepsredirect_data
*)((BYTE
*)section
+ *data_offset
);
3979 if (entity
->u
.ifaceps
.name
)
3980 name_len
= strlenW(entity
->u
.ifaceps
.name
)*sizeof(WCHAR
);
3985 RtlInitUnicodeString(&str
, entity
->u
.ifaceps
.iid
);
3986 RtlGUIDFromString(&str
, &(*index
)->guid
);
3987 (*index
)->data_offset
= *data_offset
;
3988 (*index
)->data_len
= sizeof(*data
) + name_len
? aligned_string_len(name_len
+ sizeof(WCHAR
)) : 0;
3989 (*index
)->rosterindex
= rosterindex
;
3991 /* setup data record */
3992 data
->size
= sizeof(*data
);
3993 data
->mask
= entity
->u
.ifaceps
.mask
;
3995 /* proxyStubClsid32 value is only stored for external PS,
3996 if set it's used as iid, otherwise 'iid' attribute value is used */
3997 if (entity
->u
.ifaceps
.ps32
)
3999 RtlInitUnicodeString(&str
, entity
->u
.ifaceps
.ps32
);
4000 RtlGUIDFromString(&str
, &data
->iid
);
4003 data
->iid
= (*index
)->guid
;
4005 data
->nummethods
= entity
->u
.ifaceps
.nummethods
;
4007 if (entity
->u
.ifaceps
.tlib
)
4009 RtlInitUnicodeString(&str
, entity
->u
.ifaceps
.tlib
);
4010 RtlGUIDFromString(&str
, &data
->tlbid
);
4013 memset(&data
->tlbid
, 0, sizeof(data
->tlbid
));
4015 if (entity
->u
.ifaceps
.base
)
4017 RtlInitUnicodeString(&str
, entity
->u
.ifaceps
.base
);
4018 RtlGUIDFromString(&str
, &data
->base
);
4021 memset(&data
->base
, 0, sizeof(data
->base
));
4023 data
->name_len
= name_len
;
4024 data
->name_offset
= data
->name_len
? sizeof(*data
) : 0;
4029 WCHAR
*ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->name_offset
);
4030 memcpy(ptrW
, entity
->u
.ifaceps
.name
, data
->name_len
);
4031 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
4034 /* move to next record */
4036 *data_offset
+= sizeof(*data
);
4038 *data_offset
+= aligned_string_len(data
->name_len
+ sizeof(WCHAR
));
4043 static NTSTATUS
build_ifaceps_section(ACTIVATION_CONTEXT
* actctx
, struct guidsection_header
**section
)
4045 unsigned int i
, j
, total_len
= 0, count
= 0;
4046 struct guidsection_header
*header
;
4047 struct guid_index
*index
;
4050 /* compute section length */
4051 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4053 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4055 get_ifaceps_datalen(&assembly
->entities
, &count
, &total_len
);
4056 for (j
= 0; j
< assembly
->num_dlls
; j
++)
4058 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
4059 get_ifaceps_datalen(&dll
->entities
, &count
, &total_len
);
4063 total_len
+= sizeof(*header
);
4065 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
4066 if (!header
) return STATUS_NO_MEMORY
;
4068 memset(header
, 0, sizeof(*header
));
4069 header
->magic
= GUIDSECTION_MAGIC
;
4070 header
->size
= sizeof(*header
);
4071 header
->count
= count
;
4072 header
->index_offset
= sizeof(*header
);
4073 index
= (struct guid_index
*)((BYTE
*)header
+ header
->index_offset
);
4074 data_offset
= header
->index_offset
+ count
*sizeof(*index
);
4076 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4078 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4080 add_ifaceps_record(header
, &assembly
->entities
, &index
, &data_offset
, i
+ 1);
4081 for (j
= 0; j
< assembly
->num_dlls
; j
++)
4083 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
4084 add_ifaceps_record(header
, &dll
->entities
, &index
, &data_offset
, i
+ 1);
4090 return STATUS_SUCCESS
;
4093 static inline struct ifacepsredirect_data
*get_ifaceps_data(ACTIVATION_CONTEXT
*actctx
, struct guid_index
*index
)
4095 return (struct ifacepsredirect_data
*)((BYTE
*)actctx
->ifaceps_section
+ index
->data_offset
);
4098 static NTSTATUS
find_cominterface_redirection(ACTIVATION_CONTEXT
* actctx
, const GUID
*guid
, ACTCTX_SECTION_KEYED_DATA
* data
)
4100 struct ifacepsredirect_data
*iface
;
4101 struct guid_index
*index
= NULL
;
4103 if (!(actctx
->sections
& IFACEREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
4105 if (!actctx
->ifaceps_section
)
4107 struct guidsection_header
*section
;
4109 NTSTATUS status
= build_ifaceps_section(actctx
, §ion
);
4110 if (status
) return status
;
4112 if (InterlockedCompareExchangePointer((void**)&actctx
->ifaceps_section
, section
, NULL
))
4113 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
4116 index
= find_guid_index(actctx
->ifaceps_section
, guid
);
4117 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
4119 iface
= get_ifaceps_data(actctx
, index
);
4121 data
->ulDataFormatVersion
= 1;
4122 data
->lpData
= iface
;
4123 data
->ulLength
= iface
->size
+ (iface
->name_len
? iface
->name_len
+ sizeof(WCHAR
) : 0);
4124 data
->lpSectionGlobalData
= NULL
;
4125 data
->ulSectionGlobalDataLength
= 0;
4126 data
->lpSectionBase
= actctx
->ifaceps_section
;
4127 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->ifaceps_section
);
4128 data
->hActCtx
= NULL
;
4130 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
4131 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
4133 return STATUS_SUCCESS
;
4136 static NTSTATUS
build_clr_surrogate_section(ACTIVATION_CONTEXT
* actctx
, struct guidsection_header
**section
)
4138 unsigned int i
, j
, total_len
= 0, count
= 0;
4139 struct guidsection_header
*header
;
4140 struct clrsurrogate_data
*data
;
4141 struct guid_index
*index
;
4144 /* compute section length */
4145 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4147 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4148 for (j
= 0; j
< assembly
->entities
.num
; j
++)
4150 struct entity
*entity
= &assembly
->entities
.base
[j
];
4151 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
)
4155 total_len
+= sizeof(*index
) + sizeof(*data
);
4156 len
= strlenW(entity
->u
.clrsurrogate
.name
) + 1;
4157 if (entity
->u
.clrsurrogate
.version
)
4158 len
+= strlenW(entity
->u
.clrsurrogate
.version
) + 1;
4159 total_len
+= aligned_string_len(len
*sizeof(WCHAR
));
4166 total_len
+= sizeof(*header
);
4168 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
4169 if (!header
) return STATUS_NO_MEMORY
;
4171 memset(header
, 0, sizeof(*header
));
4172 header
->magic
= GUIDSECTION_MAGIC
;
4173 header
->size
= sizeof(*header
);
4174 header
->count
= count
;
4175 header
->index_offset
= sizeof(*header
);
4176 index
= (struct guid_index
*)((BYTE
*)header
+ header
->index_offset
);
4177 data_offset
= header
->index_offset
+ count
*sizeof(*index
);
4179 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4181 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4182 for (j
= 0; j
< assembly
->entities
.num
; j
++)
4184 struct entity
*entity
= &assembly
->entities
.base
[j
];
4185 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
)
4187 ULONG version_len
, name_len
;
4191 if (entity
->u
.clrsurrogate
.version
)
4192 version_len
= strlenW(entity
->u
.clrsurrogate
.version
)*sizeof(WCHAR
);
4195 name_len
= strlenW(entity
->u
.clrsurrogate
.name
)*sizeof(WCHAR
);
4197 /* setup new index entry */
4198 RtlInitUnicodeString(&str
, entity
->u
.clrsurrogate
.clsid
);
4199 RtlGUIDFromString(&str
, &index
->guid
);
4201 index
->data_offset
= data_offset
;
4202 index
->data_len
= sizeof(*data
) + aligned_string_len(name_len
+ sizeof(WCHAR
) + (version_len
? version_len
+ sizeof(WCHAR
) : 0));
4203 index
->rosterindex
= i
+ 1;
4206 data
= (struct clrsurrogate_data
*)((BYTE
*)header
+ index
->data_offset
);
4207 data
->size
= sizeof(*data
);
4209 data
->clsid
= index
->guid
;
4210 data
->version_offset
= version_len
? data
->size
: 0;
4211 data
->version_len
= version_len
;
4212 data
->name_offset
= data
->size
+ version_len
;
4214 data
->name_offset
+= sizeof(WCHAR
);
4215 data
->name_len
= name_len
;
4217 /* surrogate name */
4218 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->name_offset
);
4219 memcpy(ptrW
, entity
->u
.clrsurrogate
.name
, data
->name_len
);
4220 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
4222 /* runtime version */
4223 if (data
->version_len
)
4225 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->version_offset
);
4226 memcpy(ptrW
, entity
->u
.clrsurrogate
.version
, data
->version_len
);
4227 ptrW
[data
->version_len
/sizeof(WCHAR
)] = 0;
4230 data_offset
+= index
->data_offset
;
4238 return STATUS_SUCCESS
;
4241 static inline struct clrsurrogate_data
*get_surrogate_data(ACTIVATION_CONTEXT
*actctx
, const struct guid_index
*index
)
4243 return (struct clrsurrogate_data
*)((BYTE
*)actctx
->clrsurrogate_section
+ index
->data_offset
);
4246 static NTSTATUS
find_clr_surrogate(ACTIVATION_CONTEXT
* actctx
, const GUID
*guid
, ACTCTX_SECTION_KEYED_DATA
* data
)
4248 struct clrsurrogate_data
*surrogate
;
4249 struct guid_index
*index
= NULL
;
4251 if (!(actctx
->sections
& CLRSURROGATES_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
4253 if (!actctx
->clrsurrogate_section
)
4255 struct guidsection_header
*section
;
4257 NTSTATUS status
= build_clr_surrogate_section(actctx
, §ion
);
4258 if (status
) return status
;
4260 if (InterlockedCompareExchangePointer((void**)&actctx
->clrsurrogate_section
, section
, NULL
))
4261 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
4264 index
= find_guid_index(actctx
->clrsurrogate_section
, guid
);
4265 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
4267 surrogate
= get_surrogate_data(actctx
, index
);
4269 data
->ulDataFormatVersion
= 1;
4270 data
->lpData
= surrogate
;
4271 /* full length includes string length with nulls */
4272 data
->ulLength
= surrogate
->size
+ surrogate
->name_len
+ sizeof(WCHAR
);
4273 if (surrogate
->version_len
)
4274 data
->ulLength
+= surrogate
->version_len
+ sizeof(WCHAR
);
4276 data
->lpSectionGlobalData
= NULL
;
4277 data
->ulSectionGlobalDataLength
= 0;
4278 data
->lpSectionBase
= actctx
->clrsurrogate_section
;
4279 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->clrsurrogate_section
);
4280 data
->hActCtx
= NULL
;
4282 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
4283 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
4285 return STATUS_SUCCESS
;
4288 static void get_progid_datalen(struct entity_array
*entities
, unsigned int *count
, unsigned int *total_len
)
4290 unsigned int i
, j
, single_len
;
4292 single_len
= sizeof(struct progidredirect_data
) + sizeof(struct string_index
) + sizeof(GUID
);
4293 for (i
= 0; i
< entities
->num
; i
++)
4295 struct entity
*entity
= &entities
->base
[i
];
4296 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)
4298 if (entity
->u
.comclass
.progid
)
4300 *total_len
+= single_len
+ aligned_string_len((strlenW(entity
->u
.comclass
.progid
)+1)*sizeof(WCHAR
));
4304 for (j
= 0; j
< entity
->u
.comclass
.progids
.num
; j
++)
4305 *total_len
+= aligned_string_len((strlenW(entity
->u
.comclass
.progids
.progids
[j
])+1)*sizeof(WCHAR
));
4307 *total_len
+= single_len
*entity
->u
.comclass
.progids
.num
;
4308 *count
+= entity
->u
.comclass
.progids
.num
;
4313 static void write_progid_record(struct strsection_header
*section
, const WCHAR
*progid
, const GUID
*alias
,
4314 struct string_index
**index
, ULONG
*data_offset
, ULONG
*global_offset
, ULONG rosterindex
)
4316 struct progidredirect_data
*data
;
4321 /* setup new index entry */
4323 /* hash progid name */
4324 RtlInitUnicodeString(&str
, progid
);
4325 RtlHashUnicodeString(&str
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &(*index
)->hash
);
4327 (*index
)->name_offset
= *data_offset
;
4328 (*index
)->name_len
= str
.Length
;
4329 (*index
)->data_offset
= (*index
)->name_offset
+ aligned_string_len(str
.MaximumLength
);
4330 (*index
)->data_len
= sizeof(*data
);
4331 (*index
)->rosterindex
= rosterindex
;
4333 *data_offset
+= aligned_string_len(str
.MaximumLength
);
4335 /* setup data structure */
4336 data
= (struct progidredirect_data
*)((BYTE
*)section
+ *data_offset
);
4337 data
->size
= sizeof(*data
);
4339 data
->clsid_offset
= *global_offset
;
4341 /* write progid string */
4342 ptrW
= (WCHAR
*)((BYTE
*)section
+ (*index
)->name_offset
);
4343 memcpy(ptrW
, progid
, (*index
)->name_len
);
4344 ptrW
[(*index
)->name_len
/sizeof(WCHAR
)] = 0;
4346 /* write guid to global area */
4347 guid_ptr
= (GUID
*)((BYTE
*)section
+ data
->clsid_offset
);
4351 *global_offset
+= sizeof(GUID
);
4352 *data_offset
+= data
->size
;
4356 static void add_progid_record(ACTIVATION_CONTEXT
* actctx
, struct strsection_header
*section
, const struct entity_array
*entities
,
4357 struct string_index
**index
, ULONG
*data_offset
, ULONG
*global_offset
, ULONG rosterindex
)
4361 for (i
= 0; i
< entities
->num
; i
++)
4363 struct entity
*entity
= &entities
->base
[i
];
4364 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)
4366 const struct progids
*progids
= &entity
->u
.comclass
.progids
;
4367 struct comclassredirect_data
*comclass
;
4368 struct guid_index
*guid_index
;
4372 RtlInitUnicodeString(&str
, entity
->u
.comclass
.clsid
);
4373 RtlGUIDFromString(&str
, &clsid
);
4375 guid_index
= find_guid_index(actctx
->comserver_section
, &clsid
);
4376 comclass
= get_comclass_data(actctx
, guid_index
);
4378 if (entity
->u
.comclass
.progid
)
4379 write_progid_record(section
, entity
->u
.comclass
.progid
, &comclass
->alias
,
4380 index
, data_offset
, global_offset
, rosterindex
);
4382 for (j
= 0; j
< progids
->num
; j
++)
4383 write_progid_record(section
, progids
->progids
[j
], &comclass
->alias
,
4384 index
, data_offset
, global_offset
, rosterindex
);
4389 static NTSTATUS
build_progid_section(ACTIVATION_CONTEXT
* actctx
, struct strsection_header
**section
)
4391 unsigned int i
, j
, total_len
= 0, count
= 0;
4392 struct strsection_header
*header
;
4393 ULONG data_offset
, global_offset
;
4394 struct string_index
*index
;
4396 /* compute section length */
4397 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4399 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4401 get_progid_datalen(&assembly
->entities
, &count
, &total_len
);
4402 for (j
= 0; j
< assembly
->num_dlls
; j
++)
4404 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
4405 get_progid_datalen(&dll
->entities
, &count
, &total_len
);
4409 total_len
+= sizeof(*header
);
4411 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
4412 if (!header
) return STATUS_NO_MEMORY
;
4414 memset(header
, 0, sizeof(*header
));
4415 header
->magic
= STRSECTION_MAGIC
;
4416 header
->size
= sizeof(*header
);
4417 header
->count
= count
;
4418 header
->global_offset
= header
->size
;
4419 header
->global_len
= count
*sizeof(GUID
);
4420 header
->index_offset
= header
->size
+ header
->global_len
;
4422 index
= (struct string_index
*)((BYTE
*)header
+ header
->index_offset
);
4423 data_offset
= header
->index_offset
+ count
*sizeof(*index
);
4424 global_offset
= header
->global_offset
;
4426 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4428 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4430 add_progid_record(actctx
, header
, &assembly
->entities
, &index
, &data_offset
, &global_offset
, i
+ 1);
4431 for (j
= 0; j
< assembly
->num_dlls
; j
++)
4433 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
4434 add_progid_record(actctx
, header
, &dll
->entities
, &index
, &data_offset
, &global_offset
, i
+ 1);
4440 return STATUS_SUCCESS
;
4443 static inline struct progidredirect_data
*get_progid_data(ACTIVATION_CONTEXT
*actctx
, const struct string_index
*index
)
4445 return (struct progidredirect_data
*)((BYTE
*)actctx
->progid_section
+ index
->data_offset
);
4448 static NTSTATUS
find_progid_redirection(ACTIVATION_CONTEXT
* actctx
, const UNICODE_STRING
*name
,
4449 PACTCTX_SECTION_KEYED_DATA data
)
4451 struct progidredirect_data
*progid
;
4452 struct string_index
*index
;
4454 if (!(actctx
->sections
& PROGIDREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
4456 if (!actctx
->comserver_section
)
4458 struct guidsection_header
*section
;
4460 NTSTATUS status
= build_comserver_section(actctx
, §ion
);
4461 if (status
) return status
;
4463 if (InterlockedCompareExchangePointer((void**)&actctx
->comserver_section
, section
, NULL
))
4464 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
4467 if (!actctx
->progid_section
)
4469 struct strsection_header
*section
;
4471 NTSTATUS status
= build_progid_section(actctx
, §ion
);
4472 if (status
) return status
;
4474 if (InterlockedCompareExchangePointer((void**)&actctx
->progid_section
, section
, NULL
))
4475 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
4478 index
= find_string_index(actctx
->progid_section
, name
);
4479 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
4481 progid
= get_progid_data(actctx
, index
);
4483 data
->ulDataFormatVersion
= 1;
4484 data
->lpData
= progid
;
4485 data
->ulLength
= progid
->size
;
4486 data
->lpSectionGlobalData
= (BYTE
*)actctx
->progid_section
+ actctx
->progid_section
->global_offset
;
4487 data
->ulSectionGlobalDataLength
= actctx
->progid_section
->global_len
;
4488 data
->lpSectionBase
= actctx
->progid_section
;
4489 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->progid_section
);
4490 data
->hActCtx
= NULL
;
4492 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
4493 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
4495 return STATUS_SUCCESS
;
4498 static NTSTATUS
find_string(ACTIVATION_CONTEXT
* actctx
, ULONG section_kind
,
4499 const UNICODE_STRING
*section_name
,
4500 DWORD flags
, PACTCTX_SECTION_KEYED_DATA data
)
4504 switch (section_kind
)
4506 case ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
:
4507 status
= find_dll_redirection(actctx
, section_name
, data
);
4509 case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
:
4510 status
= find_window_class(actctx
, section_name
, data
);
4512 case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
:
4513 status
= find_progid_redirection(actctx
, section_name
, data
);
4515 case ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE
:
4516 DPRINT1("Unsupported yet section_kind %x\n", section_kind
);
4517 return STATUS_SXS_SECTION_NOT_FOUND
;
4519 DPRINT1("Unknown section_kind %x\n", section_kind
);
4520 return STATUS_SXS_SECTION_NOT_FOUND
;
4523 if (status
!= STATUS_SUCCESS
) return status
;
4525 if (flags
& FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
)
4527 actctx_addref(actctx
);
4528 data
->hActCtx
= actctx
;
4530 return STATUS_SUCCESS
;
4533 static NTSTATUS
find_guid(ACTIVATION_CONTEXT
* actctx
, ULONG section_kind
,
4534 const GUID
*guid
, DWORD flags
, PACTCTX_SECTION_KEYED_DATA data
)
4538 switch (section_kind
)
4540 case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
:
4541 status
= find_tlib_redirection(actctx
, guid
, data
);
4543 case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
:
4544 status
= find_comserver_redirection(actctx
, guid
, data
);
4546 case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
:
4547 status
= find_cominterface_redirection(actctx
, guid
, data
);
4549 case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
:
4550 status
= find_clr_surrogate(actctx
, guid
, data
);
4553 DPRINT("Unknown section_kind %x\n", section_kind
);
4554 return STATUS_SXS_SECTION_NOT_FOUND
;
4557 if (status
!= STATUS_SUCCESS
) return status
;
4559 if (flags
& FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
)
4561 actctx_addref(actctx
);
4562 data
->hActCtx
= actctx
;
4564 return STATUS_SUCCESS
;
4567 /* initialize the activation context for the current process */
4568 void actctx_init(void)
4573 ctx
.cbSize
= sizeof(ctx
);
4574 ctx
.lpSource
= NULL
;
4575 ctx
.dwFlags
= ACTCTX_FLAG_RESOURCE_NAME_VALID
| ACTCTX_FLAG_HMODULE_VALID
;
4576 ctx
.hModule
= NtCurrentTeb()->ProcessEnvironmentBlock
->ImageBaseAddress
;
4577 ctx
.lpResourceName
= (LPCWSTR
)CREATEPROCESS_MANIFEST_RESOURCE_ID
;
4579 if (NT_SUCCESS(RtlCreateActivationContext(0, (PVOID
)&ctx
, 0, NULL
, NULL
, &handle
)))
4581 process_actctx
= check_actctx(handle
);
4585 /* FUNCTIONS ***************************************************************/
4589 RtlCreateActivationContext(IN ULONG Flags
,
4590 IN PACTIVATION_CONTEXT_DATA ActivationContextData
,
4591 IN ULONG ExtraBytes
,
4592 IN PVOID NotificationRoutine
,
4593 IN PVOID NotificationContext
,
4594 OUT PACTIVATION_CONTEXT
*ActCtx
)
4596 const ACTCTXW
*pActCtx
= (PVOID
)ActivationContextData
;
4597 const WCHAR
*directory
= NULL
;
4598 PACTIVATION_CONTEXT_WRAPPED ActualActCtx
;
4599 ACTIVATION_CONTEXT
*actctx
;
4600 UNICODE_STRING nameW
;
4602 NTSTATUS status
= STATUS_NO_MEMORY
;
4604 struct actctx_loader acl
;
4606 DPRINT("%p %08x\n", pActCtx
, pActCtx
? pActCtx
->dwFlags
: 0);
4608 if (!pActCtx
|| pActCtx
->cbSize
< sizeof(*pActCtx
) ||
4609 (pActCtx
->dwFlags
& ~ACTCTX_FLAGS_ALL
))
4610 return STATUS_INVALID_PARAMETER
;
4613 if (!(ActualActCtx
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ActualActCtx
))))
4614 return STATUS_NO_MEMORY
;
4616 ActualActCtx
->MagicMarker
= ACTCTX_MAGIC_MARKER
;
4618 actctx
= &ActualActCtx
->ActivationContext
;
4619 actctx
->RefCount
= 1;
4620 actctx
->config
.type
= ACTIVATION_CONTEXT_PATH_TYPE_NONE
;
4621 actctx
->config
.info
= NULL
;
4622 actctx
->appdir
.type
= ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
;
4623 if (pActCtx
->dwFlags
& ACTCTX_FLAG_APPLICATION_NAME_VALID
)
4625 if (!(actctx
->appdir
.info
= strdupW( pActCtx
->lpApplicationName
))) goto error
;
4633 if (pActCtx
->dwFlags
& ACTCTX_FLAG_HMODULE_VALID
) module
= pActCtx
->hModule
;
4634 else module
= NtCurrentTeb()->ProcessEnvironmentBlock
->ImageBaseAddress
;
4636 status
= get_module_filename(module
, &dir
, 0);
4637 if (!NT_SUCCESS(status
)) goto error
;
4638 if ((p
= strrchrW( dir
.Buffer
, '\\' ))) p
[1] = 0;
4639 actctx
->appdir
.info
= dir
.Buffer
;
4642 nameW
.Buffer
= NULL
;
4644 /* open file only if it's going to be used */
4645 if (pActCtx
->lpSource
&& !((pActCtx
->dwFlags
& ACTCTX_FLAG_RESOURCE_NAME_VALID
) &&
4646 (pActCtx
->dwFlags
& ACTCTX_FLAG_HMODULE_VALID
)))
4648 if (!RtlDosPathNameToNtPathName_U(pActCtx
->lpSource
, &nameW
, NULL
, NULL
))
4650 status
= STATUS_NO_SUCH_FILE
;
4653 status
= open_nt_file( &file
, &nameW
);
4654 if (!NT_SUCCESS(status
))
4656 RtlFreeUnicodeString( &nameW
);
4661 acl
.actctx
= actctx
;
4662 acl
.dependencies
= NULL
;
4663 acl
.num_dependencies
= 0;
4664 acl
.allocated_dependencies
= 0;
4666 if (pActCtx
->dwFlags
& ACTCTX_FLAG_LANGID_VALID
) lang
= pActCtx
->wLangId
;
4667 if (pActCtx
->dwFlags
& ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID
) directory
= pActCtx
->lpAssemblyDirectory
;
4669 if (pActCtx
->dwFlags
& ACTCTX_FLAG_RESOURCE_NAME_VALID
)
4671 /* if we have a resource it's a PE file */
4672 if (pActCtx
->dwFlags
& ACTCTX_FLAG_HMODULE_VALID
)
4674 status
= get_manifest_in_module( &acl
, NULL
, NULL
, directory
, FALSE
, pActCtx
->hModule
,
4675 pActCtx
->lpResourceName
, lang
);
4676 if (status
&& status
!= STATUS_SXS_CANT_GEN_ACTCTX
)
4677 /* FIXME: what to do if pActCtx->lpSource is set */
4678 status
= get_manifest_in_associated_manifest( &acl
, NULL
, NULL
, directory
,
4679 pActCtx
->hModule
, pActCtx
->lpResourceName
);
4681 else if (pActCtx
->lpSource
)
4683 status
= get_manifest_in_pe_file( &acl
, NULL
, nameW
.Buffer
, directory
, FALSE
,
4684 file
, pActCtx
->lpResourceName
, lang
);
4685 if (status
&& status
!= STATUS_SXS_CANT_GEN_ACTCTX
)
4686 status
= get_manifest_in_associated_manifest( &acl
, NULL
, nameW
.Buffer
, directory
,
4687 NULL
, pActCtx
->lpResourceName
);
4689 else status
= STATUS_INVALID_PARAMETER
;
4693 status
= get_manifest_in_manifest_file( &acl
, NULL
, nameW
.Buffer
, directory
, FALSE
, file
);
4696 if (file
) NtClose( file
);
4697 RtlFreeUnicodeString( &nameW
);
4699 if (NT_SUCCESS(status
)) status
= parse_depend_manifests(&acl
);
4700 free_depend_manifests( &acl
);
4702 if (NT_SUCCESS(status
))
4704 else actctx_release( actctx
);
4708 if (file
) NtClose( file
);
4709 actctx_release( actctx
);
4714 #define ACT_CTX_VALID(p) ((((ULONG_PTR)p - 1) | 7) != -1)
4718 RtlAddRefActivationContext(IN PACTIVATION_CONTEXT Handle
)
4720 PIACTIVATION_CONTEXT ActCtx
= (PIACTIVATION_CONTEXT
)Handle
;
4721 LONG OldRefCount
, NewRefCount
;
4723 if ((ActCtx
) && (ACT_CTX_VALID(ActCtx
)) && (ActCtx
->RefCount
!= LONG_MAX
))
4725 RtlpValidateActCtx(ActCtx
);
4729 OldRefCount
= ActCtx
->RefCount
;
4730 ASSERT(OldRefCount
> 0);
4732 if (OldRefCount
== LONG_MAX
) break;
4734 NewRefCount
= OldRefCount
+ 1;
4735 if (InterlockedCompareExchange(&ActCtx
->RefCount
,
4737 OldRefCount
) == OldRefCount
)
4743 NewRefCount
= LONG_MAX
;
4744 ASSERT(NewRefCount
> 0);
4750 RtlReleaseActivationContext( HANDLE handle
)
4752 PIACTIVATION_CONTEXT ActCtx
= (PIACTIVATION_CONTEXT
) Handle
;
4754 if ((ActCtx
) && (ACT_CTX_VALID(ActCtx
)) && (ActCtx
->RefCount
!= LONG_MAX
))
4756 RtlpValidateActCtx(ActCtx
);
4758 actctx_release(ActCtx
);
4764 RtlAddRefActivationContext( HANDLE handle
)
4766 ACTIVATION_CONTEXT
*actctx
;
4768 if ((actctx
= check_actctx(handle
))) actctx_addref(actctx
);
4773 RtlReleaseActivationContext( HANDLE handle
)
4775 ACTIVATION_CONTEXT
*actctx
;
4777 if ((actctx
= check_actctx(handle
))) actctx_release(actctx
);
4782 NTAPI
RtlActivateActivationContextEx( ULONG flags
, PTEB tebAddress
, HANDLE handle
, PULONG_PTR cookie
)
4784 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
;
4786 if (!(frame
= RtlAllocateHeap( RtlGetProcessHeap(), 0, sizeof(*frame
) )))
4787 return STATUS_NO_MEMORY
;
4789 frame
->Previous
= tebAddress
->ActivationContextStackPointer
->ActiveFrame
;
4790 frame
->ActivationContext
= handle
;
4793 tebAddress
->ActivationContextStackPointer
->ActiveFrame
= frame
;
4794 RtlAddRefActivationContext( handle
);
4796 *cookie
= (ULONG_PTR
)frame
;
4797 DPRINT( "%p cookie=%lx\n", handle
, *cookie
);
4798 return STATUS_SUCCESS
;
4803 NTAPI
RtlActivateActivationContext( ULONG flags
, HANDLE handle
, PULONG_PTR cookie
)
4805 return RtlActivateActivationContextEx(flags
, NtCurrentTeb(), handle
, cookie
);
4810 RtlDeactivateActivationContext( ULONG flags
, ULONG_PTR cookie
)
4812 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
, *top
;
4814 DPRINT( "%x cookie=%lx\n", flags
, cookie
);
4816 /* find the right frame */
4817 top
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
;
4818 for (frame
= top
; frame
; frame
= frame
->Previous
)
4819 if ((ULONG_PTR
)frame
== cookie
) break;
4822 RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION
);
4824 if (frame
!= top
&& !(flags
& RTL_DEACTIVATE_ACTIVATION_CONTEXT_FLAG_FORCE_EARLY_DEACTIVATION
))
4825 RtlRaiseStatus( STATUS_SXS_EARLY_DEACTIVATION
);
4827 /* pop everything up to and including frame */
4828 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= frame
->Previous
;
4830 while (top
!= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
4832 frame
= top
->Previous
;
4833 RtlReleaseActivationContext( top
->ActivationContext
);
4834 RtlFreeHeap( RtlGetProcessHeap(), 0, top
);
4838 return STATUS_SUCCESS
;
4843 RtlFreeActivationContextStack(IN PACTIVATION_CONTEXT_STACK Stack
)
4845 PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame
, PrevFrame
;
4847 /* Nothing to do if there is no stack */
4850 /* Get the current active frame */
4851 ActiveFrame
= Stack
->ActiveFrame
;
4853 /* Go through them in backwards order and release */
4856 PrevFrame
= ActiveFrame
->Previous
;
4857 RtlReleaseActivationContext(ActiveFrame
->ActivationContext
);
4858 RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveFrame
);
4859 ActiveFrame
= PrevFrame
;
4862 /* Zero out the active frame */
4863 Stack
->ActiveFrame
= NULL
;
4865 /* TODO: Empty the Frame List Cache */
4866 ASSERT(IsListEmpty(&Stack
->FrameListCache
));
4868 /* Free activation stack memory */
4869 RtlFreeHeap(RtlGetProcessHeap(), 0, Stack
);
4873 NTAPI
RtlFreeThreadActivationContextStack(VOID
)
4875 RtlFreeActivationContextStack(NtCurrentTeb()->ActivationContextStackPointer
);
4876 NtCurrentTeb()->ActivationContextStackPointer
= NULL
;
4881 NTAPI
RtlGetActiveActivationContext( HANDLE
*handle
)
4883 if (NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
4885 *handle
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
->ActivationContext
;
4886 RtlAddRefActivationContext( *handle
);
4891 return STATUS_SUCCESS
;
4896 NTAPI
RtlIsActivationContextActive( HANDLE handle
)
4898 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
;
4900 for (frame
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
; frame
; frame
= frame
->Previous
)
4901 if (frame
->ActivationContext
== handle
) return TRUE
;
4907 RtlQueryInformationActivationContext( ULONG flags
, HANDLE handle
, PVOID subinst
,
4908 ULONG
class, PVOID buffer
,
4909 SIZE_T bufsize
, SIZE_T
*retlen
)
4911 ACTIVATION_CONTEXT
*actctx
;
4914 DPRINT("%08x %p %p %u %p %Iu %p\n", flags
, handle
,
4915 subinst
, class, buffer
, bufsize
, retlen
);
4917 if (retlen
) *retlen
= 0;
4918 if ((status
= find_query_actctx( &handle
, flags
, class ))) return status
;
4922 case ActivationContextBasicInformation
:
4924 ACTIVATION_CONTEXT_BASIC_INFORMATION
*info
= buffer
;
4926 if (retlen
) *retlen
= sizeof(*info
);
4927 if (!info
|| bufsize
< sizeof(*info
)) return STATUS_BUFFER_TOO_SMALL
;
4929 info
->hActCtx
= handle
;
4930 info
->dwFlags
= 0; /* FIXME */
4931 if (!(flags
& RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF
)) RtlAddRefActivationContext(handle
);
4935 case ActivationContextDetailedInformation
:
4937 ACTIVATION_CONTEXT_DETAILED_INFORMATION
*acdi
= buffer
;
4938 struct assembly
*assembly
= NULL
;
4939 SIZE_T len
, manifest_len
= 0, config_len
= 0, appdir_len
= 0;
4942 if (!(actctx
= check_actctx(handle
))) return STATUS_INVALID_PARAMETER
;
4944 if (actctx
->num_assemblies
) assembly
= actctx
->assemblies
;
4946 if (assembly
&& assembly
->manifest
.info
)
4947 manifest_len
= strlenW(assembly
->manifest
.info
) + 1;
4948 if (actctx
->config
.info
) config_len
= strlenW(actctx
->config
.info
) + 1;
4949 if (actctx
->appdir
.info
) appdir_len
= strlenW(actctx
->appdir
.info
) + 1;
4950 len
= sizeof(*acdi
) + (manifest_len
+ config_len
+ appdir_len
) * sizeof(WCHAR
);
4952 if (retlen
) *retlen
= len
;
4953 if (!buffer
|| bufsize
< len
) return STATUS_BUFFER_TOO_SMALL
;
4956 acdi
->ulFormatVersion
= assembly
? 1 : 0; /* FIXME */
4957 acdi
->ulAssemblyCount
= actctx
->num_assemblies
;
4958 acdi
->ulRootManifestPathType
= assembly
? assembly
->manifest
.type
: 0 /* FIXME */;
4959 acdi
->ulRootManifestPathChars
= assembly
&& assembly
->manifest
.info
? (DWORD
)manifest_len
- 1 : 0;
4960 acdi
->ulRootConfigurationPathType
= actctx
->config
.type
;
4961 acdi
->ulRootConfigurationPathChars
= actctx
->config
.info
? (DWORD
)config_len
- 1 : 0;
4962 acdi
->ulAppDirPathType
= actctx
->appdir
.type
;
4963 acdi
->ulAppDirPathChars
= actctx
->appdir
.info
? (DWORD
)appdir_len
- 1 : 0;
4964 ptr
= (LPWSTR
)(acdi
+ 1);
4967 acdi
->lpRootManifestPath
= ptr
;
4968 memcpy(ptr
, assembly
->manifest
.info
, manifest_len
* sizeof(WCHAR
));
4969 ptr
+= manifest_len
;
4971 else acdi
->lpRootManifestPath
= NULL
;
4974 acdi
->lpRootConfigurationPath
= ptr
;
4975 memcpy(ptr
, actctx
->config
.info
, config_len
* sizeof(WCHAR
));
4978 else acdi
->lpRootConfigurationPath
= NULL
;
4981 acdi
->lpAppDirPath
= ptr
;
4982 memcpy(ptr
, actctx
->appdir
.info
, appdir_len
* sizeof(WCHAR
));
4984 else acdi
->lpAppDirPath
= NULL
;
4988 case AssemblyDetailedInformationInActivationContext
:
4990 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION
*afdi
= buffer
;
4991 struct assembly
*assembly
;
4994 SIZE_T len
, id_len
= 0, ad_len
= 0, path_len
= 0;
4997 if (!(actctx
= check_actctx(handle
))) return STATUS_INVALID_PARAMETER
;
4998 if (!subinst
) return STATUS_INVALID_PARAMETER
;
5000 index
= *(DWORD
*)subinst
;
5001 if (!index
|| index
> actctx
->num_assemblies
) return STATUS_INVALID_PARAMETER
;
5003 assembly
= &actctx
->assemblies
[index
- 1];
5005 if (!(assembly_id
= build_assembly_id( &assembly
->id
))) return STATUS_NO_MEMORY
;
5006 id_len
= strlenW(assembly_id
) + 1;
5007 if (assembly
->directory
) ad_len
= strlenW(assembly
->directory
) + 1;
5009 if (assembly
->manifest
.info
&&
5010 (assembly
->type
== ASSEMBLY_MANIFEST
|| assembly
->type
== ASSEMBLY_SHARED_MANIFEST
))
5011 path_len
= strlenW(assembly
->manifest
.info
) + 1;
5013 len
= sizeof(*afdi
) + (id_len
+ ad_len
+ path_len
) * sizeof(WCHAR
);
5015 if (retlen
) *retlen
= len
;
5016 if (!buffer
|| bufsize
< len
)
5018 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id
);
5019 return STATUS_BUFFER_TOO_SMALL
;
5022 afdi
->ulFlags
= 0; /* FIXME */
5023 afdi
->ulEncodedAssemblyIdentityLength
= (DWORD
)(id_len
- 1) * sizeof(WCHAR
);
5024 afdi
->ulManifestPathType
= assembly
->manifest
.type
;
5025 afdi
->ulManifestPathLength
= assembly
->manifest
.info
? (DWORD
)(path_len
- 1) * sizeof(WCHAR
) : 0;
5026 /* FIXME afdi->liManifestLastWriteTime = 0; */
5027 afdi
->ulPolicyPathType
= ACTIVATION_CONTEXT_PATH_TYPE_NONE
; /* FIXME */
5028 afdi
->ulPolicyPathLength
= 0;
5029 /* FIXME afdi->liPolicyLastWriteTime = 0; */
5030 afdi
->ulMetadataSatelliteRosterIndex
= 0; /* FIXME */
5031 afdi
->ulManifestVersionMajor
= 1;
5032 afdi
->ulManifestVersionMinor
= 0;
5033 afdi
->ulPolicyVersionMajor
= 0; /* FIXME */
5034 afdi
->ulPolicyVersionMinor
= 0; /* FIXME */
5035 afdi
->ulAssemblyDirectoryNameLength
= ad_len
? (DWORD
)(ad_len
- 1) * sizeof(WCHAR
) : 0;
5036 ptr
= (LPWSTR
)(afdi
+ 1);
5037 afdi
->lpAssemblyEncodedAssemblyIdentity
= ptr
;
5038 memcpy( ptr
, assembly_id
, id_len
* sizeof(WCHAR
) );
5042 afdi
->lpAssemblyManifestPath
= ptr
;
5043 memcpy(ptr
, assembly
->manifest
.info
, path_len
* sizeof(WCHAR
));
5045 } else afdi
->lpAssemblyManifestPath
= NULL
;
5046 afdi
->lpAssemblyPolicyPath
= NULL
; /* FIXME */
5049 afdi
->lpAssemblyDirectoryName
= ptr
;
5050 memcpy(ptr
, assembly
->directory
, ad_len
* sizeof(WCHAR
));
5052 else afdi
->lpAssemblyDirectoryName
= NULL
;
5053 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id
);
5057 case FileInformationInAssemblyOfAssemblyInActivationContext
:
5059 const ACTIVATION_CONTEXT_QUERY_INDEX
*acqi
= subinst
;
5060 ASSEMBLY_FILE_DETAILED_INFORMATION
*afdi
= buffer
;
5061 struct assembly
*assembly
;
5062 struct dll_redirect
*dll
;
5063 SIZE_T len
, dll_len
= 0;
5066 if (!(actctx
= check_actctx(handle
))) return STATUS_INVALID_PARAMETER
;
5067 if (!acqi
) return STATUS_INVALID_PARAMETER
;
5069 if (acqi
->ulAssemblyIndex
>= actctx
->num_assemblies
)
5070 return STATUS_INVALID_PARAMETER
;
5071 assembly
= &actctx
->assemblies
[acqi
->ulAssemblyIndex
];
5073 if (acqi
->ulFileIndexInAssembly
>= assembly
->num_dlls
)
5074 return STATUS_INVALID_PARAMETER
;
5075 dll
= &assembly
->dlls
[acqi
->ulFileIndexInAssembly
];
5077 if (dll
->name
) dll_len
= strlenW(dll
->name
) + 1;
5078 len
= sizeof(*afdi
) + dll_len
* sizeof(WCHAR
);
5080 if (!buffer
|| bufsize
< len
)
5082 if (retlen
) *retlen
= len
;
5083 return STATUS_BUFFER_TOO_SMALL
;
5085 if (retlen
) *retlen
= 0; /* yes that's what native does !! */
5086 afdi
->ulFlags
= ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
;
5087 afdi
->ulFilenameLength
= dll_len
? (DWORD
)(dll_len
- 1) * sizeof(WCHAR
) : 0;
5088 afdi
->ulPathLength
= 0; /* FIXME */
5089 ptr
= (LPWSTR
)(afdi
+ 1);
5092 afdi
->lpFileName
= ptr
;
5093 memcpy( ptr
, dll
->name
, dll_len
* sizeof(WCHAR
) );
5094 } else afdi
->lpFileName
= NULL
;
5095 afdi
->lpFilePath
= NULL
; /* FIXME */
5100 DPRINT( "class %u not implemented\n", class );
5101 return STATUS_NOT_IMPLEMENTED
;
5103 return STATUS_SUCCESS
;
5108 RtlQueryInformationActiveActivationContext(ULONG ulInfoClass
,
5110 SIZE_T cbBuffer OPTIONAL
,
5111 SIZE_T
*pcbWrittenOrRequired OPTIONAL
)
5113 return RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT
,
5119 pcbWrittenOrRequired
);
5122 #define FIND_ACTCTX_RETURN_FLAGS 0x00000002
5123 #define FIND_ACTCTX_RETURN_ASSEMBLY_METADATA 0x00000004
5124 #define FIND_ACTCTX_VALID_MASK (FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX | FIND_ACTCTX_RETURN_FLAGS | FIND_ACTCTX_RETURN_ASSEMBLY_METADATA)
5128 RtlpFindActivationContextSection_CheckParameters( ULONG flags
, const GUID
*guid
, ULONG section_kind
,
5129 const UNICODE_STRING
*section_name
, PACTCTX_SECTION_KEYED_DATA data
)
5131 /* Check general parameter combinations */
5132 if (!section_name
|| !section_name
->Buffer
||
5133 (flags
& ~FIND_ACTCTX_VALID_MASK
) ||
5134 ((flags
& FIND_ACTCTX_VALID_MASK
) && !data
) ||
5135 (data
&& data
->cbSize
< offsetof(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
)))
5137 DPRINT1("invalid parameter\n");
5138 return STATUS_INVALID_PARAMETER
;
5142 if (flags
& FIND_ACTCTX_RETURN_FLAGS
||
5143 flags
& FIND_ACTCTX_RETURN_ASSEMBLY_METADATA
)
5145 DPRINT1("unknown flags %08x\n", flags
);
5146 return STATUS_INVALID_PARAMETER
;
5149 return STATUS_SUCCESS
;
5154 RtlFindActivationContextSectionString( ULONG flags
, const GUID
*guid
, ULONG section_kind
,
5155 const UNICODE_STRING
*section_name
, PVOID ptr
)
5157 PACTCTX_SECTION_KEYED_DATA data
= ptr
;
5160 status
= RtlpFindActivationContextSection_CheckParameters(flags
, guid
, section_kind
, section_name
, data
);
5161 if (!NT_SUCCESS(status
)) return status
;
5163 status
= STATUS_SXS_KEY_NOT_FOUND
;
5165 /* if there is no data, but params are valid,
5166 we return that sxs key is not found to be at least somehow compatible */
5167 if (!data
) return status
;
5169 ASSERT(NtCurrentTeb());
5170 ASSERT(NtCurrentTeb()->ActivationContextStackPointer
);
5172 if (NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
5174 ACTIVATION_CONTEXT
*actctx
= check_actctx(NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
->ActivationContext
);
5175 if (actctx
) status
= find_string( actctx
, section_kind
, section_name
, flags
, data
);
5178 if (status
!= STATUS_SUCCESS
)
5179 status
= find_string( process_actctx
, section_kind
, section_name
, flags
, data
);
5184 NTSTATUS WINAPI
RtlFindActivationContextSectionGuid( ULONG flags
, const GUID
*extguid
, ULONG section_kind
,
5185 const GUID
*guid
, void *ptr
)
5187 ACTCTX_SECTION_KEYED_DATA
*data
= ptr
;
5188 NTSTATUS status
= STATUS_SXS_KEY_NOT_FOUND
;
5192 DPRINT1("expected extguid == NULL\n");
5193 return STATUS_INVALID_PARAMETER
;
5196 if (flags
& ~FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
)
5198 DPRINT1("unknown flags %08x\n", flags
);
5199 return STATUS_INVALID_PARAMETER
;
5202 if (!data
|| data
->cbSize
< FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) || !guid
)
5203 return STATUS_INVALID_PARAMETER
;
5205 if (NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
5207 ACTIVATION_CONTEXT
*actctx
= check_actctx(NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
->ActivationContext
);
5208 if (actctx
) status
= find_guid( actctx
, section_kind
, guid
, flags
, data
);
5211 if (status
!= STATUS_SUCCESS
)
5212 status
= find_guid( process_actctx
, section_kind
, guid
, flags
, data
);
5221 RtlAllocateActivationContextStack(IN PACTIVATION_CONTEXT_STACK
*Stack
)
5223 PACTIVATION_CONTEXT_STACK ContextStack
;
5225 /* Check if it's already allocated */
5226 if (*Stack
) return STATUS_SUCCESS
;
5228 /* Allocate space for the context stack */
5229 ContextStack
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ACTIVATION_CONTEXT_STACK
));
5232 return STATUS_NO_MEMORY
;
5235 /* Initialize the context stack */
5236 ContextStack
->Flags
= 0;
5237 ContextStack
->ActiveFrame
= NULL
;
5238 InitializeListHead(&ContextStack
->FrameListCache
);
5239 ContextStack
->NextCookieSequenceNumber
= 1;
5240 ContextStack
->StackId
= 1; //TODO: Timer-based
5242 *Stack
= ContextStack
;
5244 return STATUS_SUCCESS
;
5247 PRTL_ACTIVATION_CONTEXT_STACK_FRAME
5249 RtlActivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame
,
5252 #if NEW_NTDLL_LOADER
5253 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*ActiveFrame
;
5255 /* Get the curren active frame */
5256 ActiveFrame
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
;
5258 DPRINT1("ActiveFrame %p, &Frame->Frame %p, Context %p\n", ActiveFrame
, &Frame
->Frame
, Context
);
5260 /* Actually activate it */
5261 Frame
->Frame
.Previous
= ActiveFrame
;
5262 Frame
->Frame
.ActivationContext
= Context
;
5263 Frame
->Frame
.Flags
= 0;
5265 /* Check if we can activate this context */
5266 if ((ActiveFrame
&& (ActiveFrame
->ActivationContext
!= Context
)) ||
5269 /* Set new active frame */
5270 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= &Frame
->Frame
;
5271 return &Frame
->Frame
;
5274 /* We can get here only one way: it was already activated */
5275 DPRINT1("Trying to activate improper activation context\n");
5277 /* Activate only if we are allowing multiple activation */
5278 if (!RtlpNotAllowingMultipleActivation
)
5280 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= &Frame
->Frame
;
5285 Frame
->Frame
.Flags
= 0x30;
5288 /* Return pointer to the activation frame */
5289 return &Frame
->Frame
;
5292 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
= &Frame
->Frame
;
5294 frame
->Previous
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
;
5295 frame
->ActivationContext
= Context
;
5298 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= frame
;
5300 return STATUS_SUCCESS
;
5304 PRTL_ACTIVATION_CONTEXT_STACK_FRAME
5306 RtlDeactivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame
)
5308 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
;
5309 //RTL_ACTIVATION_CONTEXT_STACK_FRAME *top;
5311 /* find the right frame */
5312 //top = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
5313 frame
= &Frame
->Frame
;
5317 DPRINT1("No top frame!\n");
5318 RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION
);
5321 /* pop everything up to and including frame */
5322 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= frame
->Previous
;
5330 RtlZombifyActivationContext(PVOID Context
)
5334 if (Context
== ACTCTX_FAKE_HANDLE
)
5335 return STATUS_SUCCESS
;
5337 return STATUS_NOT_IMPLEMENTED
;