Sync to Wine-0_9_1:
authorGé van Geldorp <ge@gse.nl>
Thu, 17 Nov 2005 20:49:37 +0000 (20:49 +0000)
committerGé van Geldorp <ge@gse.nl>
Thu, 17 Nov 2005 20:49:37 +0000 (20:49 +0000)
Ivan Leo Puoti <ivanleo@gmail.com>
- Fix some wrong prototypes.
Thomas Weidenmueller <wine-patches@reactsoft.com>
- Passing NULL as the last two parameters to ReadFile is illegal and
  actually causes a crash on windows. The attached patch fixes this.
Aric Stewart <aric@codeweavers.com>
- Force files to install if the REINSTALL property is set.
Mike McCormack <mike@codeweavers.com>
- Some installers don't call the CreateFolders action before the
  InstallFiles action as MSDN specifies, but it still seems to work, so
  make sure that we create component directories in the InstallFiles
  action anyway.
- Create component folders in the CreateFolders action.
- If an action fails, print out its name as well as the error code.  Use
  %d for error codes so it's easy to match them up to something in
  winerror.h.
- Rename load_dynamic_stringW to msi_dup_record_field to better describe
  what it does, and replace a few instances with MSI_RecordGetString to
  avoid allocating memory.
- Tidy up the RegisterProduct action a little.
- Create a stub function to apply a single table transform and call it
  where we need to apply transforms.
- Enumerate the substorage transforms for any patches that are passed on
  the command line with PATCH=.  Need to implement
  table_apply_transform() before this will do anything interesting.
- Simplify register_progid() and remove a fixed length buffer.
- Make enter and escape trigger the default and cancel buttons in
  dialogs.
- Switch back to using IPicture to load images.  LoadImage did the
  resizing for us, but doesn't handle jpeg files and requires us writing
  a temp file, whereas IPicture handles jpeg files and can load directly
  from a stream.
- Remove unused package parameter of register_progid_base().
- Remove an incorrect comment and check for 0 being an invalid file
  handle.
- Add missing semicolons that caused compile trouble on FreeBSD.
- Extract file directly to their target location, bypassing the need to
  use temporary files and move files.
- Put the UI update code for cabinet file into a separate function.
- Translate INVALID_HANDLE_VALUE to zero for cabinet handles.
- Fix a memory leak in the cabinet extracting code.
- Fix passing of NULL pointers to MsiDecomposeDescriptor and add a
  test.
- Fix parameter handling in MsiSetTargetPath, and add a test for it.
- Deleted two buggy functions that incorrectly and inefficiently check
  whether a row already exists in a table, and replaced them with a call
  to an existing working function that does the same thing correctly.
- Fix and test MsiGetProperty and MsiSetProperty.
- Add a stub implementation of msi.MsiSetMode.
- NULL and empty strings are the same in conditions.
- Add a bunch of tests for MsiEvaluateCondition and make them pass.
- Fix error handling in MsiEvaluateCondition.
- Create the +msidb debug channel for msi database code.
- Implement transforms.  This still includes some debugging code which
  can be enabled by setting debug_transform to 1 in the relevant
  places.
- Define NONAMELESSUNION and NONAMELESSSTRUCT for older compilers.
- Remove some redundant null pointer checks.
- Make sure to unregister all the classes that were registered when msi
  is unloaded, so we can register again cleanly.
- Fix a memory leak.
- Implement the RemoveFiles action.
- Add a read-only implementation of the SelectionTree control.
- Make sure we only CoUninitialize after successfully initializing.
  Fix the address of the returned IShellLinkDataList interface.
- Use an enumeration for file states.
- Handle MaskEdit masks containing dashes and other constant
  characters.
- Stub implementation for MsiAdvertiseScriptA/W.
- Add a stub for the AllocateRegistrySpace action.
- Explicitly check for MSICONDITION_TRUE being returned from
  MsiEvaluateCondition.
- Stub implementation for MsiGetFileHashA/W.
- Define MSIDBOPEN_ constants using LPCWSTR when compiling Wine.
- Improve MsiUseFeatureEx and MsiGetFeatureState a little, add some
  simple test cases.
- Use msi_get_property_int() in a few more places.
- Implement MsiGetFeatureUsageA and MsiUseFeature(Ex)A using their W
  versions.
- Use "static const" rather than "const static" as gcc -W complains
  about the former.
- Add an implementation for MsiGetShortcutTargetA/W.
- Don't change the UI level during ExecuteAction.
- Return an error in MsiGetComponentPathW if passed a null component.
- Remove the unused 1st parameter of ACTION_VerifyComponentForAction.
- Fix MsiGetPropertyA/W spec declarations.
- Create an internal handle-free api for reading MSI database summary
  information.

svn path=/trunk/; revision=19307

34 files changed:
reactos/lib/msi/action.c
reactos/lib/msi/action.h
reactos/lib/msi/appsearch.c
reactos/lib/msi/classes.c
reactos/lib/msi/cond.y
reactos/lib/msi/create.c
reactos/lib/msi/custom.c
reactos/lib/msi/database.c
reactos/lib/msi/delete.c
reactos/lib/msi/dialog.c
reactos/lib/msi/distinct.c
reactos/lib/msi/files.c
reactos/lib/msi/format.c
reactos/lib/msi/helpers.c
reactos/lib/msi/insert.c
reactos/lib/msi/install.c
reactos/lib/msi/msi.c
reactos/lib/msi/msi.rc
reactos/lib/msi/msi.spec
reactos/lib/msi/msi_Ko.rc [new file with mode: 0644]
reactos/lib/msi/msipriv.h
reactos/lib/msi/msiquery.c
reactos/lib/msi/order.c
reactos/lib/msi/package.c
reactos/lib/msi/record.c
reactos/lib/msi/registry.c
reactos/lib/msi/select.c
reactos/lib/msi/string.c
reactos/lib/msi/suminfo.c
reactos/lib/msi/table.c
reactos/lib/msi/update.c
reactos/lib/msi/where.c
reactos/w32api/include/msi.h
reactos/w32api/include/msiquery.h

index 6a7eca6..3559c88 100644 (file)
@@ -60,119 +60,119 @@ static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
  */
 static const WCHAR c_colon[] = {'C',':','\\',0};
 
-const static WCHAR szCreateFolders[] =
+static const WCHAR szCreateFolders[] =
     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
