actctx.c 193 KB
Newer Older
1 2 3 4 5 6 7
/*
 * Activation contexts
 *
 * Copyright 2004 Jon Griffiths
 * Copyright 2007 Eric Pouech
 * Copyright 2007 Jacek Caban for CodeWeavers
 * Copyright 2007 Alexandre Julliard
8
 * Copyright 2013 Nikolay Sivov
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"
#include "wine/port.h"

#include <stdarg.h>
#include <stdio.h>

#include "ntstatus.h"
#define WIN32_NO_STATUS
33
#define NONAMELESSUNION
34
#include "winternl.h"
35
#include "ddk/wdm.h"
36
#include "ntdll_misc.h"
37
#include "wine/exception.h"
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
#include "wine/debug.h"
#include "wine/unicode.h"

WINE_DEFAULT_DEBUG_CHANNEL(actctx);

#define ACTCTX_FLAGS_ALL (\
 ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID |\
 ACTCTX_FLAG_LANGID_VALID |\
 ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID |\
 ACTCTX_FLAG_RESOURCE_NAME_VALID |\
 ACTCTX_FLAG_SET_PROCESS_DEFAULT |\
 ACTCTX_FLAG_APPLICATION_NAME_VALID |\
 ACTCTX_FLAG_SOURCE_IS_ASSEMBLYREF |\
 ACTCTX_FLAG_HMODULE_VALID )

#define ACTCTX_MAGIC       0xC07E3E11
54 55
#define STRSECTION_MAGIC   0x64487353 /* dHsS */
#define GUIDSECTION_MAGIC  0x64487347 /* dHsG */
56

57 58 59 60
/* we don't want to include winuser.h */
#define RT_MANIFEST                        ((ULONG_PTR)24)
#define CREATEPROCESS_MANIFEST_RESOURCE_ID ((ULONG_PTR)1)

61 62 63 64 65 66 67 68
/* from oaidl.h */
typedef enum tagLIBFLAGS {
    LIBFLAG_FRESTRICTED   = 0x1,
    LIBFLAG_FCONTROL      = 0x2,
    LIBFLAG_FHIDDEN       = 0x4,
    LIBFLAG_FHASDISKIMAGE = 0x8
} LIBFLAGS;

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
/* from oleidl.idl */
typedef enum tagOLEMISC
{
    OLEMISC_RECOMPOSEONRESIZE            = 0x1,
    OLEMISC_ONLYICONIC                   = 0x2,
    OLEMISC_INSERTNOTREPLACE             = 0x4,
    OLEMISC_STATIC                       = 0x8,
    OLEMISC_CANTLINKINSIDE               = 0x10,
    OLEMISC_CANLINKBYOLE1                = 0x20,
    OLEMISC_ISLINKOBJECT                 = 0x40,
    OLEMISC_INSIDEOUT                    = 0x80,
    OLEMISC_ACTIVATEWHENVISIBLE          = 0x100,
    OLEMISC_RENDERINGISDEVICEINDEPENDENT = 0x200,
    OLEMISC_INVISIBLEATRUNTIME           = 0x400,
    OLEMISC_ALWAYSRUN                    = 0x800,
    OLEMISC_ACTSLIKEBUTTON               = 0x1000,
    OLEMISC_ACTSLIKELABEL                = 0x2000,
    OLEMISC_NOUIACTIVATE                 = 0x4000,
    OLEMISC_ALIGNABLE                    = 0x8000,
    OLEMISC_SIMPLEFRAME                  = 0x10000,
    OLEMISC_SETCLIENTSITEFIRST           = 0x20000,
    OLEMISC_IMEMODE                      = 0x40000,
    OLEMISC_IGNOREACTIVATEWHENVISIBLE    = 0x80000,
    OLEMISC_WANTSTOMENUMERGE             = 0x100000,
    OLEMISC_SUPPORTSMULTILEVELUNDO       = 0x200000
} OLEMISC;

96 97
#define MAX_NAMESPACES 64

98 99
typedef struct
{
100
    const WCHAR        *ptr;
101 102 103
    unsigned int        len;
} xmlstr_t;

104 105 106
struct xml_elem
{
    xmlstr_t            name;
107
    xmlstr_t            ns;
108
    int                 ns_pos;
109 110 111 112 113 114 115 116
};

struct xml_attr
{
    xmlstr_t            name;
    xmlstr_t            value;
};

117 118
typedef struct
{
119 120
    const WCHAR        *ptr;
    const WCHAR        *end;
121 122
    struct xml_attr     namespaces[MAX_NAMESPACES];
    int                 ns_pos;
123
    BOOL                error;
124 125
} xmlbuf_t;

126 127 128 129 130 131
struct file_info
{
    ULONG               type;
    WCHAR              *info;
};

132
struct assembly_version
133 134 135 136 137 138 139 140 141
{
    USHORT              major;
    USHORT              minor;
    USHORT              build;
    USHORT              revision;
};

struct assembly_identity
{
142
    WCHAR                *name;
143
    WCHAR                *arch;
144
    WCHAR                *public_key;
145
    WCHAR                *language;
146
    WCHAR                *type;
147
    struct assembly_version version;
148
    BOOL                  optional;
149
    BOOL                  delayed;
150 151
};

152
struct strsection_header
153 154
{
    DWORD magic;
155 156
    ULONG size;
    DWORD unk1[3];
157 158
    ULONG count;
    ULONG index_offset;
159 160 161
    DWORD unk2[2];
    ULONG global_offset;
    ULONG global_len;
162 163
};

164
struct string_index
165
{
166 167
    ULONG hash;        /* key string hash */
    ULONG name_offset;
168 169 170 171 172 173
    ULONG name_len;
    ULONG data_offset; /* redirect data offset */
    ULONG data_len;
    ULONG rosterindex;
};

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
struct guidsection_header
{
    DWORD magic;
    ULONG size;
    DWORD unk[3];
    ULONG count;
    ULONG index_offset;
    DWORD unk2;
    ULONG names_offset;
    ULONG names_len;
};

struct guid_index
{
    GUID  guid;
    ULONG data_offset;
    ULONG data_len;
    ULONG rosterindex;
};

194 195 196 197 198 199 200 201 202 203
struct wndclass_redirect_data
{
    ULONG size;
    DWORD res;
    ULONG name_len;
    ULONG name_offset;  /* versioned name offset */
    ULONG module_len;
    ULONG module_offset;/* container name offset */
};

204 205 206 207 208 209 210
struct dllredirect_data
{
    ULONG size;
    ULONG unk;
    DWORD res[3];
};

211 212 213 214 215 216 217 218 219 220 221 222 223 224
struct tlibredirect_data
{
    ULONG  size;
    DWORD  res;
    ULONG  name_len;
    ULONG  name_offset;
    LANGID langid;
    WORD   flags;
    ULONG  help_len;
    ULONG  help_offset;
    WORD   major_version;
    WORD   minor_version;
};

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
enum comclass_threadingmodel
{
    ThreadingModel_Apartment = 1,
    ThreadingModel_Free      = 2,
    ThreadingModel_No        = 3,
    ThreadingModel_Both      = 4,
    ThreadingModel_Neutral   = 5
};

enum comclass_miscfields
{
    MiscStatus          = 1,
    MiscStatusIcon      = 2,
    MiscStatusContent   = 4,
    MiscStatusThumbnail = 8,
    MiscStatusDocPrint  = 16
};

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
struct comclassredirect_data
{
    ULONG size;
    BYTE  res;
    BYTE  miscmask;
    BYTE  res1[2];
    DWORD model;
    GUID  clsid;
    GUID  alias;
    GUID  clsid2;
    GUID  tlbid;
    ULONG name_len;
    ULONG name_offset;
    ULONG progid_len;
    ULONG progid_offset;
258 259
    ULONG clrdata_len;
    ULONG clrdata_offset;
260 261 262 263 264 265 266
    DWORD miscstatus;
    DWORD miscstatuscontent;
    DWORD miscstatusthumbnail;
    DWORD miscstatusicon;
    DWORD miscstatusdocprint;
};

267 268 269 270 271 272
enum ifaceps_mask
{
    NumMethods = 1,
    BaseIface  = 2
};

273 274 275 276 277 278 279 280 281 282 283 284
struct ifacepsredirect_data
{
    ULONG size;
    DWORD mask;
    GUID  iid;
    ULONG nummethods;
    GUID  tlbid;
    GUID  base;
    ULONG name_len;
    ULONG name_offset;
};

285 286 287 288 289 290 291 292 293 294 295
struct clrsurrogate_data
{
    ULONG size;
    DWORD res;
    GUID  clsid;
    ULONG version_offset;
    ULONG version_len;
    ULONG name_offset;
    ULONG name_len;
};

296 297 298 299 300 301 302 303 304 305 306 307 308
struct clrclass_data
{
    ULONG size;
    DWORD res[2];
    ULONG module_len;
    ULONG module_offset;
    ULONG name_len;
    ULONG name_offset;
    ULONG version_len;
    ULONG version_offset;
    DWORD res2[2];
};

309 310 311 312 313 314 315
struct progidredirect_data
{
    ULONG size;
    DWORD reserved;
    ULONG clsid_offset;
};

316
/*
317 318 319 320 321 322 323 324 325 326

   Sections structure.

   Sections are accessible by string or guid key, that defines two types of sections.
   All sections of each type have same magic value and header structure, index
   data could be of two possible types too. So every string based section uses
   the same index format, same applies to guid sections - they share same guid index
   format.

   - window class redirection section is a plain buffer with following format:
327 328 329 330 331 332 333 334

   <section header>
   <index[]>
   <data[]> --- <original name>
                <redirect data>
                <versioned name>
                <module name>

335
   Header is fixed length structure - struct strsection_header,
336 337 338
   contains redirected classes count;

   Index is an array of fixed length index records, each record is
339
   struct string_index.
340 341 342 343 344

   All strings in data itself are WCHAR, null terminated, 4-bytes aligned.

   Versioned name offset is relative to redirect data structure (struct wndclass_redirect_data),
   others are relative to section itself.
345 346 347 348 349 350 351 352 353

   - dll redirect section format:

   <section header>
   <index[]>
   <data[]> --- <dll name>
                <data>

   This section doesn't seem to carry any payload data except dll names.
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

   - typelib section format:

   <section header>
   <module names[]>
   <index[]>
   <data[]> --- <data>
                <helpstring>

   Header is fixed length, index is an array of fixed length 'struct guid_index'.
   All strings are WCHAR, null terminated, 4-bytes aligned. Module names part is
   4-bytes aligned as a whole.

   Module name offsets are relative to section, helpstring offset is relative to data
   structure itself.
369 370 371 372 373 374

   - comclass section format:

   <section header>
   <module names[]>
   <index[]>
375 376 377 378 379
   <data[]> --- <data>   --- <data>
                <progid>     <clrdata>
                             <name>
                             <version>
                             <progid>
380 381 382 383 384

   This section uses two index records per comclass, one entry contains original guid
   as specified by context, another one has a generated guid. Index and strings handling
   is similar to typelib sections.

385 386 387
   For CLR classes additional data is stored after main COM class data, it contains
   class name and runtime version string, see 'struct clrclass_data'.

388 389
   Module name offsets are relative to section, progid offset is relative to data
   structure itself.
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404

   - COM interface section format:

   <section header>
   <index[]>
   <data[]> --- <data>
                <name>

   Interface section contains data for proxy/stubs and external proxy/stubs. External
   ones are defined at assembly level, so this section has no module information.
   All records are indexed with 'iid' value from manifest. There an exception for
   external variants - if 'proxyStubClsid32' is specified, it's stored as iid in
   redirect data, but index is still 'iid' from manifest.

   Interface name offset is relative to data structure itself.
405 406 407 408 409 410 411 412 413 414 415

   - CLR surrogates section format:

   <section header>
   <index[]>
   <data[]> --- <data>
                <name>
                <version>

    There's nothing special about this section, same way to store strings is used,
    no modules part as it belongs to assembly level, not a file.
416 417 418 419 420 421 422 423 424 425 426 427

   - ProgID section format:

   <section header>
   <guids[]>
   <index[]>
   <data[]> --- <progid>
                <data>

   This sections uses generated alias guids from COM server section. This way
   ProgID -> CLSID mapping returns generated guid, not the real one. ProgID string
   is stored too, aligned.
428 429
*/

430 431 432 433 434 435 436
struct progids
{
    WCHAR        **progids;
    unsigned int   num;
    unsigned int   allocated;
};

437 438 439 440 441 442 443 444 445
struct entity
{
    DWORD kind;
    union
    {
        struct
        {
            WCHAR *tlbid;
            WCHAR *helpdir;
446 447 448
            WORD   flags;
            WORD   major;
            WORD   minor;
449 450 451 452
	} typelib;
        struct
        {
            WCHAR *clsid;
453 454
            WCHAR *tlbid;
            WCHAR *progid;
455 456
            WCHAR *name;    /* clrClass: class name */
            WCHAR *version; /* clrClass: CLR runtime version */
457 458 459 460 461 462
            DWORD  model;
            DWORD  miscstatus;
            DWORD  miscstatuscontent;
            DWORD  miscstatusthumbnail;
            DWORD  miscstatusicon;
            DWORD  miscstatusdocprint;
463
            struct progids progids;
464 465 466
	} comclass;
	struct {
            WCHAR *iid;
467 468
            WCHAR *base;
            WCHAR *tlib;
469
            WCHAR *name;
470 471 472 473
            WCHAR *ps32; /* only stored for 'comInterfaceExternalProxyStub' */
            DWORD  mask;
            ULONG  nummethods;
	} ifaceps;
474 475 476
        struct
        {
            WCHAR *name;
477
            BOOL   versioned;
478
        } class;
479 480 481 482
        struct
        {
            WCHAR *name;
            WCHAR *clsid;
483
            WCHAR *version;
484
        } clrsurrogate;
485 486 487 488
        struct
        {
            WCHAR *name;
            WCHAR *value;
489
            WCHAR *ns;
490
        } settings;
491 492 493
    } u;
};

494 495 496 497 498 499 500
struct entity_array
{
    struct entity        *base;
    unsigned int          num;
    unsigned int          allocated;
};

501 502 503
struct dll_redirect
{
    WCHAR                *name;
504
    WCHAR                *hash;
505
    struct entity_array   entities;
506 507
};

508 509 510
enum assembly_type
{
    APPLICATION_MANIFEST,
511 512
    ASSEMBLY_MANIFEST,
    ASSEMBLY_SHARED_MANIFEST,
513 514 515 516
};

struct assembly
{
517 518 519 520 521 522 523 524 525 526 527 528 529
    enum assembly_type             type;
    struct assembly_identity       id;
    struct file_info               manifest;
    WCHAR                         *directory;
    BOOL                           no_inherit;
    struct dll_redirect           *dlls;
    unsigned int                   num_dlls;
    unsigned int                   allocated_dlls;
    struct entity_array            entities;
    COMPATIBILITY_CONTEXT_ELEMENT *compat_contexts;
    ULONG                          num_compat_contexts;
    ACTCTX_REQUESTED_RUN_LEVEL     run_level;
    ULONG                          ui_access;
530 531
};

532 533
enum context_sections
{
534 535 536
    WINDOWCLASS_SECTION    = 1,
    DLLREDIRECT_SECTION    = 2,
    TLIBREDIRECT_SECTION   = 4,
537
    SERVERREDIRECT_SECTION = 8,
538
    IFACEREDIRECT_SECTION  = 16,
539 540
    CLRSURROGATES_SECTION  = 32,
    PROGIDREDIRECT_SECTION = 64
541 542
};

543 544 545 546
typedef struct _ACTIVATION_CONTEXT
{
    ULONG               magic;
    int                 ref_count;
547 548 549 550 551
    struct file_info    config;
    struct file_info    appdir;
    struct assembly    *assemblies;
    unsigned int        num_assemblies;
    unsigned int        allocated_assemblies;
552 553
    /* section data */
    DWORD               sections;
554 555
    struct strsection_header  *wndclass_section;
    struct strsection_header  *dllredirect_section;
556
    struct strsection_header  *progid_section;
557
    struct guidsection_header *tlib_section;
558
    struct guidsection_header *comserver_section;
559
    struct guidsection_header *ifaceps_section;
560
    struct guidsection_header *clrsurrogate_section;
561 562
} ACTIVATION_CONTEXT;

563 564 565 566 567 568 569 570
struct actctx_loader
{
    ACTIVATION_CONTEXT       *actctx;
    struct assembly_identity *dependencies;
    unsigned int              num_dependencies;
    unsigned int              allocated_dependencies;
};

571 572
static const xmlstr_t empty_xmlstr;

573 574 575
static const WCHAR asmv1W[] = {'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};
static const WCHAR asmv2W[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','a','s','m','.','v','2',0};
static const WCHAR asmv3W[] = {'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};
576 577 578 579 580 581 582 583 584 585 586 587
static const WCHAR assemblyW[] = {'a','s','s','e','m','b','l','y',0};
static const WCHAR assemblyIdentityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
static const WCHAR bindingRedirectW[] = {'b','i','n','d','i','n','g','R','e','d','i','r','e','c','t',0};
static const WCHAR clrClassW[] = {'c','l','r','C','l','a','s','s',0};
static const WCHAR clrSurrogateW[] = {'c','l','r','S','u','r','r','o','g','a','t','e',0};
static const WCHAR comClassW[] = {'c','o','m','C','l','a','s','s',0};
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};
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};
static const WCHAR dependencyW[] = {'d','e','p','e','n','d','e','n','c','y',0};
static const WCHAR dependentAssemblyW[] = {'d','e','p','e','n','d','e','n','t','A','s','s','e','m','b','l','y',0};
static const WCHAR descriptionW[] = {'d','e','s','c','r','i','p','t','i','o','n',0};
static const WCHAR fileW[] = {'f','i','l','e',0};
588
static const WCHAR hashW[] = {'h','a','s','h',0};
589 590 591 592 593 594 595 596 597 598 599 600
static const WCHAR noInheritW[] = {'n','o','I','n','h','e','r','i','t',0};
static const WCHAR noInheritableW[] = {'n','o','I','n','h','e','r','i','t','a','b','l','e',0};
static const WCHAR typelibW[] = {'t','y','p','e','l','i','b',0};
static const WCHAR windowClassW[] = {'w','i','n','d','o','w','C','l','a','s','s',0};

static const WCHAR clsidW[] = {'c','l','s','i','d',0};
static const WCHAR hashalgW[] = {'h','a','s','h','a','l','g',0};
static const WCHAR helpdirW[] = {'h','e','l','p','d','i','r',0};
static const WCHAR iidW[] = {'i','i','d',0};
static const WCHAR languageW[] = {'l','a','n','g','u','a','g','e',0};
static const WCHAR manifestVersionW[] = {'m','a','n','i','f','e','s','t','V','e','r','s','i','o','n',0};
static const WCHAR nameW[] = {'n','a','m','e',0};
601
static const WCHAR neutralW[] = {'n','e','u','t','r','a','l',0};
602 603 604 605
static const WCHAR newVersionW[] = {'n','e','w','V','e','r','s','i','o','n',0};
static const WCHAR oldVersionW[] = {'o','l','d','V','e','r','s','i','o','n',0};
static const WCHAR optionalW[] = {'o','p','t','i','o','n','a','l',0};
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};
606
static const WCHAR progidW[] = {'p','r','o','g','i','d',0};
607
static const WCHAR publicKeyTokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
608
static const WCHAR threadingmodelW[] = {'t','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
609 610 611 612
static const WCHAR tlbidW[] = {'t','l','b','i','d',0};
static const WCHAR typeW[] = {'t','y','p','e',0};
static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
613 614 615
static const WCHAR versionedW[] = {'v','e','r','s','i','o','n','e','d',0};
static const WCHAR yesW[] = {'y','e','s',0};
static const WCHAR noW[] = {'n','o',0};
616 617 618 619 620
static const WCHAR restrictedW[] = {'R','E','S','T','R','I','C','T','E','D',0};
static const WCHAR controlW[] = {'C','O','N','T','R','O','L',0};
static const WCHAR hiddenW[] = {'H','I','D','D','E','N',0};
static const WCHAR hasdiskimageW[] = {'H','A','S','D','I','S','K','I','M','A','G','E',0};
static const WCHAR flagsW[] = {'f','l','a','g','s',0};
621 622 623 624 625
static const WCHAR miscstatusW[] = {'m','i','s','c','S','t','a','t','u','s',0};
static const WCHAR miscstatusiconW[] = {'m','i','s','c','S','t','a','t','u','s','I','c','o','n',0};
static const WCHAR miscstatuscontentW[] = {'m','i','s','c','S','t','a','t','u','s','C','o','n','t','e','n','t',0};
static const WCHAR miscstatusthumbnailW[] = {'m','i','s','c','S','t','a','t','u','s','T','h','u','m','b','n','a','i','l',0};
static const WCHAR miscstatusdocprintW[] = {'m','i','s','c','S','t','a','t','u','s','D','o','c','P','r','i','n','t',0};
626 627 628
static const WCHAR baseInterfaceW[] = {'b','a','s','e','I','n','t','e','r','f','a','c','e',0};
static const WCHAR nummethodsW[] = {'n','u','m','M','e','t','h','o','d','s',0};
static const WCHAR proxyStubClsid32W[] = {'p','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
629
static const WCHAR runtimeVersionW[] = {'r','u','n','t','i','m','e','V','e','r','s','i','o','n',0};
630 631
static const WCHAR mscoreeW[] = {'M','S','C','O','R','E','E','.','D','L','L',0};
static const WCHAR mscoree2W[] = {'m','s','c','o','r','e','e','.','d','l','l',0};
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655

static const WCHAR activatewhenvisibleW[] = {'a','c','t','i','v','a','t','e','w','h','e','n','v','i','s','i','b','l','e',0};
static const WCHAR actslikebuttonW[] = {'a','c','t','s','l','i','k','e','b','u','t','t','o','n',0};
static const WCHAR actslikelabelW[] = {'a','c','t','s','l','i','k','e','l','a','b','e','l',0};
static const WCHAR alignableW[] = {'a','l','i','g','n','a','b','l','e',0};
static const WCHAR alwaysrunW[] = {'a','l','w','a','y','s','r','u','n',0};
static const WCHAR canlinkbyole1W[] = {'c','a','n','l','i','n','k','b','y','o','l','e','1',0};
static const WCHAR cantlinkinsideW[] = {'c','a','n','t','l','i','n','k','i','n','s','i','d','e',0};
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};
static const WCHAR imemodeW[] = {'i','m','e','m','o','d','e',0};
static const WCHAR insertnotreplaceW[] = {'i','n','s','e','r','t','n','o','t','r','e','p','l','a','c','e',0};
static const WCHAR insideoutW[] = {'i','n','s','i','d','e','o','u','t',0};
static const WCHAR invisibleatruntimeW[] = {'i','n','v','i','s','i','b','l','e','a','t','r','u','n','t','i','m','e',0};
static const WCHAR islinkobjectW[] = {'i','s','l','i','n','k','o','b','j','e','c','t',0};
static const WCHAR nouiactivateW[] = {'n','o','u','i','a','c','t','i','v','a','t','e',0};
static const WCHAR onlyiconicW[] = {'o','n','l','y','i','c','o','n','i','c',0};
static const WCHAR recomposeonresizeW[] = {'r','e','c','o','m','p','o','s','e','o','n','r','e','s','i','z','e',0};
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};
static const WCHAR setclientsitefirstW[] = {'s','e','t','c','l','i','e','n','t','s','i','t','e','f','i','r','s','t',0};
static const WCHAR simpleframeW[] = {'s','i','m','p','l','e','f','r','a','m','e',0};
static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
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};
static const WCHAR wantstomenumergeW[] = {'w','a','n','t','s','t','o','m','e','n','u','m','e','r','g','e',0};

