package.c 76.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Implementation of the Microsoft Installer (msi.dll)
 *
 * Copyright 2004 Aric Stewart for CodeWeavers
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21
 */

#define NONAMELESSUNION
22
#define NONAMELESSSTRUCT
23
#define COBJMACROS
24 25 26 27 28 29 30

#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
#include "shlwapi.h"
31
#include "wingdi.h"
32 33 34 35 36 37
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "objidl.h"
#include "wincrypt.h"
#include "winuser.h"
38
#include "wininet.h"
39
#include "winver.h"
40
#include "urlmon.h"
41 42 43
#include "shlobj.h"
#include "wine/unicode.h"
#include "objbase.h"
44
#include "msidefs.h"
45
#include "sddl.h"
46

47
#include "msipriv.h"
48
#include "msiserver.h"
49

50 51
WINE_DEFAULT_DEBUG_CHANNEL(msi);

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
static void remove_tracked_tempfiles( MSIPACKAGE *package )
{
    struct list *item, *cursor;

    LIST_FOR_EACH_SAFE( item, cursor, &package->tempfiles )
    {
        MSITEMPFILE *temp = LIST_ENTRY( item, MSITEMPFILE, entry );

        list_remove( &temp->entry );
        TRACE("deleting temp file %s\n", debugstr_w( temp->Path ));
        if (!DeleteFileW( temp->Path ))
            ERR("failed to delete %s\n", debugstr_w( temp->Path ));
        msi_free( temp->Path );
        msi_free( temp );
    }
}

static void free_feature( MSIFEATURE *feature )
{
    struct list *item, *cursor;

    LIST_FOR_EACH_SAFE( item, cursor, &feature->Children )
    {
        FeatureList *fl = LIST_ENTRY( item, FeatureList, entry );
        list_remove( &fl->entry );
        msi_free( fl );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &feature->Components )
    {
        ComponentList *cl = LIST_ENTRY( item, ComponentList, entry );
        list_remove( &cl->entry );
        msi_free( cl );
    }
    msi_free( feature->Feature );
    msi_free( feature->Feature_Parent );
    msi_free( feature->Directory );
    msi_free( feature->Description );
    msi_free( feature->Title );
    msi_free( feature );
}

static void free_extension( MSIEXTENSION *ext )
{
    struct list *item, *cursor;

    LIST_FOR_EACH_SAFE( item, cursor, &ext->verbs )
    {
        MSIVERB *verb = LIST_ENTRY( item, MSIVERB, entry );

        list_remove( &verb->entry );
        msi_free( verb->Verb );
        msi_free( verb->Command );
        msi_free( verb->Argument );
        msi_free( verb );
    }

    msi_free( ext->Extension );
    msi_free( ext->ProgIDText );
    msi_free( ext );
}

static void free_package_structures( MSIPACKAGE *package )
{
    INT i;
    struct list *item, *cursor;

    TRACE("Freeing package action data\n");

    remove_tracked_tempfiles(package);

    LIST_FOR_EACH_SAFE( item, cursor, &package->features )
    {
        MSIFEATURE *feature = LIST_ENTRY( item, MSIFEATURE, entry );
        list_remove( &feature->entry );
        free_feature( feature );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &package->folders )
    {
        MSIFOLDER *folder = LIST_ENTRY( item, MSIFOLDER, entry );

        list_remove( &folder->entry );
        msi_free( folder->Parent );
        msi_free( folder->Directory );
        msi_free( folder->TargetDefault );
        msi_free( folder->SourceLongPath );
        msi_free( folder->SourceShortPath );
        msi_free( folder->ResolvedTarget );
        msi_free( folder->ResolvedSource );
        msi_free( folder->Property );
        msi_free( folder );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &package->components )
    {
        MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry );

        list_remove( &comp->entry );
        msi_free( comp->Component );
        msi_free( comp->ComponentId );
        msi_free( comp->Directory );
        msi_free( comp->Condition );
        msi_free( comp->KeyPath );
        msi_free( comp->FullKeypath );
        msi_free( comp );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &package->files )
    {
        MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry );

        list_remove( &file->entry );
        msi_free( file->File );
        msi_free( file->FileName );
        msi_free( file->ShortName );
        msi_free( file->LongName );
        msi_free( file->Version );
        msi_free( file->Language );
        msi_free( file->TargetPath );
        msi_free( file );
    }

    /* clean up extension, progid, class and verb structures */
    LIST_FOR_EACH_SAFE( item, cursor, &package->classes )
    {
        MSICLASS *cls = LIST_ENTRY( item, MSICLASS, entry );

        list_remove( &cls->entry );
        msi_free( cls->clsid );
        msi_free( cls->Context );
        msi_free( cls->Description );
        msi_free( cls->FileTypeMask );
        msi_free( cls->IconPath );
        msi_free( cls->DefInprocHandler );
        msi_free( cls->DefInprocHandler32 );
        msi_free( cls->Argument );
        msi_free( cls->ProgIDText );
        msi_free( cls );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &package->extensions )
    {
        MSIEXTENSION *ext = LIST_ENTRY( item, MSIEXTENSION, entry );

        list_remove( &ext->entry );
        free_extension( ext );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &package->progids )
    {
        MSIPROGID *progid = LIST_ENTRY( item, MSIPROGID, entry );

        list_remove( &progid->entry );
        msi_free( progid->ProgID );
        msi_free( progid->Description );
        msi_free( progid->IconPath );
        msi_free( progid );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &package->mimes )
    {
        MSIMIME *mt = LIST_ENTRY( item, MSIMIME, entry );

        list_remove( &mt->entry );
217
        msi_free( mt->suffix );
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
        msi_free( mt->clsid );
        msi_free( mt->ContentType );
        msi_free( mt );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &package->appids )
    {
        MSIAPPID *appid = LIST_ENTRY( item, MSIAPPID, entry );

        list_remove( &appid->entry );
        msi_free( appid->AppID );
        msi_free( appid->RemoteServerName );
        msi_free( appid->LocalServer );
        msi_free( appid->ServiceParameters );
        msi_free( appid->DllSurrogate );
        msi_free( appid );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_info )
    {
        MSISOURCELISTINFO *info = LIST_ENTRY( item, MSISOURCELISTINFO, entry );

        list_remove( &info->entry );
        msi_free( info->value );
        msi_free( info );
    }

    LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_media )
    {
        MSIMEDIADISK *info = LIST_ENTRY( item, MSIMEDIADISK, entry );

        list_remove( &info->entry );
        msi_free( info->volume_label );
        msi_free( info->disk_prompt );
        msi_free( info );
    }

    if (package->script)
    {
        for (i = 0; i < TOTAL_SCRIPTS; i++)
            msi_free_action_script( package, i );

        for (i = 0; i < package->script->UniqueActionsCount; i++)
            msi_free( package->script->UniqueActions[i] );

        msi_free( package->script->UniqueActions );
        msi_free( package->script );
    }

267
    LIST_FOR_EACH_SAFE( item, cursor, &package->patches )
268
    {
269 270 271 272 273
        MSIPATCHINFO *patch = LIST_ENTRY( item, MSIPATCHINFO, entry );

        list_remove( &patch->entry );
        msi_free( patch->patchcode );
        msi_free( patch->transforms );
274
        msi_free( patch->localfile );
275
        msi_free( patch );
276 277 278 279 280 281 282
    }

    msi_free( package->BaseURL );
    msi_free( package->PackagePath );
    msi_free( package->ProductCode );
    msi_free( package->ActionFormat );
    msi_free( package->LastAction );
283
    msi_free( package->langids );
284 285 286 287 288

    /* cleanup control event subscriptions */
    ControlEvent_CleanupSubscriptions( package );
}

289
static void MSI_FreePackage( MSIOBJECTHDR *arg)
290
{
291
    MSIPACKAGE *package= (MSIPACKAGE*) arg;
292

293 294
    if( package->dialog )
        msi_dialog_destroy( package->dialog );
295

296
    msiobj_release( &package->db->hdr );
297
    free_package_structures(package);
298 299
}

300
static UINT create_temp_property_table(MSIPACKAGE *package)
301
{
302
    MSIQUERY *view = NULL;
303
    UINT rc;
304

305
    static const WCHAR CreateSql[] = {
306 307 308 309 310 311 312 313 314
       'C','R','E','A','T','E',' ','T','A','B','L','E',' ',
       '`','_','P','r','o','p','e','r','t','y','`',' ','(',' ',
       '`','_','P','r','o','p','e','r','t','y','`',' ',
       'C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U','L','L',' ',
       'T','E','M','P','O','R','A','R','Y',',',' ',
       '`','V','a','l','u','e','`',' ','C','H','A','R','(','9','8',')',' ',
       'N','O','T',' ','N','U','L','L',' ','T','E','M','P','O','R','A','R','Y',
       ' ','P','R','I','M','A','R','Y',' ','K','E','Y',' ',
       '`','_','P','r','o','p','e','r','t','y','`',')',' ','H','O','L','D',0};
315 316 317 318 319 320 321 322 323 324 325 326 327

    rc = MSI_DatabaseOpenViewW(package->db, CreateSql, &view);
    if (rc != ERROR_SUCCESS)
        return rc;

    rc = MSI_ViewExecute(view, 0);
    MSI_ViewClose(view);
    msiobj_release(&view->hdr);
    return rc;
}