-const static WCHAR szCostFinalize[] =
+static const WCHAR szCostFinalize[] =
     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
 const WCHAR szInstallFiles[] =
     {'I','n','s','t','a','l','l','F','i','l','e','s',0};
 const WCHAR szDuplicateFiles[] =
     {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
-const static WCHAR szWriteRegistryValues[] =
+static const WCHAR szWriteRegistryValues[] =
     {'W','r','i','t','e','R','e','g','i','s','t','r','y',
             'V','a','l','u','e','s',0};
-const static WCHAR szCostInitialize[] =
+static const WCHAR szCostInitialize[] =
     {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
-const static WCHAR szFileCost[] = 
+static const WCHAR szFileCost[] = 
     {'F','i','l','e','C','o','s','t',0};
-const static WCHAR szInstallInitialize[] = 
+static const WCHAR szInstallInitialize[] = 
     {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
-const static WCHAR szInstallValidate[] = 
+static const WCHAR szInstallValidate[] = 
     {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
-const static WCHAR szLaunchConditions[] = 
+static const WCHAR szLaunchConditions[] = 
     {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
-const static WCHAR szProcessComponents[] = 
+static const WCHAR szProcessComponents[] = 
     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
-const static WCHAR szRegisterTypeLibraries[] = 
+static const WCHAR szRegisterTypeLibraries[] = 
     {'R','e','g','i','s','t','e','r','T','y','p','e',
             'L','i','b','r','a','r','i','e','s',0};
 const WCHAR szRegisterClassInfo[] = 
     {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
 const WCHAR szRegisterProgIdInfo[] = 
     {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
-const static WCHAR szCreateShortcuts[] = 
+static const WCHAR szCreateShortcuts[] = 
     {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
-const static WCHAR szPublishProduct[] = 
+static const WCHAR szPublishProduct[] = 
     {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
-const static WCHAR szWriteIniValues[] = 
+static const WCHAR szWriteIniValues[] = 
     {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
-const static WCHAR szSelfRegModules[] = 
+static const WCHAR szSelfRegModules[] = 
     {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
-const static WCHAR szPublishFeatures[] = 
+static const WCHAR szPublishFeatures[] = 
     {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
-const static WCHAR szRegisterProduct[] = 
+static const WCHAR szRegisterProduct[] = 
     {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
-const static WCHAR szInstallExecute[] = 
+static const WCHAR szInstallExecute[] = 
     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
-const static WCHAR szInstallExecuteAgain[] = 
+static const WCHAR szInstallExecuteAgain[] = 
     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
             'A','g','a','i','n',0};
-const static WCHAR szInstallFinalize[] = 
+static const WCHAR szInstallFinalize[] = 
     {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
-const static WCHAR szForceReboot[] = 
+static const WCHAR szForceReboot[] = 
     {'F','o','r','c','e','R','e','b','o','o','t',0};
-const static WCHAR szResolveSource[] =
+static const WCHAR szResolveSource[] =
     {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
 const WCHAR szAppSearch[] = 
     {'A','p','p','S','e','a','r','c','h',0};
-const static WCHAR szAllocateRegistrySpace[] = 
+static const WCHAR szAllocateRegistrySpace[] = 
     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
             'S','p','a','c','e',0};
-const static WCHAR szBindImage[] = 
+static const WCHAR szBindImage[] = 
     {'B','i','n','d','I','m','a','g','e',0};
-const static WCHAR szCCPSearch[] = 
+static const WCHAR szCCPSearch[] = 
     {'C','C','P','S','e','a','r','c','h',0};
-const static WCHAR szDeleteServices[] = 
+static const WCHAR szDeleteServices[] = 
     {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
-const static WCHAR szDisableRollback[] = 
+static const WCHAR szDisableRollback[] = 
     {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
-const static WCHAR szExecuteAction[] = 
+static const WCHAR szExecuteAction[] = 
     {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
 const WCHAR szFindRelatedProducts[] = 
     {'F','i','n','d','R','e','l','a','t','e','d',
             'P','r','o','d','u','c','t','s',0};
-const static WCHAR szInstallAdminPackage[] = 
+static const WCHAR szInstallAdminPackage[] = 
     {'I','n','s','t','a','l','l','A','d','m','i','n',
             'P','a','c','k','a','g','e',0};
-const static WCHAR szInstallSFPCatalogFile[] = 
+static const WCHAR szInstallSFPCatalogFile[] = 
     {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
             'F','i','l','e',0};
-const static WCHAR szIsolateComponents[] = 
+static const WCHAR szIsolateComponents[] = 
     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
 const WCHAR szMigrateFeatureStates[] = 
     {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
             'S','t','a','t','e','s',0};
 const WCHAR szMoveFiles[] = 
     {'M','o','v','e','F','i','l','e','s',0};
-const static WCHAR szMsiPublishAssemblies[] = 
+static const WCHAR szMsiPublishAssemblies[] = 
     {'M','s','i','P','u','b','l','i','s','h',
             'A','s','s','e','m','b','l','i','e','s',0};
-const static WCHAR szMsiUnpublishAssemblies[] = 
+static const WCHAR szMsiUnpublishAssemblies[] = 
     {'M','s','i','U','n','p','u','b','l','i','s','h',
             'A','s','s','e','m','b','l','i','e','s',0};
-const static WCHAR szInstallODBC[] = 
+static const WCHAR szInstallODBC[] = 
     {'I','n','s','t','a','l','l','O','D','B','C',0};
-const static WCHAR szInstallServices[] = 
+static const WCHAR szInstallServices[] = 
     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
 const WCHAR szPatchFiles[] = 
     {'P','a','t','c','h','F','i','l','e','s',0};
-const static WCHAR szPublishComponents[] = 
+static const WCHAR szPublishComponents[] = 
     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
-const static WCHAR szRegisterComPlus[] =
+static const WCHAR szRegisterComPlus[] =
     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
 const WCHAR szRegisterExtensionInfo[] =
     {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
             'I','n','f','o',0};
-const static WCHAR szRegisterFonts[] =
+static const WCHAR szRegisterFonts[] =
     {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
 const WCHAR szRegisterMIMEInfo[] =
     {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
-const static WCHAR szRegisterUser[] =
+static const WCHAR szRegisterUser[] =
     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
 const WCHAR szRemoveDuplicateFiles[] =
     {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
             'F','i','l','e','s',0};
-const static WCHAR szRemoveEnvironmentStrings[] =
+static const WCHAR szRemoveEnvironmentStrings[] =
     {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
             'S','t','r','i','n','g','s',0};
 const WCHAR szRemoveExistingProducts[] =
@@ -180,55 +180,55 @@ const WCHAR szRemoveExistingProducts[] =
             'P','r','o','d','u','c','t','s',0};
 const WCHAR szRemoveFiles[] =
     {'R','e','m','o','v','e','F','i','l','e','s',0};
-const static WCHAR szRemoveFolders[] =
+static const WCHAR szRemoveFolders[] =
     {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
-const static WCHAR szRemoveIniValues[] =
+static const WCHAR szRemoveIniValues[] =
     {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
-const static WCHAR szRemoveODBC[] =
+static const WCHAR szRemoveODBC[] =
     {'R','e','m','o','v','e','O','D','B','C',0};
-const static WCHAR szRemoveRegistryValues[] =
+static const WCHAR szRemoveRegistryValues[] =
     {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
             'V','a','l','u','e','s',0};
-const static WCHAR szRemoveShortcuts[] =
+static const WCHAR szRemoveShortcuts[] =
     {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
-const static WCHAR szRMCCPSearch[] =
+static const WCHAR szRMCCPSearch[] =
     {'R','M','C','C','P','S','e','a','r','c','h',0};
-const static WCHAR szScheduleReboot[] =
+static const WCHAR szScheduleReboot[] =
     {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
-const static WCHAR szSelfUnregModules[] =
+static const WCHAR szSelfUnregModules[] =
     {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
-const static WCHAR szSetODBCFolders[] =
+static const WCHAR szSetODBCFolders[] =
     {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
-const static WCHAR szStartServices[] =
+static const WCHAR szStartServices[] =
     {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
-const static WCHAR szStopServices[] =
+static const WCHAR szStopServices[] =
     {'S','t','o','p','S','e','r','v','i','c','e','s',0};
-const static WCHAR szUnpublishComponents[] =
+static const WCHAR szUnpublishComponents[] =
     {'U','n','p','u','b','l','i','s','h',
             'C','o','m','p','o','n','e','n','t','s',0};
-const static WCHAR szUnpublishFeatures[] =
+static const WCHAR szUnpublishFeatures[] =
     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
 const WCHAR szUnregisterClassInfo[] =
     {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
             'I','n','f','o',0};
-const static WCHAR szUnregisterComPlus[] =
+static const WCHAR szUnregisterComPlus[] =
     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
 const WCHAR szUnregisterExtensionInfo[] =
     {'U','n','r','e','g','i','s','t','e','r',
             'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
-const static WCHAR szUnregisterFonts[] =
+static const WCHAR szUnregisterFonts[] =
     {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
 const WCHAR szUnregisterMIMEInfo[] =
     {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
 const WCHAR szUnregisterProgIdInfo[] =
     {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
             'I','n','f','o',0};
-const static WCHAR szUnregisterTypeLibraries[] =
+static const WCHAR szUnregisterTypeLibraries[] =
     {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
             'L','i','b','r','a','r','i','e','s',0};
-const static WCHAR szValidateProductID[] =
+static const WCHAR szValidateProductID[] =
     {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
-const static WCHAR szWriteEnvironmentStrings[] =
+static const WCHAR szWriteEnvironmentStrings[] =
     {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
             'S','t','r','i','n','g','s',0};
 
@@ -404,6 +404,171 @@ static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
     return ERROR_SUCCESS;
 }
 
+
+static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
+{
+    LPWSTR p, *ret = NULL;
+    UINT count = 0;
+
+    if (!str)
+        return ret;
+
+    /* count the number of substrings */
+    for ( p = (LPWSTR)str, count = 0; p; count++ )
+    {
+        p = strchrW( p, sep );
+        if (p)
+            p++;
+    }
+
+    /* allocate space for an array of substring pointers and the substrings */
+    ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
+                     (lstrlenW(str)+1) * sizeof(WCHAR) );
+    if (!ret)
+        return ret;
+
+    /* copy the string and set the pointers */
+    p = (LPWSTR) &ret[count+1];
+    lstrcpyW( p, str );
+    for( count = 0; (ret[count] = p); count++ )
+    {
+        p = strchrW( p, sep );
+        if (p)
+            *p++ = 0;
+    }
+
+    return ret;
+}
+
+static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
+                                 MSIDATABASE *patch_db, LPCWSTR name )
+{
+    UINT ret = ERROR_FUNCTION_FAILED;
+    IStorage *stg = NULL;
+    HRESULT r;
+
+    TRACE("%p %s\n", package, debugstr_w(name) );
+
+    if (*name++ != ':')
+    {
+        ERR("expected a colon in %s\n", debugstr_w(name));
+        return ERROR_FUNCTION_FAILED;
+    }
+
+    r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
+    if (SUCCEEDED(r))
+    {
+        ret = msi_table_apply_transform( package->db, stg );
+        IStorage_Release( stg );
+        ret = ERROR_SUCCESS;
+    }
+    else
+        ERR("failed to open substorage %s\n", debugstr_w(name));
+
+    return ret;
+}
+
+static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
+{
+    static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
+    LPWSTR guid_list, *guids, product_id;
+    UINT i, ret = ERROR_FUNCTION_FAILED;
+
+    product_id = msi_dup_property( package, szProdID );
+    if (!product_id)
+    {
+        /* FIXME: the property ProductID should be written into the DB somewhere */
+        ERR("no product ID to check\n");
+        return ERROR_SUCCESS;
+    }
+
+    guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
+    guids = msi_split_string( guid_list, ';' );
+    for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
+    {
+        if (!lstrcmpW( guids[i], product_id ))
+            ret = ERROR_SUCCESS;
+    }
+    msi_free( guids );
+    msi_free( guid_list );
+    msi_free( product_id );
+
+    return ret;
+}
+
+static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
+{
+    MSISUMMARYINFO *si;
+    LPWSTR str, *substorage;
+    UINT i, r = ERROR_SUCCESS;
+
+    si = MSI_GetSummaryInformationW( patch_db, 0 );
+    if (!si)
+        return ERROR_FUNCTION_FAILED;
+
+    msi_check_patch_applicable( package, si );
+
+    /* enumerate the substorage */
+    str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
+    substorage = msi_split_string( str, ';' );
+    for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
+        r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
+    msi_free( substorage );
+    msi_free( str );
+
+    /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
+
+    msiobj_release( &si->hdr );
+
+    return r;
+}
+
+static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
+{
+    MSIDATABASE *patch_db = NULL;
+    UINT r;
+
+    TRACE("%p %s\n", package, debugstr_w( file ) );
+
+    /* FIXME:
+     *  We probably want to make sure we only open a patch collection here.
+     *  Patch collections (.msp) and databases (.msi) have different GUIDs
+     *  but currently MSI_OpenDatabaseW will accept both.
+     */
+    r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
+    if ( r != ERROR_SUCCESS )
+    {
+        ERR("failed to open patch collection %s\n", debugstr_w( file ) );
+        return r;
+    }
+
+    msi_parse_patch_summary( package, patch_db );
+    msiobj_release( &patch_db->hdr );
+
+    return ERROR_SUCCESS;
+}
+
+/* get the PATCH property, and apply all the patches it specifies */
+static UINT msi_apply_patches( MSIPACKAGE *package )
+{
+    static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
+    LPWSTR patch_list, *patches;
+    UINT i, r = ERROR_SUCCESS;
+
+    patch_list = msi_dup_property( package, szPatch );
+
+    TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
+
+    patches = msi_split_string( patch_list, ';' );
+    for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
+        r = msi_apply_patch_package( package, patches[i] );
+
+    msi_free( patches );
+    msi_free( patch_list );
+
+    return r;
+}
+
 /****************************************************
  * TOP level entry points 
  *****************************************************/
@@ -453,6 +618,8 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
 
     msi_parse_command_line( package, szCommandLine );
 
+    msi_apply_patches( package );
+
     if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
     {
         package->script->InWhatSequence |= SEQUENCE_UI;
@@ -593,7 +760,7 @@ static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
         rc = ERROR_SUCCESS;
 
     if (rc != ERROR_SUCCESS)
-        ERR("Execution halted due to error (%i)\n",rc);
+        ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
 
     return rc;
 }
@@ -708,7 +875,7 @@ static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
     
     if (rc == ERROR_SUCCESS)
     {
-        TRACE("Running the actions \n"); 
+        TRACE("Running the actions\n"); 
 
         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
         msiobj_release(&view->hdr);
@@ -727,6 +894,12 @@ static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
     BOOL run = force;
     int i;
 
+    if (!package)
+    {
+        ERR("package was null!\n");
+        return FALSE;
+    }
+
     if (!run && !package->script->CurrentlyScripting)
         run = TRUE;
    
@@ -855,7 +1028,7 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
     dir = MSI_RecordGetString(row,1);
     if (!dir)
     {
-        ERR("Unable to get folder id \n");
+        ERR("Unable to get folder id\n");
         return ERROR_SUCCESS;
     }
 
@@ -883,6 +1056,42 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
     return ERROR_SUCCESS;
 }
 
+/* FIXME: probably should merge this with the above function */
+static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
+{
+    UINT rc = ERROR_SUCCESS;
+    MSIFOLDER *folder;
+    LPWSTR install_path;
+
+    install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
+    if (!install_path)
+        return ERROR_FUNCTION_FAILED; 
+
+    /* create the path */
+    if (folder->State == 0)
+    {
+        create_full_pathW(install_path);
+        folder->State = 2;
+    }
+    msi_free(install_path);
+
+    return rc;
+}
+
+UINT msi_create_component_directories( MSIPACKAGE *package )
+{
+    MSICOMPONENT *comp;
+
+    /* create all the folders required by the components are going to install */
+    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
+    {
+        if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
+            continue;
+        msi_create_directory( package, comp->Directory );
+    }
+
+    return ERROR_SUCCESS;
+}
 
 /*
  * Also we cannot enable/disable components either, so for now I am just going 
@@ -898,13 +1107,16 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package)
     UINT rc;
     MSIQUERY *view;
 
+    /* create all the empty folders specified in the CreateFolder table */
     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
     if (rc != ERROR_SUCCESS)
         return ERROR_SUCCESS;
 
     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
     msiobj_release(&view->hdr);
-   
+
+    msi_create_component_directories( package );
+
     return rc;
 }
 
@@ -917,15 +1129,15 @@ static MSICOMPONENT* load_component( MSIRECORD * row )
         return comp;
 
     /* fill in the data */
-    comp->Component = load_dynamic_stringW( row, 1 );
+    comp->Component = msi_dup_record_field( row, 1 );
 
     TRACE("Loading Component %s\n", debugstr_w(comp->Component));
 
-    comp->ComponentId = load_dynamic_stringW( row, 2 );
-    comp->Directory = load_dynamic_stringW( row, 3 );
+    comp->ComponentId = msi_dup_record_field( row, 2 );
+    comp->Directory = msi_dup_record_field( row, 3 );
     comp->Attributes = MSI_RecordGetInteger(row,4);
-    comp->Condition = load_dynamic_stringW( row, 5 );
-    comp->KeyPath = load_dynamic_stringW( row, 6 );
+    comp->Condition = msi_dup_record_field( row, 5 );
+    comp->KeyPath = msi_dup_record_field( row, 6 );
 
     comp->Installed = INSTALLSTATE_ABSENT;
     comp->Action = INSTALLSTATE_UNKNOWN;
@@ -1031,19 +1243,19 @@ static UINT load_feature(MSIRECORD * row, LPVOID param)
 
     list_init( &feature->Components );
     
-    feature->Feature = load_dynamic_stringW( row, 1 );
+    feature->Feature = msi_dup_record_field( row, 1 );
 
     TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
 
-    feature->Feature_Parent = load_dynamic_stringW( row, 2 );
-    feature->Title = load_dynamic_stringW( row, 3 );
-    feature->Description = load_dynamic_stringW( row, 4 );
+    feature->Feature_Parent = msi_dup_record_field( row, 2 );
+    feature->Title = msi_dup_record_field( row, 3 );
+    feature->Description = msi_dup_record_field( row, 4 );
 
     if (!MSI_RecordIsNull(row,5))
         feature->Display = MSI_RecordGetInteger(row,5);
   
     feature->Level= MSI_RecordGetInteger(row,6);
-    feature->Directory = load_dynamic_stringW( row, 7 );
+    feature->Directory = msi_dup_record_field( row, 7 );
     feature->Attributes = MSI_RecordGetInteger(row,8);
 
     feature->Installed = INSTALLSTATE_ABSENT;
@@ -1079,7 +1291,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     if (!file)
         return ERROR_NOT_ENOUGH_MEMORY;
  
-    file->File = load_dynamic_stringW( row, 1 );
+    file->File = msi_dup_record_field( row, 1 );
 
     component = MSI_RecordGetString( row, 2 );
     file->Component = get_loaded_component( package, component );
@@ -1087,19 +1299,19 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     if (!file->Component)
         ERR("Unfound Component %s\n",debugstr_w(component));
 
-    file->FileName = load_dynamic_stringW( row, 3 );
+    file->FileName = msi_dup_record_field( row, 3 );
     reduce_to_longfilename( file->FileName );
 
-    file->ShortName = load_dynamic_stringW( row, 3 );
+    file->ShortName = msi_dup_record_field( row, 3 );
     reduce_to_shortfilename( file->ShortName );
     
     file->FileSize = MSI_RecordGetInteger( row, 4 );
-    file->Version = load_dynamic_stringW( row, 5 );
-    file->Language = load_dynamic_stringW( row, 6 );
+    file->Version = msi_dup_record_field( row, 5 );
+    file->Language = msi_dup_record_field( row, 6 );
     file->Attributes = MSI_RecordGetInteger( row, 7 );
     file->Sequence = MSI_RecordGetInteger( row, 8 );
 
-    file->State = 0;
+    file->state = msifs_invalid;
 
     TRACE("File Loaded (%s)\n",debugstr_w(file->File));  
 
@@ -1154,11 +1366,8 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package)
     static const WCHAR szCosting[] =
         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
     static const WCHAR szZero[] = { '0', 0 };
-    WCHAR buffer[3];
-    DWORD sz = 3;
 
-    MSI_GetPropertyW(package, szCosting, buffer, &sz);
-    if (buffer[0]=='1')
+    if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
         return ERROR_SUCCESS;
     
     MSI_SetPropertyW(package, szCosting, szZero);
@@ -1239,7 +1448,7 @@ static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
     if (!row)
         return NULL;
 
-    ptargetdir = targetdir = load_dynamic_stringW(row,3);
+    ptargetdir = targetdir = msi_dup_record_field(row,3);
 
     /* split src and target dir */
     if (strchrW(targetdir,':'))
@@ -1404,6 +1613,8 @@ static UINT SetFeatureStates(MSIPACKAGE *package)
         {'A','D','D','L','O','C','A','L',0};
     static const WCHAR szRemove[] =
         {'R','E','M','O','V','E',0};
+    static const WCHAR szReinstall[] =
+        {'R','E','I','N','S','T','A','L','L',0};
     BOOL override = FALSE;
     MSICOMPONENT* component;
     MSIFEATURE *feature;
@@ -1439,6 +1650,7 @@ static UINT SetFeatureStates(MSIPACKAGE *package)
      */
     override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
     override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
+    override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
 
     if (!override)
     {
@@ -1617,13 +1829,10 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
     UINT rc;
     MSIQUERY * view;
     LPWSTR level;
-    DWORD sz = 3;
-    WCHAR buffer[3];
 
-    MSI_GetPropertyW(package, szCosting, buffer, &sz);
-    if (buffer[0]=='1')
+    if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
         return ERROR_SUCCESS;
-
+    
     TRACE("Building Directory properties\n");
 
     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
@@ -1661,7 +1870,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
 
         if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
         {
-            file->State = 1;
+            file->state = msifs_missing;
             comp->Cost += file->FileSize;
             continue;
         }
@@ -1672,14 +1881,13 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
             DWORD versize;
             UINT sz;
             LPVOID version;
-            static const WCHAR name[] = 
-                {'\\',0};
+            static WCHAR name[] = {'\\',0};
             static const WCHAR name_fmt[] = 
                 {'%','u','.','%','u','.','%','u','.','%','u',0};
             WCHAR filever[0x100];
             VS_FIXEDFILEINFO *lpVer;
 
-            TRACE("Version comparison.. \n");
+            TRACE("Version comparison..\n");
             versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
             version = msi_alloc(versize);
             GetFileVersionInfoW(file->TargetPath, 0, versize, version);
@@ -1696,16 +1904,16 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package)
                   debugstr_w(filever));
             if (strcmpiW(filever,file->Version)<0)
             {
-                file->State = 2;
-                FIXME("cost should be diff in size\n");
+                file->state = msifs_overwrite;
+                /* FIXME: cost should be diff in size */
                 comp->Cost += file->FileSize;
             }
             else
-                file->State = 3;
+                file->state = msifs_present;
             msi_free(version);
         }
         else
-            file->State = 3;
+            file->state = msifs_present;
     }
 
     TRACE("Evaluating Condition Table\n");
@@ -1893,7 +2101,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
     if (!comp)
         return ERROR_SUCCESS;
 
-    if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
+    if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
     {
         TRACE("Skipping write due to disabled component %s\n",
                         debugstr_w(component));
@@ -2349,9 +2557,6 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
     MSICOMPONENT *comp;
     HKEY hkey=0,hkey2=0;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     /* writes the Component and Features values to the registry */
 
     rc = MSIREG_OpenComponents(&hkey);
@@ -2385,8 +2590,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
             * Write the keypath out if the component is to be registered
             * and delete the key if the component is to be deregistered
             */
-            if (ACTION_VerifyComponentForAction(package, comp,
-                                    INSTALLSTATE_LOCAL))
+            if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
             {
                 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
                 if (rc != ERROR_SUCCESS)
@@ -2417,8 +2621,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
                     msiobj_release( &uirow->hdr );
                }
             }
-            else if (ACTION_VerifyComponentForAction(package, comp,
-                                    INSTALLSTATE_ABSENT))
+            else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
             {
                 DWORD res;
 
@@ -2523,7 +2726,7 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
     if (!comp)
         return ERROR_SUCCESS;
 
-    if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
+    if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
     {
         TRACE("Skipping typelib reg due to disabled component\n");
 
@@ -2539,19 +2742,18 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
         return ERROR_SUCCESS;
 
     module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
-    if (module != NULL)
+    if (module)
     {
-        LPWSTR guid;
-        guid = load_dynamic_stringW(row,1);
-        CLSIDFromString(guid, &tl_struct.clsid);
-        msi_free(guid);
+        LPCWSTR guid;
+        guid = MSI_RecordGetString(row,1);
+        CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
         tl_struct.source = strdupW( file->TargetPath );
         tl_struct.path = NULL;
 
         EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
                         (LONG_PTR)&tl_struct);
 
-        if (tl_struct.path != NULL)
+        if (tl_struct.path)
         {
             LPWSTR help = NULL;
             LPCWSTR helpid;
@@ -2604,9 +2806,6 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
          '`','T','y','p','e','L','i','b','`',0};
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
     if (rc != ERROR_SUCCESS)
         return ERROR_SUCCESS;
@@ -2634,7 +2833,7 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
     if (!comp)
         return ERROR_SUCCESS;
 
-    if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
+    if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
     {
         TRACE("Skipping shortcut creation due to disabled component\n");
 
@@ -2755,9 +2954,6 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
          '`','S','h','o','r','t','c','u','t','`',0};
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
     if (rc != ERROR_SUCCESS)
         return ERROR_SUCCESS;
@@ -2856,9 +3052,6 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
     DWORD size;
     MSIHANDLE hDb, hSumInfo;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     /* write out icon files */
 
     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
@@ -2925,7 +3118,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
         }
         else
         {
-            ERR("Unable to query Revision_Number... \n");
+            ERR("Unable to query Revision_Number...\n");
             rc = ERROR_SUCCESS;
         }
         MsiCloseHandle(hSumInfo);
@@ -2959,7 +3152,7 @@ static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
     component = MSI_RecordGetString(row, 8);
     comp = get_loaded_component(package,component);
 
-    if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
+    if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
     {
         TRACE("Skipping ini file due to disabled component %s\n",
                         debugstr_w(component));
@@ -3133,9 +3326,6 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
     HKEY hkey=0;
     HKEY hukey=0;
     
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
     if (rc != ERROR_SUCCESS)
         goto end;
@@ -3281,55 +3471,54 @@ static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
     return ERROR_SUCCESS;
 }
 
+static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
+{
+    LPWSTR prop, val, key;
+    static const LPCSTR propval[] = {
+        "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
+        "ARPCONTACT",             "Contact",
+        "ARPCOMMENTS",            "Comments",
+        "ProductName",            "DisplayName",
+        "ProductVersion",         "DisplayVersion",
+        "ARPHELPLINK",            "HelpLink",
+        "ARPHELPTELEPHONE",       "HelpTelephone",
+        "ARPINSTALLLOCATION",     "InstallLocation",
+        "SourceDir",              "InstallSource",
+        "Manufacturer",           "Publisher",
+        "ARPREADME",              "Readme",
+        "ARPSIZE",                "Size",
+        "ARPURLINFOABOUT",        "URLInfoAbout",
+        "ARPURLUPDATEINFO",       "URLUpdateInfo",
+        NULL,
+    };
+    const LPCSTR *p = propval;
+
+    while( *p )
+    {
+        prop = strdupAtoW( *p++ );
+        key = strdupAtoW( *p++ );
+        val = msi_dup_property( package, prop );
+        msi_reg_set_val_str( hkey, key, val );
+        msi_free(val);
+        msi_free(key);
+        msi_free(prop);
+    }
+    return ERROR_SUCCESS;
+}
+
 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
 {
     HKEY hkey=0;
     LPWSTR buffer = NULL;
-    UINT rc,i;
+    UINT rc;
     DWORD size, langid;
     static const WCHAR szWindowsInstaller[] = 
-    {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
-    static const WCHAR szPropKeys[][80] = 
-    {
-{'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
-{'A','R','P','C','O','N','T','A','C','T',0},
-{'A','R','P','C','O','M','M','E','N','T','S',0},
-{'P','r','o','d','u','c','t','N','a','m','e',0},
-{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
-{'A','R','P','H','E','L','P','L','I','N','K',0},
-{'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
-{'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
-{'S','o','u','r','c','e','D','i','r',0},
-{'M','a','n','u','f','a','c','t','u','r','e','r',0},
-{'A','R','P','R','E','A','D','M','E',0},
-{'A','R','P','S','I','Z','E',0},
-{'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
-{'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
-{0},
-    };
-
-    static const WCHAR szRegKeys[][80] = 
-    {
-{'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
-{'C','o','n','t','a','c','t',0},
-{'C','o','m','m','e','n','t','s',0},
-{'D','i','s','p','l','a','y','N','a','m','e',0},
-{'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
-{'H','e','l','p','L','i','n','k',0},
-{'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
-{'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
-{'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
-{'P','u','b','l','i','s','h','e','r',0},
-{'R','e','a','d','m','e',0},
-{'S','i','z','e',0},
-{'U','R','L','I','n','f','o','A','b','o','u','t',0},
-{'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
-{0},
-    };
+        {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
     static const WCHAR szUpgradeCode[] = 
         {'U','p','g','r','a','d','e','C','o','d','e',0};
     static const WCHAR modpath_fmt[] = 
-        {'M','s','i','E','x','e','c','.','e','x','e',' ','/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
+        {'M','s','i','E','x','e','c','.','e','x','e',' ',
+         '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
     static const WCHAR szModifyPath[] = 
         {'M','o','d','i','f','y','P','a','t','h',0};
     static const WCHAR szUninstallString[] = 
@@ -3344,23 +3533,16 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
     SYSTEMTIME systime;
     static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
     LPWSTR upgrade_code;
-
-    if (!package)
-        return ERROR_INVALID_HANDLE;
+    WCHAR szDate[9]; 
 
     rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
     if (rc != ERROR_SUCCESS)
-        goto end;
+        return rc;
 
     /* dump all the info i can grab */
-    FIXME("Flesh out more information \n");
+    FIXME("Flesh out more information\n");
 
-    for( i=0; szPropKeys[i][0]; i++ )
-    {
-        buffer = msi_dup_property( package, szPropKeys[i] );
-        msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
-        msi_free(buffer);
-    }
+    msi_write_uninstall_property_vals( package, hkey );
 
     msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
     
@@ -3376,11 +3558,8 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
     msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
    
     GetLocalTime(&systime);
-    size = 9*sizeof(WCHAR);
-    buffer= msi_alloc(size);
-    sprintfW(buffer,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
-    msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, buffer );
-    msi_free(buffer);
+    sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
+    msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
    
     langid = msi_get_property_int( package, szProductLanguage, 0 );
     msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
@@ -3414,7 +3593,6 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
         msi_free(upgrade_code);
     }
     
-end:
     RegCloseKey(hkey);
 
     return ERROR_SUCCESS;
@@ -3422,23 +3600,13 @@ end:
 
 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
 {
-    UINT rc;
-
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
-    rc = execute_script(package,INSTALL_SCRIPT);
-
-    return rc;
+    return execute_script(package,INSTALL_SCRIPT);
 }
 
 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
 {
     UINT rc;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     /* turn off scheduleing */
     package->script->CurrentlyScripting= FALSE;
 
@@ -3481,9 +3649,6 @@ static UINT ACTION_ForceReboot(MSIPACKAGE *package)
     HKEY hkey;
     WCHAR squished_pc[100];
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     squash_guid(package->ProductCode,squished_pc);
 
     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
@@ -3579,9 +3744,6 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package)
         {0},
     };
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
     if (!productid)
         return ERROR_SUCCESS;
@@ -3607,17 +3769,10 @@ end:
 
 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
 {
-    static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
-    static const WCHAR szTwo[] = {'2',0};
     UINT rc;
-    LPWSTR level;
-    level = msi_dup_property( package, szUILevel );
 
-    MSI_SetPropertyW(package,szUILevel,szTwo);
     package->script->InWhatSequence |= SEQUENCE_EXEC;
     rc = ACTION_ProcessExecSequence(package,FALSE);
-    MSI_SetPropertyW(package,szUILevel,level);
-    msi_free(level);
     return rc;
 }
 
@@ -3784,8 +3939,7 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
     }
 
     /* check to make sure that component is installed */
-    if (!ACTION_VerifyComponentForAction(package, 
-                file->Component, INSTALLSTATE_LOCAL))
+    if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
     {
         TRACE("Skipping: Component not scheduled for install\n");
         return ERROR_SUCCESS;
@@ -3797,7 +3951,7 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
     if (MSI_RecordIsNull(row,2))
         name = load_ttfname_from( file->TargetPath );
     else
-        name = load_dynamic_stringW(row,2);
+        name = msi_dup_record_field(row,2);
 
     if (name)
     {
@@ -3850,9 +4004,9 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
     component = MSI_RecordGetString(rec,3);
     comp = get_loaded_component(package,component);
 
-    if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL) && 
-       !ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_SOURCE) &&
-       !ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_ADVERTISED))
+    if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) && 
+       !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
+       !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
     {
         TRACE("Skipping: Component %s not scheduled for install\n",
                         debugstr_w(component));
@@ -3944,6 +4098,12 @@ static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
     return ERROR_SUCCESS;
 }
 
+static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
+{
+    TRACE("%p\n", package);
+    return ERROR_SUCCESS;
+}
+
 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
 {
     static const WCHAR table[] =
@@ -4051,7 +4211,7 @@ static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
 }
 
 static struct _actions StandardActions[] = {
-    { szAllocateRegistrySpace, NULL},
+    { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
     { szAppSearch, ACTION_AppSearch },
     { szBindImage, ACTION_BindImage },
     { szCCPSearch, NULL},
@@ -4099,7 +4259,7 @@ static struct _actions StandardActions[] = {
     { szRemoveDuplicateFiles, NULL},
     { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
     { szRemoveExistingProducts, NULL},
-    { szRemoveFiles, NULL},
+    { szRemoveFiles, ACTION_RemoveFiles},
     { szRemoveFolders, NULL},
     { szRemoveIniValues, ACTION_RemoveIniValues },
     { szRemoveODBC, NULL},
index d2e03e2..9b3e58d 100644 (file)
@@ -93,6 +93,15 @@ typedef struct tagMSIFOLDER
     INT   Space;
 } MSIFOLDER;
 
+typedef enum _msi_file_state {
+    msifs_invalid,
+    msifs_missing,
+    msifs_overwrite,
+    msifs_present,
+    msifs_installed,
+    msifs_skipped,
+} msi_file_state;
+
 typedef struct tagMSIFILE
 {
     struct list entry;
@@ -105,14 +114,7 @@ typedef struct tagMSIFILE
     LPWSTR Language;
     INT Attributes;
     INT Sequence;   
-
-    INT State;
-       /* 0 = uninitialize */
-       /* 1 = not present */
-       /* 2 = present but replace */
-       /* 3 = present do not replace */
-       /* 4 = Installed */
-       /* 5 = Skipped */
+    msi_file_state state;
     LPWSTR  SourcePath;
     LPWSTR  TargetPath;
 } MSIFILE;
@@ -241,6 +243,7 @@ extern UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL ex
 extern UINT ACTION_AppSearch(MSIPACKAGE *package);
 extern UINT ACTION_FindRelatedProducts(MSIPACKAGE *package);
 extern UINT ACTION_InstallFiles(MSIPACKAGE *package);
+extern UINT ACTION_RemoveFiles(MSIPACKAGE *package);
 extern UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
 extern UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
 extern UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
@@ -250,7 +253,7 @@ extern UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
 
 /* Helpers */
 extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
-extern WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index);
+extern LPWSTR msi_dup_record_field(MSIRECORD *row, INT index);
 extern LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop);
 extern LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
                       BOOL set_prop, MSIFOLDER **folder);
@@ -264,7 +267,7 @@ extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR);
 extern DWORD build_version_dword(LPCWSTR);
 extern LPWSTR build_directory_name(DWORD , ...);
 extern BOOL create_full_pathW(const WCHAR *path);
-extern BOOL ACTION_VerifyComponentForAction(MSIPACKAGE*, MSICOMPONENT*, INSTALLSTATE);
+extern BOOL ACTION_VerifyComponentForAction(MSICOMPONENT*, INSTALLSTATE);
 extern BOOL ACTION_VerifyFeatureForAction(MSIFEATURE*, INSTALLSTATE);
 extern void reduce_to_longfilename(WCHAR*);
 extern void reduce_to_shortfilename(WCHAR*);
@@ -273,6 +276,7 @@ extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
 extern UINT register_unique_action(MSIPACKAGE *, LPCWSTR);
 extern BOOL check_unique_action(MSIPACKAGE *, LPCWSTR);
 extern WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... );
+extern UINT msi_create_component_directories( MSIPACKAGE *package );
 
 
 /* control event stuff */
index 91c41d5..4c59c1a 100644 (file)
@@ -118,15 +118,15 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig,
         }
 
         /* get properties */
-        sig->File = load_dynamic_stringW(row,2);
-        minVersion = load_dynamic_stringW(row,3);
+        sig->File = msi_dup_record_field(row,2);
+        minVersion = msi_dup_record_field(row,3);
         if (minVersion)
         {
             ACTION_VerStrToInteger(minVersion, &sig->MinVersionMS,
              &sig->MinVersionLS);
             msi_free( minVersion);
         }
-        maxVersion = load_dynamic_stringW(row,4);
+        maxVersion = msi_dup_record_field(row,4);
         if (maxVersion)
         {
             ACTION_VerStrToInteger(maxVersion, &sig->MaxVersionMS,
@@ -139,7 +139,7 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig,
         sig->MaxSize = MSI_RecordGetInteger(row,6);
         if (sig->MaxSize == MSI_NULL_INTEGER)
             sig->MaxSize = 0;
-        sig->Languages = load_dynamic_stringW(row,9);
+        sig->Languages = msi_dup_record_field(row,9);
         time = MSI_RecordGetInteger(row,7);
         if (time != MSI_NULL_INTEGER)
             DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &sig->MinTime);
@@ -276,9 +276,9 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
         }
 
         root = MSI_RecordGetInteger(row,2);
-        keyPath = load_dynamic_stringW(row,3);
+        keyPath = msi_dup_record_field(row,3);
         /* FIXME: keyPath needs to be expanded for properties */
-        valueName = load_dynamic_stringW(row,4);
+        valueName = msi_dup_record_field(row,4);
         /* FIXME: valueName probably does too */
         type = MSI_RecordGetInteger(row,5);
 
@@ -442,7 +442,7 @@ static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound,
         }
 
         /* get file name */
-        fileName = load_dynamic_stringW(row,2);
+        fileName = msi_dup_record_field(row,2);
         FIXME("AppSearch unimplemented for IniLocator (ini file name %s)\n",
          debugstr_w(fileName));
         msi_free( fileName);
@@ -549,7 +549,7 @@ static UINT ACTION_FileVersionMatches(MSISIGNATURE *sig, LPCWSTR filePath,
 
             if (buf)
             {
-                static const WCHAR rootW[] = { '\\',0 };
+                static WCHAR rootW[] = { '\\',0 };
                 UINT versionLen;
                 LPVOID subBlock = NULL;
 
index c834531..b7799f3 100644 (file)
@@ -65,15 +65,15 @@ static MSIAPPID *load_appid( MSIPACKAGE* package, MSIRECORD *row )
     if (!appid)
         return NULL;
     
-    appid->AppID = load_dynamic_stringW( row, 1 );
+    appid->AppID = msi_dup_record_field( row, 1 );
     TRACE("loading appid %s\n", debugstr_w( appid->AppID ));
 
     buffer = MSI_RecordGetString(row,2);
     deformat_string( package, buffer, &appid->RemoteServerName );
 
-    appid->LocalServer = load_dynamic_stringW(row,3);
-    appid->ServiceParameters = load_dynamic_stringW(row,4);
-    appid->DllSurrogate = load_dynamic_stringW(row,5);
+    appid->LocalServer = msi_dup_record_field(row,3);
+    appid->ServiceParameters = msi_dup_record_field(row,4);
+    appid->DllSurrogate = msi_dup_record_field(row,5);
 
     appid->ActivateAtStorage = !MSI_RecordIsNull(row,6);
     appid->RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
@@ -131,7 +131,7 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
 
     list_add_tail( &package->progids, &progid->entry );
 
-    progid->ProgID = load_dynamic_stringW(row,1);
+    progid->ProgID = msi_dup_record_field(row,1);
     TRACE("loading progid %s\n",debugstr_w(progid->ProgID));
 
     buffer = MSI_RecordGetString(row,2);
@@ -144,12 +144,12 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
     if (progid->Class == NULL && buffer)
         FIXME("Unknown class %s\n",debugstr_w(buffer));
 
-    progid->Description = load_dynamic_stringW(row,4);
+    progid->Description = msi_dup_record_field(row,4);
 
     if (!MSI_RecordIsNull(row,6))
     {
         INT icon_index = MSI_RecordGetInteger(row,6); 
-        LPWSTR FileName = load_dynamic_stringW(row,5);
+        LPCWSTR FileName = MSI_RecordGetString(row,5);
         LPWSTR FilePath;
         static const WCHAR fmt[] = {'%','s',',','%','i',0};
 
@@ -160,7 +160,6 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
         sprintfW(progid->IconPath,fmt,FilePath,icon_index);
 
         msi_free(FilePath);
-        msi_free(FileName);
     }
     else
     {
@@ -180,7 +179,7 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
         while (parent->Parent && parent->Parent != parent)
             parent = parent->Parent;
 
-        FIXME("need to determing if we are really the CurVer\n");
+        /* FIXME: need to determing if we are really the CurVer */
 
         progid->CurVer = parent;
         parent->VersionInd = progid;
@@ -235,28 +234,28 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
 
     list_add_tail( &package->classes, &cls->entry );
 
-    cls->clsid = load_dynamic_stringW( row, 1 );
+    cls->clsid = msi_dup_record_field( row, 1 );
     TRACE("loading class %s\n",debugstr_w(cls->clsid));
-    cls->Context = load_dynamic_stringW( row, 2 );
+    cls->Context = msi_dup_record_field( row, 2 );
     buffer = MSI_RecordGetString(row,3);
     cls->Component = get_loaded_component(package, buffer);
 
-    cls->ProgIDText = load_dynamic_stringW(row,4);
+    cls->ProgIDText = msi_dup_record_field(row,4);
     cls->ProgID = load_given_progid(package, cls->ProgIDText);
 
-    cls->Description = load_dynamic_stringW(row,5);
+    cls->Description = msi_dup_record_field(row,5);
 
     buffer = MSI_RecordGetString(row,6);
     if (buffer)
         cls->AppID = load_given_appid(package, buffer);
 
-    cls->FileTypeMask = load_dynamic_stringW(row,7);
+    cls->FileTypeMask = msi_dup_record_field(row,7);
 
     if (!MSI_RecordIsNull(row,9))
     {
 
         INT icon_index = MSI_RecordGetInteger(row,9); 
-        LPWSTR FileName = load_dynamic_stringW(row,8);
+        LPCWSTR FileName = MSI_RecordGetString(row,8);
         LPWSTR FilePath;
         static const WCHAR fmt[] = {'%','s',',','%','i',0};
 
@@ -267,7 +266,6 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
         sprintfW(cls->IconPath,fmt,FilePath,icon_index);
 
         msi_free(FilePath);
-        msi_free(FileName);
     }
     else
     {
@@ -300,7 +298,7 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
         }
         else
         {
-            cls->DefInprocHandler32 = load_dynamic_stringW( row, 10);
+            cls->DefInprocHandler32 = msi_dup_record_field( row, 10);
             reduce_to_longfilename(cls->DefInprocHandler32);
         }
     }
@@ -366,13 +364,13 @@ static MSIMIME *load_mime( MSIPACKAGE* package, MSIRECORD *row )
     if (!mt)
         return mt;
 
-    mt->ContentType = load_dynamic_stringW( row, 1 ); 
+    mt->ContentType = msi_dup_record_field( row, 1 ); 
     TRACE("loading mime %s\n", debugstr_w(mt->ContentType));
 
     buffer = MSI_RecordGetString( row, 2 );
     mt->Extension = load_given_extension( package, buffer );
 
-    mt->clsid = load_dynamic_stringW( row, 3 );
+    mt->clsid = msi_dup_record_field( row, 3 );
     mt->Class = load_given_class( package, mt->clsid );
 
     list_add_tail( &package->mimes, &mt->entry );
@@ -428,13 +426,13 @@ static MSIEXTENSION *load_extension( MSIPACKAGE* package, MSIRECORD *row )
 
     list_add_tail( &package->extensions, &ext->entry );
 
-    ext->Extension = load_dynamic_stringW( row, 1 );
+    ext->Extension = msi_dup_record_field( row, 1 );
     TRACE("loading extension %s\n", debugstr_w(ext->Extension));
 
     buffer = MSI_RecordGetString( row, 2 );
     ext->Component = get_loaded_component( package,buffer );
 
-    ext->ProgIDText = load_dynamic_stringW( row, 3 );
+    ext->ProgIDText = msi_dup_record_field( row, 3 );
     ext->ProgID = load_given_progid( package, ext->ProgIDText );
 
     buffer = MSI_RecordGetString( row, 4 );
@@ -505,7 +503,7 @@ static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
     if (!verb)
         return ERROR_OUTOFMEMORY;
 
-    verb->Verb = load_dynamic_stringW(row,2);
+    verb->Verb = msi_dup_record_field(row,2);
     TRACE("loading verb %s\n",debugstr_w(verb->Verb));
     verb->Sequence = MSI_RecordGetInteger(row,3);
 
@@ -837,9 +835,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
     BOOL install_on_demand = FALSE;
     MSICLASS *cls;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     load_classes_and_such(package);
     rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
     if (rc != ERROR_SUCCESS)
@@ -1043,68 +1038,36 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
     return rc;
 }
 
-static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
-                                 LPWSTR clsid)
+static LPCWSTR get_clsid_of_progid( MSIPROGID *progid )
 {
-    static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
-    static const WCHAR szDefaultIcon[] =
-        {'D','e','f','a','u','l','t','I','c','o','n',0};
-    HKEY hkey;
-
-    RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
-
-    if (progid->Description)
-        msi_reg_set_val_str( hkey, NULL, progid->Description );
-
-    if (progid->Class)
-    {   
-        msi_reg_set_subkey_val( hkey, szCLSID, NULL, progid->Class->clsid );
-        if (clsid)
-            strcpyW( clsid, progid->Class->clsid );
-    }
-    else
+    while (progid)
     {
-        FIXME("progid (%s) with null classid\n", debugstr_w(progid->ProgID));
+        if (progid->Class)
+            return progid->Class->clsid;
+        progid = progid->Parent;
     }
-
-    if (progid->IconPath)
-        msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath );
-
-    return ERROR_SUCCESS;
+    return NULL;
 }
 
-static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, 
-                LPWSTR clsid)
+static UINT register_progid( MSIPROGID* progid )
 {
-    UINT rc = ERROR_SUCCESS; 
+    static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+    static const WCHAR szDefaultIcon[] =
+        {'D','e','f','a','u','l','t','I','c','o','n',0};
+    static const WCHAR szCurVer[] =
+        {'C','u','r','V','e','r',0};
+    HKEY hkey = 0;
+    UINT rc;
 
-    if (progid->Parent == NULL)
-        rc = register_progid_base(package, progid, clsid);
-    else
+    rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey );
+    if (rc == ERROR_SUCCESS)
     {
-        DWORD disp;
-        HKEY hkey;
-        static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
-        static const WCHAR szDefaultIcon[] =
-            {'D','e','f','a','u','l','t','I','c','o','n',0};
-        static const WCHAR szCurVer[] =
-            {'C','u','r','V','e','r',0};
-
-        /* check if already registered */
-        RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
-                        KEY_ALL_ACCESS, NULL, &hkey, &disp );
-        if (disp == REG_OPENED_EXISTING_KEY)
-        {
-            TRACE("Key already registered\n");
-            RegCloseKey(hkey);
-            return rc;
-        }
-
-        TRACE("Registering Parent %s\n", debugstr_w(progid->Parent->ProgID) );
-        rc = register_progid( package, progid->Parent, clsid );
+        LPCWSTR clsid = get_clsid_of_progid( progid );
 
-        /* clsid is same as parent */
-        msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid );
+        if (clsid)
+            msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid );
+        else
+            ERR("%s has no class\n", debugstr_w( progid->ProgID ) );
 
         if (progid->Description)
             msi_reg_set_val_str( hkey, NULL, progid->Description );
@@ -1118,6 +1081,9 @@ static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid,
 
         RegCloseKey(hkey);
     }
+    else
+        ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) );
+
     return rc;
 }
 
@@ -1126,15 +1092,10 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
     MSIPROGID *progid;
     MSIRECORD *uirow;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     load_classes_and_such(package);
 
     LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
     {
-        WCHAR clsid[0x1000];
-
         /* check if this progid is to be installed */
         if (progid->Class && progid->Class->Installed)
             progid->InstallMe = TRUE;
@@ -1148,9 +1109,9 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
        
         TRACE("Registering progid %s\n", debugstr_w(progid->ProgID));
 
-        register_progid( package, progid, clsid );
+        register_progid( progid );
 
-        uirow = MSI_CreateRecord(1);
+        uirow = MSI_CreateRecord( 1 );
         MSI_RecordSetStringW( uirow, 1, progid->ProgID );
         ui_actiondata( package, szRegisterProgIdInfo, uirow );
         msiobj_release( &uirow->hdr );
@@ -1247,9 +1208,6 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
     MSIRECORD *uirow;
     BOOL install_on_demand = TRUE;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     load_classes_and_such(package);
 
     /* We need to set install_on_demand based on if the shell handles advertised
@@ -1355,9 +1313,6 @@ UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
     MSIRECORD *uirow;
     MSIMIME *mt;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     load_classes_and_such(package);
 
     LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
index 977f81a..7abf2d3 100644 (file)
 
 #include "windef.h"
 #include "winbase.h"
+#include "winuser.h"
 #include "wine/debug.h"
 #include "wine/unicode.h"
 
 #include "msi.h"
 #include "msiquery.h"
 #include "msipriv.h"
+#include "action.h"
 
 #define YYLEX_PARAM info
 #define YYPARSE_PARAM info
@@ -58,45 +60,44 @@ struct cond_str {
 static LPWSTR COND_GetString( struct cond_str *str );
 static LPWSTR COND_GetLiteral( struct cond_str *str );
 static int COND_lex( void *COND_lval, COND_input *info);
+static const WCHAR szEmpty[] = { 0 };
 
-typedef INT (*comp_int)(INT a, INT b);
-typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless);
-typedef INT (*comp_m1)(LPWSTR a,int b);
-typedef INT (*comp_m2)(int a,LPWSTR b);
-
-static INT comp_lt_i(INT a, INT b);
-static INT comp_gt_i(INT a, INT b);
-static INT comp_le_i(INT a, INT b);
-static INT comp_ge_i(INT a, INT b);
-static INT comp_eq_i(INT a, INT b);
-static INT comp_ne_i(INT a, INT b);
-static INT comp_bitand(INT a, INT b);
-static INT comp_highcomp(INT a, INT b);
-static INT comp_lowcomp(INT a, INT b);
-
-static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless);
-
-static INT comp_eq_m1(LPWSTR a, INT b);
-static INT comp_ne_m1(LPWSTR a, INT b);
-static INT comp_lt_m1(LPWSTR a, INT b);
-static INT comp_gt_m1(LPWSTR a, INT b);
-static INT comp_le_m1(LPWSTR a, INT b);
-static INT comp_ge_m1(LPWSTR a, INT b);
-
-static INT comp_eq_m2(INT a, LPWSTR b);
-static INT comp_ne_m2(INT a, LPWSTR b);
-static INT comp_lt_m2(INT a, LPWSTR b);
-static INT comp_gt_m2(INT a, LPWSTR b);
-static INT comp_le_m2(INT a, LPWSTR b);
-static INT comp_ge_m2(INT a, LPWSTR b);
+static INT compare_int( INT a, INT operator, INT b );
+static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b );
+
+static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b )
+{
+    INT r;
+
+    r = compare_string( a, op, b );
+    msi_free( a );
+    msi_free( b );
+    return r;
+}
+
+static BOOL num_from_prop( LPCWSTR p, INT *val )
+{
+    INT ret = 0, sign = 1;
+
+    if (!p)
+        return FALSE;
+    if (*p == '-')
+    {
+        sign = -1;
+        p++;
+    }
+    if (!*p)
+        return FALSE;
+    while (*p)
+    {
+        if( *p < '0' || *p > '9' )
+            return FALSE;
+        ret = ret*10 + (*p - '0');
+        p++;
+    }
+    *val = ret*sign;
+    return TRUE;
+}
 
 %}
 
@@ -107,37 +108,36 @@ static INT comp_ge_m2(INT a, LPWSTR b);
     struct cond_str str;
     LPWSTR    string;
     INT       value;
-    comp_int  fn_comp_int;
-    comp_str  fn_comp_str;
-    comp_m1   fn_comp_m1;
-    comp_m2   fn_comp_m2;
 }
 
 %token COND_SPACE COND_EOF COND_SPACE
-%token COND_OR COND_AND COND_NOT
-%token COND_LT COND_GT COND_EQ 
-%token COND_LPAR COND_RPAR COND_TILDA
+%token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
+%token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
+%token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
+%token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS
+%token COND_ILHS COND_IRHS COND_LHS COND_RHS
 %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
 %token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER
 
-%nonassoc COND_EOF COND_ERROR
+%nonassoc COND_ERROR COND_EOF
 
 %type <value> expression boolean_term boolean_factor 
-%type <value> term value_i symbol_i integer
-%type <string> identifier value_s symbol_s literal
-%type <fn_comp_int> comp_op_i
-%type <fn_comp_str> comp_op_s 
-%type <fn_comp_m1>  comp_op_m1 
-%type <fn_comp_m2>  comp_op_m2
+%type <value> value_i integer operator
+%type <string> identifier symbol_s value_s literal
 
 %%
 
 condition:
-    expression
+    expression 
         {
             COND_input* cond = (COND_input*) info;
             cond->result = $1;
         }
+  | /* empty */
+        {
+            COND_input* cond = (COND_input*) info;
+            cond->result = MSICONDITION_NONE;
+        }
     ;
 
 expression:
@@ -145,254 +145,122 @@ expression:
         {
             $$ = $1;
         }
-  | boolean_term COND_OR expression
+  | expression COND_OR boolean_term
         {
             $$ = $1 || $3;
         }
-    ;
-
-boolean_term:
-    boolean_factor
-        {
-            $$ = $1;
-        }
-    | boolean_term COND_AND boolean_factor
+  | expression COND_IMP boolean_term
         {
-            $$ = $1 && $3;
+            $$ = !$1 || $3;
         }
-    ;
-
-boolean_factor:
-    term
+  | expression COND_XOR boolean_term
         {
-            $$ = $1;
+            $$ = ( $1 || $3 ) && !( $1 && $3 );
         }
-  | COND_NOT term
+  | expression COND_EQV boolean_term
         {
-            $$ = ! $2;
+            $$ = ( $1 && $3 ) || ( !$1 && !$3 );
         }
     ;
 
-
-term:
-    value_i
+boolean_term:
+    boolean_factor
         {
             $$ = $1;
         }
-  | value_s
-        {
-            $$ = ($1 && $1[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE;
-            msi_free( $1 );
-        }
-  | value_i comp_op_i value_i
-        {
-            $$ = $2( $1, $3 );
-        }
-  | value_s comp_op_s value_s
-        {
-            $$ = $2( $1, $3, FALSE );
-            msi_free( $1 );
-            msi_free( $3 );
-        }
-  | value_s COND_TILDA comp_op_s value_s
-        {
-            $$ = $3( $1, $4, TRUE );
-            msi_free( $1 );
-            msi_free( $4 );
-        }
-  | value_s comp_op_m1 value_i
-        {
-            $$ = $2( $1, $3 );
-            msi_free( $1 );
-        }
-  | value_i comp_op_m2 value_s
+  | boolean_term COND_AND boolean_factor
         {
-            $$ = $2( $1, $3 );
-            msi_free( $3 );
-        }
-  | COND_LPAR expression COND_RPAR
-        {
-            $$ = $2;
-        }
-    ;
-
-comp_op_i:
-    /* common functions */
-   COND_EQ
-        {
-            $$ = comp_eq_i;
-        }
-  | COND_LT COND_GT
-        {
-            $$ = comp_ne_i;
-        }
-  | COND_LT
-        {
-            $$ = comp_lt_i;
-        }
-  | COND_GT
-        {
-            $$ = comp_gt_i;
-        }
-  | COND_LT COND_EQ
-        {
-            $$ = comp_le_i;
-        }
-  | COND_GT COND_EQ
-        {
-            $$ = comp_ge_i;
-        }
-  /*Int only*/
-  | COND_GT COND_LT
-        {
-            $$ = comp_bitand;
-        }
-  | COND_LT COND_LT
-        {
-            $$ = comp_highcomp;
-        }
-  | COND_GT COND_GT
-        {
-            $$ = comp_lowcomp;
+            $$ = $1 && $3;
         }
     ;
 
-comp_op_s:
-    /* common functions */
-   COND_EQ
-        {
-            $$ = comp_eq_s;
-        }
-  | COND_LT COND_GT
-        {
-            $$ = comp_ne_s;
-        }
-  | COND_LT
-        {
-            $$ = comp_lt_s;
-        }
-  | COND_GT
-        {
-            $$ = comp_gt_s;
-        }
-  | COND_LT COND_EQ
+boolean_factor:
+    COND_NOT boolean_factor
         {
-            $$ = comp_le_s;
+            $$ = $2 ? 0 : 1;
         }
-  | COND_GT COND_EQ
+  | value_i
         {
-            $$ = comp_ge_s;
+            $$ = $1 ? 1 : 0;
         }
-  /*string only*/
-  | COND_GT COND_LT
+  | value_s
         {
-            $$ = comp_substring;
+            $$ = ($1 && $1[0]) ? 1 : 0;
         }
-  | COND_LT COND_LT
+  | value_i operator value_i
         {
-            $$ = comp_start;
+            $$ = compare_int( $1, $2, $3 );
         }
-  | COND_GT COND_GT
+  | symbol_s operator value_i
         {
-            $$ = comp_end;
+            int num;
+            if (num_from_prop( $1, &num ))
+                $$ = compare_int( num, $2, $3 );
+            else 
+                $$ = ($2 == COND_NE || $2 == COND_INE );
         }
-    ;
-
-comp_op_m1:
-    /* common functions */
-   COND_EQ
+  | value_i operator symbol_s
         {
-            $$ = comp_eq_m1;
+            int num;
+            if (num_from_prop( $3, &num ))
+                $$ = compare_int( $1, $2, num );
+            else 
+                $$ = ($2 == COND_NE || $2 == COND_INE );
         }
-  | COND_LT COND_GT
+  | symbol_s operator symbol_s
         {
-            $$ = comp_ne_m1;
+            $$ = compare_and_free_strings( $1, $2, $3 );
         }
-  | COND_LT
+  | symbol_s operator literal
         {
-            $$ = comp_lt_m1;
+            $$ = compare_and_free_strings( $1, $2, $3 );
         }
-  | COND_GT
+  | literal operator symbol_s
         {
-            $$ = comp_gt_m1;
+            $$ = compare_and_free_strings( $1, $2, $3 );
         }
-  | COND_LT COND_EQ
+  | literal operator literal
         {
-            $$ = comp_le_m1;
+            $$ = compare_and_free_strings( $1, $2, $3 );
         }
-  | COND_GT COND_EQ
-        {
-            $$ = comp_ge_m1;
-        }
-  /*Not valid for mixed compares*/
-  | COND_GT COND_LT
+  | literal operator value_i
         {
             $$ = 0;
         }
-  | COND_LT COND_LT
+  | value_i operator literal
         {
             $$ = 0;
         }
-  | COND_GT COND_GT
+  | COND_LPAR expression COND_RPAR
         {
-            $$ = 0;
+            $$ = $2;
         }
     ;
 
-comp_op_m2:
+operator:
     /* common functions */
-   COND_EQ
-        {
-            $$ = comp_eq_m2;
-        }
-  | COND_LT COND_GT
-        {
-            $$ = comp_ne_m2;
-        }
-  | COND_LT
-        {
-            $$ = comp_lt_m2;
-        }
-  | COND_GT
-        {
-            $$ = comp_gt_m2;
-        }
-  | COND_LT COND_EQ
-        {
-            $$ = comp_le_m2;
-        }
-  | COND_GT COND_EQ
-        {
-            $$ = comp_ge_m2;
-        }
-  /*Not valid for mixed compares*/
-  | COND_GT COND_LT
-        {
-            $$ = 0;
-        }
-  | COND_LT COND_LT
-        {
-            $$ = 0;
-        }
-  | COND_GT COND_GT
-        {
-            $$ = 0;
-        }
-    ;
-
-value_i:
-    symbol_i
-        {
-            $$ = $1;
-        }
-  | integer
-        {
-            $$ = $1;
-        }
+    COND_EQ { $$ = COND_EQ; }
+  | COND_NE { $$ = COND_NE; }
+  | COND_LT { $$ = COND_LT; }
+  | COND_GT { $$ = COND_GT; }
+  | COND_LE { $$ = COND_LE; }
+  | COND_GE { $$ = COND_GE; }
+  | COND_SS { $$ = COND_SS; }
+  | COND_IEQ { $$ = COND_IEQ; }
+  | COND_INE { $$ = COND_INE; }
+  | COND_ILT { $$ = COND_ILT; }
+  | COND_IGT { $$ = COND_IGT; }
+  | COND_ILE { $$ = COND_ILE; }
+  | COND_IGE { $$ = COND_IGE; }
+  | COND_ISS { $$ = COND_ISS; }
+  | COND_LHS { $$ = COND_LHS; }
+  | COND_RHS { $$ = COND_RHS; }
+  | COND_ILHS { $$ = COND_ILHS; }
+  | COND_IRHS { $$ = COND_IRHS; }
     ;
 
 value_s:
-  symbol_s
+    symbol_s
     {
         $$ = $1;
     } 
@@ -411,8 +279,12 @@ literal:
         }
     ;
 
-symbol_i:
-    COND_DOLLARS identifier
+value_i:
+    integer
+        {
+            $$ = $1;
+        }
+  | COND_DOLLARS identifier
         {
             COND_input* cond = (COND_input*) info;
             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
@@ -453,35 +325,19 @@ symbol_i:
 symbol_s:
     identifier
         {
-            DWORD sz;
             COND_input* cond = (COND_input*) info;
 
-            sz = 0;
-            MSI_GetPropertyW(cond->package, $1, NULL, &sz);
-            if (sz == 0)
-            {
-                $$ = msi_alloc( sizeof(WCHAR));
-                $$[0] = 0;
-            }
-            else
-            {
-                sz ++;
-                $$ = msi_alloc( sz*sizeof (WCHAR) );
-
-                /* Lookup the identifier */
-
-                MSI_GetPropertyW(cond->package,$1,$$,&sz);
-            }
+            $$ = msi_dup_property( cond->package, $1 );
             msi_free( $1 );
         }
     | COND_PERCENT identifier
         {
             UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
-            if( len++ )
+            $$ = NULL;
+            if (len++)
             {
                 $$ = msi_alloc( len*sizeof (WCHAR) );
-                if( $$ )
-                    GetEnvironmentVariableW( $2, $$, len );
+                GetEnvironmentVariableW( $2, $$, len );
             }
             msi_free( $2 );
         }
@@ -522,83 +378,105 @@ static int COND_IsNumber( WCHAR x )
     return( (( x >= '0' ) && ( x <= '9' ))  || (x =='-') || (x =='.') );
 }
 
+static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub )
+{
+    LPWSTR strlower, sublower, r;
+    strlower = CharLowerW( strdupW( str ) );
+    sublower = CharLowerW( strdupW( sub ) );
+    r = strstrW( strlower, sublower );
+    if (r)
+        r = (LPWSTR)str + (r - strlower);
+    msi_free( strlower );
+    msi_free( sublower );
+    return r;
+}
 
-/* the mess of comparison functions */
-
-static INT comp_lt_i(INT a, INT b)
-{ return (a < b); }
-static INT comp_gt_i(INT a, INT b)
-{ return (a > b); }
-static INT comp_le_i(INT a, INT b)
-{ return (a <= b); }
-static INT comp_ge_i(INT a, INT b)
-{ return (a >= b); }
-static INT comp_eq_i(INT a, INT b)
-{ return (a == b); }
-static INT comp_ne_i(INT a, INT b)
-{ return (a != b); }
-static INT comp_bitand(INT a, INT b)
-{ return a & b;}
-static INT comp_highcomp(INT a, INT b)
-{ return HIWORD(a)==b; }
-static INT comp_lowcomp(INT a, INT b)
-{ return LOWORD(a)==b; }
-
-static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless)
-{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);}
-static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless)
-{ if (casless) return strcmpiW(a,b); else  return strcmpW(a,b);}
-static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless)
-{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;}
-static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless)
-{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;}
-static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless)
-{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;}
-static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless)
-{ if (casless) return strcmpiW(a,b)>=0; else return  strcmpW(a,b)>=0;}
-static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless)
-/* ERROR NOT WORKING REWRITE */
-{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;}
-static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless)
-{ if (casless) return strncmpiW(a,b,strlenW(b))==0; 
-  else return strncmpW(a,b,strlenW(b))==0;}
-static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless)
-{ 
-    int i = strlenW(a); 
-    int j = strlenW(b); 
-    if (j>i)
+static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b )
+{
+    /* null and empty string are equivalent */
+    if (!a) a = szEmpty;
+    if (!b) b = szEmpty;
+
+    /* a or b may be NULL */
+    switch (operator)
+    {
+    case COND_LT:
+        return -1 == lstrcmpW( a, b );
+    case COND_GT:
+        return  1 == lstrcmpW( a, b );
+    case COND_EQ:
+        return  0 == lstrcmpW( a, b );
+    case COND_NE:
+        return  0 != lstrcmpW( a, b );
+    case COND_GE:
+        return -1 != lstrcmpW( a, b );
+    case COND_LE:
+        return  1 != lstrcmpW( a, b );
+    case COND_SS: /* substring */
+        return strstrW( a, b ) ? 1 : 0;
+    case COND_ILT:
+        return -1 == lstrcmpiW( a, b );
+    case COND_IGT:
+        return  1 == lstrcmpiW( a, b );
+    case COND_IEQ:
+        return  0 == lstrcmpiW( a, b );
+    case COND_INE:
+        return  0 != lstrcmpiW( a, b );
+    case COND_IGE:
+        return -1 != lstrcmpiW( a, b );
+    case COND_ILE:
+        return  1 != lstrcmpiW( a, b );
+    case COND_ISS:
+        return strstriW( a, b ) ? 1 : 0;
+    case COND_LHS:
+    case COND_RHS:
+    case COND_ILHS:
+    case COND_IRHS:
+        ERR("unimplemented string comparison\n");
+        break;
+    default:
+        ERR("invalid integer operator\n");
         return 0;
-    if (casless) return (!strcmpiW(&a[i-j-1],b));
-    else  return (!strcmpW(&a[i-j-1],b));
+    }
+    return 0;
 }
 
 
-static INT comp_eq_m1(LPWSTR a, INT b)
-{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;}
-static INT comp_ne_m1(LPWSTR a, INT b)
-{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;}
-static INT comp_lt_m1(LPWSTR a, INT b)
-{ if (COND_IsNumber(a[0])) return atoiW(a)<b; else return 0;}
-static INT comp_gt_m1(LPWSTR a, INT b)
-{ if (COND_IsNumber(a[0])) return atoiW(a)>b; else return 0;}
-static INT comp_le_m1(LPWSTR a, INT b)
-{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;}
-static INT comp_ge_m1(LPWSTR a, INT b)
-{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;}
-
-static INT comp_eq_m2(INT a, LPWSTR b)
-{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;}
-static INT comp_ne_m2(INT a, LPWSTR b)
-{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;}
-static INT comp_lt_m2(INT a, LPWSTR b)
-{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;}
-static INT comp_gt_m2(INT a, LPWSTR b)
-{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;}
-static INT comp_le_m2(INT a, LPWSTR b)
-{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;}
-static INT comp_ge_m2(INT a, LPWSTR b)
-{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;}
-
+static INT compare_int( INT a, INT operator, INT b )
+{
+    switch (operator)
+    {
+    case COND_LT:
+    case COND_ILT:
+        return a < b;
+    case COND_GT:
+    case COND_IGT:
+        return a > b;
+    case COND_EQ:
+    case COND_IEQ:
+        return a == b;
+    case COND_NE:
+    case COND_INE:
+        return a != b;
+    case COND_GE:
+    case COND_IGE:
+        return a >= b;
+    case COND_LE:
+    case COND_ILE:
+        return a >= b;
+    case COND_SS:
+    case COND_ISS:
+        return ( a & b ) ? 1 : 0;
+    case COND_RHS:
+        return ( ( a & 0xffff ) == b ) ? 1 : 0;
+    case COND_LHS:
+        return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0;
+    default:
+        ERR("invalid integer operator\n");
+        return 0;
+    }
+    return 0;
+}
 
 
 static int COND_IsIdent( WCHAR x )
@@ -607,17 +485,54 @@ static int COND_IsIdent( WCHAR x )
             || ( x == '#' ) || (x == '.') );
 }
 
+static int COND_GetOperator( COND_input *cond )
+{
+    static const struct {
+        const WCHAR str[4];
+        int id;
+    } table[] = {
+        { {'~','=',0},     COND_IEQ },
+        { {'~','>','=',0}, COND_ILE },
+        { {'~','>','<',0}, COND_ISS },
+        { {'~','>','>',0}, COND_IRHS },
+        { {'~','>',0},     COND_ILT },
+        { {'~','<','>',0}, COND_INE },
+        { {'~','<','=',0}, COND_IGE },
+        { {'~','<','<',0}, COND_ILHS },
+        { {'~','<',0},     COND_IGT },
+        { {'>','=',0},     COND_GE  },
+        { {'>','<',0},     COND_SS  },
+        { {'>','>',0},     COND_LHS },
+        { {'>',0},         COND_GT  },
+        { {'<','>',0},     COND_NE  },
+        { {'<','=',0},     COND_LE  },
+        { {'<','<',0},     COND_RHS },
+        { {'<',0},         COND_LT  },
+        { {0},             0        }
+    };
+    LPCWSTR p = &cond->str[cond->n];
+    int i = 0, len;
+
+    while ( 1 )
+    {
+        len = lstrlenW( table[i].str );
+        if ( !len || 0 == strncmpW( table[i].str, p, len ) )
+            break;
+        i++;
+    }
+    cond->n += len;
+    return table[i].id;
+}
+
 static int COND_GetOne( struct cond_str *str, COND_input *cond )
 {
-    static const WCHAR szNot[] = {'N','O','T',0};
-    static const WCHAR szAnd[] = {'A','N','D',0};
-    static const WCHAR szOr[] = {'O','R',0};
-    WCHAR ch;
     int rc, len = 1;
+    WCHAR ch;
 
     str->data = &cond->str[cond->n];
 
     ch = str->data[0];
+
     switch( ch )
     {
     case 0: return 0;
@@ -630,58 +545,73 @@ static int COND_GetOne( struct cond_str *str, COND_input *cond )
     case '%': rc = COND_PERCENT; break;
     case ' ': rc = COND_SPACE; break;
     case '=': rc = COND_EQ; break;
-    case '~': rc = COND_TILDA; break;
-    case '<': rc = COND_LT; break;
-    case '>': rc = COND_GT; break;
-    case '"':
-       {
-           const WCHAR *ch2 = str->data + 1;
-
-
-           while ( *ch2 && *ch2 != '"' )
-               ++ch2;
-           if (*ch2 == '"')
-           {
-               len = ch2 - str->data + 1;
-               rc = COND_LITER;
-               break;
-           }
-       }
-       ERR("Unterminated string\n");
-       rc = COND_ERROR;
-       break;
-    default: 
-        if( COND_IsAlpha( ch ) )
-        {
-            while( COND_IsIdent( str->data[len] ) )
-                len++;
-            rc = COND_IDENT;
-            break;
-        }
+        break;
 
-        if( COND_IsNumber( ch ) )
-        {
-            while( COND_IsNumber( str->data[len] ) )
-                len++;
-            rc = COND_NUMBER;
-            break;
-        }
+    case '~':
+    case '<':
+    case '>':
+        rc = COND_GetOperator( cond );
+        if (!rc)
+            rc = COND_ERROR;
+        return rc;
+    default:
+        rc = 0;
+    }
 
-        ERR("Got unknown character %c(%x)\n",ch,ch);
-        rc = COND_ERROR;
-        break;
+    if ( rc )
+    {
+        cond->n += len;
+        return rc;
     }
 
-    /* keyword identifiers */
-    if( rc == COND_IDENT )
+    if (ch == '"' )
+    {
+        LPCWSTR p = strchrW( str->data + 1, '"' );
+       if (!p)
+            return COND_ERROR;
+        len = p - str->data + 1;
+        rc = COND_LITER;
+    }
+    else if( COND_IsAlpha( ch ) )
     {
-        if( (len==3) && (strncmpiW(str->data,szNot,len)==0) )
-            rc = COND_NOT;
-        else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) )
-            rc = COND_AND;
-        else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) )
+        static const WCHAR szNot[] = {'N','O','T',0};
+        static const WCHAR szAnd[] = {'A','N','D',0};
+        static const WCHAR szXor[] = {'X','O','R',0};
+        static const WCHAR szEqv[] = {'E','Q','V',0};
+        static const WCHAR szImp[] = {'I','M','P',0};
+        static const WCHAR szOr[] = {'O','R',0};
+
+        while( COND_IsIdent( str->data[len] ) )
+            len++;
+        rc = COND_IDENT;
+
+        if ( len == 3 )
+        {
+            if ( !strncmpiW( str->data, szNot, len ) )
+                rc = COND_NOT;
+            else if( !strncmpiW( str->data, szAnd, len ) )
+                rc = COND_AND;
+            else if( !strncmpiW( str->data, szXor, len ) )
+                rc = COND_XOR;
+            else if( !strncmpiW( str->data, szEqv, len ) )
+                rc = COND_EQV;
+            else if( !strncmpiW( str->data, szImp, len ) )
+                rc = COND_IMP;
+        }
+        else if( (len == 2) && !strncmpiW( str->data, szOr, len ) )
             rc = COND_OR;
     }
+    else if( COND_IsNumber( ch ) )
+    {
+        while( COND_IsNumber( str->data[len] ) )
+            len++;
+        rc = COND_NUMBER;
+    }
+    else
+    {
+        ERR("Got unknown character %c(%x)\n",ch,ch);
+        return COND_ERROR;
+    }
 
     cond->n += len;
     str->len = len;
@@ -731,6 +661,7 @@ static LPWSTR COND_GetLiteral( struct cond_str *str )
 
 static int COND_error(const char *str)
 {
+    TRACE("%s\n", str );
     return 0;
 }
 
@@ -739,21 +670,22 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
     COND_input cond;
     MSICONDITION r;
 
+    TRACE("%s\n", debugstr_w( szCondition ) );
+
+    if ( szCondition == NULL )
+       return MSICONDITION_NONE;
+
     cond.package = package;
     cond.str   = szCondition;
     cond.n     = 0;
-    cond.result = -1;
+    cond.result = MSICONDITION_ERROR;
     
-    TRACE("Evaluating %s\n",debugstr_w(szCondition));    
-
-    if ( szCondition == NULL || szCondition[0] == 0)
-       r = MSICONDITION_NONE;
-    else if ( !COND_parse( &cond ) )
+    if ( !COND_parse( &cond ) )
         r = cond.result;
     else
         r = MSICONDITION_ERROR;
 
-    TRACE("Evaluates to %i\n",r);
+    TRACE("%i <- %s\n", r, debugstr_w(szCondition));
     return r;
 }
 
@@ -764,7 +696,7 @@ MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szConditi
 
     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
     if( !package)
-        return ERROR_INVALID_HANDLE;
+        return MSICONDITION_ERROR;
     ret = MSI_EvaluateConditionW( package, szCondition );
     msiobj_release( &package->hdr );
     return ret;
@@ -775,16 +707,11 @@ MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szConditio
     LPWSTR szwCond = NULL;
     MSICONDITION r;
 
-    if( szCondition )
-    {
-        UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 );
-        szwCond = msi_alloc( len * sizeof (WCHAR) );
-        MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len );
-    }
+    szwCond = strdupAtoW( szCondition );
+    if( szCondition && !szwCond )
+        return MSICONDITION_ERROR;
 
     r = MsiEvaluateConditionW( hInstall, szwCond );
-
     msi_free( szwCond );
-
     return r;
 }
index 2e98a2c..fb93c62 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 
 /* below is the query interface to a table */
index efb40c5..170e214 100644 (file)
@@ -125,8 +125,7 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
      ' ','W','H','E','R','E',' ','`','A','c','t','i' ,'o','n','`',' ',
      '=',' ','\'','%','s','\'',0};
     UINT type;
-    LPWSTR source;
-    LPWSTR target;
+    LPCWSTR source, target;
     WCHAR *deformated=NULL;
 
     row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action );
