package.c 56.2 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
static void MSI_FreePackage( MSIOBJECTHDR *arg)
53
{
54
    MSIPACKAGE *package= (MSIPACKAGE*) arg;
55

56 57
    if( package->dialog )
        msi_dialog_destroy( package->dialog );
58

59
    msiobj_release( &package->db->hdr );
60
    ACTION_free_package_structures(package);
61 62
}

63
static UINT create_temp_property_table(MSIPACKAGE *package)
64
{
65
    MSIQUERY *view = NULL;
66
    UINT rc;
67

68 69 70 71
    static const WCHAR CreateSql[] = {
       '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',
72 73 74 75 76
       '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',
        '`',')',0};
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

    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)
{
    MSIQUERY *view = NULL;
    UINT rc;

93 94 95 96 97 98 99 100 101 102 103 104 105 106
    static const WCHAR Query[] = {
       'S','E','L','E','C','T',' ','*',' ',
       'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0};
    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};

    /* clone the existing properties */
    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
    if (rc != ERROR_SUCCESS)
        return rc;
107

108 109
    rc = MSI_ViewExecute(view, 0);
    if (rc != ERROR_SUCCESS)
110
    {
111
        MSI_ViewClose(view);
112
        msiobj_release(&view->hdr);
113
        return rc;
114
    }
115 116 117 118 119 120 121 122 123 124 125

    while (1)
    {
        MSIRECORD *row;
        MSIQUERY *view2;

        rc = MSI_ViewFetch(view, &row);
        if (rc != ERROR_SUCCESS)
            break;

        rc = MSI_DatabaseOpenViewW(package->db, Insert, &view2);
126 127 128
        if (rc != ERROR_SUCCESS)
        {
            msiobj_release(&row->hdr);
129
            continue;
130
        }
131

132
        MSI_ViewExecute(view2, row);
133 134
        MSI_ViewClose(view2);
        msiobj_release(&view2->hdr);
135
        msiobj_release(&row->hdr);
136 137 138 139 140 141
    }

    MSI_ViewClose(view);
    msiobj_release(&view->hdr);

    return rc;
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
/*
 * 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 )
{
    static const WCHAR szInstalled[] = {
        'I','n','s','t','a','l','l','e','d',0 };
    WCHAR val[2] = { '1', 0 };
    HKEY hkey = 0;
    UINT r;

    r = MSIREG_OpenUninstallKey( package->ProductCode, &hkey, FALSE );
    if (r == ERROR_SUCCESS)
    {
        RegCloseKey( hkey );
        MSI_SetPropertyW( package, szInstalled, val );
    }

    return r;
}

168 169 170 171
static UINT set_user_sid_prop( MSIPACKAGE *package )
{
    SID_NAME_USE use;
    LPWSTR user_name;
172
    LPWSTR sid_str = NULL, dom = NULL;
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
    DWORD size, dom_size;
    PSID psid = NULL;
    UINT r = ERROR_FUNCTION_FAILED;

    static const WCHAR user_sid[] = {'U','s','e','r','S','I','D',0};

    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 );
194
    dom = msi_alloc( dom_size*sizeof (WCHAR) );
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
    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;

    r = MSI_SetPropertyW( package, user_sid, sid_str );

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

    return r;
}

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 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
static LPWSTR get_fusion_filename(MSIPACKAGE *package)
{
    HKEY netsetup;
    LONG res;
    LPWSTR file;
    DWORD index = 0, size;
    WCHAR ver[MAX_PATH];
    WCHAR name[MAX_PATH];
    WCHAR windir[MAX_PATH];

    static const WCHAR backslash[] = {'\\',0};
    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;

    ver[0] = '\0';
    size = MAX_PATH;
    while (RegEnumKeyExW(netsetup, index, name, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
    {
        index++;
        if (lstrcmpW(ver, name) < 0)
            lstrcpyW(ver, name);
    }

    RegCloseKey(netsetup);

    if (!index)
        return NULL;

    GetWindowsDirectoryW(windir, MAX_PATH);

    size = lstrlenW(windir) + lstrlenW(subdir) + lstrlenW(ver) +lstrlenW(fusion) + 3;
    file = msi_alloc(size * sizeof(WCHAR));
    if (!file)
        return NULL;

    lstrcpyW(file, windir);
    lstrcatW(file, backslash);
    lstrcatW(file, subdir);
    lstrcatW(file, ver);
    lstrcatW(file, backslash);
    lstrcatW(file, fusion);

    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;

    MSI_SetPropertyW(package, netasm, verstr);

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

335
static VOID set_installer_properties(MSIPACKAGE *package)
336 337
{
    WCHAR pth[MAX_PATH];
Aric Stewart's avatar
Aric Stewart committed
338
    WCHAR *ptr;
339
    OSVERSIONINFOEXW OSVersion;
340
    MEMORYSTATUSEX msex;
341
    DWORD verval;
342 343
    WCHAR verstr[10], bufstr[20];
    HDC dc;
344
    HKEY hkey;
345
    LPWSTR username, companyname;
346 347
    SYSTEM_INFO sys_info;
    SYSTEMTIME systemtime;
348
    LANGID langid;
349 350 351 352 353 354 355 356

    static const WCHAR cszbs[]={'\\',0};
    static const WCHAR CFF[] = 
{'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
    static const WCHAR PFF[] = 
{'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
    static const WCHAR CADF[] = 
{'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
    static const WCHAR FaF[] = 
{'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
    static const WCHAR FoF[] = 
{'F','o','n','t','s','F','o','l','d','e','r',0};
    static const WCHAR SendTF[] = 
{'S','e','n','d','T','o','F','o','l','d','e','r',0};
    static const WCHAR SMF[] = 
{'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
    static const WCHAR StF[] = 
{'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
    static const WCHAR TemplF[] = 
{'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
    static const WCHAR DF[] = 
{'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
    static const WCHAR PMF[] = 
{'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
373 374 375 376 377 378
    static const WCHAR ATF[] = 
{'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
    static const WCHAR ADF[] = 
{'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
    static const WCHAR SF[] = 
{'S','y','s','t','e','m','F','o','l','d','e','r',0};
379 380
    static const WCHAR SF16[] = 
{'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
381 382 383 384 385 386 387 388
    static const WCHAR LADF[] = 
{'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
    static const WCHAR MPF[] = 
{'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
    static const WCHAR PF[] = 
{'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
    static const WCHAR WF[] = 
{'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
Aric Stewart's avatar
Aric Stewart committed
389 390
    static const WCHAR WV[] = 
{'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
391 392
    static const WCHAR TF[]=
{'T','e','m','p','F','o','l','d','e','r',0};
393 394 395 396 397 398 399 400
    static const WCHAR szAdminUser[] =
{'A','d','m','i','n','U','s','e','r',0};
    static const WCHAR szPriv[] =
{'P','r','i','v','i','l','e','g','e','d',0};
    static const WCHAR szOne[] =
{'1',0};
    static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 };
    static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 };
401
    static const WCHAR szMsiNTProductType[] = { 'M','s','i','N','T','P','r','o','d','u','c','t','T','y','p','e',0 };
402 403 404 405 406 407 408
    static const WCHAR szFormat[] = {'%','l','i',0};
    static const WCHAR szWinBuild[] =
{'W','i','n','d','o','w','s','B','u','i','l','d', 0 };
    static const WCHAR szSPL[] = 
{'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 };
    static const WCHAR szSix[] = {'6',0 };

409
    static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
410
    static const WCHAR szVersionDatabase[] = { 'V','e','r','s','i','o','n','D','a','t','a','b','a','s','e',0 };
411
    static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 };
412
    static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
413 414 415 416
/* Screen properties */
    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};