UINT msi_clone_properties(MSIPACKAGE *package)
{
328
    MSIQUERY *view_select = NULL;
329 330
    UINT rc;

331
    static const WCHAR query_select[] = {
332 333
       'S','E','L','E','C','T',' ','*',' ',
       'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0};
334
    static const WCHAR query_insert[] = {
335 336 337 338 339
       'I','N','S','E','R','T',' ','i','n','t','o',' ',
       '`','_','P','r','o','p','e','r','t','y','`',' ',
       '(','`','_','P','r','o','p','e','r','t','y','`',',',
       '`','V','a','l','u','e','`',')',' ',
       'V','A','L','U','E','S',' ','(','?',',','?',')',0};
340 341 342 343
    static const WCHAR query_update[] = {
        'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ',
        'S','E','T',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ',
        'W','H','E','R','E',' ','`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','?',0};
344

345
    rc = MSI_DatabaseOpenViewW( package->db, query_select, &view_select );
346 347
    if (rc != ERROR_SUCCESS)
        return rc;
348

349
    rc = MSI_ViewExecute( view_select, 0 );
350
    if (rc != ERROR_SUCCESS)
351
    {
352 353
        MSI_ViewClose( view_select );
        msiobj_release( &view_select->hdr );
354
        return rc;
355
    }
356 357 358

    while (1)
    {
359 360
        MSIQUERY *view_insert, *view_update;
        MSIRECORD *rec_select;
361

362
        rc = MSI_ViewFetch( view_select, &rec_select );
363 364 365
        if (rc != ERROR_SUCCESS)
            break;

366
        rc = MSI_DatabaseOpenViewW( package->db, query_insert, &view_insert );
367 368
        if (rc != ERROR_SUCCESS)
        {
369
            msiobj_release( &rec_select->hdr );
370
            continue;
371
        }
372

373 374 375 376 377 378
        rc = MSI_ViewExecute( view_insert, rec_select );
        MSI_ViewClose( view_insert );
        msiobj_release( &view_insert->hdr );
        if (rc != ERROR_SUCCESS)
        {
            MSIRECORD *rec_update;
379

380 381 382 383 384 385 386 387 388
            TRACE("insert failed, trying update\n");

            rc = MSI_DatabaseOpenViewW( package->db, query_update, &view_update );
            if (rc != ERROR_SUCCESS)
            {
                WARN("open view failed %u\n", rc);
                msiobj_release( &rec_select->hdr );
                continue;
            }
389

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
            rec_update = MSI_CreateRecord( 2 );
            MSI_RecordCopyField( rec_select, 1, rec_update, 2 );
            MSI_RecordCopyField( rec_select, 2, rec_update, 1 );
            rc = MSI_ViewExecute( view_update, rec_update );
            if (rc != ERROR_SUCCESS)
                WARN("update failed %u\n", rc);

            MSI_ViewClose( view_update );
            msiobj_release( &view_update->hdr );
            msiobj_release( &rec_update->hdr );
        }

        msiobj_release( &rec_select->hdr );
    }

    MSI_ViewClose( view_select );
    msiobj_release( &view_select->hdr );
407
    return rc;
408 409
}

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
/*
 * set_installed_prop
 *
 * Sets the "Installed" property to indicate that
 *  the product is installed for the current user.
 */
static UINT set_installed_prop( MSIPACKAGE *package )
{
    HKEY hkey = 0;
    UINT r;

    r = MSIREG_OpenUninstallKey( package->ProductCode, &hkey, FALSE );
    if (r == ERROR_SUCCESS)
    {
        RegCloseKey( hkey );
425
        msi_set_property( package->db, szInstalled, szOne );
426 427 428 429 430
    }

    return r;
}

431 432 433 434
static UINT set_user_sid_prop( MSIPACKAGE *package )
{
    SID_NAME_USE use;
    LPWSTR user_name;
435
    LPWSTR sid_str = NULL, dom = NULL;
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
    DWORD size, dom_size;
    PSID psid = NULL;
    UINT r = ERROR_FUNCTION_FAILED;

    size = 0;
    GetUserNameW( NULL, &size );

    user_name = msi_alloc( (size + 1) * sizeof(WCHAR) );
    if (!user_name)
        return ERROR_OUTOFMEMORY;

    if (!GetUserNameW( user_name, &size ))
        goto done;

    size = 0;
    dom_size = 0;
    LookupAccountNameW( NULL, user_name, NULL, &size, NULL, &dom_size, &use );

    psid = msi_alloc( size );
455
    dom = msi_alloc( dom_size*sizeof (WCHAR) );
456 457 458 459 460 461 462 463 464 465 466 467
    if (!psid || !dom)
    {
        r = ERROR_OUTOFMEMORY;
        goto done;
    }

    if (!LookupAccountNameW( NULL, user_name, psid, &size, dom, &dom_size, &use ))
        goto done;

    if (!ConvertSidToStringSidW( psid, &sid_str ))
        goto done;

468
    r = msi_set_property( package->db, szUserSID, sid_str );
469 470 471 472 473 474 475 476 477 478

done:
    LocalFree( sid_str );
    msi_free( dom );
    msi_free( psid );
    msi_free( user_name );

    return r;
}

479 480 481 482
static LPWSTR get_fusion_filename(MSIPACKAGE *package)
{
    HKEY netsetup;
    LONG res;
483
    LPWSTR file = NULL;
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
    DWORD index = 0, size;
    WCHAR ver[MAX_PATH];
    WCHAR name[MAX_PATH];
    WCHAR windir[MAX_PATH];

    static const WCHAR fusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
    static const WCHAR sub[] = {
        'S','o','f','t','w','a','r','e','\\',
        'M','i','c','r','o','s','o','f','t','\\',
        'N','E','T',' ','F','r','a','m','e','w','o','r','k',' ','S','e','t','u','p','\\',
        'N','D','P',0
    };
    static const WCHAR subdir[] = {
        'M','i','c','r','o','s','o','f','t','.','N','E','T','\\',
        'F','r','a','m','e','w','o','r','k','\\',0
    };

    res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, sub, 0, KEY_ENUMERATE_SUB_KEYS, &netsetup);
    if (res != ERROR_SUCCESS)
        return NULL;

505 506
    GetWindowsDirectoryW(windir, MAX_PATH);

507 508 509 510 511
    ver[0] = '\0';
    size = MAX_PATH;
    while (RegEnumKeyExW(netsetup, index, name, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
    {
        index++;
512 513

        /* verify existence of fusion.dll .Net 3.0 does not install a new one */
514
        if (lstrcmpW(ver, name) < 0)
515 516 517 518 519 520 521
        {
            LPWSTR check;
            size = lstrlenW(windir) + lstrlenW(subdir) + lstrlenW(name) +lstrlenW(fusion) + 3;
            check = msi_alloc(size * sizeof(WCHAR));

            if (!check)
            {
522
                msi_free(file);
523 524 525 526
                return NULL;
            }

            lstrcpyW(check, windir);
527
            lstrcatW(check, szBackSlash);
528 529
            lstrcatW(check, subdir);
            lstrcatW(check, name);
530
            lstrcatW(check, szBackSlash);
531 532 533 534 535 536 537 538 539 540 541
            lstrcatW(check, fusion);

            if(GetFileAttributesW(check) != INVALID_FILE_ATTRIBUTES)
            {
                msi_free(file);
                file = check;
                lstrcpyW(ver, name);
            }
            else
                msi_free(check);
        }
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
    }

    RegCloseKey(netsetup);
    return file;
}

typedef struct tagLANGANDCODEPAGE
{
  WORD wLanguage;
  WORD wCodePage;
} LANGANDCODEPAGE;

static void set_msi_assembly_prop(MSIPACKAGE *package)
{
    UINT val_len;
    DWORD size, handle;
    LPVOID version = NULL;
    WCHAR buf[MAX_PATH];
    LPWSTR fusion, verstr;
    LANGANDCODEPAGE *translate;

    static const WCHAR netasm[] = {
        'M','s','i','N','e','t','A','s','s','e','m','b','l','y','S','u','p','p','o','r','t',0
    };
    static const WCHAR translation[] = {
        '\\','V','a','r','F','i','l','e','I','n','f','o',
        '\\','T','r','a','n','s','l','a','t','i','o','n',0
    };
    static const WCHAR verfmt[] = {
        '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
        '\\','%','0','4','x','%','0','4','x',
        '\\','P','r','o','d','u','c','t','V','e','r','s','i','o','n',0
    };

    fusion = get_fusion_filename(package);
    if (!fusion)
        return;

    size = GetFileVersionInfoSizeW(fusion, &handle);
    if (!size) return;

    version = msi_alloc(size);
    if (!version) return;

    if (!GetFileVersionInfoW(fusion, handle, size, version))
        goto done;

    if (!VerQueryValueW(version, translation, (LPVOID *)&translate, &val_len))
        goto done;

    sprintfW(buf, verfmt, translate[0].wLanguage, translate[0].wCodePage);

    if (!VerQueryValueW(version, buf, (LPVOID *)&verstr, &val_len))
        goto done;

    if (!val_len || !verstr)
        goto done;

600
    msi_set_property(package->db, netasm, verstr);
601 602 603 604 605 606

done:
    msi_free(fusion);
    msi_free(version);
}

607
static VOID set_installer_properties(MSIPACKAGE *package)
608 609
{
    WCHAR pth[MAX_PATH];
Aric Stewart's avatar
Aric Stewart committed
610
    WCHAR *ptr;
611
    OSVERSIONINFOEXW OSVersion;
612
    MEMORYSTATUSEX msex;
613
    DWORD verval, len;
614 615
    WCHAR verstr[10], bufstr[20];
    HDC dc;
616
    HKEY hkey;
617
    LPWSTR username, companyname;
618 619
    SYSTEM_INFO sys_info;
    SYSTEMTIME systemtime;
620
    LANGID langid;
621

622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
    static const WCHAR szCommonFilesFolder[] = {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
    static const WCHAR szProgramFilesFolder[] = {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
    static const WCHAR szCommonAppDataFolder[] = {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
    static const WCHAR szFavoritesFolder[] = {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
    static const WCHAR szFontsFolder[] = {'F','o','n','t','s','F','o','l','d','e','r',0};
    static const WCHAR szSendToFolder[] = {'S','e','n','d','T','o','F','o','l','d','e','r',0};
    static const WCHAR szStartMenuFolder[] = {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
    static const WCHAR szStartupFolder[] = {'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
    static const WCHAR szTemplateFolder[] = {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
    static const WCHAR szDesktopFolder[] = {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
    static const WCHAR szProgramMenuFolder[] = {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
    static const WCHAR szAdminToolsFolder[] = {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
    static const WCHAR szAppDataFolder[] = {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
    static const WCHAR szSystemFolder[] = {'S','y','s','t','e','m','F','o','l','d','e','r',0};
    static const WCHAR szSystem16Folder[] = {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
    static const WCHAR szLocalAppDataFolder[] = {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
    static const WCHAR szMyPicturesFolder[] = {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
    static const WCHAR szPersonalFolder[] = {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
    static const WCHAR szWindowsFolder[] = {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
    static const WCHAR szWindowsVolume[] = {'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
    static const WCHAR szTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
    static const WCHAR szPrivileged[] = {'P','r','i','v','i','l','e','g','e','d',0};
    static const WCHAR szVersion9x[] = {'V','e','r','s','i','o','n','9','X',0};
    static const WCHAR szVersionNT[] = {'V','e','r','s','i','o','n','N','T',0};
    static const WCHAR szMsiNTProductType[] = {'M','s','i','N','T','P','r','o','d','u','c','t','T','y','p','e',0};
647
    static const WCHAR szFormat[] = {'%','l','i',0};
648 649
    static const WCHAR szWindowsBuild[] = {'W','i','n','d','o','w','s','B','u','i','l','d',0};
    static const WCHAR szServicePackLevel[] = {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0};
650
    static const WCHAR szSix[] = {'6',0 };
651
    static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
652
    static const WCHAR szVersionDatabase[] = { 'V','e','r','s','i','o','n','D','a','t','a','b','a','s','e',0 };
653
    static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 };
654
    static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
655 656 657
    static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
    static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
    static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
658
    static const WCHAR szIntFormat[] = {'%','d',0};
659 660
    static const WCHAR szMsiAMD64[] = { 'M','s','i','A','M','D','6','4',0 };
    static const WCHAR szMsix64[] = { 'M','s','i','x','6','4',0 };
661
    static const WCHAR szSystem64Folder[] = { 'S','y','s','t','e','m','6','4','F','o','l','d','e','r',0 };
662 663 664 665 666 667 668 669
    static const WCHAR szUserInfo[] = {
        'S','O','F','T','W','A','R','E','\\',
        'M','i','c','r','o','s','o','f','t','\\',
        'M','S',' ','S','e','t','u','p',' ','(','A','C','M','E',')','\\',
        'U','s','e','r',' ','I','n','f','o',0
    };
    static const WCHAR szDefName[] = { 'D','e','f','N','a','m','e',0 };
    static const WCHAR szDefCompany[] = { 'D','e','f','C','o','m','p','a','n','y',0 };
670 671 672 673 674 675 676
    static const WCHAR szCurrentVersion[] = {
        'S','O','F','T','W','A','R','E','\\',
        'M','i','c','r','o','s','o','f','t','\\',
        'W','i','n','d','o','w','s',' ','N','T','\\',
        'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0
    };
    static const WCHAR szRegisteredUser[] = {'R','e','g','i','s','t','e','r','e','d','O','w','n','e','r',0};
677
    static const WCHAR szRegisteredOrganization[] = {
678 679 680 681
        'R','e','g','i','s','t','e','r','e','d','O','r','g','a','n','i','z','a','t','i','o','n',0
    };
    static const WCHAR szUSERNAME[] = {'U','S','E','R','N','A','M','E',0};
    static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0};
682 683
    static const WCHAR szDate[] = {'D','a','t','e',0};
    static const WCHAR szTime[] = {'T','i','m','e',0};
684
    static const WCHAR szUserLanguageID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0};
685
    static const WCHAR szSystemLangID[] = {'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0};
686
    static const WCHAR szProductState[] = {'P','r','o','d','u','c','t','S','t','a','t','e',0};
687
    static const WCHAR szLogonUser[] = {'L','o','g','o','n','U','s','e','r',0};
688 689 690
    static const WCHAR szNetHoodFolder[] = {'N','e','t','H','o','o','d','F','o','l','d','e','r',0};
    static const WCHAR szPrintHoodFolder[] = {'P','r','i','n','t','H','o','o','d','F','o','l','d','e','r',0};
    static const WCHAR szRecentFolder[] = {'R','e','c','e','n','t','F','o','l','d','e','r',0};
691

692 693 694
    /*
     * Other things that probably should be set:
     *
695
     * ComputerName VirtualMemory
696
     * ShellAdvSupport DefaultUIFont PackagecodeChanging
697
     * CaptionHeight BorderTop BorderSide TextHeight
698
     * RedirectedDllSupport
699
     */
700

701
    SHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, pth);
702
    strcatW(pth, szBackSlash);
703
    msi_set_property(package->db, szCommonFilesFolder, pth);
704

705
    SHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES, NULL, 0, pth);
706
    strcatW(pth, szBackSlash);
707
    msi_set_property(package->db, szProgramFilesFolder, pth);
708

709
    SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, pth);
710
    strcatW(pth, szBackSlash);
711
    msi_set_property(package->db, szCommonAppDataFolder, pth);
712

713
    SHGetFolderPathW(NULL, CSIDL_FAVORITES, NULL, 0, pth);
714
    strcatW(pth, szBackSlash);
715
    msi_set_property(package->db, szFavoritesFolder, pth);
716

717
    SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, pth);
718
    strcatW(pth, szBackSlash);
719
    msi_set_property(package->db, szFontsFolder, pth);
720

721
    SHGetFolderPathW(NULL, CSIDL_SENDTO, NULL, 0, pth);
722
    strcatW(pth, szBackSlash);
723
    msi_set_property(package->db, szSendToFolder, pth);
724

725
    SHGetFolderPathW(NULL, CSIDL_STARTMENU, NULL, 0, pth);
726
    strcatW(pth, szBackSlash);
727
    msi_set_property(package->db, szStartMenuFolder, pth);
728

729
    SHGetFolderPathW(NULL, CSIDL_STARTUP, NULL, 0, pth);
730
    strcatW(pth, szBackSlash);
731
    msi_set_property(package->db, szStartupFolder, pth);
732

733
    SHGetFolderPathW(NULL, CSIDL_TEMPLATES, NULL, 0, pth);
734
    strcatW(pth, szBackSlash);
735
    msi_set_property(package->db, szTemplateFolder, pth);
736

737
    SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, pth);
738
    strcatW(pth, szBackSlash);
739
    msi_set_property(package->db, szDesktopFolder, pth);
740

741
    /* FIXME: set to AllUsers profile path if ALLUSERS is set */
742
    SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, pth);
743
    strcatW(pth, szBackSlash);
744
    msi_set_property(package->db, szProgramMenuFolder, pth);
745

746
    SHGetFolderPathW(NULL, CSIDL_ADMINTOOLS, NULL, 0, pth);
747
    strcatW(pth, szBackSlash);
748
    msi_set_property(package->db, szAdminToolsFolder, pth);
749

750
    SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, pth);
751
    strcatW(pth, szBackSlash);
752
    msi_set_property(package->db, szAppDataFolder, pth);
753

754
    SHGetFolderPathW(NULL, CSIDL_SYSTEM, NULL, 0, pth);
755
    strcatW(pth, szBackSlash);
756 757
    msi_set_property(package->db, szSystemFolder, pth);
    msi_set_property(package->db, szSystem16Folder, pth);
758

759
    SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pth);
760
    strcatW(pth, szBackSlash);
761
    msi_set_property(package->db, szLocalAppDataFolder, pth);
762

763
    SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, 0, pth);
764
    strcatW(pth, szBackSlash);
765
    msi_set_property(package->db, szMyPicturesFolder, pth);
766

767
    SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, pth);
768
    strcatW(pth, szBackSlash);
769
    msi_set_property(package->db, szPersonalFolder, pth);
770

771
    SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
772
    strcatW(pth, szBackSlash);
773
    msi_set_property(package->db, szWindowsFolder, pth);
774
    
775 776 777 778 779 780 781 782 783 784 785 786
    SHGetFolderPathW(NULL, CSIDL_PRINTHOOD, NULL, 0, pth);
    strcatW(pth, szBackSlash);
    msi_set_property(package->db, szPrintHoodFolder, pth);

    SHGetFolderPathW(NULL, CSIDL_NETHOOD, NULL, 0, pth);
    strcatW(pth, szBackSlash);
    msi_set_property(package->db, szNetHoodFolder, pth);

    SHGetFolderPathW(NULL, CSIDL_RECENT, NULL, 0, pth);
    strcatW(pth, szBackSlash);
    msi_set_property(package->db, szRecentFolder, pth);

787 788 789
    /* Physical Memory is specified in MB. Using total amount. */
    msex.dwLength = sizeof(msex);
    GlobalMemoryStatusEx( &msex );
790
    sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys / 1024 / 1024) );
791
    msi_set_property(package->db, szPhysicalMemory, bufstr);
792

793
    SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, pth);
Aric Stewart's avatar
Aric Stewart committed
794
    ptr = strchrW(pth,'\\');
795 796
    if (ptr) *(ptr + 1) = 0;
    msi_set_property(package->db, szWindowsVolume, pth);
Aric Stewart's avatar
Aric Stewart committed
797
    
798
    GetTempPathW(MAX_PATH,pth);
799
    msi_set_property(package->db, szTempFolder, pth);
800

801
    /* in a wine environment the user is always admin and privileged */
802
    msi_set_property(package->db, szAdminUser, szOne);
803
    msi_set_property(package->db, szPrivileged, szOne);
804 805

    /* set the os things */
806 807
    OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
    GetVersionExW((OSVERSIONINFOW *)&OSVersion);
808 809
    verval = OSVersion.dwMinorVersion + OSVersion.dwMajorVersion * 100;
    sprintfW(verstr, szFormat, verval);
810 811 812
    switch (OSVersion.dwPlatformId)
    {
        case VER_PLATFORM_WIN32_WINDOWS:    
813
            msi_set_property(package->db, szVersion9x, verstr);
814 815
            break;
        case VER_PLATFORM_WIN32_NT:
816 817
            msi_set_property(package->db, szVersionNT, verstr);
            sprintfW(verstr, szFormat,OSVersion.wProductType);
818
            msi_set_property(package->db, szMsiNTProductType, verstr);
819 820
            break;
    }
821 822
    sprintfW(verstr, szFormat, OSVersion.dwBuildNumber);
    msi_set_property(package->db, szWindowsBuild, verstr);
823
    /* just fudge this */
824
    msi_set_property(package->db, szServicePackLevel, szSix);
825

826
    sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
827
    msi_set_property( package->db, szVersionMsi, bufstr );
828
    sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100);
829
    msi_set_property( package->db, szVersionDatabase, bufstr );
830

831
    GetSystemInfo( &sys_info );
832
    if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
833
    {
834
        sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
835
        msi_set_property( package->db, szIntel, bufstr );
836
    }
837 838 839 840 841
    else if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
    {
        sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
        msi_set_property( package->db, szMsiAMD64, bufstr );
        msi_set_property( package->db, szMsix64, bufstr );
842 843 844

        GetSystemDirectoryW( pth, MAX_PATH );
        msi_set_property( package->db, szSystem64Folder, pth );
845
    }
846

847 848
    /* Screen properties. */
    dc = GetDC(0);
849
    sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, HORZRES ) );
850
    msi_set_property( package->db, szScreenX, bufstr );
851
    sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, VERTRES ));