@@ -135,8 +134,8 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
 
     type = MSI_RecordGetInteger(row,2);
 
-    source = load_dynamic_stringW(row,3);
-    target = load_dynamic_stringW(row,4);
+    source = MSI_RecordGetString(row,3);
+    target = MSI_RecordGetString(row,4);
 
     TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
           debugstr_w(source), debugstr_w(target));
@@ -231,8 +230,6 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
     }
 
 end:
-    msi_free(source);
-    msi_free(target);
     msiobj_release(&row->hdr);
     return rc;
 }
@@ -330,16 +327,16 @@ static UINT process_action_return_value(UINT type, HANDLE ThreadHandle)
 
     switch (rc)
     {
-        case ERROR_FUNCTION_NOT_CALLED:
-        case ERROR_SUCCESS:
-        case ERROR_INSTALL_USEREXIT:
-        case ERROR_INSTALL_FAILURE:
-            return rc;
-        case ERROR_NO_MORE_ITEMS:
-            return ERROR_SUCCESS;
-        default:
-            ERR("Invalid Return Code %lx\n",rc);
-            return ERROR_INSTALL_FAILURE;
+    case ERROR_FUNCTION_NOT_CALLED:
+    case ERROR_SUCCESS:
+    case ERROR_INSTALL_USEREXIT:
+    case ERROR_INSTALL_FAILURE:
+        return rc;
+    case ERROR_NO_MORE_ITEMS:
+        return ERROR_SUCCESS;
+    default:
+        ERR("Invalid Return Code %ld\n",rc);
+        return ERROR_INSTALL_FAILURE;
     }
 }
 