656 657 658 659 660
static const WCHAR compatibilityW[] = {'c','o','m','p','a','t','i','b','i','l','i','t','y',0};
static const WCHAR compatibilityNSW[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','c','o','m','p','a','t','i','b','i','l','i','t','y','.','v','1',0};
static const WCHAR applicationW[] = {'a','p','p','l','i','c','a','t','i','o','n',0};
static const WCHAR supportedOSW[] = {'s','u','p','p','o','r','t','e','d','O','S',0};
static const WCHAR IdW[] = {'I','d',0};
661 662 663 664
static const WCHAR requestedExecutionLevelW[] = {'r','e','q','u','e','s','t','e','d','E','x','e','c','u','t','i','o','n','L','e','v','e','l',0};
static const WCHAR requestedPrivilegesW[] = {'r','e','q','u','e','s','t','e','d','P','r','i','v','i','l','e','g','e','s',0};
static const WCHAR securityW[] = {'s','e','c','u','r','i','t','y',0};
static const WCHAR trustInfoW[] = {'t','r','u','s','t','I','n','f','o',0};
665 666 667 668
static const WCHAR windowsSettingsW[] = {'w','i','n','d','o','w','s','S','e','t','t','i','n','g','s',0};
static const WCHAR autoElevateW[] = {'a','u','t','o','E','l','e','v','a','t','e',0};
static const WCHAR disableThemingW[] = {'d','i','s','a','b','l','e','T','h','e','m','i','n','g',0};
static const WCHAR disableWindowFilteringW[] = {'d','i','s','a','b','l','e','W','i','n','d','o','w','F','i','l','t','e','r','i','n','g',0};
669 670 671 672
static const WCHAR windowsSettings2005NSW[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','S','M','I','/','2','0','0','5','/','W','i','n','d','o','w','s','S','e','t','t','i','n','g','s',0};
static const WCHAR windowsSettings2011NSW[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','S','M','I','/','2','0','1','1','/','W','i','n','d','o','w','s','S','e','t','t','i','n','g','s',0};
static const WCHAR windowsSettings2016NSW[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','S','M','I','/','2','0','1','6','/','W','i','n','d','o','w','s','S','e','t','t','i','n','g','s',0};
static const WCHAR windowsSettings2017NSW[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','S','M','I','/','2','0','1','7','/','W','i','n','d','o','w','s','S','e','t','t','i','n','g','s',0};
673 674 675 676 677 678 679 680
static const WCHAR dpiAwareW[] = {'d','p','i','A','w','a','r','e',0};
static const WCHAR dpiAwarenessW[] = {'d','p','i','A','w','a','r','e','n','e','s','s',0};
static const WCHAR gdiScalingW[] = {'g','d','i','S','c','a','l','i','n','g',0};
static const WCHAR highResolutionScrollingAwareW[] = {'h','i','g','h','R','e','s','o','l','u','t','i','o','n','S','c','r','o','l','l','i','n','g','A','w','a','r','e',0};
static const WCHAR longPathAwareW[] = {'l','o','n','g','P','a','t','h','A','w','a','r','e',0};
static const WCHAR magicFutureSettingW[] = {'m','a','g','i','c','F','u','t','u','r','e','S','e','t','t','i','n','g',0};
static const WCHAR printerDriverIsolationW[] = {'p','r','i','n','t','e','r','D','r','i','v','e','r','I','s','o','l','a','t','i','o','n',0};
static const WCHAR ultraHighResolutionScrollingAwareW[] = {'u','l','t','r','a','H','i','g','h','R','e','s','o','l','u','t','i','o','n','S','c','r','o','l','l','i','n','g','A','w','a','r','e',0};
681

682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
struct olemisc_entry
{
    const WCHAR *name;
    OLEMISC value;
};

static const struct olemisc_entry olemisc_values[] =
{
    { activatewhenvisibleW,          OLEMISC_ACTIVATEWHENVISIBLE },
    { actslikebuttonW,               OLEMISC_ACTSLIKEBUTTON },
    { actslikelabelW,                OLEMISC_ACTSLIKELABEL },
    { alignableW,                    OLEMISC_ALIGNABLE },
    { alwaysrunW,                    OLEMISC_ALWAYSRUN },
    { canlinkbyole1W,                OLEMISC_CANLINKBYOLE1 },
    { cantlinkinsideW,               OLEMISC_CANTLINKINSIDE },
    { ignoreactivatewhenvisibleW,    OLEMISC_IGNOREACTIVATEWHENVISIBLE },
    { imemodeW,                      OLEMISC_IMEMODE },
    { insertnotreplaceW,             OLEMISC_INSERTNOTREPLACE },
    { insideoutW,                    OLEMISC_INSIDEOUT },
    { invisibleatruntimeW,           OLEMISC_INVISIBLEATRUNTIME },
    { islinkobjectW,                 OLEMISC_ISLINKOBJECT },
    { nouiactivateW,                 OLEMISC_NOUIACTIVATE },
    { onlyiconicW,                   OLEMISC_ONLYICONIC },
    { recomposeonresizeW,            OLEMISC_RECOMPOSEONRESIZE },
    { renderingisdeviceindependentW, OLEMISC_RENDERINGISDEVICEINDEPENDENT },
    { setclientsitefirstW,           OLEMISC_SETCLIENTSITEFIRST },
    { simpleframeW,                  OLEMISC_SIMPLEFRAME },
    { staticW,                       OLEMISC_STATIC },
    { supportsmultilevelundoW,       OLEMISC_SUPPORTSMULTILEVELUNDO },
    { wantstomenumergeW,             OLEMISC_WANTSTOMENUMERGE }
};
713 714

static const WCHAR xmlW[] = {'?','x','m','l',0};
715
static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
716
static const WCHAR version_formatW[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
717
static const WCHAR wildcardW[] = {'*',0};
718

719 720
static ACTIVATION_CONTEXT system_actctx = { ACTCTX_MAGIC, 1 };
static ACTIVATION_CONTEXT *process_actctx = &system_actctx;
721

722 723 724 725 726 727 728 729 730
static WCHAR *strdupW(const WCHAR* str)
{
    WCHAR*      ptr;

    if (!(ptr = RtlAllocateHeap(GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR))))
        return NULL;
    return strcpyW(ptr, str);
}

731 732 733 734
static WCHAR *xmlstrdupW(const xmlstr_t* str)
{
    WCHAR *strW;

735
    if ((strW = RtlAllocateHeap(GetProcessHeap(), 0, (str->len + 1) * sizeof(WCHAR))))
736
    {
737 738
        memcpy( strW, str->ptr, str->len * sizeof(WCHAR) );
        strW[str->len] = 0;
739 740 741 742
    }
    return strW;
}

743
static inline BOOL xmlstr_cmp(const xmlstr_t* xmlstr, const WCHAR *str)
744
{
745
    return !strncmpW(xmlstr->ptr, str, xmlstr->len) && !str[xmlstr->len];
746 747
}

748 749 750 751 752
static inline BOOL xmlstr_cmpi(const xmlstr_t* xmlstr, const WCHAR *str)
{
    return !strncmpiW(xmlstr->ptr, str, xmlstr->len) && !str[xmlstr->len];
}

753
static BOOL xml_attr_cmp( const struct xml_attr *attr, const WCHAR *str )
754
{
755
    return xmlstr_cmp( &attr->name, str );
756 757
}

758
static BOOL xml_name_cmp( const struct xml_elem *elem1, const struct xml_elem *elem2 )
759
{
760 761 762 763 764
    return (elem1->name.len == elem2->name.len &&
            elem1->ns.len == elem2->ns.len &&
            !strncmpW( elem1->name.ptr, elem2->name.ptr, elem1->name.len ) &&
            !strncmpW( elem1->ns.ptr, elem2->ns.ptr, elem1->ns.len ));
}
765

766 767
static inline BOOL xml_elem_cmp(const struct xml_elem *elem, const WCHAR *str, const WCHAR *namespace)
{
768 769 770 771 772 773 774 775 776 777 778 779
    if (!xmlstr_cmp( &elem->name, str )) return FALSE;
    if (xmlstr_cmp( &elem->ns, namespace )) return TRUE;
    if (!strcmpW( namespace, asmv1W ))
    {
        if (xmlstr_cmp( &elem->ns, asmv2W )) return TRUE;
        if (xmlstr_cmp( &elem->ns, asmv3W )) return TRUE;
    }
    else if (!strcmpW( namespace, asmv2W ))
    {
        if (xmlstr_cmp( &elem->ns, asmv3W )) return TRUE;
    }
    return FALSE;
780 781
}

782
static inline BOOL isxmlspace( WCHAR ch )
783 784 785 786 787 788
{
    return (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t');
}

static inline const char* debugstr_xmlstr(const xmlstr_t* str)
{
789
    return debugstr_wn(str->ptr, str->len);
790 791
}

792 793
static inline const char *debugstr_xml_elem( const struct xml_elem *elem )
{
794 795
    return wine_dbg_sprintf( "%s ns %s", debugstr_wn( elem->name.ptr, elem->name.len ),
                             debugstr_wn( elem->ns.ptr, elem->ns.len ));
796 797 798 799 800 801 802 803
}

static inline const char *debugstr_xml_attr( const struct xml_attr *attr )
{
    return wine_dbg_sprintf( "%s=%s", debugstr_wn( attr->name.ptr, attr->name.len ),
                             debugstr_wn( attr->value.ptr, attr->value.len ));
}

804
static inline const char* debugstr_version(const struct assembly_version *ver)
805 806 807 808
{
    return wine_dbg_sprintf("%u.%u.%u.%u", ver->major, ver->minor, ver->build, ver->revision);
}

809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
static struct assembly *add_assembly(ACTIVATION_CONTEXT *actctx, enum assembly_type at)
{
    struct assembly *assembly;

    if (actctx->num_assemblies == actctx->allocated_assemblies)
    {
        void *ptr;
        unsigned int new_count;
        if (actctx->assemblies)
        {
            new_count = actctx->allocated_assemblies * 2;
            ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                     actctx->assemblies, new_count * sizeof(*assembly) );
        }
        else
        {
            new_count = 4;
            ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*assembly) );
        }
        if (!ptr) return NULL;
        actctx->assemblies = ptr;
        actctx->allocated_assemblies = new_count;
    }

    assembly = &actctx->assemblies[actctx->num_assemblies++];
    assembly->type = at;
    return assembly;
}

838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
static struct dll_redirect* add_dll_redirect(struct assembly* assembly)
{
    if (assembly->num_dlls == assembly->allocated_dlls)
    {
        void *ptr;
        unsigned int new_count;
        if (assembly->dlls)
        {
            new_count = assembly->allocated_dlls * 2;
            ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                     assembly->dlls, new_count * sizeof(*assembly->dlls) );
        }
        else
        {
            new_count = 4;
            ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*assembly->dlls) );
        }
        if (!ptr) return NULL;
        assembly->dlls = ptr;
        assembly->allocated_dlls = new_count;
    }
    return &assembly->dlls[assembly->num_dlls++];
}

862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
static PCOMPATIBILITY_CONTEXT_ELEMENT add_compat_context(struct assembly* assembly)
{
    void *ptr;
    if (assembly->num_compat_contexts)
    {
        unsigned int new_count = assembly->num_compat_contexts + 1;
        ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                 assembly->compat_contexts,
                                 new_count * sizeof(COMPATIBILITY_CONTEXT_ELEMENT) );
    }
    else
    {
        ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMPATIBILITY_CONTEXT_ELEMENT) );
    }
    if (!ptr) return NULL;
    assembly->compat_contexts = ptr;
    return &assembly->compat_contexts[assembly->num_compat_contexts++];
}

881 882 883
static void free_assembly_identity(struct assembly_identity *ai)
{
    RtlFreeHeap( GetProcessHeap(), 0, ai->name );
884
    RtlFreeHeap( GetProcessHeap(), 0, ai->arch );
885
    RtlFreeHeap( GetProcessHeap(), 0, ai->public_key );
886
    RtlFreeHeap( GetProcessHeap(), 0, ai->language );
887
    RtlFreeHeap( GetProcessHeap(), 0, ai->type );
888 889
}

890
static struct entity* add_entity(struct entity_array *array, DWORD kind)
891 892 893
{
    struct entity*      entity;

894
    if (array->num == array->allocated)
895 896 897
    {
        void *ptr;
        unsigned int new_count;
898
        if (array->base)
899
        {
900
            new_count = array->allocated * 2;
901
            ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
902
                                     array->base, new_count * sizeof(*array->base) );
903 904 905 906
        }
        else
        {
            new_count = 4;
907
            ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*array->base) );
908 909
        }
        if (!ptr) return NULL;
910 911
        array->base = ptr;
        array->allocated = new_count;
912
    }
913
    entity = &array->base[array->num++];
914 915 916 917
    entity->kind = kind;
    return entity;
}

918
static void free_entity_array(struct entity_array *array)
919
{
920
    unsigned int i, j;
921
    for (i = 0; i < array->num; i++)
922
    {
923 924 925 926 927
        struct entity *entity = &array->base[i];
        switch (entity->kind)
        {
        case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.comclass.clsid);
928 929
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.comclass.tlbid);
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.comclass.progid);
930 931
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.comclass.name);
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.comclass.version);
932 933 934
            for (j = 0; j < entity->u.comclass.progids.num; j++)
                RtlFreeHeap(GetProcessHeap(), 0, entity->u.comclass.progids.progids[j]);
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.comclass.progids.progids);
935 936
            break;
        case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
937 938 939 940
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.ifaceps.iid);
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.ifaceps.base);
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.ifaceps.ps32);
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.ifaceps.name);
941
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.ifaceps.tlib);
942 943 944 945 946 947 948 949
            break;
        case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION:
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.typelib.tlbid);
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.typelib.helpdir);
            break;
        case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION:
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.class.name);
            break;
950 951 952
        case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES:
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.clrsurrogate.name);
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.clrsurrogate.clsid);
953
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.clrsurrogate.version);
954
            break;
955 956 957
        case ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS:
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.settings.name);
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.settings.value);
958
            RtlFreeHeap(GetProcessHeap(), 0, entity->u.settings.ns);
959
            break;
960 961 962
        default:
            FIXME("Unknown entity kind %d\n", entity->kind);
        }
963
    }
964
    RtlFreeHeap( GetProcessHeap(), 0, array->base );
965 966
}

967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
static BOOL is_matching_string( const WCHAR *str1, const WCHAR *str2 )
{
    if (!str1) return !str2;
    return str2 && !strcmpiW( str1, str2 );
}

static BOOL is_matching_identity( const struct assembly_identity *id1,
                                  const struct assembly_identity *id2 )
{
    if (!is_matching_string( id1->name, id2->name )) return FALSE;
    if (!is_matching_string( id1->arch, id2->arch )) return FALSE;
    if (!is_matching_string( id1->public_key, id2->public_key )) return FALSE;

    if (id1->language && id2->language && strcmpiW( id1->language, id2->language ))
    {
        if (strcmpW( wildcardW, id1->language ) && strcmpW( wildcardW, id2->language ))
            return FALSE;
    }
    if (id1->version.major != id2->version.major) return FALSE;
    if (id1->version.minor != id2->version.minor) return FALSE;
    if (id1->version.build > id2->version.build) return FALSE;
    if (id1->version.build == id2->version.build &&
        id1->version.revision > id2->version.revision) return FALSE;
    return TRUE;
}

993 994 995
static BOOL add_dependent_assembly_id(struct actctx_loader* acl,
                                      struct assembly_identity* ai)
{
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
    unsigned int i;

    /* check if we already have that assembly */

    for (i = 0; i < acl->actctx->num_assemblies; i++)
        if (is_matching_identity( ai, &acl->actctx->assemblies[i].id ))
        {
            TRACE( "reusing existing assembly for %s arch %s version %u.%u.%u.%u\n",
                   debugstr_w(ai->name), debugstr_w(ai->arch), ai->version.major, ai->version.minor,
                   ai->version.build, ai->version.revision );
            return TRUE;
        }

    for (i = 0; i < acl->num_dependencies; i++)
        if (is_matching_identity( ai, &acl->dependencies[i] ))
        {
            TRACE( "reusing existing dependency for %s arch %s version %u.%u.%u.%u\n",
                   debugstr_w(ai->name), debugstr_w(ai->arch), ai->version.major, ai->version.minor,
                   ai->version.build, ai->version.revision );
            return TRUE;
        }

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
    if (acl->num_dependencies == acl->allocated_dependencies)
    {
        void *ptr;
        unsigned int new_count;
        if (acl->dependencies)
        {
            new_count = acl->allocated_dependencies * 2;
            ptr = RtlReAllocateHeap(GetProcessHeap(), 0, acl->dependencies,
                                    new_count * sizeof(acl->dependencies[0]));
        }
        else
        {
            new_count = 4;
            ptr = RtlAllocateHeap(GetProcessHeap(), 0, new_count * sizeof(acl->dependencies[0]));
        }
        if (!ptr) return FALSE;
        acl->dependencies = ptr;
        acl->allocated_dependencies = new_count;
    }
    acl->dependencies[acl->num_dependencies++] = *ai;

    return TRUE;
}

static void free_depend_manifests(struct actctx_loader* acl)
{
    unsigned int i;
    for (i = 0; i < acl->num_dependencies; i++)
        free_assembly_identity(&acl->dependencies[i]);
    RtlFreeHeap(GetProcessHeap(), 0, acl->dependencies);
}