417
    static const WCHAR szIntFormat[] = {'%','d',0};
418
    static const WCHAR szIntel[] = { 'I','n','t','e','l',0 };
419 420 421 422 423 424 425 426
    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 };
427 428 429 430 431 432 433 434 435 436 437 438
    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};
    static const WCHAR szRegisteredOrg[] = {
        '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};
439 440
    static const WCHAR szDate[] = {'D','a','t','e',0};
    static const WCHAR szTime[] = {'T','i','m','e',0};
441
    static const WCHAR szUserLangID[] = {'U','s','e','r','L','a','n','g','u','a','g','e','I','D',0};
442

443 444 445 446
    /*
     * Other things that probably should be set:
     *
     * SystemLanguageID ComputerName UserLanguageID LogonUser VirtualMemory
447
     * ShellAdvSupport DefaultUIFont PackagecodeChanging
448
     * ProductState CaptionHeight BorderTop BorderSide TextHeight
449
     * RedirectedDllSupport
450
     */
451 452 453

    SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
    strcatW(pth,cszbs);
454
    MSI_SetPropertyW(package, CFF, pth);
455 456 457

    SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
    strcatW(pth,cszbs);
458
    MSI_SetPropertyW(package, PFF, pth);
459 460 461

    SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
    strcatW(pth,cszbs);
462
    MSI_SetPropertyW(package, CADF, pth);
463

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
    SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth);
    strcatW(pth,cszbs);
    MSI_SetPropertyW(package, FaF, pth);

    SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth);
    strcatW(pth,cszbs);
    MSI_SetPropertyW(package, FoF, pth);

    SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth);
    strcatW(pth,cszbs);
    MSI_SetPropertyW(package, SendTF, pth);

    SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth);
    strcatW(pth,cszbs);
    MSI_SetPropertyW(package, SMF, pth);

    SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth);
    strcatW(pth,cszbs);
    MSI_SetPropertyW(package, StF, pth);

    SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth);
    strcatW(pth,cszbs);
    MSI_SetPropertyW(package, TemplF, pth);

    SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth);
    strcatW(pth,cszbs);
    MSI_SetPropertyW(package, DF, pth);

    SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth);
    strcatW(pth,cszbs);
    MSI_SetPropertyW(package, PMF, pth);

496 497
    SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
    strcatW(pth,cszbs);
498
    MSI_SetPropertyW(package, ATF, pth);
499 500 501

    SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
    strcatW(pth,cszbs);
502
    MSI_SetPropertyW(package, ADF, pth);
503 504 505

    SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
    strcatW(pth,cszbs);
506
    MSI_SetPropertyW(package, SF, pth);
507
    MSI_SetPropertyW(package, SF16, pth);
508 509 510

    SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
    strcatW(pth,cszbs);
511
    MSI_SetPropertyW(package, LADF, pth);
512 513 514

    SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
    strcatW(pth,cszbs);
515
    MSI_SetPropertyW(package, MPF, pth);
516 517 518

    SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
    strcatW(pth,cszbs);
519
    MSI_SetPropertyW(package, PF, pth);
520 521 522

    SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
    strcatW(pth,cszbs);
523
    MSI_SetPropertyW(package, WF, pth);
524 525 526 527
    
    /* Physical Memory is specified in MB. Using total amount. */
    msex.dwLength = sizeof(msex);
    GlobalMemoryStatusEx( &msex );
528
    sprintfW( bufstr, szIntFormat, (int)(msex.ullTotalPhys/1024/1024));