852
    msi_set_property( package->db, szScreenY, bufstr );
853
    sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, BITSPIXEL ));
854
    msi_set_property( package->db, szColorBits, bufstr );
855
    ReleaseDC(0, dc);
856 857

    /* USERNAME and COMPANYNAME */
858 859
    username = msi_dup_property( package->db, szUSERNAME );
    companyname = msi_dup_property( package->db, szCOMPANYNAME );
860

861 862
    if ((!username || !companyname) &&
        RegOpenKeyW( HKEY_CURRENT_USER, szUserInfo, &hkey ) == ERROR_SUCCESS)
863
    {
864 865
        if (!username &&
            (username = msi_reg_get_val_str( hkey, szDefName )))
866
            msi_set_property( package->db, szUSERNAME, username );
867 868
        if (!companyname &&
            (companyname = msi_reg_get_val_str( hkey, szDefCompany )))
869
            msi_set_property( package->db, szCOMPANYNAME, companyname );
870
        CloseHandle( hkey );
871
    }
872 873
    if ((!username || !companyname) &&
        RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey ) == ERROR_SUCCESS)
874
    {
875 876
        if (!username &&
            (username = msi_reg_get_val_str( hkey, szRegisteredUser )))
877
            msi_set_property( package->db, szUSERNAME, username );
878
        if (!companyname &&
879
            (companyname = msi_reg_get_val_str( hkey, szRegisteredOrganization )))
880
            msi_set_property( package->db, szCOMPANYNAME, companyname );
881
        CloseHandle( hkey );
882
    }