1050 1051 1052 1053 1054 1055
static WCHAR *build_assembly_dir(struct assembly_identity* ai)
{
    static const WCHAR undW[] = {'_',0};
    static const WCHAR noneW[] = {'n','o','n','e',0};
    static const WCHAR mskeyW[] = {'d','e','a','d','b','e','e','f',0};

1056
    const WCHAR *arch = ai->arch ? ai->arch : noneW;
1057 1058
    const WCHAR *key = ai->public_key ? ai->public_key : noneW;
    const WCHAR *lang = ai->language ? ai->language : noneW;
1059 1060 1061
    const WCHAR *name = ai->name ? ai->name : noneW;
    SIZE_T size = (strlenW(arch) + 1 + strlenW(name) + 1 + strlenW(key) + 24 + 1 +
		    strlenW(lang) + 1) * sizeof(WCHAR) + sizeof(mskeyW);
1062 1063 1064 1065
    WCHAR *ret;

    if (!(ret = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return NULL;

1066
    strcpyW( ret, arch );
1067
    strcatW( ret, undW );
1068
    strcatW( ret, name );
1069 1070 1071
    strcatW( ret, undW );
    strcatW( ret, key );
    strcatW( ret, undW );
1072
    sprintfW( ret + strlenW(ret), version_formatW,
1073 1074 1075 1076 1077 1078 1079 1080
              ai->version.major, ai->version.minor, ai->version.build, ai->version.revision );
    strcatW( ret, undW );
    strcatW( ret, lang );
    strcatW( ret, undW );
    strcatW( ret, mskeyW );
    return ret;
}

1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
static inline void append_string( WCHAR *buffer, const WCHAR *prefix, const WCHAR *str )
{
    WCHAR *p = buffer;

    if (!str) return;
    strcatW( buffer, prefix );
    p += strlenW(p);
    *p++ = '"';
    strcpyW( p, str );
    p += strlenW(p);
    *p++ = '"';
    *p = 0;
}

static WCHAR *build_assembly_id( const struct assembly_identity *ai )
{
    static const WCHAR archW[] =
        {',','p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e','=',0};
    static const WCHAR public_keyW[] =
1100
        {',','p','u','b','l','i','c','K','e','y','T','o','k','e','n','=',0};
1101
    static const WCHAR typeW[] =
1102
        {',','t','y','p','e','=',0};
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
    static const WCHAR versionW[] =
        {',','v','e','r','s','i','o','n','=',0};

    WCHAR version[64], *ret;
    SIZE_T size = 0;

    sprintfW( version, version_formatW,
              ai->version.major, ai->version.minor, ai->version.build, ai->version.revision );
    if (ai->name) size += strlenW(ai->name) * sizeof(WCHAR);
    if (ai->arch) size += strlenW(archW) + strlenW(ai->arch) + 2;
    if (ai->public_key) size += strlenW(public_keyW) + strlenW(ai->public_key) + 2;
1114
    if (ai->type) size += strlenW(typeW) + strlenW(ai->type) + 2;
1115 1116 1117 1118 1119 1120 1121 1122 1123
    size += strlenW(versionW) + strlenW(version) + 2;

    if (!(ret = RtlAllocateHeap( GetProcessHeap(), 0, (size + 1) * sizeof(WCHAR) )))
        return NULL;

    if (ai->name) strcpyW( ret, ai->name );
    else *ret = 0;
    append_string( ret, archW, ai->arch );
    append_string( ret, public_keyW, ai->public_key );
1124
    append_string( ret, typeW, ai->type );
1125 1126 1127 1128
    append_string( ret, versionW, version );
    return ret;
}

1129 1130
static ACTIVATION_CONTEXT *check_actctx( HANDLE h )
{
1131
    ACTIVATION_CONTEXT *ret = NULL, *actctx = h;
1132 1133

    if (!h || h == INVALID_HANDLE_VALUE) return NULL;
1134 1135 1136 1137 1138
    __TRY
    {
        if (actctx->magic == ACTCTX_MAGIC) ret = actctx;
    }
    __EXCEPT_PAGE_FAULT
1139 1140
    {
    }
1141 1142
    __ENDTRY
    return ret;
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
}

static inline void actctx_addref( ACTIVATION_CONTEXT *actctx )
{
    interlocked_xchg_add( &actctx->ref_count, 1 );
}

static void actctx_release( ACTIVATION_CONTEXT *actctx )
{
    if (interlocked_xchg_add( &actctx->ref_count, -1 ) == 1)
    {
1154
        unsigned int i, j;
1155 1156 1157

        for (i = 0; i < actctx->num_assemblies; i++)
        {
1158 1159 1160 1161
            struct assembly *assembly = &actctx->assemblies[i];
            for (j = 0; j < assembly->num_dlls; j++)
            {
                struct dll_redirect *dll = &assembly->dlls[j];
1162
                free_entity_array( &dll->entities );
1163
                RtlFreeHeap( GetProcessHeap(), 0, dll->name );
1164
                RtlFreeHeap( GetProcessHeap(), 0, dll->hash );
1165 1166 1167
            }
            RtlFreeHeap( GetProcessHeap(), 0, assembly->dlls );
            RtlFreeHeap( GetProcessHeap(), 0, assembly->manifest.info );
1168
            RtlFreeHeap( GetProcessHeap(), 0, assembly->directory );
1169
            RtlFreeHeap( GetProcessHeap(), 0, assembly->compat_contexts );
1170
            free_entity_array( &assembly->entities );
1171
            free_assembly_identity(&assembly->id);
1172 1173 1174 1175
        }
        RtlFreeHeap( GetProcessHeap(), 0, actctx->config.info );
        RtlFreeHeap( GetProcessHeap(), 0, actctx->appdir.info );
        RtlFreeHeap( GetProcessHeap(), 0, actctx->assemblies );
1176
        RtlFreeHeap( GetProcessHeap(), 0, actctx->dllredirect_section );
1177
        RtlFreeHeap( GetProcessHeap(), 0, actctx->wndclass_section );
1178
        RtlFreeHeap( GetProcessHeap(), 0, actctx->tlib_section );
1179
        RtlFreeHeap( GetProcessHeap(), 0, actctx->comserver_section );
1180
        RtlFreeHeap( GetProcessHeap(), 0, actctx->ifaceps_section );
1181
        RtlFreeHeap( GetProcessHeap(), 0, actctx->clrsurrogate_section );
1182
        RtlFreeHeap( GetProcessHeap(), 0, actctx->progid_section );
1183 1184 1185 1186 1187
        actctx->magic = 0;
        RtlFreeHeap( GetProcessHeap(), 0, actctx );
    }
}

1188 1189 1190 1191 1192 1193
static BOOL set_error( xmlbuf_t *xmlbuf )
{
    xmlbuf->error = TRUE;
    return FALSE;
}

1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
static BOOL is_xmlns_attr( const struct xml_attr *attr )
{
    const int len = strlenW( xmlnsW );
    if (attr->name.len < len) return FALSE;
    if (strncmpW( attr->name.ptr, xmlnsW, len )) return FALSE;
    return (attr->name.len == len || attr->name.ptr[len] == ':');
}

static void push_xmlns( xmlbuf_t *xmlbuf, const struct xml_attr *attr )
{
    const int len = strlenW( xmlnsW );
    struct xml_attr *ns;

    if (xmlbuf->ns_pos == MAX_NAMESPACES - 1)
    {
        FIXME( "too many namespaces in manifest\n" );
        set_error( xmlbuf );
        return;
    }
    ns = &xmlbuf->namespaces[xmlbuf->ns_pos++];
    ns->value = attr->value;
    if (attr->name.len > len)
    {
        ns->name.ptr = attr->name.ptr + len + 1;
        ns->name.len = attr->name.len - len - 1;
    }
    else ns->name = empty_xmlstr;
}

static xmlstr_t find_xmlns( xmlbuf_t *xmlbuf, const xmlstr_t *name )
{
    int i;

    for (i = xmlbuf->ns_pos - 1; i >= 0; i--)
    {
        if (xmlbuf->namespaces[i].name.len == name->len &&
            !strncmpW( xmlbuf->namespaces[i].name.ptr, name->ptr, name->len ))
            return xmlbuf->namespaces[i].value;
    }
    if (xmlbuf->ns_pos) WARN( "namespace %s not found\n", debugstr_xmlstr( name ));
    return empty_xmlstr;
}

1237
static BOOL next_xml_attr(xmlbuf_t *xmlbuf, struct xml_attr *attr, BOOL *end)
1238
{
1239
    const WCHAR* ptr;
1240

1241
    if (xmlbuf->error) return FALSE;
1242 1243 1244 1245

    while (xmlbuf->ptr < xmlbuf->end && isxmlspace(*xmlbuf->ptr))
        xmlbuf->ptr++;

1246
    if (xmlbuf->ptr == xmlbuf->end) return set_error( xmlbuf );
1247 1248 1249 1250 1251

    if (*xmlbuf->ptr == '/')
    {
        xmlbuf->ptr++;
        if (xmlbuf->ptr == xmlbuf->end || *xmlbuf->ptr != '>')
1252
            return set_error( xmlbuf );
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267

        xmlbuf->ptr++;
        *end = TRUE;
        return FALSE;
    }

    if (*xmlbuf->ptr == '>')
    {
        xmlbuf->ptr++;
        return FALSE;
    }

    ptr = xmlbuf->ptr;
    while (ptr < xmlbuf->end && *ptr != '=' && *ptr != '>' && !isxmlspace(*ptr)) ptr++;

1268
    if (ptr == xmlbuf->end) return set_error( xmlbuf );
1269

1270 1271
    attr->name.ptr = xmlbuf->ptr;
    attr->name.len = ptr-xmlbuf->ptr;
1272 1273
    xmlbuf->ptr = ptr;

1274 1275
    /* skip spaces before '=' */
    while (ptr < xmlbuf->end && *ptr != '=' && isxmlspace(*ptr)) ptr++;
1276
    if (ptr == xmlbuf->end || *ptr != '=') return set_error( xmlbuf );
1277 1278

    /* skip '=' itself */
1279
    ptr++;
1280
    if (ptr == xmlbuf->end) return set_error( xmlbuf );
1281 1282 1283 1284

    /* skip spaces after '=' */
    while (ptr < xmlbuf->end && *ptr != '"' && *ptr != '\'' && isxmlspace(*ptr)) ptr++;

1285
    if (ptr == xmlbuf->end || (*ptr != '"' && *ptr != '\'')) return set_error( xmlbuf );
1286

1287
    attr->value.ptr = ++ptr;
1288
    if (ptr == xmlbuf->end) return set_error( xmlbuf );
1289

1290
    ptr = memchrW(ptr, ptr[-1], xmlbuf->end - ptr);
1291 1292 1293
    if (!ptr)
    {
        xmlbuf->ptr = xmlbuf->end;
1294
        return set_error( xmlbuf );
1295 1296
    }

1297
    attr->value.len = ptr - attr->value.ptr;
1298
    xmlbuf->ptr = ptr + 1;
1299
    if (xmlbuf->ptr != xmlbuf->end) return TRUE;
1300

1301
    return set_error( xmlbuf );
1302 1303
}

1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
static void read_xml_elem( xmlbuf_t *xmlbuf, struct xml_elem *elem )
{
    const WCHAR* ptr = xmlbuf->ptr;

    elem->ns = empty_xmlstr;
    elem->name.ptr = ptr;
    while (ptr < xmlbuf->end && !isxmlspace(*ptr) && *ptr != '>' && *ptr != '/')
    {
        if (*ptr == ':')
        {
            elem->ns.ptr = elem->name.ptr;
            elem->ns.len = ptr - elem->ns.ptr;
            elem->name.ptr = ptr + 1;
        }
        ptr++;
    }
    elem->name.len = ptr - elem->name.ptr;
    xmlbuf->ptr = ptr;
}

1324
static BOOL next_xml_elem( xmlbuf_t *xmlbuf, struct xml_elem *elem, const struct xml_elem *parent )
1325
{
1326
    const WCHAR* ptr;
1327 1328 1329 1330 1331
    struct xml_attr attr;
    xmlbuf_t attr_buf;
    BOOL end = FALSE;

    xmlbuf->ns_pos = parent->ns_pos;  /* restore namespace stack to parent state */
1332

1333 1334
    if (xmlbuf->error) return FALSE;

1335
    for (;;)
1336
    {
1337
        ptr = memchrW(xmlbuf->ptr, '<', xmlbuf->end - xmlbuf->ptr);
1338 1339 1340
        if (!ptr)
        {
            xmlbuf->ptr = xmlbuf->end;
1341
            return set_error( xmlbuf );
1342 1343
        }
        ptr++;
1344
        if (ptr + 3 < xmlbuf->end && ptr[0] == '!' && ptr[1] == '-' && ptr[2] == '-') /* skip comment */
1345 1346 1347 1348 1349 1350 1351
        {
            for (ptr += 3; ptr + 3 <= xmlbuf->end; ptr++)
                if (ptr[0] == '-' && ptr[1] == '-' && ptr[2] == '>') break;

            if (ptr + 3 > xmlbuf->end)
            {
                xmlbuf->ptr = xmlbuf->end;
1352
                return set_error( xmlbuf );
1353 1354 1355 1356
            }
            xmlbuf->ptr = ptr + 3;
        }
        else break;
1357 1358
    }

1359
    xmlbuf->ptr = ptr;
1360
    /* check for element terminating the parent element */
1361
    if (ptr < xmlbuf->end && *ptr == '/')
1362
    {
1363 1364
        xmlbuf->ptr++;
        read_xml_elem( xmlbuf, elem );
1365
        elem->ns = find_xmlns( xmlbuf, &elem->ns );
1366 1367 1368 1369 1370 1371 1372 1373
        if (!xml_name_cmp( elem, parent ))
        {
            ERR( "wrong closing element %s for %s\n",
                 debugstr_xmlstr(&elem->name), debugstr_xmlstr(&parent->name ));
            return set_error( xmlbuf );
        }
        while (xmlbuf->ptr < xmlbuf->end && isxmlspace(*xmlbuf->ptr)) xmlbuf->ptr++;
        if (xmlbuf->ptr == xmlbuf->end || *xmlbuf->ptr++ != '>') return set_error( xmlbuf );
1374 1375 1376
        return FALSE;
    }

1377
    read_xml_elem( xmlbuf, elem );
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387

    /* parse namespace attributes */
    attr_buf = *xmlbuf;
    while (next_xml_attr( &attr_buf, &attr, &end ))
    {
        if (is_xmlns_attr( &attr )) push_xmlns( xmlbuf, &attr );
    }
    elem->ns = find_xmlns( xmlbuf, &elem->ns );
    elem->ns_pos = xmlbuf->ns_pos;

1388 1389 1390
    if (xmlbuf->ptr != xmlbuf->end) return TRUE;

    return set_error( xmlbuf );
1391 1392 1393 1394 1395
}

static BOOL parse_xml_header(xmlbuf_t* xmlbuf)
{
    /* FIXME: parse attributes */
1396
    const WCHAR *ptr;
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408

    for (ptr = xmlbuf->ptr; ptr < xmlbuf->end - 1; ptr++)
    {
        if (ptr[0] == '?' && ptr[1] == '>')
        {
            xmlbuf->ptr = ptr + 2;
            return TRUE;
        }
    }
    return FALSE;
}

1409 1410
static BOOL parse_text_content(xmlbuf_t* xmlbuf, xmlstr_t* content)
{
1411
    const WCHAR *ptr;
1412

1413 1414 1415
    if (xmlbuf->error) return FALSE;

    if (!(ptr = memchrW(xmlbuf->ptr, '<', xmlbuf->end - xmlbuf->ptr))) return set_error( xmlbuf );
1416 1417 1418 1419 1420 1421 1422 1423

    content->ptr = xmlbuf->ptr;
    content->len = ptr - xmlbuf->ptr;
    xmlbuf->ptr = ptr;

    return TRUE;
}

1424
static BOOL parse_version(const xmlstr_t *str, struct assembly_version *version)
1425 1426 1427
{
    unsigned int ver[4];
    unsigned int pos;
1428
    const WCHAR *curr;
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455

    /* major.minor.build.revision */
    ver[0] = ver[1] = ver[2] = ver[3] = pos = 0;
    for (curr = str->ptr; curr < str->ptr + str->len; curr++)
    {
        if (*curr >= '0' && *curr <= '9')
        {
            ver[pos] = ver[pos] * 10 + *curr - '0';
            if (ver[pos] >= 0x10000) goto error;
        }
        else if (*curr == '.')
        {
            if (++pos >= 4) goto error;
        }
        else goto error;
    }
    version->major = ver[0];
    version->minor = ver[1];
    version->build = ver[2];
    version->revision = ver[3];
    return TRUE;

error:
    FIXME( "Wrong version definition in manifest file (%s)\n", debugstr_xmlstr(str) );
    return FALSE;
}

1456
static void parse_expect_no_attr(xmlbuf_t* xmlbuf, BOOL* end)
1457
{
1458
    struct xml_attr attr;
1459

1460
    while (next_xml_attr(xmlbuf, &attr, end))
1461
    {
1462
        if (!is_xmlns_attr( &attr )) WARN("unexpected attr %s\n", debugstr_xml_attr(&attr));
1463 1464 1465
    }
}

1466
static void parse_expect_end_elem( xmlbuf_t *xmlbuf, const struct xml_elem *parent )
1467
{
1468
    struct xml_elem elem;
1469 1470

    if (next_xml_elem(xmlbuf, &elem, parent))
1471
    {
1472
        FIXME( "unexpected element %s\n", debugstr_xml_elem(&elem) );
1473
        set_error( xmlbuf );
1474 1475 1476
    }
}

1477
static void parse_unknown_elem(xmlbuf_t *xmlbuf, const struct xml_elem *parent)
1478
{
1479 1480
    struct xml_elem elem;
    struct xml_attr attr;
1481
    BOOL end = FALSE;
1482

1483 1484
    while (next_xml_attr(xmlbuf, &attr, &end));
    if (end) return;
1485

1486 1487
    while (next_xml_elem(xmlbuf, &elem, parent))
        parse_unknown_elem(xmlbuf, &elem);
1488 1489
}

1490
static void parse_assembly_identity_elem(xmlbuf_t *xmlbuf, ACTIVATION_CONTEXT *actctx,
1491
                                         struct assembly_identity* ai, const struct xml_elem *parent)
1492
{
1493
    struct xml_attr attr;
1494
    BOOL end = FALSE;
1495

1496
    while (next_xml_attr(xmlbuf, &attr, &end))
1497
    {
1498
        if (xml_attr_cmp(&attr, nameW))
1499
        {
1500
            if (!(ai->name = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1501
        }
1502
        else if (xml_attr_cmp(&attr, typeW))
1503
        {
1504
            if (!(ai->type = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1505
        }
1506
        else if (xml_attr_cmp(&attr, versionW))
1507
        {
1508
            if (!parse_version(&attr.value, &ai->version)) set_error( xmlbuf );
1509
        }
1510
        else if (xml_attr_cmp(&attr, processorArchitectureW))
1511
        {
1512
            if (!(ai->arch = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1513
        }
1514
        else if (xml_attr_cmp(&attr, publicKeyTokenW))
1515
        {
1516
            if (!(ai->public_key = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1517
        }
1518
        else if (xml_attr_cmp(&attr, languageW))
1519
        {
1520
            if (!(ai->language = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1521
        }
1522
        else if (!is_xmlns_attr( &attr ))
1523
        {
1524
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
1525 1526 1527
        }
    }

1528 1529 1530
    TRACE( "name=%s version=%s arch=%s\n",
           debugstr_w(ai->name), debugstr_version(&ai->version), debugstr_w(ai->arch) );

1531
    if (!end) parse_expect_end_elem(xmlbuf, parent);
1532 1533
}

1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558
static enum comclass_threadingmodel parse_com_class_threadingmodel(xmlstr_t *value)
{
    static const WCHAR apartW[] = {'A','p','a','r','t','m','e','n','t',0};
    static const WCHAR neutralW[] = {'N','e','u','t','r','a','l',0};
    static const WCHAR freeW[] = {'F','r','e','e',0};
    static const WCHAR bothW[] = {'B','o','t','h',0};

    if (value->len == 0) return ThreadingModel_No;
    if (xmlstr_cmp(value, apartW))
        return ThreadingModel_Apartment;
    else if (xmlstr_cmp(value, freeW))
        return ThreadingModel_Free;
    else if (xmlstr_cmp(value, bothW))
        return ThreadingModel_Both;
    else if (xmlstr_cmp(value, neutralW))
        return ThreadingModel_Neutral;
    else
        return ThreadingModel_No;
};

static OLEMISC get_olemisc_value(const WCHAR *str, int len)
{
    int min, max;

    min = 0;
1559
    max = ARRAY_SIZE(olemisc_values) - 1;
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602

    while (min <= max)
    {
        int n, c;

        n = (min+max)/2;

        c = strncmpW(olemisc_values[n].name, str, len);
        if (!c && !olemisc_values[n].name[len])
            return olemisc_values[n].value;

        if (c >= 0)
            max = n-1;
        else
            min = n+1;
    }

    WARN("unknown flag %s\n", debugstr_wn(str, len));
    return 0;
}

static DWORD parse_com_class_misc(const xmlstr_t *value)
{
    const WCHAR *str = value->ptr, *start;
    DWORD flags = 0;
    int i = 0;

    /* it's comma separated list of flags */
    while (i < value->len)
    {
        start = str;
        while (*str != ',' && (i++ < value->len)) str++;

        flags |= get_olemisc_value(start, str-start);

        /* skip separator */
        str++;
        i++;
    }

    return flags;
}

1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614
static BOOL com_class_add_progid(const xmlstr_t *progid, struct entity *entity)
{
    struct progids *progids = &entity->u.comclass.progids;

    if (progids->allocated == 0)
    {
        progids->allocated = 4;
        if (!(progids->progids = RtlAllocateHeap(GetProcessHeap(), 0, progids->allocated * sizeof(WCHAR*)))) return FALSE;
    }

    if (progids->allocated == progids->num)
    {
1615 1616 1617
        WCHAR **new_progids = RtlReAllocateHeap(GetProcessHeap(), 0, progids->progids,
                                                2 * progids->allocated * sizeof(WCHAR*));
        if (!new_progids) return FALSE;
1618
        progids->allocated *= 2;
1619
        progids->progids = new_progids;
1620 1621 1622 1623 1624 1625 1626 1627
    }

    if (!(progids->progids[progids->num] = xmlstrdupW(progid))) return FALSE;
    progids->num++;

    return TRUE;
}

1628
static void parse_com_class_progid(xmlbuf_t *xmlbuf, struct entity *entity, const struct xml_elem *parent)
1629 1630 1631 1632
{
    xmlstr_t content;
    BOOL end = FALSE;

1633 1634 1635
    parse_expect_no_attr(xmlbuf, &end);
    if (end) set_error( xmlbuf );
    if (!parse_text_content(xmlbuf, &content)) return;
1636

1637
    if (!com_class_add_progid(&content, entity)) set_error( xmlbuf );
1638
    parse_expect_end_elem(xmlbuf, parent);
1639 1640
}

1641 1642
static void parse_com_class_elem( xmlbuf_t *xmlbuf, struct dll_redirect *dll, struct actctx_loader *acl,
                                  const struct xml_elem *parent )
1643
{
1644 1645
    struct xml_elem elem;
    struct xml_attr attr;
1646
    BOOL end = FALSE;
1647 1648
    struct entity*      entity;

1649
    if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)))
1650 1651 1652 1653
    {
        set_error( xmlbuf );
        return;
    }
1654

1655
    while (next_xml_attr(xmlbuf, &attr, &end))
1656
    {
1657
        if (xml_attr_cmp(&attr, clsidW))
1658
        {
1659
            if (!(entity->u.comclass.clsid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1660
        }
1661
        else if (xml_attr_cmp(&attr, progidW))
1662
        {
1663
            if (!(entity->u.comclass.progid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1664
        }
1665
        else if (xml_attr_cmp(&attr, tlbidW))
1666
        {
1667
            if (!(entity->u.comclass.tlbid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1668
        }
1669
        else if (xml_attr_cmp(&attr, threadingmodelW))
1670
        {
1671
            entity->u.comclass.model = parse_com_class_threadingmodel(&attr.value);
1672
        }
1673
        else if (xml_attr_cmp(&attr, miscstatusW))
1674
        {
1675
            entity->u.comclass.miscstatus = parse_com_class_misc(&attr.value);
1676
        }
1677
        else if (xml_attr_cmp(&attr, miscstatuscontentW))
1678
        {
1679
            entity->u.comclass.miscstatuscontent = parse_com_class_misc(&attr.value);
1680
        }
1681
        else if (xml_attr_cmp(&attr, miscstatusthumbnailW))
1682
        {
1683
            entity->u.comclass.miscstatusthumbnail = parse_com_class_misc(&attr.value);
1684
        }
1685
        else if (xml_attr_cmp(&attr, miscstatusiconW))
1686
        {
1687
            entity->u.comclass.miscstatusicon = parse_com_class_misc(&attr.value);
1688
        }
1689
        else if (xml_attr_cmp(&attr, miscstatusdocprintW))
1690
        {
1691
            entity->u.comclass.miscstatusdocprint = parse_com_class_misc(&attr.value);
1692
        }
1693
        else if (xml_attr_cmp(&attr, descriptionW))
1694 1695 1696
        {
            /* not stored */
        }
1697
        else if (!is_xmlns_attr( &attr ))
1698
        {
1699
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
1700 1701 1702
        }
    }

1703
    acl->actctx->sections |= SERVERREDIRECT_SECTION;
1704 1705
    if (entity->u.comclass.progid)
        acl->actctx->sections |= PROGIDREDIRECT_SECTION;
1706

1707
    if (end) return;
1708

1709
    while (next_xml_elem(xmlbuf, &elem, parent))
1710
    {
1711
        if (xml_elem_cmp(&elem, progidW, asmv1W))
1712
        {
1713
            parse_com_class_progid(xmlbuf, entity, &elem);
1714
        }
1715 1716
        else
        {
1717
            WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
1718
            parse_unknown_elem(xmlbuf, &elem);
1719 1720
        }
    }
1721 1722 1723

    if (entity->u.comclass.progids.num)
        acl->actctx->sections |= PROGIDREDIRECT_SECTION;
1724 1725
}

1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745
static BOOL parse_nummethods(const xmlstr_t *str, struct entity *entity)
{
    const WCHAR *curr;
    ULONG num = 0;

    for (curr = str->ptr; curr < str->ptr + str->len; curr++)
    {
        if (*curr >= '0' && *curr <= '9')
            num = num * 10 + *curr - '0';
        else
        {
            ERR("wrong numeric value %s\n", debugstr_xmlstr(str));
            return FALSE;
        }
    }
    entity->u.ifaceps.nummethods = num;

    return TRUE;
}

1746 1747
static void parse_cominterface_proxy_stub_elem( xmlbuf_t *xmlbuf, struct dll_redirect *dll,
                                                struct actctx_loader *acl, const struct xml_elem *parent )
1748
{
1749
    struct xml_attr attr;
1750
    BOOL end = FALSE;
1751 1752
    struct entity*      entity;

1753
    if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)))
1754 1755 1756 1757
    {
        set_error( xmlbuf );
        return;
    }
1758

1759
    while (next_xml_attr(xmlbuf, &attr, &end))
1760
    {
1761
        if (xml_attr_cmp(&attr, iidW))
1762
        {
1763
            if (!(entity->u.ifaceps.iid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1764
        }
1765
        else if (xml_attr_cmp(&attr, nameW))
1766
        {
1767
            if (!(entity->u.ifaceps.name = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1768
        }
1769
        else if (xml_attr_cmp(&attr, baseInterfaceW))
1770
        {
1771
            if (!(entity->u.ifaceps.base = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1772 1773
            entity->u.ifaceps.mask |= BaseIface;
        }
1774
        else if (xml_attr_cmp(&attr, nummethodsW))
1775
        {
1776
            if (!(parse_nummethods(&attr.value, entity))) set_error( xmlbuf );
1777 1778
            entity->u.ifaceps.mask |= NumMethods;
        }
1779
        else if (xml_attr_cmp(&attr, tlbidW))
1780
        {
1781
            if (!(entity->u.ifaceps.tlib = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1782 1783
        }
        /* not used */
1784
        else if (xml_attr_cmp(&attr, proxyStubClsid32W) || xml_attr_cmp(&attr, threadingmodelW))
1785 1786
        {
        }
1787
        else if (!is_xmlns_attr( &attr ))
1788
        {
1789
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
1790 1791 1792
        }
    }

1793
    acl->actctx->sections |= IFACEREDIRECT_SECTION;
1794
    if (!end) parse_expect_end_elem(xmlbuf, parent);
1795 1796
}

1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810
static BOOL parse_typelib_flags(const xmlstr_t *value, struct entity *entity)
{
    WORD *flags = &entity->u.typelib.flags;
    const WCHAR *str = value->ptr, *start;
    int i = 0;

    *flags = 0;

    /* it's comma separated list of flags */
    while (i < value->len)
    {
        start = str;
        while (*str != ',' && (i++ < value->len)) str++;

1811
        if (!strncmpiW(start, restrictedW, str-start))
1812
            *flags |= LIBFLAG_FRESTRICTED;
1813
        else if (!strncmpiW(start, controlW, str-start))
1814
            *flags |= LIBFLAG_FCONTROL;
1815
        else if (!strncmpiW(start, hiddenW, str-start))
1816
            *flags |= LIBFLAG_FHIDDEN;
1817
        else if (!strncmpiW(start, hasdiskimageW, str-start))
1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
            *flags |= LIBFLAG_FHASDISKIMAGE;
        else
        {
            WARN("unknown flags value %s\n", debugstr_xmlstr(value));
            return FALSE;
        }

        /* skip separator */
        str++;
        i++;
    }

    return TRUE;
}

static BOOL parse_typelib_version(const xmlstr_t *str, struct entity *entity)
{
    unsigned int ver[2];
    unsigned int pos;
    const WCHAR *curr;

    /* major.minor */
    ver[0] = ver[1] = pos = 0;
    for (curr = str->ptr; curr < str->ptr + str->len; curr++)
    {
        if (*curr >= '0' && *curr <= '9')
        {
            ver[pos] = ver[pos] * 10 + *curr - '0';
            if (ver[pos] >= 0x10000) goto error;
        }
        else if (*curr == '.')
        {
            if (++pos >= 2) goto error;
        }
        else goto error;
    }
    entity->u.typelib.major = ver[0];
    entity->u.typelib.minor = ver[1];
    return TRUE;

error:
    FIXME("wrong typelib version value (%s)\n", debugstr_xmlstr(str));
    return FALSE;
}

1863 1864
static void parse_typelib_elem( xmlbuf_t *xmlbuf, struct dll_redirect *dll,
                                struct actctx_loader *acl, const struct xml_elem *parent )
1865
{
1866
    struct xml_attr attr;
1867
    BOOL end = FALSE;
1868 1869
    struct entity*      entity;

1870
    if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)))
1871 1872 1873 1874
    {
        set_error( xmlbuf );
        return;
    }
1875

1876
    while (next_xml_attr(xmlbuf, &attr, &end))
1877
    {
1878
        if (xml_attr_cmp(&attr, tlbidW))
1879
        {
1880
            if (!(entity->u.typelib.tlbid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1881
        }
1882
        else if (xml_attr_cmp(&attr, versionW))
1883
        {
1884
            if (!parse_typelib_version(&attr.value, entity)) set_error( xmlbuf );
1885
        }
1886
        else if (xml_attr_cmp(&attr, helpdirW))
1887
        {
1888
            if (!(entity->u.typelib.helpdir = xmlstrdupW(&attr.value))) set_error( xmlbuf );
1889
        }
1890
        else if (xml_attr_cmp(&attr, flagsW))
1891
        {
1892
            if (!parse_typelib_flags(&attr.value, entity)) set_error( xmlbuf );
1893
        }
1894
        else if (!is_xmlns_attr( &attr ))
1895
        {
1896
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
1897 1898 1899
        }
    }

1900
    acl->actctx->sections |= TLIBREDIRECT_SECTION;
1901
    if (!end) parse_expect_end_elem(xmlbuf, parent);
1902 1903
}

1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918
static inline int aligned_string_len(int len)
{
    return (len + 3) & ~3;
}

static int get_assembly_version(struct assembly *assembly, WCHAR *ret)
{
    static const WCHAR fmtW[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
    struct assembly_version *ver = &assembly->id.version;
    WCHAR buff[25];

    if (!ret) ret = buff;
    return sprintfW(ret, fmtW, ver->major, ver->minor, ver->build, ver->revision);
}

1919 1920
static void parse_window_class_elem( xmlbuf_t *xmlbuf, struct dll_redirect *dll,
                                     struct actctx_loader *acl, const struct xml_elem *parent )
1921
{
1922 1923 1924
    struct xml_elem elem;
    struct xml_attr attr;
    xmlstr_t content;
1925
    BOOL end = FALSE;
1926 1927
    struct entity*      entity;

1928
    if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)))
1929 1930 1931 1932
    {
        set_error( xmlbuf );
        return;
    }
1933
    entity->u.class.versioned = TRUE;
1934
    while (next_xml_attr(xmlbuf, &attr, &end))
1935
    {
1936
        if (xml_attr_cmp(&attr, versionedW))
1937
        {
1938
            if (xmlstr_cmpi(&attr.value, noW))
1939
                entity->u.class.versioned = FALSE;
1940
            else if (!xmlstr_cmpi(&attr.value, yesW))
1941
                set_error( xmlbuf );
1942
        }
1943
        else if (!is_xmlns_attr( &attr ))
1944
        {
1945
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
1946 1947 1948
        }
    }

1949
    if (end) return;
1950

1951 1952
    if (!parse_text_content(xmlbuf, &content)) return;
    if (!(entity->u.class.name = xmlstrdupW(&content))) set_error( xmlbuf );
1953

1954 1955
    acl->actctx->sections |= WINDOWCLASS_SECTION;

1956
    while (next_xml_elem(xmlbuf, &elem, parent))
1957
    {
1958 1959
        WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
        parse_unknown_elem(xmlbuf, &elem);
1960 1961 1962
    }
}

1963
static void parse_binding_redirect_elem( xmlbuf_t *xmlbuf, const struct xml_elem *parent )
1964
{
1965
    struct xml_attr attr;
1966
    BOOL end = FALSE;
1967

1968
    while (next_xml_attr(xmlbuf, &attr, &end))
1969
    {
1970
        if (xml_attr_cmp(&attr, oldVersionW))
1971
        {
1972
            FIXME("Not stored yet %s\n", debugstr_xml_attr(&attr));
1973
        }
1974
        else if (xml_attr_cmp(&attr, newVersionW))
1975
        {
1976
            FIXME("Not stored yet %s\n", debugstr_xml_attr(&attr));
1977
        }
1978
        else if (!is_xmlns_attr( &attr ))
1979
        {
1980
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
1981 1982 1983
        }
    }

1984
    if (!end) parse_expect_end_elem(xmlbuf, parent);
1985 1986
}

1987
static void parse_description_elem( xmlbuf_t *xmlbuf, const struct xml_elem *parent )
1988
{
1989 1990 1991
    struct xml_elem elem;
    struct xml_attr attr;
    xmlstr_t content;
1992
    BOOL end = FALSE;
1993

1994
    while (next_xml_attr(xmlbuf, &attr, &end))
1995 1996 1997
    {
        if (!is_xmlns_attr( &attr )) WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
    }
1998

1999 2000
    if (end) return;
    if (!parse_text_content(xmlbuf, &content)) return;
2001 2002 2003

    TRACE("Got description %s\n", debugstr_xmlstr(&content));

2004
    while (next_xml_elem(xmlbuf, &elem, parent))
2005
    {
2006 2007
        WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
        parse_unknown_elem(xmlbuf, &elem);
2008 2009 2010
    }
}

2011
static void parse_com_interface_external_proxy_stub_elem(xmlbuf_t *xmlbuf,
2012
                                                         struct assembly* assembly,
2013 2014
                                                         struct actctx_loader* acl,
                                                         const struct xml_elem *parent)
2015
{
2016
    struct xml_attr attr;
2017
    BOOL end = FALSE;
2018 2019
    struct entity*      entity;

2020 2021 2022 2023 2024
    if (!(entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)))
    {
        set_error( xmlbuf );
        return;
    }
2025

2026
    while (next_xml_attr(xmlbuf, &attr, &end))
2027
    {
2028
        if (xml_attr_cmp(&attr, iidW))
2029
        {
2030
            if (!(entity->u.ifaceps.iid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2031
        }
2032
        else if (xml_attr_cmp(&attr, nameW))
2033
        {
2034
            if (!(entity->u.ifaceps.name = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2035
        }
2036
        else if (xml_attr_cmp(&attr, baseInterfaceW))
2037
        {
2038
            if (!(entity->u.ifaceps.base = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2039 2040
            entity->u.ifaceps.mask |= BaseIface;
        }
2041
        else if (xml_attr_cmp(&attr, nummethodsW))
2042
        {
2043
            if (!(parse_nummethods(&attr.value, entity))) set_error( xmlbuf );
2044 2045
            entity->u.ifaceps.mask |= NumMethods;
        }
2046
        else if (xml_attr_cmp(&attr, proxyStubClsid32W))
2047
        {
2048
            if (!(entity->u.ifaceps.ps32 = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2049
        }
2050
        else if (xml_attr_cmp(&attr, tlbidW))
2051
        {
2052
            if (!(entity->u.ifaceps.tlib = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2053
        }
2054
        else if (!is_xmlns_attr( &attr ))
2055
        {
2056
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
2057 2058 2059
        }
    }

2060
    acl->actctx->sections |= IFACEREDIRECT_SECTION;
2061
    if (!end) parse_expect_end_elem(xmlbuf, parent);
2062 2063
}

2064 2065 2066
static void parse_clr_class_elem( xmlbuf_t* xmlbuf, struct assembly* assembly,
                                  struct actctx_loader *acl, const struct xml_elem *parent )

2067
{
2068 2069
    struct xml_elem elem;
    struct xml_attr attr;
2070
    BOOL end = FALSE;
2071 2072
    struct entity*      entity;

2073 2074 2075 2076 2077
    if (!(entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)))
    {
        set_error( xmlbuf );
        return;
    }
2078

2079
    while (next_xml_attr(xmlbuf, &attr, &end))
2080
    {
2081
        if (xml_attr_cmp(&attr, nameW))
2082
        {
2083
            if (!(entity->u.comclass.name = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2084
        }
2085
        else if (xml_attr_cmp(&attr, clsidW))
2086
        {
2087
            if (!(entity->u.comclass.clsid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2088
        }
2089
        else if (xml_attr_cmp(&attr, progidW))
2090
        {
2091
            if (!(entity->u.comclass.progid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2092
        }
2093
        else if (xml_attr_cmp(&attr, tlbidW))
2094
        {
2095
            if (!(entity->u.comclass.tlbid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2096
        }
2097
        else if (xml_attr_cmp(&attr, threadingmodelW))
2098
        {
2099
            entity->u.comclass.model = parse_com_class_threadingmodel(&attr.value);
2100
        }
2101
        else if (xml_attr_cmp(&attr, runtimeVersionW))
2102
        {
2103
            if (!(entity->u.comclass.version = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2104
        }
2105
        else if (!is_xmlns_attr( &attr ))
2106
        {
2107
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
2108 2109 2110
        }
    }

2111
    acl->actctx->sections |= SERVERREDIRECT_SECTION;
2112 2113
    if (entity->u.comclass.progid)
        acl->actctx->sections |= PROGIDREDIRECT_SECTION;
2114
    if (end) return;
2115

2116
    while (next_xml_elem(xmlbuf, &elem, parent))
2117
    {
2118
        if (xml_elem_cmp(&elem, progidW, asmv1W))
2119
        {
2120
            parse_com_class_progid(xmlbuf, entity, &elem);
2121 2122 2123
        }
        else
        {
2124
            WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
2125
            parse_unknown_elem(xmlbuf, &elem);
2126 2127
        }
    }
2128 2129 2130

    if (entity->u.comclass.progids.num)
        acl->actctx->sections |= PROGIDREDIRECT_SECTION;
2131 2132
}

2133 2134
static void parse_clr_surrogate_elem( xmlbuf_t *xmlbuf, struct assembly *assembly,
                                      struct actctx_loader *acl, const struct xml_elem *parent )
2135
{
2136
    struct xml_attr attr;
2137
    BOOL end = FALSE;
2138 2139
    struct entity*      entity;

2140 2141 2142 2143 2144
    if (!(entity = add_entity(&assembly->entities, ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES)))
    {
        set_error( xmlbuf );
        return;
    }
2145

2146
    while (next_xml_attr(xmlbuf, &attr, &end))
2147
    {
2148
        if (xml_attr_cmp(&attr, nameW))
2149
        {
2150
            if (!(entity->u.clrsurrogate.name = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2151
        }
2152
        else if (xml_attr_cmp(&attr, clsidW))
2153
        {
2154
            if (!(entity->u.clrsurrogate.clsid = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2155
        }
2156
        else if (xml_attr_cmp(&attr, runtimeVersionW))
2157
        {
2158
            if (!(entity->u.clrsurrogate.version = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2159
        }
2160
        else if (!is_xmlns_attr( &attr ))
2161
        {
2162
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
2163 2164 2165
        }
    }

2166
    acl->actctx->sections |= CLRSURROGATES_SECTION;
2167
    if (!end) parse_expect_end_elem(xmlbuf, parent);
2168 2169
}

2170 2171
static void parse_dependent_assembly_elem( xmlbuf_t *xmlbuf, struct actctx_loader *acl,
                                           const struct xml_elem *parent, BOOL optional )
2172
{
2173 2174
    struct xml_elem elem;
    struct xml_attr attr;
2175
    struct assembly_identity    ai;
2176
    BOOL end = FALSE;
2177

2178 2179 2180 2181
    memset(&ai, 0, sizeof(ai));
    ai.optional = optional;

    while (next_xml_attr(xmlbuf, &attr, &end))
2182 2183 2184 2185
    {
        static const WCHAR allowDelayedBindingW[] = {'a','l','l','o','w','D','e','l','a','y','e','d','B','i','n','d','i','n','g',0};
        static const WCHAR trueW[] = {'t','r','u','e',0};

2186
        if (xml_attr_cmp(&attr, allowDelayedBindingW))
2187
            ai.delayed = xmlstr_cmp(&attr.value, trueW);
2188
        else if (!is_xmlns_attr( &attr ))
2189
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
2190 2191
    }

2192
    if (end) return;
2193

2194
    while (next_xml_elem(xmlbuf, &elem, parent))
2195
    {
2196
        if (xml_elem_cmp(&elem, assemblyIdentityW, asmv1W))
2197
        {
2198 2199 2200 2201 2202
            parse_assembly_identity_elem(xmlbuf, acl->actctx, &ai, &elem);
            /* store the newly found identity for later loading */
            TRACE( "adding name=%s version=%s arch=%s\n",
                   debugstr_w(ai.name), debugstr_version(&ai.version), debugstr_w(ai.arch) );
            if (!add_dependent_assembly_id(acl, &ai)) set_error( xmlbuf );
2203
        }
2204
        else if (xml_elem_cmp(&elem, bindingRedirectW, asmv1W))
2205
        {
2206
            parse_binding_redirect_elem(xmlbuf, &elem);
2207
        }
2208 2209
        else
        {
2210
            WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
2211
            parse_unknown_elem(xmlbuf, &elem);
2212 2213 2214 2215
        }
    }
}

2216 2217 2218
static void parse_dependency_elem( xmlbuf_t *xmlbuf, struct actctx_loader *acl,
                                   const struct xml_elem *parent )

2219
{
2220 2221
    struct xml_elem elem;
    struct xml_attr attr;
2222
    BOOL end = FALSE, optional = FALSE;
2223

2224
    while (next_xml_attr(xmlbuf, &attr, &end))
2225
    {
2226
        if (xml_attr_cmp(&attr, optionalW))
2227
        {
2228 2229
            optional = xmlstr_cmpi( &attr.value, yesW );
            TRACE("optional=%s\n", debugstr_xmlstr(&attr.value));
2230
        }
2231
        else if (!is_xmlns_attr( &attr ))
2232
        {
2233
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
2234 2235
        }
    }
2236

2237
    while (next_xml_elem(xmlbuf, &elem, parent))
2238
    {
2239
        if (xml_elem_cmp(&elem, dependentAssemblyW, asmv1W))
2240
        {
2241
            parse_dependent_assembly_elem(xmlbuf, acl, &elem, optional);
2242 2243 2244
        }
        else
        {
2245
            WARN("unknown element %s\n", debugstr_xml_elem(&elem));
2246
            parse_unknown_elem(xmlbuf, &elem);
2247 2248 2249 2250
        }
    }
}

2251
static void parse_noinherit_elem( xmlbuf_t *xmlbuf, const struct xml_elem *parent )
2252 2253 2254
{
    BOOL end = FALSE;

2255
    parse_expect_no_attr(xmlbuf, &end);
2256
    if (!end) parse_expect_end_elem(xmlbuf, parent);
2257 2258
}

2259
static void parse_noinheritable_elem( xmlbuf_t *xmlbuf, const struct xml_elem *parent )
2260 2261 2262
{
    BOOL end = FALSE;

2263
    parse_expect_no_attr(xmlbuf, &end);
2264
    if (!end) parse_expect_end_elem(xmlbuf, parent);
2265 2266
}

2267 2268
static void parse_file_elem( xmlbuf_t* xmlbuf, struct assembly* assembly,
                             struct actctx_loader* acl, const struct xml_elem *parent )
2269
{
2270 2271
    struct xml_elem elem;
    struct xml_attr attr;
2272
    BOOL end = FALSE;
2273 2274
    struct dll_redirect* dll;

2275 2276 2277 2278 2279
    if (!(dll = add_dll_redirect(assembly)))
    {
        set_error( xmlbuf );
        return;
    }
2280

2281
    while (next_xml_attr(xmlbuf, &attr, &end))
2282
    {
2283
        if (xml_attr_cmp(&attr, nameW))
2284
        {
2285
            if (!(dll->name = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2286
            TRACE("name=%s\n", debugstr_xmlstr(&attr.value));
2287
        }
2288
        else if (xml_attr_cmp(&attr, hashW))
2289
        {
2290
            if (!(dll->hash = xmlstrdupW(&attr.value))) set_error( xmlbuf );
2291
        }
2292
        else if (xml_attr_cmp(&attr, hashalgW))
2293
        {
2294
            static const WCHAR sha1W[] = {'S','H','A','1',0};
2295 2296
            if (!xmlstr_cmpi(&attr.value, sha1W))
                FIXME("hashalg should be SHA1, got %s\n", debugstr_xmlstr(&attr.value));
2297
        }
2298
        else if (!is_xmlns_attr( &attr ))
2299
        {
2300
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
2301 2302 2303
        }
    }

2304
    if (!dll->name) set_error( xmlbuf );
2305 2306 2307

    acl->actctx->sections |= DLLREDIRECT_SECTION;

2308
    if (end) return;
2309

2310
    while (next_xml_elem(xmlbuf, &elem, parent))
2311
    {
2312
        if (xml_elem_cmp(&elem, comClassW, asmv1W))
2313
        {
2314
            parse_com_class_elem(xmlbuf, dll, acl, &elem);
2315
        }
2316
        else if (xml_elem_cmp(&elem, comInterfaceProxyStubW, asmv1W))
2317
        {
2318
            parse_cominterface_proxy_stub_elem(xmlbuf, dll, acl, &elem);
2319
        }
2320
        else if (xml_elem_cmp(&elem, hashW, asmv2W))
2321
        {
2322
            WARN("asmv2:hash (undocumented) not supported\n");
2323
            parse_unknown_elem(xmlbuf, &elem);
2324
        }
2325
        else if (xml_elem_cmp(&elem, typelibW, asmv1W))
2326
        {
2327
            parse_typelib_elem(xmlbuf, dll, acl, &elem);
2328
        }
2329
        else if (xml_elem_cmp(&elem, windowClassW, asmv1W))
2330
        {
2331
            parse_window_class_elem(xmlbuf, dll, acl, &elem);
2332
        }
2333 2334
        else
        {
2335
            WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
2336
            parse_unknown_elem( xmlbuf, &elem );
2337 2338 2339 2340
        }
    }
}

2341 2342
static void parse_supportedos_elem( xmlbuf_t *xmlbuf, struct assembly *assembly,
                                    struct actctx_loader *acl, const struct xml_elem *parent )
2343
{
2344
    struct xml_attr attr;
2345
    BOOL end = FALSE;
2346

2347
    while (next_xml_attr(xmlbuf, &attr, &end))
2348
    {
2349
        if (xml_attr_cmp(&attr, IdW))
2350 2351 2352 2353 2354
        {
            COMPATIBILITY_CONTEXT_ELEMENT *compat;
            UNICODE_STRING str;
            GUID compat_id;

2355 2356
            str.Buffer = (PWSTR)attr.value.ptr;
            str.Length = str.MaximumLength = (USHORT)attr.value.len * sizeof(WCHAR);
2357 2358
            if (RtlGUIDFromString(&str, &compat_id) == STATUS_SUCCESS)
            {
2359 2360 2361 2362 2363
                if (!(compat = add_compat_context(assembly)))
                {
                    set_error( xmlbuf );
                    return;
                }
2364 2365 2366 2367 2368
                compat->Type = ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS;
                compat->Id = compat_id;
            }
            else
            {
2369
                WARN("Invalid guid %s\n", debugstr_xmlstr(&attr.value));
2370 2371
            }
        }
2372
        else if (!is_xmlns_attr( &attr ))
2373
        {
2374
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
2375 2376 2377
        }
    }

2378
    if (!end) parse_expect_end_elem(xmlbuf, parent);
2379 2380
}

2381
static void parse_compatibility_application_elem(xmlbuf_t *xmlbuf, struct assembly *assembly,
2382
                                                 struct actctx_loader* acl, const struct xml_elem *parent)
2383
{
2384
    struct xml_elem elem;
2385

2386
    while (next_xml_elem(xmlbuf, &elem, parent))
2387
    {
2388
        if (xml_elem_cmp(&elem, supportedOSW, compatibilityNSW))
2389
        {
2390
            parse_supportedos_elem(xmlbuf, assembly, acl, &elem);
2391 2392 2393
        }
        else
        {
2394
            WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
2395
            parse_unknown_elem(xmlbuf, &elem);
2396 2397 2398 2399
        }
    }
}

2400
static void parse_compatibility_elem(xmlbuf_t *xmlbuf, struct assembly *assembly,
2401
                                     struct actctx_loader* acl, const struct xml_elem *parent)
2402
{
2403
    struct xml_elem elem;
2404

2405
    while (next_xml_elem(xmlbuf, &elem, parent))
2406
    {
2407
        if (xml_elem_cmp(&elem, applicationW, compatibilityNSW))
2408
        {
2409
            parse_compatibility_application_elem(xmlbuf, assembly, acl, &elem);
2410 2411 2412
        }
        else
        {
2413
            WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
2414
            parse_unknown_elem(xmlbuf, &elem);
2415 2416 2417 2418
        }
    }
}

2419
static void parse_settings_elem( xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader *acl,
2420
                                 struct xml_elem *parent )
2421
{
2422 2423 2424
    struct xml_elem elem;
    struct xml_attr attr;
    xmlstr_t content;
2425
    BOOL end = FALSE;
2426 2427
    struct entity *entity;

2428
    while (next_xml_attr( xmlbuf, &attr, &end ))
2429
    {
2430
        if (!is_xmlns_attr( &attr )) WARN( "unknown attr %s\n", debugstr_xml_attr(&attr) );
2431 2432
    }

2433
    if (end) return;
2434

2435
    if (!parse_text_content( xmlbuf, &content )) return;
2436
    TRACE( "got %s %s\n", debugstr_xmlstr(&parent->name), debugstr_xmlstr(&content) );
2437 2438

    entity = add_entity( &assembly->entities, ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS );
2439 2440 2441 2442 2443
    if (!entity)
    {
        set_error( xmlbuf );
        return;
    }
2444
    entity->u.settings.name = xmlstrdupW( &parent->name );
2445
    entity->u.settings.value = xmlstrdupW( &content );
2446
    entity->u.settings.ns = xmlstrdupW( &parent->ns );
2447

2448
    while (next_xml_elem(xmlbuf, &elem, parent))
2449
    {
2450 2451
        WARN( "unknown elem %s\n", debugstr_xml_elem(&elem) );
        parse_unknown_elem( xmlbuf, &elem );
2452 2453 2454
    }
}

2455
static void parse_windows_settings_elem( xmlbuf_t *xmlbuf, struct assembly *assembly,
2456
                                         struct actctx_loader *acl, const struct xml_elem *parent )
2457
{
2458
    struct xml_elem elem;
2459

2460
    while (next_xml_elem( xmlbuf, &elem, parent ))
2461
    {
2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472
        if (xml_elem_cmp( &elem, autoElevateW, windowsSettings2005NSW ) ||
            xml_elem_cmp( &elem, disableThemingW, windowsSettings2005NSW ) ||
            xml_elem_cmp( &elem, disableWindowFilteringW, windowsSettings2011NSW ) ||
            xml_elem_cmp( &elem, dpiAwareW, windowsSettings2005NSW ) ||
            xml_elem_cmp( &elem, dpiAwarenessW, windowsSettings2016NSW ) ||
            xml_elem_cmp( &elem, gdiScalingW, windowsSettings2017NSW ) ||
            xml_elem_cmp( &elem, highResolutionScrollingAwareW, windowsSettings2017NSW ) ||
            xml_elem_cmp( &elem, longPathAwareW, windowsSettings2016NSW ) ||
            xml_elem_cmp( &elem, magicFutureSettingW, windowsSettings2017NSW ) ||
            xml_elem_cmp( &elem, printerDriverIsolationW, windowsSettings2011NSW ) ||
            xml_elem_cmp( &elem, ultraHighResolutionScrollingAwareW, windowsSettings2017NSW ))
2473
        {
2474
            parse_settings_elem( xmlbuf, assembly, acl, &elem );
2475 2476 2477
        }
        else
        {
2478
            WARN( "unknown elem %s\n", debugstr_xml_elem(&elem) );
2479
            parse_unknown_elem( xmlbuf, &elem );
2480 2481 2482 2483
        }
    }
}

2484 2485
static void parse_application_elem( xmlbuf_t *xmlbuf, struct assembly *assembly,
                                    struct actctx_loader *acl, const struct xml_elem *parent )
2486
{
2487
    struct xml_elem elem;
2488

2489
    while (next_xml_elem( xmlbuf, &elem, parent ))
2490
    {
2491
        if (xml_elem_cmp( &elem, windowsSettingsW, asmv3W ))
2492
        {
2493
            parse_windows_settings_elem( xmlbuf, assembly, acl, &elem );
2494 2495 2496
        }
        else
        {
2497
            WARN( "unknown elem %s\n", debugstr_xml_elem(&elem) );
2498
            parse_unknown_elem( xmlbuf, &elem );
2499 2500 2501 2502
        }
    }
}

2503
static void parse_requested_execution_level_elem( xmlbuf_t *xmlbuf, struct assembly *assembly,
2504
                                                  struct actctx_loader *acl, const struct xml_elem *parent )
2505 2506 2507 2508 2509 2510 2511 2512 2513
{
    static const WCHAR levelW[] = {'l','e','v','e','l',0};
    static const WCHAR asInvokerW[] = {'a','s','I','n','v','o','k','e','r',0};
    static const WCHAR requireAdministratorW[] = {'r','e','q','u','i','r','e','A','d','m','i','n','i','s','t','r','a','t','o','r',0};
    static const WCHAR highestAvailableW[] = {'h','i','g','h','e','s','t','A','v','a','i','l','a','b','l','e',0};
    static const WCHAR uiAccessW[] = {'u','i','A','c','c','e','s','s',0};
    static const WCHAR falseW[] = {'f','a','l','s','e',0};
    static const WCHAR trueW[] = {'t','r','u','e',0};

2514 2515
    struct xml_elem elem;
    struct xml_attr attr;
2516
    BOOL end = FALSE;
2517 2518

    /* Multiple requestedExecutionLevel elements are not supported. */
2519
    if (assembly->run_level != ACTCTX_RUN_LEVEL_UNSPECIFIED) set_error( xmlbuf );
2520

2521
    while (next_xml_attr(xmlbuf, &attr, &end))
2522
    {
2523
        if (xml_attr_cmp(&attr, levelW))
2524
        {
2525
            if (xmlstr_cmpi(&attr.value, asInvokerW))
2526
                assembly->run_level = ACTCTX_RUN_LEVEL_AS_INVOKER;
2527
            else if (xmlstr_cmpi(&attr.value, highestAvailableW))
2528
                assembly->run_level = ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE;
2529
            else if (xmlstr_cmpi(&attr.value, requireAdministratorW))
2530 2531
                assembly->run_level = ACTCTX_RUN_LEVEL_REQUIRE_ADMIN;
            else
2532
                FIXME("unknown execution level: %s\n", debugstr_xmlstr(&attr.value));
2533
        }
2534
        else if (xml_attr_cmp(&attr, uiAccessW))
2535
        {
2536
            if (xmlstr_cmpi(&attr.value, falseW))
2537
                assembly->ui_access = FALSE;
2538
            else if (xmlstr_cmpi(&attr.value, trueW))
2539 2540
                assembly->ui_access = TRUE;
            else
2541
                FIXME("unknown uiAccess value: %s\n", debugstr_xmlstr(&attr.value));
2542
        }
2543 2544
        else if (!is_xmlns_attr( &attr ))
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
2545 2546
    }

2547
    if (end) return;
2548

2549
    while (next_xml_elem(xmlbuf, &elem, parent))
2550
    {
2551 2552
        WARN("unknown element %s\n", debugstr_xml_elem(&elem));
        parse_unknown_elem(xmlbuf, &elem);
2553 2554 2555
    }
}

2556
static void parse_requested_privileges_elem( xmlbuf_t *xmlbuf, struct assembly *assembly,
2557
                                             struct actctx_loader *acl, const struct xml_elem *parent )
2558
{
2559
    struct xml_elem elem;
2560

2561
    while (next_xml_elem(xmlbuf, &elem, parent))
2562
    {
2563 2564
        if (xml_elem_cmp(&elem, requestedExecutionLevelW, asmv1W))
        {
2565
            parse_requested_execution_level_elem(xmlbuf, assembly, acl, &elem);
2566
        }
2567 2568
        else
        {
2569
            WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
2570
            parse_unknown_elem(xmlbuf, &elem);
2571 2572 2573 2574
        }
    }
}

2575 2576
static void parse_security_elem( xmlbuf_t *xmlbuf, struct assembly *assembly,
                                 struct actctx_loader *acl, const struct xml_elem *parent )
2577
{
2578
    struct xml_elem elem;
2579

2580
    while (next_xml_elem(xmlbuf, &elem, parent))
2581
    {
2582 2583
        if (xml_elem_cmp(&elem, requestedPrivilegesW, asmv1W))
        {
2584
            parse_requested_privileges_elem(xmlbuf, assembly, acl, &elem);
2585
        }
2586 2587
        else
        {
2588
            WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
2589
            parse_unknown_elem(xmlbuf, &elem);
2590 2591 2592 2593
        }
    }
}

2594 2595
static void parse_trust_info_elem( xmlbuf_t *xmlbuf, struct assembly *assembly,
                                   struct actctx_loader *acl, const struct xml_elem *parent )
2596
{
2597
    struct xml_elem elem;
2598

2599
    while (next_xml_elem(xmlbuf, &elem, parent))
2600
    {
2601 2602
        if (xml_elem_cmp(&elem, securityW, asmv1W))
        {
2603
            parse_security_elem(xmlbuf, assembly, acl, &elem);
2604
        }
2605 2606
        else
        {
2607
            WARN("unknown elem %s\n", debugstr_xml_elem(&elem));
2608
            parse_unknown_elem(xmlbuf, &elem);
2609 2610 2611 2612
        }
    }
}

2613 2614 2615
static void parse_assembly_elem( xmlbuf_t *xmlbuf, struct assembly* assembly,
                                 struct actctx_loader* acl, const struct xml_elem *parent,
                                 struct assembly_identity* expected_ai)
2616
{
2617 2618
    struct xml_elem elem;
    struct xml_attr attr;
2619
    BOOL end = FALSE, version = FALSE;
2620 2621 2622

    TRACE("(%p)\n", xmlbuf);

2623
    while (next_xml_attr(xmlbuf, &attr, &end))
2624
    {
2625
        if (xml_attr_cmp(&attr, manifestVersionW))
2626
        {
2627
            static const WCHAR v10W[] = {'1','.','0',0};
2628
            if (!xmlstr_cmp(&attr.value, v10W))
2629
            {
2630
                FIXME("wrong version %s\n", debugstr_xmlstr(&attr.value));
2631
                break;
2632 2633 2634
            }
            version = TRUE;
        }
2635
        else if (!is_xmlns_attr( &attr ))
2636
        {
2637
            WARN("unknown attr %s\n", debugstr_xml_attr(&attr));
2638 2639 2640
        }
    }

2641
    if (end || !version)
2642
    {
2643 2644
        set_error( xmlbuf );
        return;
2645 2646
    }

2647
    while (next_xml_elem(xmlbuf, &elem, parent))
2648
    {
2649
        if (assembly->type == APPLICATION_MANIFEST && xml_elem_cmp(&elem, noInheritW, asmv1W))
2650
        {
2651
            parse_noinherit_elem(xmlbuf, &elem);
2652 2653 2654 2655
            assembly->no_inherit = TRUE;
        }
        else if (xml_elem_cmp(&elem, noInheritableW, asmv1W))
        {
2656
            parse_noinheritable_elem(xmlbuf, &elem);
2657
        }
2658
        else if (xml_elem_cmp(&elem, descriptionW, asmv1W))
2659
        {
2660
            parse_description_elem(xmlbuf, &elem);
2661
        }
2662
        else if (xml_elem_cmp(&elem, comInterfaceExternalProxyStubW, asmv1W))
2663
        {
2664
            parse_com_interface_external_proxy_stub_elem(xmlbuf, assembly, acl, &elem);
2665
        }
2666
        else if (xml_elem_cmp(&elem, dependencyW, asmv1W))
2667
        {
2668
            parse_dependency_elem(xmlbuf, acl, &elem);
2669
        }
2670
        else if (xml_elem_cmp(&elem, fileW, asmv1W))
2671
        {
2672
            parse_file_elem(xmlbuf, assembly, acl, &elem);
2673
        }
2674
        else if (xml_elem_cmp(&elem, clrClassW, asmv1W))
2675
        {
2676
            parse_clr_class_elem(xmlbuf, assembly, acl, &elem);
2677
        }
2678
        else if (xml_elem_cmp(&elem, clrSurrogateW, asmv1W))
2679
        {
2680
            parse_clr_surrogate_elem(xmlbuf, assembly, acl, &elem);
2681
        }
2682
        else if (xml_elem_cmp(&elem, trustInfoW, asmv1W))
2683
        {
2684
            parse_trust_info_elem(xmlbuf, assembly, acl, &elem);
2685
        }
2686
        else if (xml_elem_cmp(&elem, assemblyIdentityW, asmv1W))
2687
        {
2688
            parse_assembly_identity_elem(xmlbuf, acl->actctx, &assembly->id, &elem);
2689

2690
            if (!xmlbuf->error && expected_ai)
2691 2692 2693 2694 2695 2696 2697 2698 2699 2700
            {
                /* FIXME: more tests */
                if (assembly->type == ASSEMBLY_MANIFEST &&
                    memcmp(&assembly->id.version, &expected_ai->version, sizeof(assembly->id.version)))
                {
                    FIXME("wrong version for assembly manifest: %u.%u.%u.%u / %u.%u.%u.%u\n",
                          expected_ai->version.major, expected_ai->version.minor,
                          expected_ai->version.build, expected_ai->version.revision,
                          assembly->id.version.major, assembly->id.version.minor,
                          assembly->id.version.build, assembly->id.version.revision);
2701
                    set_error( xmlbuf );
2702 2703 2704 2705 2706 2707 2708 2709 2710
                }
                else if (assembly->type == ASSEMBLY_SHARED_MANIFEST &&
                         (assembly->id.version.major != expected_ai->version.major ||
                          assembly->id.version.minor != expected_ai->version.minor ||
                          assembly->id.version.build < expected_ai->version.build ||
                          (assembly->id.version.build == expected_ai->version.build &&
                           assembly->id.version.revision < expected_ai->version.revision)))
                {
                    FIXME("wrong version for shared assembly manifest\n");
2711
                    set_error( xmlbuf );
2712 2713 2714
                }
            }
        }
2715 2716
        else if (xml_elem_cmp(&elem, compatibilityW, compatibilityNSW))
        {
2717
            parse_compatibility_elem(xmlbuf, assembly, acl, &elem);
2718
        }
2719 2720
        else if (xml_elem_cmp(&elem, applicationW, asmv3W))
        {
2721
            parse_application_elem(xmlbuf, assembly, acl, &elem);
2722
        }
2723 2724
        else
        {
2725
            WARN("unknown element %s\n", debugstr_xml_elem(&elem));
2726
            parse_unknown_elem(xmlbuf, &elem);
2727 2728 2729
        }
    }

2730 2731 2732 2733 2734
    if ((assembly->type == ASSEMBLY_MANIFEST || assembly->type == ASSEMBLY_SHARED_MANIFEST) &&
        assembly->no_inherit)
    {
        set_error( xmlbuf );
    }
2735 2736
}

2737 2738
static NTSTATUS parse_manifest_buffer( struct actctx_loader* acl, struct assembly *assembly,
                                       struct assembly_identity* ai, xmlbuf_t *xmlbuf )
2739
{
2740
    struct xml_elem elem;
2741
    struct xml_elem parent = {};
2742

2743
    xmlbuf->error = FALSE;
2744
    xmlbuf->ns_pos = 0;
2745

2746
    if (!next_xml_elem(xmlbuf, &elem, &parent)) return STATUS_SXS_CANT_GEN_ACTCTX;
2747

2748
    if (xmlstr_cmp(&elem.name, xmlW) &&
2749
        (!parse_xml_header(xmlbuf) || !next_xml_elem(xmlbuf, &elem, &parent)))
2750 2751
        return STATUS_SXS_CANT_GEN_ACTCTX;

2752
    if (!xml_elem_cmp(&elem, assemblyW, asmv1W))
2753
    {
2754
        FIXME("root element is %s, not <assembly>\n", debugstr_xml_elem(&elem));
2755 2756 2757
        return STATUS_SXS_CANT_GEN_ACTCTX;
    }

2758
    parse_assembly_elem(xmlbuf, assembly, acl, &elem, ai);
2759
    if (xmlbuf->error)
2760
    {
2761
        FIXME("failed to parse manifest %s\n", debugstr_w(assembly->manifest.info) );
2762
        return STATUS_SXS_CANT_GEN_ACTCTX;
2763
    }
2764

2765
    if (next_xml_elem(xmlbuf, &elem, &parent))
2766
    {
2767
        FIXME("unexpected element %s\n", debugstr_xml_elem(&elem));
2768 2769 2770 2771 2772
        return STATUS_SXS_CANT_GEN_ACTCTX;
    }

    if (xmlbuf->ptr != xmlbuf->end)
    {
2773
        FIXME("parse error\n");
2774 2775
        return STATUS_SXS_CANT_GEN_ACTCTX;
    }
2776 2777 2778
    return STATUS_SUCCESS;
}

2779
static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
2780 2781
                                LPCWSTR filename, LPCWSTR directory, BOOL shared,
                                const void *buffer, SIZE_T size )
2782 2783 2784 2785
{
    xmlbuf_t xmlbuf;
    NTSTATUS status;
    struct assembly *assembly;
2786
    int unicode_tests;
2787 2788 2789

    TRACE( "parsing manifest loaded from %s base dir %s\n", debugstr_w(filename), debugstr_w(directory) );

2790
    if (!(assembly = add_assembly(acl->actctx, shared ? ASSEMBLY_SHARED_MANIFEST : ASSEMBLY_MANIFEST)))
2791 2792 2793 2794 2795 2796 2797 2798 2799
        return STATUS_SXS_CANT_GEN_ACTCTX;

    if (directory && !(assembly->directory = strdupW(directory)))
        return STATUS_NO_MEMORY;

    if (filename) assembly->manifest.info = strdupW( filename + 4 /* skip \??\ prefix */ );
    assembly->manifest.type = assembly->manifest.info ? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
                                                      : ACTIVATION_CONTEXT_PATH_TYPE_NONE;

2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
    unicode_tests = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE;
    if (RtlIsTextUnicode( buffer, size, &unicode_tests ))
    {
        xmlbuf.ptr = buffer;
        xmlbuf.end = xmlbuf.ptr + size / sizeof(WCHAR);
        status = parse_manifest_buffer( acl, assembly, ai, &xmlbuf );
    }
    else if (unicode_tests & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
    {
        const WCHAR *buf = buffer;
        WCHAR *new_buff;
        unsigned int i;

        if (!(new_buff = RtlAllocateHeap( GetProcessHeap(), 0, size )))
            return STATUS_NO_MEMORY;
        for (i = 0; i < size / sizeof(WCHAR); i++)
            new_buff[i] = RtlUshortByteSwap( buf[i] );
        xmlbuf.ptr = new_buff;
        xmlbuf.end = xmlbuf.ptr + size / sizeof(WCHAR);
        status = parse_manifest_buffer( acl, assembly, ai, &xmlbuf );
        RtlFreeHeap( GetProcessHeap(), 0, new_buff );
    }
    else
2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843
    {
        /* let's assume utf-8 for now */
        int len = wine_utf8_mbstowcs( 0, buffer, size, NULL, 0 );
        WCHAR *new_buff;

        if (len == -1)
        {
            FIXME( "utf-8 conversion failed\n" );
            return STATUS_SXS_CANT_GEN_ACTCTX;
        }
        if (!(new_buff = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
            return STATUS_NO_MEMORY;
        wine_utf8_mbstowcs( 0, buffer, size, new_buff, len );
        xmlbuf.ptr = new_buff;
        xmlbuf.end = xmlbuf.ptr + len;
        status = parse_manifest_buffer( acl, assembly, ai, &xmlbuf );
        RtlFreeHeap( GetProcessHeap(), 0, new_buff );
    }
    return status;
}

2844
static NTSTATUS open_nt_file( HANDLE *handle, UNICODE_STRING *name )
2845 2846 2847 2848 2849 2850 2851 2852 2853 2854
{
    OBJECT_ATTRIBUTES attr;
    IO_STATUS_BLOCK io;

    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.Attributes = OBJ_CASE_INSENSITIVE;
    attr.ObjectName = name;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
2855
    return NtOpenFile( handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
2856 2857 2858 2859 2860
}

static NTSTATUS get_module_filename( HMODULE module, UNICODE_STRING *str, unsigned int extra_len )
{
    NTSTATUS status;
2861
    ULONG_PTR magic;
2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881
    LDR_MODULE *pldr;

    LdrLockLoaderLock(0, NULL, &magic);
    status = LdrFindEntryForAddress( module, &pldr );
    if (status == STATUS_SUCCESS)
    {
        if ((str->Buffer = RtlAllocateHeap( GetProcessHeap(), 0,
                                            pldr->FullDllName.Length + extra_len + sizeof(WCHAR) )))
        {
            memcpy( str->Buffer, pldr->FullDllName.Buffer, pldr->FullDllName.Length + sizeof(WCHAR) );
            str->Length = pldr->FullDllName.Length;
            str->MaximumLength = pldr->FullDllName.Length + extra_len + sizeof(WCHAR);
        }
        else status = STATUS_NO_MEMORY;
    }
    LdrUnlockLoaderLock(0, magic);
    return status;
}

static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai,
2882 2883
                                        LPCWSTR filename, LPCWSTR directory, BOOL shared,
                                        HANDLE hModule, LPCWSTR resname, ULONG lang )
2884 2885 2886 2887 2888 2889 2890
{
    NTSTATUS status;
    UNICODE_STRING nameW;
    LDR_RESOURCE_INFO info;
    const IMAGE_RESOURCE_DATA_ENTRY* entry = NULL;
    void *ptr;

2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901
    if (TRACE_ON(actctx))
    {
        if (!filename && !get_module_filename( hModule, &nameW, 0 ))
        {
            TRACE( "looking for res %s in module %p %s\n", debugstr_w(resname),
                   hModule, debugstr_w(nameW.Buffer) );
            RtlFreeUnicodeString( &nameW );
        }
        else TRACE( "looking for res %s in module %p %s\n", debugstr_w(resname),
                    hModule, debugstr_w(filename) );
    }
2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931

    if (!resname) return STATUS_INVALID_PARAMETER;

    info.Type = RT_MANIFEST;
    info.Language = lang;
    if (!((ULONG_PTR)resname >> 16))
    {
        info.Name = (ULONG_PTR)resname;
        status = LdrFindResource_U(hModule, &info, 3, &entry);
    }
    else if (resname[0] == '#')
    {
        ULONG value;
        RtlInitUnicodeString(&nameW, resname + 1);
        if (RtlUnicodeStringToInteger(&nameW, 10, &value) != STATUS_SUCCESS || HIWORD(value))
            return STATUS_INVALID_PARAMETER;
        info.Name = value;
        status = LdrFindResource_U(hModule, &info, 3, &entry);
    }
    else
    {
        RtlCreateUnicodeString(&nameW, resname);
        RtlUpcaseUnicodeString(&nameW, &nameW, FALSE);
        info.Name = (ULONG_PTR)nameW.Buffer;
        status = LdrFindResource_U(hModule, &info, 3, &entry);
        RtlFreeUnicodeString(&nameW);
    }
    if (status == STATUS_SUCCESS) status = LdrAccessResource(hModule, entry, &ptr, NULL);

    if (status == STATUS_SUCCESS)
2932
        status = parse_manifest(acl, ai, filename, directory, shared, ptr, entry->Size);
2933

2934 2935 2936 2937
    return status;
}

static NTSTATUS get_manifest_in_pe_file( struct actctx_loader* acl, struct assembly_identity* ai,
2938 2939
                                         LPCWSTR filename, LPCWSTR directory, BOOL shared,
                                         HANDLE file, LPCWSTR resname, ULONG lang )
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973
{
    HANDLE              mapping;
    OBJECT_ATTRIBUTES   attr;
    LARGE_INTEGER       size;
    LARGE_INTEGER       offset;
    NTSTATUS            status;
    SIZE_T              count;
    void               *base;

    TRACE( "looking for res %s in %s\n", debugstr_w(resname), debugstr_w(filename) );

    attr.Length                   = sizeof(attr);
    attr.RootDirectory            = 0;
    attr.ObjectName               = NULL;
    attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
    attr.SecurityDescriptor       = NULL;
    attr.SecurityQualityOfService = NULL;

    size.QuadPart = 0;
    status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
                              &attr, &size, PAGE_READONLY, SEC_COMMIT, file );
    if (status != STATUS_SUCCESS) return status;

    offset.QuadPart = 0;
    count = 0;
    base = NULL;
    status = NtMapViewOfSection( mapping, GetCurrentProcess(), &base, 0, 0, &offset,
                                 &count, ViewShare, 0, PAGE_READONLY );
    NtClose( mapping );
    if (status != STATUS_SUCCESS) return status;

    if (RtlImageNtHeader(base)) /* we got a PE file */
    {
        HANDLE module = (HMODULE)((ULONG_PTR)base | 1);  /* make it a LOAD_LIBRARY_AS_DATAFILE handle */
2974
        status = get_manifest_in_module( acl, ai, filename, directory, shared, module, resname, lang );
2975 2976 2977 2978 2979 2980 2981 2982
    }
    else status = STATUS_INVALID_IMAGE_FORMAT;

    NtUnmapViewOfSection( GetCurrentProcess(), base );
    return status;
}

static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct assembly_identity* ai,
2983
                                               LPCWSTR filename, LPCWSTR directory, BOOL shared, HANDLE file )
2984
{
2985 2986
    FILE_END_OF_FILE_INFORMATION info;
    IO_STATUS_BLOCK io;
2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016
    HANDLE              mapping;
    OBJECT_ATTRIBUTES   attr;
    LARGE_INTEGER       size;
    LARGE_INTEGER       offset;
    NTSTATUS            status;
    SIZE_T              count;
    void               *base;

    TRACE( "loading manifest file %s\n", debugstr_w(filename) );

    attr.Length                   = sizeof(attr);
    attr.RootDirectory            = 0;
    attr.ObjectName               = NULL;
    attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
    attr.SecurityDescriptor       = NULL;
    attr.SecurityQualityOfService = NULL;

    size.QuadPart = 0;
    status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
                              &attr, &size, PAGE_READONLY, SEC_COMMIT, file );
    if (status != STATUS_SUCCESS) return status;

    offset.QuadPart = 0;
    count = 0;
    base = NULL;
    status = NtMapViewOfSection( mapping, GetCurrentProcess(), &base, 0, 0, &offset,
                                 &count, ViewShare, 0, PAGE_READONLY );
    NtClose( mapping );
    if (status != STATUS_SUCCESS) return status;

3017 3018
    status = NtQueryInformationFile( file, &io, &info, sizeof(info), FileEndOfFileInformation );
    if (status == STATUS_SUCCESS)
3019
        status = parse_manifest(acl, ai, filename, directory, shared, base, info.EndOfFile.QuadPart);
3020 3021 3022 3023 3024 3025 3026

    NtUnmapViewOfSection( GetCurrentProcess(), base );
    return status;
}

/* try to load the .manifest file associated to the file */
static NTSTATUS get_manifest_in_associated_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
3027
                                                     LPCWSTR filename, LPCWSTR directory, HMODULE module, LPCWSTR resname )
3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048
{
    static const WCHAR fmtW[] = { '.','%','l','u',0 };
    WCHAR *buffer;
    NTSTATUS status;
    UNICODE_STRING nameW;
    HANDLE file;
    ULONG_PTR resid = CREATEPROCESS_MANIFEST_RESOURCE_ID;

    if (!((ULONG_PTR)resname >> 16)) resid = (ULONG_PTR)resname & 0xffff;

    TRACE( "looking for manifest associated with %s id %lu\n", debugstr_w(filename), resid );

    if (module) /* use the module filename */
    {
        UNICODE_STRING name;

        if (!(status = get_module_filename( module, &name, sizeof(dotManifestW) + 10*sizeof(WCHAR) )))
        {
            if (resid != 1) sprintfW( name.Buffer + strlenW(name.Buffer), fmtW, resid );
            strcatW( name.Buffer, dotManifestW );
            if (!RtlDosPathNameToNtPathName_U( name.Buffer, &nameW, NULL, NULL ))
3049
                status = STATUS_RESOURCE_DATA_NOT_FOUND;
3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064
            RtlFreeUnicodeString( &name );
        }
        if (status) return status;
    }
    else
    {
        if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0,
                                        (strlenW(filename) + 10) * sizeof(WCHAR) + sizeof(dotManifestW) )))
            return STATUS_NO_MEMORY;
        strcpyW( buffer, filename );
        if (resid != 1) sprintfW( buffer + strlenW(buffer), fmtW, resid );
        strcatW( buffer, dotManifestW );
        RtlInitUnicodeString( &nameW, buffer );
    }

3065
    if (!open_nt_file( &file, &nameW ))
3066
    {
3067
        status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, FALSE, file );
3068 3069
        NtClose( file );
    }
3070
    else status = STATUS_RESOURCE_TYPE_NOT_FOUND;
3071 3072 3073 3074
    RtlFreeUnicodeString( &nameW );
    return status;
}

3075 3076 3077 3078
static WCHAR *lookup_manifest_file( HANDLE dir, struct assembly_identity *ai )
{
    static const WCHAR lookup_fmtW[] =
        {'%','s','_','%','s','_','%','s','_','%','u','.','%','u','.','*','.','*','_',
3079
         '%','s','_','*','.','m','a','n','i','f','e','s','t',0};
3080
    static const WCHAR wine_trailerW[] = {'d','e','a','d','b','e','e','f','.','m','a','n','i','f','e','s','t'};
3081 3082 3083 3084

    WCHAR *lookup, *ret = NULL;
    UNICODE_STRING lookup_us;
    IO_STATUS_BLOCK io;
3085
    const WCHAR *lang = ai->language;
3086 3087 3088 3089 3090 3091 3092 3093 3094
    unsigned int data_pos = 0, data_len;
    char buffer[8192];

    if (!(lookup = RtlAllocateHeap( GetProcessHeap(), 0,
                                    (strlenW(ai->arch) + strlenW(ai->name)
                                     + strlenW(ai->public_key) + 20) * sizeof(WCHAR)
                                    + sizeof(lookup_fmtW) )))
        return NULL;

3095 3096 3097
    if (!lang || !strcmpiW( lang, neutralW )) lang = wildcardW;
    sprintfW( lookup, lookup_fmtW, ai->arch, ai->name, ai->public_key,
              ai->version.major, ai->version.minor, lang );
3098 3099
    RtlInitUnicodeString( &lookup_us, lookup );

3100 3101
    if (!NtQueryDirectoryFile( dir, 0, NULL, NULL, &io, buffer, sizeof(buffer),
                               FileBothDirectoryInformation, FALSE, &lookup_us, TRUE ))
3102
    {
3103
        ULONG min_build = ai->version.build, min_revision = ai->version.revision;
3104 3105 3106 3107 3108 3109 3110 3111 3112 3113
        FILE_BOTH_DIR_INFORMATION *dir_info;
        WCHAR *tmp;
        ULONG build, revision;

        data_len = io.Information;

        for (;;)
        {
            if (data_pos >= data_len)
            {
3114 3115 3116
                if (NtQueryDirectoryFile( dir, 0, NULL, NULL, &io, buffer, sizeof(buffer),
                                          FileBothDirectoryInformation, FALSE, &lookup_us, FALSE ))
                    break;
3117 3118 3119 3120 3121 3122 3123 3124
                data_len = io.Information;
                data_pos = 0;
            }
            dir_info = (FILE_BOTH_DIR_INFORMATION*)(buffer + data_pos);

            if (dir_info->NextEntryOffset) data_pos += dir_info->NextEntryOffset;
            else data_pos = data_len;

3125
            tmp = dir_info->FileName + (strchrW(lookup, '*') - lookup);
3126
            build = atoiW(tmp);
3127
            if (build < min_build) continue;
3128 3129
            tmp = strchrW(tmp, '.') + 1;
            revision = atoiW(tmp);
3130
            if (build == min_build && revision < min_revision) continue;
3131 3132
            tmp = strchrW(tmp, '_') + 1;
            tmp = strchrW(tmp, '_') + 1;
3133
            if (dir_info->FileNameLength - (tmp - dir_info->FileName) * sizeof(WCHAR) == sizeof(wine_trailerW) &&
3134
                !memicmpW( tmp, wine_trailerW, ARRAY_SIZE( wine_trailerW )))
3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146
            {
                /* prefer a non-Wine manifest if we already have one */
                /* we'll still load the builtin dll if specified through DllOverrides */
                if (ret) continue;
            }
            else
            {
                min_build = build;
                min_revision = revision;
            }
            ai->version.build = build;
            ai->version.revision = revision;
3147
            RtlFreeHeap( GetProcessHeap(), 0, ret );
3148 3149 3150 3151 3152 3153 3154
            if ((ret = RtlAllocateHeap( GetProcessHeap(), 0, dir_info->FileNameLength + sizeof(WCHAR) )))
            {
                memcpy( ret, dir_info->FileName, dir_info->FileNameLength );
                ret[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
            }
        }
    }
3155
    else WARN("no matching file for %s\n", debugstr_w(lookup));
3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173
    RtlFreeHeap( GetProcessHeap(), 0, lookup );
    return ret;
}

static NTSTATUS lookup_winsxs(struct actctx_loader* acl, struct assembly_identity* ai)
{
    struct assembly_identity    sxs_ai;
    UNICODE_STRING              path_us;
    OBJECT_ATTRIBUTES           attr;
    IO_STATUS_BLOCK             io;
    WCHAR *path, *file = NULL;
    HANDLE handle;

    static const WCHAR manifest_dirW[] =
        {'\\','w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s',0};

    if (!ai->arch || !ai->name || !ai->public_key) return STATUS_NO_SUCH_FILE;

3174 3175
    if (!(path = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(manifest_dirW) +
                                  strlenW(user_shared_data->NtSystemRoot) * sizeof(WCHAR) )))
3176 3177
        return STATUS_NO_MEMORY;

3178 3179
    strcpyW( path, user_shared_data->NtSystemRoot );
    memcpy( path + strlenW(path), manifest_dirW, sizeof(manifest_dirW) );
3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194

    if (!RtlDosPathNameToNtPathName_U( path, &path_us, NULL, NULL ))
    {
        RtlFreeHeap( GetProcessHeap(), 0, path );
        return STATUS_NO_SUCH_FILE;
    }
    RtlFreeHeap( GetProcessHeap(), 0, path );

    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.Attributes = OBJ_CASE_INSENSITIVE;
    attr.ObjectName = &path_us;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;

3195
    if (!NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219
                     FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ))
    {
        sxs_ai = *ai;
        file = lookup_manifest_file( handle, &sxs_ai );
        NtClose( handle );
    }
    if (!file)
    {
        RtlFreeUnicodeString( &path_us );
        return STATUS_NO_SUCH_FILE;
    }

    /* append file name to directory path */
    if (!(path = RtlReAllocateHeap( GetProcessHeap(), 0, path_us.Buffer,
                                    path_us.Length + (strlenW(file) + 2) * sizeof(WCHAR) )))
    {
        RtlFreeHeap( GetProcessHeap(), 0, file );
        RtlFreeUnicodeString( &path_us );
        return STATUS_NO_MEMORY;
    }

    path[path_us.Length/sizeof(WCHAR)] = '\\';
    strcpyW( path + path_us.Length/sizeof(WCHAR) + 1, file );
    RtlInitUnicodeString( &path_us, path );
3220
    *strrchrW(file, '.') = 0;  /* remove .manifest extension */
3221 3222 3223

    if (!open_nt_file( &handle, &path_us ))
    {
3224
        io.u.Status = get_manifest_in_manifest_file(acl, &sxs_ai, path_us.Buffer, file, TRUE, handle);
3225 3226 3227 3228
        NtClose( handle );
    }
    else io.u.Status = STATUS_NO_SUCH_FILE;

3229
    RtlFreeHeap( GetProcessHeap(), 0, file );
3230 3231 3232 3233
    RtlFreeUnicodeString( &path_us );
    return io.u.Status;
}

3234 3235 3236 3237 3238
static NTSTATUS lookup_assembly(struct actctx_loader* acl,
                                struct assembly_identity* ai)
{
    static const WCHAR dotDllW[] = {'.','d','l','l',0};
    unsigned int i;
3239
    WCHAR *buffer, *p, *directory;
3240 3241 3242
    NTSTATUS status;
    UNICODE_STRING nameW;
    HANDLE file;
3243
    DWORD len;
3244

3245 3246 3247
    TRACE( "looking for name=%s version=%s arch=%s\n",
           debugstr_w(ai->name), debugstr_version(&ai->version), debugstr_w(ai->arch) );

3248 3249
    if ((status = lookup_winsxs(acl, ai)) != STATUS_NO_SUCH_FILE) return status;

3250 3251
    /* FIXME: add support for language specific lookup */

3252 3253 3254
    len = max(RtlGetFullPathName_U(acl->actctx->assemblies->manifest.info, 0, NULL, NULL) / sizeof(WCHAR),
        strlenW(acl->actctx->appdir.info));

3255 3256
    nameW.Buffer = NULL;
    if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0,
3257
                                    (len + 2 * strlenW(ai->name) + 2) * sizeof(WCHAR) + sizeof(dotManifestW) )))
3258 3259
        return STATUS_NO_MEMORY;

3260 3261 3262 3263 3264 3265
    if (!(directory = build_assembly_dir( ai )))
    {
        RtlFreeHeap( GetProcessHeap(), 0, buffer );
        return STATUS_NO_MEMORY;
    }

3266 3267 3268 3269 3270 3271 3272
    /* Lookup in <dir>\name.dll
     *           <dir>\name.manifest
     *           <dir>\name\name.dll
     *           <dir>\name\name.manifest
     *
     * First 'appdir' is used as <dir>, if that failed
     * it tries application manifest file path.
3273 3274 3275
     */
    strcpyW( buffer, acl->actctx->appdir.info );
    p = buffer + strlenW(buffer);
3276
    for (i = 0; i < 4; i++)
3277
    {
3278 3279 3280 3281 3282 3283 3284
        if (i == 2)
        {
            struct assembly *assembly = acl->actctx->assemblies;
            if (!RtlGetFullPathName_U(assembly->manifest.info, len * sizeof(WCHAR), buffer, &p)) break;
        }
        else *p++ = '\\';

3285 3286 3287 3288 3289 3290 3291 3292 3293
        strcpyW( p, ai->name );
        p += strlenW(p);

        strcpyW( p, dotDllW );
        if (RtlDosPathNameToNtPathName_U( buffer, &nameW, NULL, NULL ))
        {
            status = open_nt_file( &file, &nameW );
            if (!status)
            {
3294
                status = get_manifest_in_pe_file( acl, ai, nameW.Buffer, directory, FALSE, file,
3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307
                                                  (LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID, 0 );
                NtClose( file );
                break;
            }
            RtlFreeUnicodeString( &nameW );
        }

        strcpyW( p, dotManifestW );
        if (RtlDosPathNameToNtPathName_U( buffer, &nameW, NULL, NULL ))
        {
            status = open_nt_file( &file, &nameW );
            if (!status)
            {
3308
                status = get_manifest_in_manifest_file( acl, ai, nameW.Buffer, directory, FALSE, file );
3309 3310 3311 3312 3313
                NtClose( file );
                break;
            }
            RtlFreeUnicodeString( &nameW );
        }
3314
        status = STATUS_SXS_ASSEMBLY_NOT_FOUND;
3315 3316
    }
    RtlFreeUnicodeString( &nameW );
3317 3318 3319
    RtlFreeHeap( GetProcessHeap(), 0, directory );
    RtlFreeHeap( GetProcessHeap(), 0, buffer );
    return status;
3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330
}

static NTSTATUS parse_depend_manifests(struct actctx_loader* acl)
{
    NTSTATUS status = STATUS_SUCCESS;
    unsigned int i;

    for (i = 0; i < acl->num_dependencies; i++)
    {
        if (lookup_assembly(acl, &acl->dependencies[i]) != STATUS_SUCCESS)
        {
3331
            if (!acl->dependencies[i].optional && !acl->dependencies[i].delayed)
3332
            {
3333 3334 3335
                FIXME( "Could not find dependent assembly %s (%s)\n",
                    debugstr_w(acl->dependencies[i].name),
                    debugstr_version(&acl->dependencies[i].version) );
3336 3337 3338
                status = STATUS_SXS_CANT_GEN_ACTCTX;
                break;
            }
3339 3340 3341 3342 3343 3344
        }
    }
    /* FIXME should now iterate through all refs */
    return status;
}

3345
/* find the appropriate activation context for RtlQueryInformationActivationContext */
3346
static NTSTATUS find_query_actctx( HANDLE *handle, DWORD flags, ULONG class )
3347 3348 3349 3350 3351
{
    NTSTATUS status = STATUS_SUCCESS;

    if (flags & QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX)
    {
3352 3353
        if (*handle) return STATUS_INVALID_PARAMETER;

3354 3355 3356 3357 3358
        if (NtCurrentTeb()->ActivationContextStack.ActiveFrame)
            *handle = NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext;
    }
    else if (flags & (QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS|QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE))
    {
3359
        ULONG_PTR magic;
3360 3361
        LDR_MODULE *pldr;

3362 3363
        if (!*handle) return STATUS_INVALID_PARAMETER;

3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374
        LdrLockLoaderLock( 0, NULL, &magic );
        if (!LdrFindEntryForAddress( *handle, &pldr ))
        {
            if ((flags & QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE) && *handle != pldr->BaseAddress)
                status = STATUS_DLL_NOT_FOUND;
            else
                *handle = pldr->ActivationContext;
        }
        else status = STATUS_DLL_NOT_FOUND;
        LdrUnlockLoaderLock( 0, magic );
    }
3375 3376
    else if (!*handle && (class != ActivationContextBasicInformation))
        *handle = process_actctx;
3377 3378 3379 3380

    return status;
}

3381
static NTSTATUS build_dllredirect_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
3382
{
3383 3384 3385 3386 3387
    unsigned int i, j, total_len = 0, dll_count = 0;
    struct strsection_header *header;
    struct dllredirect_data *data;
    struct string_index *index;
    ULONG name_offset;
3388

3389 3390 3391 3392 3393 3394 3395
    /* compute section length */
    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
3396

3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411
            /* each entry needs index, data and string data */
            total_len += sizeof(*index);
            total_len += sizeof(*data);
            total_len += aligned_string_len((strlenW(dll->name)+1)*sizeof(WCHAR));
        }

        dll_count += assembly->num_dlls;
    }

    total_len += sizeof(*header);

    header = RtlAllocateHeap(GetProcessHeap(), 0, total_len);
    if (!header) return STATUS_NO_MEMORY;

    memset(header, 0, sizeof(*header));
3412
    header->magic = STRSECTION_MAGIC;
3413 3414 3415 3416 3417
    header->size  = sizeof(*header);
    header->count = dll_count;
    header->index_offset = sizeof(*header);
    index = (struct string_index*)((BYTE*)header + header->index_offset);
    name_offset = header->index_offset + header->count*sizeof(*index);
3418 3419 3420 3421 3422 3423 3424

    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454
            UNICODE_STRING str;
            WCHAR *ptrW;

            /* setup new index entry */
            str.Buffer = dll->name;
            str.Length = strlenW(dll->name)*sizeof(WCHAR);
            str.MaximumLength = str.Length + sizeof(WCHAR);
            /* hash original class name */
            RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &index->hash);

            index->name_offset = name_offset;
            index->name_len = str.Length;
            index->data_offset = index->name_offset + aligned_string_len(str.MaximumLength);
            index->data_len = sizeof(*data);
            index->rosterindex = i + 1;

            /* setup data */
            data = (struct dllredirect_data*)((BYTE*)header + index->data_offset);
            data->size = sizeof(*data);
            data->unk = 2; /* FIXME: seems to be constant */
            memset(data->res, 0, sizeof(data->res));

            /* dll name */
            ptrW = (WCHAR*)((BYTE*)header + index->name_offset);
            memcpy(ptrW, dll->name, index->name_len);
            ptrW[index->name_len/sizeof(WCHAR)] = 0;

            name_offset += sizeof(*data) + aligned_string_len(str.MaximumLength);

            index++;
3455 3456
        }
    }
3457 3458 3459 3460

    *section = header;

    return STATUS_SUCCESS;
3461 3462
}

3463
static struct string_index *find_string_index(const struct strsection_header *section, const UNICODE_STRING *name)
3464
{
3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476
    struct string_index *iter, *index = NULL;
    ULONG hash = 0, i;

    RtlHashUnicodeString(name, TRUE, HASH_STRING_ALGORITHM_X65599, &hash);
    iter = (struct string_index*)((BYTE*)section + section->index_offset);

    for (i = 0; i < section->count; i++)
    {
        if (iter->hash == hash)
        {
            const WCHAR *nameW = (WCHAR*)((BYTE*)section + iter->name_offset);

3477
            if (!strcmpiW(nameW, name->Buffer))
3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488
            {
                index = iter;
                break;
            }
            else
                WARN("hash collision 0x%08x, %s, %s\n", hash, debugstr_us(name), debugstr_w(nameW));
        }
        iter++;
    }

    return index;
3489 3490
}

3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510
static struct guid_index *find_guid_index(const struct guidsection_header *section, const GUID *guid)
{
    struct guid_index *iter, *index = NULL;
    ULONG i;

    iter = (struct guid_index*)((BYTE*)section + section->index_offset);

    for (i = 0; i < section->count; i++)
    {
        if (!memcmp(guid, &iter->guid, sizeof(*guid)))
        {
            index = iter;
            break;
        }
        iter++;
    }

    return index;
}

3511
static inline struct dllredirect_data *get_dllredirect_data(ACTIVATION_CONTEXT *ctxt, struct string_index *index)
3512
{
3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537
    return (struct dllredirect_data*)((BYTE*)ctxt->dllredirect_section + index->data_offset);
}

static NTSTATUS find_dll_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
                                     PACTCTX_SECTION_KEYED_DATA data)
{
    struct dllredirect_data *dll;
    struct string_index *index;

    if (!(actctx->sections & DLLREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;

    if (!actctx->dllredirect_section)
    {
        struct strsection_header *section;

        NTSTATUS status = build_dllredirect_section(actctx, &section);
        if (status) return status;

        if (interlocked_cmpxchg_ptr((void**)&actctx->dllredirect_section, section, NULL))
            RtlFreeHeap(GetProcessHeap(), 0, section);
    }

    index = find_string_index(actctx->dllredirect_section, name);
    if (!index) return STATUS_SXS_KEY_NOT_FOUND;

3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553
    if (data)
    {
        dll = get_dllredirect_data(actctx, index);

        data->ulDataFormatVersion = 1;
        data->lpData = dll;
        data->ulLength = dll->size;
        data->lpSectionGlobalData = NULL;
        data->ulSectionGlobalDataLength = 0;
        data->lpSectionBase = actctx->dllredirect_section;
        data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->dllredirect_section );
        data->hActCtx = NULL;

        if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
            data->ulAssemblyRosterIndex = index->rosterindex;
    }
3554 3555

    return STATUS_SUCCESS;
3556 3557
}

3558
static inline struct string_index *get_wndclass_first_index(ACTIVATION_CONTEXT *actctx)
3559
{
3560 3561 3562 3563 3564 3565
    return (struct string_index*)((BYTE*)actctx->wndclass_section + actctx->wndclass_section->index_offset);
}

static inline struct wndclass_redirect_data *get_wndclass_data(ACTIVATION_CONTEXT *ctxt, struct string_index *index)
{
    return (struct wndclass_redirect_data*)((BYTE*)ctxt->wndclass_section + index->data_offset);
3566 3567
}

3568
static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
3569 3570 3571
{
    unsigned int i, j, k, total_len = 0, class_count = 0;
    struct wndclass_redirect_data *data;
3572 3573
    struct strsection_header *header;
    struct string_index *index;
3574
    ULONG name_offset;
3575

3576
    /* compute section length */
3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587
    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
            for (k = 0; k < dll->entities.num; k++)
            {
                struct entity *entity = &dll->entities.base[k];
                if (entity->kind == ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)
                {
3588
                    int class_len = strlenW(entity->u.class.name) + 1;
3589 3590 3591
                    int len;

                    /* each class entry needs index, data and string data */
3592 3593
                    total_len += sizeof(*index);
                    total_len += sizeof(*data);
3594
                    /* original name is stored separately */
3595
                    total_len += aligned_string_len(class_len*sizeof(WCHAR));
3596
                    /* versioned name and module name are stored one after another */
3597 3598 3599 3600
                    if (entity->u.class.versioned)
                        len = get_assembly_version(assembly, NULL) + class_len + 1 /* '!' separator */;
                    else
                        len = class_len;
3601 3602 3603 3604
                    len += strlenW(dll->name) + 1;
                    total_len += aligned_string_len(len*sizeof(WCHAR));

                    class_count++;
3605 3606 3607 3608
                }
            }
        }
    }
3609 3610 3611 3612 3613 3614 3615

    total_len += sizeof(*header);

    header = RtlAllocateHeap(GetProcessHeap(), 0, total_len);
    if (!header) return STATUS_NO_MEMORY;

    memset(header, 0, sizeof(*header));
3616
    header->magic = STRSECTION_MAGIC;
3617
    header->size  = sizeof(*header);
3618 3619
    header->count = class_count;
    header->index_offset = sizeof(*header);
3620
    index = (struct string_index*)((BYTE*)header + header->index_offset);
3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646
    name_offset = header->index_offset + header->count*sizeof(*index);

    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
            for (k = 0; k < dll->entities.num; k++)
            {
                struct entity *entity = &dll->entities.base[k];
                if (entity->kind == ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)
                {
                    static const WCHAR exclW[] = {'!',0};
                    ULONG versioned_len, module_len;
                    UNICODE_STRING str;
                    WCHAR *ptrW;

                    /* setup new index entry */
                    str.Buffer = entity->u.class.name;
                    str.Length = strlenW(entity->u.class.name)*sizeof(WCHAR);
                    str.MaximumLength = str.Length + sizeof(WCHAR);
                    /* hash original class name */
                    RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &index->hash);

                    /* include '!' separator too */
3647 3648 3649 3650
                    if (entity->u.class.versioned)
                        versioned_len = (get_assembly_version(assembly, NULL) + 1)*sizeof(WCHAR) + str.Length;
                    else
                        versioned_len = str.Length;
3651 3652 3653 3654 3655 3656
                    module_len = strlenW(dll->name)*sizeof(WCHAR);

                    index->name_offset = name_offset;
                    index->name_len = str.Length;
                    index->data_offset = index->name_offset + aligned_string_len(str.MaximumLength);
                    index->data_len = sizeof(*data) + versioned_len + module_len + 2*sizeof(WCHAR) /* two nulls */;
3657
                    index->rosterindex = i + 1;
3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679

                    /* setup data */
                    data = (struct wndclass_redirect_data*)((BYTE*)header + index->data_offset);
                    data->size = sizeof(*data);
                    data->res = 0;
                    data->name_len = versioned_len;
                    data->name_offset = sizeof(*data);
                    data->module_len = module_len;
                    data->module_offset = index->data_offset + data->name_offset + data->name_len + sizeof(WCHAR);

                    /* original class name */
                    ptrW = (WCHAR*)((BYTE*)header + index->name_offset);
                    memcpy(ptrW, entity->u.class.name, index->name_len);
                    ptrW[index->name_len/sizeof(WCHAR)] = 0;

                    /* module name */
                    ptrW = (WCHAR*)((BYTE*)header + data->module_offset);
                    memcpy(ptrW, dll->name, data->module_len);
                    ptrW[data->module_len/sizeof(WCHAR)] = 0;

                    /* versioned name */
                    ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690
                    if (entity->u.class.versioned)
                    {
                        get_assembly_version(assembly, ptrW);
                        strcatW(ptrW, exclW);
                        strcatW(ptrW, entity->u.class.name);
                    }
                    else
                    {
                        memcpy(ptrW, entity->u.class.name, index->name_len);
                        ptrW[index->name_len/sizeof(WCHAR)] = 0;
                    }
3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708

                    name_offset += sizeof(*data);
                    name_offset += aligned_string_len(str.MaximumLength) + aligned_string_len(versioned_len + module_len + 2*sizeof(WCHAR));

                    index++;
                }
            }
        }
    }

    *section = header;

    return STATUS_SUCCESS;
}

static NTSTATUS find_window_class(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
                                  PACTCTX_SECTION_KEYED_DATA data)
{
3709
    struct string_index *iter, *index = NULL;
3710 3711 3712 3713 3714 3715 3716 3717
    struct wndclass_redirect_data *class;
    ULONG hash;
    int i;

    if (!(actctx->sections & WINDOWCLASS_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;

    if (!actctx->wndclass_section)
    {
3718
        struct strsection_header *section;
3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736

        NTSTATUS status = build_wndclass_section(actctx, &section);
        if (status) return status;

        if (interlocked_cmpxchg_ptr((void**)&actctx->wndclass_section, section, NULL))
            RtlFreeHeap(GetProcessHeap(), 0, section);
    }

    hash = 0;
    RtlHashUnicodeString(name, TRUE, HASH_STRING_ALGORITHM_X65599, &hash);
    iter = get_wndclass_first_index(actctx);

    for (i = 0; i < actctx->wndclass_section->count; i++)
    {
        if (iter->hash == hash)
        {
            const WCHAR *nameW = (WCHAR*)((BYTE*)actctx->wndclass_section + iter->name_offset);

3737
            if (!strcmpiW(nameW, name->Buffer))
3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749
            {
                index = iter;
                break;
            }
            else
                WARN("hash collision 0x%08x, %s, %s\n", hash, debugstr_us(name), debugstr_w(nameW));
        }
        iter++;
    }

    if (!index) return STATUS_SXS_KEY_NOT_FOUND;

3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766
    if (data)
    {
        class = get_wndclass_data(actctx, index);

        data->ulDataFormatVersion = 1;
        data->lpData = class;
        /* full length includes string length with nulls */
        data->ulLength = class->size + class->name_len + class->module_len + 2*sizeof(WCHAR);
        data->lpSectionGlobalData = NULL;
        data->ulSectionGlobalDataLength = 0;
        data->lpSectionBase = actctx->wndclass_section;
        data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->wndclass_section );
        data->hActCtx = NULL;

        if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
            data->ulAssemblyRosterIndex = index->rosterindex;
    }
3767 3768

    return STATUS_SUCCESS;
3769 3770
}

3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926
static NTSTATUS build_tlib_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
{
    unsigned int i, j, k, total_len = 0, tlib_count = 0, names_len = 0;
    struct guidsection_header *header;
    ULONG module_offset, data_offset;
    struct tlibredirect_data *data;
    struct guid_index *index;

    /* compute section length */
    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
            for (k = 0; k < dll->entities.num; k++)
            {
                struct entity *entity = &dll->entities.base[k];
                if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)
                {
                    /* each entry needs index, data and string data for module name and help string */
                    total_len += sizeof(*index);
                    total_len += sizeof(*data);
                    /* help string is stored separately */
                    if (*entity->u.typelib.helpdir)
                        total_len += aligned_string_len((strlenW(entity->u.typelib.helpdir)+1)*sizeof(WCHAR));

                    /* module names are packed one after another */
                    names_len += (strlenW(dll->name)+1)*sizeof(WCHAR);

                    tlib_count++;
                }
            }
        }
    }

    total_len += aligned_string_len(names_len);
    total_len += sizeof(*header);

    header = RtlAllocateHeap(GetProcessHeap(), 0, total_len);
    if (!header) return STATUS_NO_MEMORY;

    memset(header, 0, sizeof(*header));
    header->magic = GUIDSECTION_MAGIC;
    header->size  = sizeof(*header);
    header->count = tlib_count;
    header->index_offset = sizeof(*header) + aligned_string_len(names_len);
    index = (struct guid_index*)((BYTE*)header + header->index_offset);
    module_offset = sizeof(*header);
    data_offset = header->index_offset + tlib_count*sizeof(*index);

    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
            for (k = 0; k < dll->entities.num; k++)
            {
                struct entity *entity = &dll->entities.base[k];
                if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION)
                {
                    ULONG module_len, help_len;
                    UNICODE_STRING str;
                    WCHAR *ptrW;

                    if (*entity->u.typelib.helpdir)
                        help_len = strlenW(entity->u.typelib.helpdir)*sizeof(WCHAR);
                    else
                        help_len = 0;

                    module_len = strlenW(dll->name)*sizeof(WCHAR);

                    /* setup new index entry */
                    RtlInitUnicodeString(&str, entity->u.typelib.tlbid);
                    RtlGUIDFromString(&str, &index->guid);
                    index->data_offset = data_offset;
                    index->data_len = sizeof(*data) + aligned_string_len(help_len);
                    index->rosterindex = i + 1;

                    /* setup data */
                    data = (struct tlibredirect_data*)((BYTE*)header + index->data_offset);
                    data->size = sizeof(*data);
                    data->res = 0;
                    data->name_len = module_len;
                    data->name_offset = module_offset;
                    /* FIXME: resourceid handling is really weird, and it doesn't seem to be useful */
                    data->langid = 0;
                    data->flags = entity->u.typelib.flags;
                    data->help_len = help_len;
                    data->help_offset = sizeof(*data);
                    data->major_version = entity->u.typelib.major;
                    data->minor_version = entity->u.typelib.minor;

                    /* module name */
                    ptrW = (WCHAR*)((BYTE*)header + data->name_offset);
                    memcpy(ptrW, dll->name, data->name_len);
                    ptrW[data->name_len/sizeof(WCHAR)] = 0;

                    /* help string */
                    if (data->help_len)
                    {
                        ptrW = (WCHAR*)((BYTE*)data + data->help_offset);
                        memcpy(ptrW, entity->u.typelib.helpdir, data->help_len);
                        ptrW[data->help_len/sizeof(WCHAR)] = 0;
                    }

                    data_offset += sizeof(*data);
                    if (help_len)
                        data_offset += aligned_string_len(help_len + sizeof(WCHAR));

                    module_offset += module_len + sizeof(WCHAR);

                    index++;
                }
            }
        }
    }

    *section = header;

    return STATUS_SUCCESS;
}

static inline struct tlibredirect_data *get_tlib_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
{
    return (struct tlibredirect_data*)((BYTE*)actctx->tlib_section + index->data_offset);
}

static NTSTATUS find_tlib_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
{
    struct guid_index *index = NULL;
    struct tlibredirect_data *tlib;

    if (!(actctx->sections & TLIBREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;

    if (!actctx->tlib_section)
    {
        struct guidsection_header *section;

        NTSTATUS status = build_tlib_section(actctx, &section);
        if (status) return status;

        if (interlocked_cmpxchg_ptr((void**)&actctx->tlib_section, section, NULL))
            RtlFreeHeap(GetProcessHeap(), 0, section);
    }

    index = find_guid_index(actctx->tlib_section, guid);
    if (!index) return STATUS_SXS_KEY_NOT_FOUND;

    tlib = get_tlib_data(actctx, index);

    data->ulDataFormatVersion = 1;
    data->lpData = tlib;
    /* full length includes string length with nulls */
    data->ulLength = tlib->size + tlib->help_len + sizeof(WCHAR);
3927 3928
    data->lpSectionGlobalData = (BYTE*)actctx->tlib_section + actctx->tlib_section->names_offset;
    data->ulSectionGlobalDataLength = actctx->tlib_section->names_len;
3929 3930 3931 3932 3933 3934 3935 3936 3937 3938
    data->lpSectionBase = actctx->tlib_section;
    data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->tlib_section );
    data->hActCtx = NULL;

    if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
        data->ulAssemblyRosterIndex = index->rosterindex;

    return STATUS_SUCCESS;
}

3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953
static void generate_uuid(ULONG *seed, GUID *guid)
{
    ULONG *ptr = (ULONG*)guid;
    int i;

    /* GUID is 16 bytes long */
    for (i = 0; i < sizeof(GUID)/sizeof(ULONG); i++, ptr++)
        *ptr = RtlUniform(seed);

    guid->Data3 &= 0x0fff;
    guid->Data3 |= (4 << 12);
    guid->Data4[0] &= 0x3f;
    guid->Data4[0] |= 0x80;
}

3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976
static void get_comserver_datalen(const struct entity_array *entities, const struct dll_redirect *dll,
    unsigned int *count, unsigned int *len, unsigned int *module_len)
{
    unsigned int i;

    for (i = 0; i < entities->num; i++)
    {
        struct entity *entity = &entities->base[i];
        if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
        {
            /* each entry needs two index entries, extra one goes for alias GUID */
            *len += 2*sizeof(struct guid_index);
            /* To save some memory we don't allocated two data structures,
               instead alias index and normal index point to the same data structure. */
            *len += sizeof(struct comclassredirect_data);

            /* for clrClass store some more */
            if (entity->u.comclass.name)
            {
                unsigned int str_len;

                /* all string data is stored together in aligned block */
                str_len = strlenW(entity->u.comclass.name)+1;
3977
                if (entity->u.comclass.progid)
3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990
                    str_len += strlenW(entity->u.comclass.progid)+1;
                if (entity->u.comclass.version)
                    str_len += strlenW(entity->u.comclass.version)+1;

                *len += sizeof(struct clrclass_data);
                *len += aligned_string_len(str_len*sizeof(WCHAR));

                /* module name is forced to mscoree.dll, and stored two times with different case */
                *module_len += sizeof(mscoreeW) + sizeof(mscoree2W);
            }
            else
            {
                /* progid string is stored separately */
3991
                if (entity->u.comclass.progid)
3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019
                    *len += aligned_string_len((strlenW(entity->u.comclass.progid)+1)*sizeof(WCHAR));

                *module_len += (strlenW(dll->name)+1)*sizeof(WCHAR);
            }

            *count += 1;
        }
    }
}

static void add_comserver_record(const struct guidsection_header *section, const struct entity_array *entities,
    const struct dll_redirect *dll, struct guid_index **index, ULONG *data_offset, ULONG *module_offset,
    ULONG *seed, ULONG rosterindex)
{
    unsigned int i;

    for (i = 0; i < entities->num; i++)
    {
        struct entity *entity = &entities->base[i];
        if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
        {
            ULONG module_len, progid_len, str_len = 0;
            struct comclassredirect_data *data;
            struct guid_index *alias_index;
            struct clrclass_data *clrdata;
            UNICODE_STRING str;
            WCHAR *ptrW;

4020
            if (entity->u.comclass.progid)
4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177
                progid_len = strlenW(entity->u.comclass.progid)*sizeof(WCHAR);
            else
                progid_len = 0;

            module_len = dll ? strlenW(dll->name)*sizeof(WCHAR) : strlenW(mscoreeW)*sizeof(WCHAR);

            /* setup new index entry */
            RtlInitUnicodeString(&str, entity->u.comclass.clsid);
            RtlGUIDFromString(&str, &(*index)->guid);

            (*index)->data_offset = *data_offset;
            (*index)->data_len = sizeof(*data); /* additional length added later */
            (*index)->rosterindex = rosterindex;

            /* Setup new index entry for alias guid. Alias index records are placed after
               normal records, so normal guids are hit first on search. Note that class count
               is doubled. */
            alias_index = (*index) + section->count/2;
            generate_uuid(seed, &alias_index->guid);
            alias_index->data_offset = (*index)->data_offset;
            alias_index->data_len = 0;
            alias_index->rosterindex = (*index)->rosterindex;

            /* setup data */
            data = (struct comclassredirect_data*)((BYTE*)section + (*index)->data_offset);
            data->size = sizeof(*data);
            data->res = 0;
            data->res1[0] = 0;
            data->res1[1] = 0;
            data->model = entity->u.comclass.model;
            data->clsid = (*index)->guid;
            data->alias = alias_index->guid;
            data->clsid2 = data->clsid;
            if (entity->u.comclass.tlbid)
            {
                RtlInitUnicodeString(&str, entity->u.comclass.tlbid);
                RtlGUIDFromString(&str, &data->tlbid);
            }
            else
                memset(&data->tlbid, 0, sizeof(data->tlbid));
            data->name_len = module_len;
            data->name_offset = *module_offset;
            data->progid_len = progid_len;
            data->progid_offset = data->progid_len ? data->size : 0; /* in case of clrClass additional offset is added later */
            data->clrdata_len = 0; /* will be set later */
            data->clrdata_offset = entity->u.comclass.name ? sizeof(*data) : 0;
            data->miscstatus = entity->u.comclass.miscstatus;
            data->miscstatuscontent = entity->u.comclass.miscstatuscontent;
            data->miscstatusthumbnail = entity->u.comclass.miscstatusthumbnail;
            data->miscstatusicon = entity->u.comclass.miscstatusicon;
            data->miscstatusdocprint = entity->u.comclass.miscstatusdocprint;

            /* mask describes which misc* data is available */
            data->miscmask = 0;
            if (data->miscstatus)
                data->miscmask |= MiscStatus;
            if (data->miscstatuscontent)
                data->miscmask |= MiscStatusContent;
            if (data->miscstatusthumbnail)
                data->miscmask |= MiscStatusThumbnail;
            if (data->miscstatusicon)
                data->miscmask |= MiscStatusIcon;
            if (data->miscstatusdocprint)
                data->miscmask |= MiscStatusDocPrint;

            if (data->clrdata_offset)
            {
                clrdata = (struct clrclass_data*)((BYTE*)data + data->clrdata_offset);

                clrdata->size = sizeof(*clrdata);
                clrdata->res[0] = 0;
                clrdata->res[1] = 2; /* FIXME: unknown field */
                clrdata->module_len = strlenW(mscoreeW)*sizeof(WCHAR);
                clrdata->module_offset = *module_offset + data->name_len + sizeof(WCHAR);
                clrdata->name_len = strlenW(entity->u.comclass.name)*sizeof(WCHAR);
                clrdata->name_offset = clrdata->size;
                clrdata->version_len = entity->u.comclass.version ? strlenW(entity->u.comclass.version)*sizeof(WCHAR) : 0;
                clrdata->version_offset = clrdata->version_len ? clrdata->name_offset + clrdata->name_len + sizeof(WCHAR) : 0;
                clrdata->res2[0] = 0;
                clrdata->res2[1] = 0;

                data->clrdata_len = clrdata->size + clrdata->name_len + sizeof(WCHAR);

                /* module name */
                ptrW = (WCHAR*)((BYTE*)section + clrdata->module_offset);
                memcpy(ptrW, mscoree2W, clrdata->module_len);
                ptrW[clrdata->module_len/sizeof(WCHAR)] = 0;

                ptrW = (WCHAR*)((BYTE*)section + data->name_offset);
                memcpy(ptrW, mscoreeW, data->name_len);
                ptrW[data->name_len/sizeof(WCHAR)] = 0;

                /* class name */
                ptrW = (WCHAR*)((BYTE*)clrdata + clrdata->name_offset);
                memcpy(ptrW, entity->u.comclass.name, clrdata->name_len);
                ptrW[clrdata->name_len/sizeof(WCHAR)] = 0;

                /* runtime version, optional */
                if (clrdata->version_len)
                {
                    data->clrdata_len += clrdata->version_len + sizeof(WCHAR);

                    ptrW = (WCHAR*)((BYTE*)clrdata + clrdata->version_offset);
                    memcpy(ptrW, entity->u.comclass.version, clrdata->version_len);
                    ptrW[clrdata->version_len/sizeof(WCHAR)] = 0;
                }

                if (data->progid_len)
                    data->progid_offset += data->clrdata_len;
                (*index)->data_len += sizeof(*clrdata);
            }
            else
            {
                clrdata = NULL;

                /* module name */
                ptrW = (WCHAR*)((BYTE*)section + data->name_offset);
                memcpy(ptrW, dll->name, data->name_len);
                ptrW[data->name_len/sizeof(WCHAR)] = 0;
            }

            /* progid string */
            if (data->progid_len)
            {
                ptrW = (WCHAR*)((BYTE*)data + data->progid_offset);
                memcpy(ptrW, entity->u.comclass.progid, data->progid_len);
                ptrW[data->progid_len/sizeof(WCHAR)] = 0;
            }

            /* string block length */
            str_len = 0;
            if (clrdata)
            {
                str_len += clrdata->name_len + sizeof(WCHAR);
                if (clrdata->version_len)
                    str_len += clrdata->version_len + sizeof(WCHAR);
            }
            if (progid_len)
                str_len += progid_len + sizeof(WCHAR);

            (*index)->data_len += aligned_string_len(str_len);
            alias_index->data_len = (*index)->data_len;

            /* move to next data record */
            (*data_offset) += sizeof(*data) + aligned_string_len(str_len);
            (*module_offset) += module_len + sizeof(WCHAR);

            if (clrdata)
            {
                (*data_offset) += sizeof(*clrdata);
                (*module_offset) += clrdata->module_len + sizeof(WCHAR);
            }
            (*index) += 1;
        }
    }
}

4178 4179
static NTSTATUS build_comserver_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
{
4180
    unsigned int i, j, total_len = 0, class_count = 0, names_len = 0;
4181 4182
    struct guidsection_header *header;
    ULONG module_offset, data_offset;
4183
    struct guid_index *index;
4184 4185 4186 4187 4188 4189
    ULONG seed;

    /* compute section length */
    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
4190
        get_comserver_datalen(&assembly->entities, NULL, &class_count, &total_len, &names_len);
4191 4192 4193
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
4194
            get_comserver_datalen(&dll->entities, dll, &class_count, &total_len, &names_len);
4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216
        }
    }

    total_len += aligned_string_len(names_len);
    total_len += sizeof(*header);

    header = RtlAllocateHeap(GetProcessHeap(), 0, total_len);
    if (!header) return STATUS_NO_MEMORY;

    memset(header, 0, sizeof(*header));
    header->magic = GUIDSECTION_MAGIC;
    header->size  = sizeof(*header);
    header->count = 2*class_count;
    header->index_offset = sizeof(*header) + aligned_string_len(names_len);
    index = (struct guid_index*)((BYTE*)header + header->index_offset);
    module_offset = sizeof(*header);
    data_offset = header->index_offset + 2*class_count*sizeof(*index);

    seed = NtGetTickCount();
    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
4217
        add_comserver_record(header, &assembly->entities, NULL, &index, &data_offset, &module_offset, &seed, i+1);
4218 4219 4220
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
4221
            add_comserver_record(header, &dll->entities, dll, &index, &data_offset, &module_offset, &seed, i+1);
4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260
        }
    }

    *section = header;

    return STATUS_SUCCESS;
}

static inline struct comclassredirect_data *get_comclass_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
{
    return (struct comclassredirect_data*)((BYTE*)actctx->comserver_section + index->data_offset);
}

static NTSTATUS find_comserver_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
{
    struct comclassredirect_data *comclass;
    struct guid_index *index = NULL;

    if (!(actctx->sections & SERVERREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;

    if (!actctx->comserver_section)
    {
        struct guidsection_header *section;

        NTSTATUS status = build_comserver_section(actctx, &section);
        if (status) return status;

        if (interlocked_cmpxchg_ptr((void**)&actctx->comserver_section, section, NULL))
            RtlFreeHeap(GetProcessHeap(), 0, section);
    }

    index = find_guid_index(actctx->comserver_section, guid);
    if (!index) return STATUS_SXS_KEY_NOT_FOUND;

    comclass = get_comclass_data(actctx, index);

    data->ulDataFormatVersion = 1;
    data->lpData = comclass;
    /* full length includes string length with nulls */
4261 4262
    data->ulLength = comclass->size + comclass->clrdata_len;
    if (comclass->progid_len) data->ulLength += comclass->progid_len + sizeof(WCHAR);
4263 4264
    data->lpSectionGlobalData = (BYTE*)actctx->comserver_section + actctx->comserver_section->names_offset;
    data->ulSectionGlobalDataLength = actctx->comserver_section->names_len;
4265 4266 4267 4268 4269 4270 4271 4272 4273 4274
    data->lpSectionBase = actctx->comserver_section;
    data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->comserver_section );
    data->hActCtx = NULL;

    if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
        data->ulAssemblyRosterIndex = index->rosterindex;

    return STATUS_SUCCESS;
}

4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462
static void get_ifaceps_datalen(const struct entity_array *entities, unsigned int *count, unsigned int *len)
{
    unsigned int i;

    for (i = 0; i < entities->num; i++)
    {
        struct entity *entity = &entities->base[i];
        if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)
        {
            *len += sizeof(struct guid_index) + sizeof(struct ifacepsredirect_data);
            if (entity->u.ifaceps.name)
                *len += aligned_string_len((strlenW(entity->u.ifaceps.name)+1)*sizeof(WCHAR));
            *count += 1;
        }
    }
}

static void add_ifaceps_record(struct guidsection_header *section, struct entity_array *entities,
    struct guid_index **index, ULONG *data_offset, ULONG rosterindex)
{
    unsigned int i;

    for (i = 0; i < entities->num; i++)
    {
        struct entity *entity = &entities->base[i];
        if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION)
        {
            struct ifacepsredirect_data *data = (struct ifacepsredirect_data*)((BYTE*)section + *data_offset);
            UNICODE_STRING str;
            ULONG name_len;

            if (entity->u.ifaceps.name)
                name_len = strlenW(entity->u.ifaceps.name)*sizeof(WCHAR);
            else
                name_len = 0;

            /* setup index */
            RtlInitUnicodeString(&str, entity->u.ifaceps.iid);
            RtlGUIDFromString(&str, &(*index)->guid);
            (*index)->data_offset = *data_offset;
            (*index)->data_len = sizeof(*data) + name_len ? aligned_string_len(name_len + sizeof(WCHAR)) : 0;
            (*index)->rosterindex = rosterindex;

            /* setup data record */
            data->size = sizeof(*data);
            data->mask = entity->u.ifaceps.mask;

            /* proxyStubClsid32 value is only stored for external PS,
               if set it's used as iid, otherwise 'iid' attribute value is used */
            if (entity->u.ifaceps.ps32)
            {
                RtlInitUnicodeString(&str, entity->u.ifaceps.ps32);
                RtlGUIDFromString(&str, &data->iid);
            }
            else
                data->iid = (*index)->guid;

            data->nummethods = entity->u.ifaceps.nummethods;

            if (entity->u.ifaceps.tlib)
            {
                RtlInitUnicodeString(&str, entity->u.ifaceps.tlib);
                RtlGUIDFromString(&str, &data->tlbid);
            }
            else
                memset(&data->tlbid, 0, sizeof(data->tlbid));

            if (entity->u.ifaceps.base)
            {
                RtlInitUnicodeString(&str, entity->u.ifaceps.base);
                RtlGUIDFromString(&str, &data->base);
            }
            else
                memset(&data->base, 0, sizeof(data->base));

            data->name_len = name_len;
            data->name_offset = data->name_len ? sizeof(*data) : 0;

            /* name string */
            if (data->name_len)
            {
                WCHAR *ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
                memcpy(ptrW, entity->u.ifaceps.name, data->name_len);
                ptrW[data->name_len/sizeof(WCHAR)] = 0;
            }

            /* move to next record */
            (*index) += 1;
            *data_offset += sizeof(*data);
            if (data->name_len)
                *data_offset += aligned_string_len(data->name_len + sizeof(WCHAR));
        }
    }
}

static NTSTATUS build_ifaceps_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
{
    unsigned int i, j, total_len = 0, count = 0;
    struct guidsection_header *header;
    struct guid_index *index;
    ULONG data_offset;

    /* compute section length */
    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];

        get_ifaceps_datalen(&assembly->entities, &count, &total_len);
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
            get_ifaceps_datalen(&dll->entities, &count, &total_len);
        }
    }

    total_len += sizeof(*header);

    header = RtlAllocateHeap(GetProcessHeap(), 0, total_len);
    if (!header) return STATUS_NO_MEMORY;

    memset(header, 0, sizeof(*header));
    header->magic = GUIDSECTION_MAGIC;
    header->size  = sizeof(*header);
    header->count = count;
    header->index_offset = sizeof(*header);
    index = (struct guid_index*)((BYTE*)header + header->index_offset);
    data_offset = header->index_offset + count*sizeof(*index);

    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];

        add_ifaceps_record(header, &assembly->entities, &index, &data_offset, i + 1);
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
            add_ifaceps_record(header, &dll->entities, &index, &data_offset, i + 1);
        }
    }

    *section = header;

    return STATUS_SUCCESS;
}

static inline struct ifacepsredirect_data *get_ifaceps_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
{
    return (struct ifacepsredirect_data*)((BYTE*)actctx->ifaceps_section + index->data_offset);
}

static NTSTATUS find_cominterface_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
{
    struct ifacepsredirect_data *iface;
    struct guid_index *index = NULL;

    if (!(actctx->sections & IFACEREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;

    if (!actctx->ifaceps_section)
    {
        struct guidsection_header *section;

        NTSTATUS status = build_ifaceps_section(actctx, &section);
        if (status) return status;

        if (interlocked_cmpxchg_ptr((void**)&actctx->ifaceps_section, section, NULL))
            RtlFreeHeap(GetProcessHeap(), 0, section);
    }

    index = find_guid_index(actctx->ifaceps_section, guid);
    if (!index) return STATUS_SXS_KEY_NOT_FOUND;

    iface = get_ifaceps_data(actctx, index);

    data->ulDataFormatVersion = 1;
    data->lpData = iface;
    data->ulLength = iface->size + (iface->name_len ? iface->name_len + sizeof(WCHAR) : 0);
    data->lpSectionGlobalData = NULL;
    data->ulSectionGlobalDataLength = 0;
    data->lpSectionBase = actctx->ifaceps_section;
    data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->ifaceps_section );
    data->hActCtx = NULL;

    if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
        data->ulAssemblyRosterIndex = index->rosterindex;

    return STATUS_SUCCESS;
}

4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614
static NTSTATUS build_clr_surrogate_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
{
    unsigned int i, j, total_len = 0, count = 0;
    struct guidsection_header *header;
    struct clrsurrogate_data *data;
    struct guid_index *index;
    ULONG data_offset;

    /* compute section length */
    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
        for (j = 0; j < assembly->entities.num; j++)
        {
            struct entity *entity = &assembly->entities.base[j];
            if (entity->kind == ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES)
            {
                ULONG len;

                total_len += sizeof(*index) + sizeof(*data);
                len = strlenW(entity->u.clrsurrogate.name) + 1;
                if (entity->u.clrsurrogate.version)
                   len += strlenW(entity->u.clrsurrogate.version) + 1;
                total_len += aligned_string_len(len*sizeof(WCHAR));

                count++;
            }
        }
    }

    total_len += sizeof(*header);

    header = RtlAllocateHeap(GetProcessHeap(), 0, total_len);
    if (!header) return STATUS_NO_MEMORY;

    memset(header, 0, sizeof(*header));
    header->magic = GUIDSECTION_MAGIC;
    header->size  = sizeof(*header);
    header->count = count;
    header->index_offset = sizeof(*header);
    index = (struct guid_index*)((BYTE*)header + header->index_offset);
    data_offset = header->index_offset + count*sizeof(*index);

    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
        for (j = 0; j < assembly->entities.num; j++)
        {
            struct entity *entity = &assembly->entities.base[j];
            if (entity->kind == ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES)
            {
                ULONG version_len, name_len;
                UNICODE_STRING str;
                WCHAR *ptrW;

                if (entity->u.clrsurrogate.version)
                    version_len = strlenW(entity->u.clrsurrogate.version)*sizeof(WCHAR);
                else
                    version_len = 0;
                name_len = strlenW(entity->u.clrsurrogate.name)*sizeof(WCHAR);

                /* setup new index entry */
                RtlInitUnicodeString(&str, entity->u.clrsurrogate.clsid);
                RtlGUIDFromString(&str, &index->guid);

                index->data_offset = data_offset;
                index->data_len = sizeof(*data) + aligned_string_len(name_len + sizeof(WCHAR) + (version_len ? version_len + sizeof(WCHAR) : 0));
                index->rosterindex = i + 1;

                /* setup data */
                data = (struct clrsurrogate_data*)((BYTE*)header + index->data_offset);
                data->size = sizeof(*data);
                data->res = 0;
                data->clsid = index->guid;
                data->version_offset = version_len ? data->size : 0;
                data->version_len = version_len;
                data->name_offset = data->size + version_len;
                if (version_len)
                    data->name_offset += sizeof(WCHAR);
                data->name_len = name_len;

                /* surrogate name */
                ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
                memcpy(ptrW, entity->u.clrsurrogate.name, data->name_len);
                ptrW[data->name_len/sizeof(WCHAR)] = 0;

                /* runtime version */
                if (data->version_len)
                {
                    ptrW = (WCHAR*)((BYTE*)data + data->version_offset);
                    memcpy(ptrW, entity->u.clrsurrogate.version, data->version_len);
                    ptrW[data->version_len/sizeof(WCHAR)] = 0;
                }

                data_offset += index->data_offset;
                index++;
            }
        }
    }

    *section = header;

    return STATUS_SUCCESS;
}

static inline struct clrsurrogate_data *get_surrogate_data(ACTIVATION_CONTEXT *actctx, const struct guid_index *index)
{
    return (struct clrsurrogate_data*)((BYTE*)actctx->clrsurrogate_section + index->data_offset);
}

static NTSTATUS find_clr_surrogate(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
{
    struct clrsurrogate_data *surrogate;
    struct guid_index *index = NULL;

    if (!(actctx->sections & CLRSURROGATES_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;

    if (!actctx->clrsurrogate_section)
    {
        struct guidsection_header *section;

        NTSTATUS status = build_clr_surrogate_section(actctx, &section);
        if (status) return status;

        if (interlocked_cmpxchg_ptr((void**)&actctx->clrsurrogate_section, section, NULL))
            RtlFreeHeap(GetProcessHeap(), 0, section);
    }

    index = find_guid_index(actctx->clrsurrogate_section, guid);
    if (!index) return STATUS_SXS_KEY_NOT_FOUND;

    surrogate = get_surrogate_data(actctx, index);

    data->ulDataFormatVersion = 1;
    data->lpData = surrogate;
    /* full length includes string length with nulls */
    data->ulLength = surrogate->size + surrogate->name_len + sizeof(WCHAR);
    if (surrogate->version_len)
        data->ulLength += surrogate->version_len + sizeof(WCHAR);

    data->lpSectionGlobalData = NULL;
    data->ulSectionGlobalDataLength = 0;
    data->lpSectionBase = actctx->clrsurrogate_section;
    data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->clrsurrogate_section );
    data->hActCtx = NULL;

    if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
        data->ulAssemblyRosterIndex = index->rosterindex;

    return STATUS_SUCCESS;
}

4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807
static void get_progid_datalen(struct entity_array *entities, unsigned int *count, unsigned int *total_len)
{
    unsigned int i, j, single_len;

    single_len = sizeof(struct progidredirect_data) + sizeof(struct string_index) + sizeof(GUID);
    for (i = 0; i < entities->num; i++)
    {
        struct entity *entity = &entities->base[i];
        if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
        {
            if (entity->u.comclass.progid)
            {
                *total_len += single_len + aligned_string_len((strlenW(entity->u.comclass.progid)+1)*sizeof(WCHAR));
                *count += 1;
            }

            for (j = 0; j < entity->u.comclass.progids.num; j++)
                *total_len += aligned_string_len((strlenW(entity->u.comclass.progids.progids[j])+1)*sizeof(WCHAR));

            *total_len += single_len*entity->u.comclass.progids.num;
            *count += entity->u.comclass.progids.num;
        }
    }
}

static void write_progid_record(struct strsection_header *section, const WCHAR *progid, const GUID *alias,
    struct string_index **index, ULONG *data_offset, ULONG *global_offset, ULONG rosterindex)
{
    struct progidredirect_data *data;
    UNICODE_STRING str;
    GUID *guid_ptr;
    WCHAR *ptrW;

    /* setup new index entry */

    /* hash progid name */
    RtlInitUnicodeString(&str, progid);
    RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &(*index)->hash);

    (*index)->name_offset = *data_offset;
    (*index)->name_len = str.Length;
    (*index)->data_offset = (*index)->name_offset + aligned_string_len(str.MaximumLength);
    (*index)->data_len = sizeof(*data);
    (*index)->rosterindex = rosterindex;

    *data_offset += aligned_string_len(str.MaximumLength);

    /* setup data structure */
    data = (struct progidredirect_data*)((BYTE*)section + *data_offset);
    data->size = sizeof(*data);
    data->reserved = 0;
    data->clsid_offset = *global_offset;

    /* write progid string */
    ptrW = (WCHAR*)((BYTE*)section + (*index)->name_offset);
    memcpy(ptrW, progid, (*index)->name_len);
    ptrW[(*index)->name_len/sizeof(WCHAR)] = 0;

    /* write guid to global area */
    guid_ptr = (GUID*)((BYTE*)section + data->clsid_offset);
    *guid_ptr = *alias;

    /* to next entry */
    *global_offset += sizeof(GUID);
    *data_offset += data->size;
    (*index) += 1;
}

static void add_progid_record(ACTIVATION_CONTEXT* actctx, struct strsection_header *section, const struct entity_array *entities,
    struct string_index **index, ULONG *data_offset, ULONG *global_offset, ULONG rosterindex)
{
    unsigned int i, j;

    for (i = 0; i < entities->num; i++)
    {
        struct entity *entity = &entities->base[i];
        if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION)
        {
            const struct progids *progids = &entity->u.comclass.progids;
            struct comclassredirect_data *comclass;
            struct guid_index *guid_index;
            UNICODE_STRING str;
            GUID clsid;

            RtlInitUnicodeString(&str, entity->u.comclass.clsid);
            RtlGUIDFromString(&str, &clsid);

            guid_index = find_guid_index(actctx->comserver_section, &clsid);
            comclass = get_comclass_data(actctx, guid_index);

            if (entity->u.comclass.progid)
                write_progid_record(section, entity->u.comclass.progid, &comclass->alias,
                     index, data_offset, global_offset, rosterindex);

            for (j = 0; j < progids->num; j++)
                write_progid_record(section, progids->progids[j], &comclass->alias,
                     index, data_offset, global_offset, rosterindex);
        }
    }
}

static NTSTATUS build_progid_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
{
    unsigned int i, j, total_len = 0, count = 0;
    struct strsection_header *header;
    ULONG data_offset, global_offset;
    struct string_index *index;

    /* compute section length */
    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];

        get_progid_datalen(&assembly->entities, &count, &total_len);
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
            get_progid_datalen(&dll->entities, &count, &total_len);
        }
    }

    total_len += sizeof(*header);

    header = RtlAllocateHeap(GetProcessHeap(), 0, total_len);
    if (!header) return STATUS_NO_MEMORY;

    memset(header, 0, sizeof(*header));
    header->magic = STRSECTION_MAGIC;
    header->size  = sizeof(*header);
    header->count = count;
    header->global_offset = header->size;
    header->global_len = count*sizeof(GUID);
    header->index_offset = header->size + header->global_len;

    index = (struct string_index*)((BYTE*)header + header->index_offset);
    data_offset = header->index_offset + count*sizeof(*index);
    global_offset = header->global_offset;

    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];

        add_progid_record(actctx, header, &assembly->entities, &index, &data_offset, &global_offset, i + 1);
        for (j = 0; j < assembly->num_dlls; j++)
        {
            struct dll_redirect *dll = &assembly->dlls[j];
            add_progid_record(actctx, header, &dll->entities, &index, &data_offset, &global_offset, i + 1);
        }
    }

    *section = header;

    return STATUS_SUCCESS;
}

static inline struct progidredirect_data *get_progid_data(ACTIVATION_CONTEXT *actctx, const struct string_index *index)
{
    return (struct progidredirect_data*)((BYTE*)actctx->progid_section + index->data_offset);
}

static NTSTATUS find_progid_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
                                     PACTCTX_SECTION_KEYED_DATA data)
{
    struct progidredirect_data *progid;
    struct string_index *index;

    if (!(actctx->sections & PROGIDREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;

    if (!actctx->comserver_section)
    {
        struct guidsection_header *section;

        NTSTATUS status = build_comserver_section(actctx, &section);
        if (status) return status;

        if (interlocked_cmpxchg_ptr((void**)&actctx->comserver_section, section, NULL))
            RtlFreeHeap(GetProcessHeap(), 0, section);
    }

    if (!actctx->progid_section)
    {
        struct strsection_header *section;

        NTSTATUS status = build_progid_section(actctx, &section);
        if (status) return status;

        if (interlocked_cmpxchg_ptr((void**)&actctx->progid_section, section, NULL))
            RtlFreeHeap(GetProcessHeap(), 0, section);
    }

    index = find_string_index(actctx->progid_section, name);
    if (!index) return STATUS_SXS_KEY_NOT_FOUND;

4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823
    if (data)
    {
        progid = get_progid_data(actctx, index);

        data->ulDataFormatVersion = 1;
        data->lpData = progid;
        data->ulLength = progid->size;
        data->lpSectionGlobalData = (BYTE*)actctx->progid_section + actctx->progid_section->global_offset;
        data->ulSectionGlobalDataLength = actctx->progid_section->global_len;
        data->lpSectionBase = actctx->progid_section;
        data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->progid_section );
        data->hActCtx = NULL;

        if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
            data->ulAssemblyRosterIndex = index->rosterindex;
    }
4824 4825 4826 4827

    return STATUS_SUCCESS;
}

4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842
static NTSTATUS find_string(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
                            const UNICODE_STRING *section_name,
                            DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
{
    NTSTATUS status;

    switch (section_kind)
    {
    case ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION:
        status = find_dll_redirection(actctx, section_name, data);
        break;
    case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION:
        status = find_window_class(actctx, section_name, data);
        break;
    case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION:
4843 4844
        status = find_progid_redirection(actctx, section_name, data);
        break;
4845 4846 4847 4848 4849 4850 4851 4852 4853 4854
    case ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE:
        FIXME("Unsupported yet section_kind %x\n", section_kind);
        return STATUS_SXS_SECTION_NOT_FOUND;
    default:
        WARN("Unknown section_kind %x\n", section_kind);
        return STATUS_SXS_SECTION_NOT_FOUND;
    }

    if (status != STATUS_SUCCESS) return status;

4855
    if (data && (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX))
4856 4857 4858 4859 4860 4861 4862
    {
        actctx_addref(actctx);
        data->hActCtx = actctx;
    }
    return STATUS_SUCCESS;
}

4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873
static NTSTATUS find_guid(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
                          const GUID *guid, DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
{
    NTSTATUS status;

    switch (section_kind)
    {
    case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION:
        status = find_tlib_redirection(actctx, guid, data);
        break;
    case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
4874 4875
        status = find_comserver_redirection(actctx, guid, data);
        break;
4876
    case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
4877 4878 4879
        status = find_cominterface_redirection(actctx, guid, data);
        break;
    case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES:
4880 4881
        status = find_clr_surrogate(actctx, guid, data);
        break;
4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896
    default:
        WARN("Unknown section_kind %x\n", section_kind);
        return STATUS_SXS_SECTION_NOT_FOUND;
    }

    if (status != STATUS_SUCCESS) return status;

    if (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
    {
        actctx_addref(actctx);
        data->hActCtx = actctx;
    }
    return STATUS_SUCCESS;
}

4897
static const WCHAR *find_app_settings( ACTIVATION_CONTEXT *actctx, const WCHAR *settings, const WCHAR *ns )
4898 4899 4900 4901 4902 4903 4904 4905 4906 4907
{
    unsigned int i, j;

    for (i = 0; i < actctx->num_assemblies; i++)
    {
        struct assembly *assembly = &actctx->assemblies[i];
        for (j = 0; j < assembly->entities.num; j++)
        {
            struct entity *entity = &assembly->entities.base[j];
            if (entity->kind == ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS &&
4908 4909
                !strcmpW( entity->u.settings.name, settings ) &&
                !strcmpW( entity->u.settings.ns, ns ))
4910 4911 4912 4913 4914 4915
                return entity->u.settings.value;
        }
    }
    return NULL;
}

4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930
/* initialize the activation context for the current process */
void actctx_init(void)
{
    ACTCTXW ctx;
    HANDLE handle;

    ctx.cbSize   = sizeof(ctx);
    ctx.lpSource = NULL;
    ctx.dwFlags  = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
    ctx.hModule  = NtCurrentTeb()->Peb->ImageBaseAddress;
    ctx.lpResourceName = (LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID;

    if (!RtlCreateActivationContext( &handle, &ctx )) process_actctx = check_actctx(handle);
}

4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941

/***********************************************************************
 * RtlCreateActivationContext (NTDLL.@)
 *
 * Create an activation context.
 *
 * FIXME: function signature/prototype is wrong
 */
NTSTATUS WINAPI RtlCreateActivationContext( HANDLE *handle, const void *ptr )
{
    const ACTCTXW *pActCtx = ptr;  /* FIXME: not the right structure */
4942
    const WCHAR *directory = NULL;
4943
    ACTIVATION_CONTEXT *actctx;
4944 4945 4946 4947 4948
    UNICODE_STRING nameW;
    ULONG lang = 0;
    NTSTATUS status = STATUS_NO_MEMORY;
    HANDLE file = 0;
    struct actctx_loader acl;
4949 4950 4951

    TRACE("%p %08x\n", pActCtx, pActCtx ? pActCtx->dwFlags : 0);

4952
    if (!pActCtx || pActCtx->cbSize < sizeof(*pActCtx) ||
4953 4954 4955
        (pActCtx->dwFlags & ~ACTCTX_FLAGS_ALL))
        return STATUS_INVALID_PARAMETER;

4956
    if (!(actctx = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*actctx) )))
4957 4958 4959 4960
        return STATUS_NO_MEMORY;

    actctx->magic = ACTCTX_MAGIC;
    actctx->ref_count = 1;
4961 4962 4963 4964
    actctx->config.type = ACTIVATION_CONTEXT_PATH_TYPE_NONE;
    actctx->config.info = NULL;
    actctx->appdir.type = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
    if (pActCtx->dwFlags & ACTCTX_FLAG_APPLICATION_NAME_VALID)
4965 4966 4967 4968 4969 4970 4971
    {
        if (!(actctx->appdir.info = strdupW( pActCtx->lpApplicationName ))) goto error;
    }
    else
    {
        UNICODE_STRING dir;
        WCHAR *p;
4972
        HMODULE module;
4973

4974 4975 4976 4977
        if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID) module = pActCtx->hModule;
        else module = NtCurrentTeb()->Peb->ImageBaseAddress;

        if ((status = get_module_filename( module, &dir, 0 ))) goto error;
4978
        if ((p = strrchrW( dir.Buffer, '\\' ))) p[1] = 0;
4979 4980 4981 4982
        actctx->appdir.info = dir.Buffer;
    }

    nameW.Buffer = NULL;
4983 4984 4985 4986

    /* open file only if it's going to be used */
    if (pActCtx->lpSource && !((pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) &&
                               (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)))
4987
    {
4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009
        WCHAR *source = NULL;
        BOOLEAN ret;

        if (pActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID &&
            RtlDetermineDosPathNameType_U(pActCtx->lpSource) == RELATIVE_PATH)
        {
            DWORD dir_len, source_len;

            dir_len = strlenW(pActCtx->lpAssemblyDirectory);
            source_len = strlenW(pActCtx->lpSource);
            if (!(source = RtlAllocateHeap( GetProcessHeap(), 0, (dir_len+source_len+2)*sizeof(WCHAR))))
            {
                status = STATUS_NO_MEMORY;
                goto error;
            }

            memcpy(source, pActCtx->lpAssemblyDirectory, dir_len*sizeof(WCHAR));
            source[dir_len] = '\\';
            memcpy(source+dir_len+1, pActCtx->lpSource, (source_len+1)*sizeof(WCHAR));
        }

        ret = RtlDosPathNameToNtPathName_U(source ? source : pActCtx->lpSource, &nameW, NULL, NULL);
5010
        RtlFreeHeap( GetProcessHeap(), 0, source );
5011
        if (!ret)
5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029
        {
            status = STATUS_NO_SUCH_FILE;
            goto error;
        }
        status = open_nt_file( &file, &nameW );
        if (status)
        {
            RtlFreeUnicodeString( &nameW );
            goto error;
        }
    }

    acl.actctx = actctx;
    acl.dependencies = NULL;
    acl.num_dependencies = 0;
    acl.allocated_dependencies = 0;

    if (pActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID) lang = pActCtx->wLangId;
5030
    if (pActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) directory = pActCtx->lpAssemblyDirectory;
5031 5032 5033 5034 5035 5036

    if (pActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID)
    {
        /* if we have a resource it's a PE file */
        if (pActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID)
        {
5037
            status = get_manifest_in_module( &acl, NULL, NULL, directory, FALSE, pActCtx->hModule,
5038
                                             pActCtx->lpResourceName, lang );
5039
            if (status && status != STATUS_SXS_CANT_GEN_ACTCTX)
5040 5041
                status = get_manifest_in_associated_manifest( &acl, NULL, NULL, directory,
                                                              pActCtx->hModule, pActCtx->lpResourceName );
5042 5043 5044
        }
        else if (pActCtx->lpSource)
        {
5045
            status = get_manifest_in_pe_file( &acl, NULL, nameW.Buffer, directory, FALSE,
5046
                                              file, pActCtx->lpResourceName, lang );
5047
            if (status && status != STATUS_SXS_CANT_GEN_ACTCTX)
5048 5049
                status = get_manifest_in_associated_manifest( &acl, NULL, nameW.Buffer, directory,
                                                              NULL, pActCtx->lpResourceName );
5050 5051 5052 5053 5054
        }
        else status = STATUS_INVALID_PARAMETER;
    }
    else
    {
5055
        status = get_manifest_in_manifest_file( &acl, NULL, nameW.Buffer, directory, FALSE, file );
5056 5057 5058 5059
    }

    if (file) NtClose( file );
    RtlFreeUnicodeString( &nameW );
5060 5061 5062 5063

    if (status == STATUS_SUCCESS) status = parse_depend_manifests(&acl);
    free_depend_manifests( &acl );

5064 5065 5066
    if (status == STATUS_SUCCESS) *handle = actctx;
    else actctx_release( actctx );
    return status;
5067 5068

error:
5069 5070 5071
    if (file) NtClose( file );
    actctx_release( actctx );
    return status;
5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094
}


/***********************************************************************
 *		RtlAddRefActivationContext (NTDLL.@)
 */
void WINAPI RtlAddRefActivationContext( HANDLE handle )
{
    ACTIVATION_CONTEXT *actctx;

    if ((actctx = check_actctx( handle ))) actctx_addref( actctx );
}


/******************************************************************
 *		RtlReleaseActivationContext (NTDLL.@)
 */
void WINAPI RtlReleaseActivationContext( HANDLE handle )
{
    ACTIVATION_CONTEXT *actctx;

    if ((actctx = check_actctx( handle ))) actctx_release( actctx );
}
5095

5096 5097 5098 5099 5100 5101 5102 5103 5104 5105
/******************************************************************
 *              RtlZombifyActivationContext (NTDLL.@)
 *
 * FIXME: function prototype might be wrong
 */
NTSTATUS WINAPI RtlZombifyActivationContext( HANDLE handle )
{
    FIXME("%p: stub\n", handle);
    return STATUS_NOT_IMPLEMENTED;
}
5106 5107 5108 5109

/******************************************************************
 *		RtlActivateActivationContext (NTDLL.@)
 */
5110
NTSTATUS WINAPI RtlActivateActivationContext( ULONG unknown, HANDLE handle, PULONG_PTR cookie )
5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123
{
    RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;

    if (!(frame = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*frame) )))
        return STATUS_NO_MEMORY;

    frame->Previous = NtCurrentTeb()->ActivationContextStack.ActiveFrame;
    frame->ActivationContext = handle;
    frame->Flags = 0;
    NtCurrentTeb()->ActivationContextStack.ActiveFrame = frame;
    RtlAddRefActivationContext( handle );

    *cookie = (ULONG_PTR)frame;
5124
    TRACE( "%p cookie=%lx\n", handle, *cookie );
5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135
    return STATUS_SUCCESS;
}


/***********************************************************************
 *		RtlDeactivateActivationContext (NTDLL.@)
 */
void WINAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie )
{
    RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame, *top;

5136
    TRACE( "%x cookie=%lx\n", flags, cookie );
5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208

    /* find the right frame */
    top = NtCurrentTeb()->ActivationContextStack.ActiveFrame;
    for (frame = top; frame; frame = frame->Previous)
        if ((ULONG_PTR)frame == cookie) break;

    if (!frame)
        RtlRaiseStatus( STATUS_SXS_INVALID_DEACTIVATION );

    if (frame != top && !(flags & DEACTIVATE_ACTCTX_FLAG_FORCE_EARLY_DEACTIVATION))
        RtlRaiseStatus( STATUS_SXS_EARLY_DEACTIVATION );

    /* pop everything up to and including frame */
    NtCurrentTeb()->ActivationContextStack.ActiveFrame = frame->Previous;

    while (top != NtCurrentTeb()->ActivationContextStack.ActiveFrame)
    {
        frame = top->Previous;
        RtlReleaseActivationContext( top->ActivationContext );
        RtlFreeHeap( GetProcessHeap(), 0, top );
        top = frame;
    }
}


/******************************************************************
 *		RtlFreeThreadActivationContextStack (NTDLL.@)
 */
void WINAPI RtlFreeThreadActivationContextStack(void)
{
    RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;

    frame = NtCurrentTeb()->ActivationContextStack.ActiveFrame;
    while (frame)
    {
        RTL_ACTIVATION_CONTEXT_STACK_FRAME *prev = frame->Previous;
        RtlReleaseActivationContext( frame->ActivationContext );
        RtlFreeHeap( GetProcessHeap(), 0, frame );
        frame = prev;
    }
    NtCurrentTeb()->ActivationContextStack.ActiveFrame = NULL;
}


/******************************************************************
 *		RtlGetActiveActivationContext (NTDLL.@)
 */
NTSTATUS WINAPI RtlGetActiveActivationContext( HANDLE *handle )
{
    if (NtCurrentTeb()->ActivationContextStack.ActiveFrame)
    {
        *handle = NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext;
        RtlAddRefActivationContext( *handle );
    }
    else
        *handle = 0;

    return STATUS_SUCCESS;
}


/******************************************************************
 *		RtlIsActivationContextActive (NTDLL.@)
 */
BOOLEAN WINAPI RtlIsActivationContextActive( HANDLE handle )
{
    RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;

    for (frame = NtCurrentTeb()->ActivationContextStack.ActiveFrame; frame; frame = frame->Previous)
        if (frame->ActivationContext == handle) return TRUE;
    return FALSE;
}
5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220


/***********************************************************************
 *		RtlQueryInformationActivationContext (NTDLL.@)
 *
 * Get information about an activation context.
 * FIXME: function signature/prototype may be wrong
 */
NTSTATUS WINAPI RtlQueryInformationActivationContext( ULONG flags, HANDLE handle, PVOID subinst,
                                                      ULONG class, PVOID buffer,
                                                      SIZE_T bufsize, SIZE_T *retlen )
{
5221
    ACTIVATION_CONTEXT *actctx;
5222 5223 5224 5225 5226
    NTSTATUS status;

    TRACE("%08x %p %p %u %p %ld %p\n", flags, handle,
          subinst, class, buffer, bufsize, retlen);

5227 5228
    if (retlen) *retlen = 0;
    if ((status = find_query_actctx( &handle, flags, class ))) return status;
5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245

    switch (class)
    {
    case ActivationContextBasicInformation:
        {
            ACTIVATION_CONTEXT_BASIC_INFORMATION *info = buffer;

            if (retlen) *retlen = sizeof(*info);
            if (!info || bufsize < sizeof(*info)) return STATUS_BUFFER_TOO_SMALL;

            info->hActCtx = handle;
            info->dwFlags = 0;  /* FIXME */
            if (!(flags & QUERY_ACTCTX_FLAG_NO_ADDREF)) RtlAddRefActivationContext( handle );
        }
        break;

    case ActivationContextDetailedInformation:
5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297
        {
            ACTIVATION_CONTEXT_DETAILED_INFORMATION *acdi = buffer;
            struct assembly *assembly = NULL;
            SIZE_T len, manifest_len = 0, config_len = 0, appdir_len = 0;
            LPWSTR ptr;

            if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;

            if (actctx->num_assemblies) assembly = actctx->assemblies;

            if (assembly && assembly->manifest.info)
                manifest_len = strlenW(assembly->manifest.info) + 1;
            if (actctx->config.info) config_len = strlenW(actctx->config.info) + 1;
            if (actctx->appdir.info) appdir_len = strlenW(actctx->appdir.info) + 1;
            len = sizeof(*acdi) + (manifest_len + config_len + appdir_len) * sizeof(WCHAR);

            if (retlen) *retlen = len;
            if (!buffer || bufsize < len) return STATUS_BUFFER_TOO_SMALL;

            acdi->dwFlags = 0;
            acdi->ulFormatVersion = assembly ? 1 : 0; /* FIXME */
            acdi->ulAssemblyCount = actctx->num_assemblies;
            acdi->ulRootManifestPathType = assembly ? assembly->manifest.type : 0 /* FIXME */;
            acdi->ulRootManifestPathChars = assembly && assembly->manifest.info ? manifest_len - 1 : 0;
            acdi->ulRootConfigurationPathType = actctx->config.type;
            acdi->ulRootConfigurationPathChars = actctx->config.info ? config_len - 1 : 0;
            acdi->ulAppDirPathType = actctx->appdir.type;
            acdi->ulAppDirPathChars = actctx->appdir.info ? appdir_len - 1 : 0;
            ptr = (LPWSTR)(acdi + 1);
            if (manifest_len)
            {
                acdi->lpRootManifestPath = ptr;
                memcpy(ptr, assembly->manifest.info, manifest_len * sizeof(WCHAR));
                ptr += manifest_len;
            }
            else acdi->lpRootManifestPath = NULL;
            if (config_len)
            {
                acdi->lpRootConfigurationPath = ptr;
                memcpy(ptr, actctx->config.info, config_len * sizeof(WCHAR));
                ptr += config_len;
            }
            else acdi->lpRootConfigurationPath = NULL;
            if (appdir_len)
            {
                acdi->lpAppDirPath = ptr;
                memcpy(ptr, actctx->appdir.info, appdir_len * sizeof(WCHAR));
            }
            else acdi->lpAppDirPath = NULL;
        }
        break;

5298
    case AssemblyDetailedInformationInActivationContext:
5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318
        {
            ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *afdi = buffer;
            struct assembly *assembly;
            WCHAR *assembly_id;
            DWORD index;
            SIZE_T len, id_len = 0, ad_len = 0, path_len = 0;
            LPWSTR ptr;

            if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
            if (!subinst) return STATUS_INVALID_PARAMETER;

            index = *(DWORD*)subinst;
            if (!index || index > actctx->num_assemblies) return STATUS_INVALID_PARAMETER;

            assembly = &actctx->assemblies[index - 1];

            if (!(assembly_id = build_assembly_id( &assembly->id ))) return STATUS_NO_MEMORY;
            id_len = strlenW(assembly_id) + 1;
            if (assembly->directory) ad_len = strlenW(assembly->directory) + 1;

5319 5320
            if (assembly->manifest.info &&
                (assembly->type == ASSEMBLY_MANIFEST || assembly->type == ASSEMBLY_SHARED_MANIFEST))
5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331
                path_len  = strlenW(assembly->manifest.info) + 1;

            len = sizeof(*afdi) + (id_len + ad_len + path_len) * sizeof(WCHAR);

            if (retlen) *retlen = len;
            if (!buffer || bufsize < len)
            {
                RtlFreeHeap( GetProcessHeap(), 0, assembly_id );
                return STATUS_BUFFER_TOO_SMALL;
            }

5332
            afdi->ulFlags = 0;  /* FIXME */
5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366
            afdi->ulEncodedAssemblyIdentityLength = (id_len - 1) * sizeof(WCHAR);
            afdi->ulManifestPathType = assembly->manifest.type;
            afdi->ulManifestPathLength = assembly->manifest.info ? (path_len - 1) * sizeof(WCHAR) : 0;
            /* FIXME afdi->liManifestLastWriteTime = 0; */
            afdi->ulPolicyPathType = ACTIVATION_CONTEXT_PATH_TYPE_NONE; /* FIXME */
            afdi->ulPolicyPathLength = 0;
            /* FIXME afdi->liPolicyLastWriteTime = 0; */
            afdi->ulMetadataSatelliteRosterIndex = 0; /* FIXME */
            afdi->ulManifestVersionMajor = 1;
            afdi->ulManifestVersionMinor = 0;
            afdi->ulPolicyVersionMajor = 0; /* FIXME */
            afdi->ulPolicyVersionMinor = 0; /* FIXME */
            afdi->ulAssemblyDirectoryNameLength = ad_len ? (ad_len - 1) * sizeof(WCHAR) : 0;
            ptr = (LPWSTR)(afdi + 1);
            afdi->lpAssemblyEncodedAssemblyIdentity = ptr;
            memcpy( ptr, assembly_id, id_len * sizeof(WCHAR) );
            ptr += id_len;
            if (path_len)
            {
                afdi->lpAssemblyManifestPath = ptr;
                memcpy(ptr, assembly->manifest.info, path_len * sizeof(WCHAR));
                ptr += path_len;
            } else afdi->lpAssemblyManifestPath = NULL;
            afdi->lpAssemblyPolicyPath = NULL; /* FIXME */
            if (ad_len)
            {
                afdi->lpAssemblyDirectoryName = ptr;
                memcpy(ptr, assembly->directory, ad_len * sizeof(WCHAR));
            }
            else afdi->lpAssemblyDirectoryName = NULL;
            RtlFreeHeap( GetProcessHeap(), 0, assembly_id );
        }
        break;

5367
    case FileInformationInAssemblyOfAssemblyInActivationContext:
5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408
        {
            const ACTIVATION_CONTEXT_QUERY_INDEX *acqi = subinst;
            ASSEMBLY_FILE_DETAILED_INFORMATION *afdi = buffer;
            struct assembly *assembly;
            struct dll_redirect *dll;
            SIZE_T len, dll_len = 0;
            LPWSTR ptr;

            if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
            if (!acqi) return STATUS_INVALID_PARAMETER;

            if (acqi->ulAssemblyIndex >= actctx->num_assemblies)
                return STATUS_INVALID_PARAMETER;
            assembly = &actctx->assemblies[acqi->ulAssemblyIndex];

            if (acqi->ulFileIndexInAssembly >= assembly->num_dlls)
                return STATUS_INVALID_PARAMETER;
            dll = &assembly->dlls[acqi->ulFileIndexInAssembly];

            if (dll->name) dll_len = strlenW(dll->name) + 1;
            len = sizeof(*afdi) + dll_len * sizeof(WCHAR);

            if (!buffer || bufsize < len)
            {
                if (retlen) *retlen = len;
                return STATUS_BUFFER_TOO_SMALL;
            }
            if (retlen) *retlen = 0; /* yes that's what native does !! */
            afdi->ulFlags = ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION;
            afdi->ulFilenameLength = dll_len ? (dll_len - 1) * sizeof(WCHAR) : 0;
            afdi->ulPathLength = 0; /* FIXME */
            ptr = (LPWSTR)(afdi + 1);
            if (dll_len)
            {
                afdi->lpFileName = ptr;
                memcpy( ptr, dll->name, dll_len * sizeof(WCHAR) );
            } else afdi->lpFileName = NULL;
            afdi->lpFilePath = NULL; /* FIXME */
        }
        break;

5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436
    case CompatibilityInformationInActivationContext:
        {
            /*ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*/DWORD *acci = buffer;
            COMPATIBILITY_CONTEXT_ELEMENT *elements;
            struct assembly *assembly = NULL;
            ULONG num_compat_contexts = 0, n;
            SIZE_T len;

            if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;

            if (actctx->num_assemblies) assembly = actctx->assemblies;

            if (assembly)
                num_compat_contexts = assembly->num_compat_contexts;
            len = sizeof(*acci) + num_compat_contexts * sizeof(COMPATIBILITY_CONTEXT_ELEMENT);

            if (retlen) *retlen = len;
            if (!buffer || bufsize < len) return STATUS_BUFFER_TOO_SMALL;

            *acci = num_compat_contexts;
            elements = (COMPATIBILITY_CONTEXT_ELEMENT*)(acci + 1);
            for (n = 0; n < num_compat_contexts; ++n)
            {
                elements[n] = assembly->compat_contexts[n];
            }
        }
        break;

5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457
    case RunlevelInformationInActivationContext:
        {
            ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION *acrli = buffer;
            struct assembly *assembly;
            SIZE_T len;

            if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;

            len = sizeof(*acrli);
            if (retlen) *retlen = len;
            if (!buffer || bufsize < len)
                return STATUS_BUFFER_TOO_SMALL;

            assembly = actctx->assemblies;

            acrli->ulFlags  = 0;
            acrli->RunLevel = assembly ? assembly->run_level : ACTCTX_RUN_LEVEL_UNSPECIFIED;
            acrli->UiAccess = assembly ? assembly->ui_access : 0;
        }
        break;

5458 5459 5460 5461 5462 5463
    default:
        FIXME( "class %u not implemented\n", class );
        return STATUS_NOT_IMPLEMENTED;
    }
    return STATUS_SUCCESS;
}
5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489

/***********************************************************************
 *		RtlFindActivationContextSectionString (NTDLL.@)
 *
 * Find information about a string in an activation context.
 * FIXME: function signature/prototype may be wrong
 */
NTSTATUS WINAPI RtlFindActivationContextSectionString( ULONG flags, const GUID *guid, ULONG section_kind,
                                                       const UNICODE_STRING *section_name, PVOID ptr )
{
    PACTCTX_SECTION_KEYED_DATA data = ptr;
    NTSTATUS status = STATUS_SXS_KEY_NOT_FOUND;

    TRACE("%08x %s %u %s %p\n", flags, debugstr_guid(guid), section_kind,
          debugstr_us(section_name), data);

    if (guid)
    {
        FIXME("expected guid == NULL\n");
        return STATUS_INVALID_PARAMETER;
    }
    if (flags & ~FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
    {
        FIXME("unknown flags %08x\n", flags);
        return STATUS_INVALID_PARAMETER;
    }
5490
    if ((data && data->cbSize < offsetof(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex)) ||
5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507
        !section_name || !section_name->Buffer)
    {
        WARN("invalid parameter\n");
        return STATUS_INVALID_PARAMETER;
    }

    if (NtCurrentTeb()->ActivationContextStack.ActiveFrame)
    {
        ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext);
        if (actctx) status = find_string( actctx, section_kind, section_name, flags, data );
    }

    if (status != STATUS_SUCCESS)
        status = find_string( process_actctx, section_kind, section_name, flags, data );

    return status;
}
5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518

/***********************************************************************
 *		RtlFindActivationContextSectionGuid (NTDLL.@)
 *
 * Find information about a GUID in an activation context.
 * FIXME: function signature/prototype may be wrong
 */
NTSTATUS WINAPI RtlFindActivationContextSectionGuid( ULONG flags, const GUID *extguid, ULONG section_kind,
                                                     const GUID *guid, void *ptr )
{
    ACTCTX_SECTION_KEYED_DATA *data = ptr;
5519
    NTSTATUS status = STATUS_SXS_KEY_NOT_FOUND;
5520

5521
    TRACE("%08x %s %u %s %p\n", flags, debugstr_guid(extguid), section_kind, debugstr_guid(guid), data);
5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537

    if (extguid)
    {
        FIXME("expected extguid == NULL\n");
        return STATUS_INVALID_PARAMETER;
    }

    if (flags & ~FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX)
    {
        FIXME("unknown flags %08x\n", flags);
        return STATUS_INVALID_PARAMETER;
    }

    if (!data || data->cbSize < FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) || !guid)
        return STATUS_INVALID_PARAMETER;

5538 5539 5540 5541 5542 5543 5544 5545 5546 5547
    if (NtCurrentTeb()->ActivationContextStack.ActiveFrame)
    {
        ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext);
        if (actctx) status = find_guid( actctx, section_kind, guid, flags, data );
    }

    if (status != STATUS_SUCCESS)
        status = find_guid( process_actctx, section_kind, guid, flags, data );

    return status;