@@ -416,7 +413,7 @@ static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff)
     CustomEntry *fn;
     DWORD rc = ERROR_SUCCESS;
 
-    TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source),
+    TRACE("calling function (%s, %s)\n", debugstr_w(stuff->source),
           debugstr_w(stuff->target));
 
     hModule = LoadLibraryW(stuff->source);
@@ -546,7 +543,7 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
         msi_free(deformated);
     }
 
-    TRACE("executing exe %s \n",debugstr_w(cmd));
+    TRACE("executing exe %s\n", debugstr_w(cmd));
 
     rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
                   c_collen, &si, &info);
@@ -607,7 +604,7 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
         msi_free(deformated);
     }
 
-    TRACE("executing exe %s \n",debugstr_w(cmd));
+    TRACE("executing exe %s\n", debugstr_w(cmd));
 
     rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
                   c_collen, &si, &info);
@@ -692,7 +689,7 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
     }
     msi_free(prop);
 
-    TRACE("executing exe %s \n",debugstr_w(cmd));
+    TRACE("executing exe %s\n", debugstr_w(cmd));
 
     rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
                   c_collen, &si, &info);
@@ -732,7 +729,7 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
     if (!deformated)
         return ERROR_FUNCTION_FAILED;
 
-    TRACE("executing exe %s \n",debugstr_w(deformated));
+    TRACE("executing exe %s\n", debugstr_w(deformated));
 
     rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,
                   c_collen, &si, &info);
index d4a9655..4da5338 100644 (file)
 
 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
-
 DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000,
              0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
 DEFINE_GUID( CLSID_MsiPatch, 0x000c1086, 0x0000, 0x0000,
@@ -67,6 +59,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
     DWORD r;
 
     free_cached_tables( db );
+    msi_free_transforms( db );
     msi_destroy_stringtable( db->strings );
     r = IStorage_Release( db->storage );
     if( r )
@@ -156,6 +149,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
     db->storage = stg;
     db->mode = szMode;
     list_init( &db->tables );
+    list_init( &db->transforms );
 
     db->strings = load_string_table( stg );
     if( !db->strings )
index d42bf60..7f6675f 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 
 /*
index 7a9c20d..3975891 100644 (file)
@@ -19,6 +19,8 @@
  */
 
 #define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
 
 #include <stdarg.h>
 
@@ -80,6 +82,8 @@ struct msi_dialog_tag
     msi_font *font_list;
     struct list controls;
     HWND hWndFocus;
+    LPWSTR control_default;
+    LPWSTR control_cancel;
     WCHAR name[1];
 };
 
@@ -102,9 +106,9 @@ const WCHAR szMsiDialogClass[] = {
 };
 const WCHAR szMsiHiddenWindow[] = {
     'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 };
-const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
-const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
-const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
+static const WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
+static const WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
+static const WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
 static const WCHAR szText[] = { 'T','e','x','t',0 };
 static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 };
 static const WCHAR szLine[] = { 'L','i','n','e',0 };
@@ -121,6 +125,8 @@ static const WCHAR szProgressBar[] = {
 static const WCHAR szRadioButtonGroup[] = { 
     'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 };
 static const WCHAR szIcon[] = { 'I','c','o','n',0 };
+static const WCHAR szSelectionTree[] = {
+    'S','e','l','e','c','t','i','o','n','T','r','e','e',0 };
 
 static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM );
 static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * );
@@ -359,7 +365,7 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog,
 
 static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name )
 {
-    const static WCHAR query[] = {
+    static const WCHAR query[] = {
         's','e','l','e','c','t',' ','*',' ',
         'f','r','o','m',' ','B','i','n','a','r','y',' ',
         'w','h','e','r','e',' ',
@@ -623,7 +629,7 @@ static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec )
 
 static LPWSTR msi_get_checkbox_value( msi_dialog *dialog, LPCWSTR prop )
 {
-    const static WCHAR query[] = {
+    static const WCHAR query[] = {
         'S','E','L','E','C','T',' ','*',' ',
         'F','R','O','M',' ','`','C','h','e','c','k','B','o','x',' ','`',
         'W','H','E','R','E',' ',
@@ -714,7 +720,7 @@ msi_richedit_stream_in( DWORD_PTR arg, LPBYTE buffer, LONG count, LONG *pcb )
 
 static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
 {
-    const static WCHAR szRichEdit20W[] = {
+    static const WCHAR szRichEdit20W[] = {
        'R','i','c','h','E','d','i','t','2','0','W',0
     };
     struct msi_streamin_info info;
@@ -750,6 +756,73 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
     return ERROR_SUCCESS;
 }
 
+static HBITMAP msi_load_picture( MSIDATABASE *db, LPCWSTR name,
+                                 INT cx, INT cy, DWORD flags )
+{
+    HBITMAP hOleBitmap = 0, hBitmap = 0, hOldSrcBitmap, hOldDestBitmap;
+    MSIRECORD *rec = NULL;
+    IStream *stm = NULL;
+    IPicture *pic = NULL;
+    HDC srcdc, destdc;
+    BITMAP bm;
+    UINT r;
+
+    rec = msi_get_binary_record( db, name );
+    if( !rec )
+        goto end;
+
+    r = MSI_RecordGetIStream( rec, 2, &stm );
+    msiobj_release( &rec->hdr );
+    if( r != ERROR_SUCCESS )
+        goto end;
+
+    r = OleLoadPicture( stm, 0, TRUE, &IID_IPicture, (LPVOID*) &pic );
+    IStream_Release( stm );
+    if( FAILED( r ) )
+    {
+        ERR("failed to load picture\n");
+        goto end;
+    }
+
+    r = IPicture_get_Handle( pic, (OLE_HANDLE*) &hOleBitmap );
+    if( FAILED( r ) )
+    {
+        ERR("failed to get bitmap handle\n");
+        goto end;
+    }
+    /* make the bitmap the desired size */
+    r = GetObjectW( hOleBitmap, sizeof bm, &bm );
+    if (r != sizeof bm )
+    {
+        ERR("failed to get bitmap size\n");
+        goto end;
+    }
+
+    if (flags & LR_DEFAULTSIZE)
+    {
+        cx = bm.bmWidth;
+        cy = bm.bmHeight;
+    }
+
+    srcdc = CreateCompatibleDC( NULL );
+    hOldSrcBitmap = SelectObject( srcdc, hOleBitmap );
+    destdc = CreateCompatibleDC( NULL );
+    hBitmap = CreateCompatibleBitmap( srcdc, cx, cy );
+    hOldDestBitmap = SelectObject( destdc, hBitmap );
+    StretchBlt( destdc, 0, 0, cx, cy,
+                srcdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
+    SelectObject( srcdc, hOldSrcBitmap );
+    SelectObject( destdc, hOldDestBitmap );
+    DeleteDC( srcdc );
+    DeleteDC( destdc );
+
+end:
+    if ( pic )
+        IPicture_Release( pic );
+    return hBitmap;
+}
+
 static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec )
 {
     UINT cx, cy, flags, style, attributes;
@@ -773,8 +846,7 @@ static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec )
     cy = msi_dialog_scale_unit( dialog, cy );
 
     text = msi_get_deformatted_field( dialog->package, rec, 10 );
-    control->hBitmap = msi_load_image( dialog->package->db, text,
-                                       IMAGE_BITMAP, cx, cy, flags );
+    control->hBitmap = msi_load_picture( dialog->package->db, text, cx, cy, flags );
     if( control->hBitmap )
         SendMessageW( control->hwnd, STM_SETIMAGE,
                       IMAGE_BITMAP, (LPARAM) control->hBitmap );
@@ -858,6 +930,20 @@ struct msi_maskedit_info
     struct msi_mask_group group[MASK_MAX_GROUPS];
 };
 
+static BOOL msi_mask_editable( WCHAR type )
+{
+    switch (type)
+    {
+    case '%':
+    case '#':
+    case '&':
+    case '`':
+    case '?':
+        return TRUE;
+    }
+    return FALSE;
+}
+
 static void msi_mask_control_change( struct msi_maskedit_info *info )
 {
     LPWSTR val;
@@ -871,9 +957,18 @@ static void msi_mask_control_change( struct msi_maskedit_info *info )
             ERR("can't fit control %d text into template\n",i);
             break;
         }
-        r = GetWindowTextW( info->group[i].hwnd, &val[n], info->group[i].len+1 );
-        if( r != info->group[i].len )
-            break;
+        if (!msi_mask_editable(info->group[i].type))
+        {
+            for(r=0; r<info->group[i].len; r++)
+                val[n+r] = info->group[i].type;
+            val[n+r] = 0;
+        }
+        else
+        {
+            r = GetWindowTextW( info->group[i].hwnd, &val[n], info->group[i].len+1 );
+            if( r != info->group[i].len )
+                break;
+        }
         n += r;
     }
 
@@ -991,12 +1086,6 @@ static struct msi_maskedit_info * msi_dialog_parse_groups( LPCWSTR mask )
     p++;
     for( i=0; i<MASK_MAX_GROUPS; i++ )
     {
-        while (*p=='-')
-        {
-            total++;
-            p++;
-        }
-
         /* stop at the end of the string */
         if( p[0] == 0 || p[0] == '>' )
             break;
@@ -1043,6 +1132,8 @@ msi_maskedit_create_children( struct msi_maskedit_info *info, LPCWSTR font )
 
     for( i = 0; i < info->num_groups; i++ )
     {
+        if (!msi_mask_editable( info->group[i].type ))
+            continue;
         wx = (info->group[i].ofs * width) / info->num_chars;
         ww = (info->group[i].len * width) / info->num_chars;
 
@@ -1062,7 +1153,10 @@ msi_maskedit_create_children( struct msi_maskedit_info *info, LPCWSTR font )
     }
 }
 
-/* office 2003 uses "73931<````=````=````=````=`````>@@@@@" */
+/*
+ * office 2003 uses "73931<````=````=````=````=`````>@@@@@"
+ * delphi 7 uses "<????-??????-??????-????>" and "<???-???>"
+ */
 static UINT msi_dialog_maskedit_control( msi_dialog *dialog, MSIRECORD *rec )
 {
     LPWSTR font_mask, val = NULL, font;
@@ -1228,6 +1322,63 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
     return r;
 }
 
+/******************** Selection Tree ***************************************/
+
+static void
+msi_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd,
+                                  LPCWSTR parent, HTREEITEM hParent )
+{
+    MSIFEATURE *feature;
+    TVINSERTSTRUCTW tvis;
+    HTREEITEM hitem;
+
+    LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
+    {
+        if ( lstrcmpW( parent, feature->Feature_Parent ) )
+            continue;
+
+        if ( !feature->Title )
+            continue;
+
+        memset( &tvis, 0, sizeof tvis );
+        tvis.hParent = hParent;
+        tvis.hInsertAfter = TVI_SORT;
+        if (feature->Title)
+        {
+            tvis.u.item.mask = TVIF_TEXT;
+            tvis.u.item.pszText = feature->Title;
+        }
+        tvis.u.item.lParam = (LPARAM) feature;
+        hitem = (HTREEITEM) SendMessageW( hwnd, TVM_INSERTITEMW, 0, (LPARAM) &tvis );
+        if (!hitem)
+            continue;
+
+        msi_dialog_tv_add_child_features( package, hwnd,
+                                          feature->Feature, hitem );
+    }
+}
+
+static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec )
+{
+    msi_control *control;
+    LPCWSTR prop;
+    LPWSTR val;
+    MSIPACKAGE *package = dialog->package;
+
+    prop = MSI_RecordGetString( rec, 9 );
+    val = msi_dup_property( package, prop );
+    control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW,
+                                      TVS_HASBUTTONS | WS_GROUP | WS_VSCROLL );
+    if (!control)
+        return ERROR_FUNCTION_FAILED;
+
+    msi_dialog_tv_add_child_features( package, control->hwnd, NULL, NULL );
+
+    msi_free( val );
+
+    return ERROR_SUCCESS;
+}
+
 struct control_handler msi_dialog_handler[] =
 {
     { szText, msi_dialog_text_control },
@@ -1243,6 +1394,7 @@ struct control_handler msi_dialog_handler[] =
     { szProgressBar, msi_dialog_progress_bar },
     { szRadioButtonGroup, msi_dialog_radiogroup_control },
     { szIcon, msi_dialog_icon_control },
+    { szSelectionTree, msi_dialog_selection_tree },
 };
 
 #define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0])
@@ -1309,7 +1461,7 @@ static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param )
     condition = MSI_RecordGetString( rec, 4 );
     r = MSI_EvaluateConditionW( dialog->package, condition );
     control = msi_dialog_find_control( dialog, name );