883 884
    msi_free( username );
    msi_free( companyname );
885

886 887 888
    if ( set_user_sid_prop( package ) != ERROR_SUCCESS)
        ERR("Failed to set the UserSID property\n");

889 890 891 892
    /* Date and time properties */
    GetSystemTime( &systemtime );
    if (GetDateFormatW( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systemtime,
                        NULL, bufstr, sizeof(bufstr)/sizeof(bufstr[0]) ))
893
        msi_set_property( package->db, szDate, bufstr );
894 895 896 897 898 899 900
    else
        ERR("Couldn't set Date property: GetDateFormat failed with error %d\n", GetLastError());

    if (GetTimeFormatW( LOCALE_USER_DEFAULT,
                        TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER,
                        &systemtime, NULL, bufstr,
                        sizeof(bufstr)/sizeof(bufstr[0]) ))
901
        msi_set_property( package->db, szTime, bufstr );
902 903 904
    else
        ERR("Couldn't set Time property: GetTimeFormat failed with error %d\n", GetLastError());

905 906
    set_msi_assembly_prop( package );

907 908
    langid = GetUserDefaultLangID();
    sprintfW(bufstr, szIntFormat, langid);
909
    msi_set_property( package->db, szUserLanguageID, bufstr );
910 911 912

    langid = GetSystemDefaultLangID();
    sprintfW(bufstr, szIntFormat, langid);
913
    msi_set_property( package->db, szSystemLangID, bufstr );
914 915

    sprintfW(bufstr, szIntFormat, MsiQueryProductStateW(package->ProductCode));
916
    msi_set_property( package->db, szProductState, bufstr );
917 918 919 920 921

    len = 0;
    if (!GetUserNameW( NULL, &len ) && GetLastError() == ERROR_MORE_DATA)
    {
        WCHAR *username;
922
        if ((username = msi_alloc( len * sizeof(WCHAR) )))
923 924
        {
            if (GetUserNameW( username, &len ))
925
                msi_set_property( package->db, szLogonUser, username );
926
            msi_free( username );
927 928
        }
    }
929
}
930

931
static UINT msi_load_summary_properties( MSIPACKAGE *package )
932 933 934 935
{
    UINT rc;
    MSIHANDLE suminfo;
    MSIHANDLE hdb = alloc_msihandle( &package->db->hdr );
936
    INT count;
937 938 939 940
    DWORD len;
    LPWSTR package_code;
    static const WCHAR szPackageCode[] = {
        'P','a','c','k','a','g','e','C','o','d','e',0};
941

942 943
    if (!hdb) {
        ERR("Unable to allocate handle\n");
944
        return ERROR_OUTOFMEMORY;
945
    }
946

947 948 949 950 951
    rc = MsiGetSummaryInformationW( hdb, NULL, 0, &suminfo );
    MsiCloseHandle(hdb);
    if (rc != ERROR_SUCCESS)
    {
        ERR("Unable to open Summary Information\n");
952
        return rc;
953 954
    }

955 956 957 958
    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_PAGECOUNT, NULL,
                                     &count, NULL, NULL, NULL );
    if (rc != ERROR_SUCCESS)
    {
959
        WARN("Unable to query page count: %d\n", rc);
960 961
        goto done;
    }
962 963 964 965 966

    /* load package code property */
    len = 0;
    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
                                     NULL, NULL, NULL, &len );
967
    if (rc != ERROR_MORE_DATA)
968
    {
969 970 971
        WARN("Unable to query revision number: %d\n", rc);
        rc = ERROR_FUNCTION_FAILED;
        goto done;
972 973
    }

974 975 976 977 978 979 980 981 982 983
    len++;
    package_code = msi_alloc( len * sizeof(WCHAR) );
    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
                                     NULL, NULL, package_code, &len );
    if (rc != ERROR_SUCCESS)
    {
        WARN("Unable to query rev number: %d\n", rc);
        goto done;
    }

984
    msi_set_property( package->db, szPackageCode, package_code );
985 986 987 988 989 990 991 992 993
    msi_free( package_code );

    /* load package attributes */
    count = 0;
    MsiSummaryInfoGetPropertyW( suminfo, PID_WORDCOUNT, NULL,
                                &count, NULL, NULL, NULL );
    package->WordCount = count;

done:
994
    MsiCloseHandle(suminfo);
995
    return rc;
996 997
}

998
static MSIPACKAGE *msi_alloc_package( void )
999
{
1000
    MSIPACKAGE *package;
1001

1002 1003
    package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
                               MSI_FreePackage );
1004
    if( package )
1005
    {
1006
        list_init( &package->components );
1007
        list_init( &package->features );
1008
        list_init( &package->files );
1009
        list_init( &package->tempfiles );
1010
        list_init( &package->folders );
1011
        list_init( &package->subscriptions );
1012
        list_init( &package->appids );
1013
        list_init( &package->classes );
1014
        list_init( &package->mimes );
1015
        list_init( &package->extensions );
1016
        list_init( &package->progids );
1017
        list_init( &package->RunningActions );
1018 1019
        list_init( &package->sourcelist_info );
        list_init( &package->sourcelist_media );
1020
        list_init( &package->patches );
1021 1022 1023 1024 1025
    }

    return package;
}

1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
static UINT msi_load_admin_properties(MSIPACKAGE *package)
{
    BYTE *data;
    UINT r, sz;

    static const WCHAR stmname[] = {'A','d','m','i','n','P','r','o','p','e','r','t','i','e','s',0};

    r = read_stream_data(package->db->storage, stmname, FALSE, &data, &sz);
    if (r != ERROR_SUCCESS)
        return r;

1037
    r = msi_parse_command_line(package, (WCHAR *)data, TRUE);
1038 1039 1040 1041 1042

    msi_free(data);
    return r;
}

1043
void msi_adjust_privilege_properties( MSIPACKAGE *package )
1044 1045
{
    /* FIXME: this should depend on the user's privileges */
1046
    if (msi_get_property_int( package->db, szAllUsers, 0 ) == 2)
1047 1048
    {
        TRACE("resetting ALLUSERS property from 2 to 1\n");
1049
        msi_set_property( package->db, szAllUsers, szOne );
1050
    }
1051
    msi_set_property( package->db, szAdminUser, szOne );
1052 1053
}

1054
MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
1055 1056 1057 1058 1059
{
    static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
    static const WCHAR szpi[] = {'%','i',0};
    MSIPACKAGE *package;
    WCHAR uilevel[10];
1060
    UINT r;
1061 1062 1063 1064 1065 1066 1067 1068 1069

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

    package = msi_alloc_package();
    if (package)
    {
        msiobj_addref( &db->hdr );
        package->db = db;

1070
        package->WordCount = 0;
1071
        package->PackagePath = strdupW( db->path );
1072
        package->BaseURL = strdupW( base_url );
1073

1074 1075
        create_temp_property_table( package );
        msi_clone_properties( package );
1076
        msi_adjust_privilege_properties( package );
1077

1078
        package->ProductCode = msi_dup_property( package->db, szProductCode );
1079 1080
        package->script = msi_alloc_zero( sizeof(MSISCRIPT) );

1081
        set_installed_prop( package );
1082 1083 1084
        set_installer_properties( package );

        sprintfW(uilevel,szpi,gUILevel);
1085
        msi_set_property(package->db, szLevel, uilevel);
1086

1087 1088 1089 1090 1091 1092
        r = msi_load_summary_properties( package );
        if (r != ERROR_SUCCESS)
        {
            msiobj_release( &package->hdr );
            return NULL;
        }
1093

1094
        if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1095
            msi_load_admin_properties( package );
1096 1097
    }

1098
    return package;
1099 1100
}

1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
/*
 * copy_package_to_temp   [internal]
 *
 * copy the msi file to a temp file to prevent locking a CD
 * with a multi disc install 
 *
 * FIXME: I think this is wrong, and instead of copying the package,
 *        we should read all the tables to memory, then open the
 *        database to read binary streams on demand.
 */ 
1111
static UINT copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
1112 1113 1114 1115
{
    WCHAR path[MAX_PATH];

    GetTempPathW( MAX_PATH, path );
1116
    GetTempFileNameW( path, szMsi, 0, filename );
1117 1118 1119

    if( !CopyFileW( szPackage, filename, FALSE ) )
    {
1120
        UINT error = GetLastError();
1121 1122 1123 1124
        if ( error == ERROR_FILE_NOT_FOUND )
            ERR("can't find %s\n", debugstr_w(szPackage));
        else
            ERR("failed to copy package %s to %s (%u)\n", debugstr_w(szPackage), debugstr_w(filename), error);
1125
        DeleteFileW( filename );
1126
        return error;
1127 1128
    }

1129
    return ERROR_SUCCESS;
1130 1131
}

1132
UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename )
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
{
    LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
    DWORD size = 0;
    HRESULT hr;

    /* call will always fail, becase size is 0,
     * but will return ERROR_FILE_NOT_FOUND first
     * if the file doesn't exist
     */
    GetUrlCacheEntryInfoW( szUrl, NULL, &size );
    if ( GetLastError() != ERROR_FILE_NOT_FOUND )
    {
1145
        cache_entry = msi_alloc( size );
1146 1147
        if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
        {
1148
            UINT error = GetLastError();
1149
            msi_free( cache_entry );
1150
            return error;
1151 1152 1153
        }

        lstrcpyW( filename, cache_entry->lpszLocalFileName );
1154
        msi_free( cache_entry );
1155
        return ERROR_SUCCESS;
1156 1157 1158 1159
    }

    hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
    if ( FAILED(hr) )
1160 1161 1162 1163
    {
        WARN("failed to download %s to cache file\n", debugstr_w(szUrl));
        return ERROR_FUNCTION_FAILED;
    }
1164

1165
    return ERROR_SUCCESS;
1166 1167
}