529
    MSI_SetPropertyW(package, szPhysicalMemory, bufstr);
530

Aric Stewart's avatar
Aric Stewart committed
531 532 533
    SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
    ptr = strchrW(pth,'\\');
    if (ptr)
534
	*(ptr+1) = 0;
Aric Stewart's avatar
Aric Stewart committed
535 536
    MSI_SetPropertyW(package, WV, pth);
    
537
    GetTempPathW(MAX_PATH,pth);
538
    MSI_SetPropertyW(package, TF, pth);
539

540

541 542 543
    /* in a wine environment the user is always admin and privileged */
    MSI_SetPropertyW(package,szAdminUser,szOne);
    MSI_SetPropertyW(package,szPriv,szOne);
544 545

    /* set the os things */
546 547
    OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
    GetVersionExW((OSVERSIONINFOW *)&OSVersion);
548
    verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
549
    sprintfW(verstr,szFormat,verval);
550 551 552
    switch (OSVersion.dwPlatformId)
    {
        case VER_PLATFORM_WIN32_WINDOWS:    
553
            MSI_SetPropertyW(package,v9x,verstr);
554 555
            break;
        case VER_PLATFORM_WIN32_NT:
556
            MSI_SetPropertyW(package,vNT,verstr);
557 558
            sprintfW(verstr,szFormat,OSVersion.wProductType);
            MSI_SetPropertyW(package,szMsiNTProductType,verstr);
559 560
            break;
    }
561 562
    sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
    MSI_SetPropertyW(package,szWinBuild,verstr);
563
    /* just fudge this */
564
    MSI_SetPropertyW(package,szSPL,szSix);
565

566 567
    sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
    MSI_SetPropertyW( package, szVersionMsi, bufstr );
568 569
    sprintfW( bufstr, szFormat, MSI_MAJORVERSION * 100);
    MSI_SetPropertyW( package, szVersionDatabase, bufstr );
570

571
    GetSystemInfo( &sys_info );
572
    if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
573
    {
574
        sprintfW( bufstr, szIntFormat, sys_info.wProcessorLevel );
575 576 577
        MSI_SetPropertyW( package, szIntel, bufstr );
    }

578 579
    /* Screen properties. */
    dc = GetDC(0);
580
    sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, HORZRES ) );
581
    MSI_SetPropertyW( package, szScreenX, bufstr );
582
    sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, VERTRES ));
583
    MSI_SetPropertyW( package, szScreenY, bufstr );
584
    sprintfW( bufstr, szIntFormat, GetDeviceCaps( dc, BITSPIXEL ));
585 586
    MSI_SetPropertyW( package, szColorBits, bufstr );
    ReleaseDC(0, dc);
587 588

    /* USERNAME and COMPANYNAME */
589 590
    username = msi_dup_property( package, szUSERNAME );
    companyname = msi_dup_property( package, szCOMPANYNAME );
591

592 593
    if ((!username || !companyname) &&
        RegOpenKeyW( HKEY_CURRENT_USER, szUserInfo, &hkey ) == ERROR_SUCCESS)
594
    {
595 596 597 598 599 600 601
        if (!username &&
            (username = msi_reg_get_val_str( hkey, szDefName )))
            MSI_SetPropertyW( package, szUSERNAME, username );
        if (!companyname &&
            (companyname = msi_reg_get_val_str( hkey, szDefCompany )))
            MSI_SetPropertyW( package, szCOMPANYNAME, companyname );
        CloseHandle( hkey );
602
    }
603 604
    if ((!username || !companyname) &&
        RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey ) == ERROR_SUCCESS)
605
    {
606 607 608 609 610 611 612
        if (!username &&
            (username = msi_reg_get_val_str( hkey, szRegisteredUser )))
            MSI_SetPropertyW( package, szUSERNAME, username );
        if (!companyname &&
            (companyname = msi_reg_get_val_str( hkey, szRegisteredOrg )))
            MSI_SetPropertyW( package, szCOMPANYNAME, companyname );
        CloseHandle( hkey );
613
    }
614 615
    msi_free( username );
    msi_free( companyname );
616

617 618 619
    if ( set_user_sid_prop( package ) != ERROR_SUCCESS)
        ERR("Failed to set the UserSID property\n");

620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
    /* Date and time properties */
    GetSystemTime( &systemtime );
    if (GetDateFormatW( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systemtime,
                        NULL, bufstr, sizeof(bufstr)/sizeof(bufstr[0]) ))
        MSI_SetPropertyW( package, szDate, bufstr );
    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]) ))
        MSI_SetPropertyW( package, szTime, bufstr );
    else
        ERR("Couldn't set Time property: GetTimeFormat failed with error %d\n", GetLastError());

636 637
    set_msi_assembly_prop( package );

638 639 640 641
    langid = GetUserDefaultLangID();
    sprintfW(bufstr, szIntFormat, langid);

    MSI_SetPropertyW( package, szUserLangID, bufstr );
642
}
643

644
static UINT msi_load_summary_properties( MSIPACKAGE *package )
645 646 647 648
{
    UINT rc;
    MSIHANDLE suminfo;
    MSIHANDLE hdb = alloc_msihandle( &package->db->hdr );
649
    INT count;
650 651 652 653
    DWORD len;
    LPWSTR package_code;
    static const WCHAR szPackageCode[] = {
        'P','a','c','k','a','g','e','C','o','d','e',0};
654

655 656
    if (!hdb) {
        ERR("Unable to allocate handle\n");
657
        return ERROR_OUTOFMEMORY;
658
    }
659

660 661 662 663 664
    rc = MsiGetSummaryInformationW( hdb, NULL, 0, &suminfo );
    MsiCloseHandle(hdb);
    if (rc != ERROR_SUCCESS)
    {
        ERR("Unable to open Summary Information\n");
665
        return rc;
666 667
    }

668 669 670 671
    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_PAGECOUNT, NULL,
                                     &count, NULL, NULL, NULL );
    if (rc != ERROR_SUCCESS)
    {
672
        WARN("Unable to query page count: %d\n", rc);
673 674
        goto done;
    }