5548
}
5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566


/***********************************************************************
 *		RtlQueryActivationContextApplicationSettings (NTDLL.@)
 */
NTSTATUS WINAPI RtlQueryActivationContextApplicationSettings( DWORD flags, HANDLE handle, const WCHAR *ns,
                                                              const WCHAR *settings, WCHAR *buffer,
                                                              SIZE_T size, SIZE_T *written )
{
    ACTIVATION_CONTEXT *actctx = check_actctx( handle );
    const WCHAR *res;

    if (flags)
    {
        WARN( "unknown flags %08x\n", flags );
        return STATUS_INVALID_PARAMETER;
    }

5567
    if (ns)
5568
    {
5569 5570 5571 5572 5573
        if (strcmpW( ns, windowsSettings2005NSW ) &&
            strcmpW( ns, windowsSettings2011NSW ) &&
            strcmpW( ns, windowsSettings2016NSW ) &&
            strcmpW( ns, windowsSettings2017NSW ))
            return STATUS_INVALID_PARAMETER;
5574
    }
5575
    else ns = windowsSettings2005NSW;
5576 5577 5578 5579

    if (!handle) handle = process_actctx;
    if (!(actctx = check_actctx( handle ))) return STATUS_INVALID_PARAMETER;

5580
    if (!(res = find_app_settings( actctx, settings, ns ))) return STATUS_SXS_KEY_NOT_FOUND;
5581 5582 5583 5584 5585 5586

    if (written) *written = strlenW(res) + 1;
    if (size < strlenW(res)) return STATUS_BUFFER_TOO_SMALL;
    strcpyW( buffer, res );
    return STATUS_SUCCESS;
}