-    if( r && control )
+    if( r == MSICONDITION_TRUE && control )
     {
         TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name));
 
@@ -1558,7 +1710,7 @@ static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param )
 
     condition = MSI_RecordGetString( rec, 5 );
     r = MSI_EvaluateConditionW( dialog->package, condition );
-    if( r )
+    if( r == MSICONDITION_TRUE )
     {
         event = MSI_RecordGetString( rec, 3 );
         arg = MSI_RecordGetString( rec, 4 );
@@ -1710,11 +1862,22 @@ static UINT msi_dialog_radiogroup_handler( msi_dialog *dialog,
 
 static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd )
 {
-    msi_control *control;
+    msi_control *control = NULL;
 
     TRACE("%p %p %08x\n", dialog, hwnd, param);
 
-    control = msi_dialog_find_control_by_hwnd( dialog, hwnd );
+    switch (param)
+    {
+    case 1: /* enter */
+        control = msi_dialog_find_control( dialog, dialog->control_default );
+        break;
+    case 2: /* escape */
+        control = msi_dialog_find_control( dialog, dialog->control_cancel );
+        break;
+    default: 
+        control = msi_dialog_find_control_by_hwnd( dialog, hwnd );
+    }
+
     if( control )
     {
         if( control->handler )
@@ -1724,7 +1887,7 @@ static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd
         }
     }
     else
-        ERR("button click from nowhere\n");
+        ERR("button click from nowhere %p %d %p\n", dialog, param, hwnd);
     return 0;
 }
 
@@ -1835,6 +1998,8 @@ msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName,
         return NULL;
     }
     dialog->attributes = MSI_RecordGetInteger( rec, 6 );
+    dialog->control_default = strdupW( MSI_RecordGetString( rec, 9 ) );
+    dialog->control_cancel = strdupW( MSI_RecordGetString( rec, 10 ) );
     msiobj_release( &rec->hdr );
 
     return dialog;
@@ -1978,6 +2143,8 @@ void msi_dialog_destroy( msi_dialog *dialog )
     }
     msi_free( dialog->default_font );
 
+    msi_free( dialog->control_default );
+    msi_free( dialog->control_cancel );
     msiobj_release( &dialog->package->hdr );
     dialog->package = NULL;
     msi_free( dialog );
@@ -2018,6 +2185,8 @@ BOOL msi_dialog_register_class( void )
 void msi_dialog_unregister_class( void )
 {
     DestroyWindow( hMsiHiddenWindow );
+    hMsiHiddenWindow = NULL;
     UnregisterClassW( szMsiDialogClass, NULL );
+    UnregisterClassW( szMsiHiddenWindow, NULL );
     uiThreadId = 0;
 }
index 7ecd48d..f5b6bd2 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 typedef struct tagDISTINCTSET
 {
index c292833..694f6d6 100644 (file)
@@ -56,26 +56,6 @@ extern const WCHAR szRemoveFiles[];
 
 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
 
-static UINT create_component_directory( MSIPACKAGE* package, MSICOMPONENT *comp )
-{
-    UINT rc = ERROR_SUCCESS;
-    MSIFOLDER *folder;
-    LPWSTR install_path;
-
-    install_path = resolve_folder(package, comp->Directory, FALSE, FALSE, &folder);
-    if (!install_path)
-        return ERROR_FUNCTION_FAILED; 
-
-    /* create the path */
-    if (folder->State == 0)
-    {
-        create_full_pathW(install_path);
-        folder->State = 2;
-    }
-    msi_free(install_path);
-
-    return rc;
-}
 
 /*
  * This is a helper function for handling embedded cabinet media
@@ -139,6 +119,7 @@ static void cabinet_free(void *pv)
 
 static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
 {
+    HANDLE handle;
     DWORD dwAccess = 0;
     DWORD dwShareMode = 0;
     DWORD dwCreateDisposition = OPEN_EXISTING;
@@ -161,35 +142,62 @@ static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
         dwCreateDisposition = CREATE_NEW;
     else if (oflag & _O_CREAT)
         dwCreateDisposition = CREATE_ALWAYS;
-    return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, 
-                                dwCreateDisposition, 0, NULL);
+    handle = CreateFileA( pszFile, dwAccess, dwShareMode, NULL, 
+                          dwCreateDisposition, 0, NULL );
+    if (handle == INVALID_HANDLE_VALUE)
+        return 0;
+    return (INT_PTR) handle;
 }
 
 static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
 {
+    HANDLE handle = (HANDLE) hf;
     DWORD dwRead;
-    if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
+    if (ReadFile(handle, pv, cb, &dwRead, NULL))
         return dwRead;
     return 0;
 }
 
 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
 {
+    HANDLE handle = (HANDLE) hf;
     DWORD dwWritten;
-    if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
+    if (WriteFile(handle, pv, cb, &dwWritten, NULL))
         return dwWritten;
     return 0;
 }
 
 static int cabinet_close(INT_PTR hf)
 {
-    return CloseHandle((HANDLE)hf) ? 0 : -1;
+    HANDLE handle = (HANDLE) hf;
+    return CloseHandle(handle) ? 0 : -1;
 }
 
 static long cabinet_seek(INT_PTR hf, long dist, int seektype)
 {
+    HANDLE handle = (HANDLE) hf;
     /* flags are compatible and so are passed straight through */
-    return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
+    return SetFilePointer(handle, dist, NULL, seektype);
+}
+
+static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f )
+{
+    MSIRECORD *uirow;
+    LPWSTR uipath, p;
+
+    /* the UI chunk */
+    uirow = MSI_CreateRecord( 9 );
+    MSI_RecordSetStringW( uirow, 1, f->FileName );
+    uipath = strdupW( f->TargetPath );
+    p = strrchrW(uipath,'\\');
+    if (p)
+        p[1]=0;
+    MSI_RecordSetStringW( uirow, 9, uipath);
+    MSI_RecordSetInteger( uirow, 6, f->FileSize );
+    ui_actiondata( package, szInstallFiles, uirow);
+    msiobj_release( &uirow->hdr );
+    msi_free( uipath );
+    ui_progress( package, 2, f->FileSize, 0, 0);
 }
 
 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
@@ -199,22 +207,13 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
     case fdintCOPY_FILE:
     {
         CabData *data = (CabData*) pfdin->pv;
-        ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
-        char *file;
-
-        LPWSTR trackname;
-        LPWSTR trackpath;
-        LPWSTR tracknametmp;
-        static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
-        LPWSTR given_file;
-
-        MSIRECORD * uirow;
-        LPWSTR uipath;
+        HANDLE handle;
+        LPWSTR file;
         MSIFILE *f;
 
-        given_file = strdupAtoW(pfdin->psz1);
-        f = get_loaded_file(data->package, given_file);
-        msi_free(given_file);
+        file = strdupAtoW(pfdin->psz1);
+        f = get_loaded_file(data->package, file);
+        msi_free(file);
 
         if (!f)
         {
@@ -222,60 +221,41 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
             return 0;
         }
 
-        if (!((f->State == 1 || f->State == 2)))
+        if (f->state != msifs_missing && f->state != msifs_overwrite)
         {
             TRACE("Skipping extraction of %s\n",debugstr_a(pfdin->psz1));
             return 0;
         }
 
-        file = cabinet_alloc((len+1)*sizeof(char));
-        strcpy(file, data->cab_path);
-        strcat(file, pfdin->psz1);
-
-        TRACE("file: %s\n", debugstr_a(file));
-
-        /* track this file so it can be deleted if not installed */
-        trackpath=strdupAtoW(file);
-        tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
-        trackname = msi_alloc((strlenW(tracknametmp) + 
-                                  strlenW(tmpprefix)+1) * sizeof(WCHAR));
-
-        strcpyW(trackname,tmpprefix);
-        strcatW(trackname,tracknametmp);
-
-        track_tempfile(data->package, trackname, trackpath);
-
-        msi_free(trackpath);
-        msi_free(trackname);
-        msi_free(tracknametmp);
+        msi_file_update_ui( data->package, f );
 
-        /* the UI chunk */
-        uirow=MSI_CreateRecord(9);
-        MSI_RecordSetStringW( uirow, 1, f->FileName );
-        uipath = strdupW( f->TargetPath );
-        *(strrchrW(uipath,'\\')+1)=0;
-        MSI_RecordSetStringW(uirow,9,uipath);
-        MSI_RecordSetInteger( uirow, 6, f->FileSize );
-        ui_actiondata(data->package,szInstallFiles,uirow);
-        msiobj_release( &uirow->hdr );
-        msi_free(uipath);
+        TRACE("extracting %s\n", debugstr_w(f->TargetPath) );
 
-        ui_progress( data->package, 2, f->FileSize, 0, 0);
+        handle = CreateFileW( f->TargetPath, GENERIC_READ | GENERIC_WRITE, 0,
+                              NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
+        if ( handle == INVALID_HANDLE_VALUE )
+        {
+            ERR("failed to create %s (error %ld)\n",
+                debugstr_w( f->TargetPath ), GetLastError() );
+            return 0;
+        }
 
-        return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
+        f->state = msifs_installed;
+        return (INT_PTR) handle;
     }
     case fdintCLOSE_FILE_INFO:
     {
         FILETIME ft;
-           FILETIME ftLocal;
+        FILETIME ftLocal;
+        HANDLE handle = (HANDLE) pfdin->hf;
+
         if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
             return -1;
         if (!LocalFileTimeToFileTime(&ft, &ftLocal))
             return -1;
-        if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
+        if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
             return -1;
-
-        cabinet_close(pfdin->hf);
+        CloseHandle(handle);
         return 1;
     }
     default:
@@ -400,7 +380,8 @@ static UINT ready_volume(MSIPACKAGE* package, LPCWSTR path, LPWSTR last_volume,
     LPCWSTR want_volume = MSI_RecordGetString(row, 5);
     BOOL ok = check_volume(path, want_volume, volume, type);
 
-    TRACE("Readying Volume for %s (%s, %s)\n",debugstr_w(path), debugstr_w(want_volume), debugstr_w(last_volume));
+    TRACE("Readying Volume for %s (%s, %s)\n", debugstr_w(path),
+          debugstr_w(want_volume), debugstr_w(last_volume));
 
     if (check_for_sourcefile(path) && !ok)
     {
@@ -463,7 +444,7 @@ static void free_media_info( struct media_info *mi )
 }
 
 static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
-                                  MSIFILE *file, MSICOMPONENT* comp )
+                                  MSIFILE *file )
 {
     UINT rc = ERROR_SUCCESS;
     MSIRECORD * row = 0;
@@ -478,6 +459,7 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
     INT seq;
     UINT type;
     LPCWSTR prompt;
+    MSICOMPONENT *comp = file->Component;
 
     if (file->Sequence <= mi->last_sequence)
     {
@@ -560,7 +542,7 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
             mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR));
             if (MSI_GetPropertyW(package, cszSourceDir, mi->source, &sz))
             {
-                ERR("No Source dir defined \n");
+                ERR("No Source dir defined\n");
                 rc = ERROR_FUNCTION_FAILED;
             }
             else
@@ -626,14 +608,11 @@ static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
 {
     MSIFILE *file;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
         if (lstrcmpW( file_key, file->File )==0)
         {
-            if (file->State >= 2)
+            if (file->state >= msifs_overwrite)
             {
                 *file_source = strdupW( file->TargetPath );
                 return ERROR_SUCCESS;
@@ -647,11 +626,11 @@ static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
 }
 
 /*
- * In order to make this work more effeciencly I am going to do this in 2
- * passes.
- * Pass 1) Correct all the TargetPaths and determin what files are to be
- * installed.
- * Pass 2) Extract Cabinents and copy files.
+ * ACTION_InstallFiles()
+ * 
+ * For efficiency, this is done in two passes:
+ * 1) Correct all the TargetPaths and determine what files are to be installed.
+ * 2) Extract Cabinets and copy files.
  */
 UINT ACTION_InstallFiles(MSIPACKAGE *package)
 {
@@ -660,13 +639,10 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
     LPWSTR ptr;
     MSIFILE *file;
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     /* increment progress bar each time action data is sent */
     ui_progress(package,1,1,0,0);
 
-    /* handle the keys for the SouceList */
+    /* handle the keys for the SourceList */
     ptr = strrchrW(package->PackagePath,'\\');
     if (ptr)
     {
@@ -676,107 +652,88 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
                 MSICODE_PRODUCT,
                 INSTALLPROPERTY_PACKAGENAMEW, ptr);
     }
-    FIXME("Write DiskPrompt\n");
+    /* FIXME("Write DiskPrompt\n"); */
     
     /* Pass 1 */
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
-        MSICOMPONENT* comp = NULL;
-
-        if (!ACTION_VerifyComponentForAction(package, file->Component, 
-                                       INSTALLSTATE_LOCAL))
+        if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL ))
         {
             ui_progress(package,2,file->FileSize,0,0);
             TRACE("File %s is not scheduled for install\n",
                    debugstr_w(file->File));
 
-            file->State = 5;
-            continue;
-        }
-
-        if ((file->State == 1) || (file->State == 2))
-        {
-            LPWSTR p = NULL;
-
-            TRACE("Pass 1: %s\n",debugstr_w(file->File));
-
-            create_component_directory( package, file->Component );
-
-            /* recalculate file paths because things may have changed */
-
-            comp = file->Component;
-            if (!comp)
-            {
-                ERR("No Component for file\n");
-                continue;
-            }
-
-            p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
-            msi_free(file->TargetPath);
-
-            file->TargetPath = build_directory_name(2, p, file->FileName);
-            msi_free(p);
+            file->state = msifs_skipped;
         }
     }
 
+    /*
+     * Despite MSDN specifying that the CreateFolders action
+     * should be called before InstallFiles, some installers don't
+     * do that, and they seem to work correctly.  We need to create
+     * directories here to make sure that the files can be copied.
+     */
+    msi_create_component_directories( package );
+
     mi = create_media_info();
 
     /* Pass 2 */
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
     {
-        if ((file->State == 1) || (file->State == 2))
+        if (file->state != msifs_missing && file->state != msifs_overwrite)
+            continue;
+
+        TRACE("Pass 2: %s\n",debugstr_w(file->File));
+
+        rc = ready_media_for_file( package, mi, file );
+        if (rc != ERROR_SUCCESS)
         {
-            TRACE("Pass 2: %s\n",debugstr_w(file->File));
+            ERR("Unable to ready media\n");
+            rc = ERROR_FUNCTION_FAILED;
+            break;
+        }
 
-            rc = ready_media_for_file( package, mi, file, file->Component );
-            if (rc != ERROR_SUCCESS)
-            {
-                ERR("Unable to ready media\n");
-                rc = ERROR_FUNCTION_FAILED;
-                break;
-            }
+        TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
+              debugstr_w(file->TargetPath));
 
-            TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
-                  debugstr_w(file->TargetPath));
+        if (file->state != msifs_missing && file->state != msifs_overwrite)
+            continue;
 
-            if (file->Attributes & msidbFileAttributesNoncompressed)
-                rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
-            else
-                rc = MoveFileW(file->SourcePath, file->TargetPath);
+        /* compressed files are extracted in ready_media_for_file */
+        if (~file->Attributes & msidbFileAttributesNoncompressed)
+        {
+            if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(file->TargetPath))
+                ERR("compressed file wasn't extracted (%s)\n",
+                    debugstr_w(file->TargetPath));
+            continue;
+        }
 
-            if (!rc)
+        rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
+        if (!rc)
+        {
+            rc = GetLastError();
+            ERR("Unable to copy file (%s -> %s) (error %d)\n",
+                debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), rc);
+            if (rc == ERROR_ALREADY_EXISTS && file->state == msifs_overwrite)
             {
-                rc = GetLastError();
-                ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
-                     debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
-                      rc);
-                if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
-                {
-                    if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
-                        ERR("Unable to copy file (%s -> %s) (error %ld)\n",
-                            debugstr_w(file->SourcePath), 
-                            debugstr_w(file->TargetPath), GetLastError());
-                    if (!(file->Attributes & msidbFileAttributesNoncompressed))
-                        DeleteFileW(file->SourcePath);
-                    rc = 0;
-                }
-                else if (rc == ERROR_FILE_NOT_FOUND)
-                {
-                    ERR("Source File Not Found!  Continuing\n");
-                    rc = 0;
-                }
-                else if (file->Attributes & msidbFileAttributesVital)
-                {
-                    ERR("Ignoring Error and continuing (nonvital file)...\n");
-                    rc = 0;
-                }
+                rc = 0;
             }
-            else
+            else if (rc == ERROR_FILE_NOT_FOUND)
+            {
+                ERR("Source File Not Found!  Continuing\n");
+                rc = 0;
+            }
+            else if (file->Attributes & msidbFileAttributesVital)
             {
-                file->State = 4;
-                rc = ERROR_SUCCESS;
+                ERR("Ignoring Error and continuing (nonvital file)...\n");
+                rc = 0;
             }
         }
+        else
+        {
+            file->state = msifs_installed;
+            rc = ERROR_SUCCESS;
+        }
     }
 
     /* cleanup */
@@ -798,7 +755,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
     component = MSI_RecordGetString(row,2);
     comp = get_loaded_component(package,component);
 