675 676 677 678 679

    /* load package code property */
    len = 0;
    rc = MsiSummaryInfoGetPropertyW( suminfo, PID_REVNUMBER, NULL,
                                     NULL, NULL, NULL, &len );
680
    if (rc != ERROR_MORE_DATA)
681
    {
682 683 684
        WARN("Unable to query revision number: %d\n", rc);
        rc = ERROR_FUNCTION_FAILED;
        goto done;
685 686
    }

687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
    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;
    }

    MSI_SetPropertyW( package, szPackageCode, package_code );
    msi_free( package_code );

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

done:
707
    MsiCloseHandle(suminfo);
708
    return rc;
709 710
}

711
static MSIPACKAGE *msi_alloc_package( void )
712
{
713
    MSIPACKAGE *package;
714

715 716
    package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
                               MSI_FreePackage );
717
    if( package )
718
    {
719
        list_init( &package->components );
720
        list_init( &package->features );
721
        list_init( &package->files );
722
        list_init( &package->tempfiles );
723
        list_init( &package->folders );
724
        list_init( &package->subscriptions );
725
        list_init( &package->appids );
726
        list_init( &package->classes );
727
        list_init( &package->mimes );
728
        list_init( &package->extensions );
729
        list_init( &package->progids );
730
        list_init( &package->RunningActions );
731 732
        list_init( &package->sourcelist_info );
        list_init( &package->sourcelist_media );
733

734
        package->patch = NULL;
735 736 737 738
        package->ActionFormat = NULL;
        package->LastAction = NULL;
        package->dialog = NULL;
        package->next_dialog = NULL;
739 740 741
        package->scheduled_action_running = FALSE;
        package->commit_action_running = FALSE;
        package->rollback_action_running = FALSE;
742 743 744 745 746
    }

    return package;
}

747 748 749 750 751 752 753 754 755 756 757
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;

758
    r = msi_parse_command_line(package, (WCHAR *)data, TRUE);
759 760 761 762 763

    msi_free(data);
    return r;
}

764
MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPCWSTR base_url )
765 766 767 768 769 770 771
{
    static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
    static const WCHAR szpi[] = {'%','i',0};
    static const WCHAR szProductCode[] = {
        'P','r','o','d','u','c','t','C','o','d','e',0};
    MSIPACKAGE *package;
    WCHAR uilevel[10];
772
    UINT r;
773 774 775 776 777 778 779 780 781

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

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

782
        package->WordCount = 0;
783
        package->PackagePath = strdupW( db->path );
784
        package->BaseURL = strdupW( base_url );
785

786 787
        create_temp_property_table( package );
        msi_clone_properties( package );
788 789 790
        set_installer_properties(package);
        sprintfW(uilevel,szpi,gUILevel);
        MSI_SetPropertyW(package, szLevel, uilevel);
791 792 793

        package->ProductCode = msi_dup_property( package, szProductCode );
        set_installed_prop( package );
794 795 796 797 798 799
        r = msi_load_summary_properties( package );
        if (r != ERROR_SUCCESS)
        {
            msiobj_release( &package->hdr );
            return NULL;
        }
800

801
        if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
802
            msi_load_admin_properties( package );
803 804
    }

805
    return package;
806 807
}

808 809 810 811 812 813 814 815 816 817 818 819 820
/*
 * 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.
 */ 
static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
{
    WCHAR path[MAX_PATH];
821
    static const WCHAR szMSI[] = {'m','s','i',0};
822 823 824 825 826 827

    GetTempPathW( MAX_PATH, path );
    GetTempFileNameW( path, szMSI, 0, filename );

    if( !CopyFileW( szPackage, filename, FALSE ) )
    {
828
        DeleteFileW( filename );
829
        ERR("failed to copy package %s\n", debugstr_w(szPackage) );
830 831 832 833 834 835 836
        return szPackage;
    }

    TRACE("Opening relocated package %s\n", debugstr_w( filename ));
    return filename;
}

837
LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename )
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
{
    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 )
    {
        cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
        if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
        {
            HeapFree( GetProcessHeap(), 0, cache_entry );
            return szUrl;
        }

        lstrcpyW( filename, cache_entry->lpszLocalFileName );
        HeapFree( GetProcessHeap(), 0, cache_entry );
        return filename;
    }

    hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
    if ( FAILED(hr) )
        return szUrl;

    return filename;
}