1168
UINT msi_get_local_package_name( LPWSTR path, LPCWSTR suffix )
1169 1170 1171
{
    static const WCHAR szInstaller[] = {
        '\\','I','n','s','t','a','l','l','e','r','\\',0};
1172 1173
    static const WCHAR fmt[] = {'%','x',0};
    DWORD time, len, i, offset;
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
    HANDLE handle;

    time = GetTickCount();
    GetWindowsDirectoryW( path, MAX_PATH );
    strcatW( path, szInstaller );
    CreateDirectoryW( path, NULL );

    len = strlenW(path);
    for (i = 0; i < 0x10000; i++)
    {
1184 1185
        offset = snprintfW( path + len, MAX_PATH - len, fmt, (time + i) & 0xffff );
        memcpy( path + len + offset, suffix, (strlenW( suffix ) + 1) * sizeof(WCHAR) );
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
        handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
                              CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
        if (handle != INVALID_HANDLE_VALUE)
        {
            CloseHandle(handle);
            break;
        }
        if (GetLastError() != ERROR_FILE_EXISTS &&
            GetLastError() != ERROR_SHARING_VIOLATION)
            return ERROR_FUNCTION_FAILED;
    }

    return ERROR_SUCCESS;
}

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 1237 1238 1239 1240 1241
static UINT apply_registered_patch( MSIPACKAGE *package, LPCWSTR patch_code )
{
    UINT r;
    DWORD len;
    WCHAR patch_file[MAX_PATH];
    MSIDATABASE *patch_db;
    MSIPATCHINFO *patch_info;
    MSISUMMARYINFO *si;

    len = sizeof(patch_file) / sizeof(WCHAR);
    r = MsiGetPatchInfoExW( patch_code, package->ProductCode, NULL, package->Context,
                            INSTALLPROPERTY_LOCALPACKAGEW, patch_file, &len );
    if (r != ERROR_SUCCESS)
    {
        ERR("failed to get patch filename %u\n", r);
        return r;
    }

    r = MSI_OpenDatabaseW( patch_file, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &patch_db );
    if (r != ERROR_SUCCESS)
    {
        ERR("failed to open patch database %s\n", debugstr_w( patch_file ));
        return r;
    }

    si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
    if (!si)
    {
        msiobj_release( &patch_db->hdr );
        return ERROR_FUNCTION_FAILED;
    }

    r = msi_parse_patch_summary( si, &patch_info );
    msiobj_release( &si->hdr );
    if (r != ERROR_SUCCESS)
    {
        ERR("failed to parse patch summary %u\n", r);
        msiobj_release( &patch_db->hdr );
        return r;
    }

1242 1243 1244 1245 1246 1247 1248
    patch_info->localfile = strdupW( patch_file );
    if (!patch_info->localfile)
    {
        msiobj_release( &patch_db->hdr );
        return ERROR_OUTOFMEMORY;
    }

1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
    r = msi_apply_patch_db( package, patch_db, patch_info );
    msiobj_release( &patch_db->hdr );
    if (r != ERROR_SUCCESS)
    {
        ERR("failed to apply patch %u\n", r);
        msi_free( patch_info->patchcode );
        msi_free( patch_info->transforms );
        msi_free( patch_info->localfile );
        msi_free( patch_info );
    }
    return r;
}

1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
static UINT msi_parse_summary( MSISUMMARYINFO *si, MSIPACKAGE *package )
{
    WCHAR *template, *p, *q;
    DWORD i, count;

    template = msi_suminfo_dup_string( si, PID_TEMPLATE );
    if (!template)
        return ERROR_SUCCESS; /* native accepts missing template property */

    TRACE("template: %s\n", debugstr_w(template));

    p = strchrW( template, ';' );
    if (!p)
    {
        WARN("invalid template string %s\n", debugstr_w(template));
        msi_free( template );
        return ERROR_PATCH_PACKAGE_INVALID;
    }
    *p = 0;
    if (!template[0] || !strcmpW( template, szIntel ))
        package->platform = PLATFORM_INTEL;
    else if (!strcmpW( template, szIntel64 ))
        package->platform = PLATFORM_INTEL64;
    else if (!strcmpW( template, szX64 ))
        package->platform = PLATFORM_X64;
    else
    {
        WARN("unknown platform %s\n", debugstr_w(template));
        msi_free( template );
        return ERROR_PATCH_PACKAGE_INVALID;
    }

    count = 1;
    for (q = ++p; (q = strchrW( q, ',' )); q++) count++;

    package->langids = msi_alloc( count * sizeof(LANGID) );
    if (!package->langids)
    {
        msi_free( template );
        return ERROR_OUTOFMEMORY;
    }

    i = 0;
    while (*p)
    {
        q = strchrW( p, ',' );
        if (q) *q = 0;
        package->langids[i] = atoiW( p );
        if (!q) break;
        p = q + 1;
        i++;
    }
    package->num_langids = i + 1;

    msi_free( template );
    return ERROR_SUCCESS;
}

1320 1321
UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
{
1322
    static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
1323
    static const WCHAR dotmsi[] = {'.','m','s','i',0};
1324
    MSIDATABASE *db = NULL;
1325
    MSIPACKAGE *package;
1326
    MSIHANDLE handle;
1327
    LPWSTR ptr, base_url = NULL;
1328
    UINT r;
1329
    WCHAR temppath[MAX_PATH], localfile[MAX_PATH], cachefile[MAX_PATH];
1330
    LPCWSTR file = szPackage;
1331
    DWORD index = 0;
1332
    MSISUMMARYINFO *si;
1333

1334 1335 1336 1337 1338 1339 1340
    TRACE("%s %p\n", debugstr_w(szPackage), pPackage);

    if( szPackage[0] == '#' )
    {
        handle = atoiW(&szPackage[1]);
        db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
        if( !db )
1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
        {
            IWineMsiRemoteDatabase *remote_database;

            remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( handle );
            if ( !remote_database )
                return ERROR_INVALID_HANDLE;

            IWineMsiRemoteDatabase_Release( remote_database );
            WARN("MsiOpenPackage not allowed during a custom action!\n");

            return ERROR_FUNCTION_FAILED;
        }
1353 1354 1355
    }
    else
    {
1356
        if ( UrlIsW( szPackage, URLIS_URL ) )
1357
        {
1358 1359 1360 1361 1362 1363 1364 1365 1366
            r = msi_download_file( szPackage, cachefile );
            if ( r != ERROR_SUCCESS )
                return r;

            r = copy_package_to_temp( cachefile, temppath );
            if ( r != ERROR_SUCCESS )
                return r;

            file = temppath;
1367 1368 1369 1370 1371 1372 1373 1374

            base_url = strdupW( szPackage );
            if ( !base_url )
                return ERROR_OUTOFMEMORY;

            ptr = strrchrW( base_url, '/' );
            if (ptr) *(ptr + 1) = '\0';
        }
1375
        else
1376 1377 1378 1379 1380 1381 1382
        {
            r = copy_package_to_temp( szPackage, temppath );
            if ( r != ERROR_SUCCESS )
                return r;

            file = temppath;
        }
1383

1384
        r = msi_get_local_package_name( localfile, dotmsi );
1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396
        if (r != ERROR_SUCCESS)
            return r;

        TRACE("Copying to local package %s\n", debugstr_w(localfile));

        if (!CopyFileW( file, localfile, FALSE ))
        {
            ERR("Unable to copy package (%s -> %s) (error %u)\n",
                debugstr_w(file), debugstr_w(localfile), GetLastError());
            return GetLastError();
        }

1397 1398
        TRACE("Opening relocated package %s\n", debugstr_w( file ));

1399 1400 1401 1402
        /* transforms that add binary streams require that we open the database
         * read/write, which is safe because we always create a copy that is thrown
         * away when we're done.
         */
1403
        r = MSI_OpenDatabaseW( file, MSIDBOPEN_TRANSACT, &db );
1404
        if( r != ERROR_SUCCESS )
1405
        {
1406 1407
            if (file != szPackage)
                DeleteFileW( file );
1408

1409 1410 1411
            if (GetFileAttributesW(szPackage) == INVALID_FILE_ATTRIBUTES)
                return ERROR_FILE_NOT_FOUND;

1412
            return r;
1413
        }
1414 1415

        db->localfile = strdupW( localfile );
1416 1417
    }

1418 1419
    package = MSI_CreatePackage( db, base_url );
    msi_free( base_url );
1420 1421
    msiobj_release( &db->hdr );
    if( !package )
1422 1423 1424
    {
        if (file != szPackage)
            DeleteFileW( file );
1425 1426

        return ERROR_INSTALL_PACKAGE_INVALID;
1427 1428 1429 1430
    }

    if( file != szPackage )
        track_tempfile( package, file );
1431

1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
    si = MSI_GetSummaryInformationW( db->storage, 0 );
    if (!si)
    {
        WARN("failed to load summary info %u\n", r);
        msiobj_release( &package->hdr );
        return ERROR_INSTALL_PACKAGE_INVALID;
    }

    r = msi_parse_summary( si, package );
    msiobj_release( &si->hdr );
    if (r != ERROR_SUCCESS)
    {
        WARN("failed to parse summary info %u\n", r);
        msiobj_release( &package->hdr );
        return r;
    }

1449
    msi_set_property( package->db, Database, db->path );
1450

1451
    if( UrlIsW( szPackage, URLIS_URL ) )
1452
        msi_set_property( package->db, szOriginalDatabase, szPackage );
1453
    else if( szPackage[0] == '#' )
1454
        msi_set_property( package->db, szOriginalDatabase, db->path );
1455 1456
    else
    {
1457 1458 1459
        WCHAR fullpath[MAX_PATH];

        GetFullPathNameW( szPackage, MAX_PATH, fullpath, NULL );
1460
        msi_set_property( package->db, szOriginalDatabase, fullpath );
1461
    }
1462

1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
    msi_set_context( package );

    while (1)
    {
        WCHAR patch_code[GUID_SIZE];
        r = MsiEnumPatchesExW( package->ProductCode, NULL, package->Context,
                               MSIPATCHSTATE_APPLIED, index, patch_code, NULL, NULL, NULL, NULL );
        if (r != ERROR_SUCCESS)
            break;

        TRACE("found registered patch %s\n", debugstr_w(patch_code));
1474

1475 1476 1477 1478
        r = apply_registered_patch( package, patch_code );
        if (r != ERROR_SUCCESS)
        {
            ERR("registered patch failed to apply %u\n", r);
1479
            msiobj_release( &package->hdr );
1480 1481 1482 1483 1484 1485
            return r;
        }

        index++;
    }

1486 1487 1488
    if (index)
    {
        msi_clone_properties( package );
1489
        msi_adjust_privilege_properties( package );
1490 1491
    }

1492
    *pPackage = package;
1493
    return ERROR_SUCCESS;
1494
}
1495

1496
UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
1497 1498 1499
{
    MSIPACKAGE *package = NULL;
    UINT ret;
1500

1501
    TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage );
1502

1503
    if( !szPackage || !phPackage )
1504 1505
        return ERROR_INVALID_PARAMETER;

1506 1507
    if ( !*szPackage )
    {
1508
        FIXME("Should create an empty database and package\n");
1509 1510 1511
        return ERROR_FUNCTION_FAILED;
    }

1512
    if( dwOptions )
1513
        FIXME("dwOptions %08x not supported\n", dwOptions);
1514

1515
    ret = MSI_OpenPackageW( szPackage, &package );