-    if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
+    if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
     {
         TRACE("Skipping copy due to disabled component %s\n",
                         debugstr_w(component));
@@ -873,7 +830,8 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
         rc = ERROR_SUCCESS;
 
     if (rc != ERROR_SUCCESS)
-        ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
+        ERR("Failed to copy file %s -> %s, last error %ld\n",
+            debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
 
     FIXME("We should track these duplicate files as well\n");   
 
@@ -892,9 +850,6 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
          '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
 
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-
     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
     if (rc != ERROR_SUCCESS)
         return ERROR_SUCCESS;
@@ -904,3 +859,29 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
 
     return rc;
 }
+
+UINT ACTION_RemoveFiles( MSIPACKAGE *package )
+{
+    MSIFILE *file;
+
+    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
+    {
+        if ( !file->Component )
+            continue;
+        if ( file->Component->Installed == INSTALLSTATE_LOCAL )
+            continue;
+
+        if ( file->state == msifs_installed )
+            ERR("removing installed file %s\n", debugstr_w(file->TargetPath));
+
+        if ( file->state != msifs_present )
+            continue;
+
+        TRACE("removing %s\n", debugstr_w(file->File) );
+        if ( !DeleteFileW( file->TargetPath ) )
+            ERR("failed to delete %s\n",  debugstr_w(file->TargetPath) );
+        file->state = msifs_missing;
+    }
+
+    return ERROR_SUCCESS;
+}
index 9bcfc7f..2730433 100644 (file)
@@ -206,7 +206,7 @@ static LPWSTR deformat_index(MSIRECORD* record, LPCWSTR key, DWORD* chunk )
 
     index = atoiW(key);
     TRACE("record index %i\n",index);
-    value = load_dynamic_stringW(record,index);
+    value = msi_dup_record_field(record,index);
     if (value)
         *chunk = strlenW(value) * sizeof(WCHAR);
     else
@@ -434,7 +434,7 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
         {
             LPBYTE nd2;
 
-            TRACE("after value %s \n",debugstr_wn((LPWSTR)newdata,
+            TRACE("after value %s\n", debugstr_wn((LPWSTR)newdata,
                                     size/sizeof(WCHAR)));
             chunk = (len - (progress - ptr)) * sizeof(WCHAR);
             TRACE("after chunk is %li + %li\n",size,chunk);
@@ -584,7 +584,7 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
 
     TRACE("%p %p %p %li\n",package, record ,buffer, *size);
 
-    rec = load_dynamic_stringW(record,0);
+    rec = msi_dup_record_field(record,0);
     if (!rec)
         rec = build_default_format(record);
 
@@ -631,7 +631,7 @@ UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer,
 
     TRACE("%p %p %p %li\n",package, record ,buffer, *size);
 
-    rec = load_dynamic_stringW(record,0);
+    rec = msi_dup_record_field(record,0);
     if (!rec)
         rec = build_default_format(record);
 
index fc466ba..a47766b 100644 (file)
@@ -107,36 +107,9 @@ LPWSTR build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name )
     return FilePath;
 }
 
-WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
+LPWSTR msi_dup_record_field( MSIRECORD *row, INT index )
 {
-    UINT rc;
-    DWORD sz;
-    LPWSTR ret;
-   
-    sz = 0; 
-    if (MSI_RecordIsNull(row,index))
-        return NULL;
-
-    rc = MSI_RecordGetStringW(row,index,NULL,&sz);
-
-    /* having an empty string is different than NULL */
-    if (sz == 0)
-    {
-        ret = msi_alloc(sizeof(WCHAR));
-        ret[0] = 0;
-        return ret;
-    }
-
-    sz ++;
-    ret = msi_alloc(sz * sizeof (WCHAR));
-    rc = MSI_RecordGetStringW(row,index,ret,&sz);
-    if (rc!=ERROR_SUCCESS)
-    {
-        ERR("Unable to load dynamic string\n");
-        msi_free(ret);
-        ret = NULL;
-    }
-    return ret;
+    return strdupW( MSI_RecordGetString(row,index) );
 }
 
 LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop)
@@ -200,9 +173,6 @@ int track_tempfile( MSIPACKAGE *package, LPCWSTR name, LPCWSTR path )
 {
     MSITEMPFILE *temp;
 
-    if (!package)
-        return -1;
-
     LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry )
     {
         if (lstrcmpW( name, temp->File )==0)
@@ -751,7 +721,7 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
 
         /* update the cached actionformat */
         msi_free(package->ActionFormat);
-        package->ActionFormat = load_dynamic_stringW(row,3);
+        package->ActionFormat = msi_dup_record_field(row,3);
 
         msi_free(package->LastAction);
         package->LastAction = strdupW(action);
@@ -773,8 +743,7 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
     msiobj_release(&row->hdr);
 }
 
-BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, MSICOMPONENT* comp,
-                                            INSTALLSTATE check )
+BOOL ACTION_VerifyComponentForAction( MSICOMPONENT* comp, INSTALLSTATE check )
 {
     if (!comp)
         return FALSE;
@@ -935,7 +904,7 @@ UINT register_unique_action(MSIPACKAGE *package, LPCWSTR action)
     UINT count;
     LPWSTR *newbuf = NULL;
 
-    if (!package || !package->script)
+    if (!package->script)
         return FALSE;
 
     TRACE("Registering Action %s as having fun\n",debugstr_w(action));
@@ -958,7 +927,7 @@ BOOL check_unique_action(MSIPACKAGE *package, LPCWSTR action)
 {
     INT i;
 
-    if (!package || !package->script)
+    if (!package->script)
         return FALSE;
 
     for (i = 0; i < package->script->UniqueActionsCount; i++)
index 5d9fcb9..536daea 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 
 /* below is the query interface to a table */
index 2098cb2..b74d244 100644 (file)
@@ -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,12 +134,15 @@ 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)
+    if (awbuf->str.w && len >= *sz)
         r = ERROR_MORE_DATA;
     *sz = len;
     return r;
@@ -293,31 +296,23 @@ UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder,
 /***********************************************************************
  * MsiSetTargetPathA  (MSI.@)
  */
-UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, 
-                             LPCSTR szFolderPath)
+UINT WINAPI MsiSetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
+                               LPCSTR szFolderPath )
 {
-    LPWSTR szwFolder;
-    LPWSTR szwFolderPath;
-    UINT rc;
+    LPWSTR szwFolder = NULL, szwFolderPath = NULL;
+    UINT rc = ERROR_OUTOFMEMORY;
 
-    if (!szFolder)
-        return ERROR_FUNCTION_FAILED;
-    if (hInstall == 0)
-        return ERROR_FUNCTION_FAILED;
+    if ( !szFolder || !szFolderPath )
+        return ERROR_INVALID_PARAMETER;
 
     szwFolder = strdupAtoW(szFolder);
-    if (!szwFolder)
-        return ERROR_FUNCTION_FAILED; 
-
     szwFolderPath = strdupAtoW(szFolderPath);
-    if (!szwFolderPath)
-    {
-        msi_free(szwFolder);
-        return ERROR_FUNCTION_FAILED; 
-    }
+    if (!szwFolder || !szwFolderPath)
+        goto end;
 
-    rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
+    rc = MsiSetTargetPathW( hInstall, szwFolder, szwFolderPath );
 
+end:
     msi_free(szwFolder);
     msi_free(szwFolderPath);
 
@@ -339,12 +334,6 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
 
     TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
 
-    if (package==NULL)
-        return ERROR_INVALID_HANDLE;
-
-    if (szFolderPath[0]==0)
-        return ERROR_FUNCTION_FAILED;
-
     attrib = GetFileAttributesW(szFolderPath);
     if ( attrib != INVALID_FILE_ATTRIBUTES &&
           (!(attrib & FILE_ATTRIBUTE_DIRECTORY) ||
@@ -353,14 +342,16 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
         return ERROR_FUNCTION_FAILED;
 
     path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
-
     if (!path)
-        return ERROR_INVALID_PARAMETER;
+        return ERROR_DIRECTORY;
 
     if (attrib == INVALID_FILE_ATTRIBUTES)
     {
         if (!CreateDirectoryW(szFolderPath,NULL))
+        {
+            msi_free( path );
             return ERROR_FUNCTION_FAILED;
+        }
         RemoveDirectoryW(szFolderPath);
     }
 
@@ -410,7 +401,13 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
 
     TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
 
+    if ( !szFolder || !szFolderPath )
+        return ERROR_INVALID_PARAMETER;
+
     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+    if (!package)
+        return ERROR_INVALID_HANDLE;
+
     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
     msiobj_release( &package->hdr );
     return ret;
@@ -456,6 +453,24 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
     return TRUE;
 }
 
+/***********************************************************************
+ *           MsiSetMode    (MSI.@)
+ */
+BOOL WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState)
+{
+    switch (iRunMode)
+    {
+    case MSIRUNMODE_RESERVED11:
+    case MSIRUNMODE_WINDOWS9X:
+    case MSIRUNMODE_RESERVED14:
+    case MSIRUNMODE_RESERVED15:
+        return FALSE;
+    default:
+        FIXME("%ld %d %d\n", hInstall, iRunMode, fState);
+    }
+    return TRUE;
+}
+
 /***********************************************************************
  * MsiSetFeatureStateA (MSI.@)
  *
index bc52d1a..bfbc384 100644 (file)
 #include "wincrypt.h"
 #include "winver.h"
 #include "winuser.h"
+#include "shlobj.h"
+#include "shobjidl.h"
+#include "objidl.h"
 #include "wine/unicode.h"
 #include "action.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
-
 /* the UI level */
 INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC;
 HWND           gUIhwnd = 0;
@@ -418,7 +413,7 @@ UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
     DWORD sz = GUID_SIZE;
     static const WCHAR szPermKey[] =
         { '0','0','0','0','0','0','0','0','0','0','0','0',
-          '0','0','0','0','0','0','0', '0','0','0','0','0',
+          '0','0','0','0','0','0','0','0','0','0','0','0',
           '0','0','0','0','0','0','0','0',0};
 
     TRACE("%s %p\n",debugstr_w(szComponent), szBuffer);
@@ -839,7 +834,7 @@ UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uTyp
 {
     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),
           uType,wLanguageId,f);
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); 
 }
 
 UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
@@ -847,7 +842,7 @@ UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uT
 {
     FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),
           uType,wLanguageId,f);
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); 
 }
 
 UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
@@ -1013,6 +1008,8 @@ INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
     TRACE("%s %s %p %p\n", debugstr_w(szProduct),
            debugstr_w(szComponent), lpPathBuf, pcchBuf);
 
+    if( !szComponent )
+        return INSTALLSTATE_INVALIDARG;
     if( lpPathBuf && !pcchBuf )
         return INSTALLSTATE_INVALIDARG;
 
@@ -1081,29 +1078,20 @@ end:
  */
 INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
 {
-    INSTALLSTATE rc;
-    LPWSTR szwProduct= NULL;
-    LPWSTR szwFeature= NULL;
+    LPWSTR szwProduct = NULL, szwFeature= NULL;
+    INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
 
-    if( szProduct )
-    {
-        szwProduct = strdupAtoW( szProduct );
-        if( !szwProduct)
-            return ERROR_OUTOFMEMORY;
-    }
+    szwProduct = strdupAtoW( szProduct );
+    if ( szProduct && !szwProduct )
+        goto end;
 
-    if( szFeature )
-    {
-        szwFeature = strdupAtoW( szFeature );
-        if( !szwFeature)
-        {
-            msi_free( szwProduct);
-            return ERROR_OUTOFMEMORY;
-        }
-    }
+    szwFeature = strdupAtoW( szFeature );
+    if ( szFeature && !szwFeature )
+        goto end;
 
     rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
 
+end:
     msi_free( szwProduct);
     msi_free( szwFeature);
 
@@ -1119,12 +1107,19 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
  */
 INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
 {
+    WCHAR squishProduct[GUID_SIZE];
     UINT rc;
     DWORD sz = 0;
     HKEY hkey;
 
     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
 
+    if (!szProduct || !szFeature)
+        return INSTALLSTATE_INVALIDARG;
+
+    if (!squash_guid( szProduct, squishProduct ))
+        return INSTALLSTATE_INVALIDARG;
+
     rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE);
     if (rc != ERROR_SUCCESS)
         return INSTALLSTATE_UNKNOWN;
@@ -1134,8 +1129,8 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
 
     if (rc == ERROR_SUCCESS)
         return INSTALLSTATE_LOCAL;
-    else
-        return INSTALLSTATE_ABSENT;
+
+    return INSTALLSTATE_UNKNOWN;
 }
 
 /******************************************************************
@@ -1192,7 +1187,7 @@ end:
 UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
                 DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
 {
-    static const WCHAR szVersionResource[] = {'\\',0};
+    static WCHAR szVersionResource[] = {'\\',0};
     static const WCHAR szVersionFormat[] = {
         '%','d','.','%','d','.','%','d','.','%','d',0};
     static const WCHAR szLangFormat[] = {'%','d',0};
@@ -1373,65 +1368,134 @@ HRESULT WINAPI DllCanUnloadNow(void)
     return S_FALSE;
 }
 
-UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature,
-                                DWORD* pdwUseCount, WORD* pwDateUsed)
+/***********************************************************************
+ * MsiGetFeatureUsageW           [MSI.@]
+ */
+UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
+                                 DWORD* pdwUseCount, WORD* pwDateUsed )
 {
     FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
           pdwUseCount, pwDateUsed);
     return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
-UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature,
-                                DWORD* pdwUseCount, WORD* pwDateUsed)
+/***********************************************************************
+ * MsiGetFeatureUsageA           [MSI.@]
+ */
+UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
+                                 DWORD* pdwUseCount, WORD* pwDateUsed )
 {
-    FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
+    LPWSTR prod = NULL, feat = NULL;
+    UINT ret = ERROR_OUTOFMEMORY;
+
+    TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
           pdwUseCount, pwDateUsed);
-    return ERROR_CALL_NOT_IMPLEMENTED;
+
+    prod = strdupAtoW( szProduct );
+    if (szProduct && !prod)
+        goto end;
+
+    feat = strdupAtoW( szFeature );
+    if (szFeature && !feat)
+        goto end;
+
+    ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
+
+end:
+    msi_free( prod );
+    msi_free( feat );
+
+    return ret;
 }
 
-INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature,
-                             DWORD dwInstallMode, DWORD dwReserved)
+/***********************************************************************
+ * MsiUseFeatureExW           [MSI.@]
+ */
+INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
+                                      DWORD dwInstallMode, DWORD dwReserved )
 {
-    FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
+    INSTALLSTATE state;
+
+    TRACE("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
           dwInstallMode, dwReserved);
 
-    /*
-     * Polls all the components of the feature to find install state and then
-     *  writes:
-     *    Software\\Microsoft\\Windows\\CurrentVersion\\
-     *    Installer\\Products\\<squishguid>\\<feature>
-     *      "Usage"=dword:........
-     */
+    state = MsiQueryFeatureStateW( szProduct, szFeature );
 
-    return INSTALLSTATE_LOCAL;
+    if (dwReserved)
+        return INSTALLSTATE_INVALIDARG;
+
+    if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
+    {
+        FIXME("mark product %s feature %s as used\n",
+              debugstr_w(szProduct), debugstr_w(szFeature) );
+    }
+
+    return state;
 }
 
 /***********************************************************************
  * MsiUseFeatureExA           [MSI.@]
  */
-INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR szProduct, LPCSTR szFeature,
-                             DWORD dwInstallMode, DWORD dwReserved)
+INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
+                                      DWORD dwInstallMode, DWORD dwReserved )
 {
-    FIXME("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
+    INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
+    LPWSTR prod = NULL, feat = NULL;
+
+    TRACE("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
           dwInstallMode, dwReserved);
 
-    return INSTALLSTATE_LOCAL;
+    prod = strdupAtoW( szProduct );
+    if (szProduct && !prod)
+        goto end;
+
+    feat = strdupAtoW( szFeature );
+    if (szFeature && !feat)
+        goto end;
+
+    ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
+
+end:
+    msi_free( prod );
+    msi_free( feat );
+
+    return ret;
 }
 
-INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR szProduct, LPCWSTR szFeature)
+INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
 {
     FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
 
     return INSTALLSTATE_LOCAL;
 }
 
-INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR szProduct, LPCSTR szFeature)
+INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
 {
-    FIXME("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature));
+    INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
+    LPWSTR prod = NULL, feat = NULL;
 
-    return INSTALLSTATE_LOCAL;
+    TRACE("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature) );
+
+    prod = strdupAtoW( szProduct );
+    if (szProduct && !prod)
+        goto end;
+
+    feat = strdupAtoW( szFeature );
+    if (szFeature && !feat)
+        goto end;
+
+    ret = MsiUseFeatureW( prod, feat );
+
+end:
+    msi_free( prod );
+    msi_free( feat );
+
+    return ret;
 }
 
+/***********************************************************************
+ * MsiProvideQualifiedComponentExW [MSI.@]
+ */
 UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
                 LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
                 DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
@@ -1441,10 +1505,9 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
     UINT rc;
     LPWSTR info;
     DWORD sz;
-    LPWSTR product = NULL;
-    LPWSTR component = NULL;
-    LPWSTR ptr;
-    GUID clsid;
+    WCHAR product[MAX_FEATURE_CHARS+1];
+    WCHAR component[MAX_FEATURE_CHARS+1];
+    WCHAR feature[MAX_FEATURE_CHARS+1];
 
     TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent),
           debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
@@ -1471,25 +1534,8 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
         return ERROR_INDEX_ABSENT;
     }
 
-    /* find the component */
-    ptr = strchrW(&info[20],'>');
-    if (ptr)
-        ptr++;
-    else
-    {
-        RegCloseKey(hkey);
-        msi_free(info);
-        return ERROR_INDEX_ABSENT;
-    }
-
-    if (!szProduct)
-    {
-        decode_base85_guid(info,&clsid);
-        StringFromCLSID(&clsid, &product);
-    }
-    decode_base85_guid(ptr,&clsid);
-    StringFromCLSID(&clsid, &component);
-
+    MsiDecomposeDescriptorW(info, product, feature, component, &sz);
+    
     if (!szProduct)
         rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf);
     else
@@ -1497,8 +1543,6 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
    
     RegCloseKey(hkey);
     msi_free(info);
-    msi_free(product);
-    msi_free(component);
 
     if (rc == INSTALLSTATE_LOCAL)
         return ERROR_SUCCESS;
@@ -1720,6 +1764,9 @@ UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
    return 0;
 }
 
+/***********************************************************************
+ * MsiGetShortcutTargetA           [MSI.@]
+ */
 UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
                                    LPSTR szProductCode, LPSTR szFeatureId,
                                    LPSTR szComponentCode )
@@ -1746,12 +1793,60 @@ UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
     return r;
 }
 
+/***********************************************************************
+ * MsiGetShortcutTargetW           [MSI.@]
+ */
 UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
                                    LPWSTR szProductCode, LPWSTR szFeatureId,
                                    LPWSTR szComponentCode )
 {
-    FIXME("%s\n", debugstr_w(szShortcutTarget));
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    IShellLinkDataList *dl = NULL;
+    IPersistFile *pf = NULL;
+    LPEXP_DARWIN_LINK darwin = NULL;
+    HRESULT r, init;
+
+    TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
+          szProductCode, szFeatureId, szComponentCode );
+
+    init = CoInitialize(NULL);
+
+    r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+                          &IID_IPersistFile, (LPVOID*) &pf );
+    if( SUCCEEDED( r ) )
+    {
+        r = IPersistFile_Load( pf, szShortcutTarget,
+                               STGM_READ | STGM_SHARE_DENY_WRITE );
+        if( SUCCEEDED( r ) )
+        {
+            r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
+                                             (LPVOID*) &dl );
+            if( SUCCEEDED( r ) )
+            {
+                IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
+                                                  (LPVOID) &darwin );
+                IShellLinkDataList_Release( dl );
+            }
+        }
+        IPersistFile_Release( pf );
+    }
+
+    if (SUCCEEDED(init))
+        CoUninitialize();
+
+    TRACE("darwin = %p\n", darwin);
+
+    if (darwin)
+    {
+        DWORD sz;
+        UINT ret;
+
+        ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
+                  szProductCode, szFeatureId, szComponentCode, &sz );
+        LocalFree( darwin );
+        return ret;
+    }
+
+    return ERROR_FUNCTION_FAILED;
 }
 
 UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
@@ -1877,3 +1972,45 @@ UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex,
           iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
     return ERROR_NO_MORE_ITEMS;
 }
+
+/***********************************************************************
+ * MsiGetFileHashW            [MSI.@]
+ */
+UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
+                             PMSIFILEHASHINFO pHash )
+{
+    FIXME("%s %08lx %p\n", debugstr_w(szFilePath), dwOptions, pHash );
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+/***********************************************************************
+ * MsiGetFileHashA            [MSI.@]
+ */
+UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
+                             PMSIFILEHASHINFO pHash )
+{
+    FIXME("%s %08lx %p\n", debugstr_a(szFilePath), dwOptions, pHash );
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+/***********************************************************************
+ * MsiAdvertiseScriptW        [MSI.@]
+ */
+UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
+                                 PHKEY phRegData, BOOL fRemoveItems )
+{
+    FIXME("%s %08lx %p %d\n",
+          debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+/***********************************************************************
+ * MsiAdvertiseScriptA        [MSI.@]
+ */
+UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
+                                 PHKEY phRegData, BOOL fRemoveItems )
+{
+    FIXME("%s %08lx %p %d\n",
+          debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
index 551af28..badc165 100644 (file)
@@ -34,6 +34,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 #include "msi_Es.rc"
 #include "msi_Fi.rc"
 #include "msi_Fr.rc"
+#include "msi_Ko.rc"
 #include "msi_Nl.rc"
 #include "msi_No.rc"
 #include "msi_Pt.rc"
index 33f2db1..28b2628 100644 (file)
@@ -31,8 +31,8 @@
 35 stdcall MsiEnableUIPreview(long ptr)
 36 stdcall MsiEnumClientsA(str long ptr)
 37 stdcall MsiEnumClientsW(wstr long ptr)
-38 stdcall MsiEnumComponentQualifiersA(str long str ptr str ptr)
-39 stdcall MsiEnumComponentQualifiersW(wstr long wstr ptr wstr ptr)
+38 stdcall MsiEnumComponentQualifiersA(str long ptr ptr ptr ptr)
+39 stdcall MsiEnumComponentQualifiersW(wstr long ptr ptr ptr ptr)
 40 stdcall MsiEnumComponentsA(long ptr)
 41 stdcall MsiEnumComponentsW(long ptr)
 42 stdcall MsiEnumFeaturesA(str long ptr ptr)
@@ -66,8 +66,8 @@
 70 stdcall MsiGetProductInfoW(wstr wstr wstr long)
 71 stdcall MsiGetProductPropertyA(long str ptr ptr)
 72 stdcall MsiGetProductPropertyW(long wstr ptr ptr)
-73 stdcall MsiGetPropertyA(ptr str str ptr)
-74 stdcall MsiGetPropertyW(ptr wstr wstr ptr)
+73 stdcall MsiGetPropertyA(ptr str ptr ptr)
+74 stdcall MsiGetPropertyW(ptr wstr ptr ptr)
 75 stdcall MsiGetSourcePathA(long str ptr ptr)
 76 stdcall MsiGetSourcePathW(long wstr ptr ptr)
 77 stdcall MsiGetSummaryInformationA(long str long ptr)
 140 stub MsiSetInstallLevel
 141 stdcall MsiSetInternalUI(long ptr)
 142 stub MsiVerifyDiskSpace
-143 stub MsiSetMode
+143 stdcall MsiSetMode(long long long)
 144 stdcall MsiSetPropertyA(long str str)
 145 stdcall MsiSetPropertyW(long wstr wstr)
 146 stdcall MsiSetTargetPathA(long str str)
 173 stdcall MsiGetComponentPathW(wstr wstr ptr ptr)
 174 stdcall MsiApplyPatchA(str str long str)
 175 stdcall MsiApplyPatchW(wstr wstr long wstr)
-176 stub MsiAdvertiseScriptA
-177 stub MsiAdvertiseScriptW
+176 stdcall MsiAdvertiseScriptA(str long ptr long)
+177 stdcall MsiAdvertiseScriptW(wstr long ptr long)
 178 stub MsiGetPatchInfoA
 179 stub MsiGetPatchInfoW
 180 stdcall MsiEnumPatchesA(str long ptr ptr ptr)
 215 stub MsiIsProductElevatedW
 216 stdcall MsiGetShortcutTargetA(str ptr ptr ptr)
 217 stdcall MsiGetShortcutTargetW(wstr ptr ptr ptr)
-218 stub MsiGetFileHashA
-219 stub MsiGetFileHashW
+218 stdcall MsiGetFileHashA(str long ptr)
+219 stdcall MsiGetFileHashW(wstr long ptr)
 220 stub MsiEnumComponentCostsA
 221 stub MsiEnumComponentCostsW
 222 stdcall MsiCreateAndVerifyInstallerDirectory(long)
diff --git a/reactos/lib/msi/msi_Ko.rc b/reactos/lib/msi/msi_Ko.rc
new file mode 100644 (file)
index 0000000..0eabd04
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Korean resources for MSI
+ *
+ * Copyright 2005 YunSong Hwang
+ *
+ * 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
+ */
+
+LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
+
+STRINGTABLE DISCARDABLE
+{
+       5 "path %s not found"
+       9 "µð½ºÅ© %s »ðÀÔ"
+       10 "Àý¸øµÈ ¸Å°³º¯¼ö"
+       11 "enter which folder contains %s"
+       12 "install source for feature missing"
+       13 "network drive for feature missing"
+       14 "feature from:"
+       15 "choose which folder contains %s"
+}
index 9f4f644..7649d39 100644 (file)
@@ -67,6 +67,7 @@ typedef struct tagMSIDATABASE
     string_table *strings;
     LPCWSTR mode;
     struct list tables;
+    struct list transforms;
 } MSIDATABASE;
 
 typedef struct tagMSIVIEW MSIVIEW;
@@ -219,6 +220,16 @@ typedef struct tagMSIPREVIEW
     msi_dialog *dialog;
 } MSIPREVIEW;
 
+#define MSI_MAX_PROPS 20
+
+typedef struct tagMSISUMMARYINFO
+{
+    MSIOBJECTHDR hdr;
+    MSIDATABASE *db;
+    DWORD update_count;
+    PROPVARIANT property[MSI_MAX_PROPS];
+} MSISUMMARYINFO;
+
 #define MSIHANDLETYPE_ANY 0
 #define MSIHANDLETYPE_DATABASE 1
 #define MSIHANDLETYPE_SUMMARYINFO 2
@@ -243,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 {
@@ -259,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 * );
@@ -269,6 +283,7 @@ extern void msiobj_lock(MSIOBJECTHDR *);
 extern void msiobj_unlock(MSIOBJECTHDR *);
 
 extern void free_cached_tables( MSIDATABASE *db );
+extern void msi_free_transforms( MSIDATABASE *db );
 extern string_table *load_string_table( IStorage *stg );
 extern UINT MSI_CommitTables( MSIDATABASE *db );
 extern HRESULT init_string_table( IStorage *stg );
@@ -300,6 +315,9 @@ extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name );
 extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
                               USHORT **pdata, UINT *psz );
 
+/* transform functions */
+extern UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg );
+
 /* action internals */
 extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR );
 extern void ACTION_free_package_structures( MSIPACKAGE* );