869 870
UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
{
871 872 873
    static const WCHAR OriginalDatabase[] =
        {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
    static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
874
    MSIDATABASE *db = NULL;
875
    MSIPACKAGE *package;
876
    MSIHANDLE handle;
877
    LPWSTR ptr, base_url = NULL;
878
    UINT r;
879 880
    WCHAR temppath[MAX_PATH];
    LPCWSTR file = szPackage;
881

882 883 884 885 886 887 888
    TRACE("%s %p\n", debugstr_w(szPackage), pPackage);

    if( szPackage[0] == '#' )
    {
        handle = atoiW(&szPackage[1]);
        db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
        if( !db )
889 890 891 892 893 894 895 896 897 898 899 900
        {
            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;
        }
901 902 903
    }
    else
    {
904
        if ( UrlIsW( szPackage, URLIS_URL ) )
905
        {
906
            file = msi_download_file( szPackage, temppath );
907 908 909 910 911 912 913 914

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

            ptr = strrchrW( base_url, '/' );
            if (ptr) *(ptr + 1) = '\0';
        }
915 916
        else
            file = copy_package_to_temp( szPackage, temppath );
917 918

        r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &db );
919
        if( r != ERROR_SUCCESS )
920
        {
921 922
            if (file != szPackage)
                DeleteFileW( file );
923

924 925 926
            if (GetFileAttributesW(szPackage) == INVALID_FILE_ATTRIBUTES)
                return ERROR_FILE_NOT_FOUND;

927
            return r;
928
        }
929 930
    }

931 932
    package = MSI_CreatePackage( db, base_url );
    msi_free( base_url );
933 934
    msiobj_release( &db->hdr );
    if( !package )
935 936 937
    {
        if (file != szPackage)
            DeleteFileW( file );
938 939

        return ERROR_INSTALL_PACKAGE_INVALID;
940 941 942 943
    }

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

945 946
    MSI_SetPropertyW( package, Database, db->path );

947
    if( UrlIsW( szPackage, URLIS_URL ) )
948
        MSI_SetPropertyW( package, OriginalDatabase, szPackage );
949 950
    else if( szPackage[0] == '#' )
        MSI_SetPropertyW( package, OriginalDatabase, db->path );
951 952
    else
    {
953 954 955 956
        WCHAR fullpath[MAX_PATH];

        GetFullPathNameW( szPackage, MAX_PATH, fullpath, NULL );
        MSI_SetPropertyW( package, OriginalDatabase, fullpath );
957
    }
958

959
    *pPackage = package;
960

961
    return ERROR_SUCCESS;
962
}
963

964
UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
965 966 967
{
    MSIPACKAGE *package = NULL;
    UINT ret;
968

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

971
    if( !szPackage || !phPackage )
972 973
        return ERROR_INVALID_PARAMETER;

974 975
    if ( !*szPackage )
    {
976
        FIXME("Should create an empty database and package\n");
977 978 979
        return ERROR_FUNCTION_FAILED;
    }

980
    if( dwOptions )
981
        FIXME("dwOptions %08x not supported\n", dwOptions);
982

983
    ret = MSI_OpenPackageW( szPackage, &package );
984 985 986
    if( ret == ERROR_SUCCESS )
    {
        *phPackage = alloc_msihandle( &package->hdr );
987 988
        if (! *phPackage)
            ret = ERROR_NOT_ENOUGH_MEMORY;
989 990
        msiobj_release( &package->hdr );
    }
991

992
    return ret;
993 994
}

995 996 997 998 999
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
{
    return MsiOpenPackageExW( szPackage, 0, phPackage );
}

1000 1001
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
1002
    LPWSTR szwPack = NULL;
1003
    UINT ret;
1004 1005 1006

    if( szPackage )
    {
1007 1008 1009
        szwPack = strdupAtoW( szPackage );
        if( !szwPack )
            return ERROR_OUTOFMEMORY;
1010 1011 1012 1013
    }

    ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );

1014
    msi_free( szwPack );
1015 1016

    return ret;
1017 1018
}

1019
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
1020
{
1021
    return MsiOpenPackageExA( szPackage, 0, phPackage );
1022 1023 1024 1025 1026
}

MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
{
    MSIPACKAGE *package;
1027
    MSIHANDLE handle = 0;
1028
    IWineMsiRemotePackage *remote_package;
1029

1030
    TRACE("(%d)\n",hInstall);
1031 1032

    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1033 1034 1035 1036 1037
    if( package)
    {
        handle = alloc_msihandle( &package->db->hdr );
        msiobj_release( &package->hdr );
    }
1038 1039 1040 1041 1042
    else if ((remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall )))
    {
        IWineMsiRemotePackage_GetActiveDatabase(remote_package, &handle);
        IWineMsiRemotePackage_Release(remote_package);
    }
1043

1044
    return handle;
1045 1046
}

1047 1048
INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
                               MSIRECORD *record)
1049
{
1050 1051 1052 1053 1054 1055
    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};
1056
    DWORD log_type = 0;
1057
    LPWSTR message;
1058
    DWORD sz;
1059 1060
    DWORD total_size = 0;
    INT i;
Aric Stewart's avatar
Aric Stewart committed
1061
    INT rc;
1062 1063
    char *msg;
    int len;
Aric Stewart's avatar
Aric Stewart committed
1064

1065
    TRACE("%x\n", eMessageType);
Aric Stewart's avatar
Aric Stewart committed
1066
    rc = 0;
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081

    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;
1082 1083 1084
    /* just a guess */
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
        log_type |= 0x800;
1085

1086 1087 1088
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
    {
        static const WCHAR template_s[]=
1089
            {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ',0};
1090 1091 1092
        static const WCHAR format[] = 
            {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
        WCHAR timet[0x100];
1093 1094
        LPCWSTR action_text, action;
        LPWSTR deformatted = NULL;
1095 1096 1097 1098 1099

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

        action = MSI_RecordGetString(record, 1);
        action_text = MSI_RecordGetString(record, 2);
1100 1101 1102 1103

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

1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
        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);
1114 1115
    }
    else
1116
    {
1117 1118 1119 1120 1121
        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++)
1122
        {
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
            LPWSTR tmp;
            WCHAR number[3];
            static const WCHAR format[] = { '%','i',':',' ',0};
            static const WCHAR space[] = { ' ',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)
                strcatW(message,space);

            msi_free(tmp);
1146 1147 1148
        }
    }