1516 1517 1518
    if( ret == ERROR_SUCCESS )
    {
        *phPackage = alloc_msihandle( &package->hdr );
1519 1520
        if (! *phPackage)
            ret = ERROR_NOT_ENOUGH_MEMORY;
1521 1522
        msiobj_release( &package->hdr );
    }
1523

1524
    return ret;
1525 1526
}

1527 1528 1529 1530 1531
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
{
    return MsiOpenPackageExW( szPackage, 0, phPackage );
}

1532 1533
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
1534
    LPWSTR szwPack = NULL;
1535
    UINT ret;
1536 1537 1538

    if( szPackage )
    {
1539 1540 1541
        szwPack = strdupAtoW( szPackage );
        if( !szwPack )
            return ERROR_OUTOFMEMORY;
1542 1543 1544 1545
    }

    ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );

1546
    msi_free( szwPack );
1547 1548

    return ret;
1549 1550
}

1551
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
1552
{
1553
    return MsiOpenPackageExA( szPackage, 0, phPackage );
1554 1555 1556 1557 1558
}

MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
{
    MSIPACKAGE *package;
1559
    MSIHANDLE handle = 0;
1560
    IUnknown *remote_unk;
1561
    IWineMsiRemotePackage *remote_package;
1562

1563
    TRACE("(%d)\n",hInstall);
1564 1565

    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1566 1567 1568 1569 1570
    if( package)
    {
        handle = alloc_msihandle( &package->db->hdr );
        msiobj_release( &package->hdr );
    }
1571
    else if ((remote_unk = msi_get_remote(hInstall)))
1572
    {
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583
        if (IUnknown_QueryInterface(remote_unk, &IID_IWineMsiRemotePackage,
                                        (LPVOID *)&remote_package) == S_OK)
        {
            IWineMsiRemotePackage_GetActiveDatabase(remote_package, &handle);
            IWineMsiRemotePackage_Release(remote_package);
        }
        else
        {
            WARN("remote handle %d is not a package\n", hInstall);
        }
        IUnknown_Release(remote_unk);
1584
    }
1585

1586
    return handle;
1587 1588
}

1589 1590
INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
                               MSIRECORD *record)
1591
{
1592 1593 1594 1595 1596 1597
    static const WCHAR szActionData[] =
        {'A','c','t','i','o','n','D','a','t','a',0};
    static const WCHAR szSetProgress[] =
        {'S','e','t','P','r','o','g','r','e','s','s',0};
    static const WCHAR szActionText[] =
        {'A','c','t','i','o','n','T','e','x','t',0};
1598
    DWORD log_type = 0;
1599
    LPWSTR message;
1600
    DWORD sz;
1601 1602
    DWORD total_size = 0;
    INT i;
Aric Stewart's avatar
Aric Stewart committed
1603
    INT rc;
1604 1605
    char *msg;
    int len;
Aric Stewart's avatar
Aric Stewart committed
1606

1607
    TRACE("%x\n", eMessageType);
Aric Stewart's avatar
Aric Stewart committed
1608
    rc = 0;
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623

    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
        log_type |= INSTALLLOGMODE_ERROR;
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
        log_type |= INSTALLLOGMODE_WARNING;
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
        log_type |= INSTALLLOGMODE_USER;
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
        log_type |= INSTALLLOGMODE_INFO;
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
        log_type |= INSTALLLOGMODE_COMMONDATA;
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
        log_type |= INSTALLLOGMODE_ACTIONSTART;
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
        log_type |= INSTALLLOGMODE_ACTIONDATA;
1624 1625 1626
    /* just a guess */
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
        log_type |= 0x800;
1627

1628 1629 1630
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
    {
        static const WCHAR template_s[]=
1631
            {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ',0};
1632 1633 1634
        static const WCHAR format[] = 
            {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
        WCHAR timet[0x100];
1635 1636
        LPCWSTR action_text, action;
        LPWSTR deformatted = NULL;
1637 1638 1639 1640 1641

        GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);

        action = MSI_RecordGetString(record, 1);
        action_text = MSI_RecordGetString(record, 2);
1642 1643 1644 1645

        if (!action || !action_text)
            return IDOK;

1646 1647 1648 1649 1650 1651 1652 1653 1654 1655
        deformat_string(package, action_text, &deformatted);

        len = strlenW(timet) + strlenW(action) + strlenW(template_s);
        if (deformatted)
            len += strlenW(deformatted);
        message = msi_alloc(len*sizeof(WCHAR));
        sprintfW(message, template_s, timet, action);
        if (deformatted)
            strcatW(message, deformatted);
        msi_free(deformatted);
1656 1657
    }
    else
1658
    {
1659 1660 1661 1662 1663
        INT msg_field=1;
        message = msi_alloc(1*sizeof (WCHAR));
        message[0]=0;
        msg_field = MSI_RecordGetFieldCount(record);
        for (i = 1; i <= msg_field; i++)
1664
        {
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
            LPWSTR tmp;
            WCHAR number[3];
            static const WCHAR format[] = { '%','i',':',' ',0};
            sz = 0;
            MSI_RecordGetStringW(record,i,NULL,&sz);
            sz+=4;
            total_size+=sz*sizeof(WCHAR);
            tmp = msi_alloc(sz*sizeof(WCHAR));
            message = msi_realloc(message,total_size*sizeof (WCHAR));

            MSI_RecordGetStringW(record,i,tmp,&sz);

            if (msg_field > 1)
            {
                sprintfW(number,format,i);
                strcatW(message,number);
            }
            strcatW(message,tmp);
            if (msg_field > 1)
1684
                strcatW(message, szSpace);
1685 1686

            msi_free(tmp);
1687 1688 1689
        }
    }

1690
    TRACE("%p %p %p %x %x %s\n", gUIHandlerA, gUIHandlerW, gUIHandlerRecord,
1691
          gUIFilter, log_type, debugstr_w(message));
1692 1693

    /* convert it to ASCII */
1694
    len = WideCharToMultiByte( CP_ACP, 0, message, -1, NULL, 0, NULL, NULL );
1695
    msg = msi_alloc( len );
1696
    WideCharToMultiByte( CP_ACP, 0, message, -1, msg, len, NULL, NULL );
1697

1698
    if (gUIHandlerW && (gUIFilter & log_type))
1699
    {
1700 1701 1702 1703 1704
        rc = gUIHandlerW( gUIContext, eMessageType, message );
    }
    else if (gUIHandlerA && (gUIFilter & log_type))
    {
        rc = gUIHandlerA( gUIContext, eMessageType, msg );
1705
    }
1706 1707 1708 1709 1710 1711 1712
    else if (gUIHandlerRecord && (gUIFilter & log_type))
    {
        MSIHANDLE rec = MsiCreateRecord( 1 );
        MsiRecordSetStringW( rec, 0, message );
        rc = gUIHandlerRecord( gUIContext, eMessageType, rec );
        MsiCloseHandle( rec );
    }
Aric Stewart's avatar
Aric Stewart committed
1713 1714 1715 1716 1717 1718 1719

    if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
                                      INSTALLMESSAGE_PROGRESS))
    {
        DWORD write;
        HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
                                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1720

Aric Stewart's avatar
Aric Stewart committed
1721 1722 1723
        if (log_file != INVALID_HANDLE_VALUE)
        {
            SetFilePointer(log_file,0, NULL, FILE_END);
1724
            WriteFile(log_file,msg,strlen(msg),&write,NULL);
Aric Stewart's avatar
Aric Stewart committed
1725 1726 1727 1728
            WriteFile(log_file,"\n",1,&write,NULL);
            CloseHandle(log_file);
        }
    }
1729
    msi_free( msg );
1730
    msi_free( message );
1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760

    switch (eMessageType & 0xff000000)
    {
    case INSTALLMESSAGE_ACTIONDATA:
        /* FIXME: format record here instead of in ui_actiondata to get the
         * correct action data for external scripts */
        ControlEvent_FireSubscribedEvent(package, szActionData, record);
        break;
    case INSTALLMESSAGE_ACTIONSTART:
    {
        MSIRECORD *uirow;
        LPWSTR deformated;
        LPCWSTR action_text = MSI_RecordGetString(record, 2);

        deformat_string(package, action_text, &deformated);
        uirow = MSI_CreateRecord(1);
        MSI_RecordSetStringW(uirow, 1, deformated);
        TRACE("INSTALLMESSAGE_ACTIONSTART: %s\n", debugstr_w(deformated));
        msi_free(deformated);

        ControlEvent_FireSubscribedEvent(package, szActionText, uirow);

        msiobj_release(&uirow->hdr);
        break;
    }
    case INSTALLMESSAGE_PROGRESS:
        ControlEvent_FireSubscribedEvent(package, szSetProgress, record);
        break;
    }

1761 1762 1763
    return ERROR_SUCCESS;
}

1764 1765 1766 1767 1768 1769 1770 1771 1772
INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
                              MSIHANDLE hRecord)
{
    UINT ret = ERROR_INVALID_HANDLE;
    MSIPACKAGE *package = NULL;
    MSIRECORD *record = NULL;

    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
    if( !package )
1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794
    {
        HRESULT hr;
        IWineMsiRemotePackage *remote_package;

        remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
        if (!remote_package)
            return ERROR_INVALID_HANDLE;

        hr = IWineMsiRemotePackage_ProcessMessage( remote_package, eMessageType, hRecord );

        IWineMsiRemotePackage_Release( remote_package );

        if (FAILED(hr))
        {
            if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
                return HRESULT_CODE(hr);

            return ERROR_FUNCTION_FAILED;
        }

        return ERROR_SUCCESS;
    }
1795 1796 1797 1798 1799 1800 1801 1802

    record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
    if( !record )
        goto out;

    ret = MSI_ProcessMessage( package, eMessageType, record );

out:
1803
    msiobj_release( &package->hdr );
1804 1805 1806 1807 1808 1809
    if( record )
        msiobj_release( &record->hdr );

    return ret;
}

1810
/* property code */
1811

1812
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
1813 1814
{
    LPWSTR szwName = NULL, szwValue = NULL;
1815
    UINT r = ERROR_OUTOFMEMORY;
1816

1817 1818 1819
    szwName = strdupAtoW( szName );
    if( szName && !szwName )
        goto end;
1820

1821 1822 1823
    szwValue = strdupAtoW( szValue );
    if( szValue && !szwValue )
        goto end;
1824

1825
    r = MsiSetPropertyW( hInstall, szwName, szwValue);
1826 1827

end:
1828 1829
    msi_free( szwName );
    msi_free( szwValue );
1830

1831
    return r;
1832 1833
}

1834
void msi_reset_folders( MSIPACKAGE *package, BOOL source )
1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852
{
    MSIFOLDER *folder;

    LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
    {
        if ( source )
        {
            msi_free( folder->ResolvedSource );
            folder->ResolvedSource = NULL;
        }
        else
        {
            msi_free( folder->ResolvedTarget );
            folder->ResolvedTarget = NULL;
        }
    }
}