@@ -401,6 +419,10 @@ extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD *
 extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * );
 extern UINT MSI_PreviewDialogW( MSIPREVIEW *, LPCWSTR );
 
+/* summary information */
+extern MSISUMMARYINFO *MSI_GetSummaryInformationW( MSIDATABASE *db, UINT uiUpdateCount );
+extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty );
+
 /* undocumented functions */
 UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD );
 UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR, LPWSTR, LPWSTR, LPWSTR, DWORD * );
index ed7d8eb..2cbfbed 100644 (file)
@@ -657,8 +657,7 @@ static UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
     if( TRACE_ON( msi ) )
         enum_stream_names( stg );
 
-    /* r = table_apply_transform( db, stg ); */
-    FIXME("should apply transform %s\n", debugstr_w(szTransformFile) );
+    r = msi_table_apply_transform( db, stg );
 
     IStorage_Release( stg );
 
index b17be99..27da7c6 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 
 /* below is the query interface to a table */
index b37ce4d..96bf46f 100644 (file)
@@ -31,7 +31,6 @@
 #include "wine/debug.h"
 #include "msi.h"
 #include "msiquery.h"
-#include "msipriv.h"
 #include "objidl.h"
 #include "wincrypt.h"
 #include "winuser.h"
 #include "wine/unicode.h"
 #include "objbase.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+#include "msipriv.h"
+#include "action.h"
 
-/*
- * 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
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
 static void MSI_FreePackage( MSIOBJECTHDR *arg)
 {
@@ -128,6 +122,30 @@ static UINT clone_properties(MSIDATABASE *db)
     return rc;
 }
 
+/*
+ * 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;
+}
+
 /*
  * There are a whole slew of these we need to set
  *
@@ -211,29 +229,14 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
     static const WCHAR szScreenFormat[] = {'%','d',0};
 
-/*
- * Other things I notice set
- *
-SystemLanguageID
-ComputerName
-UserLanguageID
-LogonUser
-VirtualMemory
-Intel
-ShellAdvSupport
-DefaultUIFont
-VersionDatabase
-PackagecodeChanging
-ProductState
-CaptionHeight
-BorderTop
-BorderSide
-TextHeight
-RedirectedDllSupport
-Time
-Date
-Privileged
-*/
+    /*
+     * Other things that probably should be set:
+     *
+     * SystemLanguageID ComputerName UserLanguageID LogonUser VirtualMemory
+     * Intel ShellAdvSupport DefaultUIFont VersionDatabase PackagecodeChanging
+     * ProductState CaptionHeight BorderTop BorderSide TextHeight
+     * RedirectedDllSupport Time Date Privileged
+     */
 
     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
     strcatW(pth,cszbs);
@@ -365,6 +368,8 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
 {
     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 = NULL;
     WCHAR uilevel[10];
 
@@ -401,6 +406,9 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
         set_installer_properties(package);
         sprintfW(uilevel,szpi,gUILevel);
         MSI_SetPropertyW(package, szLevel, uilevel);
+
+        package->ProductCode = msi_dup_property( package, szProductCode );
+        set_installed_prop( package );
     }
 
     return package;
@@ -439,8 +447,6 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     MSIDATABASE *db = NULL;
     MSIPACKAGE *package;
     MSIHANDLE handle;
-    DWORD size;
-    static const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0};
     UINT r;
 
     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
@@ -486,13 +492,6 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
         MSI_SetPropertyW( package, Database, szPackage );
     }
 
-    /* this property must exist */
-    size  = 0;
-    MSI_GetPropertyW(package,szProductCode,NULL,&size);
-    size ++;
-    package->ProductCode = msi_alloc(size * sizeof(WCHAR));
-    MSI_GetPropertyW(package,szProductCode,package->ProductCode, &size);
-    
     *pPackage = package;
 
     return ERROR_SUCCESS;
@@ -577,7 +576,7 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
     char *msg;
     int len;
 
-    TRACE("%x \n",eMessageType);
+    TRACE("%x\n", eMessageType);
     rc = 0;
 
     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
@@ -605,8 +604,8 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
     {
         LPWSTR tmp;
         WCHAR number[3];
-        const static WCHAR format[] = { '%','i',':',' ',0};
-        const static WCHAR space[] = { ' ',0};
+        static const WCHAR format[] = { '%','i',':',' ',0};
+        static const WCHAR space[] = { ' ',0};
         sz = 0;
         MSI_RecordGetStringW(record,i,NULL,&sz);
         sz+=4;
@@ -690,32 +689,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)
@@ -736,8 +729,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 weird... */
+    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)
@@ -775,11 +774,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;
@@ -788,51 +782,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;
-
-    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);
-    }
+    if (!name || !name[0])
+        return NULL;
 
-    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);
@@ -853,106 +829,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 );
-    msiobj_release( &package->hdr );
 
-    /* MsiGetProperty does not return error codes on missing properties */
-    if (ret != ERROR_MORE_DATA)
-        ret = ERROR_SUCCESS;
+    row = MSI_GetPropertyRow( package, name );
+    if (row)
+        val = MSI_RecordGetString( row, 1 );
 
-    return ret;
+    if (!val)
+        val = empty;
+
+    r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );
+
+    if (row)
+        msiobj_release( &row->hdr );
+    msiobj_release( &package->hdr );
+
+    return r;
 }
 
-  
-UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, 
-                           LPWSTR szValueBuf, DWORD* pchValueBuf)
+UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
+                             LPSTR szValueBuf, DWORD* pchValueBuf )
 {
-    MSIPACKAGE *package;
-    UINT ret;
-
-    TRACE("%lu %s %p\n", hInstall, debugstr_w(szName), pchValueBuf);
+    awstring val;
+    LPWSTR name;
+    UINT r;
 
-    if (0 == hInstall)
-        return ERROR_INVALID_HANDLE;
-    if (NULL == szName)
-        return ERROR_INVALID_PARAMETER;
-    if (NULL != szValueBuf && NULL == pchValueBuf)
-        return ERROR_INVALID_PARAMETER;
+    val.unicode = FALSE;
+    val.str.a = szValueBuf;
 
-    /* This was tested against native msi */
-    if (NULL == szValueBuf && NULL != pchValueBuf)
-        *pchValueBuf = 0;
+    name = strdupAtoW( szName );
+    if (szName && !name)
+        return ERROR_OUTOFMEMORY;
 
-    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
-    if (!package)
-        return ERROR_INVALID_HANDLE;
-    ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
-    msiobj_release( &package->hdr );
+    r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
+    msi_free( name );
+    return r;
+}
+  
+UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
+                             LPWSTR szValueBuf, DWORD* pchValueBuf )
+{
+    awstring val;
 
-    /* MsiGetProperty does not return error codes on missing properties */
-    if (ret != ERROR_MORE_DATA)
-        ret = ERROR_SUCCESS;
+    val.unicode = TRUE;
+    val.str.w = szValueBuf;
 
-    return ret;
+    return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
 }
index 05f8096..c1f6d1f 100644 (file)
@@ -39,7 +39,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 #define MSIFIELD_NULL   0
 #define MSIFIELD_INT    1
index b8c206a..941608c 100644 (file)
@@ -253,6 +253,9 @@ BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
 {
     DWORD i, val = 0, base = 1, *p;
 
+    if (!str)
+        return FALSE;
+
     p = (DWORD*) guid;
     for( i=0; i<20; i++ )
     {
@@ -532,10 +535,13 @@ UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
     len = (p - &szDescriptor[20]);
     if( len > MAX_FEATURE_CHARS )
         return ERROR_INVALID_PARAMETER;
-    memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
-    szFeature[len] = 0;
+    if (szFeature)
+    {
+        memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
+        szFeature[len] = 0;
+    }
 
-    TRACE("feature %s\n", debugstr_w( szFeature ));
+    TRACE("feature %s\n", debugstr_w( &szDescriptor[20] ));
 
     r = decode_base85_guid( p+1, &component );
     if( !r )
@@ -543,8 +549,10 @@ UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
 
     TRACE("component %s\n", debugstr_guid( &component ));
 
-    StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
-    StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
+    if (szProduct)
+        StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
+    if (szComponent)
+        StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
     len = ( &p[21] - szDescriptor );
 
     TRACE("length = %d\n", len);
@@ -559,26 +567,30 @@ UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
     WCHAR product[MAX_FEATURE_CHARS+1];
     WCHAR feature[MAX_FEATURE_CHARS+1];
     WCHAR component[MAX_FEATURE_CHARS+1];
-    LPWSTR str = NULL;
+    LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
     UINT r;
 
     TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
           szFeature, szComponent, pUsed);
 
-    if( szDescriptor )
-    {
-        str = strdupAtoW( szDescriptor );
-        if( !str )
-            return ERROR_OUTOFMEMORY;
-    }
+    str = strdupAtoW( szDescriptor );
+    if( szDescriptor && !str )
+        return ERROR_OUTOFMEMORY;
+
+    if (szProduct)
+        p = product;
+    if (szFeature)
+        f = feature;
+    if (szComponent)
+        c = component;
 
-    r = MsiDecomposeDescriptorW( str, product, feature, component, pUsed );
+    r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
 
-    WideCharToMultiByte( CP_ACP, 0, product, MAX_FEATURE_CHARS+1,
+    WideCharToMultiByte( CP_ACP, 0, p, MAX_FEATURE_CHARS+1,
                          szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
-    WideCharToMultiByte( CP_ACP, 0, feature, MAX_FEATURE_CHARS+1,
+    WideCharToMultiByte( CP_ACP, 0, f, MAX_FEATURE_CHARS+1,
                          szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
-    WideCharToMultiByte( CP_ACP, 0, component, MAX_FEATURE_CHARS+1,
+    WideCharToMultiByte( CP_ACP, 0, c, MAX_FEATURE_CHARS+1,
                          szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
 
     msi_free( str );
@@ -757,157 +769,134 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
     return r;
 }
 
+UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
+                awstring *lpQualBuf, DWORD* pcchQual,
+                awstring *lpAppBuf, DWORD* pcchAppBuf )
+{
+    DWORD name_sz, val_sz, type, ofs;
+    LPWSTR name = NULL, val = NULL;
+    UINT r, r2;
+    HKEY key;
+
+    TRACE("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex,
+          lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
+
+    if (!szComponent)
+        return ERROR_INVALID_PARAMETER;
+
+    r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
+    if (r != ERROR_SUCCESS)
+        return ERROR_UNKNOWN_COMPONENT;
+
+    /* figure out how big the name is we want to return */
+    name_sz = 0;
+    if (pcchQual)
+    {
+        r = ERROR_OUTOFMEMORY;
+        name_sz = *pcchQual * 4;
+        name = msi_alloc( name_sz * sizeof(WCHAR) );
+        if (!name)
+            goto end;
+    }
+
+    /* figure out how big the value is */
+    type = 0;
+    val_sz = 0;
+    r = RegEnumValueW( key, iIndex, NULL, NULL,
+                       NULL, &type, NULL, &val_sz );
+    if (r != ERROR_SUCCESS)
+        goto end;
+
+    if (type != REG_MULTI_SZ)
+    {
+        ERR("component data has wrong type (%ld)\n", type);
+        goto end;
+    }
+
+    /* the value size is in bytes */
+    val_sz += sizeof(WCHAR);
+    val = msi_alloc( val_sz );
+    if (!val)
+        goto end;
+
+    r = RegEnumValueW( key, iIndex, name, &name_sz,
+                       NULL, &type, (LPBYTE)val, &val_sz );
+    if (r != ERROR_SUCCESS)
+        goto end;
+
+    ofs = 0;
+    r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
+    if (r != ERROR_SUCCESS)
+        goto end;
+
+    TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
+
+    r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual );
+    r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf );
+
+    if (r2 != ERROR_SUCCESS)
+        r = r2;
+
+end:
+    msi_free(val);
+    msi_free(name);
+    RegCloseKey(key);
+
+    return r;
+}
+
 /*************************************************************************
  *  MsiEnumComponentQualifiersA [MSI.@]
- *
  */
-UINT WINAPI MsiEnumComponentQualifiersA( LPSTR szComponent, DWORD iIndex,
+UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
                 LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf,
-                LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf)
+                LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf )
 {
-    LPWSTR szwComponent;
-    LPWSTR lpwQualifierBuf;
-    DWORD pcchwQualifierBuf;
-    LPWSTR lpwApplicationDataBuf;
-    DWORD pcchwApplicationDataBuf;
-    DWORD rc;
-    DWORD length;
+    awstring qual, appdata;
+    LPWSTR comp;
+    UINT r;
 
     TRACE("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex,
           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
           pcchApplicationDataBuf);
 
-    szwComponent = strdupAtoW(szComponent);
-
-    if (lpQualifierBuf)
-        lpwQualifierBuf = msi_alloc( (*pcchQualifierBuf) * sizeof(WCHAR));
-    else
-        lpwQualifierBuf = NULL;
-
-    if (pcchQualifierBuf)
-        pcchwQualifierBuf = *pcchQualifierBuf;
-    else
-        pcchwQualifierBuf = 0;
+    comp = strdupAtoW( szComponent );
+    if (szComponent && !comp)
+        return ERROR_OUTOFMEMORY;
 
-    if (lpApplicationDataBuf)
-       lpwApplicationDataBuf = msi_alloc( (*pcchApplicationDataBuf) * sizeof(WCHAR));
-    else
-        lpwApplicationDataBuf = NULL;
-
-    if (pcchApplicationDataBuf)
-        pcchwApplicationDataBuf = *pcchApplicationDataBuf;
-    else
-        pcchwApplicationDataBuf = 0;
+    qual.unicode = FALSE;
+    qual.str.a = lpQualifierBuf;
 
-    rc = MsiEnumComponentQualifiersW( szwComponent, iIndex, lpwQualifierBuf, 
-                    &pcchwQualifierBuf, lpwApplicationDataBuf,
-                    &pcchwApplicationDataBuf);
+    appdata.unicode = FALSE;
+    appdata.str.a = lpApplicationDataBuf;
 
-    /*
-     * A bit of wizardry to report back the length without the null.
-     * just in case the buffer is too small and is filled.
-     */
-    if (lpQualifierBuf)
-    {
-        length = WideCharToMultiByte(CP_ACP, 0, lpwQualifierBuf, -1,
-                        lpQualifierBuf, *pcchQualifierBuf, NULL, NULL); 
-
-        if (*pcchQualifierBuf == length && lpQualifierBuf[length-1])
-            *pcchQualifierBuf = length;
-        else
-            *pcchQualifierBuf = length - 1;
-    }
-    if (lpApplicationDataBuf)
-    {
-        length = WideCharToMultiByte(CP_ACP, 0,
-                        lpwApplicationDataBuf, -1, lpApplicationDataBuf,
-                        *pcchApplicationDataBuf, NULL, NULL); 
-
-        if (*pcchApplicationDataBuf == length && lpApplicationDataBuf[length-1])
-            *pcchApplicationDataBuf = length;
-        else
-            *pcchApplicationDataBuf = length - 1;
-    }
-
-    msi_free(lpwApplicationDataBuf);
-    msi_free(lpwQualifierBuf);
-    msi_free(szwComponent);
-
-    return rc;
+    r = MSI_EnumComponentQualifiers( comp, iIndex,
+              &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
+    msi_free( comp );
+    return r;
 }
 
 /*************************************************************************
  *  MsiEnumComponentQualifiersW [MSI.@]
- *
  */
-UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex,
+UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
                 LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf,
                 LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf )
 {
-    UINT rc;
-    HKEY key;
-    DWORD actual_pcchQualifierBuf = 0;
-    DWORD actual_pcchApplicationDataBuf = 0;
-    LPWSTR full_buffer = NULL;
-    DWORD full_buffer_size = 0;
-    LPWSTR ptr;
+    awstring qual, appdata;
 
     TRACE("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex,
           lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
           pcchApplicationDataBuf);
 
-    if (pcchQualifierBuf)
-        actual_pcchQualifierBuf = *pcchQualifierBuf * sizeof(WCHAR);
-    if (pcchApplicationDataBuf)
-        actual_pcchApplicationDataBuf = *pcchApplicationDataBuf * sizeof(WCHAR);
-    
-    rc = MSIREG_OpenUserComponentsKey(szComponent, &key, FALSE);
-    if (rc != ERROR_SUCCESS)
-        return ERROR_UNKNOWN_COMPONENT;
+    qual.unicode = TRUE;
+    qual.str.w = lpQualifierBuf;
 
-    full_buffer_size = (52 * sizeof(WCHAR)) + actual_pcchApplicationDataBuf;
-    full_buffer = msi_alloc(full_buffer_size);
-    
-    rc = RegEnumValueW(key, iIndex, lpQualifierBuf, pcchQualifierBuf, NULL, 
-                    NULL, (LPBYTE)full_buffer, &full_buffer_size);
+    appdata.unicode = TRUE;
+    appdata.str.w = lpApplicationDataBuf;
 
-    if (rc == ERROR_MORE_DATA)
-    {
-        msi_free(full_buffer);
-        full_buffer_size+=sizeof(WCHAR);
-        full_buffer = msi_alloc(full_buffer_size);
-        rc = RegEnumValueW(key, iIndex, lpQualifierBuf, pcchQualifierBuf, NULL, 
-                    NULL, (LPBYTE)full_buffer, &full_buffer_size);
-    }
-    
-    RegCloseKey(key);
-
-    if (rc == ERROR_SUCCESS)
-    {
-        if (lpApplicationDataBuf && pcchApplicationDataBuf)
-        {
-            ptr = full_buffer;
-            /* Skip the first guid */
-            ptr += 21;
-    
-            /* Skip the name and the component guid if it exists */
-            if (strchrW(ptr,'<'))
-                ptr = strchrW(ptr,'<');
-            else 
-                ptr = strchrW(ptr,'>') + 21;
-
-            lstrcpynW(lpApplicationDataBuf,ptr,*pcchApplicationDataBuf);
-            *pcchApplicationDataBuf = strlenW(ptr);
-        }
-        if (lpQualifierBuf && pcchQualifierBuf)
-            *pcchQualifierBuf /= sizeof(WCHAR); 
-        TRACE("Providing %s and %s\n", debugstr_w(lpQualifierBuf), 
-                        debugstr_w(lpApplicationDataBuf));
-    }
-
-    msi_free(full_buffer);
-
-    return rc;
+    return MSI_EnumComponentQualifiers( szComponent, iIndex,
+                 &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
 }
 
 /*************************************************************************
index 7345c17..9bc2b96 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 
 /* below is the query interface to a table */
index 815d808..a5ec138 100644 (file)
@@ -35,7 +35,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 typedef struct _msistring
 {
index 323da5c..8a5d973 100644 (file)
@@ -39,8 +39,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
-#define MSI_MAX_PROPS 20
-
 #include "pshpack1.h"
 
 typedef struct { 
@@ -83,14 +81,6 @@ typedef struct {
 
 #define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER))
 
-typedef struct tagMSISUMMARYINFO
-{
-    MSIOBJECTHDR hdr;
-    MSIDATABASE *db;
-    DWORD update_count;
-    PROPVARIANT property[MSI_MAX_PROPS];
-} MSISUMMARYINFO;
-
 static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y',
                        'I','n','f','o','r','m','a','t','i','o','n',0 };
 
@@ -417,45 +407,19 @@ static UINT save_summary_info( MSISUMMARYINFO * si, IStream *stm )
     return ERROR_SUCCESS;
 }
 
-UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, 
-              LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
+MSISUMMARYINFO *MSI_GetSummaryInformationW( MSIDATABASE *db, UINT uiUpdateCount )
 {
-    UINT ret = ERROR_SUCCESS;
     IStream *stm = NULL;
     MSISUMMARYINFO *si;
-    MSIHANDLE handle;
-    MSIDATABASE *db;
     DWORD grfMode;
     HRESULT r;
 
-    TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
-           uiUpdateCount, pHandle);
-
-    if( !pHandle )
-        return ERROR_INVALID_PARAMETER;
-
-    if( szDatabase )
-    {
-        UINT res;
-
-        res = MSI_OpenDatabaseW(szDatabase, NULL, &db);
-        if( res != ERROR_SUCCESS )
-            return res;
-    }
-    else
-    {
-        db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
-        if( !db )
-            return ERROR_INVALID_PARAMETER;
-    }
+    TRACE("%p %d\n", db, uiUpdateCount );
 
     si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, 
                   sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
     if( !si )
-    {
-        ret = ERROR_FUNCTION_FAILED;
-        goto end;
-    }
+        return si;
 
     msiobj_addref( &db->hdr );
     si->db = db;
@@ -471,14 +435,44 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
         IStream_Release( stm );
     }
 
-    handle = alloc_msihandle( &si->hdr );
-    if( handle )
-        *pHandle = handle;
+    return si;
+}
+
+UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, 
+              LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
+{
+    MSISUMMARYINFO *si;
+    MSIDATABASE *db;
+    UINT ret = ERROR_FUNCTION_FAILED;
+
+    TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
+           uiUpdateCount, pHandle);
+
+    if( !pHandle )
+        return ERROR_INVALID_PARAMETER;
+
+    if( szDatabase )
+    {
+        ret = MSI_OpenDatabaseW( szDatabase, NULL, &db );
+        if( ret != ERROR_SUCCESS )
+            return ret;
+    }
     else
-        ret = ERROR_FUNCTION_FAILED;
-    msiobj_release( &si->hdr );
+    {
+        db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
+        if( !db )
+            return ERROR_INVALID_PARAMETER;
+    }
+
+    si = MSI_GetSummaryInformationW( db, uiUpdateCount );
+    if (si)
+    {
+        *pHandle = alloc_msihandle( &si->hdr );
+        if( *pHandle )
+            ret = ERROR_SUCCESS;
+        msiobj_release( &si->hdr );
+    }
 
-end:
     if( db )
         msiobj_release( &db->hdr );
 
@@ -539,6 +533,12 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
     if( !si )
         return ERROR_INVALID_HANDLE;
 
+    if ( uiProperty >= MSI_MAX_PROPS )
+    {
+        *puiDataType = VT_EMPTY;
+        return ret;
+    }
+
     prop = &si->property[uiProperty];
 
     if( puiDataType )
@@ -590,6 +590,18 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
     return ret;
 }
 
+LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty )
+{
+    PROPVARIANT *prop;
+
+    if ( uiProperty >= MSI_MAX_PROPS )
+        return NULL;
+    prop = &si->property[uiProperty];
+    if( prop->vt != VT_LPSTR )
+        return NULL;
+    return strdupAtoW( prop->u.pszVal );
+}
+
 UINT WINAPI MsiSummaryInfoGetPropertyA(
       MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
       FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
index b3b110a..a3becc6 100644 (file)
@@ -37,7 +37,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 typedef struct tagMSICOLUMNINFO
 {
@@ -56,6 +56,11 @@ struct tagMSITABLE
     WCHAR name[1];
 };
 
+typedef struct tagMSITRANSFORM {
+    struct list entry;
+    IStorage *stg;
+} MSITRANSFORM;
+
 #define MAX_STREAM_NAME 0x1f
 
 static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name,
@@ -276,14 +281,23 @@ UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
 
     r = IStorage_OpenStream(db->storage, encname, NULL, 
             STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm);
-    msi_free( encname );
     if( FAILED( r ) )
     {
-        WARN("open stream failed r = %08lx - empty table?\n",r);
-        return ERROR_FUNCTION_FAILED;
+        MSITRANSFORM *transform;
+
+        LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
+        {
+            TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
+            r = IStorage_OpenStream( transform->stg, encname, NULL, 
+                    STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
+            if (SUCCEEDED(r))
+                break;
+        }
     }
 
-    return ERROR_SUCCESS;
+    msi_free( encname );
+
+    return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
 }
 
 UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
@@ -1050,7 +1064,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
         return ERROR_FUNCTION_FAILED;
     }
 
-    /* TRACE("Data [%d][%d] = %d \n", row, col, *val ); */
+    /* TRACE("Data [%d][%d] = %d\n", row, col, *val ); */
 
     return ERROR_SUCCESS;
 }