1149
    TRACE("(%p %x %x %s)\n", gUIHandlerA, gUIFilter, log_type,
1150 1151 1152 1153 1154
                             debugstr_w(message));

    /* convert it to ASCII */
    len = WideCharToMultiByte( CP_ACP, 0, message, -1,
                               NULL, 0, NULL, NULL );
1155
    msg = msi_alloc( len );
1156 1157
    WideCharToMultiByte( CP_ACP, 0, message, -1,
                         msg, len, NULL, NULL );
1158

1159
    if (gUIHandlerA && (gUIFilter & log_type))
1160
    {
1161
        rc = gUIHandlerA(gUIContext,eMessageType,msg);
1162
    }
Aric Stewart's avatar
Aric Stewart committed
1163 1164 1165 1166 1167 1168 1169

    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);
1170

Aric Stewart's avatar
Aric Stewart committed
1171 1172 1173
        if (log_file != INVALID_HANDLE_VALUE)
        {
            SetFilePointer(log_file,0, NULL, FILE_END);
1174
            WriteFile(log_file,msg,strlen(msg),&write,NULL);
Aric Stewart's avatar
Aric Stewart committed
1175 1176 1177 1178
            WriteFile(log_file,"\n",1,&write,NULL);
            CloseHandle(log_file);
        }
    }
1179
    msi_free( msg );
1180

1181
    msi_free( message);
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211

    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;
    }

1212 1213 1214
    return ERROR_SUCCESS;
}

1215 1216 1217 1218 1219 1220 1221 1222 1223
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 )
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
    {
        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;
    }
1246 1247 1248 1249 1250 1251 1252 1253

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

    ret = MSI_ProcessMessage( package, eMessageType, record );

out:
1254
    msiobj_release( &package->hdr );
1255 1256 1257 1258 1259 1260
    if( record )
        msiobj_release( &record->hdr );

    return ret;
}

1261
/* property code */
1262

1263
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
1264 1265
{
    LPWSTR szwName = NULL, szwValue = NULL;
1266
    UINT r = ERROR_OUTOFMEMORY;
1267

1268 1269 1270
    szwName = strdupAtoW( szName );
    if( szName && !szwName )
        goto end;
1271

1272 1273 1274
    szwValue = strdupAtoW( szValue );
    if( szValue && !szwValue )
        goto end;
1275

1276
    r = MsiSetPropertyW( hInstall, szwName, szwValue);
1277 1278

end:
1279 1280
    msi_free( szwName );
    msi_free( szwValue );
1281

1282
    return r;
1283 1284
}

1285
UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
1286
{
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
    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};
1308

1309 1310 1311 1312 1313
    TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue));

    if (!szName)
        return ERROR_INVALID_PARAMETER;

1314
    /* this one is weird... */
1315 1316
    if (!szName[0])
        return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
1317

1318 1319 1320 1321 1322 1323 1324 1325
    rc = MSI_GetPropertyW(package, szName, 0, &sz);
    if (!szValue || !*szValue)
    {
        sprintfW(Query, Delete, szName);
    }
    else if (rc == ERROR_MORE_DATA || rc == ERROR_SUCCESS)
    {
        sprintfW(Query, Update, szName);
1326

1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
        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);
    }
1338

1339 1340
    rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
    if (rc == ERROR_SUCCESS)
1341
    {
1342 1343 1344
        rc = MSI_ViewExecute(view, row);
        MSI_ViewClose(view);
        msiobj_release(&view->hdr);
1345
    }
1346

1347
    msiobj_release(&row->hdr);
1348

1349 1350 1351
    if (rc == ERROR_SUCCESS && (!lstrcmpW(szName, cszSourceDir)))
        msi_reset_folders(package, TRUE);

1352
    return rc;
1353 1354
}

1355 1356 1357 1358 1359 1360
UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
{
    MSIPACKAGE *package;
    UINT ret;

    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1361
    if( !package )
1362 1363
    {
        HRESULT hr;
1364
        BSTR name = NULL, value = NULL;
1365 1366 1367 1368 1369 1370
        IWineMsiRemotePackage *remote_package;

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

James Hawkins's avatar
James Hawkins committed
1371 1372
        name = SysAllocString( szName );
        value = SysAllocString( szValue );
1373
        if ((!name && szName) || (!value && szValue))
James Hawkins's avatar
James Hawkins committed
1374 1375 1376 1377 1378 1379
        {
            SysFreeString( name );
            SysFreeString( value );
            IWineMsiRemotePackage_Release( remote_package );
            return ERROR_OUTOFMEMORY;
        }
1380

James Hawkins's avatar
James Hawkins committed
1381 1382 1383 1384 1385
        hr = IWineMsiRemotePackage_SetProperty( remote_package, name, value );

        SysFreeString( name );
        SysFreeString( value );
        IWineMsiRemotePackage_Release( remote_package );
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397

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

            return ERROR_FUNCTION_FAILED;
        }

        return ERROR_SUCCESS;
    }

1398 1399 1400 1401 1402
    ret = MSI_SetPropertyW( package, szName, szValue);
    msiobj_release( &package->hdr );
    return ret;
}

