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 asmv2hashW
[] = {'a','s','m','v','2',':','h','a','s','h',0};
586 static const WCHAR noInheritW
[] = {'n','o','I','n','h','e','r','i','t',0};
587 static const WCHAR noInheritableW
[] = {'n','o','I','n','h','e','r','i','t','a','b','l','e',0};
588 static const WCHAR typelibW
[] = {'t','y','p','e','l','i','b',0};
589 static const WCHAR windowClassW
[] = {'w','i','n','d','o','w','C','l','a','s','s',0};
591 static const WCHAR clsidW
[] = {'c','l','s','i','d',0};
592 static const WCHAR hashW
[] = {'h','a','s','h',0};
593 static const WCHAR hashalgW
[] = {'h','a','s','h','a','l','g',0};
594 static const WCHAR helpdirW
[] = {'h','e','l','p','d','i','r',0};
595 static const WCHAR iidW
[] = {'i','i','d',0};
596 static const WCHAR languageW
[] = {'l','a','n','g','u','a','g','e',0};
597 static const WCHAR manifestVersionW
[] = {'m','a','n','i','f','e','s','t','V','e','r','s','i','o','n',0};
598 static const WCHAR g_nameW
[] = {'n','a','m','e',0};
599 static const WCHAR neutralW
[] = {'n','e','u','t','r','a','l',0};
600 static const WCHAR newVersionW
[] = {'n','e','w','V','e','r','s','i','o','n',0};
601 static const WCHAR oldVersionW
[] = {'o','l','d','V','e','r','s','i','o','n',0};
602 static const WCHAR optionalW
[] = {'o','p','t','i','o','n','a','l',0};
603 static const WCHAR processorArchitectureW
[] = {'p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e',0};
604 static const WCHAR progidW
[] = {'p','r','o','g','i','d',0};
605 static const WCHAR publicKeyTokenW
[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
606 static const WCHAR threadingmodelW
[] = {'t','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
607 static const WCHAR tlbidW
[] = {'t','l','b','i','d',0};
608 static const WCHAR typeW
[] = {'t','y','p','e',0};
609 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
610 static const WCHAR xmlnsW
[] = {'x','m','l','n','s',0};
611 static const WCHAR versionedW
[] = {'v','e','r','s','i','o','n','e','d',0};
612 static const WCHAR yesW
[] = {'y','e','s',0};
613 static const WCHAR noW
[] = {'n','o',0};
614 static const WCHAR restrictedW
[] = {'R','E','S','T','R','I','C','T','E','D',0};
615 static const WCHAR controlW
[] = {'C','O','N','T','R','O','L',0};
616 static const WCHAR hiddenW
[] = {'H','I','D','D','E','N',0};
617 static const WCHAR hasdiskimageW
[] = {'H','A','S','D','I','S','K','I','M','A','G','E',0};
618 static const WCHAR flagsW
[] = {'f','l','a','g','s',0};
619 static const WCHAR miscstatusW
[] = {'m','i','s','c','S','t','a','t','u','s',0};
620 static const WCHAR miscstatusiconW
[] = {'m','i','s','c','S','t','a','t','u','s','I','c','o','n',0};
621 static const WCHAR miscstatuscontentW
[] = {'m','i','s','c','S','t','a','t','u','s','C','o','n','t','e','n','t',0};
622 static const WCHAR miscstatusthumbnailW
[] = {'m','i','s','c','S','t','a','t','u','s','T','h','u','m','b','n','a','i','l',0};
623 static const WCHAR miscstatusdocprintW
[] = {'m','i','s','c','S','t','a','t','u','s','D','o','c','P','r','i','n','t',0};
624 static const WCHAR baseInterfaceW
[] = {'b','a','s','e','I','n','t','e','r','f','a','c','e',0};
625 static const WCHAR nummethodsW
[] = {'n','u','m','M','e','t','h','o','d','s',0};
626 static const WCHAR proxyStubClsid32W
[] = {'p','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
627 static const WCHAR runtimeVersionW
[] = {'r','u','n','t','i','m','e','V','e','r','s','i','o','n',0};
628 static const WCHAR mscoreeW
[] = {'M','S','C','O','R','E','E','.','D','L','L',0};
629 static const WCHAR mscoree2W
[] = {'m','s','c','o','r','e','e','.','d','l','l',0};
631 static const WCHAR activatewhenvisibleW
[] = {'a','c','t','i','v','a','t','e','w','h','e','n','v','i','s','i','b','l','e',0};
632 static const WCHAR actslikebuttonW
[] = {'a','c','t','s','l','i','k','e','b','u','t','t','o','n',0};
633 static const WCHAR actslikelabelW
[] = {'a','c','t','s','l','i','k','e','l','a','b','e','l',0};
634 static const WCHAR alignableW
[] = {'a','l','i','g','n','a','b','l','e',0};
635 static const WCHAR alwaysrunW
[] = {'a','l','w','a','y','s','r','u','n',0};
636 static const WCHAR canlinkbyole1W
[] = {'c','a','n','l','i','n','k','b','y','o','l','e','1',0};
637 static const WCHAR cantlinkinsideW
[] = {'c','a','n','t','l','i','n','k','i','n','s','i','d','e',0};
638 static const WCHAR ignoreactivatewhenvisibleW
[] = {'i','g','n','o','r','e','a','c','t','i','v','a','t','e','w','h','e','n','v','i','s','i','b','l','e',0};
639 static const WCHAR imemodeW
[] = {'i','m','e','m','o','d','e',0};
640 static const WCHAR insertnotreplaceW
[] = {'i','n','s','e','r','t','n','o','t','r','e','p','l','a','c','e',0};
641 static const WCHAR insideoutW
[] = {'i','n','s','i','d','e','o','u','t',0};
642 static const WCHAR invisibleatruntimeW
[] = {'i','n','v','i','s','i','b','l','e','a','t','r','u','n','t','i','m','e',0};
643 static const WCHAR islinkobjectW
[] = {'i','s','l','i','n','k','o','b','j','e','c','t',0};
644 static const WCHAR nouiactivateW
[] = {'n','o','u','i','a','c','t','i','v','a','t','e',0};
645 static const WCHAR onlyiconicW
[] = {'o','n','l','y','i','c','o','n','i','c',0};
646 static const WCHAR recomposeonresizeW
[] = {'r','e','c','o','m','p','o','s','e','o','n','r','e','s','i','z','e',0};
647 static const WCHAR renderingisdeviceindependentW
[] = {'r','e','n','d','e','r','i','n','g','i','s','d','e','v','i','c','e','i','n','d','e','p','e','n','d','e','n','t',0};
648 static const WCHAR setclientsitefirstW
[] = {'s','e','t','c','l','i','e','n','t','s','i','t','e','f','i','r','s','t',0};
649 static const WCHAR simpleframeW
[] = {'s','i','m','p','l','e','f','r','a','m','e',0};
650 static const WCHAR staticW
[] = {'s','t','a','t','i','c',0};
651 static const WCHAR supportsmultilevelundoW
[] = {'s','u','p','p','o','r','t','s','m','u','l','t','i','l','e','v','e','l','u','n','d','o',0};
652 static const WCHAR wantstomenumergeW
[] = {'w','a','n','t','s','t','o','m','e','n','u','m','e','r','g','e',0};
660 static const struct olemisc_entry olemisc_values
[] =
662 { activatewhenvisibleW
, OLEMISC_ACTIVATEWHENVISIBLE
},
663 { actslikebuttonW
, OLEMISC_ACTSLIKEBUTTON
},
664 { actslikelabelW
, OLEMISC_ACTSLIKELABEL
},
665 { alignableW
, OLEMISC_ALIGNABLE
},
666 { alwaysrunW
, OLEMISC_ALWAYSRUN
},
667 { canlinkbyole1W
, OLEMISC_CANLINKBYOLE1
},
668 { cantlinkinsideW
, OLEMISC_CANTLINKINSIDE
},
669 { ignoreactivatewhenvisibleW
, OLEMISC_IGNOREACTIVATEWHENVISIBLE
},
670 { imemodeW
, OLEMISC_IMEMODE
},
671 { insertnotreplaceW
, OLEMISC_INSERTNOTREPLACE
},
672 { insideoutW
, OLEMISC_INSIDEOUT
},
673 { invisibleatruntimeW
, OLEMISC_INVISIBLEATRUNTIME
},
674 { islinkobjectW
, OLEMISC_ISLINKOBJECT
},
675 { nouiactivateW
, OLEMISC_NOUIACTIVATE
},
676 { onlyiconicW
, OLEMISC_ONLYICONIC
},
677 { recomposeonresizeW
, OLEMISC_RECOMPOSEONRESIZE
},
678 { renderingisdeviceindependentW
, OLEMISC_RENDERINGISDEVICEINDEPENDENT
},
679 { setclientsitefirstW
, OLEMISC_SETCLIENTSITEFIRST
},
680 { simpleframeW
, OLEMISC_SIMPLEFRAME
},
681 { staticW
, OLEMISC_STATIC
},
682 { supportsmultilevelundoW
, OLEMISC_SUPPORTSMULTILEVELUNDO
},
683 { wantstomenumergeW
, OLEMISC_WANTSTOMENUMERGE
}
686 static const WCHAR g_xmlW
[] = {'?','x','m','l',0};
687 static const WCHAR manifestv1W
[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','a','s','m','.','v','1',0};
688 static const WCHAR manifestv3W
[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','a','s','m','.','v','3',0};
690 static const WCHAR dotManifestW
[] = {'.','m','a','n','i','f','e','s','t',0};
691 static const WCHAR version_formatW
[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
692 static const WCHAR wildcardW
[] = {'*',0};
694 static ACTIVATION_CONTEXT_WRAPPED system_actctx
= { ACTCTX_MAGIC_MARKER
, { 1 } };
695 static ACTIVATION_CONTEXT
*process_actctx
= &system_actctx
.ActivationContext
;
697 static WCHAR
*strdupW(const WCHAR
* str
)
701 if (!(ptr
= RtlAllocateHeap(RtlGetProcessHeap(), 0, (strlenW(str
) + 1) * sizeof(WCHAR
))))
703 return strcpyW(ptr
, str
);
706 static WCHAR
*xmlstrdupW(const xmlstr_t
* str
)
710 if ((strW
= RtlAllocateHeap(RtlGetProcessHeap(), 0, (str
->len
+ 1) * sizeof(WCHAR
))))
712 memcpy( strW
, str
->ptr
, str
->len
* sizeof(WCHAR
) );
718 static inline BOOL
xmlstr_cmp(const xmlstr_t
* xmlstr
, const WCHAR
*str
)
720 return !strncmpW(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
723 static inline BOOL
xmlstr_cmpi(const xmlstr_t
* xmlstr
, const WCHAR
*str
)
725 return !strncmpiW(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
728 static inline BOOL
xmlstr_cmp_end(const xmlstr_t
* xmlstr
, const WCHAR
*str
)
730 return (xmlstr
->len
&& xmlstr
->ptr
[0] == '/' &&
731 !strncmpW(xmlstr
->ptr
+ 1, str
, xmlstr
->len
- 1) && !str
[xmlstr
->len
- 1]);
734 static inline BOOL
xml_elem_cmp(const xmlstr_t
*elem
, const WCHAR
*str
, const WCHAR
*namespace)
736 UINT len
= strlenW( namespace );
738 if (!strncmpW(elem
->ptr
, str
, elem
->len
) && !str
[elem
->len
]) return TRUE
;
739 return (elem
->len
> len
&& !strncmpW(elem
->ptr
, namespace, len
) &&
740 !strncmpW(elem
->ptr
+ len
, str
, elem
->len
- len
) && !str
[elem
->len
- len
]);
743 static inline BOOL
xml_elem_cmp_end(const xmlstr_t
*elem
, const WCHAR
*str
, const WCHAR
*namespace)
745 if (elem
->len
&& elem
->ptr
[0] == '/')
748 elem_end
.ptr
= elem
->ptr
+ 1;
749 elem_end
.len
= elem
->len
- 1;
750 return xml_elem_cmp( &elem_end
, str
, namespace );
755 static inline BOOL
isxmlspace( WCHAR ch
)
757 return (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== '\t');
760 static UNICODE_STRING
xmlstr2unicode(const xmlstr_t
*xmlstr
)
764 res
.Buffer
= (PWSTR
)xmlstr
->ptr
;
765 res
.Length
= res
.MaximumLength
= (USHORT
)xmlstr
->len
* sizeof(WCHAR
);
770 static struct assembly
*add_assembly(ACTIVATION_CONTEXT
*actctx
, enum assembly_type at
)
772 struct assembly
*assembly
;
774 if (actctx
->num_assemblies
== actctx
->allocated_assemblies
)
777 unsigned int new_count
;
778 if (actctx
->assemblies
)
780 new_count
= actctx
->allocated_assemblies
* 2;
781 ptr
= RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
782 actctx
->assemblies
, new_count
* sizeof(*assembly
) );
787 ptr
= RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* sizeof(*assembly
) );
789 if (!ptr
) return NULL
;
790 actctx
->assemblies
= ptr
;
791 actctx
->allocated_assemblies
= new_count
;
794 assembly
= &actctx
->assemblies
[actctx
->num_assemblies
++];
799 static struct dll_redirect
* add_dll_redirect(struct assembly
* assembly
)
801 if (assembly
->num_dlls
== assembly
->allocated_dlls
)
804 unsigned int new_count
;
807 new_count
= assembly
->allocated_dlls
* 2;
808 ptr
= RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
809 assembly
->dlls
, new_count
* sizeof(*assembly
->dlls
) );
814 ptr
= RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* sizeof(*assembly
->dlls
) );
816 if (!ptr
) return NULL
;
817 assembly
->dlls
= ptr
;
818 assembly
->allocated_dlls
= new_count
;
820 return &assembly
->dlls
[assembly
->num_dlls
++];
823 static void free_assembly_identity(struct assembly_identity
*ai
)
825 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->name
);
826 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->arch
);
827 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->public_key
);
828 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->language
);
829 RtlFreeHeap( RtlGetProcessHeap(), 0, ai
->type
);
832 static struct entity
* add_entity(struct entity_array
*array
, DWORD kind
)
834 struct entity
* entity
;
836 if (array
->num
== array
->allocated
)
839 unsigned int new_count
;
842 new_count
= array
->allocated
* 2;
843 ptr
= RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
,
844 array
->base
, new_count
* sizeof(*array
->base
) );
849 ptr
= RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, new_count
* sizeof(*array
->base
) );
851 if (!ptr
) return NULL
;
853 array
->allocated
= new_count
;
855 entity
= &array
->base
[array
->num
++];
860 static void free_entity_array(struct entity_array
*array
)
863 for (i
= 0; i
< array
->num
; i
++)
865 struct entity
*entity
= &array
->base
[i
];
866 switch (entity
->kind
)
868 case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
:
869 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.clsid
);
870 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.tlbid
);
871 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.progid
);
872 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.name
);
873 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.version
);
874 for (j
= 0; j
< entity
->u
.comclass
.progids
.num
; j
++)
875 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.progids
.progids
[j
]);
876 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.comclass
.progids
.progids
);
878 case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
:
879 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.ifaceps
.iid
);
880 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.ifaceps
.base
);
881 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.ifaceps
.ps32
);
882 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.ifaceps
.name
);
884 case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
:
885 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.typelib
.tlbid
);
886 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.typelib
.helpdir
);
888 case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
:
889 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.class.name
);
891 case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
:
892 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.clrsurrogate
.name
);
893 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.clrsurrogate
.clsid
);
894 RtlFreeHeap(RtlGetProcessHeap(), 0, entity
->u
.clrsurrogate
.version
);
897 DPRINT1("Unknown entity kind %u\n", entity
->kind
);
900 RtlFreeHeap( RtlGetProcessHeap(), 0, array
->base
);
903 static BOOL
is_matching_string( const WCHAR
*str1
, const WCHAR
*str2
)
905 if (!str1
) return !str2
;
906 return str2
&& !strcmpiW( str1
, str2
);
909 static BOOL
is_matching_identity( const struct assembly_identity
*id1
,
910 const struct assembly_identity
*id2
)
912 if (!is_matching_string( id1
->name
, id2
->name
)) return FALSE
;
913 if (!is_matching_string( id1
->arch
, id2
->arch
)) return FALSE
;
914 if (!is_matching_string( id1
->public_key
, id2
->public_key
)) return FALSE
;
916 if (id1
->language
&& id2
->language
&& strcmpiW( id1
->language
, id2
->language
))
918 if (strcmpW( wildcardW
, id1
->language
) && strcmpW( wildcardW
, id2
->language
))
921 if (id1
->version
.major
!= id2
->version
.major
) return FALSE
;
922 if (id1
->version
.minor
!= id2
->version
.minor
) return FALSE
;
923 if (id1
->version
.build
> id2
->version
.build
) return FALSE
;
924 if (id1
->version
.build
== id2
->version
.build
&&
925 id1
->version
.revision
> id2
->version
.revision
) return FALSE
;
929 static BOOL
add_dependent_assembly_id(struct actctx_loader
* acl
,
930 struct assembly_identity
* ai
)
934 /* check if we already have that assembly */
936 for (i
= 0; i
< acl
->actctx
->num_assemblies
; i
++)
937 if (is_matching_identity( ai
, &acl
->actctx
->assemblies
[i
].id
))
939 DPRINT( "reusing existing assembly for %S arch %S version %u.%u.%u.%u\n",
940 ai
->name
, ai
->arch
, ai
->version
.major
, ai
->version
.minor
,
941 ai
->version
.build
, ai
->version
.revision
);
945 for (i
= 0; i
< acl
->num_dependencies
; i
++)
946 if (is_matching_identity( ai
, &acl
->dependencies
[i
] ))
948 DPRINT( "reusing existing dependency for %S arch %S version %u.%u.%u.%u\n",
949 ai
->name
, ai
->arch
, ai
->version
.major
, ai
->version
.minor
,
950 ai
->version
.build
, ai
->version
.revision
);
954 if (acl
->num_dependencies
== acl
->allocated_dependencies
)
957 unsigned int new_count
;
958 if (acl
->dependencies
)
960 new_count
= acl
->allocated_dependencies
* 2;
961 ptr
= RtlReAllocateHeap(RtlGetProcessHeap(), 0, acl
->dependencies
,
962 new_count
* sizeof(acl
->dependencies
[0]));
967 ptr
= RtlAllocateHeap(RtlGetProcessHeap(), 0, new_count
* sizeof(acl
->dependencies
[0]));
969 if (!ptr
) return FALSE
;
970 acl
->dependencies
= ptr
;
971 acl
->allocated_dependencies
= new_count
;
973 acl
->dependencies
[acl
->num_dependencies
++] = *ai
;
978 static void free_depend_manifests(struct actctx_loader
* acl
)
981 for (i
= 0; i
< acl
->num_dependencies
; i
++)
982 free_assembly_identity(&acl
->dependencies
[i
]);
983 RtlFreeHeap(RtlGetProcessHeap(), 0, acl
->dependencies
);
986 static WCHAR
*build_assembly_dir(struct assembly_identity
* ai
)
988 static const WCHAR undW
[] = {'_',0};
989 static const WCHAR noneW
[] = {'n','o','n','e',0};
990 static const WCHAR mskeyW
[] = {'d','e','a','d','b','e','e','f',0};
992 const WCHAR
*arch
= ai
->arch
? ai
->arch
: noneW
;
993 const WCHAR
*key
= ai
->public_key
? ai
->public_key
: noneW
;
994 const WCHAR
*lang
= ai
->language
? ai
->language
: noneW
;
995 const WCHAR
*name
= ai
->name
? ai
->name
: noneW
;
996 SIZE_T size
= (strlenW(arch
) + 1 + strlenW(name
) + 1 + strlenW(key
) + 24 + 1 +
997 strlenW(lang
) + 1) * sizeof(WCHAR
) + sizeof(mskeyW
);
1000 if (!(ret
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
))) return NULL
;
1002 strcpyW( ret
, arch
);
1003 strcatW( ret
, undW
);
1004 strcatW( ret
, name
);
1005 strcatW( ret
, undW
);
1006 strcatW( ret
, key
);
1007 strcatW( ret
, undW
);
1008 sprintfW( ret
+ strlenW(ret
), version_formatW
,
1009 ai
->version
.major
, ai
->version
.minor
, ai
->version
.build
, ai
->version
.revision
);
1010 strcatW( ret
, undW
);
1011 strcatW( ret
, lang
);
1012 strcatW( ret
, undW
);
1013 strcatW( ret
, mskeyW
);
1017 static inline void append_string( WCHAR
*buffer
, const WCHAR
*prefix
, const WCHAR
*str
)
1022 strcatW( buffer
, prefix
);
1031 static WCHAR
*build_assembly_id( const struct assembly_identity
*ai
)
1033 static const WCHAR archW
[] =
1034 {',','p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e','=',0};
1035 static const WCHAR public_keyW
[] =
1036 {',','p','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
1037 static const WCHAR typeW2
[] =
1038 {',','t','y','p','e','=',0};
1039 static const WCHAR versionW2
[] =
1040 {',','v','e','r','s','i','o','n','=',0};
1042 WCHAR version
[64], *ret
;
1045 sprintfW( version
, version_formatW
,
1046 ai
->version
.major
, ai
->version
.minor
, ai
->version
.build
, ai
->version
.revision
);
1047 if (ai
->name
) size
+= strlenW(ai
->name
) * sizeof(WCHAR
);
1048 if (ai
->arch
) size
+= strlenW(archW
) + strlenW(ai
->arch
) + 2;
1049 if (ai
->public_key
) size
+= strlenW(public_keyW
) + strlenW(ai
->public_key
) + 2;
1050 if (ai
->type
) size
+= strlenW(typeW2
) + strlenW(ai
->type
) + 2;
1051 size
+= strlenW(versionW2
) + strlenW(version
) + 2;
1053 if (!(ret
= RtlAllocateHeap( RtlGetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
) )))
1056 if (ai
->name
) strcpyW( ret
, ai
->name
);
1058 append_string( ret
, archW
, ai
->arch
);
1059 append_string( ret
, public_keyW
, ai
->public_key
);
1060 append_string( ret
, typeW2
, ai
->type
);
1061 append_string( ret
, versionW2
, version
);
1064 static ACTIVATION_CONTEXT
*check_actctx( HANDLE h
)
1066 ACTIVATION_CONTEXT
*ret
= NULL
, *actctx
= h
;
1067 PACTIVATION_CONTEXT_WRAPPED pActual
;
1069 if (!h
|| h
== INVALID_HANDLE_VALUE
) return NULL
;
1074 pActual
= CONTAINING_RECORD(actctx
, ACTIVATION_CONTEXT_WRAPPED
, ActivationContext
);
1075 if (pActual
->MagicMarker
== ACTCTX_MAGIC_MARKER
) ret
= &pActual
->ActivationContext
;
1078 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1080 DPRINT1("Invalid activation context handle!\n");
1086 static inline void actctx_addref( ACTIVATION_CONTEXT
*actctx
)
1088 InterlockedExchangeAdd( &actctx
->RefCount
, 1 );
1091 static void actctx_release( ACTIVATION_CONTEXT
*actctx
)
1093 PACTIVATION_CONTEXT_WRAPPED pActual
;
1095 if (InterlockedExchangeAdd(&actctx
->RefCount
, -1) == 1)
1099 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
1101 struct assembly
*assembly
= &actctx
->assemblies
[i
];
1102 for (j
= 0; j
< assembly
->num_dlls
; j
++)
1104 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
1105 free_entity_array( &dll
->entities
);
1106 RtlFreeHeap( RtlGetProcessHeap(), 0, dll
->name
);
1107 RtlFreeHeap( RtlGetProcessHeap(), 0, dll
->hash
);
1109 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly
->dlls
);
1110 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly
->manifest
.info
);
1111 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly
->directory
);
1112 free_entity_array( &assembly
->entities
);
1113 free_assembly_identity(&assembly
->id
);
1115 RtlFreeHeap( RtlGetProcessHeap(), 0, actctx
->config
.info
);
1116 RtlFreeHeap( RtlGetProcessHeap(), 0, actctx
->appdir
.info
);
1117 RtlFreeHeap( RtlGetProcessHeap(), 0, actctx
->assemblies
);
1118 pActual
= CONTAINING_RECORD(actctx
, ACTIVATION_CONTEXT_WRAPPED
, ActivationContext
);
1119 pActual
->MagicMarker
= 0;
1120 RtlFreeHeap(RtlGetProcessHeap(), 0, pActual
);
1124 static BOOL
next_xml_attr(xmlbuf_t
* xmlbuf
, xmlstr_t
* name
, xmlstr_t
* value
,
1125 BOOL
* error
, BOOL
* end
)
1131 while (xmlbuf
->ptr
< xmlbuf
->end
&& isxmlspace(*xmlbuf
->ptr
))
1134 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
1136 if (*xmlbuf
->ptr
== '/')
1139 if (xmlbuf
->ptr
== xmlbuf
->end
|| *xmlbuf
->ptr
!= '>')
1148 if (*xmlbuf
->ptr
== '>')
1156 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && *ptr
!= '>' && !isxmlspace(*ptr
)) ptr
++;
1158 if (ptr
== xmlbuf
->end
) return FALSE
;
1160 name
->ptr
= xmlbuf
->ptr
;
1161 name
->len
= ptr
-xmlbuf
->ptr
;
1164 /* skip spaces before '=' */
1165 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && isxmlspace(*ptr
)) ptr
++;
1166 if (ptr
== xmlbuf
->end
|| *ptr
!= '=') return FALSE
;
1168 /* skip '=' itself */
1170 if (ptr
== xmlbuf
->end
) return FALSE
;
1172 /* skip spaces after '=' */
1173 while (ptr
< xmlbuf
->end
&& *ptr
!= '"' && *ptr
!= '\'' && isxmlspace(*ptr
)) ptr
++;
1175 if (ptr
== xmlbuf
->end
|| (*ptr
!= '"' && *ptr
!= '\'')) return FALSE
;
1178 if (ptr
== xmlbuf
->end
) return FALSE
;
1180 ptr
= memchrW(ptr
, ptr
[-1], xmlbuf
->end
- ptr
);
1183 xmlbuf
->ptr
= xmlbuf
->end
;
1187 value
->len
= ptr
- value
->ptr
;
1188 xmlbuf
->ptr
= ptr
+ 1;
1190 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
1196 static BOOL
next_xml_elem(xmlbuf_t
* xmlbuf
, xmlstr_t
* elem
)
1202 ptr
= memchrW(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
1205 xmlbuf
->ptr
= xmlbuf
->end
;
1209 if (ptr
+ 3 < xmlbuf
->end
&& ptr
[0] == '!' && ptr
[1] == '-' && ptr
[2] == '-') /* skip comment */
1211 for (ptr
+= 3; ptr
+ 3 <= xmlbuf
->end
; ptr
++)
1212 if (ptr
[0] == '-' && ptr
[1] == '-' && ptr
[2] == '>') break;
1214 if (ptr
+ 3 > xmlbuf
->end
)
1216 xmlbuf
->ptr
= xmlbuf
->end
;
1219 xmlbuf
->ptr
= ptr
+ 3;
1225 while (ptr
< xmlbuf
->end
&& !isxmlspace(*ptr
) && *ptr
!= '>' && (*ptr
!= '/' || ptr
== xmlbuf
->ptr
))
1228 elem
->ptr
= xmlbuf
->ptr
;
1229 elem
->len
= ptr
- xmlbuf
->ptr
;
1231 return xmlbuf
->ptr
!= xmlbuf
->end
;
1234 static BOOL
parse_xml_header(xmlbuf_t
* xmlbuf
)
1236 /* FIXME: parse attributes */
1239 for (ptr
= xmlbuf
->ptr
; ptr
< xmlbuf
->end
- 1; ptr
++)
1241 if (ptr
[0] == '?' && ptr
[1] == '>')
1243 xmlbuf
->ptr
= ptr
+ 2;
1250 static BOOL
parse_text_content(xmlbuf_t
* xmlbuf
, xmlstr_t
* content
)
1252 const WCHAR
*ptr
= memchrW(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
1254 if (!ptr
) return FALSE
;
1256 content
->ptr
= xmlbuf
->ptr
;
1257 content
->len
= ptr
- xmlbuf
->ptr
;
1263 static BOOL
parse_version(const xmlstr_t
*str
, struct assembly_version
*version
)
1265 unsigned int ver
[4];
1268 UNICODE_STRING strU
;
1270 /* major.minor.build.revision */
1271 ver
[0] = ver
[1] = ver
[2] = ver
[3] = pos
= 0;
1272 for (curr
= str
->ptr
; curr
< str
->ptr
+ str
->len
; curr
++)
1274 if (*curr
>= '0' && *curr
<= '9')
1276 ver
[pos
] = ver
[pos
] * 10 + *curr
- '0';
1277 if (ver
[pos
] >= 0x10000) goto error
;
1279 else if (*curr
== '.')
1281 if (++pos
>= 4) goto error
;
1285 version
->major
= ver
[0];
1286 version
->minor
= ver
[1];
1287 version
->build
= ver
[2];
1288 version
->revision
= ver
[3];
1292 strU
= xmlstr2unicode(str
);
1293 DPRINT1( "Wrong version definition in manifest file (%wZ)\n", &strU
);
1297 static BOOL
parse_expect_elem(xmlbuf_t
* xmlbuf
, const WCHAR
* name
, const WCHAR
*namespace)
1300 UNICODE_STRING elemU
;
1301 if (!next_xml_elem(xmlbuf
, &elem
)) return FALSE
;
1302 if (xml_elem_cmp(&elem
, name
, namespace)) return TRUE
;
1303 elemU
= xmlstr2unicode(&elem
);
1304 DPRINT1( "unexpected element %wZ\n", &elemU
);
1308 static BOOL
parse_expect_no_attr(xmlbuf_t
* xmlbuf
, BOOL
* end
)
1310 xmlstr_t attr_name
, attr_value
;
1311 UNICODE_STRING attr_nameU
, attr_valueU
;
1314 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, end
))
1316 attr_nameU
= xmlstr2unicode(&attr_name
);
1317 attr_valueU
= xmlstr2unicode(&attr_value
);
1318 DPRINT1( "unexpected attr %wZ=%wZ\n", &attr_nameU
,
1324 static BOOL
parse_end_element(xmlbuf_t
*xmlbuf
)
1327 return parse_expect_no_attr(xmlbuf
, &end
) && !end
;
1330 static BOOL
parse_expect_end_elem(xmlbuf_t
*xmlbuf
, const WCHAR
*name
, const WCHAR
*namespace)
1333 UNICODE_STRING elemU
;
1334 if (!next_xml_elem(xmlbuf
, &elem
)) return FALSE
;
1335 if (!xml_elem_cmp_end(&elem
, name
, namespace))
1337 elemU
= xmlstr2unicode(&elem
);
1338 DPRINT1( "unexpected element %wZ\n", &elemU
);
1341 return parse_end_element(xmlbuf
);
1344 static BOOL
parse_unknown_elem(xmlbuf_t
*xmlbuf
, const xmlstr_t
*unknown_elem
)
1346 xmlstr_t attr_name
, attr_value
, elem
;
1347 BOOL end
= FALSE
, error
, ret
= TRUE
;
1349 while(next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
));
1350 if(error
|| end
) return end
;
1352 while(ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
1354 if(*elem
.ptr
== '/' && elem
.len
- 1 == unknown_elem
->len
&&
1355 !strncmpW(elem
.ptr
+1, unknown_elem
->ptr
, unknown_elem
->len
))
1358 ret
= parse_unknown_elem(xmlbuf
, &elem
);
1361 return ret
&& parse_end_element(xmlbuf
);
1364 static BOOL
parse_assembly_identity_elem(xmlbuf_t
* xmlbuf
, ACTIVATION_CONTEXT
* actctx
,
1365 struct assembly_identity
* ai
)
1367 xmlstr_t attr_name
, attr_value
;
1368 BOOL end
= FALSE
, error
;
1369 UNICODE_STRING attr_valueU
, attr_nameU
;
1371 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1373 if (xmlstr_cmp(&attr_name
, g_nameW
))
1375 if (!(ai
->name
= xmlstrdupW(&attr_value
))) return FALSE
;
1377 else if (xmlstr_cmp(&attr_name
, typeW
))
1379 if (!(ai
->type
= xmlstrdupW(&attr_value
))) return FALSE
;
1381 else if (xmlstr_cmp(&attr_name
, versionW
))
1383 if (!parse_version(&attr_value
, &ai
->version
)) return FALSE
;
1385 else if (xmlstr_cmp(&attr_name
, processorArchitectureW
))
1387 if (!(ai
->arch
= xmlstrdupW(&attr_value
))) return FALSE
;
1389 else if (xmlstr_cmp(&attr_name
, publicKeyTokenW
))
1391 if (!(ai
->public_key
= xmlstrdupW(&attr_value
))) return FALSE
;
1393 else if (xmlstr_cmp(&attr_name
, languageW
))
1395 DPRINT1("Unsupported yet language attribute (%S)\n",
1397 if (!(ai
->language
= xmlstrdupW(&attr_value
))) return FALSE
;
1401 attr_nameU
= xmlstr2unicode(&attr_name
);
1402 attr_valueU
= xmlstr2unicode(&attr_value
);
1403 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1407 if (error
|| end
) return end
;
1408 return parse_expect_end_elem(xmlbuf
, assemblyIdentityW
, asmv1W
);
1411 static enum comclass_threadingmodel
parse_com_class_threadingmodel(xmlstr_t
*value
)
1413 static const WCHAR apartW
[] = {'A','p','a','r','t','m','e','n','t',0};
1414 static const WCHAR neutralW
[] = {'N','e','u','t','r','a','l',0};
1415 static const WCHAR freeW
[] = {'F','r','e','e',0};
1416 static const WCHAR bothW
[] = {'B','o','t','h',0};
1418 if (value
->len
== 0) return ThreadingModel_No
;
1419 if (xmlstr_cmp(value
, apartW
))
1420 return ThreadingModel_Apartment
;
1421 else if (xmlstr_cmp(value
, freeW
))
1422 return ThreadingModel_Free
;
1423 else if (xmlstr_cmp(value
, bothW
))
1424 return ThreadingModel_Both
;
1425 else if (xmlstr_cmp(value
, neutralW
))
1426 return ThreadingModel_Neutral
;
1428 return ThreadingModel_No
;
1431 static OLEMISC
get_olemisc_value(const WCHAR
*str
, int len
)
1436 max
= sizeof(olemisc_values
)/sizeof(struct olemisc_entry
) - 1;
1444 c
= strncmpW(olemisc_values
[n
].name
, str
, len
);
1445 if (!c
&& !olemisc_values
[n
].name
[len
])
1446 return olemisc_values
[n
].value
;
1454 DPRINT1("unknown flag %S\n", str
);
1458 static DWORD
parse_com_class_misc(const xmlstr_t
*value
)
1460 const WCHAR
*str
= value
->ptr
, *start
;
1464 /* it's comma separated list of flags */
1465 while (i
< value
->len
)
1468 while (*str
!= ',' && (i
++ < value
->len
)) str
++;
1470 flags
|= get_olemisc_value(start
, str
-start
);
1472 /* skip separator */
1480 static BOOL
com_class_add_progid(const xmlstr_t
*progid
, struct entity
*entity
)
1482 struct progids
*progids
= &entity
->u
.comclass
.progids
;
1484 if (progids
->allocated
== 0)
1486 progids
->allocated
= 4;
1487 if (!(progids
->progids
= RtlAllocateHeap(RtlGetProcessHeap(), 0, progids
->allocated
* sizeof(WCHAR
*)))) return FALSE
;
1490 if (progids
->allocated
== progids
->num
)
1492 progids
->allocated
*= 2;
1493 progids
->progids
= RtlReAllocateHeap(RtlGetProcessHeap(), 0, progids
->progids
, progids
->allocated
* sizeof(WCHAR
*));
1496 if (!(progids
->progids
[progids
->num
] = xmlstrdupW(progid
))) return FALSE
;
1502 static BOOL
parse_com_class_progid(xmlbuf_t
* xmlbuf
, struct entity
*entity
)
1507 if (!parse_expect_no_attr(xmlbuf
, &end
) || end
|| !parse_text_content(xmlbuf
, &content
))
1510 if (!com_class_add_progid(&content
, entity
)) return FALSE
;
1511 return parse_expect_end_elem(xmlbuf
, progidW
, asmv1W
);
1514 static BOOL
parse_com_class_elem(xmlbuf_t
* xmlbuf
, struct dll_redirect
* dll
, struct actctx_loader
*acl
)
1516 xmlstr_t elem
, attr_name
, attr_value
;
1517 BOOL ret
= TRUE
, end
= FALSE
, error
;
1518 struct entity
* entity
;
1519 UNICODE_STRING attr_valueU
, attr_nameU
;
1521 if (!(entity
= add_entity(&dll
->entities
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)))
1524 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1526 if (xmlstr_cmp(&attr_name
, clsidW
))
1528 if (!(entity
->u
.comclass
.clsid
= xmlstrdupW(&attr_value
))) return FALSE
;
1530 else if (xmlstr_cmp(&attr_name
, progidW
))
1532 if (!(entity
->u
.comclass
.progid
= xmlstrdupW(&attr_value
))) return FALSE
;
1534 else if (xmlstr_cmp(&attr_name
, tlbidW
))
1536 if (!(entity
->u
.comclass
.tlbid
= xmlstrdupW(&attr_value
))) return FALSE
;
1538 else if (xmlstr_cmp(&attr_name
, threadingmodelW
))
1540 entity
->u
.comclass
.model
= parse_com_class_threadingmodel(&attr_value
);
1542 else if (xmlstr_cmp(&attr_name
, miscstatusW
))
1544 entity
->u
.comclass
.miscstatus
= parse_com_class_misc(&attr_value
);
1546 else if (xmlstr_cmp(&attr_name
, miscstatuscontentW
))
1548 entity
->u
.comclass
.miscstatuscontent
= parse_com_class_misc(&attr_value
);
1550 else if (xmlstr_cmp(&attr_name
, miscstatusthumbnailW
))
1552 entity
->u
.comclass
.miscstatusthumbnail
= parse_com_class_misc(&attr_value
);
1554 else if (xmlstr_cmp(&attr_name
, miscstatusiconW
))
1556 entity
->u
.comclass
.miscstatusicon
= parse_com_class_misc(&attr_value
);
1558 else if (xmlstr_cmp(&attr_name
, miscstatusdocprintW
))
1560 entity
->u
.comclass
.miscstatusdocprint
= parse_com_class_misc(&attr_value
);
1562 else if (xmlstr_cmp(&attr_name
, descriptionW
))
1568 attr_nameU
= xmlstr2unicode(&attr_name
);
1569 attr_valueU
= xmlstr2unicode(&attr_value
);
1570 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1574 if (error
) return FALSE
;
1576 acl
->actctx
->sections
|= SERVERREDIRECT_SECTION
;
1577 if (entity
->u
.comclass
.progid
)
1578 acl
->actctx
->sections
|= PROGIDREDIRECT_SECTION
;
1580 if (end
) return TRUE
;
1582 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
1584 if (xmlstr_cmp_end(&elem
, comClassW
))
1586 ret
= parse_end_element(xmlbuf
);
1589 else if (xmlstr_cmp(&elem
, progidW
))
1591 ret
= parse_com_class_progid(xmlbuf
, entity
);
1595 attr_nameU
= xmlstr2unicode(&elem
);
1596 DPRINT1("unknown elem %wZ\n", &attr_nameU
);
1597 ret
= parse_unknown_elem(xmlbuf
, &elem
);
1601 if (entity
->u
.comclass
.progids
.num
)
1602 acl
->actctx
->sections
|= PROGIDREDIRECT_SECTION
;
1607 static BOOL
parse_nummethods(const xmlstr_t
*str
, struct entity
*entity
)
1612 for (curr
= str
->ptr
; curr
< str
->ptr
+ str
->len
; curr
++)
1614 if (*curr
>= '0' && *curr
<= '9')
1615 num
= num
* 10 + *curr
- '0';
1618 UNICODE_STRING strU
= xmlstr2unicode(str
);
1619 DPRINT1("wrong numeric value %wZ\n", &strU
);
1623 entity
->u
.ifaceps
.nummethods
= num
;
1628 static BOOL
parse_cominterface_proxy_stub_elem(xmlbuf_t
* xmlbuf
, struct dll_redirect
* dll
, struct actctx_loader
* acl
)
1630 xmlstr_t attr_name
, attr_value
;
1631 BOOL end
= FALSE
, error
;
1632 struct entity
* entity
;
1633 UNICODE_STRING attr_valueU
, attr_nameU
;
1635 if (!(entity
= add_entity(&dll
->entities
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
)))
1638 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1640 if (xmlstr_cmp(&attr_name
, iidW
))
1642 if (!(entity
->u
.ifaceps
.iid
= xmlstrdupW(&attr_value
))) return FALSE
;
1644 else if (xmlstr_cmp(&attr_name
, g_nameW
))
1646 if (!(entity
->u
.ifaceps
.name
= xmlstrdupW(&attr_value
))) return FALSE
;
1648 else if (xmlstr_cmp(&attr_name
, baseInterfaceW
))
1650 if (!(entity
->u
.ifaceps
.base
= xmlstrdupW(&attr_value
))) return FALSE
;
1651 entity
->u
.ifaceps
.mask
|= BaseIface
;
1653 else if (xmlstr_cmp(&attr_name
, nummethodsW
))
1655 if (!(parse_nummethods(&attr_value
, entity
))) return FALSE
;
1656 entity
->u
.ifaceps
.mask
|= NumMethods
;
1658 else if (xmlstr_cmp(&attr_name
, tlbidW
))
1660 if (!(entity
->u
.ifaceps
.tlib
= xmlstrdupW(&attr_value
))) return FALSE
;
1663 else if (xmlstr_cmp(&attr_name
, proxyStubClsid32W
) || xmlstr_cmp(&attr_name
, threadingmodelW
))
1668 attr_nameU
= xmlstr2unicode(&attr_name
);
1669 attr_valueU
= xmlstr2unicode(&attr_value
);
1670 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1674 if (error
) return FALSE
;
1675 acl
->actctx
->sections
|= IFACEREDIRECT_SECTION
;
1676 if (end
) return TRUE
;
1678 return parse_expect_end_elem(xmlbuf
, comInterfaceProxyStubW
, asmv1W
);
1681 static BOOL
parse_typelib_flags(const xmlstr_t
*value
, struct entity
*entity
)
1683 WORD
*flags
= &entity
->u
.typelib
.flags
;
1684 const WCHAR
*str
= value
->ptr
, *start
;
1689 /* it's comma separated list of flags */
1690 while (i
< value
->len
)
1693 while (*str
!= ',' && (i
++ < value
->len
)) str
++;
1695 if (!strncmpiW(start
, restrictedW
, str
-start
))
1696 *flags
|= LIBFLAG_FRESTRICTED
;
1697 else if (!strncmpiW(start
, controlW
, str
-start
))
1698 *flags
|= LIBFLAG_FCONTROL
;
1699 else if (!strncmpiW(start
, hiddenW
, str
-start
))
1700 *flags
|= LIBFLAG_FHIDDEN
;
1701 else if (!strncmpiW(start
, hasdiskimageW
, str
-start
))
1702 *flags
|= LIBFLAG_FHASDISKIMAGE
;
1705 UNICODE_STRING valueU
= xmlstr2unicode(value
);
1706 DPRINT1("unknown flags value %wZ\n", &valueU
);
1710 /* skip separator */
1718 static BOOL
parse_typelib_version(const xmlstr_t
*str
, struct entity
*entity
)
1720 unsigned int ver
[2];
1723 UNICODE_STRING strW
;
1726 ver
[0] = ver
[1] = pos
= 0;
1727 for (curr
= str
->ptr
; curr
< str
->ptr
+ str
->len
; curr
++)
1729 if (*curr
>= '0' && *curr
<= '9')
1731 ver
[pos
] = ver
[pos
] * 10 + *curr
- '0';
1732 if (ver
[pos
] >= 0x10000) goto error
;
1734 else if (*curr
== '.')
1736 if (++pos
>= 2) goto error
;
1740 entity
->u
.typelib
.major
= ver
[0];
1741 entity
->u
.typelib
.minor
= ver
[1];
1745 strW
= xmlstr2unicode(str
);
1746 DPRINT1("FIXME: wrong typelib version value (%wZ)\n", &strW
);
1750 static BOOL
parse_typelib_elem(xmlbuf_t
* xmlbuf
, struct dll_redirect
* dll
, struct actctx_loader
* acl
)
1752 xmlstr_t attr_name
, attr_value
;
1753 BOOL end
= FALSE
, error
;
1754 struct entity
* entity
;
1755 UNICODE_STRING attr_valueU
, attr_nameU
;
1757 if (!(entity
= add_entity(&dll
->entities
, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
)))
1760 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1762 if (xmlstr_cmp(&attr_name
, tlbidW
))
1764 if (!(entity
->u
.typelib
.tlbid
= xmlstrdupW(&attr_value
))) return FALSE
;
1766 else if (xmlstr_cmp(&attr_name
, versionW
))
1768 if (!parse_typelib_version(&attr_value
, entity
)) return FALSE
;
1770 else if (xmlstr_cmp(&attr_name
, helpdirW
))
1772 if (!(entity
->u
.typelib
.helpdir
= xmlstrdupW(&attr_value
))) return FALSE
;
1774 else if (xmlstr_cmp(&attr_name
, flagsW
))
1776 if (!parse_typelib_flags(&attr_value
, entity
)) return FALSE
;
1780 attr_nameU
= xmlstr2unicode(&attr_name
);
1781 attr_valueU
= xmlstr2unicode(&attr_value
);
1782 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1786 if (error
) return FALSE
;
1788 acl
->actctx
->sections
|= TLIBREDIRECT_SECTION
;
1790 if (end
) return TRUE
;
1792 return parse_expect_end_elem(xmlbuf
, typelibW
, asmv1W
);
1795 static inline int aligned_string_len(int len
)
1797 return (len
+ 3) & ~3;
1800 static int get_assembly_version(struct assembly
*assembly
, WCHAR
*ret
)
1802 static const WCHAR fmtW
[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
1803 struct assembly_version
*ver
= &assembly
->id
.version
;
1806 if (!ret
) ret
= buff
;
1807 return sprintfW(ret
, fmtW
, ver
->major
, ver
->minor
, ver
->build
, ver
->revision
);
1810 static BOOL
parse_window_class_elem(xmlbuf_t
* xmlbuf
, struct dll_redirect
* dll
, struct actctx_loader
* acl
)
1812 xmlstr_t elem
, content
, attr_name
, attr_value
;
1813 BOOL end
= FALSE
, ret
= TRUE
, error
;
1814 struct entity
* entity
;
1815 UNICODE_STRING elemU
, attr_nameU
, attr_valueU
;
1817 if (!(entity
= add_entity(&dll
->entities
, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
)))
1820 entity
->u
.class.versioned
= TRUE
;
1821 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1823 if (xmlstr_cmp(&attr_name
, versionedW
))
1825 if (xmlstr_cmpi(&attr_value
, noW
))
1826 entity
->u
.class.versioned
= FALSE
;
1827 else if (!xmlstr_cmpi(&attr_value
, yesW
))
1832 attr_nameU
= xmlstr2unicode(&attr_name
);
1833 attr_valueU
= xmlstr2unicode(&attr_value
);
1834 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1838 if (error
|| end
) return end
;
1840 if (!parse_text_content(xmlbuf
, &content
)) return FALSE
;
1842 if (!(entity
->u
.class.name
= xmlstrdupW(&content
))) return FALSE
;
1844 acl
->actctx
->sections
|= WINDOWCLASS_SECTION
;
1846 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
1848 if (xmlstr_cmp_end(&elem
, windowClassW
))
1850 ret
= parse_end_element(xmlbuf
);
1855 elemU
= xmlstr2unicode(&elem
);
1856 DPRINT1("unknown elem %wZ\n", &elemU
);
1857 ret
= parse_unknown_elem(xmlbuf
, &elem
);
1864 static BOOL
parse_binding_redirect_elem(xmlbuf_t
* xmlbuf
)
1866 xmlstr_t attr_name
, attr_value
;
1867 UNICODE_STRING attr_valueU
, attr_nameU
;
1868 BOOL end
= FALSE
, error
;
1870 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1872 attr_nameU
= xmlstr2unicode(&attr_name
);
1873 attr_valueU
= xmlstr2unicode(&attr_value
);
1875 if (xmlstr_cmp(&attr_name
, oldVersionW
))
1877 DPRINT1("Not stored yet oldVersion=%wZ\n", &attr_valueU
);
1879 else if (xmlstr_cmp(&attr_name
, newVersionW
))
1881 DPRINT1("Not stored yet newVersion=%wZ\n", &attr_valueU
);
1885 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1889 if (error
|| end
) return end
;
1890 return parse_expect_end_elem(xmlbuf
, bindingRedirectW
, asmv1W
);
1893 static BOOL
parse_description_elem(xmlbuf_t
* xmlbuf
)
1895 xmlstr_t elem
, content
;
1896 UNICODE_STRING elemU
;
1897 BOOL end
= FALSE
, ret
= TRUE
;
1899 if (!parse_expect_no_attr(xmlbuf
, &end
) || end
||
1900 !parse_text_content(xmlbuf
, &content
))
1903 elemU
= xmlstr2unicode(&content
);
1904 DPRINT("Got description %wZ\n", &elemU
);
1906 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
1908 if (xmlstr_cmp_end(&elem
, descriptionW
))
1910 ret
= parse_end_element(xmlbuf
);
1915 elemU
= xmlstr2unicode(&elem
);
1916 DPRINT1("unknown elem %wZ\n", &elemU
);
1917 ret
= parse_unknown_elem(xmlbuf
, &elem
);
1924 static BOOL
parse_com_interface_external_proxy_stub_elem(xmlbuf_t
* xmlbuf
,
1925 struct assembly
* assembly
,
1926 struct actctx_loader
* acl
)
1928 xmlstr_t attr_name
, attr_value
;
1929 UNICODE_STRING attr_nameU
, attr_valueU
;
1930 BOOL end
= FALSE
, error
;
1931 struct entity
* entity
;
1933 entity
= add_entity(&assembly
->entities
, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
);
1934 if (!entity
) return FALSE
;
1936 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1938 if (xmlstr_cmp(&attr_name
, iidW
))
1940 if (!(entity
->u
.ifaceps
.iid
= xmlstrdupW(&attr_value
))) return FALSE
;
1942 else if (xmlstr_cmp(&attr_name
, g_nameW
))
1944 if (!(entity
->u
.ifaceps
.name
= xmlstrdupW(&attr_value
))) return FALSE
;
1946 else if (xmlstr_cmp(&attr_name
, baseInterfaceW
))
1948 if (!(entity
->u
.ifaceps
.base
= xmlstrdupW(&attr_value
))) return FALSE
;
1949 entity
->u
.ifaceps
.mask
|= BaseIface
;
1951 else if (xmlstr_cmp(&attr_name
, nummethodsW
))
1953 if (!(parse_nummethods(&attr_value
, entity
))) return FALSE
;
1954 entity
->u
.ifaceps
.mask
|= NumMethods
;
1956 else if (xmlstr_cmp(&attr_name
, proxyStubClsid32W
))
1958 if (!(entity
->u
.ifaceps
.ps32
= xmlstrdupW(&attr_value
))) return FALSE
;
1960 else if (xmlstr_cmp(&attr_name
, tlbidW
))
1962 if (!(entity
->u
.ifaceps
.tlib
= xmlstrdupW(&attr_value
))) return FALSE
;
1966 attr_nameU
= xmlstr2unicode(&attr_name
);
1967 attr_valueU
= xmlstr2unicode(&attr_value
);
1968 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
1972 if (error
) return FALSE
;
1973 acl
->actctx
->sections
|= IFACEREDIRECT_SECTION
;
1974 if (end
) return TRUE
;
1976 return parse_expect_end_elem(xmlbuf
, comInterfaceExternalProxyStubW
, asmv1W
);
1979 static BOOL
parse_clr_class_elem(xmlbuf_t
* xmlbuf
, struct assembly
* assembly
, struct actctx_loader
*acl
)
1981 xmlstr_t attr_name
, attr_value
, elem
;
1982 BOOL end
= FALSE
, error
, ret
= TRUE
;
1983 struct entity
* entity
;
1985 entity
= add_entity(&assembly
->entities
, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
);
1986 if (!entity
) return FALSE
;
1988 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
1990 if (xmlstr_cmp(&attr_name
, g_nameW
))
1992 if (!(entity
->u
.comclass
.name
= xmlstrdupW(&attr_value
))) return FALSE
;
1994 else if (xmlstr_cmp(&attr_name
, clsidW
))
1996 if (!(entity
->u
.comclass
.clsid
= xmlstrdupW(&attr_value
))) return FALSE
;
1998 else if (xmlstr_cmp(&attr_name
, progidW
))
2000 if (!(entity
->u
.comclass
.progid
= xmlstrdupW(&attr_value
))) return FALSE
;
2002 else if (xmlstr_cmp(&attr_name
, tlbidW
))
2004 if (!(entity
->u
.comclass
.tlbid
= xmlstrdupW(&attr_value
))) return FALSE
;
2006 else if (xmlstr_cmp(&attr_name
, threadingmodelW
))
2008 entity
->u
.comclass
.model
= parse_com_class_threadingmodel(&attr_value
);
2010 else if (xmlstr_cmp(&attr_name
, runtimeVersionW
))
2012 if (!(entity
->u
.comclass
.version
= xmlstrdupW(&attr_value
))) return FALSE
;
2016 UNICODE_STRING attr_nameU
, attr_valueU
;
2017 attr_nameU
= xmlstr2unicode(&attr_name
);
2018 attr_valueU
= xmlstr2unicode(&attr_value
);
2019 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2023 if (error
) return FALSE
;
2024 acl
->actctx
->sections
|= SERVERREDIRECT_SECTION
;
2025 if (entity
->u
.comclass
.progid
)
2026 acl
->actctx
->sections
|= PROGIDREDIRECT_SECTION
;
2027 if (end
) return TRUE
;
2029 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
2031 if (xmlstr_cmp_end(&elem
, clrClassW
))
2033 ret
= parse_end_element(xmlbuf
);
2036 else if (xmlstr_cmp(&elem
, progidW
))
2038 ret
= parse_com_class_progid(xmlbuf
, entity
);
2042 UNICODE_STRING elemU
= xmlstr2unicode(&elem
);
2043 DPRINT1("unknown elem %wZ\n", &elemU
);
2044 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2048 if (entity
->u
.comclass
.progids
.num
)
2049 acl
->actctx
->sections
|= PROGIDREDIRECT_SECTION
;
2054 static BOOL
parse_clr_surrogate_elem(xmlbuf_t
* xmlbuf
, struct assembly
* assembly
, struct actctx_loader
*acl
)
2056 xmlstr_t attr_name
, attr_value
;
2057 UNICODE_STRING attr_nameU
, attr_valueU
;
2058 BOOL end
= FALSE
, error
;
2059 struct entity
* entity
;
2061 entity
= add_entity(&assembly
->entities
, ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
);
2062 if (!entity
) return FALSE
;
2064 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
2066 if (xmlstr_cmp(&attr_name
, g_nameW
))
2068 if (!(entity
->u
.clrsurrogate
.name
= xmlstrdupW(&attr_value
))) return FALSE
;
2070 else if (xmlstr_cmp(&attr_name
, clsidW
))
2072 if (!(entity
->u
.clrsurrogate
.clsid
= xmlstrdupW(&attr_value
))) return FALSE
;
2074 else if (xmlstr_cmp(&attr_name
, runtimeVersionW
))
2076 if (!(entity
->u
.clrsurrogate
.version
= xmlstrdupW(&attr_value
))) return FALSE
;
2080 attr_nameU
= xmlstr2unicode(&attr_name
);
2081 attr_valueU
= xmlstr2unicode(&attr_value
);
2082 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2086 if (error
) return FALSE
;
2087 acl
->actctx
->sections
|= CLRSURROGATES_SECTION
;
2088 if (end
) return TRUE
;
2090 return parse_expect_end_elem(xmlbuf
, clrSurrogateW
, asmv1W
);
2093 static BOOL
parse_dependent_assembly_elem(xmlbuf_t
* xmlbuf
, struct actctx_loader
* acl
, BOOL optional
)
2095 struct assembly_identity ai
;
2097 BOOL end
= FALSE
, ret
= TRUE
;
2099 if (!parse_expect_no_attr(xmlbuf
, &end
) || end
) return end
;
2101 memset(&ai
, 0, sizeof(ai
));
2102 ai
.optional
= optional
;
2104 if (!parse_expect_elem(xmlbuf
, assemblyIdentityW
, asmv1W
) ||
2105 !parse_assembly_identity_elem(xmlbuf
, acl
->actctx
, &ai
))
2108 //TRACE( "adding name=%s version=%s arch=%s\n", debugstr_w(ai.name), debugstr_version(&ai.version), debugstr_w(ai.arch) );
2110 /* store the newly found identity for later loading */
2111 if (!add_dependent_assembly_id(acl
, &ai
)) return FALSE
;
2113 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
2115 if (xmlstr_cmp_end(&elem
, dependentAssemblyW
))
2117 ret
= parse_end_element(xmlbuf
);
2120 else if (xmlstr_cmp(&elem
, bindingRedirectW
))
2122 ret
= parse_binding_redirect_elem(xmlbuf
);
2126 DPRINT1("unknown elem %S\n", elem
.ptr
);
2127 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2134 static BOOL
parse_dependency_elem(xmlbuf_t
* xmlbuf
, struct actctx_loader
* acl
)
2136 xmlstr_t attr_name
, attr_value
, elem
;
2137 UNICODE_STRING attr_nameU
, attr_valueU
;
2138 BOOL end
= FALSE
, ret
= TRUE
, error
, optional
= FALSE
;
2140 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
2142 attr_nameU
= xmlstr2unicode(&attr_name
);
2143 attr_valueU
= xmlstr2unicode(&attr_value
);
2145 if (xmlstr_cmp(&attr_name
, optionalW
))
2147 optional
= xmlstr_cmpi( &attr_value
, yesW
);
2148 DPRINT1("optional=%wZ\n", &attr_valueU
);
2152 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2156 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
2158 if (xmlstr_cmp_end(&elem
, dependencyW
))
2160 ret
= parse_end_element(xmlbuf
);
2163 else if (xmlstr_cmp(&elem
, dependentAssemblyW
))
2165 ret
= parse_dependent_assembly_elem(xmlbuf
, acl
, optional
);
2169 attr_nameU
= xmlstr2unicode(&elem
);
2170 DPRINT1("unknown element %wZ\n", &attr_nameU
);
2171 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2178 static BOOL
parse_noinherit_elem(xmlbuf_t
* xmlbuf
)
2182 if (!parse_expect_no_attr(xmlbuf
, &end
)) return FALSE
;
2183 return end
|| parse_expect_end_elem(xmlbuf
, noInheritW
, asmv1W
);
2186 static BOOL
parse_noinheritable_elem(xmlbuf_t
* xmlbuf
)
2190 if (!parse_expect_no_attr(xmlbuf
, &end
)) return FALSE
;
2191 return end
|| parse_expect_end_elem(xmlbuf
, noInheritableW
, asmv1W
);
2194 static BOOL
parse_file_elem(xmlbuf_t
* xmlbuf
, struct assembly
* assembly
, struct actctx_loader
* acl
)
2196 xmlstr_t attr_name
, attr_value
, elem
;
2197 UNICODE_STRING attr_nameU
, attr_valueU
;
2198 BOOL end
= FALSE
, error
, ret
= TRUE
;
2199 struct dll_redirect
* dll
;
2201 if (!(dll
= add_dll_redirect(assembly
))) return FALSE
;
2203 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
2205 attr_nameU
= xmlstr2unicode(&attr_name
);
2206 attr_valueU
= xmlstr2unicode(&attr_value
);
2208 if (xmlstr_cmp(&attr_name
, g_nameW
))
2210 if (!(dll
->name
= xmlstrdupW(&attr_value
))) return FALSE
;
2211 DPRINT("name=%wZ\n", &attr_valueU
);
2213 else if (xmlstr_cmp(&attr_name
, hashW
))
2215 if (!(dll
->hash
= xmlstrdupW(&attr_value
))) return FALSE
;
2217 else if (xmlstr_cmp(&attr_name
, hashalgW
))
2219 static const WCHAR sha1W
[] = {'S','H','A','1',0};
2220 if (!xmlstr_cmpi(&attr_value
, sha1W
))
2221 DPRINT1("hashalg should be SHA1, got %wZ\n", &attr_valueU
);
2225 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2229 if (error
|| !dll
->name
) return FALSE
;
2231 acl
->actctx
->sections
|= DLLREDIRECT_SECTION
;
2233 if (end
) return TRUE
;
2235 while (ret
&& (ret
= next_xml_elem(xmlbuf
, &elem
)))
2237 if (xmlstr_cmp_end(&elem
, fileW
))
2239 ret
= parse_end_element(xmlbuf
);
2242 else if (xmlstr_cmp(&elem
, comClassW
))
2244 ret
= parse_com_class_elem(xmlbuf
, dll
, acl
);
2246 else if (xmlstr_cmp(&elem
, comInterfaceProxyStubW
))
2248 ret
= parse_cominterface_proxy_stub_elem(xmlbuf
, dll
, acl
);
2250 else if (xml_elem_cmp(&elem
, hashW
, asmv2W
))
2252 DPRINT1("asmv2hash (undocumented) not supported\n");
2253 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2255 else if (xmlstr_cmp(&elem
, typelibW
))
2257 ret
= parse_typelib_elem(xmlbuf
, dll
, acl
);
2259 else if (xmlstr_cmp(&elem
, windowClassW
))
2261 ret
= parse_window_class_elem(xmlbuf
, dll
, acl
);
2265 attr_nameU
= xmlstr2unicode(&elem
);
2266 DPRINT1("unknown elem %wZ\n", &attr_nameU
);
2267 ret
= parse_unknown_elem( xmlbuf
, &elem
);
2274 static BOOL
parse_assembly_elem(xmlbuf_t
* xmlbuf
, struct actctx_loader
* acl
,
2275 struct assembly
* assembly
,
2276 struct assembly_identity
* expected_ai
)
2278 xmlstr_t attr_name
, attr_value
, elem
;
2279 UNICODE_STRING attr_nameU
, attr_valueU
;
2280 BOOL end
= FALSE
, error
, version
= FALSE
, xmlns
= FALSE
, ret
= TRUE
;
2282 DPRINT("(%p)\n", xmlbuf
);
2284 while (next_xml_attr(xmlbuf
, &attr_name
, &attr_value
, &error
, &end
))
2286 attr_nameU
= xmlstr2unicode(&attr_name
);
2287 attr_valueU
= xmlstr2unicode(&attr_value
);
2289 if (xmlstr_cmp(&attr_name
, manifestVersionW
))
2291 static const WCHAR v10W
[] = {'1','.','0',0};
2292 if (!xmlstr_cmp(&attr_value
, v10W
))
2294 DPRINT1("wrong version %wZ\n", &attr_valueU
);
2299 else if (xmlstr_cmp(&attr_name
, xmlnsW
))
2301 if (!xmlstr_cmp(&attr_value
, manifestv1W
) && !xmlstr_cmp(&attr_value
, manifestv3W
))
2303 DPRINT1("wrong namespace %wZ\n", &attr_valueU
);
2310 DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU
, &attr_valueU
);
2314 if (error
|| end
|| !xmlns
|| !version
) return FALSE
;
2315 if (!next_xml_elem(xmlbuf
, &elem
)) return FALSE
;
2317 if (assembly
->type
== APPLICATION_MANIFEST
&& xmlstr_cmp(&elem
, noInheritW
))
2319 if (!parse_noinherit_elem(xmlbuf
) || !next_xml_elem(xmlbuf
, &elem
))
2321 assembly
->no_inherit
= TRUE
;
2324 if (xml_elem_cmp(&elem
, noInheritableW
, asmv1W
))
2326 if (!parse_noinheritable_elem(xmlbuf
) || !next_xml_elem(xmlbuf
, &elem
))
2329 else if ((assembly
->type
== ASSEMBLY_MANIFEST
|| assembly
->type
== ASSEMBLY_SHARED_MANIFEST
) &&
2330 assembly
->no_inherit
)
2335 if (xml_elem_cmp_end(&elem
, assemblyW
, asmv1W
))
2337 ret
= parse_end_element(xmlbuf
);
2340 else if (xml_elem_cmp(&elem
, descriptionW
, asmv1W
))
2342 ret
= parse_description_elem(xmlbuf
);
2344 else if (xml_elem_cmp(&elem
, comInterfaceExternalProxyStubW
, asmv1W
))
2346 ret
= parse_com_interface_external_proxy_stub_elem(xmlbuf
, assembly
, acl
);
2348 else if (xml_elem_cmp(&elem
, dependencyW
, asmv1W
))
2350 ret
= parse_dependency_elem(xmlbuf
, acl
);
2352 else if (xml_elem_cmp(&elem
, fileW
, asmv1W
))
2354 ret
= parse_file_elem(xmlbuf
, assembly
, acl
);
2356 else if (xml_elem_cmp(&elem
, clrClassW
, asmv1W
))
2358 ret
= parse_clr_class_elem(xmlbuf
, assembly
, acl
);
2360 else if (xml_elem_cmp(&elem
, clrSurrogateW
, asmv1W
))
2362 ret
= parse_clr_surrogate_elem(xmlbuf
, assembly
, acl
);
2364 else if (xml_elem_cmp(&elem
, assemblyIdentityW
, asmv1W
))
2366 if (!parse_assembly_identity_elem(xmlbuf
, acl
->actctx
, &assembly
->id
)) return FALSE
;
2370 /* FIXME: more tests */
2371 if (assembly
->type
== ASSEMBLY_MANIFEST
&&
2372 memcmp(&assembly
->id
.version
, &expected_ai
->version
, sizeof(assembly
->id
.version
)))
2374 DPRINT1("wrong version for assembly manifest: %u.%u.%u.%u / %u.%u.%u.%u\n",
2375 expected_ai
->version
.major
, expected_ai
->version
.minor
,
2376 expected_ai
->version
.build
, expected_ai
->version
.revision
,
2377 assembly
->id
.version
.major
, assembly
->id
.version
.minor
,
2378 assembly
->id
.version
.build
, assembly
->id
.version
.revision
);
2381 else if (assembly
->type
== ASSEMBLY_SHARED_MANIFEST
&&
2382 (assembly
->id
.version
.major
!= expected_ai
->version
.major
||
2383 assembly
->id
.version
.minor
!= expected_ai
->version
.minor
||
2384 assembly
->id
.version
.build
< expected_ai
->version
.build
||
2385 (assembly
->id
.version
.build
== expected_ai
->version
.build
&&
2386 assembly
->id
.version
.revision
< expected_ai
->version
.revision
)))
2388 DPRINT1("wrong version for shared assembly manifest\n");
2395 attr_nameU
= xmlstr2unicode(&elem
);
2396 DPRINT1("unknown element %wZ\n", &attr_nameU
);
2397 ret
= parse_unknown_elem(xmlbuf
, &elem
);
2399 if (ret
) ret
= next_xml_elem(xmlbuf
, &elem
);
2405 static NTSTATUS
parse_manifest_buffer( struct actctx_loader
* acl
, struct assembly
*assembly
,
2406 struct assembly_identity
* ai
, xmlbuf_t
*xmlbuf
)
2409 UNICODE_STRING elemU
;
2411 if (!next_xml_elem(xmlbuf
, &elem
)) return STATUS_SXS_CANT_GEN_ACTCTX
;
2413 if (xmlstr_cmp(&elem
, g_xmlW
) &&
2414 (!parse_xml_header(xmlbuf
) || !next_xml_elem(xmlbuf
, &elem
)))
2415 return STATUS_SXS_CANT_GEN_ACTCTX
;
2417 if (!xml_elem_cmp(&elem
, assemblyW
, asmv1W
))
2419 elemU
= xmlstr2unicode(&elem
);
2420 DPRINT1("root element is %wZ, not <assembly>\n", &elemU
);
2421 return STATUS_SXS_CANT_GEN_ACTCTX
;
2424 if (!parse_assembly_elem(xmlbuf
, acl
, assembly
, ai
))
2426 DPRINT1("failed to parse manifest %S\n", assembly
->manifest
.info
);
2427 return STATUS_SXS_CANT_GEN_ACTCTX
;
2430 if (next_xml_elem(xmlbuf
, &elem
))
2432 elemU
= xmlstr2unicode(&elem
);
2433 DPRINT1("unexpected element %wZ\n", &elemU
);
2434 return STATUS_SXS_CANT_GEN_ACTCTX
;
2437 if (xmlbuf
->ptr
!= xmlbuf
->end
)
2439 DPRINT1("parse error\n");
2440 return STATUS_SXS_CANT_GEN_ACTCTX
;
2442 return STATUS_SUCCESS
;
2445 static NTSTATUS
parse_manifest( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2446 LPCWSTR filename
, LPCWSTR directory
, BOOL shared
,
2447 const void *buffer
, SIZE_T size
)
2451 struct assembly
*assembly
;
2454 DPRINT( "parsing manifest loaded from %S base dir %S\n", filename
, directory
);
2456 if (!(assembly
= add_assembly(acl
->actctx
, shared
? ASSEMBLY_SHARED_MANIFEST
: ASSEMBLY_MANIFEST
)))
2457 return STATUS_SXS_CANT_GEN_ACTCTX
;
2459 if (directory
&& !(assembly
->directory
= strdupW(directory
)))
2460 return STATUS_NO_MEMORY
;
2462 if (filename
) assembly
->manifest
.info
= strdupW( filename
+ 4 /* skip \??\ prefix */ );
2463 assembly
->manifest
.type
= assembly
->manifest
.info
? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
2464 : ACTIVATION_CONTEXT_PATH_TYPE_NONE
;
2466 unicode_tests
= IS_TEXT_UNICODE_SIGNATURE
| IS_TEXT_UNICODE_REVERSE_SIGNATURE
;
2467 if (RtlIsTextUnicode((PVOID
)buffer
, (ULONG
)size
, &unicode_tests
))
2469 xmlbuf
.ptr
= buffer
;
2470 xmlbuf
.end
= xmlbuf
.ptr
+ size
/ sizeof(WCHAR
);
2471 status
= parse_manifest_buffer( acl
, assembly
, ai
, &xmlbuf
);
2473 else if (unicode_tests
& IS_TEXT_UNICODE_REVERSE_SIGNATURE
)
2475 const WCHAR
*buf
= buffer
;
2479 if (!(new_buff
= RtlAllocateHeap( RtlGetProcessHeap(), 0, size
)))
2480 return STATUS_NO_MEMORY
;
2481 for (i
= 0; i
< size
/ sizeof(WCHAR
); i
++)
2482 new_buff
[i
] = RtlUshortByteSwap( buf
[i
] );
2483 xmlbuf
.ptr
= new_buff
;
2484 xmlbuf
.end
= xmlbuf
.ptr
+ size
/ sizeof(WCHAR
);
2485 status
= parse_manifest_buffer( acl
, assembly
, ai
, &xmlbuf
);
2486 RtlFreeHeap( RtlGetProcessHeap(), 0, new_buff
);
2490 /* TODO: this doesn't handle arbitrary encodings */
2494 status
= RtlMultiByteToUnicodeSize(&sizeU
, buffer
, size
);
2495 if (!NT_SUCCESS(status
))
2497 DPRINT1("RtlMultiByteToUnicodeSize failed with %lx\n", status
);
2498 return STATUS_SXS_CANT_GEN_ACTCTX
;
2501 new_buff
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeU
);
2503 return STATUS_NO_MEMORY
;
2505 status
= RtlMultiByteToUnicodeN(new_buff
, sizeU
, &sizeU
, buffer
, size
);
2506 if (!NT_SUCCESS(status
))
2508 DPRINT1("RtlMultiByteToUnicodeN failed with %lx\n", status
);
2509 return STATUS_SXS_CANT_GEN_ACTCTX
;
2512 xmlbuf
.ptr
= new_buff
;
2513 xmlbuf
.end
= xmlbuf
.ptr
+ sizeU
/ sizeof(WCHAR
);
2514 status
= parse_manifest_buffer(acl
, assembly
, ai
, &xmlbuf
);
2515 RtlFreeHeap(RtlGetProcessHeap(), 0, new_buff
);
2520 static NTSTATUS
open_nt_file( HANDLE
*handle
, UNICODE_STRING
*name
)
2522 OBJECT_ATTRIBUTES attr
;
2525 attr
.Length
= sizeof(attr
);
2526 attr
.RootDirectory
= 0;
2527 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2528 attr
.ObjectName
= name
;
2529 attr
.SecurityDescriptor
= NULL
;
2530 attr
.SecurityQualityOfService
= NULL
;
2531 return NtOpenFile(handle
,
2532 GENERIC_READ
| SYNCHRONIZE
,
2535 FILE_SYNCHRONOUS_IO_ALERT
);
2538 static NTSTATUS
get_module_filename( HMODULE module
, UNICODE_STRING
*str
, USHORT extra_len
)
2542 LDR_DATA_TABLE_ENTRY
*pldr
;
2544 LdrLockLoaderLock(0, NULL
, &magic
);
2545 status
= LdrFindEntryForAddress( module
, &pldr
);
2546 if (status
== STATUS_SUCCESS
)
2548 if ((str
->Buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2549 pldr
->FullDllName
.Length
+ extra_len
+ sizeof(WCHAR
) )))
2551 memcpy( str
->Buffer
, pldr
->FullDllName
.Buffer
, pldr
->FullDllName
.Length
+ sizeof(WCHAR
) );
2552 str
->Length
= pldr
->FullDllName
.Length
;
2553 str
->MaximumLength
= pldr
->FullDllName
.Length
+ extra_len
+ sizeof(WCHAR
);
2555 else status
= STATUS_NO_MEMORY
;
2557 LdrUnlockLoaderLock(0, magic
);
2561 static NTSTATUS
get_manifest_in_module( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2562 LPCWSTR filename
, LPCWSTR directory
, BOOL shared
,
2563 HANDLE hModule
, LPCWSTR resname
, ULONG lang
)
2566 UNICODE_STRING nameW
;
2567 LDR_RESOURCE_INFO info
;
2568 IMAGE_RESOURCE_DATA_ENTRY
* entry
= NULL
;
2571 //DPRINT( "looking for res %s in module %p %s\n", resname,
2572 // hModule, filename );
2575 if (TRACE_ON(actctx
))
2577 if (!filename
&& !get_module_filename( hModule
, &nameW
, 0 ))
2579 DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname
),
2580 hModule
, debugstr_w(nameW
.Buffer
) );
2581 RtlFreeUnicodeString( &nameW
);
2583 else DPRINT( "looking for res %s in module %p %s\n", debugstr_w(resname
),
2584 hModule
, debugstr_w(filename
) );
2588 if (!resname
) return STATUS_INVALID_PARAMETER
;
2590 info
.Type
= (ULONG_PTR
)RT_MANIFEST
;
2591 info
.Language
= lang
;
2592 if (!((ULONG_PTR
)resname
>> 16))
2594 info
.Name
= (ULONG_PTR
)resname
;
2595 status
= LdrFindResource_U(hModule
, &info
, 3, &entry
);
2597 else if (resname
[0] == '#')
2600 RtlInitUnicodeString(&nameW
, resname
+ 1);
2601 if (RtlUnicodeStringToInteger(&nameW
, 10, &value
) != STATUS_SUCCESS
|| HIWORD(value
))
2602 return STATUS_INVALID_PARAMETER
;
2604 status
= LdrFindResource_U(hModule
, &info
, 3, &entry
);
2608 RtlCreateUnicodeString(&nameW
, resname
);
2609 RtlUpcaseUnicodeString(&nameW
, &nameW
, FALSE
);
2610 info
.Name
= (ULONG_PTR
)nameW
.Buffer
;
2611 status
= LdrFindResource_U(hModule
, &info
, 3, &entry
);
2612 RtlFreeUnicodeString(&nameW
);
2614 if (status
== STATUS_SUCCESS
) status
= LdrAccessResource(hModule
, entry
, &ptr
, NULL
);
2616 if (status
== STATUS_SUCCESS
)
2617 status
= parse_manifest(acl
, ai
, filename
, directory
, shared
, ptr
, entry
->Size
);
2622 static NTSTATUS
get_manifest_in_pe_file( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2623 LPCWSTR filename
, LPCWSTR directory
, BOOL shared
,
2624 HANDLE file
, LPCWSTR resname
, ULONG lang
)
2627 OBJECT_ATTRIBUTES attr
;
2629 LARGE_INTEGER offset
;
2634 DPRINT( "looking for res %S in %S\n", resname
, filename
);
2636 attr
.Length
= sizeof(attr
);
2637 attr
.RootDirectory
= 0;
2638 attr
.ObjectName
= NULL
;
2639 attr
.Attributes
= OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
;
2640 attr
.SecurityDescriptor
= NULL
;
2641 attr
.SecurityQualityOfService
= NULL
;
2644 status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
| SECTION_MAP_READ
,
2645 &attr
, &size
, PAGE_READONLY
, SEC_COMMIT
, file
);
2646 if (status
!= STATUS_SUCCESS
) return status
;
2648 offset
.QuadPart
= 0;
2651 status
= NtMapViewOfSection( mapping
, NtCurrentProcess(), &base
, 0, 0, &offset
,
2652 &count
, ViewShare
, 0, PAGE_READONLY
);
2654 if (status
!= STATUS_SUCCESS
) return status
;
2656 if (RtlImageNtHeader(base
)) /* we got a PE file */
2658 HANDLE module
= (HMODULE
)((ULONG_PTR
)base
| 1); /* make it a LOAD_LIBRARY_AS_DATAFILE handle */
2659 status
= get_manifest_in_module( acl
, ai
, filename
, directory
, shared
, module
, resname
, lang
);
2661 else status
= STATUS_INVALID_IMAGE_FORMAT
;
2663 NtUnmapViewOfSection( NtCurrentProcess(), base
);
2667 static NTSTATUS
get_manifest_in_manifest_file( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2668 LPCWSTR filename
, LPCWSTR directory
, BOOL shared
, HANDLE file
)
2670 FILE_STANDARD_INFORMATION info
;
2673 OBJECT_ATTRIBUTES attr
;
2675 LARGE_INTEGER offset
;
2680 DPRINT( "loading manifest file %S\n", filename
);
2682 attr
.Length
= sizeof(attr
);
2683 attr
.RootDirectory
= 0;
2684 attr
.ObjectName
= NULL
;
2685 attr
.Attributes
= OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
;
2686 attr
.SecurityDescriptor
= NULL
;
2687 attr
.SecurityQualityOfService
= NULL
;
2690 status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
| SECTION_MAP_READ
,
2691 &attr
, &size
, PAGE_READONLY
, SEC_COMMIT
, file
);
2693 if (status
!= STATUS_SUCCESS
) return status
;
2695 offset
.QuadPart
= 0;
2698 status
= NtMapViewOfSection( mapping
, NtCurrentProcess(), &base
, 0, 0, &offset
,
2699 &count
, ViewShare
, 0, PAGE_READONLY
);
2701 if (status
!= STATUS_SUCCESS
) return status
;
2703 /* Fixme: WINE uses FileEndOfFileInformation with NtQueryInformationFile. */
2704 status
= NtQueryInformationFile( file
, &io
, &info
, sizeof(info
), FileStandardInformation
);
2706 if (status
== STATUS_SUCCESS
)
2707 status
= parse_manifest(acl
, ai
, filename
, directory
, shared
, base
, (SIZE_T
)info
.EndOfFile
.QuadPart
);
2709 NtUnmapViewOfSection( NtCurrentProcess(), base
);
2713 /* try to load the .manifest file associated to the file */
2714 static NTSTATUS
get_manifest_in_associated_manifest( struct actctx_loader
* acl
, struct assembly_identity
* ai
,
2715 LPCWSTR filename
, LPCWSTR directory
, HMODULE module
, LPCWSTR resname
)
2717 static const WCHAR fmtW
[] = { '.','%','l','u',0 };
2720 UNICODE_STRING nameW
;
2722 ULONG_PTR resid
= (ULONG_PTR
)CREATEPROCESS_MANIFEST_RESOURCE_ID
;
2724 if (!((ULONG_PTR
)resname
>> 16)) resid
= (ULONG_PTR
)resname
& 0xffff;
2726 DPRINT( "looking for manifest associated with %S id %lu\n", filename
, resid
);
2728 if (module
) /* use the module filename */
2730 UNICODE_STRING name
;
2732 if (!(status
= get_module_filename( module
, &name
, sizeof(dotManifestW
) + 10*sizeof(WCHAR
) )))
2734 if (resid
!= 1) sprintfW( name
.Buffer
+ strlenW(name
.Buffer
), fmtW
, resid
);
2735 strcatW( name
.Buffer
, dotManifestW
);
2736 if (!RtlDosPathNameToNtPathName_U( name
.Buffer
, &nameW
, NULL
, NULL
))
2737 status
= STATUS_RESOURCE_DATA_NOT_FOUND
;
2738 RtlFreeUnicodeString( &name
);
2740 if (status
) return status
;
2744 if (!(buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2745 (strlenW(filename
) + 10) * sizeof(WCHAR
) + sizeof(dotManifestW
) )))
2746 return STATUS_NO_MEMORY
;
2747 strcpyW( buffer
, filename
);
2748 if (resid
!= 1) sprintfW( buffer
+ strlenW(buffer
), fmtW
, resid
);
2749 strcatW( buffer
, dotManifestW
);
2750 RtlInitUnicodeString( &nameW
, buffer
);
2753 if (!open_nt_file( &file
, &nameW
))
2755 status
= get_manifest_in_manifest_file( acl
, ai
, nameW
.Buffer
, directory
, FALSE
, file
);
2758 else status
= STATUS_RESOURCE_TYPE_NOT_FOUND
;
2759 RtlFreeUnicodeString( &nameW
);
2763 static WCHAR
*lookup_manifest_file( HANDLE dir
, struct assembly_identity
*ai
)
2765 static const WCHAR lookup_fmtW
[] =
2766 {'%','s','_','%','s','_','%','s','_','%','u','.','%','u','.','*','.','*','_',
2768 '.','m','a','n','i','f','e','s','t',0};
2770 WCHAR
*lookup
, *ret
= NULL
;
2771 UNICODE_STRING lookup_us
;
2773 const WCHAR
*lang
= ai
->language
;
2774 unsigned int data_pos
= 0, data_len
;
2777 if (!(lookup
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2778 (strlenW(ai
->arch
) + strlenW(ai
->name
)
2779 + strlenW(ai
->public_key
) + 20) * sizeof(WCHAR
)
2780 + sizeof(lookup_fmtW
) )))
2783 if (!lang
|| !strcmpiW( lang
, neutralW
)) lang
= wildcardW
;
2784 sprintfW( lookup
, lookup_fmtW
, ai
->arch
, ai
->name
, ai
->public_key
,
2785 ai
->version
.major
, ai
->version
.minor
, lang
);
2786 RtlInitUnicodeString( &lookup_us
, lookup
);
2788 NtQueryDirectoryFile( dir
, 0, NULL
, NULL
, &io
, buffer
, sizeof(buffer
),
2789 FileBothDirectoryInformation
, FALSE
, &lookup_us
, TRUE
);
2790 if (io
.Status
== STATUS_SUCCESS
)
2792 FILE_BOTH_DIR_INFORMATION
*dir_info
;
2794 ULONG build
, revision
;
2796 data_len
= (ULONG
)io
.Information
;
2800 if (data_pos
>= data_len
)
2802 NtQueryDirectoryFile( dir
, 0, NULL
, NULL
, &io
, buffer
, sizeof(buffer
),
2803 FileBothDirectoryInformation
, FALSE
, &lookup_us
, FALSE
);
2804 if (io
.Status
!= STATUS_SUCCESS
) break;
2805 data_len
= (ULONG
)io
.Information
;
2808 dir_info
= (FILE_BOTH_DIR_INFORMATION
*)(buffer
+ data_pos
);
2810 if (dir_info
->NextEntryOffset
) data_pos
+= dir_info
->NextEntryOffset
;
2811 else data_pos
= data_len
;
2813 tmp
= (WCHAR
*)dir_info
->FileName
+ (strchrW(lookup
, '*') - lookup
);
2815 if (build
< ai
->version
.build
) continue;
2816 tmp
= strchrW(tmp
, '.') + 1;
2817 revision
= atoiW(tmp
);
2818 if (build
== ai
->version
.build
&& revision
< ai
->version
.revision
)
2820 ai
->version
.build
= (USHORT
)build
;
2821 ai
->version
.revision
= (USHORT
)revision
;
2823 if ((ret
= RtlAllocateHeap( RtlGetProcessHeap(), 0, dir_info
->FileNameLength
* sizeof(WCHAR
) )))
2825 memcpy( ret
, dir_info
->FileName
, dir_info
->FileNameLength
);
2826 ret
[dir_info
->FileNameLength
/sizeof(WCHAR
)] = 0;
2831 else DPRINT1("no matching file for %S\n", lookup
);
2832 RtlFreeHeap( RtlGetProcessHeap(), 0, lookup
);
2836 static NTSTATUS
lookup_winsxs(struct actctx_loader
* acl
, struct assembly_identity
* ai
)
2838 struct assembly_identity sxs_ai
;
2839 UNICODE_STRING path_us
;
2840 OBJECT_ATTRIBUTES attr
;
2842 WCHAR
*path
, *file
= NULL
;
2845 static const WCHAR manifest_dirW
[] =
2846 {'\\','w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s',0};
2848 if (!ai
->arch
|| !ai
->name
|| !ai
->public_key
) return STATUS_NO_SUCH_FILE
;
2850 if (!(path
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2851 ((strlenW(SharedUserData
->NtSystemRoot
) + 1) *sizeof(WCHAR
)) + sizeof(manifest_dirW
) )))
2852 return STATUS_NO_MEMORY
;
2854 memcpy( path
, SharedUserData
->NtSystemRoot
, strlenW(SharedUserData
->NtSystemRoot
) * sizeof(WCHAR
) );
2855 memcpy( path
+ strlenW(SharedUserData
->NtSystemRoot
), manifest_dirW
, sizeof(manifest_dirW
) );
2857 if (!RtlDosPathNameToNtPathName_U( path
, &path_us
, NULL
, NULL
))
2859 RtlFreeHeap( RtlGetProcessHeap(), 0, path
);
2860 return STATUS_NO_SUCH_FILE
;
2862 RtlFreeHeap( RtlGetProcessHeap(), 0, path
);
2864 attr
.Length
= sizeof(attr
);
2865 attr
.RootDirectory
= 0;
2866 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
2867 attr
.ObjectName
= &path_us
;
2868 attr
.SecurityDescriptor
= NULL
;
2869 attr
.SecurityQualityOfService
= NULL
;
2871 if (!NtOpenFile(&handle
,
2872 GENERIC_READ
| SYNCHRONIZE
,
2874 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2875 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
))
2878 file
= lookup_manifest_file( handle
, &sxs_ai
);
2883 RtlFreeUnicodeString( &path_us
);
2884 return STATUS_NO_SUCH_FILE
;
2887 /* append file name to directory path */
2888 if (!(path
= RtlReAllocateHeap( RtlGetProcessHeap(), 0, path_us
.Buffer
,
2889 path_us
.Length
+ (strlenW(file
) + 2) * sizeof(WCHAR
) )))
2891 RtlFreeHeap( RtlGetProcessHeap(), 0, file
);
2892 RtlFreeUnicodeString( &path_us
);
2893 return STATUS_NO_MEMORY
;
2896 path
[path_us
.Length
/sizeof(WCHAR
)] = '\\';
2897 strcpyW( path
+ path_us
.Length
/sizeof(WCHAR
) + 1, file
);
2898 RtlInitUnicodeString( &path_us
, path
);
2899 *strrchrW(file
, '.') = 0; /* remove .manifest extension */
2901 if (!open_nt_file( &handle
, &path_us
))
2903 io
.Status
= get_manifest_in_manifest_file(acl
, &sxs_ai
, path_us
.Buffer
, file
, TRUE
, handle
);
2906 else io
.Status
= STATUS_NO_SUCH_FILE
;
2908 RtlFreeHeap( RtlGetProcessHeap(), 0, file
);
2909 RtlFreeUnicodeString( &path_us
);
2913 static NTSTATUS
lookup_assembly(struct actctx_loader
* acl
,
2914 struct assembly_identity
* ai
)
2916 static const WCHAR dotDllW
[] = {'.','d','l','l',0};
2918 WCHAR
*buffer
, *p
, *directory
;
2920 UNICODE_STRING nameW
;
2924 DPRINT( "looking for name=%S version=%u.%u.%u.%u arch=%S\n",
2925 ai
->name
, ai
->version
.major
, ai
->version
.minor
, ai
->version
.build
, ai
->version
.revision
, ai
->arch
);
2927 if ((status
= lookup_winsxs(acl
, ai
)) != STATUS_NO_SUCH_FILE
) return status
;
2929 /* FIXME: add support for language specific lookup */
2931 len
= max(RtlGetFullPathName_U(acl
->actctx
->assemblies
->manifest
.info
, 0, NULL
, NULL
) / sizeof(WCHAR
),
2932 strlenW(acl
->actctx
->appdir
.info
));
2934 nameW
.Buffer
= NULL
;
2935 if (!(buffer
= RtlAllocateHeap( RtlGetProcessHeap(), 0,
2936 (len
+ 2 * strlenW(ai
->name
) + 2) * sizeof(WCHAR
) + sizeof(dotManifestW
) )))
2937 return STATUS_NO_MEMORY
;
2939 if (!(directory
= build_assembly_dir( ai
)))
2941 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
2942 return STATUS_NO_MEMORY
;
2945 /* Lookup in <dir>\name.dll
2946 * <dir>\name.manifest
2947 * <dir>\name\name.dll
2948 * <dir>\name\name.manifest
2950 * First 'appdir' is used as <dir>, if that failed
2951 * it tries application manifest file path.
2953 strcpyW( buffer
, acl
->actctx
->appdir
.info
);
2954 p
= buffer
+ strlenW(buffer
);
2955 for (i
= 0; i
< 4; i
++)
2959 struct assembly
*assembly
= acl
->actctx
->assemblies
;
2960 if (!RtlGetFullPathName_U(assembly
->manifest
.info
, len
* sizeof(WCHAR
), buffer
, &p
)) break;
2964 strcpyW( p
, ai
->name
);
2967 strcpyW( p
, dotDllW
);
2968 if (RtlDosPathNameToNtPathName_U( buffer
, &nameW
, NULL
, NULL
))
2970 status
= open_nt_file( &file
, &nameW
);
2973 status
= get_manifest_in_pe_file( acl
, ai
, nameW
.Buffer
, directory
, FALSE
, file
,
2974 (LPCWSTR
)CREATEPROCESS_MANIFEST_RESOURCE_ID
, 0 );
2978 RtlFreeUnicodeString( &nameW
);
2981 strcpyW( p
, dotManifestW
);
2982 if (RtlDosPathNameToNtPathName_U( buffer
, &nameW
, NULL
, NULL
))
2984 status
= open_nt_file( &file
, &nameW
);
2987 status
= get_manifest_in_manifest_file( acl
, ai
, nameW
.Buffer
, directory
, FALSE
, file
);
2991 RtlFreeUnicodeString( &nameW
);
2993 status
= STATUS_SXS_ASSEMBLY_NOT_FOUND
;
2995 RtlFreeUnicodeString( &nameW
);
2996 RtlFreeHeap( RtlGetProcessHeap(), 0, directory
);
2997 RtlFreeHeap( RtlGetProcessHeap(), 0, buffer
);
3001 static NTSTATUS
parse_depend_manifests(struct actctx_loader
* acl
)
3003 NTSTATUS status
= STATUS_SUCCESS
;
3006 for (i
= 0; i
< acl
->num_dependencies
; i
++)
3008 if (lookup_assembly(acl
, &acl
->dependencies
[i
]) != STATUS_SUCCESS
)
3010 if (!acl
->dependencies
[i
].optional
)
3012 const struct assembly_version
*ver
= &acl
->dependencies
[i
].version
;
3013 DPRINT1( "Could not find dependent assembly %S (%u.%u.%u.%u)\n",
3014 acl
->dependencies
[i
].name
,
3015 ver
->major
, ver
->minor
, ver
->build
, ver
->revision
);
3016 status
= STATUS_SXS_CANT_GEN_ACTCTX
;
3021 /* FIXME should now iterate through all refs */
3025 /* find the appropriate activation context for RtlQueryInformationActivationContext */
3026 static NTSTATUS
find_query_actctx( HANDLE
*handle
, DWORD flags
, ULONG
class )
3028 NTSTATUS status
= STATUS_SUCCESS
;
3030 if (flags
& RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT
)
3032 if (*handle
) return STATUS_INVALID_PARAMETER
;
3034 if (NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
3035 *handle
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
->ActivationContext
;
3037 else if (flags
& (RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_ADDRESS
| RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE
))
3040 LDR_DATA_TABLE_ENTRY
*pldr
;
3042 if (!*handle
) return STATUS_INVALID_PARAMETER
;
3044 LdrLockLoaderLock( 0, NULL
, &magic
);
3045 if (!LdrFindEntryForAddress( *handle
, &pldr
))
3047 if ((flags
& RTL_QUERY_ACTIVATION_CONTEXT_FLAG_IS_HMODULE
) && *handle
!= pldr
->DllBase
)
3048 status
= STATUS_DLL_NOT_FOUND
;
3050 *handle
= pldr
->EntryPointActivationContext
;
3052 else status
= STATUS_DLL_NOT_FOUND
;
3053 LdrUnlockLoaderLock( 0, magic
);
3055 else if (!*handle
&& (class != ActivationContextBasicInformation
))
3056 *handle
= process_actctx
;
3061 static NTSTATUS
build_dllredirect_section(ACTIVATION_CONTEXT
* actctx
, struct strsection_header
**section
)
3063 unsigned int i
, j
, total_len
= 0, dll_count
= 0;
3064 struct strsection_header
*header
;
3065 struct dllredirect_data
*data
;
3066 struct string_index
*index
;
3069 /* compute section length */
3070 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3072 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3073 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3075 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3077 /* each entry needs index, data and string data */
3078 total_len
+= sizeof(*index
);
3079 total_len
+= sizeof(*data
);
3080 total_len
+= aligned_string_len((strlenW(dll
->name
)+1)*sizeof(WCHAR
));
3083 dll_count
+= assembly
->num_dlls
;
3086 total_len
+= sizeof(*header
);
3088 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
3089 if (!header
) return STATUS_NO_MEMORY
;
3091 memset(header
, 0, sizeof(*header
));
3092 header
->magic
= STRSECTION_MAGIC
;
3093 header
->size
= sizeof(*header
);
3094 header
->count
= dll_count
;
3095 header
->index_offset
= sizeof(*header
);
3096 index
= (struct string_index
*)((BYTE
*)header
+ header
->index_offset
);
3097 name_offset
= header
->index_offset
+ header
->count
*sizeof(*index
);
3099 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3101 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3102 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3104 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3108 /* setup new index entry */
3109 str
.Buffer
= dll
->name
;
3110 str
.Length
= strlenW(dll
->name
)*sizeof(WCHAR
);
3111 str
.MaximumLength
= str
.Length
+ sizeof(WCHAR
);
3112 /* hash original class name */
3113 RtlHashUnicodeString(&str
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &index
->hash
);
3115 index
->name_offset
= name_offset
;
3116 index
->name_len
= str
.Length
;
3117 index
->data_offset
= index
->name_offset
+ aligned_string_len(str
.MaximumLength
);
3118 index
->data_len
= sizeof(*data
);
3119 index
->rosterindex
= i
+ 1;
3122 data
= (struct dllredirect_data
*)((BYTE
*)header
+ index
->data_offset
);
3123 data
->size
= sizeof(*data
);
3124 data
->unk
= 2; /* FIXME: seems to be constant */
3125 memset(data
->res
, 0, sizeof(data
->res
));
3128 ptrW
= (WCHAR
*)((BYTE
*)header
+ index
->name_offset
);
3129 memcpy(ptrW
, dll
->name
, index
->name_len
);
3130 ptrW
[index
->name_len
/sizeof(WCHAR
)] = 0;
3132 name_offset
+= sizeof(*data
) + aligned_string_len(str
.MaximumLength
);
3140 return STATUS_SUCCESS
;
3143 static struct string_index
*find_string_index(const struct strsection_header
*section
, const UNICODE_STRING
*name
)
3145 struct string_index
*iter
, *index
= NULL
;
3148 RtlHashUnicodeString(name
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &hash
);
3149 iter
= (struct string_index
*)((BYTE
*)section
+ section
->index_offset
);
3151 for (i
= 0; i
< section
->count
; i
++)
3153 if (iter
->hash
== hash
)
3155 const WCHAR
*nameW
= (WCHAR
*)((BYTE
*)section
+ iter
->name_offset
);
3157 if (!strcmpiW(nameW
, name
->Buffer
))
3163 DPRINT1("hash collision 0x%08x, %wZ, %S\n", hash
, name
, nameW
);
3171 static struct guid_index
*find_guid_index(const struct guidsection_header
*section
, const GUID
*guid
)
3173 struct guid_index
*iter
, *index
= NULL
;
3176 iter
= (struct guid_index
*)((BYTE
*)section
+ section
->index_offset
);
3178 for (i
= 0; i
< section
->count
; i
++)
3180 if (!memcmp(guid
, &iter
->guid
, sizeof(*guid
)))
3191 static inline struct dllredirect_data
*get_dllredirect_data(ACTIVATION_CONTEXT
*ctxt
, struct string_index
*index
)
3193 return (struct dllredirect_data
*)((BYTE
*)ctxt
->dllredirect_section
+ index
->data_offset
);
3196 static NTSTATUS
find_dll_redirection(ACTIVATION_CONTEXT
* actctx
, const UNICODE_STRING
*name
,
3197 PACTCTX_SECTION_KEYED_DATA data
)
3199 struct dllredirect_data
*dll
;
3200 struct string_index
*index
;
3202 if (!(actctx
->sections
& DLLREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
3204 if (!actctx
->dllredirect_section
)
3206 struct strsection_header
*section
;
3208 NTSTATUS status
= build_dllredirect_section(actctx
, §ion
);
3209 if (status
) return status
;
3211 if (InterlockedCompareExchangePointer((void**)&actctx
->dllredirect_section
, section
, NULL
))
3212 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
3215 index
= find_string_index(actctx
->dllredirect_section
, name
);
3216 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
3218 dll
= get_dllredirect_data(actctx
, index
);
3220 data
->ulDataFormatVersion
= 1;
3222 data
->ulLength
= dll
->size
;
3223 data
->lpSectionGlobalData
= NULL
;
3224 data
->ulSectionGlobalDataLength
= 0;
3225 data
->lpSectionBase
= actctx
->dllredirect_section
;
3226 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->dllredirect_section
);
3227 data
->hActCtx
= NULL
;
3229 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
3230 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
3232 return STATUS_SUCCESS
;
3235 static inline struct string_index
*get_wndclass_first_index(ACTIVATION_CONTEXT
*actctx
)
3237 return (struct string_index
*)((BYTE
*)actctx
->wndclass_section
+ actctx
->wndclass_section
->index_offset
);
3240 static inline struct wndclass_redirect_data
*get_wndclass_data(ACTIVATION_CONTEXT
*ctxt
, struct string_index
*index
)
3242 return (struct wndclass_redirect_data
*)((BYTE
*)ctxt
->wndclass_section
+ index
->data_offset
);
3245 static NTSTATUS
build_wndclass_section(ACTIVATION_CONTEXT
* actctx
, struct strsection_header
**section
)
3247 unsigned int i
, j
, k
, total_len
= 0, class_count
= 0;
3248 struct wndclass_redirect_data
*data
;
3249 struct strsection_header
*header
;
3250 struct string_index
*index
;
3253 /* compute section length */
3254 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3256 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3257 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3259 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3260 for (k
= 0; k
< dll
->entities
.num
; k
++)
3262 struct entity
*entity
= &dll
->entities
.base
[k
];
3263 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
)
3265 int class_len
= strlenW(entity
->u
.class.name
) + 1;
3268 /* each class entry needs index, data and string data */
3269 total_len
+= sizeof(*index
);
3270 total_len
+= sizeof(*data
);
3271 /* original name is stored separately */
3272 total_len
+= aligned_string_len(class_len
*sizeof(WCHAR
));
3273 /* versioned name and module name are stored one after another */
3274 if (entity
->u
.class.versioned
)
3275 len
= get_assembly_version(assembly
, NULL
) + class_len
+ 1 /* '!' separator */;
3278 len
+= strlenW(dll
->name
) + 1;
3279 total_len
+= aligned_string_len(len
*sizeof(WCHAR
));
3287 total_len
+= sizeof(*header
);
3289 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
3290 if (!header
) return STATUS_NO_MEMORY
;
3292 memset(header
, 0, sizeof(*header
));
3293 header
->magic
= STRSECTION_MAGIC
;
3294 header
->size
= sizeof(*header
);
3295 header
->count
= class_count
;
3296 header
->index_offset
= sizeof(*header
);
3297 index
= (struct string_index
*)((BYTE
*)header
+ header
->index_offset
);
3298 name_offset
= header
->index_offset
+ header
->count
*sizeof(*index
);
3300 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3302 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3303 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3305 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3306 for (k
= 0; k
< dll
->entities
.num
; k
++)
3308 struct entity
*entity
= &dll
->entities
.base
[k
];
3309 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
)
3311 static const WCHAR exclW
[] = {'!',0};
3312 ULONG versioned_len
, module_len
;
3316 /* setup new index entry */
3317 str
.Buffer
= entity
->u
.class.name
;
3318 str
.Length
= strlenW(entity
->u
.class.name
)*sizeof(WCHAR
);
3319 str
.MaximumLength
= str
.Length
+ sizeof(WCHAR
);
3320 /* hash original class name */
3321 RtlHashUnicodeString(&str
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &index
->hash
);
3323 /* include '!' separator too */
3324 if (entity
->u
.class.versioned
)
3325 versioned_len
= (get_assembly_version(assembly
, NULL
) + 1)*sizeof(WCHAR
) + str
.Length
;
3327 versioned_len
= str
.Length
;
3328 module_len
= strlenW(dll
->name
)*sizeof(WCHAR
);
3330 index
->name_offset
= name_offset
;
3331 index
->name_len
= str
.Length
;
3332 index
->data_offset
= index
->name_offset
+ aligned_string_len(str
.MaximumLength
);
3333 index
->data_len
= sizeof(*data
) + versioned_len
+ module_len
+ 2*sizeof(WCHAR
) /* two nulls */;
3334 index
->rosterindex
= i
+ 1;
3337 data
= (struct wndclass_redirect_data
*)((BYTE
*)header
+ index
->data_offset
);
3338 data
->size
= sizeof(*data
);
3340 data
->name_len
= versioned_len
;
3341 data
->name_offset
= sizeof(*data
);
3342 data
->module_len
= module_len
;
3343 data
->module_offset
= index
->data_offset
+ data
->name_offset
+ data
->name_len
+ sizeof(WCHAR
);
3345 /* original class name */
3346 ptrW
= (WCHAR
*)((BYTE
*)header
+ index
->name_offset
);
3347 memcpy(ptrW
, entity
->u
.class.name
, index
->name_len
);
3348 ptrW
[index
->name_len
/sizeof(WCHAR
)] = 0;
3351 ptrW
= (WCHAR
*)((BYTE
*)header
+ data
->module_offset
);
3352 memcpy(ptrW
, dll
->name
, data
->module_len
);
3353 ptrW
[data
->module_len
/sizeof(WCHAR
)] = 0;
3355 /* versioned name */
3356 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->name_offset
);
3357 if (entity
->u
.class.versioned
)
3359 get_assembly_version(assembly
, ptrW
);
3360 strcatW(ptrW
, exclW
);
3361 strcatW(ptrW
, entity
->u
.class.name
);
3365 memcpy(ptrW
, entity
->u
.class.name
, index
->name_len
);
3366 ptrW
[index
->name_len
/sizeof(WCHAR
)] = 0;
3369 name_offset
+= sizeof(*data
);
3370 name_offset
+= aligned_string_len(str
.MaximumLength
) + aligned_string_len(versioned_len
+ module_len
+ 2*sizeof(WCHAR
));
3380 return STATUS_SUCCESS
;
3383 static NTSTATUS
find_window_class(ACTIVATION_CONTEXT
* actctx
, const UNICODE_STRING
*name
,
3384 PACTCTX_SECTION_KEYED_DATA data
)
3386 struct string_index
*iter
, *index
= NULL
;
3387 struct wndclass_redirect_data
*class;
3391 if (!(actctx
->sections
& WINDOWCLASS_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
3393 if (!actctx
->wndclass_section
)
3395 struct strsection_header
*section
;
3397 NTSTATUS status
= build_wndclass_section(actctx
, §ion
);
3398 if (status
) return status
;
3400 if (InterlockedCompareExchangePointer((void**)&actctx
->wndclass_section
, section
, NULL
))
3401 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
3405 RtlHashUnicodeString(name
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &hash
);
3406 iter
= get_wndclass_first_index(actctx
);
3408 for (i
= 0; i
< actctx
->wndclass_section
->count
; i
++)
3410 if (iter
->hash
== hash
)
3412 const WCHAR
*nameW
= (WCHAR
*)((BYTE
*)actctx
->wndclass_section
+ iter
->name_offset
);
3414 if (!strcmpW(nameW
, name
->Buffer
))
3420 DPRINT1("hash collision 0x%08x, %wZ, %S\n", hash
, name
, nameW
);
3425 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
3427 class = get_wndclass_data(actctx
, index
);
3429 data
->ulDataFormatVersion
= 1;
3430 data
->lpData
= class;
3431 /* full length includes string length with nulls */
3432 data
->ulLength
= class->size
+ class->name_len
+ class->module_len
+ 2*sizeof(WCHAR
);
3433 data
->lpSectionGlobalData
= NULL
;
3434 data
->ulSectionGlobalDataLength
= 0;
3435 data
->lpSectionBase
= actctx
->wndclass_section
;
3436 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->wndclass_section
);
3437 data
->hActCtx
= NULL
;
3439 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
3440 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
3442 return STATUS_SUCCESS
;
3445 static NTSTATUS
build_tlib_section(ACTIVATION_CONTEXT
* actctx
, struct guidsection_header
**section
)
3447 unsigned int i
, j
, k
, total_len
= 0, tlib_count
= 0, names_len
= 0;
3448 struct guidsection_header
*header
;
3449 ULONG module_offset
, data_offset
;
3450 struct tlibredirect_data
*data
;
3451 struct guid_index
*index
;
3453 /* compute section length */
3454 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3456 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3457 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3459 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3460 for (k
= 0; k
< dll
->entities
.num
; k
++)
3462 struct entity
*entity
= &dll
->entities
.base
[k
];
3463 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
)
3465 /* each entry needs index, data and string data for module name and help string */
3466 total_len
+= sizeof(*index
);
3467 total_len
+= sizeof(*data
);
3468 /* help string is stored separately */
3469 if (*entity
->u
.typelib
.helpdir
)
3470 total_len
+= aligned_string_len((strlenW(entity
->u
.typelib
.helpdir
)+1)*sizeof(WCHAR
));
3472 /* module names are packed one after another */
3473 names_len
+= (strlenW(dll
->name
)+1)*sizeof(WCHAR
);
3481 total_len
+= aligned_string_len(names_len
);
3482 total_len
+= sizeof(*header
);
3484 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
3485 if (!header
) return STATUS_NO_MEMORY
;
3487 memset(header
, 0, sizeof(*header
));
3488 header
->magic
= GUIDSECTION_MAGIC
;
3489 header
->size
= sizeof(*header
);
3490 header
->count
= tlib_count
;
3491 header
->index_offset
= sizeof(*header
) + aligned_string_len(names_len
);
3492 index
= (struct guid_index
*)((BYTE
*)header
+ header
->index_offset
);
3493 module_offset
= sizeof(*header
);
3494 data_offset
= header
->index_offset
+ tlib_count
*sizeof(*index
);
3496 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3498 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3499 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3501 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3502 for (k
= 0; k
< dll
->entities
.num
; k
++)
3504 struct entity
*entity
= &dll
->entities
.base
[k
];
3505 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
)
3507 ULONG module_len
, help_len
;
3511 if (*entity
->u
.typelib
.helpdir
)
3512 help_len
= strlenW(entity
->u
.typelib
.helpdir
)*sizeof(WCHAR
);
3516 module_len
= strlenW(dll
->name
)*sizeof(WCHAR
);
3518 /* setup new index entry */
3519 RtlInitUnicodeString(&str
, entity
->u
.typelib
.tlbid
);
3520 RtlGUIDFromString(&str
, &index
->guid
);
3521 index
->data_offset
= data_offset
;
3522 index
->data_len
= sizeof(*data
) + aligned_string_len(help_len
);
3523 index
->rosterindex
= i
+ 1;
3526 data
= (struct tlibredirect_data
*)((BYTE
*)header
+ index
->data_offset
);
3527 data
->size
= sizeof(*data
);
3529 data
->name_len
= module_len
;
3530 data
->name_offset
= module_offset
;
3531 /* FIXME: resourceid handling is really weird, and it doesn't seem to be useful */
3533 data
->flags
= entity
->u
.typelib
.flags
;
3534 data
->help_len
= help_len
;
3535 data
->help_offset
= sizeof(*data
);
3536 data
->major_version
= entity
->u
.typelib
.major
;
3537 data
->minor_version
= entity
->u
.typelib
.minor
;
3540 ptrW
= (WCHAR
*)((BYTE
*)header
+ data
->name_offset
);
3541 memcpy(ptrW
, dll
->name
, data
->name_len
);
3542 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
3547 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->help_offset
);
3548 memcpy(ptrW
, entity
->u
.typelib
.helpdir
, data
->help_len
);
3549 ptrW
[data
->help_len
/sizeof(WCHAR
)] = 0;
3552 data_offset
+= sizeof(*data
);
3554 data_offset
+= aligned_string_len(help_len
+ sizeof(WCHAR
));
3556 module_offset
+= module_len
+ sizeof(WCHAR
);
3566 return STATUS_SUCCESS
;
3569 static inline struct tlibredirect_data
*get_tlib_data(ACTIVATION_CONTEXT
*actctx
, struct guid_index
*index
)
3571 return (struct tlibredirect_data
*)((BYTE
*)actctx
->tlib_section
+ index
->data_offset
);
3574 static NTSTATUS
find_tlib_redirection(ACTIVATION_CONTEXT
* actctx
, const GUID
*guid
, ACTCTX_SECTION_KEYED_DATA
* data
)
3576 struct guid_index
*index
= NULL
;
3577 struct tlibredirect_data
*tlib
;
3579 if (!(actctx
->sections
& TLIBREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
3581 if (!actctx
->tlib_section
)
3583 struct guidsection_header
*section
;
3585 NTSTATUS status
= build_tlib_section(actctx
, §ion
);
3586 if (status
) return status
;
3588 if (InterlockedCompareExchangePointer((void**)&actctx
->tlib_section
, section
, NULL
))
3589 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
3592 index
= find_guid_index(actctx
->tlib_section
, guid
);
3593 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
3595 tlib
= get_tlib_data(actctx
, index
);
3597 data
->ulDataFormatVersion
= 1;
3598 data
->lpData
= tlib
;
3599 /* full length includes string length with nulls */
3600 data
->ulLength
= tlib
->size
+ tlib
->help_len
+ sizeof(WCHAR
);
3601 data
->lpSectionGlobalData
= (BYTE
*)actctx
->tlib_section
+ actctx
->tlib_section
->names_offset
;
3602 data
->ulSectionGlobalDataLength
= actctx
->tlib_section
->names_len
;
3603 data
->lpSectionBase
= actctx
->tlib_section
;
3604 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->tlib_section
);
3605 data
->hActCtx
= NULL
;
3607 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
3608 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
3610 return STATUS_SUCCESS
;
3613 static void generate_uuid(ULONG
*seed
, GUID
*guid
)
3615 ULONG
*ptr
= (ULONG
*)guid
;
3618 /* GUID is 16 bytes long */
3619 for (i
= 0; i
< sizeof(GUID
)/sizeof(ULONG
); i
++, ptr
++)
3620 *ptr
= RtlUniform(seed
);
3622 guid
->Data3
&= 0x0fff;
3623 guid
->Data3
|= (4 << 12);
3624 guid
->Data4
[0] &= 0x3f;
3625 guid
->Data4
[0] |= 0x80;
3628 static void get_comserver_datalen(const struct entity_array
*entities
, const struct dll_redirect
*dll
,
3629 unsigned int *count
, unsigned int *len
, unsigned int *module_len
)
3633 for (i
= 0; i
< entities
->num
; i
++)
3635 struct entity
*entity
= &entities
->base
[i
];
3636 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)
3638 /* each entry needs two index entries, extra one goes for alias GUID */
3639 *len
+= 2*sizeof(struct guid_index
);
3640 /* To save some memory we don't allocated two data structures,
3641 instead alias index and normal index point to the same data structure. */
3642 *len
+= sizeof(struct comclassredirect_data
);
3644 /* for clrClass store some more */
3645 if (entity
->u
.comclass
.name
)
3647 unsigned int str_len
;
3649 /* all string data is stored together in aligned block */
3650 str_len
= strlenW(entity
->u
.comclass
.name
)+1;
3651 if (entity
->u
.comclass
.progid
)
3652 str_len
+= strlenW(entity
->u
.comclass
.progid
)+1;
3653 if (entity
->u
.comclass
.version
)
3654 str_len
+= strlenW(entity
->u
.comclass
.version
)+1;
3656 *len
+= sizeof(struct clrclass_data
);
3657 *len
+= aligned_string_len(str_len
*sizeof(WCHAR
));
3659 /* module name is forced to mscoree.dll, and stored two times with different case */
3660 *module_len
+= sizeof(mscoreeW
) + sizeof(mscoree2W
);
3664 /* progid string is stored separately */
3665 if (entity
->u
.comclass
.progid
)
3666 *len
+= aligned_string_len((strlenW(entity
->u
.comclass
.progid
)+1)*sizeof(WCHAR
));
3668 *module_len
+= (strlenW(dll
->name
)+1)*sizeof(WCHAR
);
3676 static void add_comserver_record(const struct guidsection_header
*section
, const struct entity_array
*entities
,
3677 const struct dll_redirect
*dll
, struct guid_index
**index
, ULONG
*data_offset
, ULONG
*module_offset
,
3678 ULONG
*seed
, ULONG rosterindex
)
3682 for (i
= 0; i
< entities
->num
; i
++)
3684 struct entity
*entity
= &entities
->base
[i
];
3685 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)
3687 ULONG module_len
, progid_len
, str_len
= 0;
3688 struct comclassredirect_data
*data
;
3689 struct guid_index
*alias_index
;
3690 struct clrclass_data
*clrdata
;
3694 if (entity
->u
.comclass
.progid
)
3695 progid_len
= strlenW(entity
->u
.comclass
.progid
)*sizeof(WCHAR
);
3699 module_len
= dll
? strlenW(dll
->name
)*sizeof(WCHAR
) : strlenW(mscoreeW
)*sizeof(WCHAR
);
3701 /* setup new index entry */
3702 RtlInitUnicodeString(&str
, entity
->u
.comclass
.clsid
);
3703 RtlGUIDFromString(&str
, &(*index
)->guid
);
3705 (*index
)->data_offset
= *data_offset
;
3706 (*index
)->data_len
= sizeof(*data
); /* additional length added later */
3707 (*index
)->rosterindex
= rosterindex
;
3709 /* Setup new index entry for alias guid. Alias index records are placed after
3710 normal records, so normal guids are hit first on search. Note that class count
3712 alias_index
= (*index
) + section
->count
/2;
3713 generate_uuid(seed
, &alias_index
->guid
);
3714 alias_index
->data_offset
= (*index
)->data_offset
;
3715 alias_index
->data_len
= 0;
3716 alias_index
->rosterindex
= (*index
)->rosterindex
;
3719 data
= (struct comclassredirect_data
*)((BYTE
*)section
+ (*index
)->data_offset
);
3720 data
->size
= sizeof(*data
);
3724 data
->model
= entity
->u
.comclass
.model
;
3725 data
->clsid
= (*index
)->guid
;
3726 data
->alias
= alias_index
->guid
;
3727 data
->clsid2
= data
->clsid
;
3728 if (entity
->u
.comclass
.tlbid
)
3730 RtlInitUnicodeString(&str
, entity
->u
.comclass
.tlbid
);
3731 RtlGUIDFromString(&str
, &data
->tlbid
);
3734 memset(&data
->tlbid
, 0, sizeof(data
->tlbid
));
3735 data
->name_len
= module_len
;
3736 data
->name_offset
= *module_offset
;
3737 data
->progid_len
= progid_len
;
3738 data
->progid_offset
= data
->progid_len
? data
->size
: 0; /* in case of clrClass additional offset is added later */
3739 data
->clrdata_len
= 0; /* will be set later */
3740 data
->clrdata_offset
= entity
->u
.comclass
.name
? sizeof(*data
) : 0;
3741 data
->miscstatus
= entity
->u
.comclass
.miscstatus
;
3742 data
->miscstatuscontent
= entity
->u
.comclass
.miscstatuscontent
;
3743 data
->miscstatusthumbnail
= entity
->u
.comclass
.miscstatusthumbnail
;
3744 data
->miscstatusicon
= entity
->u
.comclass
.miscstatusicon
;
3745 data
->miscstatusdocprint
= entity
->u
.comclass
.miscstatusdocprint
;
3747 /* mask describes which misc* data is available */
3749 if (data
->miscstatus
)
3750 data
->miscmask
|= MiscStatus
;
3751 if (data
->miscstatuscontent
)
3752 data
->miscmask
|= MiscStatusContent
;
3753 if (data
->miscstatusthumbnail
)
3754 data
->miscmask
|= MiscStatusThumbnail
;
3755 if (data
->miscstatusicon
)
3756 data
->miscmask
|= MiscStatusIcon
;
3757 if (data
->miscstatusdocprint
)
3758 data
->miscmask
|= MiscStatusDocPrint
;
3760 if (data
->clrdata_offset
)
3762 clrdata
= (struct clrclass_data
*)((BYTE
*)data
+ data
->clrdata_offset
);
3764 clrdata
->size
= sizeof(*clrdata
);
3765 clrdata
->res
[0] = 0;
3766 clrdata
->res
[1] = 2; /* FIXME: unknown field */
3767 clrdata
->module_len
= strlenW(mscoreeW
)*sizeof(WCHAR
);
3768 clrdata
->module_offset
= *module_offset
+ data
->name_len
+ sizeof(WCHAR
);
3769 clrdata
->name_len
= strlenW(entity
->u
.comclass
.name
)*sizeof(WCHAR
);
3770 clrdata
->name_offset
= clrdata
->size
;
3771 clrdata
->version_len
= entity
->u
.comclass
.version
? strlenW(entity
->u
.comclass
.version
)*sizeof(WCHAR
) : 0;
3772 clrdata
->version_offset
= clrdata
->version_len
? clrdata
->name_offset
+ clrdata
->name_len
+ sizeof(WCHAR
) : 0;
3773 clrdata
->res2
[0] = 0;
3774 clrdata
->res2
[1] = 0;
3776 data
->clrdata_len
= clrdata
->size
+ clrdata
->name_len
+ sizeof(WCHAR
);
3779 ptrW
= (WCHAR
*)((BYTE
*)section
+ clrdata
->module_offset
);
3780 memcpy(ptrW
, mscoree2W
, clrdata
->module_len
);
3781 ptrW
[clrdata
->module_len
/sizeof(WCHAR
)] = 0;
3783 ptrW
= (WCHAR
*)((BYTE
*)section
+ data
->name_offset
);
3784 memcpy(ptrW
, mscoreeW
, data
->name_len
);
3785 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
3788 ptrW
= (WCHAR
*)((BYTE
*)clrdata
+ clrdata
->name_offset
);
3789 memcpy(ptrW
, entity
->u
.comclass
.name
, clrdata
->name_len
);
3790 ptrW
[clrdata
->name_len
/sizeof(WCHAR
)] = 0;
3792 /* runtime version, optional */
3793 if (clrdata
->version_len
)
3795 data
->clrdata_len
+= clrdata
->version_len
+ sizeof(WCHAR
);
3797 ptrW
= (WCHAR
*)((BYTE
*)clrdata
+ clrdata
->version_offset
);
3798 memcpy(ptrW
, entity
->u
.comclass
.version
, clrdata
->version_len
);
3799 ptrW
[clrdata
->version_len
/sizeof(WCHAR
)] = 0;
3802 if (data
->progid_len
)
3803 data
->progid_offset
+= data
->clrdata_len
;
3804 (*index
)->data_len
+= sizeof(*clrdata
);
3811 ptrW
= (WCHAR
*)((BYTE
*)section
+ data
->name_offset
);
3812 memcpy(ptrW
, dll
->name
, data
->name_len
);
3813 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
3817 if (data
->progid_len
)
3819 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->progid_offset
);
3820 memcpy(ptrW
, entity
->u
.comclass
.progid
, data
->progid_len
);
3821 ptrW
[data
->progid_len
/sizeof(WCHAR
)] = 0;
3824 /* string block length */
3828 str_len
+= clrdata
->name_len
+ sizeof(WCHAR
);
3829 if (clrdata
->version_len
)
3830 str_len
+= clrdata
->version_len
+ sizeof(WCHAR
);
3833 str_len
+= progid_len
+ sizeof(WCHAR
);
3835 (*index
)->data_len
+= aligned_string_len(str_len
);
3836 alias_index
->data_len
= (*index
)->data_len
;
3838 /* move to next data record */
3839 (*data_offset
) += sizeof(*data
) + aligned_string_len(str_len
);
3840 (*module_offset
) += module_len
+ sizeof(WCHAR
);
3844 (*data_offset
) += sizeof(*clrdata
);
3845 (*module_offset
) += clrdata
->module_len
+ sizeof(WCHAR
);
3852 static NTSTATUS
build_comserver_section(ACTIVATION_CONTEXT
* actctx
, struct guidsection_header
**section
)
3854 unsigned int i
, j
, total_len
= 0, class_count
= 0, names_len
= 0;
3855 struct guidsection_header
*header
;
3856 ULONG module_offset
, data_offset
;
3857 struct guid_index
*index
;
3860 /* compute section length */
3861 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3863 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3864 get_comserver_datalen(&assembly
->entities
, NULL
, &class_count
, &total_len
, &names_len
);
3865 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3867 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3868 get_comserver_datalen(&dll
->entities
, dll
, &class_count
, &total_len
, &names_len
);
3872 total_len
+= aligned_string_len(names_len
);
3873 total_len
+= sizeof(*header
);
3875 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
3876 if (!header
) return STATUS_NO_MEMORY
;
3878 memset(header
, 0, sizeof(*header
));
3879 header
->magic
= GUIDSECTION_MAGIC
;
3880 header
->size
= sizeof(*header
);
3881 header
->count
= 2*class_count
;
3882 header
->index_offset
= sizeof(*header
) + aligned_string_len(names_len
);
3883 index
= (struct guid_index
*)((BYTE
*)header
+ header
->index_offset
);
3884 module_offset
= sizeof(*header
);
3885 data_offset
= header
->index_offset
+ 2*class_count
*sizeof(*index
);
3887 seed
= NtGetTickCount();
3888 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
3890 struct assembly
*assembly
= &actctx
->assemblies
[i
];
3891 add_comserver_record(header
, &assembly
->entities
, NULL
, &index
, &data_offset
, &module_offset
, &seed
, i
+1);
3892 for (j
= 0; j
< assembly
->num_dlls
; j
++)
3894 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
3895 add_comserver_record(header
, &dll
->entities
, dll
, &index
, &data_offset
, &module_offset
, &seed
, i
+1);
3901 return STATUS_SUCCESS
;
3904 static inline struct comclassredirect_data
*get_comclass_data(ACTIVATION_CONTEXT
*actctx
, struct guid_index
*index
)
3906 return (struct comclassredirect_data
*)((BYTE
*)actctx
->comserver_section
+ index
->data_offset
);
3909 static NTSTATUS
find_comserver_redirection(ACTIVATION_CONTEXT
* actctx
, const GUID
*guid
, ACTCTX_SECTION_KEYED_DATA
* data
)
3911 struct comclassredirect_data
*comclass
;
3912 struct guid_index
*index
= NULL
;
3914 if (!(actctx
->sections
& SERVERREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
3916 if (!actctx
->comserver_section
)
3918 struct guidsection_header
*section
;
3920 NTSTATUS status
= build_comserver_section(actctx
, §ion
);
3921 if (status
) return status
;
3923 if (InterlockedCompareExchangePointer((void**)&actctx
->comserver_section
, section
, NULL
))
3924 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
3927 index
= find_guid_index(actctx
->comserver_section
, guid
);
3928 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
3930 comclass
= get_comclass_data(actctx
, index
);
3932 data
->ulDataFormatVersion
= 1;
3933 data
->lpData
= comclass
;
3934 /* full length includes string length with nulls */
3935 data
->ulLength
= comclass
->size
+ comclass
->clrdata_len
;
3936 if (comclass
->progid_len
) data
->ulLength
+= comclass
->progid_len
+ sizeof(WCHAR
);
3937 data
->lpSectionGlobalData
= (BYTE
*)actctx
->comserver_section
+ actctx
->comserver_section
->names_offset
;
3938 data
->ulSectionGlobalDataLength
= actctx
->comserver_section
->names_len
;
3939 data
->lpSectionBase
= actctx
->comserver_section
;
3940 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->comserver_section
);
3941 data
->hActCtx
= NULL
;
3943 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
3944 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
3946 return STATUS_SUCCESS
;
3949 static void get_ifaceps_datalen(const struct entity_array
*entities
, unsigned int *count
, unsigned int *len
)
3953 for (i
= 0; i
< entities
->num
; i
++)
3955 struct entity
*entity
= &entities
->base
[i
];
3956 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
)
3958 *len
+= sizeof(struct guid_index
) + sizeof(struct ifacepsredirect_data
);
3959 if (entity
->u
.ifaceps
.name
)
3960 *len
+= aligned_string_len((strlenW(entity
->u
.ifaceps
.name
)+1)*sizeof(WCHAR
));
3966 static void add_ifaceps_record(struct guidsection_header
*section
, struct entity_array
*entities
,
3967 struct guid_index
**index
, ULONG
*data_offset
, ULONG rosterindex
)
3971 for (i
= 0; i
< entities
->num
; i
++)
3973 struct entity
*entity
= &entities
->base
[i
];
3974 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
)
3976 struct ifacepsredirect_data
*data
= (struct ifacepsredirect_data
*)((BYTE
*)section
+ *data_offset
);
3980 if (entity
->u
.ifaceps
.name
)
3981 name_len
= strlenW(entity
->u
.ifaceps
.name
)*sizeof(WCHAR
);
3986 RtlInitUnicodeString(&str
, entity
->u
.ifaceps
.iid
);
3987 RtlGUIDFromString(&str
, &(*index
)->guid
);
3988 (*index
)->data_offset
= *data_offset
;
3989 (*index
)->data_len
= sizeof(*data
) + name_len
? aligned_string_len(name_len
+ sizeof(WCHAR
)) : 0;
3990 (*index
)->rosterindex
= rosterindex
;
3992 /* setup data record */
3993 data
->size
= sizeof(*data
);
3994 data
->mask
= entity
->u
.ifaceps
.mask
;
3996 /* proxyStubClsid32 value is only stored for external PS,
3997 if set it's used as iid, otherwise 'iid' attribute value is used */
3998 if (entity
->u
.ifaceps
.ps32
)
4000 RtlInitUnicodeString(&str
, entity
->u
.ifaceps
.ps32
);
4001 RtlGUIDFromString(&str
, &data
->iid
);
4004 data
->iid
= (*index
)->guid
;
4006 data
->nummethods
= entity
->u
.ifaceps
.nummethods
;
4008 if (entity
->u
.ifaceps
.tlib
)
4010 RtlInitUnicodeString(&str
, entity
->u
.ifaceps
.tlib
);
4011 RtlGUIDFromString(&str
, &data
->tlbid
);
4014 memset(&data
->tlbid
, 0, sizeof(data
->tlbid
));
4016 if (entity
->u
.ifaceps
.base
)
4018 RtlInitUnicodeString(&str
, entity
->u
.ifaceps
.base
);
4019 RtlGUIDFromString(&str
, &data
->base
);
4022 memset(&data
->base
, 0, sizeof(data
->base
));
4024 data
->name_len
= name_len
;
4025 data
->name_offset
= data
->name_len
? sizeof(*data
) : 0;
4030 WCHAR
*ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->name_offset
);
4031 memcpy(ptrW
, entity
->u
.ifaceps
.name
, data
->name_len
);
4032 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
4035 /* move to next record */
4037 *data_offset
+= sizeof(*data
);
4039 *data_offset
+= aligned_string_len(data
->name_len
+ sizeof(WCHAR
));
4044 static NTSTATUS
build_ifaceps_section(ACTIVATION_CONTEXT
* actctx
, struct guidsection_header
**section
)
4046 unsigned int i
, j
, total_len
= 0, count
= 0;
4047 struct guidsection_header
*header
;
4048 struct guid_index
*index
;
4051 /* compute section length */
4052 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4054 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4056 get_ifaceps_datalen(&assembly
->entities
, &count
, &total_len
);
4057 for (j
= 0; j
< assembly
->num_dlls
; j
++)
4059 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
4060 get_ifaceps_datalen(&dll
->entities
, &count
, &total_len
);
4064 total_len
+= sizeof(*header
);
4066 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
4067 if (!header
) return STATUS_NO_MEMORY
;
4069 memset(header
, 0, sizeof(*header
));
4070 header
->magic
= GUIDSECTION_MAGIC
;
4071 header
->size
= sizeof(*header
);
4072 header
->count
= count
;
4073 header
->index_offset
= sizeof(*header
);
4074 index
= (struct guid_index
*)((BYTE
*)header
+ header
->index_offset
);
4075 data_offset
= header
->index_offset
+ count
*sizeof(*index
);
4077 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4079 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4081 add_ifaceps_record(header
, &assembly
->entities
, &index
, &data_offset
, i
+ 1);
4082 for (j
= 0; j
< assembly
->num_dlls
; j
++)
4084 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
4085 add_ifaceps_record(header
, &dll
->entities
, &index
, &data_offset
, i
+ 1);
4091 return STATUS_SUCCESS
;
4094 static inline struct ifacepsredirect_data
*get_ifaceps_data(ACTIVATION_CONTEXT
*actctx
, struct guid_index
*index
)
4096 return (struct ifacepsredirect_data
*)((BYTE
*)actctx
->ifaceps_section
+ index
->data_offset
);
4099 static NTSTATUS
find_cominterface_redirection(ACTIVATION_CONTEXT
* actctx
, const GUID
*guid
, ACTCTX_SECTION_KEYED_DATA
* data
)
4101 struct ifacepsredirect_data
*iface
;
4102 struct guid_index
*index
= NULL
;
4104 if (!(actctx
->sections
& IFACEREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
4106 if (!actctx
->ifaceps_section
)
4108 struct guidsection_header
*section
;
4110 NTSTATUS status
= build_ifaceps_section(actctx
, §ion
);
4111 if (status
) return status
;
4113 if (InterlockedCompareExchangePointer((void**)&actctx
->ifaceps_section
, section
, NULL
))
4114 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
4117 index
= find_guid_index(actctx
->ifaceps_section
, guid
);
4118 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
4120 iface
= get_ifaceps_data(actctx
, index
);
4122 data
->ulDataFormatVersion
= 1;
4123 data
->lpData
= iface
;
4124 data
->ulLength
= iface
->size
+ (iface
->name_len
? iface
->name_len
+ sizeof(WCHAR
) : 0);
4125 data
->lpSectionGlobalData
= NULL
;
4126 data
->ulSectionGlobalDataLength
= 0;
4127 data
->lpSectionBase
= actctx
->ifaceps_section
;
4128 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->ifaceps_section
);
4129 data
->hActCtx
= NULL
;
4131 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
4132 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
4134 return STATUS_SUCCESS
;
4137 static NTSTATUS
build_clr_surrogate_section(ACTIVATION_CONTEXT
* actctx
, struct guidsection_header
**section
)
4139 unsigned int i
, j
, total_len
= 0, count
= 0;
4140 struct guidsection_header
*header
;
4141 struct clrsurrogate_data
*data
;
4142 struct guid_index
*index
;
4145 /* compute section length */
4146 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4148 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4149 for (j
= 0; j
< assembly
->entities
.num
; j
++)
4151 struct entity
*entity
= &assembly
->entities
.base
[j
];
4152 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
)
4156 total_len
+= sizeof(*index
) + sizeof(*data
);
4157 len
= strlenW(entity
->u
.clrsurrogate
.name
) + 1;
4158 if (entity
->u
.clrsurrogate
.version
)
4159 len
+= strlenW(entity
->u
.clrsurrogate
.version
) + 1;
4160 total_len
+= aligned_string_len(len
*sizeof(WCHAR
));
4167 total_len
+= sizeof(*header
);
4169 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
4170 if (!header
) return STATUS_NO_MEMORY
;
4172 memset(header
, 0, sizeof(*header
));
4173 header
->magic
= GUIDSECTION_MAGIC
;
4174 header
->size
= sizeof(*header
);
4175 header
->count
= count
;
4176 header
->index_offset
= sizeof(*header
);
4177 index
= (struct guid_index
*)((BYTE
*)header
+ header
->index_offset
);
4178 data_offset
= header
->index_offset
+ count
*sizeof(*index
);
4180 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4182 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4183 for (j
= 0; j
< assembly
->entities
.num
; j
++)
4185 struct entity
*entity
= &assembly
->entities
.base
[j
];
4186 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
)
4188 ULONG version_len
, name_len
;
4192 if (entity
->u
.clrsurrogate
.version
)
4193 version_len
= strlenW(entity
->u
.clrsurrogate
.version
)*sizeof(WCHAR
);
4196 name_len
= strlenW(entity
->u
.clrsurrogate
.name
)*sizeof(WCHAR
);
4198 /* setup new index entry */
4199 RtlInitUnicodeString(&str
, entity
->u
.clrsurrogate
.clsid
);
4200 RtlGUIDFromString(&str
, &index
->guid
);
4202 index
->data_offset
= data_offset
;
4203 index
->data_len
= sizeof(*data
) + aligned_string_len(name_len
+ sizeof(WCHAR
) + (version_len
? version_len
+ sizeof(WCHAR
) : 0));
4204 index
->rosterindex
= i
+ 1;
4207 data
= (struct clrsurrogate_data
*)((BYTE
*)header
+ index
->data_offset
);
4208 data
->size
= sizeof(*data
);
4210 data
->clsid
= index
->guid
;
4211 data
->version_offset
= version_len
? data
->size
: 0;
4212 data
->version_len
= version_len
;
4213 data
->name_offset
= data
->size
+ version_len
;
4215 data
->name_offset
+= sizeof(WCHAR
);
4216 data
->name_len
= name_len
;
4218 /* surrogate name */
4219 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->name_offset
);
4220 memcpy(ptrW
, entity
->u
.clrsurrogate
.name
, data
->name_len
);
4221 ptrW
[data
->name_len
/sizeof(WCHAR
)] = 0;
4223 /* runtime version */
4224 if (data
->version_len
)
4226 ptrW
= (WCHAR
*)((BYTE
*)data
+ data
->version_offset
);
4227 memcpy(ptrW
, entity
->u
.clrsurrogate
.version
, data
->version_len
);
4228 ptrW
[data
->version_len
/sizeof(WCHAR
)] = 0;
4231 data_offset
+= index
->data_offset
;
4239 return STATUS_SUCCESS
;
4242 static inline struct clrsurrogate_data
*get_surrogate_data(ACTIVATION_CONTEXT
*actctx
, const struct guid_index
*index
)
4244 return (struct clrsurrogate_data
*)((BYTE
*)actctx
->clrsurrogate_section
+ index
->data_offset
);
4247 static NTSTATUS
find_clr_surrogate(ACTIVATION_CONTEXT
* actctx
, const GUID
*guid
, ACTCTX_SECTION_KEYED_DATA
* data
)
4249 struct clrsurrogate_data
*surrogate
;
4250 struct guid_index
*index
= NULL
;
4252 if (!(actctx
->sections
& CLRSURROGATES_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
4254 if (!actctx
->clrsurrogate_section
)
4256 struct guidsection_header
*section
;
4258 NTSTATUS status
= build_clr_surrogate_section(actctx
, §ion
);
4259 if (status
) return status
;
4261 if (InterlockedCompareExchangePointer((void**)&actctx
->clrsurrogate_section
, section
, NULL
))
4262 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
4265 index
= find_guid_index(actctx
->clrsurrogate_section
, guid
);
4266 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
4268 surrogate
= get_surrogate_data(actctx
, index
);
4270 data
->ulDataFormatVersion
= 1;
4271 data
->lpData
= surrogate
;
4272 /* full length includes string length with nulls */
4273 data
->ulLength
= surrogate
->size
+ surrogate
->name_len
+ sizeof(WCHAR
);
4274 if (surrogate
->version_len
)
4275 data
->ulLength
+= surrogate
->version_len
+ sizeof(WCHAR
);
4277 data
->lpSectionGlobalData
= NULL
;
4278 data
->ulSectionGlobalDataLength
= 0;
4279 data
->lpSectionBase
= actctx
->clrsurrogate_section
;
4280 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->clrsurrogate_section
);
4281 data
->hActCtx
= NULL
;
4283 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
4284 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
4286 return STATUS_SUCCESS
;
4289 static void get_progid_datalen(struct entity_array
*entities
, unsigned int *count
, unsigned int *total_len
)
4291 unsigned int i
, j
, single_len
;
4293 single_len
= sizeof(struct progidredirect_data
) + sizeof(struct string_index
) + sizeof(GUID
);
4294 for (i
= 0; i
< entities
->num
; i
++)
4296 struct entity
*entity
= &entities
->base
[i
];
4297 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)
4299 if (entity
->u
.comclass
.progid
)
4301 *total_len
+= single_len
+ aligned_string_len((strlenW(entity
->u
.comclass
.progid
)+1)*sizeof(WCHAR
));
4305 for (j
= 0; j
< entity
->u
.comclass
.progids
.num
; j
++)
4306 *total_len
+= aligned_string_len((strlenW(entity
->u
.comclass
.progids
.progids
[j
])+1)*sizeof(WCHAR
));
4308 *total_len
+= single_len
*entity
->u
.comclass
.progids
.num
;
4309 *count
+= entity
->u
.comclass
.progids
.num
;
4314 static void write_progid_record(struct strsection_header
*section
, const WCHAR
*progid
, const GUID
*alias
,
4315 struct string_index
**index
, ULONG
*data_offset
, ULONG
*global_offset
, ULONG rosterindex
)
4317 struct progidredirect_data
*data
;
4322 /* setup new index entry */
4324 /* hash progid name */
4325 RtlInitUnicodeString(&str
, progid
);
4326 RtlHashUnicodeString(&str
, TRUE
, HASH_STRING_ALGORITHM_X65599
, &(*index
)->hash
);
4328 (*index
)->name_offset
= *data_offset
;
4329 (*index
)->name_len
= str
.Length
;
4330 (*index
)->data_offset
= (*index
)->name_offset
+ aligned_string_len(str
.MaximumLength
);
4331 (*index
)->data_len
= sizeof(*data
);
4332 (*index
)->rosterindex
= rosterindex
;
4334 *data_offset
+= aligned_string_len(str
.MaximumLength
);
4336 /* setup data structure */
4337 data
= (struct progidredirect_data
*)((BYTE
*)section
+ *data_offset
);
4338 data
->size
= sizeof(*data
);
4340 data
->clsid_offset
= *global_offset
;
4342 /* write progid string */
4343 ptrW
= (WCHAR
*)((BYTE
*)section
+ (*index
)->name_offset
);
4344 memcpy(ptrW
, progid
, (*index
)->name_len
);
4345 ptrW
[(*index
)->name_len
/sizeof(WCHAR
)] = 0;
4347 /* write guid to global area */
4348 guid_ptr
= (GUID
*)((BYTE
*)section
+ data
->clsid_offset
);
4352 *global_offset
+= sizeof(GUID
);
4353 *data_offset
+= data
->size
;
4357 static void add_progid_record(ACTIVATION_CONTEXT
* actctx
, struct strsection_header
*section
, const struct entity_array
*entities
,
4358 struct string_index
**index
, ULONG
*data_offset
, ULONG
*global_offset
, ULONG rosterindex
)
4362 for (i
= 0; i
< entities
->num
; i
++)
4364 struct entity
*entity
= &entities
->base
[i
];
4365 if (entity
->kind
== ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
)
4367 const struct progids
*progids
= &entity
->u
.comclass
.progids
;
4368 struct comclassredirect_data
*comclass
;
4369 struct guid_index
*guid_index
;
4373 RtlInitUnicodeString(&str
, entity
->u
.comclass
.clsid
);
4374 RtlGUIDFromString(&str
, &clsid
);
4376 guid_index
= find_guid_index(actctx
->comserver_section
, &clsid
);
4377 comclass
= get_comclass_data(actctx
, guid_index
);
4379 if (entity
->u
.comclass
.progid
)
4380 write_progid_record(section
, entity
->u
.comclass
.progid
, &comclass
->alias
,
4381 index
, data_offset
, global_offset
, rosterindex
);
4383 for (j
= 0; j
< progids
->num
; j
++)
4384 write_progid_record(section
, progids
->progids
[j
], &comclass
->alias
,
4385 index
, data_offset
, global_offset
, rosterindex
);
4390 static NTSTATUS
build_progid_section(ACTIVATION_CONTEXT
* actctx
, struct strsection_header
**section
)
4392 unsigned int i
, j
, total_len
= 0, count
= 0;
4393 struct strsection_header
*header
;
4394 ULONG data_offset
, global_offset
;
4395 struct string_index
*index
;
4397 /* compute section length */
4398 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4400 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4402 get_progid_datalen(&assembly
->entities
, &count
, &total_len
);
4403 for (j
= 0; j
< assembly
->num_dlls
; j
++)
4405 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
4406 get_progid_datalen(&dll
->entities
, &count
, &total_len
);
4410 total_len
+= sizeof(*header
);
4412 header
= RtlAllocateHeap(RtlGetProcessHeap(), 0, total_len
);
4413 if (!header
) return STATUS_NO_MEMORY
;
4415 memset(header
, 0, sizeof(*header
));
4416 header
->magic
= STRSECTION_MAGIC
;
4417 header
->size
= sizeof(*header
);
4418 header
->count
= count
;
4419 header
->global_offset
= header
->size
;
4420 header
->global_len
= count
*sizeof(GUID
);
4421 header
->index_offset
= header
->size
+ header
->global_len
;
4423 index
= (struct string_index
*)((BYTE
*)header
+ header
->index_offset
);
4424 data_offset
= header
->index_offset
+ count
*sizeof(*index
);
4425 global_offset
= header
->global_offset
;
4427 for (i
= 0; i
< actctx
->num_assemblies
; i
++)
4429 struct assembly
*assembly
= &actctx
->assemblies
[i
];
4431 add_progid_record(actctx
, header
, &assembly
->entities
, &index
, &data_offset
, &global_offset
, i
+ 1);
4432 for (j
= 0; j
< assembly
->num_dlls
; j
++)
4434 struct dll_redirect
*dll
= &assembly
->dlls
[j
];
4435 add_progid_record(actctx
, header
, &dll
->entities
, &index
, &data_offset
, &global_offset
, i
+ 1);
4441 return STATUS_SUCCESS
;
4444 static inline struct progidredirect_data
*get_progid_data(ACTIVATION_CONTEXT
*actctx
, const struct string_index
*index
)
4446 return (struct progidredirect_data
*)((BYTE
*)actctx
->progid_section
+ index
->data_offset
);
4449 static NTSTATUS
find_progid_redirection(ACTIVATION_CONTEXT
* actctx
, const UNICODE_STRING
*name
,
4450 PACTCTX_SECTION_KEYED_DATA data
)
4452 struct progidredirect_data
*progid
;
4453 struct string_index
*index
;
4455 if (!(actctx
->sections
& PROGIDREDIRECT_SECTION
)) return STATUS_SXS_KEY_NOT_FOUND
;
4457 if (!actctx
->comserver_section
)
4459 struct guidsection_header
*section
;
4461 NTSTATUS status
= build_comserver_section(actctx
, §ion
);
4462 if (status
) return status
;
4464 if (InterlockedCompareExchangePointer((void**)&actctx
->comserver_section
, section
, NULL
))
4465 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
4468 if (!actctx
->progid_section
)
4470 struct strsection_header
*section
;
4472 NTSTATUS status
= build_progid_section(actctx
, §ion
);
4473 if (status
) return status
;
4475 if (InterlockedCompareExchangePointer((void**)&actctx
->progid_section
, section
, NULL
))
4476 RtlFreeHeap(RtlGetProcessHeap(), 0, section
);
4479 index
= find_string_index(actctx
->progid_section
, name
);
4480 if (!index
) return STATUS_SXS_KEY_NOT_FOUND
;
4482 progid
= get_progid_data(actctx
, index
);
4484 data
->ulDataFormatVersion
= 1;
4485 data
->lpData
= progid
;
4486 data
->ulLength
= progid
->size
;
4487 data
->lpSectionGlobalData
= (BYTE
*)actctx
->progid_section
+ actctx
->progid_section
->global_offset
;
4488 data
->ulSectionGlobalDataLength
= actctx
->progid_section
->global_len
;
4489 data
->lpSectionBase
= actctx
->progid_section
;
4490 data
->ulSectionTotalLength
= RtlSizeHeap( RtlGetProcessHeap(), 0, actctx
->progid_section
);
4491 data
->hActCtx
= NULL
;
4493 if (data
->cbSize
>= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) + sizeof(ULONG
))
4494 data
->ulAssemblyRosterIndex
= index
->rosterindex
;
4496 return STATUS_SUCCESS
;
4499 static NTSTATUS
find_string(ACTIVATION_CONTEXT
* actctx
, ULONG section_kind
,
4500 const UNICODE_STRING
*section_name
,
4501 DWORD flags
, PACTCTX_SECTION_KEYED_DATA data
)
4505 switch (section_kind
)
4507 case ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
:
4508 status
= find_dll_redirection(actctx
, section_name
, data
);
4510 case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
:
4511 status
= find_window_class(actctx
, section_name
, data
);
4513 case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION
:
4514 status
= find_progid_redirection(actctx
, section_name
, data
);
4516 case ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE
:
4517 DPRINT1("Unsupported yet section_kind %x\n", section_kind
);
4518 return STATUS_SXS_SECTION_NOT_FOUND
;
4520 DPRINT1("Unknown section_kind %x\n", section_kind
);
4521 return STATUS_SXS_SECTION_NOT_FOUND
;
4524 if (status
!= STATUS_SUCCESS
) return status
;
4526 if (flags
& FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
)
4528 actctx_addref(actctx
);
4529 data
->hActCtx
= actctx
;
4531 return STATUS_SUCCESS
;
4534 static NTSTATUS
find_guid(ACTIVATION_CONTEXT
* actctx
, ULONG section_kind
,
4535 const GUID
*guid
, DWORD flags
, PACTCTX_SECTION_KEYED_DATA data
)
4539 switch (section_kind
)
4541 case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
:
4542 status
= find_tlib_redirection(actctx
, guid
, data
);
4544 case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION
:
4545 status
= find_comserver_redirection(actctx
, guid
, data
);
4547 case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
:
4548 status
= find_cominterface_redirection(actctx
, guid
, data
);
4550 case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES
:
4551 status
= find_clr_surrogate(actctx
, guid
, data
);
4554 DPRINT("Unknown section_kind %x\n", section_kind
);
4555 return STATUS_SXS_SECTION_NOT_FOUND
;
4558 if (status
!= STATUS_SUCCESS
) return status
;
4560 if (flags
& FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
)
4562 actctx_addref(actctx
);
4563 data
->hActCtx
= actctx
;
4565 return STATUS_SUCCESS
;
4568 /* initialize the activation context for the current process */
4569 void actctx_init(void)
4574 ctx
.cbSize
= sizeof(ctx
);
4575 ctx
.lpSource
= NULL
;
4576 ctx
.dwFlags
= ACTCTX_FLAG_RESOURCE_NAME_VALID
| ACTCTX_FLAG_HMODULE_VALID
;
4577 ctx
.hModule
= NtCurrentTeb()->ProcessEnvironmentBlock
->ImageBaseAddress
;
4578 ctx
.lpResourceName
= (LPCWSTR
)CREATEPROCESS_MANIFEST_RESOURCE_ID
;
4580 if (NT_SUCCESS(RtlCreateActivationContext(0, (PVOID
)&ctx
, 0, NULL
, NULL
, &handle
)))
4582 process_actctx
= check_actctx(handle
);
4586 /* FUNCTIONS ***************************************************************/
4590 RtlCreateActivationContext(IN ULONG Flags
,
4591 IN PACTIVATION_CONTEXT_DATA ActivationContextData
,
4592 IN ULONG ExtraBytes
,
4593 IN PVOID NotificationRoutine
,
4594 IN PVOID NotificationContext
,
4595 OUT PACTIVATION_CONTEXT
*ActCtx
)
4597 const ACTCTXW
*pActCtx
= (PVOID
)ActivationContextData
;
4598 const WCHAR
*directory
= NULL
;
4599 PACTIVATION_CONTEXT_WRAPPED ActualActCtx
;
4600 ACTIVATION_CONTEXT
*actctx
;
4601 UNICODE_STRING nameW
;
4603 NTSTATUS status
= STATUS_NO_MEMORY
;
4605 struct actctx_loader acl
;
4607 DPRINT("%p %08x\n", pActCtx
, pActCtx
? pActCtx
->dwFlags
: 0);
4609 if (!pActCtx
|| pActCtx
->cbSize
< sizeof(*pActCtx
) ||
4610 (pActCtx
->dwFlags
& ~ACTCTX_FLAGS_ALL
))
4611 return STATUS_INVALID_PARAMETER
;
4614 if (!(ActualActCtx
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ActualActCtx
))))
4615 return STATUS_NO_MEMORY
;
4617 ActualActCtx
->MagicMarker
= ACTCTX_MAGIC_MARKER
;
4619 actctx
= &ActualActCtx
->ActivationContext
;
4620 actctx
->RefCount
= 1;
4621 actctx
->config
.type
= ACTIVATION_CONTEXT_PATH_TYPE_NONE
;
4622 actctx
->config
.info
= NULL
;
4623 actctx
->appdir
.type
= ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
;
4624 if (pActCtx
->dwFlags
& ACTCTX_FLAG_APPLICATION_NAME_VALID
)
4626 if (!(actctx
->appdir
.info
= strdupW( pActCtx
->lpApplicationName
))) goto error
;
4634 if (pActCtx
->dwFlags
& ACTCTX_FLAG_HMODULE_VALID
) module
= pActCtx
->hModule
;
4635 else module
= NtCurrentTeb()->ProcessEnvironmentBlock
->ImageBaseAddress
;
4637 status
= get_module_filename(module
, &dir
, 0);
4638 if (!NT_SUCCESS(status
)) goto error
;
4639 if ((p
= strrchrW( dir
.Buffer
, '\\' ))) p
[1] = 0;
4640 actctx
->appdir
.info
= dir
.Buffer
;
4643 nameW
.Buffer
= NULL
;
4645 /* open file only if it's going to be used */
4646 if (pActCtx
->lpSource
&& !((pActCtx
->dwFlags
& ACTCTX_FLAG_RESOURCE_NAME_VALID
) &&
4647 (pActCtx
->dwFlags
& ACTCTX_FLAG_HMODULE_VALID
)))
4649 if (!RtlDosPathNameToNtPathName_U(pActCtx
->lpSource
, &nameW
, NULL
, NULL
))
4651 status
= STATUS_NO_SUCH_FILE
;
4654 status
= open_nt_file( &file
, &nameW
);
4655 if (!NT_SUCCESS(status
))
4657 RtlFreeUnicodeString( &nameW
);
4662 acl
.actctx
= actctx
;
4663 acl
.dependencies
= NULL
;
4664 acl
.num_dependencies
= 0;
4665 acl
.allocated_dependencies
= 0;
4667 if (pActCtx
->dwFlags
& ACTCTX_FLAG_LANGID_VALID
) lang
= pActCtx
->wLangId
;
4668 if (pActCtx
->dwFlags
& ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID
) directory
= pActCtx
->lpAssemblyDirectory
;
4670 if (pActCtx
->dwFlags
& ACTCTX_FLAG_RESOURCE_NAME_VALID
)
4672 /* if we have a resource it's a PE file */
4673 if (pActCtx
->dwFlags
& ACTCTX_FLAG_HMODULE_VALID
)
4675 status
= get_manifest_in_module( &acl
, NULL
, NULL
, directory
, FALSE
, pActCtx
->hModule
,
4676 pActCtx
->lpResourceName
, lang
);
4677 if (status
&& status
!= STATUS_SXS_CANT_GEN_ACTCTX
)
4678 /* FIXME: what to do if pActCtx->lpSource is set */
4679 status
= get_manifest_in_associated_manifest( &acl
, NULL
, NULL
, directory
,
4680 pActCtx
->hModule
, pActCtx
->lpResourceName
);
4682 else if (pActCtx
->lpSource
)
4684 status
= get_manifest_in_pe_file( &acl
, NULL
, nameW
.Buffer
, directory
, FALSE
,
4685 file
, pActCtx
->lpResourceName
, lang
);
4686 if (status
&& status
!= STATUS_SXS_CANT_GEN_ACTCTX
)
4687 status
= get_manifest_in_associated_manifest( &acl
, NULL
, nameW
.Buffer
, directory
,
4688 NULL
, pActCtx
->lpResourceName
);
4690 else status
= STATUS_INVALID_PARAMETER
;
4694 status
= get_manifest_in_manifest_file( &acl
, NULL
, nameW
.Buffer
, directory
, FALSE
, file
);
4697 if (file
) NtClose( file
);
4698 RtlFreeUnicodeString( &nameW
);
4700 if (NT_SUCCESS(status
)) status
= parse_depend_manifests(&acl
);
4701 free_depend_manifests( &acl
);
4703 if (NT_SUCCESS(status
))
4705 else actctx_release( actctx
);
4709 if (file
) NtClose( file
);
4710 actctx_release( actctx
);
4715 #define ACT_CTX_VALID(p) ((((ULONG_PTR)p - 1) | 7) != -1)
4719 RtlAddRefActivationContext(IN PACTIVATION_CONTEXT Handle
)
4721 PIACTIVATION_CONTEXT ActCtx
= (PIACTIVATION_CONTEXT
)Handle
;
4722 LONG OldRefCount
, NewRefCount
;
4724 if ((ActCtx
) && (ACT_CTX_VALID(ActCtx
)) && (ActCtx
->RefCount
!= LONG_MAX
))
4726 RtlpValidateActCtx(ActCtx
);
4730 OldRefCount
= ActCtx
->RefCount
;
4731 ASSERT(OldRefCount
> 0);
4733 if (OldRefCount
== LONG_MAX
) break;
4735 NewRefCount
= OldRefCount
+ 1;
4736 if (InterlockedCompareExchange(&ActCtx
->RefCount
,
4738 OldRefCount
) == OldRefCount
)
4744 NewRefCount
= LONG_MAX
;
4745 ASSERT(NewRefCount
> 0);
4751 RtlReleaseActivationContext( HANDLE handle
)
4753 PIACTIVATION_CONTEXT ActCtx
= (PIACTIVATION_CONTEXT
) Handle
;
4755 if ((ActCtx
) && (ACT_CTX_VALID(ActCtx
)) && (ActCtx
->RefCount
!= LONG_MAX
))
4757 RtlpValidateActCtx(ActCtx
);
4759 actctx_release(ActCtx
);
4765 RtlAddRefActivationContext( HANDLE handle
)
4767 ACTIVATION_CONTEXT
*actctx
;
4769 if ((actctx
= check_actctx(handle
))) actctx_addref(actctx
);
4774 RtlReleaseActivationContext( HANDLE handle
)
4776 ACTIVATION_CONTEXT
*actctx
;
4778 if ((actctx
= check_actctx(handle
))) actctx_release(actctx
);
4783 NTAPI
RtlActivateActivationContextEx( ULONG flags
, PTEB tebAddress
, HANDLE handle
, PULONG_PTR cookie
)
4785 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
;
4787 if (!(frame
= RtlAllocateHeap( RtlGetProcessHeap(), 0, sizeof(*frame
) )))
4788 return STATUS_NO_MEMORY
;
4790 frame
->Previous
= tebAddress
->ActivationContextStackPointer
->ActiveFrame
;
4791 frame
->ActivationContext
= handle
;
4794 tebAddress
->ActivationContextStackPointer
->ActiveFrame
= frame
;
4795 RtlAddRefActivationContext( handle
);
4797 *cookie
= (ULONG_PTR
)frame
;
4798 DPRINT( "%p cookie=%lx\n", handle
, *cookie
);
4799 return STATUS_SUCCESS
;
4804 NTAPI
RtlActivateActivationContext( ULONG flags
, HANDLE handle
, PULONG_PTR cookie
)
4806 return RtlActivateActivationContextEx(flags
, NtCurrentTeb(), handle
, cookie
);
4811 RtlDeactivateActivationContext( ULONG flags
, ULONG_PTR cookie
)
4813 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
, *top
;
4815 DPRINT( "%x cookie=%lx\n", flags
, cookie
);
4817 /* find the right frame */
4818 top
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
;
4819 for (frame
= top
; frame
; frame
= frame
->Previous
)
4820 if ((ULONG_PTR
)frame
== cookie
) break;
4823 RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION
);
4825 if (frame
!= top
&& !(flags
& RTL_DEACTIVATE_ACTIVATION_CONTEXT_FLAG_FORCE_EARLY_DEACTIVATION
))
4826 RtlRaiseStatus( STATUS_SXS_EARLY_DEACTIVATION
);
4828 /* pop everything up to and including frame */
4829 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= frame
->Previous
;
4831 while (top
!= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
4833 frame
= top
->Previous
;
4834 RtlReleaseActivationContext( top
->ActivationContext
);
4835 RtlFreeHeap( RtlGetProcessHeap(), 0, top
);
4839 return STATUS_SUCCESS
;
4844 RtlFreeActivationContextStack(IN PACTIVATION_CONTEXT_STACK Stack
)
4846 PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame
, PrevFrame
;
4848 /* Nothing to do if there is no stack */
4851 /* Get the current active frame */
4852 ActiveFrame
= Stack
->ActiveFrame
;
4854 /* Go through them in backwards order and release */
4857 PrevFrame
= ActiveFrame
->Previous
;
4858 RtlReleaseActivationContext(ActiveFrame
->ActivationContext
);
4859 RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveFrame
);
4860 ActiveFrame
= PrevFrame
;
4863 /* Zero out the active frame */
4864 Stack
->ActiveFrame
= NULL
;
4866 /* TODO: Empty the Frame List Cache */
4867 ASSERT(IsListEmpty(&Stack
->FrameListCache
));
4869 /* Free activation stack memory */
4870 RtlFreeHeap(RtlGetProcessHeap(), 0, Stack
);
4874 NTAPI
RtlFreeThreadActivationContextStack(VOID
)
4876 RtlFreeActivationContextStack(NtCurrentTeb()->ActivationContextStackPointer
);
4877 NtCurrentTeb()->ActivationContextStackPointer
= NULL
;
4882 NTAPI
RtlGetActiveActivationContext( HANDLE
*handle
)
4884 if (NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
4886 *handle
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
->ActivationContext
;
4887 RtlAddRefActivationContext( *handle
);
4892 return STATUS_SUCCESS
;
4897 NTAPI
RtlIsActivationContextActive( HANDLE handle
)
4899 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
;
4901 for (frame
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
; frame
; frame
= frame
->Previous
)
4902 if (frame
->ActivationContext
== handle
) return TRUE
;
4908 RtlQueryInformationActivationContext( ULONG flags
, HANDLE handle
, PVOID subinst
,
4909 ULONG
class, PVOID buffer
,
4910 SIZE_T bufsize
, SIZE_T
*retlen
)
4912 ACTIVATION_CONTEXT
*actctx
;
4915 DPRINT("%08x %p %p %u %p %Iu %p\n", flags
, handle
,
4916 subinst
, class, buffer
, bufsize
, retlen
);
4918 if (retlen
) *retlen
= 0;
4919 if ((status
= find_query_actctx( &handle
, flags
, class ))) return status
;
4923 case ActivationContextBasicInformation
:
4925 ACTIVATION_CONTEXT_BASIC_INFORMATION
*info
= buffer
;
4927 if (retlen
) *retlen
= sizeof(*info
);
4928 if (!info
|| bufsize
< sizeof(*info
)) return STATUS_BUFFER_TOO_SMALL
;
4930 info
->hActCtx
= handle
;
4931 info
->dwFlags
= 0; /* FIXME */
4932 if (!(flags
& RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF
)) RtlAddRefActivationContext(handle
);
4936 case ActivationContextDetailedInformation
:
4938 ACTIVATION_CONTEXT_DETAILED_INFORMATION
*acdi
= buffer
;
4939 struct assembly
*assembly
= NULL
;
4940 SIZE_T len
, manifest_len
= 0, config_len
= 0, appdir_len
= 0;
4943 if (!(actctx
= check_actctx(handle
))) return STATUS_INVALID_PARAMETER
;
4945 if (actctx
->num_assemblies
) assembly
= actctx
->assemblies
;
4947 if (assembly
&& assembly
->manifest
.info
)
4948 manifest_len
= strlenW(assembly
->manifest
.info
) + 1;
4949 if (actctx
->config
.info
) config_len
= strlenW(actctx
->config
.info
) + 1;
4950 if (actctx
->appdir
.info
) appdir_len
= strlenW(actctx
->appdir
.info
) + 1;
4951 len
= sizeof(*acdi
) + (manifest_len
+ config_len
+ appdir_len
) * sizeof(WCHAR
);
4953 if (retlen
) *retlen
= len
;
4954 if (!buffer
|| bufsize
< len
) return STATUS_BUFFER_TOO_SMALL
;
4957 acdi
->ulFormatVersion
= assembly
? 1 : 0; /* FIXME */
4958 acdi
->ulAssemblyCount
= actctx
->num_assemblies
;
4959 acdi
->ulRootManifestPathType
= assembly
? assembly
->manifest
.type
: 0 /* FIXME */;
4960 acdi
->ulRootManifestPathChars
= assembly
&& assembly
->manifest
.info
? (DWORD
)manifest_len
- 1 : 0;
4961 acdi
->ulRootConfigurationPathType
= actctx
->config
.type
;
4962 acdi
->ulRootConfigurationPathChars
= actctx
->config
.info
? (DWORD
)config_len
- 1 : 0;
4963 acdi
->ulAppDirPathType
= actctx
->appdir
.type
;
4964 acdi
->ulAppDirPathChars
= actctx
->appdir
.info
? (DWORD
)appdir_len
- 1 : 0;
4965 ptr
= (LPWSTR
)(acdi
+ 1);
4968 acdi
->lpRootManifestPath
= ptr
;
4969 memcpy(ptr
, assembly
->manifest
.info
, manifest_len
* sizeof(WCHAR
));
4970 ptr
+= manifest_len
;
4972 else acdi
->lpRootManifestPath
= NULL
;
4975 acdi
->lpRootConfigurationPath
= ptr
;
4976 memcpy(ptr
, actctx
->config
.info
, config_len
* sizeof(WCHAR
));
4979 else acdi
->lpRootConfigurationPath
= NULL
;
4982 acdi
->lpAppDirPath
= ptr
;
4983 memcpy(ptr
, actctx
->appdir
.info
, appdir_len
* sizeof(WCHAR
));
4985 else acdi
->lpAppDirPath
= NULL
;
4989 case AssemblyDetailedInformationInActivationContext
:
4991 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION
*afdi
= buffer
;
4992 struct assembly
*assembly
;
4995 SIZE_T len
, id_len
= 0, ad_len
= 0, path_len
= 0;
4998 if (!(actctx
= check_actctx(handle
))) return STATUS_INVALID_PARAMETER
;
4999 if (!subinst
) return STATUS_INVALID_PARAMETER
;
5001 index
= *(DWORD
*)subinst
;
5002 if (!index
|| index
> actctx
->num_assemblies
) return STATUS_INVALID_PARAMETER
;
5004 assembly
= &actctx
->assemblies
[index
- 1];
5006 if (!(assembly_id
= build_assembly_id( &assembly
->id
))) return STATUS_NO_MEMORY
;
5007 id_len
= strlenW(assembly_id
) + 1;
5008 if (assembly
->directory
) ad_len
= strlenW(assembly
->directory
) + 1;
5010 if (assembly
->manifest
.info
&&
5011 (assembly
->type
== ASSEMBLY_MANIFEST
|| assembly
->type
== ASSEMBLY_SHARED_MANIFEST
))
5012 path_len
= strlenW(assembly
->manifest
.info
) + 1;
5014 len
= sizeof(*afdi
) + (id_len
+ ad_len
+ path_len
) * sizeof(WCHAR
);
5016 if (retlen
) *retlen
= len
;
5017 if (!buffer
|| bufsize
< len
)
5019 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id
);
5020 return STATUS_BUFFER_TOO_SMALL
;
5023 afdi
->ulFlags
= 0; /* FIXME */
5024 afdi
->ulEncodedAssemblyIdentityLength
= (DWORD
)(id_len
- 1) * sizeof(WCHAR
);
5025 afdi
->ulManifestPathType
= assembly
->manifest
.type
;
5026 afdi
->ulManifestPathLength
= assembly
->manifest
.info
? (DWORD
)(path_len
- 1) * sizeof(WCHAR
) : 0;
5027 /* FIXME afdi->liManifestLastWriteTime = 0; */
5028 afdi
->ulPolicyPathType
= ACTIVATION_CONTEXT_PATH_TYPE_NONE
; /* FIXME */
5029 afdi
->ulPolicyPathLength
= 0;
5030 /* FIXME afdi->liPolicyLastWriteTime = 0; */
5031 afdi
->ulMetadataSatelliteRosterIndex
= 0; /* FIXME */
5032 afdi
->ulManifestVersionMajor
= 1;
5033 afdi
->ulManifestVersionMinor
= 0;
5034 afdi
->ulPolicyVersionMajor
= 0; /* FIXME */
5035 afdi
->ulPolicyVersionMinor
= 0; /* FIXME */
5036 afdi
->ulAssemblyDirectoryNameLength
= ad_len
? (DWORD
)(ad_len
- 1) * sizeof(WCHAR
) : 0;
5037 ptr
= (LPWSTR
)(afdi
+ 1);
5038 afdi
->lpAssemblyEncodedAssemblyIdentity
= ptr
;
5039 memcpy( ptr
, assembly_id
, id_len
* sizeof(WCHAR
) );
5043 afdi
->lpAssemblyManifestPath
= ptr
;
5044 memcpy(ptr
, assembly
->manifest
.info
, path_len
* sizeof(WCHAR
));
5046 } else afdi
->lpAssemblyManifestPath
= NULL
;
5047 afdi
->lpAssemblyPolicyPath
= NULL
; /* FIXME */
5050 afdi
->lpAssemblyDirectoryName
= ptr
;
5051 memcpy(ptr
, assembly
->directory
, ad_len
* sizeof(WCHAR
));
5053 else afdi
->lpAssemblyDirectoryName
= NULL
;
5054 RtlFreeHeap( RtlGetProcessHeap(), 0, assembly_id
);
5058 case FileInformationInAssemblyOfAssemblyInActivationContext
:
5060 const ACTIVATION_CONTEXT_QUERY_INDEX
*acqi
= subinst
;
5061 ASSEMBLY_FILE_DETAILED_INFORMATION
*afdi
= buffer
;
5062 struct assembly
*assembly
;
5063 struct dll_redirect
*dll
;
5064 SIZE_T len
, dll_len
= 0;
5067 if (!(actctx
= check_actctx(handle
))) return STATUS_INVALID_PARAMETER
;
5068 if (!acqi
) return STATUS_INVALID_PARAMETER
;
5070 if (acqi
->ulAssemblyIndex
>= actctx
->num_assemblies
)
5071 return STATUS_INVALID_PARAMETER
;
5072 assembly
= &actctx
->assemblies
[acqi
->ulAssemblyIndex
];
5074 if (acqi
->ulFileIndexInAssembly
>= assembly
->num_dlls
)
5075 return STATUS_INVALID_PARAMETER
;
5076 dll
= &assembly
->dlls
[acqi
->ulFileIndexInAssembly
];
5078 if (dll
->name
) dll_len
= strlenW(dll
->name
) + 1;
5079 len
= sizeof(*afdi
) + dll_len
* sizeof(WCHAR
);
5081 if (!buffer
|| bufsize
< len
)
5083 if (retlen
) *retlen
= len
;
5084 return STATUS_BUFFER_TOO_SMALL
;
5086 if (retlen
) *retlen
= 0; /* yes that's what native does !! */
5087 afdi
->ulFlags
= ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
;
5088 afdi
->ulFilenameLength
= dll_len
? (DWORD
)(dll_len
- 1) * sizeof(WCHAR
) : 0;
5089 afdi
->ulPathLength
= 0; /* FIXME */
5090 ptr
= (LPWSTR
)(afdi
+ 1);
5093 afdi
->lpFileName
= ptr
;
5094 memcpy( ptr
, dll
->name
, dll_len
* sizeof(WCHAR
) );
5095 } else afdi
->lpFileName
= NULL
;
5096 afdi
->lpFilePath
= NULL
; /* FIXME */
5101 DPRINT( "class %u not implemented\n", class );
5102 return STATUS_NOT_IMPLEMENTED
;
5104 return STATUS_SUCCESS
;
5109 RtlQueryInformationActiveActivationContext(ULONG ulInfoClass
,
5111 SIZE_T cbBuffer OPTIONAL
,
5112 SIZE_T
*pcbWrittenOrRequired OPTIONAL
)
5114 return RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT
,
5120 pcbWrittenOrRequired
);
5123 #define FIND_ACTCTX_RETURN_FLAGS 0x00000002
5124 #define FIND_ACTCTX_RETURN_ASSEMBLY_METADATA 0x00000004
5125 #define FIND_ACTCTX_VALID_MASK (FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX | FIND_ACTCTX_RETURN_FLAGS | FIND_ACTCTX_RETURN_ASSEMBLY_METADATA)
5129 RtlpFindActivationContextSection_CheckParameters( ULONG flags
, const GUID
*guid
, ULONG section_kind
,
5130 const UNICODE_STRING
*section_name
, PACTCTX_SECTION_KEYED_DATA data
)
5132 /* Check general parameter combinations */
5133 if (!section_name
||
5134 (flags
& ~FIND_ACTCTX_VALID_MASK
) ||
5135 ((flags
& FIND_ACTCTX_VALID_MASK
) && !data
) ||
5136 (data
&& data
->cbSize
< offsetof(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
)))
5138 DPRINT1("invalid parameter\n");
5139 return STATUS_INVALID_PARAMETER
;
5143 if (flags
& FIND_ACTCTX_RETURN_FLAGS
||
5144 flags
& FIND_ACTCTX_RETURN_ASSEMBLY_METADATA
)
5146 DPRINT1("unknown flags %08x\n", flags
);
5147 return STATUS_INVALID_PARAMETER
;
5150 return STATUS_SUCCESS
;
5155 RtlFindActivationContextSectionString( ULONG flags
, const GUID
*guid
, ULONG section_kind
,
5156 const UNICODE_STRING
*section_name
, PVOID ptr
)
5158 PACTCTX_SECTION_KEYED_DATA data
= ptr
;
5161 status
= RtlpFindActivationContextSection_CheckParameters(flags
, guid
, section_kind
, section_name
, data
);
5162 if (!NT_SUCCESS(status
)) return status
;
5164 status
= STATUS_SXS_KEY_NOT_FOUND
;
5166 /* if there is no data, but params are valid,
5167 we return that sxs key is not found to be at least somehow compatible */
5168 if (!data
) return status
;
5170 ASSERT(NtCurrentTeb());
5171 ASSERT(NtCurrentTeb()->ActivationContextStackPointer
);
5173 if (NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
5175 ACTIVATION_CONTEXT
*actctx
= check_actctx(NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
->ActivationContext
);
5176 if (actctx
) status
= find_string( actctx
, section_kind
, section_name
, flags
, data
);
5179 if (status
!= STATUS_SUCCESS
)
5180 status
= find_string( process_actctx
, section_kind
, section_name
, flags
, data
);
5185 NTSTATUS WINAPI
RtlFindActivationContextSectionGuid( ULONG flags
, const GUID
*extguid
, ULONG section_kind
,
5186 const GUID
*guid
, void *ptr
)
5188 ACTCTX_SECTION_KEYED_DATA
*data
= ptr
;
5189 NTSTATUS status
= STATUS_SXS_KEY_NOT_FOUND
;
5193 DPRINT1("expected extguid == NULL\n");
5194 return STATUS_INVALID_PARAMETER
;
5197 if (flags
& ~FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
)
5199 DPRINT1("unknown flags %08x\n", flags
);
5200 return STATUS_INVALID_PARAMETER
;
5203 if (!data
|| data
->cbSize
< FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA
, ulAssemblyRosterIndex
) || !guid
)
5204 return STATUS_INVALID_PARAMETER
;
5206 if (NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
)
5208 ACTIVATION_CONTEXT
*actctx
= check_actctx(NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
->ActivationContext
);
5209 if (actctx
) status
= find_guid( actctx
, section_kind
, guid
, flags
, data
);
5212 if (status
!= STATUS_SUCCESS
)
5213 status
= find_guid( process_actctx
, section_kind
, guid
, flags
, data
);
5222 RtlAllocateActivationContextStack(IN PACTIVATION_CONTEXT_STACK
*Stack
)
5224 PACTIVATION_CONTEXT_STACK ContextStack
;
5226 /* Check if it's already allocated */
5227 if (*Stack
) return STATUS_SUCCESS
;
5229 /* Allocate space for the context stack */
5230 ContextStack
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ACTIVATION_CONTEXT_STACK
));
5233 return STATUS_NO_MEMORY
;
5236 /* Initialize the context stack */
5237 ContextStack
->Flags
= 0;
5238 ContextStack
->ActiveFrame
= NULL
;
5239 InitializeListHead(&ContextStack
->FrameListCache
);
5240 ContextStack
->NextCookieSequenceNumber
= 1;
5241 ContextStack
->StackId
= 1; //TODO: Timer-based
5243 *Stack
= ContextStack
;
5245 return STATUS_SUCCESS
;
5248 PRTL_ACTIVATION_CONTEXT_STACK_FRAME
5250 RtlActivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame
,
5253 #if NEW_NTDLL_LOADER
5254 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*ActiveFrame
;
5256 /* Get the curren active frame */
5257 ActiveFrame
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
;
5259 DPRINT1("ActiveFrame %p, &Frame->Frame %p, Context %p\n", ActiveFrame
, &Frame
->Frame
, Context
);
5261 /* Actually activate it */
5262 Frame
->Frame
.Previous
= ActiveFrame
;
5263 Frame
->Frame
.ActivationContext
= Context
;
5264 Frame
->Frame
.Flags
= 0;
5266 /* Check if we can activate this context */
5267 if ((ActiveFrame
&& (ActiveFrame
->ActivationContext
!= Context
)) ||
5270 /* Set new active frame */
5271 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= &Frame
->Frame
;
5272 return &Frame
->Frame
;
5275 /* We can get here only one way: it was already activated */
5276 DPRINT1("Trying to activate improper activation context\n");
5278 /* Activate only if we are allowing multiple activation */
5279 if (!RtlpNotAllowingMultipleActivation
)
5281 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= &Frame
->Frame
;
5286 Frame
->Frame
.Flags
= 0x30;
5289 /* Return pointer to the activation frame */
5290 return &Frame
->Frame
;
5293 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
= &Frame
->Frame
;
5295 frame
->Previous
= NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
;
5296 frame
->ActivationContext
= Context
;
5299 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= frame
;
5301 return STATUS_SUCCESS
;
5305 PRTL_ACTIVATION_CONTEXT_STACK_FRAME
5307 RtlDeactivateActivationContextUnsafeFast(IN PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame
)
5309 RTL_ACTIVATION_CONTEXT_STACK_FRAME
*frame
;
5310 //RTL_ACTIVATION_CONTEXT_STACK_FRAME *top;
5312 /* find the right frame */
5313 //top = NtCurrentTeb()->ActivationContextStackPointer->ActiveFrame;
5314 frame
= &Frame
->Frame
;
5318 DPRINT1("No top frame!\n");
5319 RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION
);
5322 /* pop everything up to and including frame */
5323 NtCurrentTeb()->ActivationContextStackPointer
->ActiveFrame
= frame
->Previous
;
5331 RtlZombifyActivationContext(PVOID Context
)
5335 if (Context
== ACTCTX_FAKE_HANDLE
)
5336 return STATUS_SUCCESS
;
5338 return STATUS_NOT_IMPLEMENTED
;