@@ -1246,118 +1260,64 @@ static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
     return ERROR_SUCCESS;
 }
 
-static UINT table_find_in_column( MSITABLEVIEW *tv, UINT col, UINT val, UINT *row )
+static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row );
+
+static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
 {
-    UINT i, r, x;
+    UINT r, row;
 
-    for( i=0; i<tv->table->row_count; i++ )
-    {
-        r = TABLE_fetch_int( (struct tagMSIVIEW*) tv, i, col, &x );
-        if ( r != ERROR_SUCCESS )
-        {
-            ERR("TABLE_fetch_int shouldn't fail here\n");
-            break;
-        }
-        if ( x == val )
-        {
-            *row = i;
-            return ERROR_SUCCESS;
-        }
-    }
-    return ERROR_FUNCTION_FAILED;
+    r = msi_table_find_row( tv, rec, &row );
+    if (r != ERROR_SUCCESS)
+        return ERROR_SUCCESS;
+    return ERROR_INVALID_DATA;
 }
 
-static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
+static UINT msi_table_modify_row( MSITABLEVIEW *tv, MSIRECORD *rec,
+                                  UINT row, UINT mask )
 {
-    LPCWSTR str;
-    UINT i, val, r, row;
-    BOOL has_key = FALSE;
+    UINT i, val, r = ERROR_SUCCESS;
 
-    /* FIXME: set the MsiViewGetError value */
+    TRACE("%p %p %u %08x\n", tv, rec, row, mask );
 
-    for( i = 0; i<tv->num_cols; i++ )
+    for( i = 0; i < tv->num_cols; i++ )
     {
-        /* check for duplicate keys */
-        if( !( tv->columns[i].type & MSITYPE_KEY ) )
+        /* set keys or values specified in the mask */
+        if( (~tv->columns[i].type & MSITYPE_KEY) && (~mask & (1<<i)) )
             continue;
 
-        has_key = TRUE;
-
-        TRACE("column %d (%s.%s)is a key\n", i,
-             debugstr_w(tv->columns[i].tablename),
-             debugstr_w(tv->columns[i].colname) );
-
-        val = 0;
-        if( tv->columns[i].type & MSITYPE_STRING )
+        if( (tv->columns[i].type & MSITYPE_STRING) &&
+            ! MSITYPE_IS_BINARY(tv->columns[i].type) )
         {
-             /* keys can't be null */
-             str = MSI_RecordGetString( rec, i+1 );
-             if( !str )
-                 return ERROR_INVALID_DATA;
-
-             /* if the string doesn't exist in the string table yet, it's OK */
-             r = msi_string2idW( tv->db->strings, str, &val );
-             if( ERROR_SUCCESS != r )
-                 return ERROR_SUCCESS;
+            const WCHAR *str = MSI_RecordGetString( rec, i+1 );
+            val = msi_addstringW( tv->db->strings, 0, str, -1, 1 );
         }
         else
         {
             val = MSI_RecordGetInteger( rec, i+1 );
-            val ^= 0x8000;
+            if ( 2 == bytes_per_column( &tv->columns[i] ) )
+                val ^= 0x8000;
         }
-
-        /* if we find the same value in the table, it's a duplicate */
-        row = 0;
-        r = table_find_in_column( tv, i+1, val, &row );
-        if( ERROR_SUCCESS != r )
-            return ERROR_SUCCESS;
-
-        TRACE("found in row %d\n", row );
+        r = TABLE_set_int( &tv->view, row, i+1, val );
+        if( r )
+            break;
     }
 
-    if (has_key)
-        return ERROR_INVALID_DATA;
-
-    return ERROR_SUCCESS;
+    return r;
 }
 
 static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec )
 {
     MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
-    UINT n, type, val, r, row, col_count = 0;
+    UINT r, row = -1;
 
-    r = TABLE_get_dimensions( view, NULL, &col_count );
-    if( r )
-        return r;
+    TRACE("%p %p\n", tv, rec );
 
-    row = -1;
     r = table_create_new_row( view, &row );
     TRACE("insert_row returned %08x\n", r);
-    if( r )
+    if( r != ERROR_SUCCESS )
         return r;
 
-    for( n = 1; n <= col_count; n++ )
-    {
-        r = TABLE_get_column_info( view, n, NULL, &type );
-        if( r )
-            break;
-
-        if( type & MSITYPE_STRING )
-        {
-            const WCHAR *str = MSI_RecordGetString( rec, n );
-            val = msi_addstringW( tv->db->strings, 0, str, -1, 1 );
-        }
-        else
-        {
-            val = MSI_RecordGetInteger( rec, n );
-            val ^= 0x8000;
-        }
-        r = TABLE_set_int( view, row, n, val );
-        if( r )
-            break;
-    }
-
-    return r;
+    return msi_table_modify_row( tv, rec, row, ~0 );
 }
 
 static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
@@ -1532,3 +1492,370 @@ UINT MSI_CommitTables( MSIDATABASE *db )
 
     return ERROR_SUCCESS;
 }
+
+static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st, USHORT *rawdata )
+{
+    UINT i, val, ofs = 0;
+    USHORT mask = *rawdata++;
+    MSICOLUMNINFO *columns = tv->columns;
+    MSIRECORD *rec;
+    const int debug_transform = 0;
+
+    rec = MSI_CreateRecord( tv->num_cols );
+    if( !rec )
+        return rec;
+
+    if( debug_transform ) MESSAGE("row -> ");
+    for( i=0; i<tv->num_cols; i++ )
+    {
+        UINT n = bytes_per_column( &columns[i] );
+
+        if ( (mask&1) && (i>=(mask>>8)) )
+            break;
+        /* all keys must be present */
+        if ( (~mask&1) && (~columns[i].type & MSITYPE_KEY) && ((1<<i) & ~mask) )
+            continue;
+
+        switch( n )
+        {
+        case 2:
+            val = rawdata[ofs];
+            if( (columns[i].type & MSITYPE_STRING) &&
+                ! MSITYPE_IS_BINARY(tv->columns[i].type) )
+            {
+                LPCWSTR sval = msi_string_lookup_id( st, val );
+                MSI_RecordSetStringW( rec, i+1, sval );
+                if( debug_transform ) MESSAGE("[%s]", debugstr_w(sval));
+            }
+            else
+            {
+                val ^= 0x8000;
+                MSI_RecordSetInteger( rec, i+1, val );
+                if( debug_transform) MESSAGE("[0x%04x]", val );
+            }
+            break;
+        case 4:
+            val = rawdata[ofs] + (rawdata[ofs + 1]<<16);
+            /* val ^= 0x80000000; */
+            MSI_RecordSetInteger( rec, i+1, val );
+            if( debug_transform ) MESSAGE("[0x%08x]", val );
+            break;
+        default:
+            ERR("oops - unknown column width %d\n", n);
+            break;
+        }
+        ofs += n/2;
+    }
+    if( debug_transform) MESSAGE("\n");
+    return rec;
+}
+
+static void dump_record( MSIRECORD *rec )
+{
+    UINT i, n;
+
+    MESSAGE("row -> ");
+    n = MSI_RecordGetFieldCount( rec );
+    for( i=1; i<=n; i++ )
+    {
+        LPCWSTR sval = MSI_RecordGetString( rec, i );
+
+        if( MSI_RecordIsNull( rec, i ) )
+            MESSAGE("[]");
+        else if( (sval = MSI_RecordGetString( rec, i )) )
+            MESSAGE("[%s]", debugstr_w(sval));
+        else
+            MESSAGE("[0x%08x]", MSI_RecordGetInteger( rec, i ) );
+    }
+    MESSAGE("\n");
+}
+
+static void dump_table( string_table *st, USHORT *rawdata, UINT rawsize )
+{
+    LPCWSTR sval;
+    UINT i;
+
+    for( i=0; i<(rawsize/2); i++ )
+    {
+        sval = msi_string_lookup_id( st, rawdata[i] );
+        if( !sval ) sval = (WCHAR[]) {0};
+        MESSAGE(" %04x %s\n", rawdata[i], debugstr_w(sval) );
+    }
+}
+
+static UINT* msi_record_to_row( MSITABLEVIEW *tv, MSIRECORD *rec )
+{
+    LPCWSTR str;
+    UINT i, r, *data;
+
+    data = msi_alloc( tv->num_cols *sizeof (UINT) );
+    for( i=0; i<tv->num_cols; i++ )
+    {
+        data[i] = 0;
+
+        if ( ~tv->columns[i].type & MSITYPE_KEY )
+            continue;
+
+        /* turn the transform column value into a row value */
+        if ( ( tv->columns[i].type & MSITYPE_STRING ) &&
+             ! MSITYPE_IS_BINARY(tv->columns[i].type) )
+        {
+            str = MSI_RecordGetString( rec, i+1 );
+            r = msi_string2idW( tv->db->strings, str, &data[i] );
+
+            /* if there's no matching string in the string table,
+               these keys can't match any record, so fail now. */
+            if( ERROR_SUCCESS != r )
+            {
+                msi_free( data );
+                return NULL;
+            }
+        }
+        else
+            data[i] = MSI_RecordGetInteger( rec, i+1 );
+    }
+    return data;
+}
+
+static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, UINT *data )
+{
+    UINT i, r, x, ret = ERROR_FUNCTION_FAILED;
+
+    for( i=0; i<tv->num_cols; i++ )
+    {
+        if ( ~tv->columns[i].type & MSITYPE_KEY )
+            continue;
+
+        /* turn the transform column value into a row value */
+        r = TABLE_fetch_int( &tv->view, row, i+1, &x );
+        if ( r != ERROR_SUCCESS )
+        {
+            ERR("TABLE_fetch_int shouldn't fail here\n");
+            break;
+        }
+
+        /* if this key matches, move to the next column */
+        if ( x != data[i] )
+        {
+            ret = ERROR_FUNCTION_FAILED;
+            break;
+        }
+
+        ret = ERROR_SUCCESS;
+    }
+
+    return ret;
+}
+
+static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
+{
+    UINT i, r = ERROR_FUNCTION_FAILED, *data;
+
+    data = msi_record_to_row( tv, rec );
+    if( !data )
+        return r;
+    for( i=0; i<tv->table->row_count; i++ )
+    {
+        r = msi_row_matches( tv, i, data );
+        if( r == ERROR_SUCCESS )
+        {
+            *row = i;
+            break;
+        }
+    }
+    msi_free( data );
+    return r;
+}
+
+static UINT msi_delete_row( MSITABLEVIEW *tv, UINT row )
+{
+    UINT i;
+    for( i=1; i<=tv->num_cols; i++ )
+        tv->view.ops->set_int( &tv->view, row, i, 0 );
+    return ERROR_SUCCESS;
+}
+
+static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
+                                      string_table *st, LPCWSTR name )
+{
+    UINT rawsize = 0;
+    USHORT *rawdata = NULL;
+    MSITABLEVIEW *tv = NULL;
+    UINT r, n, sz, i, mask;
+    MSIRECORD *rec = NULL;
+    const int debug_transform = 0;
+
+    TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
+
+    /* create a table view */
+    r = TABLE_CreateView( db, name, (MSIVIEW**) &tv );
+    if( r != ERROR_SUCCESS )
+        goto err;
+
+    r = tv->view.ops->execute( &tv->view, NULL );
+    if( r != ERROR_SUCCESS )
+        goto err;
+
+    /* read the transform data */
+    r = ERROR_FUNCTION_FAILED;
+    read_stream_data( stg, name, &rawdata, &rawsize );
+    if( !rawdata || (rawsize < 2) )
+    {
+        ERR("odd sized transform for table %s\n", debugstr_w(name));
+        goto err;
+    }
+
+    TRACE("name = %s columns = %u row_size = %u raw size = %u\n",
+          debugstr_w(name), tv->num_cols, tv->row_size, rawsize );
+
+    /* interpret the data */
+    r = ERROR_SUCCESS;
+    for( n=0; n < (rawsize/2);  )
+    {
+        mask = rawdata[n];
+
+        if (mask&1)
+        {
+            /*
+             * if the low bit is set, columns are continuous and
+             * the number of columns is specified in the high byte
+             */
+            sz = 2 + tv->row_size;
+        }
+        else
+        {
+            /*
+             * If the low bit is not set, rowdata[n] is a bitmask.
+             * Excepting for key fields, which are always present,
+             *  each bit indicates that a field is present in the transform record.
+             *
+             * rawdata[n] == 0 is a special case ... only the keys will be present
+             * and it means that this row should be deleted.
+             */
+            sz = 2;
+            for( i=0; i<tv->num_cols; i++ )
+            {
+                if( (tv->columns[i].type & MSITYPE_KEY) || ((1<<i)&mask))
+                    sz += bytes_per_column( &tv->columns[i] );
+            }
+        }
+
+        /* check we didn't run of the end of the table */
+        if ( (n+sz) > rawsize )
+        {
+            ERR("borked.\n");
+            dump_table( st, rawdata, rawsize );
+            break;
+        }
+
+        rec = msi_get_transform_record( tv, st, &rawdata[n] );
+        if (rec)
+        {
+            UINT row = 0;
+
+            r = msi_table_find_row( tv, rec, &row );
+
+            if( rawdata[n] & 1)
+            {
+                if( debug_transform ) MESSAGE("insert [%d]: ", row);
+                TABLE_insert_row( &tv->view, rec );
+            }
+            else if( mask & 0xff )
+            {
+                if( debug_transform ) MESSAGE("modify [%d]: ", row);
+                msi_table_modify_row( tv, rec, row, mask );
+            }
+            else
+            {
+                if( debug_transform ) MESSAGE("delete [%d]: ", row);
+                msi_delete_row( tv, row );
+            }
+            if( debug_transform ) dump_record( rec );
+            msiobj_release( &rec->hdr );
+        }
+
+        n += sz/2;
+        
+    }
+
+err:
+    /* no need to free the table, it's associated with the database */
+    msi_free( rawdata );
+    if( tv )
+        tv->view.ops->delete( &tv->view );
+
+    return ERROR_SUCCESS;
+}
+
+/*
+ * msi_table_apply_transform
+ *
+ * Enumerate the table transforms in a transform storage and apply each one.
+ */
+UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
+{
+    IEnumSTATSTG *stgenum = NULL;
+    HRESULT r;
+    STATSTG stat;
+    ULONG n, count;
+    WCHAR name[0x40];
+    string_table *strings;
+    UINT ret = ERROR_FUNCTION_FAILED;
+
+    TRACE("%p %p\n", db, stg );
+
+    strings = load_string_table( stg );
+    if( !strings )
+        goto end;
+
+    r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum );
+    if( FAILED( r ) )
+        goto end;
+
+    n = 0;
+    ret = ERROR_SUCCESS;
+
+    while( r == ERROR_SUCCESS )
+    {
+        count = 0;
+        r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
+        if( FAILED( r ) || !count )
+            break;
+        decode_streamname( stat.pwcsName, name );
+        if( ( name[0] == 0x4840 ) && ( name[1] != '_' ) )
+            ret = msi_table_load_transform( db, stg, strings, name+1 );
+        else
+            TRACE("transform contains stream %s\n", debugstr_w(name));
+        n++;
+    }
+
+    if ( ret == ERROR_SUCCESS )
+    {
+        MSITRANSFORM *t;
+
+        t = msi_alloc( sizeof *t );
+        t->stg = stg;
+        IStorage_AddRef( stg );
+        list_add_tail( &db->transforms, &t->entry );
+    }
+
+end:
+    if ( stgenum )
+        IEnumSTATSTG_Release( stgenum );
+    if ( strings )
+        msi_destroy_stringtable( strings );
+
+    return ret;
+}
+
+void msi_free_transforms( MSIDATABASE *db )
+{
+    while( !list_empty( &db->transforms ) )
+    {
+        MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
+                                      MSITRANSFORM, entry );
+        list_remove( &t->entry );
+        IStorage_Release( t->stg );
+        msi_free( t );
+    }
+}
index 6a57912..a36c519 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 
 /* below is the query interface to a table */
index cf54e4a..b11ebe7 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "query.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
 
 
 /* below is the query interface to a table */
index 7dfb69e..0e2a14f 100644 (file)
@@ -31,6 +31,7 @@ typedef unsigned long MSIHANDLE;
 
 typedef enum tagINSTALLSTATE
 {
+    INSTALLSTATE_NOTUSED = -7,
     INSTALLSTATE_BADCONFIG = -6,
     INSTALLSTATE_INCOMPLETE = -5,
     INSTALLSTATE_SOURCEABSENT = -4,
@@ -136,12 +137,33 @@ typedef enum tagINSTALLLOGATTRIBUTES
     INSTALLLOGATTRIBUTES_FLUSHEACHLINE = 0x00000002
 } INSTALLLOGATTRIBUTES;
 
+typedef enum tagINSTALLMODE
+{
+    INSTALLMODE_NODETECTION_ANY     = -4,
+    INSTALLMODE_NOSOURCERESOLUTION  = -3,
+    INSTALLMODE_NODETECTION         = -2,
+    INSTALLMODE_EXISTING            = -1,
+    INSTALLMODE_DEFAULT             = 0
+} INSTALLMODE;
+
 typedef enum tagADVERTISEFLAGS
 {
     ADVERTISEFLAGS_MACHINEASSIGN = 0,
     ADVERTISEFLAGS_USERASSIGN = 1
 } ADVERTISEFLAGS;
 
+typedef enum tagSCRIPTFLAGS
+{
+    SCRIPTFLAGS_CACHEINFO = 1,
+    SCRIPTFLAGS_SHORTCUTS = 4,
+    SCRIPTFLAGS_MACHINEASSIGN = 8,
+    SCRIPTFLAGS_REGDATA_APPINFO = 0x10,
+    SCRIPTFLAGS_REGDATA_CNFGINFO = 0x20,
+    SCRIPTFLAGS_VALIDATE_TRANSFORMS_LIST = 0x40,
+    SCRIPTFLAGS_REGDATA_CLASSINFO = 0x80,
+    SCRIPTFLAGS_REGDATA_EXTENSIONINFO = 0x100,
+} SCRIPTFLAGS;
+
 typedef enum tagINSTALLTYPE
 {
     INSTALLTYPE_DEFAULT = 0,
@@ -173,6 +195,11 @@ typedef enum tagMSICODE
     MSICODE_PATCH = 0x40000000L
 } MSICODE;
 
+typedef struct _MSIFILEHASHINFO {
+    ULONG dwFileHashInfoSize;
+    ULONG dwData[4];
+} MSIFILEHASHINFO, *PMSIFILEHASHINFO;
+
 #define MAX_FEATURE_CHARS 38
 
 /* Strings defined in msi.h */
@@ -409,6 +436,10 @@ UINT WINAPI MsiConfigureProductExA(LPCSTR, int, INSTALLSTATE, LPCSTR);
 UINT WINAPI MsiConfigureProductExW(LPCWSTR, int, INSTALLSTATE, LPCWSTR);
 #define     MsiConfigureProductEx WINELIB_NAME_AW(MsiConfigureProductEx);
 
+UINT WINAPI MsiConfigureFeatureA(LPCSTR, LPCSTR, INSTALLSTATE);
+UINT WINAPI MsiConfigureFeatureW(LPCWSTR, LPCWSTR, INSTALLSTATE);
+#define     MsiConfigureFeature WINELIB_NAME_AW(MsiConfigureFeature);
+
 UINT WINAPI MsiGetProductCodeA(LPCSTR, LPSTR);
 UINT WINAPI MsiGetProductCodeW(LPCWSTR, LPWSTR);
 #define     MsiGetProductCode WINELIB_NAME_AW(MsiGetProductCode)
@@ -445,8 +476,8 @@ UINT WINAPI MsiProvideAssemblyA(LPCSTR, LPCSTR, DWORD, DWORD, LPSTR, DWORD*);
 UINT WINAPI MsiProvideAssemblyW(LPCWSTR, LPCWSTR, DWORD, DWORD, LPWSTR, DWORD*);
 #define MsiProvideAssembly WINELIB_NAME_AW(MsiProvideAssembly)
 
-UINT WINAPI MsiEnumComponentQualifiersA(LPSTR, DWORD, LPSTR, DWORD*, LPSTR, DWORD*);
-UINT WINAPI MsiEnumComponentQualifiersW(LPWSTR, DWORD, LPWSTR, DWORD*, LPWSTR, DWORD*);
+UINT WINAPI MsiEnumComponentQualifiersA(LPCSTR, DWORD, LPSTR, DWORD*, LPSTR, DWORD*);
+UINT WINAPI MsiEnumComponentQualifiersW(LPCWSTR, DWORD, LPWSTR, DWORD*, LPWSTR, DWORD*);
 #define MsiEnumComponentQualifiers WINELIB_NAME_AW(MsiEnumComponentQualifiers)
 
 UINT WINAPI MsiGetFileVersionA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*);
@@ -513,6 +544,18 @@ UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD,
 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPCWSTR, LPCWSTR);
 #define     MsiSourceListAddMediaDisk WINELIB_NAME_AW(MsiSourceListAddMediaDisk)
 
+UINT WINAPI MsiEnumPatchesA(LPCSTR, DWORD, LPSTR, LPSTR, DWORD*);
+UINT WINAPI MsiEnumPatchesW(LPCWSTR, DWORD, LPWSTR, LPWSTR, DWORD*);
+#define     MsiEnumPatches WINELIB_NAME_AW(MsiEnumPatches)
+
+UINT WINAPI MsiGetFileHashA(LPCSTR, DWORD, PMSIFILEHASHINFO);
+UINT WINAPI MsiGetFileHashW(LPCWSTR, DWORD, PMSIFILEHASHINFO);
+#define     MsiGetFileHash WINELIB_NAME_AW(MsiGetFileHash)
+
+UINT WINAPI MsiAdvertiseScriptA(LPCSTR, DWORD, PHKEY, BOOL);
+UINT WINAPI MsiAdvertiseScriptW(LPCWSTR, DWORD, PHKEY, BOOL);
+#define     MsiAdvertiseScript WINELIB_NAME_AW(MsiAdvertiseScript)
+
 /* Non Unicode */
 UINT WINAPI MsiCloseHandle(MSIHANDLE);
 UINT WINAPI MsiCloseAllHandles(void);
index ab70681..c98c30f 100644 (file)
@@ -53,11 +53,19 @@ typedef enum tagMSIMODIFY
     MSIMODIFY_VALIDATE_DELETE = 11
 } MSIMODIFY;
 
+#ifndef __WINESRC__
 #define MSIDBOPEN_READONLY (LPCTSTR)0
 #define MSIDBOPEN_TRANSACT (LPCTSTR)1
 #define MSIDBOPEN_DIRECT   (LPCTSTR)2
 #define MSIDBOPEN_CREATE   (LPCTSTR)3
 #define MSIDBOPEN_CREATEDIRECT (LPCTSTR)4
+#else
+#define MSIDBOPEN_READONLY (LPCWSTR)0
+#define MSIDBOPEN_TRANSACT (LPCWSTR)1
+#define MSIDBOPEN_DIRECT   (LPCWSTR)2
+#define MSIDBOPEN_CREATE   (LPCWSTR)3
+#define MSIDBOPEN_CREATEDIRECT (LPCWSTR)4
+#endif
 
 typedef enum tagMSIRUNMODE
 {
@@ -261,6 +269,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE,UINT*);
 
 UINT WINAPI MsiEnableUIPreview(MSIHANDLE, MSIHANDLE*);
 BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE);
+BOOL WINAPI MsiSetMode(MSIHANDLE, MSIRUNMODE, BOOL);
 
 UINT WINAPI MsiViewModify(MSIHANDLE, MSIMODIFY, MSIHANDLE);