1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name )
{
    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','`',
        '=','\'','%','s','\'',0};

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

    return MSI_QueryGetRecord( package->db, query, name );
}

1417 1418
/* internal function, not compatible with MsiGetPropertyW */
UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName, 
1419
                       LPWSTR szValueBuf, LPDWORD pchValueBuf )
1420
{
1421 1422 1423 1424
    MSIRECORD *row;
    UINT rc = ERROR_FUNCTION_FAILED;

    row = MSI_GetPropertyRow( package, szName );
1425 1426 1427 1428

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

1429
    if (row)
1430
    {
1431 1432
        rc = MSI_RecordGetStringW(row, 1, szValueBuf, pchValueBuf);
        msiobj_release(&row->hdr);
1433 1434
    }

1435 1436 1437 1438 1439 1440
    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));
1441
    else
1442
    {
1443 1444
        *pchValueBuf = 0;
        TRACE("property %s not found\n", debugstr_w(szName));
1445 1446
    }

1447
    return rc;
1448 1449
}

1450
LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop)
1451
{
1452 1453 1454 1455 1456 1457 1458
    DWORD sz = 0;
    LPWSTR str;
    UINT r;

    r = MSI_GetPropertyW(package, prop, NULL, &sz);
    if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
        return NULL;
1459

1460 1461 1462 1463 1464 1465 1466 1467
    sz++;
    str = msi_alloc(sz * sizeof(WCHAR));
    r = MSI_GetPropertyW(package, prop, str, &sz);
    if (r != ERROR_SUCCESS)
    {
        msi_free(str);
        str = NULL;
    }
1468

1469
    return str;
1470 1471
}

1472
int msi_get_property_int(MSIPACKAGE *package, LPCWSTR prop, int def)
1473
{
1474 1475 1476 1477
    LPWSTR str = msi_dup_property(package, prop);
    int val = str ? atoiW(str) : def;
    msi_free(str);
    return val;
1478 1479
}

1480
static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
1481
                             awstring *szValueBuf, LPDWORD pchValueBuf )
1482
{
1483
    static const WCHAR empty[] = {0};
1484
    MSIPACKAGE *package;
1485
    MSIRECORD *row = NULL;
1486
    UINT r = ERROR_FUNCTION_FAILED;
1487
    LPCWSTR val = NULL;
1488

1489
    TRACE("%u %s %p %p\n", handle, debugstr_w(name),
1490
          szValueBuf->str.w, pchValueBuf );
1491

1492
    if (!name)
1493
        return ERROR_INVALID_PARAMETER;
1494

1495
    package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE );
1496
    if (!package)
1497 1498 1499 1500
    {
        HRESULT hr;
        IWineMsiRemotePackage *remote_package;
        LPWSTR value = NULL;
James Hawkins's avatar
James Hawkins committed
1501
        BSTR bname;
1502 1503 1504 1505 1506 1507
        DWORD len;

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

James Hawkins's avatar
James Hawkins committed
1508 1509 1510 1511 1512 1513 1514
        bname = SysAllocString( name );
        if (!bname)
        {
            IWineMsiRemotePackage_Release( remote_package );
            return ERROR_OUTOFMEMORY;
        }

1515
        len = 0;
James Hawkins's avatar
James Hawkins committed
1516
        hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, NULL, &len );
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
        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
1528
        hr = IWineMsiRemotePackage_GetProperty( remote_package, bname, (BSTR *)value, &len );
1529 1530 1531 1532
        if (FAILED(hr))
            goto done;

        r = msi_strcpy_to_awstring( value, szValueBuf, pchValueBuf );
1533 1534

        /* Bug required by Adobe installers */
1535
        if (!szValueBuf->unicode && !szValueBuf->str.a)
1536
            *pchValueBuf *= sizeof(WCHAR);
1537 1538 1539

done:
        IWineMsiRemotePackage_Release(remote_package);
James Hawkins's avatar
James Hawkins committed
1540
        SysFreeString(bname);
1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
        msi_free(value);

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

            return ERROR_FUNCTION_FAILED;
        }

        return r;
    }
1553

1554 1555 1556
    row = MSI_GetPropertyRow( package, name );
    if (row)
        val = MSI_RecordGetString( row, 1 );
1557

1558 1559 1560 1561 1562
    if (!val)
        val = empty;

    r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );

1563 1564
    if (row)
        msiobj_release( &row->hdr );
1565 1566 1567
    msiobj_release( &package->hdr );

    return r;
1568 1569
}

1570
UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
1571
                             LPSTR szValueBuf, LPDWORD pchValueBuf )
1572
{
1573 1574 1575
    awstring val;
    LPWSTR name;
    UINT r;
1576

1577 1578
    val.unicode = FALSE;
    val.str.a = szValueBuf;
1579

1580 1581 1582
    name = strdupAtoW( szName );
    if (szName && !name)
        return ERROR_OUTOFMEMORY;
1583

1584 1585 1586 1587
    r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
    msi_free( name );
    return r;
}
1588

1589
UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
1590
                             LPWSTR szValueBuf, LPDWORD pchValueBuf )
1591 1592
{
    awstring val;
1593

1594 1595
    val.unicode = TRUE;
    val.str.w = szValueBuf;
1596

1597
    return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
1598
}
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652

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;
}

1653
static HRESULT WINAPI mrp_GetActiveDatabase( IWineMsiRemotePackage *iface, MSIHANDLE *handle )
1654 1655
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676
    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 );
1677 1678 1679
    return S_OK;
}

1680
static HRESULT WINAPI mrp_GetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR *value, DWORD *size )
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691
{
    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;
}

1692
static HRESULT WINAPI mrp_SetProperty( IWineMsiRemotePackage *iface, BSTR property, BSTR value )
1693 1694
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1695
    UINT r = MsiSetPropertyW(This->package, property, value);
1696 1697 1698
    return HRESULT_FROM_WIN32(r);
}

1699
static HRESULT WINAPI mrp_ProcessMessage( IWineMsiRemotePackage *iface, INSTALLMESSAGE message, MSIHANDLE record )
1700 1701 1702 1703 1704 1705
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiProcessMessage(This->package, message, record);
    return HRESULT_FROM_WIN32(r);
}

1706
static HRESULT WINAPI mrp_DoAction( IWineMsiRemotePackage *iface, BSTR action )
1707 1708
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1709
    UINT r = MsiDoActionW(This->package, action);
1710 1711 1712
    return HRESULT_FROM_WIN32(r);
}

1713
static HRESULT WINAPI mrp_Sequence( IWineMsiRemotePackage *iface, BSTR table, int sequence )
1714 1715
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1716
    UINT r = MsiSequenceW(This->package, table, sequence);
1717 1718 1719
    return HRESULT_FROM_WIN32(r);
}

1720
static HRESULT WINAPI mrp_GetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
1721 1722 1723 1724 1725 1726
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiGetTargetPathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
    return HRESULT_FROM_WIN32(r);
}

1727
static HRESULT WINAPI mrp_SetTargetPath( IWineMsiRemotePackage *iface, BSTR folder, BSTR value)
1728 1729
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1730
    UINT r = MsiSetTargetPathW(This->package, folder, value);
1731 1732 1733
    return HRESULT_FROM_WIN32(r);
}

1734
static HRESULT WINAPI mrp_GetSourcePath( IWineMsiRemotePackage *iface, BSTR folder, BSTR *value, DWORD *size )
1735 1736 1737 1738 1739 1740
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiGetSourcePathW(This->package, (LPWSTR)folder, (LPWSTR)value, size);
    return HRESULT_FROM_WIN32(r);
}

1741
static HRESULT WINAPI mrp_GetMode( IWineMsiRemotePackage *iface, MSIRUNMODE mode, BOOL *ret )
1742 1743 1744 1745 1746 1747
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    *ret = MsiGetMode(This->package, mode);
    return S_OK;
}

1748
static HRESULT WINAPI mrp_GetFeatureState( IWineMsiRemotePackage *iface, BSTR feature,
1749 1750 1751
                                    INSTALLSTATE *installed, INSTALLSTATE *action )
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1752
    UINT r = MsiGetFeatureStateW(This->package, feature, installed, action);
1753 1754 1755
    return HRESULT_FROM_WIN32(r);
}

1756
static HRESULT WINAPI mrp_SetFeatureState( IWineMsiRemotePackage *iface, BSTR feature, INSTALLSTATE state )
1757 1758
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1759
    UINT r = MsiSetFeatureStateW(This->package, feature, state);
1760 1761 1762
    return HRESULT_FROM_WIN32(r);
}

1763
static HRESULT WINAPI mrp_GetComponentState( IWineMsiRemotePackage *iface, BSTR component,
1764 1765 1766
                                      INSTALLSTATE *installed, INSTALLSTATE *action )
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1767
    UINT r = MsiGetComponentStateW(This->package, component, installed, action);
1768 1769 1770
    return HRESULT_FROM_WIN32(r);
}

1771
static HRESULT WINAPI mrp_SetComponentState( IWineMsiRemotePackage *iface, BSTR component, INSTALLSTATE state )
1772 1773
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1774
    UINT r = MsiSetComponentStateW(This->package, component, state);
1775 1776 1777
    return HRESULT_FROM_WIN32(r);
}

1778
static HRESULT WINAPI mrp_GetLanguage( IWineMsiRemotePackage *iface, LANGID *language )
1779 1780 1781 1782 1783 1784
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    *language = MsiGetLanguage(This->package);
    return S_OK;
}

1785
static HRESULT WINAPI mrp_SetInstallLevel( IWineMsiRemotePackage *iface, int level )
1786 1787 1788 1789 1790 1791
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
    UINT r = MsiSetInstallLevel(This->package, level);
    return HRESULT_FROM_WIN32(r);
}

1792
static HRESULT WINAPI mrp_FormatRecord( IWineMsiRemotePackage *iface, MSIHANDLE record,
1793
                                        BSTR *value)
1794
{
1795
    DWORD size = 0;
1796
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1797 1798 1799 1800 1801 1802 1803 1804 1805
    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);
    }
1806 1807 1808
    return HRESULT_FROM_WIN32(r);
}

1809
static HRESULT WINAPI mrp_EvaluateCondition( IWineMsiRemotePackage *iface, BSTR condition )
1810 1811
{
    msi_remote_package_impl* This = mrp_from_IWineMsiRemotePackage( iface );
1812
    UINT r = MsiEvaluateConditionW(This->package, condition);
1813 1814 1815
    return HRESULT_FROM_WIN32(r);
}

1816 1817 1818 1819 1820 1821 1822 1823 1824
static const IWineMsiRemotePackageVtbl msi_remote_package_vtbl =
{
    mrp_QueryInterface,
    mrp_AddRef,
    mrp_Release,
    mrp_SetMsiHandle,
    mrp_GetActiveDatabase,
    mrp_GetProperty,
    mrp_SetProperty,
1825
    mrp_ProcessMessage,
1826
    mrp_DoAction,
1827
    mrp_Sequence,
1828
    mrp_GetTargetPath,
1829
    mrp_SetTargetPath,
1830
    mrp_GetSourcePath,
1831
    mrp_GetMode,
1832
    mrp_GetFeatureState,
1833
    mrp_SetFeatureState,
1834
    mrp_GetComponentState,
1835
    mrp_SetComponentState,
1836
    mrp_GetLanguage,
1837
    mrp_SetInstallLevel,
1838
    mrp_FormatRecord,
1839
    mrp_EvaluateCondition,
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857
};

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;
}
1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894

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;
}