1853
UINT msi_set_property( MSIDATABASE *db, LPCWSTR szName, LPCWSTR szValue )
1854
{
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
    MSIQUERY *view;
    MSIRECORD *row = NULL;
    UINT rc;
    DWORD sz = 0;
    WCHAR Query[1024];

    static const WCHAR Insert[] = {
        'I','N','S','E','R','T',' ','i','n','t','o',' ',
        '`','_','P','r','o','p','e','r','t','y','`',' ','(',
        '`','_','P','r','o','p','e','r','t','y','`',',',
        '`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
        ,' ','(','?',',','?',')',0};
    static const WCHAR Update[] = {
        'U','P','D','A','T','E',' ','`','_','P','r','o','p','e','r','t','y','`',
        ' ','s','e','t',' ','`','V','a','l','u','e','`',' ','=',' ','?',' ',
        'w','h','e','r','e',' ','`','_','P','r','o','p','e','r','t','y','`',
        ' ','=',' ','\'','%','s','\'',0};
    static const WCHAR Delete[] = {
        'D','E','L','E','T','E',' ','F','R','O','M',' ',
        '`','_','P','r','o','p','e','r','t','y','`',' ','W','H','E','R','E',' ',
        '`','_','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
1876

1877
    TRACE("%p %s %s\n", db, debugstr_w(szName), debugstr_w(szValue));
1878 1879 1880 1881

    if (!szName)
        return ERROR_INVALID_PARAMETER;

1882
    /* this one is weird... */
1883 1884
    if (!szName[0])
        return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
1885

1886
    rc = msi_get_property(db, szName, 0, &sz);
1887 1888 1889 1890 1891 1892 1893
    if (!szValue || !*szValue)
    {
        sprintfW(Query, Delete, szName);
    }
    else if (rc == ERROR_MORE_DATA || rc == ERROR_SUCCESS)
    {
        sprintfW(Query, Update, szName);
1894

1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905
        row = MSI_CreateRecord(1);
        MSI_RecordSetStringW(row, 1, szValue);
    }
    else
    {
        strcpyW(Query, Insert);

        row = MSI_CreateRecord(2);
        MSI_RecordSetStringW(row, 1, szName);
        MSI_RecordSetStringW(row, 2, szValue);
    }
1906

1907
    rc = MSI_DatabaseOpenViewW(db, Query, &view);
1908
    if (rc == ERROR_SUCCESS)
1909
    {
1910 1911 1912
        rc = MSI_ViewExecute(view, row);
        MSI_ViewClose(view);
        msiobj_release(&view->hdr);
1913
    }
1914

1915 1916
    if (row)
      msiobj_release(&row->hdr);
1917

1918
    return rc;
1919 1920
}

1921 1922 1923 1924 1925 1926
UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
{
    MSIPACKAGE *package;
    UINT ret;

    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1927
    if( !package )
1928 1929
    {
        HRESULT hr;
1930
        BSTR name = NULL, value = NULL;
1931 1932 1933 1934 1935 1936
        IWineMsiRemotePackage *remote_package;

        remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
        if (!remote_package)
            return ERROR_INVALID_HANDLE;

James Hawkins's avatar
James Hawkins committed
1937 1938
        name = SysAllocString( szName );
        value = SysAllocString( szValue );
1939
        if ((!name && szName) || (!value && szValue))
James Hawkins's avatar
James Hawkins committed
1940 1941 1942 1943 1944 1945
        {
            SysFreeString( name );
            SysFreeString( value );
            IWineMsiRemotePackage_Release( remote_package );
            return ERROR_OUTOFMEMORY;
        }
1946

James Hawkins's avatar
James Hawkins committed
1947 1948 1949 1950 1951
        hr = IWineMsiRemotePackage_SetProperty( remote_package, name, value );

        SysFreeString( name );
        SysFreeString( value );
        IWineMsiRemotePackage_Release( remote_package );
1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963

        if (FAILED(hr))
        {
            if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
                return HRESULT_CODE(hr);

            return ERROR_FUNCTION_FAILED;
        }

        return ERROR_SUCCESS;
    }

1964
    ret = msi_set_property( package->db, szName, szValue );
1965 1966 1967
    if (ret == ERROR_SUCCESS && !strcmpW( szName, cszSourceDir ))
        msi_reset_folders( package, TRUE );

1968 1969 1970 1971
    msiobj_release( &package->hdr );
    return ret;
}

1972
static MSIRECORD *msi_get_property_row( MSIDATABASE *db, LPCWSTR name )
1973
{
1974 1975 1976 1977
    MSIQUERY *view;
    MSIRECORD *rec, *row = NULL;
    UINT r;

1978 1979 1980 1981
    static const WCHAR query[]= {
        'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
        'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
        ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
1982
        '=','?',0};
1983 1984 1985 1986

    if (!name || !*name)
        return NULL;

1987 1988 1989 1990 1991 1992
    rec = MSI_CreateRecord(1);
    if (!rec)
        return NULL;

    MSI_RecordSetStringW(rec, 1, name);

1993
    r = MSI_DatabaseOpenViewW(db, query, &view);
1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
    if (r == ERROR_SUCCESS)
    {
        MSI_ViewExecute(view, rec);
        MSI_ViewFetch(view, &row);
        MSI_ViewClose(view);
        msiobj_release(&view->hdr);
    }

    msiobj_release(&rec->hdr);
    return row;
2004 2005
}

2006
/* internal function, not compatible with MsiGetPropertyW */
2007
UINT msi_get_property( MSIDATABASE *db, LPCWSTR szName,
2008
                       LPWSTR szValueBuf, LPDWORD pchValueBuf )
2009
{
2010 2011 2012
    MSIRECORD *row;
    UINT rc = ERROR_FUNCTION_FAILED;

2013
    row = msi_get_property_row( db, szName );
2014 2015 2016 2017

    if (*pchValueBuf > 0)
        szValueBuf[0] = 0;

2018
    if (row)
2019
    {
2020 2021
        rc = MSI_RecordGetStringW(row, 1, szValueBuf, pchValueBuf);
        msiobj_release(&row->hdr);
2022 2023
    }

2024 2025 2026 2027 2028 2029
    if (rc == ERROR_SUCCESS)
        TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
            debugstr_w(szName));
    else if (rc == ERROR_MORE_DATA)
        TRACE("need %d sized buffer for %s\n", *pchValueBuf,
            debugstr_w(szName));
2030
    else
2031
    {
2032 2033
        *pchValueBuf = 0;
        TRACE("property %s not found\n", debugstr_w(szName));
2034 2035
    }

2036
    return rc;
2037 2038
}

2039
LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop)
2040
{
2041 2042 2043 2044
    DWORD sz = 0;
    LPWSTR str;
    UINT r;

2045
    r = msi_get_property(db, prop, NULL, &sz);
2046 2047
    if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
        return NULL;
2048

2049 2050
    sz++;
    str = msi_alloc(sz * sizeof(WCHAR));
2051
    r = msi_get_property(db, prop, str, &sz);
2052 2053 2054 2055 2056
    if (r != ERROR_SUCCESS)
    {
        msi_free(str);
        str = NULL;
    }
2057

2058
    return str;
2059 2060
}

2061
int msi_get_property_int( MSIDATABASE *db, LPCWSTR prop, int def )
2062
{
2063
    LPWSTR str = msi_dup_property( db, prop );
2064 2065 2066
    int val = str ? atoiW(str) : def;
    msi_free(str);
    return val;
2067 2068
}

2069
static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
2070
                             awstring *szValueBuf, LPDWORD pchValueBuf )
2071 2072
{
    MSIPACKAGE *package;
2073
    MSIRECORD *row = NULL;
2074
    UINT r = ERROR_FUNCTION_FAILED;
2075
    LPCWSTR val = NULL;
2076

2077
    TRACE("%u %s %p %p\n", handle, debugstr_w(name),
2078
          szValueBuf->str.w, pchValueBuf );
2079

2080
    if (!name)
2081
        return ERROR_INVALID_PARAMETER;
2082

2083
    package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE );
2084
    if (!package)
2085 2086 2087 2088
    {
        HRESULT hr;
        IWineMsiRemotePackage *remote_package;
        LPWSTR value = NULL;
James Hawkins's avatar
James Hawkins committed
2089
        BSTR bname;
2090 2091 2092 2093 2094 2095
        DWORD len;

        remote_package = (IWineMsiRemotePackage *)msi_get_remote( handle );
        if (!remote_package)
            return ERROR_INVALID_HANDLE;

James Hawkins's avatar
James Hawkins committed
2096 2097 2098 2099 2100 2101 2102
        bname = SysAllocString( name );
        if (!bname)
        {
            IWineMsiRemotePackage_Release( remote_package );
            return ERROR_OUTOFMEMORY;
        }

2103
        len = 0;
James Hawkins's avatar
James Hawkins committed
2104
        hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, NULL, &len );
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115
        if (FAILED(hr))
            goto done;

        len++;
        value = msi_alloc(len * sizeof(WCHAR));
        if (!value)
        {
            r = ERROR_OUTOFMEMORY;
            goto done;
        }

James Hawkins's avatar
James Hawkins committed
2116
        hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, (BSTR *)value, &len );
2117 2118 2119 2120
        if (FAILED(hr))
            goto done;

        r = msi_strcpy_to_awstring( value, szValueBuf, pchValueBuf );
2121 2122

        /* Bug required by Adobe installers */
2123
        if (!szValueBuf->unicode && !szValueBuf->str.a)
2124
            *pchValueBuf *= sizeof(WCHAR);
2125 2126 2127

done:
        IWineMsiRemotePackage_Release(remote_package);
James Hawkins's avatar
James Hawkins committed
2128
        SysFreeString(bname);
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140
        msi_free(value);

        if (FAILED(hr))
        {
            if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
                return HRESULT_CODE(hr);

            return ERROR_FUNCTION_FAILED;
        }

        return r;
    }
2141

2142
    row = msi_get_property_row( package->db, name );
2143 2144
    if (row)
        val = MSI_RecordGetString( row, 1 );
2145

2146
    if (!val)
2147
        val = szEmpty;
2148 2149 2150

    r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );

2151 2152
    if (row)
        msiobj_release( &row->hdr );
2153 2154 2155
    msiobj_release( &package->hdr );

    return r;
2156 2157
}

2158
UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
2159
                             LPSTR szValueBuf, LPDWORD pchValueBuf )
2160
{
2161 2162 2163
    awstring val;
    LPWSTR name;
    UINT r;
2164

2165 2166
    val.unicode = FALSE;
    val.str.a = szValueBuf;
2167

2168 2169 2170
    name = strdupAtoW( szName );
    if (szName && !name)
        return ERROR_OUTOFMEMORY;
2171

2172 2173 2174 2175
    r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
    msi_free( name );
    return r;
}
2176

