package.c 26.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#define NONAMELESSUNION

#include <stdarg.h>
24
#include <stdio.h>
25 26 27 28 29
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
#include "shlwapi.h"
30
#include "wingdi.h"
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
#include "objidl.h"
#include "wincrypt.h"
#include "winuser.h"
#include "shlobj.h"
#include "wine/unicode.h"
#include "objbase.h"

WINE_DEFAULT_DEBUG_CHANNEL(msi);

/*
 * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
 *  which is a problem because LPCTSTR isn't defined when compiling wine.
 * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
 *  and make sure to only use it in W functions.
 */
#define LPCTSTR LPCWSTR

52
void MSI_FreePackage( MSIOBJECTHDR *arg)
53
{
54
    MSIPACKAGE *package= (MSIPACKAGE*) arg;
55

56 57
    if( package->dialog )
        msi_dialog_destroy( package->dialog );
Aric Stewart's avatar
Aric Stewart committed
58
    ACTION_free_package_structures(package);
59

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

63
static UINT clone_properties(MSIDATABASE *db)
64
{
65
    MSIQUERY * view = NULL;
66
    UINT rc;
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
    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',
       'L','L',',',' ','`','V','a','l','u','e','`',' ','C','H','A','R','(','9',
       '8',')',' ','N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R',
       'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0};
    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','`',')',' ',
82
       'V','A','L','U','E','S',' ','(','?',',','?',')',0};
83 84

    /* create the temporary properties table */
85 86 87 88 89 90 91 92
    rc = MSI_DatabaseOpenViewW(db, CreateSql, &view);
    if (rc != ERROR_SUCCESS)
        return rc;
    rc = MSI_ViewExecute(view,0);   
    MSI_ViewClose(view);
    msiobj_release(&view->hdr); 
    if (rc != ERROR_SUCCESS)
        return rc;
93 94

    /* clone the existing properties */
95 96 97
    rc = MSI_DatabaseOpenViewW(db, Query, &view);
    if (rc != ERROR_SUCCESS)
        return rc;
98

99 100 101 102 103 104 105
    rc = MSI_ViewExecute(view, 0);
    if (rc != ERROR_SUCCESS)
    {
        MSI_ViewClose(view);
        msiobj_release(&view->hdr); 
        return rc;
    }
106 107
    while (1)
    {
108 109
        MSIRECORD * row;
        MSIQUERY * view2;
110

111
        rc = MSI_ViewFetch(view,&row);
112 113 114
        if (rc != ERROR_SUCCESS)
            break;

115 116 117 118 119 120
        rc = MSI_DatabaseOpenViewW(db,Insert,&view2);  
        if (rc!= ERROR_SUCCESS)
            continue;
        rc = MSI_ViewExecute(view2,row);
        MSI_ViewClose(view2);
        msiobj_release(&view2->hdr);
121
 
122 123
        if (rc == ERROR_SUCCESS) 
            msiobj_release(&row->hdr); 
124
    }
125 126
    MSI_ViewClose(view);
    msiobj_release(&view->hdr);
127
    
128
    return rc;
129 130 131 132 133 134 135 136
}

/*
 * There are a whole slew of these we need to set
 *
 *
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
 */
137
static VOID set_installer_properties(MSIPACKAGE *package)
138 139
{
    WCHAR pth[MAX_PATH];
Aric Stewart's avatar
Aric Stewart committed
140
    WCHAR *ptr;
141 142
    OSVERSIONINFOA OSVersion;
    DWORD verval;
143 144
    WCHAR verstr[10], bufstr[20];
    HDC dc;
145 146 147 148 149 150 151 152

    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};
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    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};
169 170 171 172 173 174
    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};
175 176
    static const WCHAR SF16[] = 
{'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
177 178 179 180 181 182 183 184
    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
185 186
    static const WCHAR WV[] = 
{'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
187 188
    static const WCHAR TF[]=
{'T','e','m','p','F','o','l','d','e','r',0};
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
    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 };
    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 };

204 205
    static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
    static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
206 207 208 209 210
/* 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};
    static const WCHAR szScreenFormat[] = {'%','d',0};
211

212
/*
213
 * Other things I notice set
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
 *
SystemLanguageID
ComputerName
UserLanguageID
LogonUser
VirtualMemory
PhysicalMemory
Intel
ShellAdvSupport
DefaultUIFont
VersionDatabase
PackagecodeChanging
ProductState
CaptionHeight
BorderTop
BorderSide
TextHeight
RedirectedDllSupport
Time
Date
234
Privileged
235 236 237 238
*/

    SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
    strcatW(pth,cszbs);
239
    MSI_SetPropertyW(package, CFF, pth);
240 241 242

    SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
    strcatW(pth,cszbs);
243
    MSI_SetPropertyW(package, PFF, pth);
244 245 246

    SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
    strcatW(pth,cszbs);
247
    MSI_SetPropertyW(package, CADF, pth);
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
    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);

281 282
    SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
    strcatW(pth,cszbs);
283
    MSI_SetPropertyW(package, ATF, pth);
284 285 286

    SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
    strcatW(pth,cszbs);
287
    MSI_SetPropertyW(package, ADF, pth);
288 289 290

    SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
    strcatW(pth,cszbs);
291
    MSI_SetPropertyW(package, SF, pth);
292
    MSI_SetPropertyW(package, SF16, pth);
293 294 295

    SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
    strcatW(pth,cszbs);
296
    MSI_SetPropertyW(package, LADF, pth);
297 298 299

    SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
    strcatW(pth,cszbs);
300
    MSI_SetPropertyW(package, MPF, pth);
301 302 303

    SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
    strcatW(pth,cszbs);
304
    MSI_SetPropertyW(package, PF, pth);
305 306 307

    SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
    strcatW(pth,cszbs);
308
    MSI_SetPropertyW(package, WF, pth);
309

Aric Stewart's avatar
Aric Stewart committed
310 311 312
    SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
    ptr = strchrW(pth,'\\');
    if (ptr)
313
	*(ptr+1) = 0;
Aric Stewart's avatar
Aric Stewart committed
314 315
    MSI_SetPropertyW(package, WV, pth);
    
316
    GetTempPathW(MAX_PATH,pth);
317
    MSI_SetPropertyW(package, TF, pth);
318

319

320 321 322
    /* in a wine environment the user is always admin and privileged */
    MSI_SetPropertyW(package,szAdminUser,szOne);
    MSI_SetPropertyW(package,szPriv,szOne);
323 324 325 326 327

    /* set the os things */
    OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
    GetVersionExA(&OSVersion);
    verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
328
    sprintfW(verstr,szFormat,verval);
329 330 331
    switch (OSVersion.dwPlatformId)
    {
        case VER_PLATFORM_WIN32_WINDOWS:    
332
            MSI_SetPropertyW(package,v9x,verstr);
333 334
            break;
        case VER_PLATFORM_WIN32_NT:
335
            MSI_SetPropertyW(package,vNT,verstr);
336 337
            break;
    }
338 339
    sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
    MSI_SetPropertyW(package,szWinBuild,verstr);
340
    /* just fudge this */
341
    MSI_SetPropertyW(package,szSPL,szSix);
342

343 344 345 346 347 348 349 350 351 352 353 354
    sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
    MSI_SetPropertyW( package, szVersionMsi, bufstr );

    /* Screen properties. */
    dc = GetDC(0);
    sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) );
    MSI_SetPropertyW( package, szScreenX, bufstr );
    sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES ));
    MSI_SetPropertyW( package, szScreenY, bufstr );
    sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL ));
    MSI_SetPropertyW( package, szColorBits, bufstr );
    ReleaseDC(0, dc);
355
}
356

357
MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
358
{
359 360
    static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
    static const WCHAR szpi[] = {'%','i',0};
361 362
    MSIPACKAGE *package = NULL;
    WCHAR uilevel[10];
363

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

366 367
    package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
                               MSI_FreePackage );
368
    if( package )
369
    {
370 371 372 373 374 375 376 377 378 379 380
        msiobj_addref( &db->hdr );

        package->db = db;
        package->features = NULL;
        package->folders = NULL;
        package->components = NULL;
        package->files = NULL;
        package->loaded_features = 0;
        package->loaded_folders = 0;
        package->loaded_components= 0;
        package->loaded_files = 0;
381 382
        package->ActionFormat = NULL;
        package->LastAction = NULL;
383 384
        package->dialog = NULL;
        package->next_dialog = NULL;
385 386 387 388 389 390 391 392

        /* OK, here is where we do a slew of things to the database to 
         * prep for all that is to come as a package */

        clone_properties(db);
        set_installer_properties(package);
        sprintfW(uilevel,szpi,gUILevel);
        MSI_SetPropertyW(package, szLevel, uilevel);
393 394
    }

395
    return package;
396 397 398 399 400
}

UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
{
    MSIDATABASE *db = NULL;
401
    MSIPACKAGE *package;
402 403 404 405 406 407 408 409 410 411 412 413 414
    MSIHANDLE handle;

    TRACE("%s %p\n", debugstr_w(szPackage), pPackage);

    if( szPackage[0] == '#' )
    {
        handle = atoiW(&szPackage[1]);
        db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
        if( !db )
            return ERROR_INVALID_HANDLE;
    }
    else
    {
415 416 417
        UINT r = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
        if( r != ERROR_SUCCESS )
            return r;
418 419
    }

420 421 422 423
    package = MSI_CreatePackage( db );
    msiobj_release( &db->hdr );
    if( !package )
        return ERROR_FUNCTION_FAILED;
424 425 426 427 428 429

    /* 
     * FIXME:  I don't think this is right.  Maybe we should be storing the
     * name of the database in the MSIDATABASE structure and fetching this
     * info from there, or maybe this is only relevant to cached databases.
     */
430
    if( szPackage[0] != '#' )
431 432 433 434 435
    {
        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};

436 437
        MSI_SetPropertyW( package, OriginalDatabase, szPackage );
        MSI_SetPropertyW( package, Database, szPackage );
438 439
    }

440
    *pPackage = package;
441

442
    return ERROR_SUCCESS;
443
}
444

445
UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
446 447 448
{
    MSIPACKAGE *package = NULL;
    UINT ret;
449

450 451 452 453 454
    TRACE("%s %08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);

    if( dwOptions )
        FIXME("dwOptions %08lx not supported\n", dwOptions);

455 456 457 458 459 460 461
    ret = MSI_OpenPackageW( szPackage, &package);
    if( ret == ERROR_SUCCESS )
    {
        *phPackage = alloc_msihandle( &package->hdr );
        msiobj_release( &package->hdr );
    }
    return ret;
462 463
}

464 465 466 467 468
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
{
    return MsiOpenPackageExW( szPackage, 0, phPackage );
}

469 470
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
    LPWSTR szwPack = NULL;
    UINT len, ret;

    if( szPackage )
    {
        len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
        szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
        if( szwPack )
            MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
    }

    ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );

    HeapFree( GetProcessHeap(), 0, szwPack );

    return ret;
487 488
}

489
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
490
{
491
    return MsiOpenPackageExA( szPackage, 0, phPackage );
492 493 494 495 496
}

MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
{
    MSIPACKAGE *package;
497
    MSIHANDLE handle = 0;
498

Mike McCormack's avatar
Mike McCormack committed
499
    TRACE("(%ld)\n",hInstall);
500 501

    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
502 503 504 505 506
    if( package)
    {
        handle = alloc_msihandle( &package->db->hdr );
        msiobj_release( &package->hdr );
    }
507

508
    return handle;
509 510
}

511 512
INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
                               MSIRECORD *record)
513
{
514
    DWORD log_type = 0;
515
    LPWSTR message;
516
    DWORD sz;
517
    DWORD total_size = 0;
518
    INT msg_field=1;
519
    INT i;
Aric Stewart's avatar
Aric Stewart committed
520
    INT rc;
521 522
    char *msg;
    int len;
Aric Stewart's avatar
Aric Stewart committed
523

524
    TRACE("%x \n",eMessageType);
Aric Stewart's avatar
Aric Stewart committed
525
    rc = 0;
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540

    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;
541 542 543
    /* just a guess */
    if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
        log_type |= 0x800;
544

545
    message = HeapAlloc(GetProcessHeap(),0,1*sizeof (WCHAR));
546
    message[0]=0;
547
    msg_field = MSI_RecordGetFieldCount(record);
548 549
    for (i = 1; i <= msg_field; i++)
    {
550 551 552 553
        LPWSTR tmp;
        WCHAR number[3];
        const static WCHAR format[] = { '%','i',':',' ',0};
        const static WCHAR space[] = { ' ',0};
554
        sz = 0;
555
        MSI_RecordGetStringW(record,i,NULL,&sz);
556
        sz+=4;
557 558 559
        total_size+=sz*sizeof(WCHAR);
        tmp = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
        message = HeapReAlloc(GetProcessHeap(),0,message,total_size*sizeof (WCHAR));
560

561
        MSI_RecordGetStringW(record,i,tmp,&sz);
562 563 564

        if (msg_field > 1)
        {
565 566
            sprintfW(number,format,i);
            strcatW(message,number);
567
        }
568
        strcatW(message,tmp);
569
        if (msg_field > 1)
570
            strcatW(message,space);
571

572 573 574
        HeapFree(GetProcessHeap(),0,tmp);
    }

575
    TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type,
576 577 578 579 580 581 582 583
                             debugstr_w(message));

    /* convert it to ASCII */
    len = WideCharToMultiByte( CP_ACP, 0, message, -1,
                               NULL, 0, NULL, NULL );
    msg = HeapAlloc( GetProcessHeap(), 0, len );
    WideCharToMultiByte( CP_ACP, 0, message, -1,
                         msg, len, NULL, NULL );
584

585
    if (gUIHandlerA && (gUIFilter & log_type))
586
    {
587
        rc = gUIHandlerA(gUIContext,eMessageType,msg);
588
    }
Aric Stewart's avatar
Aric Stewart committed
589 590 591 592 593 594 595

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

Aric Stewart's avatar
Aric Stewart committed
597 598 599
        if (log_file != INVALID_HANDLE_VALUE)
        {
            SetFilePointer(log_file,0, NULL, FILE_END);
600
            WriteFile(log_file,msg,strlen(msg),&write,NULL);
Aric Stewart's avatar
Aric Stewart committed
601 602 603 604
            WriteFile(log_file,"\n",1,&write,NULL);
            CloseHandle(log_file);
        }
    }
605
    HeapFree( GetProcessHeap(), 0, msg );
Aric Stewart's avatar
Aric Stewart committed
606
    
607
    HeapFree(GetProcessHeap(),0,message);
608 609 610
    return ERROR_SUCCESS;
}

611 612 613 614 615 616 617 618 619
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 )
620
        return ERROR_INVALID_HANDLE;
621 622 623 624 625 626 627 628

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

    ret = MSI_ProcessMessage( package, eMessageType, record );

out:
629
    msiobj_release( &package->hdr );
630 631 632 633 634 635
    if( record )
        msiobj_release( &record->hdr );

    return ret;
}

636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
/* property code */
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
{
    LPWSTR szwName = NULL, szwValue = NULL;
    UINT hr = ERROR_INSTALL_FAILURE;
    UINT len;

    if (0 == hInstall) {
      return ERROR_INVALID_HANDLE;
    }
    if (NULL == szName) {
      return ERROR_INVALID_PARAMETER;
    }
    if (NULL == szValue) {
      return ERROR_INVALID_PARAMETER;
    }

    len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
    szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
    if( !szwName )
        goto end;
    MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );

    len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
    szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
    if( !szwValue)
        goto end;
    MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );

    hr = MsiSetPropertyW( hInstall, szwName, szwValue);

end:
668 669
    HeapFree( GetProcessHeap(), 0, szwName );
    HeapFree( GetProcessHeap(), 0, szwValue );
670 671 672 673

    return hr;
}

674
UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
675
{
676 677
    MSIQUERY *view;
    MSIRECORD *row;
678 679
    UINT rc;
    DWORD sz = 0;
680 681 682 683
    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'
684
,' ','(','?',',','?',')',0};
685 686 687 688 689 690
    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};
    WCHAR Query[1024];
691 692 693 694

    TRACE("Setting property (%s %s)\n",debugstr_w(szName),
          debugstr_w(szValue));

695
    rc = MSI_GetPropertyW(package,szName,0,&sz);
696
    if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
697
    {
698 699
        sprintfW(Query,Update,szName);

700 701
        row = MSI_CreateRecord(1);
        MSI_RecordSetStringW(row,1,szValue);
702

703
    }
704 705 706
    else
    {
       strcpyW(Query,Insert);
707

708 709 710
        row = MSI_CreateRecord(2);
        MSI_RecordSetStringW(row,1,szName);
        MSI_RecordSetStringW(row,2,szValue);
711
    }
712

713

714
    rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
715
    if (rc!= ERROR_SUCCESS)
716
    {
717
        msiobj_release(&row->hdr);
718
        return rc;
719
    }
720

721
    rc = MSI_ViewExecute(view,row);
722

723 724 725
    msiobj_release(&row->hdr);
    MSI_ViewClose(view);
    msiobj_release(&view->hdr);
726 727 728 729

    return rc;
}

730 731 732 733 734 735 736 737 738 739 740 741 742
UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
{
    MSIPACKAGE *package;
    UINT ret;

    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
    if( !package)
        return ERROR_INVALID_HANDLE;
    ret = MSI_SetPropertyW( package, szName, szValue);
    msiobj_release( &package->hdr );
    return ret;
}

743
static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row)
744
{
745 746 747 748 749 750 751
    MSIQUERY *view;
    UINT rc, sz;
    static const WCHAR select[]=
    {'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};
    LPWSTR query;
752

753 754
    if (!szName)
        return ERROR_INVALID_PARAMETER;
755

756 757 758
    sz = sizeof select + strlenW(szName)*sizeof(WCHAR);
    query = HeapAlloc(GetProcessHeap(), 0, sz);
    sprintfW(query,select,szName);
759

760 761 762
    rc = MSI_DatabaseOpenViewW(package->db, query, &view);
    HeapFree(GetProcessHeap(), 0, query);
    if (rc == ERROR_SUCCESS)
763
    {
764 765 766
        rc = MSI_ViewExecute(view, 0);
        if (rc == ERROR_SUCCESS)
            rc = MSI_ViewFetch(view,row);
767

768 769
        MSI_ViewClose(view);
        msiobj_release(&view->hdr);
770 771
    }

772
    return rc;
773 774
}

775
UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, 
776 777
                           LPWSTR szValueBuf, DWORD* pchValueBuf)
{
778
    MSIRECORD *row;
779 780
    UINT rc;

781
    rc = MSI_GetPropertyRow(package, szName, &row);
782 783 784 785

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

786 787 788 789
    if (rc == ERROR_SUCCESS)
    {
        rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);
        msiobj_release(&row->hdr);
790 791 792
    }

    if (rc == ERROR_SUCCESS)
793 794
        TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
            debugstr_w(szName));
Aric Stewart's avatar
Aric Stewart committed
795
    else if (rc == ERROR_MORE_DATA)
796
        TRACE("need %li sized buffer for %s\n", *pchValueBuf,
Aric Stewart's avatar
Aric Stewart committed
797
            debugstr_w(szName));
798
    else
799
    {
800 801 802
        *pchValueBuf = 0;
        TRACE("property not found\n");
    }
803

804 805 806 807 808 809 810 811 812 813
    return rc;
}

UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, 
                           LPSTR szValueBuf, DWORD* pchValueBuf)
{
    MSIRECORD *row;
    UINT rc, len;
    LPWSTR szwName;

814 815 816
    if (*pchValueBuf > 0)
        szValueBuf[0] = 0;
    
817 818 819 820 821 822 823 824 825 826 827
    len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
    szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
    if (!szwName)
        return ERROR_NOT_ENOUGH_MEMORY;
    MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );

    rc = MSI_GetPropertyRow(package, szwName, &row);
    if (rc == ERROR_SUCCESS)
    {
        rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf);
        msiobj_release(&row->hdr);
828 829 830
    }

    if (rc == ERROR_SUCCESS)
831 832
        TRACE("returning %s for property %s\n", debugstr_a(szValueBuf),
            debugstr_a(szName));
833 834 835
    else if (rc == ERROR_MORE_DATA)
        TRACE("need %ld sized buffer for %s\n", *pchValueBuf,
            debugstr_a(szName));
836 837 838 839 840
    else
    {
        *pchValueBuf = 0;
        TRACE("property not found\n");
    }
841
    HeapFree( GetProcessHeap(), 0, szwName );
842 843 844

    return rc;
}
845

846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) 
{
    MSIPACKAGE *package;
    UINT ret;

    TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);

    if (0 == hInstall)
        return ERROR_INVALID_HANDLE;
    if (NULL == szName)
        return ERROR_INVALID_PARAMETER;
    if (NULL != szValueBuf && NULL == pchValueBuf)
        return ERROR_INVALID_PARAMETER;

    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
    if (!package)
        return ERROR_INVALID_HANDLE;
    ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
    msiobj_release( &package->hdr );
865 866 867 868 869 870

    /* MsiGetProperty does not return error codes on missing properties */
    if (ret!= ERROR_MORE_DATA)
        return ERROR_SUCCESS;
    else
        return ret;
871 872
}

873 874 875 876 877 878 879
  
UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, 
                           LPWSTR szValueBuf, DWORD* pchValueBuf)
{
    MSIPACKAGE *package;
    UINT ret;

880 881 882 883 884 885 886
    if (0 == hInstall)
        return ERROR_INVALID_HANDLE;
    if (NULL == szName)
        return ERROR_INVALID_PARAMETER;
    if (NULL != szValueBuf && NULL == pchValueBuf)
        return ERROR_INVALID_PARAMETER;

887
    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
888
    if (!package)
889 890 891
        return ERROR_INVALID_HANDLE;
    ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
    msiobj_release( &package->hdr );
892 893 894 895 896 897

    /* MsiGetProperty does not return error codes on missing properties */
    if (ret!= ERROR_MORE_DATA)
        return ERROR_SUCCESS;
    else
        return ret;
898
}