diff --git a/dlls/msi/install.c b/dlls/msi/install.c index 2ba539b339b..bb7b5b8045f 100644 --- a/dlls/msi/install.c +++ b/dlls/msi/install.c @@ -116,7 +116,7 @@ UINT WINAPI MsiSequenceW( MSIHANDLE hInstall, LPCWSTR szTable, INT iSequenceMode return ret; } -static UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) +UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) { UINT len, r = ERROR_SUCCESS; @@ -134,9 +134,12 @@ static UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) } else { - len = WideCharToMultiByte( CP_ACP, 0, str, -1, - awbuf->str.a, *sz, NULL, NULL ); - len--; + len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); + if (len) + len--; + WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL ); + if ( *sz && (len >= *sz) ) + awbuf->str.a[*sz - 1] = 0; } if (len >= *sz) diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 76a9e461a21..7649d39add7 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -254,6 +254,7 @@ DEFINE_GUID(CLSID_IMsiServerX3, 0x000C1094,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x0 DEFINE_GUID(CLSID_IMsiServerMessage, 0x000C101D,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); +/* handle unicode/ascii output in the Msi* API functions */ typedef struct { BOOL unicode; union { @@ -270,6 +271,8 @@ typedef struct { } str; } awcstring; +UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ); + /* handle functions */ extern void *msihandle2msiinfo(MSIHANDLE handle, UINT type); extern MSIHANDLE alloc_msihandle( MSIOBJECTHDR * ); diff --git a/dlls/msi/package.c b/dlls/msi/package.c index a12cd286f35..16a26080f9d 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -682,32 +682,26 @@ out: } /* property code */ -UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue) +UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue ) { LPWSTR szwName = NULL, szwValue = NULL; - UINT hr = ERROR_INSTALL_FAILURE; + UINT r = ERROR_OUTOFMEMORY; - if( szName ) - { - szwName = strdupAtoW( szName ); - if( !szwName ) - goto end; - } + szwName = strdupAtoW( szName ); + if( szName && !szwName ) + goto end; - if( szValue ) - { - szwValue = strdupAtoW( szValue ); - if( !szwValue) - goto end; - } + szwValue = strdupAtoW( szValue ); + if( szValue && !szwValue ) + goto end; - hr = MsiSetPropertyW( hInstall, szwName, szwValue); + r = MsiSetPropertyW( hInstall, szwName, szwValue); end: msi_free( szwName ); msi_free( szwValue ); - return hr; + return r; } UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue) @@ -728,8 +722,14 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue) ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0}; WCHAR Query[1024]; - TRACE("Setting property (%s %s)\n",debugstr_w(szName), - debugstr_w(szValue)); + TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue)); + + if (!szName) + return ERROR_INVALID_PARAMETER; + + /* this one is wierd... */ + if (!szName[0]) + return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS; rc = MSI_GetPropertyW(package,szName,0,&sz); if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS) @@ -767,11 +767,6 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue MSIPACKAGE *package; UINT ret; - if (NULL == szName) - return ERROR_INVALID_PARAMETER; - if (NULL == szValue) - return ERROR_INVALID_PARAMETER; - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); if( !package ) return ERROR_INVALID_HANDLE; @@ -780,51 +775,33 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue return ret; } -static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row) +static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name ) { - MSIQUERY *view; - UINT rc, sz; - static const WCHAR select[]= + 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}; - LPWSTR query; - if (!szName) - return ERROR_INVALID_PARAMETER; + if (!name || !name[0]) + return NULL; - sz = sizeof select + strlenW(szName)*sizeof(WCHAR); - query = msi_alloc( sz); - sprintfW(query,select,szName); - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - msi_free(query); - if (rc == ERROR_SUCCESS) - { - rc = MSI_ViewExecute(view, 0); - if (rc == ERROR_SUCCESS) - rc = MSI_ViewFetch(view,row); - - MSI_ViewClose(view); - msiobj_release(&view->hdr); - } - - return rc; + return MSI_QueryGetRecord( package->db, query, name ); } - -UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, - LPWSTR szValueBuf, DWORD* pchValueBuf) + +/* internal function, not compatible with MsiGetPropertyW */ +UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName, + LPWSTR szValueBuf, DWORD* pchValueBuf ) { MSIRECORD *row; - UINT rc; + UINT rc = ERROR_FUNCTION_FAILED; - rc = MSI_GetPropertyRow(package, szName, &row); + row = MSI_GetPropertyRow( package, szName ); if (*pchValueBuf > 0) szValueBuf[0] = 0; - if (rc == ERROR_SUCCESS) + if (row) { rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf); msiobj_release(&row->hdr); @@ -845,106 +822,67 @@ UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, return rc; } -UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, - LPSTR szValueBuf, DWORD* pchValueBuf) -{ - MSIRECORD *row; - UINT rc; - LPWSTR szwName = NULL; - - if (*pchValueBuf > 0) - szValueBuf[0] = 0; - - if( szName ) - { - szwName = strdupAtoW( szName ); - if (!szwName) - return ERROR_NOT_ENOUGH_MEMORY; - } - - rc = MSI_GetPropertyRow(package, szwName, &row); - if (rc == ERROR_SUCCESS) - { - rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf); - msiobj_release(&row->hdr); - } - - if (rc == ERROR_SUCCESS) - TRACE("returning %s for property %s\n", debugstr_a(szValueBuf), - debugstr_a(szName)); - else if (rc == ERROR_MORE_DATA) - TRACE("need %ld sized buffer for %s\n", *pchValueBuf, - debugstr_a(szName)); - else - { - *pchValueBuf = 0; - TRACE("property not found\n"); - } - msi_free( szwName ); - - return rc; -} - -UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) +static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name, + awstring *szValueBuf, DWORD* pchValueBuf ) { + static const WCHAR empty[] = {0}; MSIPACKAGE *package; - UINT ret; + MSIRECORD *row = NULL; + UINT r; + LPCWSTR val = NULL; - TRACE("%lu %s %p\n", hInstall, debugstr_a(szName), pchValueBuf); + TRACE("%lu %s %p %p\n", handle, debugstr_w(name), + szValueBuf->str.w, pchValueBuf ); - if (0 == hInstall) - return ERROR_INVALID_HANDLE; - if (NULL == szName) - return ERROR_INVALID_PARAMETER; - if (NULL != szValueBuf && NULL == pchValueBuf) + if (!name) return ERROR_INVALID_PARAMETER; - /* This was tested against native msi */ - if (NULL == szValueBuf && NULL != pchValueBuf) - *pchValueBuf = 0; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); + package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE ); if (!package) return ERROR_INVALID_HANDLE; - ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf ); + + row = MSI_GetPropertyRow( package, name ); + if (row) + val = MSI_RecordGetString( row, 1 ); + + if (!val) + val = empty; + + r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf ); + + if (row) + msiobj_release( &row->hdr ); msiobj_release( &package->hdr ); - /* MsiGetProperty does not return error codes on missing properties */ - if (ret != ERROR_MORE_DATA) - ret = ERROR_SUCCESS; - - return ret; + return r; } +UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName, + LPSTR szValueBuf, DWORD* pchValueBuf ) +{ + awstring val; + LPWSTR name; + UINT r; + + val.unicode = FALSE; + val.str.a = szValueBuf; + + name = strdupAtoW( szName ); + if (szName && !name) + return ERROR_OUTOFMEMORY; + + r = MSI_GetProperty( hInstall, name, &val, pchValueBuf ); + msi_free( name ); + return r; +} -UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, - LPWSTR szValueBuf, DWORD* pchValueBuf) +UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, + LPWSTR szValueBuf, DWORD* pchValueBuf ) { - MSIPACKAGE *package; - UINT ret; + awstring val; - TRACE("%lu %s %p\n", hInstall, debugstr_w(szName), pchValueBuf); + val.unicode = TRUE; + val.str.w = szValueBuf; - if (0 == hInstall) - return ERROR_INVALID_HANDLE; - if (NULL == szName) - return ERROR_INVALID_PARAMETER; - if (NULL != szValueBuf && NULL == pchValueBuf) - return ERROR_INVALID_PARAMETER; - - /* This was tested against native msi */ - if (NULL == szValueBuf && NULL != pchValueBuf) - *pchValueBuf = 0; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf ); - msiobj_release( &package->hdr ); - - /* MsiGetProperty does not return error codes on missing properties */ - if (ret != ERROR_MORE_DATA) - ret = ERROR_SUCCESS; - - return ret; + return MSI_GetProperty( hInstall, szName, &val, pchValueBuf ); } diff --git a/dlls/msi/tests/package.c b/dlls/msi/tests/package.c index d10e45d7806..fa22e808de2 100644 --- a/dlls/msi/tests/package.c +++ b/dlls/msi/tests/package.c @@ -567,6 +567,128 @@ void test_condition(void) MsiCloseHandle( hpkg ); } +static BOOL check_prop_empty( MSIHANDLE hpkg, char * prop) +{ + UINT r; + DWORD sz; + char buffer[2]; + + sz = sizeof buffer; + strcpy(buffer,"x"); + r = MsiGetProperty( hpkg, prop, buffer, &sz ); + return r == ERROR_SUCCESS && buffer[0] == 0 && sz == 0; +} + +static void test_props(void) +{ + MSIHANDLE hpkg; + UINT r; + DWORD sz; + char buffer[0x100]; + + hpkg = package_from_db(create_package_db()); + ok( hpkg, "failed to create package\n"); + + /* test invalid values */ + r = MsiGetProperty( 0, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "wrong return val\n"); + + r = MsiGetProperty( hpkg, NULL, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "wrong return val\n"); + + r = MsiGetProperty( hpkg, "boo", NULL, NULL ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + + r = MsiGetProperty( hpkg, "boo", buffer, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "wrong return val\n"); + + /* test retrieving an empty/non-existant property */ + sz = sizeof buffer; + r = MsiGetProperty( hpkg, "boo", NULL, &sz ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + ok( sz == 0, "wrong size returned\n"); + + check_prop_empty( hpkg, "boo"); + sz = 0; + strcpy(buffer,"x"); + r = MsiGetProperty( hpkg, "boo", buffer, &sz ); + ok( r == ERROR_MORE_DATA, "wrong return val\n"); + ok( !strcmp(buffer,"x"), "buffer was changed\n"); + ok( sz == 0, "wrong size returned\n"); + + sz = 1; + strcpy(buffer,"x"); + r = MsiGetProperty( hpkg, "boo", buffer, &sz ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + ok( buffer[0] == 0, "buffer was not changed\n"); + ok( sz == 0, "wrong size returned\n"); + + /* set the property to something */ + r = MsiSetProperty( 0, NULL, NULL ); + ok( r == ERROR_INVALID_HANDLE, "wrong return val\n"); + + r = MsiSetProperty( hpkg, NULL, NULL ); + ok( r == ERROR_INVALID_PARAMETER, "wrong return val\n"); + + r = MsiSetProperty( hpkg, "", NULL ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + + /* try set and get some illegal property identifiers */ + r = MsiSetProperty( hpkg, "", "asdf" ); + ok( r == ERROR_FUNCTION_FAILED, "wrong return val\n"); + + r = MsiSetProperty( hpkg, "=", "asdf" ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + + r = MsiSetProperty( hpkg, " ", "asdf" ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + + r = MsiSetProperty( hpkg, "'", "asdf" ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + + sz = sizeof buffer; + buffer[0]=0; + r = MsiGetProperty( hpkg, "'", buffer, &sz ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + ok( !strcmp(buffer,"asdf"), "buffer was not changed\n"); + + /* set empty values */ + r = MsiSetProperty( hpkg, "boo", NULL ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + ok( check_prop_empty( hpkg, "boo"), "prop wasn't empty\n"); + + r = MsiSetProperty( hpkg, "boo", "" ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + ok( check_prop_empty( hpkg, "boo"), "prop wasn't empty\n"); + + /* set a non-empty value */ + r = MsiSetProperty( hpkg, "boo", "xyz" ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + + sz = 1; + strcpy(buffer,"x"); + r = MsiGetProperty( hpkg, "boo", buffer, &sz ); + ok( r == ERROR_MORE_DATA, "wrong return val\n"); + ok( buffer[0] == 0, "buffer was not changed\n"); + ok( sz == 3, "wrong size returned\n"); + + sz = 4; + strcpy(buffer,"x"); + r = MsiGetProperty( hpkg, "boo", buffer, &sz ); + ok( r == ERROR_SUCCESS, "wrong return val\n"); + ok( !strcmp(buffer,"xyz"), "buffer was not changed\n"); + ok( sz == 3, "wrong size returned\n"); + + sz = 3; + strcpy(buffer,"x"); + r = MsiGetProperty( hpkg, "boo", buffer, &sz ); + ok( r == ERROR_MORE_DATA, "wrong return val\n"); + ok( !strcmp(buffer,"xy"), "buffer was not changed\n"); + ok( sz == 3, "wrong size returned\n"); + + MsiCloseHandle( hpkg ); +} + START_TEST(package) { test_createpackage(); @@ -574,4 +696,5 @@ START_TEST(package) test_getsourcepath(); test_doaction(); test_gettargetpath_bad(); + test_props(); }