2177
UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
2178
                             LPWSTR szValueBuf, LPDWORD pchValueBuf )
2179 2180
{
    awstring val;
2181

2182 2183
    val.unicode = TRUE;
    val.str.w = szValueBuf;
2184

2185
    return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
2186
}
2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240

typedef struct _msi_remote_package_impl {
    const IWineMsiRemotePackageVtbl *lpVtbl;
    MSIHANDLE package;
    LONG refs;
} msi_remote_package_impl;

static inline msi_remote_package_impl* mrp_from_IWineMsiRemotePackage( IWineMsiRemotePackage* iface )
{
    return (msi_remote_package_impl*) iface;
}

static HRESULT WINAPI mrp_QueryInterface( IWineMsiRemotePackage *iface,
                REFIID riid,LPVOID *ppobj)
{
    if( IsEqualCLSID( riid, &IID_IUnknown ) ||
        IsEqualCLSID( riid, &IID_IWineMsiRemotePackage ) )
    {
        IUnknown_AddRef( iface );
        *ppobj = iface;
        return S_OK;
    }

    return E_NOINTERFACE;
}

static ULONG WINAPI mrp_AddRef( IWineMsiRemotePackage *iface )
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );

    return InterlockedIncrement( &This->refs );
}

static ULONG WINAPI mrp_Release( IWineMsiRemotePackage *iface )
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    ULONG r;

    r = InterlockedDecrement( &This->refs );
    if (r == 0)
    {
        MsiCloseHandle( This->package );
        msi_free( This );
    }
    return r;
}

static HRESULT WINAPI mrp_SetMsiHandle( IWineMsiRemotePackage *iface, MSIHANDLE handle )
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    This->package = handle;
    return S_OK;
}

2241
static HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHANDLE *handle )
2242 2243
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264
    IWineMsiRemoteDatabase *rdb = NULL;
    HRESULT hr;
    MSIHANDLE hdb;

    hr = create_msi_remote_database( NULL, (LPVOID *)&rdb );
    if (FAILED(hr) || !rdb)
    {
        ERR("Failed to create remote database\n");
        return hr;
    }

    hdb = MsiGetActiveDatabase(This->package);

    hr = IWineMsiRemoteDatabase_SetMsiHandle( rdb, hdb );
    if (FAILED(hr))
    {
        ERR("Failed to set the database handle\n");
        return hr;
    }

    *handle = alloc_msi_remote_handle( (IUnknown *)rdb );
2265 2266 2267
    return S_OK;
}

2268
static HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR *value, DWORD *size )
2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r;

    r = MsiGetPropertyW(This->package, (LPWSTR)property, (LPWSTR)value, size);
    if (r != ERROR_SUCCESS)
        return HRESULT_FROM_WIN32(r);

    return S_OK;
}

2280
static HRESULT WINAPI mrp_SetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value )
2281 2282
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2283
    UINT r = MsiSetPropertyW(This->package, property, value);
2284 2285 2286
    return HRESULT_FROM_WIN32(r);
}

2287
static HRESULT WINAPI mrp_ProcessMessage( IWineMsiRemotePackage *iface, INSTALLMESSAGE message, MSIHANDLE record )
2288 2289 2290 2291 2292 2293
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiProcessMessage(This->package, message, record);
    return HRESULT_FROM_WIN32(r);
}

2294
static HRESULT WINAPI mrp_DoAction( IWineMsiRemotePackage *iface, BSTR action )
2295 2296
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2297
    UINT r = MsiDoActionW(This->package, action);
2298 2299 2300
    return HRESULT_FROM_WIN32(r);
}

2301
static HRESULT WINAPI mrp_Sequence( IWineMsiRemotePackage *iface, BSTR table, int sequence )
2302 2303
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2304
    UINT r = MsiSequenceW(This->package, table, sequence);
2305 2306 2307
    return HRESULT_FROM_WIN32(r);
}

2308
static HRESULT WINAPI mrp_GetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
2309 2310 2311 2312 2313 2314
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiGetTargetPathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
    return HRESULT_FROM_WIN32(r);
}

2315
static HRESULT WINAPI mrp_SetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value)
2316 2317
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2318
    UINT r = MsiSetTargetPathW(This->package, folder, value);
2319 2320 2321
    return HRESULT_FROM_WIN32(r);
}

2322
static HRESULT WINAPI mrp_GetSourcePath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
2323 2324 2325 2326 2327 2328
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiGetSourcePathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
    return HRESULT_FROM_WIN32(r);
}

2329
static HRESULT WINAPI mrp_GetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL *ret )
2330 2331 2332 2333 2334 2335
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    *ret = MsiGetMode(This->package, mode);
    return S_OK;
}

2336 2337 2338 2339 2340 2341 2342
static HRESULT WINAPI mrp_SetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL state )
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiSetMode(This->package, mode, state);
    return HRESULT_FROM_WIN32(r);
}

2343
static HRESULT WINAPI mrp_GetFeatureState( IWineMsiRemotePackage *iface, BSTR feature,
2344 2345 2346
                                    INSTALLSTATE *installed, INSTALLSTATE *action )
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2347
    UINT r = MsiGetFeatureStateW(This->package, feature, installed, action);
2348 2349 2350
    return HRESULT_FROM_WIN32(r);
}

2351
static HRESULT WINAPI mrp_SetFeatureState( IWineMsiRemotePackage *iface, BSTR feature, INSTALLSTATE state )
2352 2353
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2354
    UINT r = MsiSetFeatureStateW(This->package, feature, state);
2355 2356 2357
    return HRESULT_FROM_WIN32(r);
}

2358
static HRESULT WINAPI mrp_GetComponentState( IWineMsiRemotePackage *iface, BSTR component,
2359 2360 2361
                                      INSTALLSTATE *installed, INSTALLSTATE *action )
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2362
    UINT r = MsiGetComponentStateW(This->package, component, installed, action);
2363 2364 2365
    return HRESULT_FROM_WIN32(r);
}

2366
static HRESULT WINAPI mrp_SetComponentState( IWineMsiRemotePackage *iface, BSTR component, INSTALLSTATE state )
2367 2368
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2369
    UINT r = MsiSetComponentStateW(This->package, component, state);
2370 2371 2372
    return HRESULT_FROM_WIN32(r);
}

2373
static HRESULT WINAPI mrp_GetLanguage( IWineMsiRemotePackage *iface, LANGID *language )
2374 2375 2376 2377 2378 2379
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    *language = MsiGetLanguage(This->package);
    return S_OK;
}

2380
static HRESULT WINAPI mrp_SetInstallLevel( IWineMsiRemotePackage *iface, int level )
2381 2382 2383 2384 2385 2386
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiSetInstallLevel(This->package, level);
    return HRESULT_FROM_WIN32(r);
}

2387
static HRESULT WINAPI mrp_FormatRecord( IWineMsiRemotePackage *iface, MSIHANDLE record,
2388
                                        BSTR *value)
2389
{
2390
    DWORD size = 0;
2391
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2392 2393 2394 2395 2396 2397 2398 2399 2400
    UINT r = MsiFormatRecordW(This->package, record, NULL, &size);
    if (r == ERROR_SUCCESS)
    {
        *value = SysAllocStringLen(NULL, size);
        if (!*value)
            return E_OUTOFMEMORY;
        size++;
        r = MsiFormatRecordW(This->package, record, *value, &size);
    }
2401 2402 2403
    return HRESULT_FROM_WIN32(r);
}

2404
static HRESULT WINAPI mrp_EvaluateCondition( IWineMsiRemotePackage *iface, BSTR condition )
2405 2406
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
2407
    UINT r = MsiEvaluateConditionW(This->package, condition);
2408 2409 2410
    return HRESULT_FROM_WIN32(r);
}

2411 2412 2413 2414 2415 2416 2417 2418
static HRESULT WINAPI mrp_GetFeatureCost( IWineMsiRemotePackage *iface, BSTR feature,
                                          INT cost_tree, INSTALLSTATE state, INT *cost )
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiGetFeatureCostW(This->package, feature, cost_tree, state, cost);
    return HRESULT_FROM_WIN32(r);
}

2419 2420 2421 2422 2423 2424 2425 2426 2427
static const IWineMsiRemotePackageVtbl msi_remote_package_vtbl =
{
    mrp_QueryInterface,
    mrp_AddRef,
    mrp_Release,
    mrp_SetMsiHandle,
    mrp_GetActiveDatabase,
    mrp_GetProperty,
    mrp_SetProperty,
2428
    mrp_ProcessMessage,
2429
    mrp_DoAction,
2430
    mrp_Sequence,
2431
    mrp_GetTargetPath,
2432
    mrp_SetTargetPath,
2433
    mrp_GetSourcePath,
2434
    mrp_GetMode,
2435
    mrp_SetMode,
2436
    mrp_GetFeatureState,
2437
    mrp_SetFeatureState,
2438
    mrp_GetComponentState,
2439
    mrp_SetComponentState,
2440
    mrp_GetLanguage,
2441
    mrp_SetInstallLevel,
2442
    mrp_FormatRecord,
2443
    mrp_EvaluateCondition,
2444
    mrp_GetFeatureCost,
2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462
};

HRESULT create_msi_remote_package( IUnknown *pOuter, LPVOID *ppObj )
{
    msi_remote_package_impl* This;

    This = msi_alloc( sizeof *This );
    if (!This)
        return E_OUTOFMEMORY;

    This->lpVtbl = &msi_remote_package_vtbl;
    This->package = 0;
    This->refs = 1;

    *ppObj = This;

    return S_OK;
}
2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499

UINT msi_package_add_info(MSIPACKAGE *package, DWORD context, DWORD options,
                          LPCWSTR property, LPWSTR value)
{
    MSISOURCELISTINFO *info;

    info = msi_alloc(sizeof(MSISOURCELISTINFO));
    if (!info)
        return ERROR_OUTOFMEMORY;

    info->context = context;
    info->options = options;
    info->property = property;
    info->value = strdupW(value);
    list_add_head(&package->sourcelist_info, &info->entry);

    return ERROR_SUCCESS;
}

UINT msi_package_add_media_disk(MSIPACKAGE *package, DWORD context, DWORD options,
                                DWORD disk_id, LPWSTR volume_label, LPWSTR disk_prompt)
{
    MSIMEDIADISK *disk;

    disk = msi_alloc(sizeof(MSIMEDIADISK));
    if (!disk)
        return ERROR_OUTOFMEMORY;

    disk->context = context;
    disk->options = options;
    disk->disk_id = disk_id;
    disk->volume_label = strdupW(volume_label);
    disk->disk_prompt = strdupW(disk_prompt);
    list_add_head(&package->sourcelist_media, &disk->entry);

    return ERROR_SUCCESS;
}