[2/7] msi: Get rid of helpers.c.

Hans Leidekker hans at codeweavers.com
Fri May 6 07:39:17 CDT 2011


---
 dlls/msi/Makefile.in |    1 -
 dlls/msi/action.c    |  503 +++++++++++++++++++++++++++--------
 dlls/msi/appsearch.c |   10 +-
 dlls/msi/assembly.c  |   14 +-
 dlls/msi/classes.c   |   53 ++--
 dlls/msi/custom.c    |   66 +++++-
 dlls/msi/dialog.c    |    2 +-
 dlls/msi/files.c     |   83 ++++--
 dlls/msi/font.c      |   12 +-
 dlls/msi/format.c    |   29 ++-
 dlls/msi/helpers.c   |  713 --------------------------------------------------
 dlls/msi/install.c   |  158 ++++++++++-
 dlls/msi/media.c     |    2 +-
 dlls/msi/msi.c       |    4 +-
 dlls/msi/msipriv.h   |   42 ++--
 dlls/msi/package.c   |   30 ++-
 dlls/msi/record.c    |   26 ++
 dlls/msi/upgrade.c   |    6 +-
 18 files changed, 802 insertions(+), 952 deletions(-)
 delete mode 100644 dlls/msi/helpers.c

diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in
index 066398e..0f076b0 100644
--- a/dlls/msi/Makefile.in
+++ b/dlls/msi/Makefile.in
@@ -22,7 +22,6 @@ C_SRCS = \
 	font.c \
 	format.c \
 	handle.c \
-	helpers.c \
 	insert.c \
 	install.c \
 	join.c \
diff --git a/dlls/msi/action.c b/dlls/msi/action.c
index 58152a4..c4d7717 100644
--- a/dlls/msi/action.c
+++ b/dlls/msi/action.c
@@ -44,9 +44,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 
-/*
- * consts and values used
- */
 static const WCHAR szCreateFolders[] =
     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
 static const WCHAR szCostFinalize[] =
@@ -1413,9 +1410,155 @@ static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
     return ret;
 }
 
+MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
+{
+    MSICOMPONENT *comp;
+
+    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
+    {
+        if (!strcmpW( Component, comp->Component )) return comp;
+    }
+    return NULL;
+}
+
+MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
+{
+    MSIFEATURE *feature;
+
+    LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
+    {
+        if (!strcmpW( Feature, feature->Feature )) return feature;
+    }
+    return NULL;
+}
+
+MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
+{
+    MSIFILE *file;
+
+    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
+    {
+        if (!strcmpW( key, file->File )) return file;
+    }
+    return NULL;
+}
+
+MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
+{
+    MSIFILEPATCH *patch;
+
+    /* FIXME: There might be more than one patch */
+    LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
+    {
+        if (!strcmpW( key, patch->File->File )) return patch;
+    }
+    return NULL;
+}
+
+MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
+{
+    MSIFOLDER *folder;
+
+    LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
+    {
+        if (!strcmpW( dir, folder->Directory )) return folder;
+    }
+    return NULL;
+}
+
 /*
- * Actual Action Handlers
+ * Recursively create all directories in the path.
+ * shamelessly stolen from setupapi/queue.c
  */
+BOOL msi_create_full_path( const WCHAR *path )
+{
+    BOOL ret = TRUE;
+    WCHAR *new_path;
+    int len;
+
+    new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
+    strcpyW( new_path, path );
+
+    while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
+    new_path[len - 1] = 0;
+
+    while (!CreateDirectoryW( new_path, NULL ))
+    {
+        WCHAR *slash;
+        DWORD last_error = GetLastError();
+        if (last_error == ERROR_ALREADY_EXISTS) break;
+        if (last_error != ERROR_PATH_NOT_FOUND)
+        {
+            ret = FALSE;
+            break;
+        }
+        if (!(slash = strrchrW( new_path, '\\' )))
+        {
+            ret = FALSE;
+            break;
+        }
+        len = slash - new_path;
+        new_path[len] = 0;
+        if (!msi_create_full_path( new_path ))
+        {
+            ret = FALSE;
+            break;
+        }
+        new_path[len] = '\\';
+    }
+    msi_free( new_path );
+    return ret;
+}
+
+void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
+{
+    MSIRECORD *row;
+
+    row = MSI_CreateRecord( 4 );
+    MSI_RecordSetInteger( row, 1, a );
+    MSI_RecordSetInteger( row, 2, b );
+    MSI_RecordSetInteger( row, 3, c );
+    MSI_RecordSetInteger( row, 4, d );
+    MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
+    msiobj_release( &row->hdr );
+
+    msi_dialog_check_messages( NULL );
+}
+
+void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
+{
+    static const WCHAR query[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+         '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
+         'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
+    WCHAR message[1024];
+    MSIRECORD *row = 0;
+    DWORD size;
+
+    if (!package->LastAction || strcmpW( package->LastAction, action ))
+    {
+        if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
+
+        if (MSI_RecordIsNull( row, 3 ))
+        {
+            msiobj_release( &row->hdr );
+            return;
+        }
+        /* update the cached action format */
+        msi_free( package->ActionFormat );
+        package->ActionFormat = msi_dup_record_field( row, 3 );
+        msi_free( package->LastAction );
+        package->LastAction = strdupW( action );
+        msiobj_release( &row->hdr );
+    }
+    size = 1024;
+    MSI_RecordSetStringW( record, 0, package->ActionFormat );
+    MSI_FormatRecordW( package, record, message, &size );
+    row = MSI_CreateRecord( 1 );
+    MSI_RecordSetStringW( row, 1, message );
+    MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
+    msiobj_release( &row->hdr );
+}
 
 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
 {
@@ -1429,7 +1572,7 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
     if (!component)
         return ERROR_SUCCESS;
 
-    comp = get_loaded_component(package, component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -1456,7 +1599,7 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
 
     uirow = MSI_CreateRecord(1);
     MSI_RecordSetStringW(uirow, 1, dir);
-    ui_actiondata(package, szCreateFolders, uirow);
+    msi_ui_actiondata(package, szCreateFolders, uirow);
     msiobj_release(&uirow->hdr);
 
     full_path = msi_get_target_folder( package, dir );
@@ -1467,10 +1610,8 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
     }
     TRACE("folder is %s\n", debugstr_w(full_path));
 
-    folder = get_loaded_folder( package, dir );
-    if (folder->State == 0)
-        create_full_pathW(full_path);
-
+    folder = msi_get_loaded_folder( package, dir );
+    if (folder->State == 0) msi_create_full_path( full_path );
     folder->State = 3;
     return ERROR_SUCCESS;
 }
@@ -1506,7 +1647,7 @@ static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
     if (!component)
         return ERROR_SUCCESS;
 
-    comp = get_loaded_component(package, component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -1541,11 +1682,11 @@ static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
 
     uirow = MSI_CreateRecord( 1 );
     MSI_RecordSetStringW( uirow, 1, dir );
-    ui_actiondata( package, szRemoveFolders, uirow );
+    msi_ui_actiondata( package, szRemoveFolders, uirow );
     msiobj_release( &uirow->hdr );
 
     RemoveDirectoryW( full_path );
-    folder = get_loaded_folder( package, dir );
+    folder = msi_get_loaded_folder( package, dir );
     folder->State = 0;
     return ERROR_SUCCESS;
 }
@@ -1659,7 +1800,7 @@ static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
     component = MSI_RecordGetString(row,1);
 
     /* check to see if the component is already loaded */
-    comp = get_loaded_component( ilfs->package, component );
+    comp = msi_get_loaded_component( ilfs->package, component );
     if (!comp)
     {
         ERR("unknown component %s\n", debugstr_w(component));
@@ -1876,7 +2017,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     file->File = msi_dup_record_field( row, 1 );
 
     component = MSI_RecordGetString( row, 2 );
-    file->Component = get_loaded_component( package, component );
+    file->Component = msi_get_loaded_component( package, component );
 
     if (!file->Component)
     {
@@ -1887,7 +2028,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
     }
 
     file->FileName = msi_dup_record_field( row, 3 );
-    reduce_to_longfilename( file->FileName );
+    msi_reduce_to_long_filename( file->FileName );
 
     file->ShortName = msi_dup_record_field( row, 3 );
     file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
@@ -1992,7 +2133,7 @@ static UINT load_patch(MSIRECORD *row, LPVOID param)
         return ERROR_NOT_ENOUGH_MEMORY;
 
     file_key = msi_dup_record_field( row, 1 );
-    patch->File = get_loaded_file( package, file_key );
+    patch->File = msi_get_loaded_file( package, file_key );
     msi_free(file_key);
 
     if( !patch->File )
@@ -2114,12 +2255,12 @@ static UINT find_folder_children( MSIRECORD *row, LPVOID param )
     MSIPACKAGE *package = param;
     MSIFOLDER *parent, *child;
 
-    if (!(child = get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
+    if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
         return ERROR_FUNCTION_FAILED;
 
     if (!child->Parent) return ERROR_SUCCESS;
 
-    if (!(parent = get_loaded_folder( package, child->Parent )))
+    if (!(parent = msi_get_loaded_folder( package, child->Parent )))
         return ERROR_FUNCTION_FAILED;
 
     return add_folder_child( parent, child );
@@ -2566,7 +2707,7 @@ static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
 
     name = MSI_RecordGetString( row, 1 );
 
-    feature = get_loaded_feature( package, name );
+    feature = msi_get_loaded_feature( package, name );
     if (!feature)
         ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
     else
@@ -2685,6 +2826,54 @@ static WCHAR *get_temp_dir( void )
     return strdupW( dir );
 }
 
+/*
+ *  msi_build_directory_name()
+ *
+ *  This function is to save messing round with directory names
+ *  It handles adding backslashes between path segments,
+ *  and can add \ at the end of the directory name if told to.
+ *
+ *  It takes a variable number of arguments.
+ *  It always allocates a new string for the result, so make sure
+ *  to free the return value when finished with it.
+ *
+ *  The first arg is the number of path segments that follow.
+ *  The arguments following count are a list of path segments.
+ *  A path segment may be NULL.
+ *
+ *  Path segments will be added with a \ separating them.
+ *  A \ will not be added after the last segment, however if the
+ *  last segment is NULL, then the last character will be a \
+ */
+WCHAR *msi_build_directory_name( DWORD count, ... )
+{
+    DWORD sz = 1, i;
+    WCHAR *dir;
+    va_list va;
+
+    va_start( va, count );
+    for (i = 0; i < count; i++)
+    {
+        const WCHAR *str = va_arg( va, const WCHAR * );
+        if (str) sz += strlenW( str ) + 1;
+    }
+    va_end( va );
+
+    dir = msi_alloc( sz * sizeof(WCHAR) );
+    dir[0] = 0;
+
+    va_start( va, count );
+    for (i = 0; i < count; i++)
+    {
+        const WCHAR *str = va_arg( va, const WCHAR * );
+        if (!str) continue;
+        strcatW( dir, str );
+        if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash );
+    }
+    va_end( va );
+    return dir;
+}
+
 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
 {
     MSIASSEMBLY *assembly = file->Component->assembly;
@@ -2695,13 +2884,13 @@ static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
     if (assembly && !assembly->application)
     {
         if (!assembly->tempdir) assembly->tempdir = get_temp_dir();
-        file->TargetPath = build_directory_name( 2, assembly->tempdir, file->FileName );
-        track_tempfile( package, file->TargetPath );
+        file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
+        msi_track_tempfile( package, file->TargetPath );
     }
     else
     {
         const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
-        file->TargetPath = build_directory_name( 2, dir, file->FileName );
+        file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
     }
 
     TRACE("resolves to %s\n", debugstr_w(file->TargetPath));
@@ -2803,7 +2992,7 @@ void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL loa
 
     TRACE("resolving %s\n", debugstr_w(name));
 
-    if (!(folder = get_loaded_folder( package, name ))) return;
+    if (!(folder = msi_get_loaded_folder( package, name ))) return;
 
     if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */
     {
@@ -2814,8 +3003,8 @@ void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL loa
     }
     else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
     {
-        parent = get_loaded_folder( package, folder->Parent );
-        path = build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
+        parent = msi_get_loaded_folder( package, folder->Parent );
+        path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
     }
     msi_clean_path( path );
     msi_set_property( package->db, folder->Directory, path );
@@ -3090,10 +3279,10 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
     BOOL check_first = FALSE;
     UINT rc;
 
-    ui_progress(package,2,0,0,0);
+    msi_ui_progress( package, 2, 0, 0, 0 );
 
     component = MSI_RecordGetString(row, 6);
-    comp = get_loaded_component(package,component);
+    comp = msi_get_loaded_component(package,component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -3188,7 +3377,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
     MSI_RecordSetStringW(uirow,1,uikey);
     if (type == REG_SZ || type == REG_EXPAND_SZ)
         MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
-    ui_actiondata(package,szWriteRegistryValues,uirow);
+    msi_ui_actiondata( package, szWriteRegistryValues, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(value_data);
@@ -3212,10 +3401,9 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
         return ERROR_SUCCESS;
 
     /* increment progress bar each time action data is sent */
-    ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
+    msi_ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
 
     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
-
     msiobj_release(&view->hdr);
     return rc;
 }
@@ -3267,10 +3455,10 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para
     UINT size;
     INT root;
 
-    ui_progress( package, 2, 0, 0, 0 );
+    msi_ui_progress( package, 2, 0, 0, 0 );
 
     component = MSI_RecordGetString( row, 6 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -3324,7 +3512,7 @@ static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID para
     MSI_RecordSetStringW( uirow, 1, ui_key_str );
     MSI_RecordSetStringW( uirow, 2, deformated_name );
 
-    ui_actiondata( package, szRemoveRegistryValues, uirow );
+    msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free( ui_key_str );
@@ -3344,10 +3532,10 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param
     UINT size;
     INT root;
 
-    ui_progress( package, 2, 0, 0, 0 );
+    msi_ui_progress( package, 2, 0, 0, 0 );
 
     component = MSI_RecordGetString( row, 5 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -3398,7 +3586,7 @@ static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param
     MSI_RecordSetStringW( uirow, 1, ui_key_str );
     MSI_RecordSetStringW( uirow, 2, deformated_name );
 
-    ui_actiondata( package, szRemoveRegistryValues, uirow );
+    msi_ui_actiondata( package, szRemoveRegistryValues, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free( ui_key_str );
@@ -3418,7 +3606,7 @@ static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
          '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0 };
 
     /* increment progress bar each time action data is sent */
-    ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
+    msi_ui_progress( package, 1, REG_PROGRESS_VALUE, 1, 0 );
 
     rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view );
     if (rc == ERROR_SUCCESS)
@@ -3478,7 +3666,7 @@ static UINT ACTION_InstallValidate(MSIPACKAGE *package)
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
         total += file->FileSize;
 
-    ui_progress(package,0,total,0,0);
+    msi_ui_progress( package, 0, total, 0, 0 );
 
     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
     {
@@ -3595,7 +3783,7 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
     }
     else
     {
-        MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
+        MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
 
         if (file)
             return strdupW( file->TargetPath );
@@ -3730,7 +3918,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
     TRACE("\n");
 
     squash_guid(package->ProductCode,squished_pc);
-    ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
+    msi_ui_progress( package, 1, COMPONENT_PROGRESS_VALUE, 1, 0 );
 
     msi_set_sourcedir_props(package, FALSE);
 
@@ -3738,7 +3926,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
     {
         MSIRECORD * uirow;
 
-        ui_progress(package,2,0,0,0);
+        msi_ui_progress( package, 2, 0, 0, 0 );
         if (!comp->ComponentId)
             continue;
 
@@ -3808,7 +3996,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
                     '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
                     '`','D','i','s','k','I','d','`',0};
 
-                if (!comp->KeyPath || !(file = get_loaded_file(package, comp->KeyPath)))
+                if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
                     continue;
 
                 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
@@ -3820,7 +4008,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
                 ptr = strrchrW(base, '\\');
                 *(ptr + 1) = '\0';
 
-                sourcepath = resolve_file_source(package, file);
+                sourcepath = msi_resolve_file_source(package, file);
                 ptr = sourcepath + lstrlenW(base);
                 lstrcpyW(ptr2, ptr);
                 msi_free(sourcepath);
@@ -3843,7 +4031,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
         MSI_RecordSetStringW(uirow,1,package->ProductCode);
         MSI_RecordSetStringW(uirow,2,comp->ComponentId);
         MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
-        ui_actiondata(package,szProcessComponents,uirow);
+        msi_ui_actiondata( package, szProcessComponents, uirow );
         msiobj_release( &uirow->hdr );
     }
 
@@ -3922,7 +4110,7 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
     HRESULT hr;
 
     component = MSI_RecordGetString(row,3);
-    comp = get_loaded_component(package,component);
+    comp = msi_get_loaded_component(package,component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -3940,12 +4128,12 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
     }
     comp->Action = INSTALLSTATE_LOCAL;
 
-    if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
+    if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
     {
         TRACE("component has no key path\n");
         return ERROR_SUCCESS;
     }
-    ui_actiondata( package, szRegisterTypeLibraries, row );
+    msi_ui_actiondata( package, szRegisterTypeLibraries, row );
 
     module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
     if (module)
@@ -4032,7 +4220,7 @@ static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
     HRESULT hr;
 
     component = MSI_RecordGetString( row, 3 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -4050,7 +4238,7 @@ static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
     }
     comp->Action = INSTALLSTATE_ABSENT;
 
-    ui_actiondata( package, szUnregisterTypeLibraries, row );
+    msi_ui_actiondata( package, szUnregisterTypeLibraries, row );
 
     guid = MSI_RecordGetString( row, 1 );
     CLSIDFromString( (LPCWSTR)guid, &libid );
@@ -4099,10 +4287,10 @@ static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
     link_folder = msi_get_target_folder( package, directory );
 
     /* may be needed because of a bug somewhere else */
-    create_full_pathW( link_folder );
+    msi_create_full_path( link_folder );
 
     filename = msi_dup_record_field( row, 3 );
-    reduce_to_longfilename( filename );
+    msi_reduce_to_long_filename( filename );
 
     extension = strchrW( filename, '.' );
     if (!extension || strcmpiW( extension, szlnk ))
@@ -4111,12 +4299,34 @@ static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
         filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
         memcpy( filename + len, szlnk, sizeof(szlnk) );
     }
-    link_file = build_directory_name( 2, link_folder, filename );
+    link_file = msi_build_directory_name( 2, link_folder, filename );
     msi_free( filename );
 
     return link_file;
 }
 
+WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
+{
+    static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
+    static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
+    WCHAR *folder, *dest, *path;
+
+    if (package->Context == MSIINSTALLCONTEXT_MACHINE)
+        folder = msi_dup_property( package->db, szWindowsFolder );
+    else
+    {
+        WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
+        folder = msi_build_directory_name( 2, appdata, szMicrosoft );
+        msi_free( appdata );
+    }
+    dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
+    msi_create_full_path( dest );
+    path = msi_build_directory_name( 2, dest, icon_name );
+    msi_free( folder );
+    msi_free( dest );
+    return path;
+}
+
 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
 {
     MSIPACKAGE *package = param;
@@ -4128,7 +4338,7 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
     HRESULT res;
 
     component = MSI_RecordGetString(row, 4);
-    comp = get_loaded_component(package, component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -4146,7 +4356,7 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
     }
     comp->Action = INSTALLSTATE_LOCAL;
 
-    ui_actiondata(package,szCreateShortcuts,row);
+    msi_ui_actiondata( package, szCreateShortcuts, row );
 
     res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
                     &IID_IShellLinkW, (LPVOID *) &sl );
@@ -4199,7 +4409,7 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
         INT index; 
         LPCWSTR icon = MSI_RecordGetString(row, 9);
 
-        path = build_icon_path(package, icon);
+        path = msi_build_icon_path(package, icon);
         index = MSI_RecordGetInteger(row,10);
 
         /* no value means 0 */
@@ -4266,7 +4476,7 @@ static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
     MSICOMPONENT *comp;
 
     component = MSI_RecordGetString( row, 4 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -4284,7 +4494,7 @@ static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
     }
     comp->Action = INSTALLSTATE_ABSENT;
 
-    ui_actiondata( package, szRemoveShortcuts, row );
+    msi_ui_actiondata( package, szRemoveShortcuts, row );
 
     link_file = get_link_file( package, row );
 
@@ -4333,7 +4543,7 @@ static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
         return ERROR_SUCCESS;
     }
 
-    FilePath = build_icon_path(package,FileName);
+    FilePath = msi_build_icon_path(package, FileName);
 
     TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
 
@@ -4475,7 +4685,7 @@ static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
     buffer = msi_dup_property(package->db, szARPProductIcon);
     if (buffer)
     {
-        LPWSTR path = build_icon_path(package,buffer);
+        LPWSTR path = msi_build_icon_path(package, buffer);
         msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
         msi_free(path);
         msi_free(buffer);
@@ -4713,7 +4923,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
 end:
     uirow = MSI_CreateRecord( 1 );
     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
-    ui_actiondata( package, szPublishProduct, uirow );
+    msi_ui_actiondata( package, szPublishProduct, uirow );
     msiobj_release( &uirow->hdr );
 
     RegCloseKey(hukey);
@@ -4749,7 +4959,7 @@ static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
         return NULL;
     }
 
-    ret = build_directory_name( 2, folder, ptr );
+    ret = msi_build_directory_name( 2, folder, ptr );
 
     msi_free( filename );
     msi_free( folder );
@@ -4766,7 +4976,7 @@ static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
     MSICOMPONENT *comp;
 
     component = MSI_RecordGetString(row, 8);
-    comp = get_loaded_component(package,component);
+    comp = msi_get_loaded_component(package,component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -4827,7 +5037,7 @@ static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
     MSI_RecordSetStringW(uirow,2,deformated_section);
     MSI_RecordSetStringW(uirow,3,deformated_key);
     MSI_RecordSetStringW(uirow,4,deformated_value);
-    ui_actiondata(package,szWriteIniValues,uirow);
+    msi_ui_actiondata( package, szWriteIniValues, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(fullname);
@@ -4867,7 +5077,7 @@ static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
     INT action;
 
     component = MSI_RecordGetString( row, 8 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -4917,7 +5127,7 @@ static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
     MSI_RecordSetStringW( uirow, 2, deformated_section );
     MSI_RecordSetStringW( uirow, 3, deformated_key );
     MSI_RecordSetStringW( uirow, 4, deformated_value );
-    ui_actiondata( package, szRemoveIniValues, uirow );
+    msi_ui_actiondata( package, szRemoveIniValues, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free( deformated_key );
@@ -4936,7 +5146,7 @@ static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
     INT action;
 
     component = MSI_RecordGetString( row, 8 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -4985,7 +5195,7 @@ static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
     MSI_RecordSetStringW( uirow, 2, deformated_section );
     MSI_RecordSetStringW( uirow, 3, deformated_key );
     MSI_RecordSetStringW( uirow, 4, deformated_value );
-    ui_actiondata( package, szRemoveIniValues, uirow );
+    msi_ui_actiondata( package, szRemoveIniValues, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free( deformated_key );
@@ -5059,7 +5269,7 @@ static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
     MSIRECORD *uirow;
 
     filename = MSI_RecordGetString(row,1);
-    file = get_loaded_file( package, filename );
+    file = msi_get_loaded_file( package, filename );
 
     if (!file)
     {
@@ -5074,7 +5284,7 @@ static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, filename );
     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
-    ui_actiondata( package, szSelfRegModules, uirow );
+    msi_ui_actiondata( package, szSelfRegModules, uirow );
     msiobj_release( &uirow->hdr );
 
     return ERROR_SUCCESS;
@@ -5109,7 +5319,7 @@ static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
     MSIRECORD *uirow;
 
     filename = MSI_RecordGetString( row, 1 );
-    file = get_loaded_file( package, filename );
+    file = msi_get_loaded_file( package, filename );
 
     if (!file)
     {
@@ -5124,7 +5334,7 @@ static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, filename );
     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
-    ui_actiondata( package, szSelfUnregModules, uirow );
+    msi_ui_actiondata( package, szSelfUnregModules, uirow );
     msiobj_release( &uirow->hdr );
 
     return ERROR_SUCCESS;
@@ -5246,9 +5456,9 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
         /* the UI chunk */
         uirow = MSI_CreateRecord( 1 );
         MSI_RecordSetStringW( uirow, 1, feature->Feature );
-        ui_actiondata( package, szPublishFeatures, uirow);
+        msi_ui_actiondata( package, szPublishFeatures, uirow );
         msiobj_release( &uirow->hdr );
-        /* FIXME: call ui_progress? */
+        /* FIXME: call msi_ui_progress? */
     }
 
 end:
@@ -5283,7 +5493,7 @@ static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
 
     uirow = MSI_CreateRecord( 1 );
     MSI_RecordSetStringW( uirow, 1, feature->Feature );
-    ui_actiondata( package, szUnpublishFeatures, uirow );
+    msi_ui_actiondata( package, szUnpublishFeatures, uirow );
     msiobj_release( &uirow->hdr );
 
     return ERROR_SUCCESS;
@@ -5482,7 +5692,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
 done:
     uirow = MSI_CreateRecord( 1 );
     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
-    ui_actiondata( package, szRegisterProduct, uirow );
+    msi_ui_actiondata( package, szRegisterProduct, uirow );
     msiobj_release( &uirow->hdr );
 
     RegCloseKey(hkey);
@@ -5626,6 +5836,43 @@ UINT ACTION_ForceReboot(MSIPACKAGE *package)
     return ERROR_INSTALL_SUSPEND;
 }
 
+WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
+{
+    static const WCHAR query[] =
+        {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
+         'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
+         '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
+    MSIRECORD *rec, *row;
+    DWORD i, size = 0;
+    va_list va;
+    const WCHAR *str;
+    WCHAR *data;
+
+    if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
+
+    rec = MSI_CreateRecord( count + 2 );
+    str = MSI_RecordGetString( row, 1 );
+    MSI_RecordSetStringW( rec, 0, str );
+    msiobj_release( &row->hdr );
+    MSI_RecordSetInteger( rec, 1, error );
+
+    va_start( va, count );
+    for (i = 0; i < count; i++)
+    {
+        str = va_arg( va, const WCHAR *);
+        MSI_RecordSetStringW( rec, i + 2, str );
+    }
+    va_end( va );
+
+    MSI_FormatRecordW( package, rec, NULL, &size );
+    size++;
+    data = msi_alloc( size * sizeof(WCHAR) );
+    if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
+    else data[0] = 0;
+    msiobj_release( &rec->hdr );
+    return data;
+}
+
 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
 {
     DWORD attrib;
@@ -5660,7 +5907,7 @@ static UINT ACTION_ResolveSource(MSIPACKAGE* package)
         else
             prompt = strdupW(package->db->path);
 
-        msg = generate_error_string(package,1302,1,prompt);
+        msg = msi_build_error_string(package, 1302, 1, prompt);
         while(attrib == INVALID_FILE_ATTRIBUTES)
         {
             rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
@@ -5728,7 +5975,7 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package)
 end:
     uirow = MSI_CreateRecord( 1 );
     MSI_RecordSetStringW( uirow, 1, productid );
-    ui_actiondata( package, szRegisterUser, uirow );
+    msi_ui_actiondata( package, szRegisterUser, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(productid);
@@ -5746,6 +5993,34 @@ static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
     return rc;
 }
 
+WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
+{
+    static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
+    WCHAR productid_85[21], component_85[21], *ret;
+    GUID clsid;
+    DWORD sz;
+
+    /* > is used if there is a component GUID and < if not.  */
+
+    productid_85[0] = 0;
+    component_85[0] = 0;
+    CLSIDFromString( package->ProductCode, &clsid );
+
+    encode_base85_guid( &clsid, productid_85 );
+    if (component)
+    {
+        CLSIDFromString( component->ComponentId, &clsid );
+        encode_base85_guid( &clsid, component_85 );
+    }
+
+    TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
+          debugstr_w(component_85));
+
+    sz = 20 + strlenW( feature ) + 20 + 3;
+    ret = msi_alloc_zero( sz * sizeof(WCHAR) );
+    if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
+    return ret;
+}
 
 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
 {
@@ -5761,7 +6036,7 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
     int len;
 
     feature = MSI_RecordGetString(rec, 5);
-    feat = get_loaded_feature(package, feature);
+    feat = msi_get_loaded_feature(package, feature);
     if (!feat)
         return ERROR_SUCCESS;
 
@@ -5775,7 +6050,7 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
     }
 
     component = MSI_RecordGetString(rec, 3);
-    comp = get_loaded_component(package, component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -5786,7 +6061,7 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
     if (rc != ERROR_SUCCESS)
         goto end;
 
-    advertise = create_component_advertise_string( package, comp, feature );
+    advertise = msi_create_component_advertise_string( package, comp, feature );
     text = MSI_RecordGetString( rec, 4 );
     if (text)
     {
@@ -5840,7 +6115,7 @@ end:
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, compgroupid );
     MSI_RecordSetStringW( uirow, 2, qualifier);
-    ui_actiondata( package, szPublishComponents, uirow);
+    msi_ui_actiondata( package, szPublishComponents, uirow );
     msiobj_release( &uirow->hdr );
     /* FIXME: call ui_progress? */
 
@@ -5887,7 +6162,7 @@ static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
     LONG res;
 
     feature = MSI_RecordGetString( rec, 5 );
-    feat = get_loaded_feature( package, feature );
+    feat = msi_get_loaded_feature( package, feature );
     if (!feat)
         return ERROR_SUCCESS;
 
@@ -5899,7 +6174,7 @@ static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
     }
 
     component = MSI_RecordGetString( rec, 3 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -5919,7 +6194,7 @@ static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, compgroupid );
     MSI_RecordSetStringW( uirow, 2, qualifier );
-    ui_actiondata( package, szUnpublishComponents, uirow );
+    msi_ui_actiondata( package, szUnpublishComponents, uirow );
     msiobj_release( &uirow->hdr );
 
     return ERROR_SUCCESS;
@@ -5962,7 +6237,7 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
     SERVICE_DESCRIPTIONW sd = {NULL};
 
     comp = MSI_RecordGetString( rec, 12 );
-    component = get_loaded_component( package, comp );
+    component = msi_get_loaded_component( package, comp );
     if (!component)
     {
         WARN("service component not found\n");
@@ -6003,7 +6278,7 @@ static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
         goto done;
     }
     key = MSI_RecordGetString(row, 6);
-    file = get_loaded_file(package, key);
+    file = msi_get_loaded_file(package, key);
     msiobj_release(&row->hdr);
     if (!file)
     {
@@ -6127,7 +6402,7 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
     UINT r = ERROR_FUNCTION_FAILED;
 
     component = MSI_RecordGetString(rec, 6);
-    comp = get_loaded_component(package, component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -6192,7 +6467,7 @@ done:
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, display_name );
     MSI_RecordSetStringW( uirow, 2, name );
-    ui_actiondata( package, szStartServices, uirow );
+    msi_ui_actiondata( package, szStartServices, uirow );
     msiobj_release( &uirow->hdr );
 
     CloseServiceHandle(service);
@@ -6325,7 +6600,7 @@ static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
         return ERROR_SUCCESS;
 
     component = MSI_RecordGetString( rec, 6 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -6366,7 +6641,7 @@ done:
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, display_name );
     MSI_RecordSetStringW( uirow, 2, name );
-    ui_actiondata( package, szStopServices, uirow );
+    msi_ui_actiondata( package, szStopServices, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free( name );
@@ -6408,7 +6683,7 @@ static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
         return ERROR_SUCCESS;
 
     component = MSI_RecordGetString(rec, 6);
-    comp = get_loaded_component(package, component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -6458,7 +6733,7 @@ done:
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, display_name );
     MSI_RecordSetStringW( uirow, 2, name );
-    ui_actiondata( package, szDeleteServices, uirow );
+    msi_ui_actiondata( package, szDeleteServices, uirow );
     msiobj_release( &uirow->hdr );
 
     CloseServiceHandle( service );
@@ -6508,7 +6783,7 @@ static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
         'F','i','l','e','U','s','a','g','e','=','1',0};
 
     component = MSI_RecordGetString( rec, 2 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -6521,10 +6796,10 @@ static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
     desc = MSI_RecordGetString(rec, 3);
 
     file_key = MSI_RecordGetString( rec, 4 );
-    if (file_key) driver_file = get_loaded_file( package, file_key );
+    if (file_key) driver_file = msi_get_loaded_file( package, file_key );
 
     file_key = MSI_RecordGetString( rec, 5 );
-    if (file_key) setup_file = get_loaded_file( package, file_key );
+    if (file_key) setup_file = msi_get_loaded_file( package, file_key );
 
     if (!driver_file)
     {
@@ -6573,7 +6848,7 @@ static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
     MSI_RecordSetStringW( uirow, 1, desc );
     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
     MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
-    ui_actiondata( package, szInstallODBC, uirow );
+    msi_ui_actiondata( package, szInstallODBC, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(driver);
@@ -6600,7 +6875,7 @@ static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
         'S','e','t','u','p','=','%','s',0};
 
     component = MSI_RecordGetString( rec, 2 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -6613,10 +6888,10 @@ static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
     desc = MSI_RecordGetString(rec, 3);
 
     file_key = MSI_RecordGetString( rec, 4 );
-    if (file_key) translator_file = get_loaded_file( package, file_key );
+    if (file_key) translator_file = msi_get_loaded_file( package, file_key );
 
     file_key = MSI_RecordGetString( rec, 5 );
-    if (file_key) setup_file = get_loaded_file( package, file_key );
+    if (file_key) setup_file = msi_get_loaded_file( package, file_key );
 
     if (!translator_file)
     {
@@ -6661,7 +6936,7 @@ static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
     MSI_RecordSetStringW( uirow, 1, desc );
     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
     MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
-    ui_actiondata( package, szInstallODBC, uirow );
+    msi_ui_actiondata( package, szInstallODBC, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(translator);
@@ -6686,7 +6961,7 @@ static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
         'D','S','N','=','%','s',0 };
 
     component = MSI_RecordGetString( rec, 2 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -6721,7 +6996,7 @@ static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
     MSI_RecordSetStringW( uirow, 1, desc );
     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
     MSI_RecordSetInteger( uirow, 3, request );
-    ui_actiondata( package, szInstallODBC, uirow );
+    msi_ui_actiondata( package, szInstallODBC, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(attrs);
@@ -6779,7 +7054,7 @@ static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
     LPCWSTR desc, component;
 
     component = MSI_RecordGetString( rec, 2 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -6802,7 +7077,7 @@ static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, desc );
     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
-    ui_actiondata( package, szRemoveODBC, uirow );
+    msi_ui_actiondata( package, szRemoveODBC, uirow );
     msiobj_release( &uirow->hdr );
 
     return ERROR_SUCCESS;
@@ -6817,7 +7092,7 @@ static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
     LPCWSTR desc, component;
 
     component = MSI_RecordGetString( rec, 2 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -6840,7 +7115,7 @@ static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, desc );
     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
-    ui_actiondata( package, szRemoveODBC, uirow );
+    msi_ui_actiondata( package, szRemoveODBC, uirow );
     msiobj_release( &uirow->hdr );
 
     return ERROR_SUCCESS;
@@ -6861,7 +7136,7 @@ static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
         'D','S','N','=','%','s',0 };
 
     component = MSI_RecordGetString( rec, 2 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -6898,7 +7173,7 @@ static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
     MSI_RecordSetStringW( uirow, 1, desc );
     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
     MSI_RecordSetInteger( uirow, 3, request );
-    ui_actiondata( package, szRemoveODBC, uirow );
+    msi_ui_actiondata( package, szRemoveODBC, uirow );
     msiobj_release( &uirow->hdr );
 
     return ERROR_SUCCESS;
@@ -7086,7 +7361,7 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
     int action = 0;
 
     component = MSI_RecordGetString(rec, 4);
-    comp = get_loaded_component(package, component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -7234,7 +7509,7 @@ done:
     MSI_RecordSetStringW( uirow, 1, name );
     MSI_RecordSetStringW( uirow, 2, newval );
     MSI_RecordSetInteger( uirow, 3, action );
-    ui_actiondata( package, szWriteEnvironmentStrings, uirow );
+    msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
     msiobj_release( &uirow->hdr );
 
     if (env) RegCloseKey(env);
@@ -7275,7 +7550,7 @@ static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
     UINT r;
 
     component = MSI_RecordGetString( rec, 4 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -7337,7 +7612,7 @@ done:
     MSI_RecordSetStringW( uirow, 1, name );
     MSI_RecordSetStringW( uirow, 2, value );
     MSI_RecordSetInteger( uirow, 3, action );
-    ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
+    msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
     msiobj_release( &uirow->hdr );
 
     if (env) RegCloseKey( env );
@@ -7405,7 +7680,7 @@ static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
 
     uirow = MSI_CreateRecord( 1 );
     MSI_RecordSetInteger( uirow, 1, space );
-    ui_actiondata( package, szAllocateRegistrySpace, uirow );
+    msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
     msiobj_release( &uirow->hdr );
 
     return ERROR_SUCCESS;
diff --git a/dlls/msi/appsearch.c b/dlls/msi/appsearch.c
index 7092a5b..f128d95 100644
--- a/dlls/msi/appsearch.c
+++ b/dlls/msi/appsearch.c
@@ -1063,7 +1063,7 @@ static UINT iterate_appsearch(MSIRECORD *row, LPVOID param)
     uirow = MSI_CreateRecord( 2 );
     MSI_RecordSetStringW( uirow, 1, propName );
     MSI_RecordSetStringW( uirow, 2, sigName );
-    ui_actiondata( package, szAppSearch, uirow );
+    msi_ui_actiondata( package, szAppSearch, uirow );
     msiobj_release( &uirow->hdr );
 
     return r;
@@ -1078,13 +1078,13 @@ UINT ACTION_AppSearch(MSIPACKAGE *package)
     MSIQUERY *view = NULL;
     UINT r;
 
-    if (check_unique_action(package, szAppSearch))
+    if (msi_action_is_unique(package, szAppSearch))
     {
         TRACE("Skipping AppSearch action: already done in UI sequence\n");
         return ERROR_SUCCESS;
     }
     else
-        register_unique_action(package, szAppSearch);
+        msi_register_unique_action(package, szAppSearch);
 
     r = MSI_OpenQuery( package->db, &view, query );
     if (r != ERROR_SUCCESS)
@@ -1133,13 +1133,13 @@ UINT ACTION_CCPSearch(MSIPACKAGE *package)
     MSIQUERY *view = NULL;
     UINT r;
 
-    if (check_unique_action(package, szCCPSearch))
+    if (msi_action_is_unique(package, szCCPSearch))
     {
         TRACE("Skipping AppSearch action: already done in UI sequence\n");
         return ERROR_SUCCESS;
     }
     else
-        register_unique_action(package, szCCPSearch);
+        msi_register_unique_action(package, szCCPSearch);
 
     r = MSI_OpenQuery(package->db, &view, query);
     if (r != ERROR_SUCCESS)
diff --git a/dlls/msi/assembly.c b/dlls/msi/assembly.c
index 5199a31..6bccc79 100644
--- a/dlls/msi/assembly.c
+++ b/dlls/msi/assembly.c
@@ -343,7 +343,7 @@ UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
     MSIFEATURE *feature = NULL;
 
     if (comp->assembly->feature)
-        feature = get_loaded_feature( package, comp->assembly->feature );
+        feature = msi_get_loaded_feature( package, comp->assembly->feature );
 
     if (assembly->application)
     {
@@ -357,12 +357,12 @@ UINT install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp )
             WARN("no manifest\n");
             return ERROR_FUNCTION_FAILED;
         }
-        manifest = get_loaded_file( package, assembly->manifest )->TargetPath;
+        manifest = msi_get_loaded_file( package, assembly->manifest )->TargetPath;
         cache = package->cache_sxs;
     }
     else
     {
-        manifest = get_loaded_file( package, comp->KeyPath )->TargetPath;
+        manifest = msi_get_loaded_file( package, comp->KeyPath )->TargetPath;
         cache = package->cache_net[get_clr_version( manifest )];
     }
     TRACE("installing assembly %s\n", debugstr_w(manifest));
@@ -541,7 +541,7 @@ UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
         win32 = assembly->attributes & msidbAssemblyAttributesWin32;
         if (assembly->application)
         {
-            MSIFILE *file = get_loaded_file( package, assembly->application );
+            MSIFILE *file = msi_get_loaded_file( package, assembly->application );
             if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey )))
             {
                 WARN("failed to open local assembly key %d\n", res);
@@ -565,7 +565,7 @@ UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
 
         uirow = MSI_CreateRecord( 2 );
         MSI_RecordSetStringW( uirow, 2, assembly->display_name );
-        ui_actiondata( package, szMsiPublishAssemblies, uirow );
+        msi_ui_actiondata( package, szMsiPublishAssemblies, uirow );
         msiobj_release( &uirow->hdr );
     }
     return ERROR_SUCCESS;
@@ -603,7 +603,7 @@ UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
         win32 = assembly->attributes & msidbAssemblyAttributesWin32;
         if (assembly->application)
         {
-            MSIFILE *file = get_loaded_file( package, assembly->application );
+            MSIFILE *file = msi_get_loaded_file( package, assembly->application );
             if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath )))
                 WARN("failed to delete local assembly key %d\n", res);
         }
@@ -622,7 +622,7 @@ UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
 
         uirow = MSI_CreateRecord( 2 );
         MSI_RecordSetStringW( uirow, 2, assembly->display_name );
-        ui_actiondata( package, szMsiPublishAssemblies, uirow );
+        msi_ui_actiondata( package, szMsiPublishAssemblies, uirow );
         msiobj_release( &uirow->hdr );
     }
     return ERROR_SUCCESS;
diff --git a/dlls/msi/classes.c b/dlls/msi/classes.c
index d11f48b..7208006 100644
--- a/dlls/msi/classes.c
+++ b/dlls/msi/classes.c
@@ -142,7 +142,7 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
         LPWSTR FilePath;
         static const WCHAR fmt[] = {'%','s',',','%','i',0};
 
-        FilePath = build_icon_path(package,FileName);
+        FilePath = msi_build_icon_path(package, FileName);
        
         progid->IconPath = msi_alloc( (strlenW(FilePath)+10)* sizeof(WCHAR) );
 
@@ -154,7 +154,7 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
     {
         buffer = MSI_RecordGetString(row,5);
         if (buffer)
-            progid->IconPath = build_icon_path(package,buffer);
+            progid->IconPath = msi_build_icon_path(package, buffer);
     }
 
     progid->CurVer = NULL;
@@ -227,7 +227,7 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
     TRACE("loading class %s\n",debugstr_w(cls->clsid));
     cls->Context = msi_dup_record_field( row, 2 );
     buffer = MSI_RecordGetString(row,3);
-    cls->Component = get_loaded_component(package, buffer);
+    cls->Component = msi_get_loaded_component( package, buffer );
 
     cls->ProgIDText = msi_dup_record_field(row,4);
     cls->ProgID = load_given_progid(package, cls->ProgIDText);
@@ -248,7 +248,7 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
         LPWSTR FilePath;
         static const WCHAR fmt[] = {'%','s',',','%','i',0};
 
-        FilePath = build_icon_path(package,FileName);
+        FilePath = msi_build_icon_path(package, FileName);
        
         cls->IconPath = msi_alloc( (strlenW(FilePath)+5)* sizeof(WCHAR) );
 
@@ -260,7 +260,7 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
     {
         buffer = MSI_RecordGetString(row,8);
         if (buffer)
-            cls->IconPath = build_icon_path(package,buffer);
+            cls->IconPath = msi_build_icon_path(package, buffer);
     }
 
     if (!MSI_RecordIsNull(row,10))
@@ -287,15 +287,15 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
         }
         else
         {
-            cls->DefInprocHandler32 = msi_dup_record_field( row, 10);
-            reduce_to_longfilename(cls->DefInprocHandler32);
+            cls->DefInprocHandler32 = msi_dup_record_field( row, 10 );
+            msi_reduce_to_long_filename( cls->DefInprocHandler32 );
         }
     }
     buffer = MSI_RecordGetString(row,11);
     deformat_string(package,buffer,&cls->Argument);
 
     buffer = MSI_RecordGetString(row,12);
-    cls->Feature = get_loaded_feature(package,buffer);
+    cls->Feature = msi_get_loaded_feature(package, buffer);
 
     cls->Attributes = MSI_RecordGetInteger(row,13);
     
@@ -420,7 +420,7 @@ static MSIEXTENSION *load_extension( MSIPACKAGE* package, MSIRECORD *row )
     TRACE("loading extension %s\n", debugstr_w(ext->Extension));
 
     buffer = MSI_RecordGetString( row, 2 );
-    ext->Component = get_loaded_component( package,buffer );
+    ext->Component = msi_get_loaded_component( package, buffer );
 
     ext->ProgIDText = msi_dup_record_field( row, 3 );
     ext->ProgID = load_given_progid( package, ext->ProgIDText );
@@ -429,7 +429,7 @@ static MSIEXTENSION *load_extension( MSIPACKAGE* package, MSIRECORD *row )
     ext->Mime = load_given_mime( package, buffer );
 
     buffer = MSI_RecordGetString(row,5);
-    ext->Feature = get_loaded_feature( package, buffer );
+    ext->Feature = msi_get_loaded_feature( package, buffer );
 
     return ext;
 }
@@ -525,7 +525,7 @@ static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
     clsid = MSI_RecordGetString(rec,1);
     context = MSI_RecordGetString(rec,2);
     buffer = MSI_RecordGetString(rec,3);
-    comp = get_loaded_component(package,buffer);
+    comp = msi_get_loaded_component(package, buffer);
 
     LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
     {
@@ -574,7 +574,7 @@ static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
 
     extension = MSI_RecordGetString(rec,1);
     buffer = MSI_RecordGetString(rec,2);
-    comp = get_loaded_component(package,buffer);
+    comp = msi_get_loaded_component(package, buffer);
 
     LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry )
     {
@@ -850,7 +850,7 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
         }
         feature->Action = feature->ActionRequest;
 
-        if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
+        if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
         {
             TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid));
             continue;
@@ -958,7 +958,7 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
         
         uirow = MSI_CreateRecord(1);
         MSI_RecordSetStringW( uirow, 1, cls->clsid );
-        ui_actiondata(package,szRegisterClassInfo,uirow);
+        msi_ui_actiondata( package, szRegisterClassInfo, uirow );
         msiobj_release(&uirow->hdr);
     }
 
@@ -1050,7 +1050,7 @@ UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package )
 
         uirow = MSI_CreateRecord( 1 );
         MSI_RecordSetStringW( uirow, 1, cls->clsid );
-        ui_actiondata( package, szUnregisterClassInfo, uirow );
+        msi_ui_actiondata( package, szUnregisterClassInfo, uirow );
         msiobj_release( &uirow->hdr );
     }
 
@@ -1131,7 +1131,7 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
 
         uirow = MSI_CreateRecord( 1 );
         MSI_RecordSetStringW( uirow, 1, progid->ProgID );
-        ui_actiondata( package, szRegisterProgIdInfo, uirow );
+        msi_ui_actiondata( package, szRegisterProgIdInfo, uirow );
         msiobj_release( &uirow->hdr );
     }
 
@@ -1166,7 +1166,7 @@ UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package )
 
         uirow = MSI_CreateRecord( 1 );
         MSI_RecordSetStringW( uirow, 1, progid->ProgID );
-        ui_actiondata( package, szUnregisterProgIdInfo, uirow );
+        msi_ui_actiondata( package, szUnregisterProgIdInfo, uirow );
         msiobj_release( &uirow->hdr );
     }
 
@@ -1187,7 +1187,7 @@ static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
     DWORD size;
     LPWSTR advertise;
 
-    keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
+    keyname = msi_build_directory_name(4, progid, szShell, verb->Verb, szCommand);
 
     TRACE("Making Key %s\n",debugstr_w(keyname));
     RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
@@ -1205,9 +1205,8 @@ static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
      msi_reg_set_val_str( key, NULL, command );
      msi_free(command);
 
-     advertise = create_component_advertise_string(package, component, 
-                                                   extension->Feature->Feature);
-
+     advertise = msi_create_component_advertise_string(package, component,
+                                                       extension->Feature->Feature);
      size = strlenW(advertise);
 
      if (verb->Argument)
@@ -1232,7 +1231,7 @@ static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
 
      if (verb->Command)
      {
-        keyname = build_directory_name(3, progid, szShell, verb->Verb);
+        keyname = msi_build_directory_name( 3, progid, szShell, verb->Verb );
         msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Command );
         msi_free(keyname);
      }
@@ -1242,7 +1241,7 @@ static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
         if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
         {
             *Sequence = verb->Sequence;
-            keyname = build_directory_name(2, progid, szShell);
+            keyname = msi_build_directory_name( 2, progid, szShell );
             msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Verb );
             msi_free(keyname);
         }
@@ -1362,7 +1361,7 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
 
         uirow = MSI_CreateRecord(1);
         MSI_RecordSetStringW( uirow, 1, ext->Extension );
-        ui_actiondata(package,szRegisterExtensionInfo,uirow);
+        msi_ui_actiondata( package, szRegisterExtensionInfo, uirow );
         msiobj_release(&uirow->hdr);
     }
 
@@ -1448,7 +1447,7 @@ UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package )
 
         uirow = MSI_CreateRecord( 1 );
         MSI_RecordSetStringW( uirow, 1, ext->Extension );
-        ui_actiondata( package, szUnregisterExtensionInfo, uirow );
+        msi_ui_actiondata( package, szUnregisterExtensionInfo, uirow );
         msiobj_release( &uirow->hdr );
     }
 
@@ -1506,7 +1505,7 @@ UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
         uirow = MSI_CreateRecord( 2 );
         MSI_RecordSetStringW( uirow, 1, mt->ContentType );
         MSI_RecordSetStringW( uirow, 2, mt->suffix );
-        ui_actiondata( package, szRegisterMIMEInfo, uirow );
+        msi_ui_actiondata( package, szRegisterMIMEInfo, uirow );
         msiobj_release( &uirow->hdr );
     }
 
@@ -1551,7 +1550,7 @@ UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package )
         uirow = MSI_CreateRecord( 2 );
         MSI_RecordSetStringW( uirow, 1, mime->ContentType );
         MSI_RecordSetStringW( uirow, 2, mime->suffix );
-        ui_actiondata( package, szUnregisterMIMEInfo, uirow );
+        msi_ui_actiondata( package, szUnregisterMIMEInfo, uirow );
         msiobj_release( &uirow->hdr );
     }
 
diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index bac86bd..9b5a796 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -89,6 +89,62 @@ static CRITICAL_SECTION msi_custom_action_cs = { &msi_custom_action_cs_debug, -1
 
 static struct list msi_pending_custom_actions = LIST_INIT( msi_pending_custom_actions );
 
+static UINT schedule_action( MSIPACKAGE *package, UINT script, const WCHAR *action )
+{
+    UINT count;
+    WCHAR **newbuf = NULL;
+
+    if (script >= TOTAL_SCRIPTS)
+    {
+        FIXME("Unknown script requested %u\n", script);
+        return ERROR_FUNCTION_FAILED;
+    }
+    TRACE("Scheduling action %s in script %u\n", debugstr_w(action), script);
+
+    count = package->script->ActionCount[script];
+    package->script->ActionCount[script]++;
+    if (count != 0) newbuf = msi_realloc( package->script->Actions[script],
+                                          package->script->ActionCount[script] * sizeof(WCHAR *) );
+    else newbuf = msi_alloc( sizeof(WCHAR *) );
+
+    newbuf[count] = strdupW( action );
+    package->script->Actions[script] = newbuf;
+    return ERROR_SUCCESS;
+}
+
+UINT msi_register_unique_action( MSIPACKAGE *package, const WCHAR *action )
+{
+    UINT count;
+    WCHAR **newbuf = NULL;
+
+    if (!package->script) return FALSE;
+
+    TRACE("Registering %s as unique action\n", debugstr_w(action));
+
+    count = package->script->UniqueActionsCount;
+    package->script->UniqueActionsCount++;
+    if (count != 0) newbuf = msi_realloc( package->script->UniqueActions,
+                                          package->script->UniqueActionsCount * sizeof(WCHAR *) );
+    else newbuf = msi_alloc( sizeof(WCHAR *) );
+
+    newbuf[count] = strdupW( action );
+    package->script->UniqueActions = newbuf;
+    return ERROR_SUCCESS;
+}
+
+BOOL msi_action_is_unique( const MSIPACKAGE *package, const WCHAR *action )
+{
+    UINT i;
+
+    if (!package->script) return FALSE;
+
+    for (i = 0; i < package->script->UniqueActionsCount; i++)
+    {
+        if (!strcmpW( package->script->UniqueActions[i], action )) return TRUE;
+    }
+    return FALSE;
+}
+
 static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR action, UINT options)
 {
     if (!package->script)
@@ -115,13 +171,13 @@ static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR acti
     }
     else if (options & msidbCustomActionTypeOncePerProcess)
     {
-        if (check_unique_action(package,action))
+        if (msi_action_is_unique(package, action))
         {
             TRACE("Skipping action due to msidbCustomActionTypeOncePerProcess option.\n");
             return FALSE;
         }
         else
-            register_unique_action(package,action);
+            msi_register_unique_action(package, action);
     }
 
     return TRUE;
@@ -982,7 +1038,7 @@ static UINT HANDLE_CustomType17(MSIPACKAGE *package, LPCWSTR source,
 
     TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
 
-    file = get_loaded_file( package, source );
+    file = msi_get_loaded_file( package, source );
     if (!file)
     {
         ERR("invalid file key %s\n", debugstr_w( source ));
@@ -1010,7 +1066,7 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
 
     memset(&si,0,sizeof(STARTUPINFOW));
 
-    file = get_loaded_file(package,source);
+    file = msi_get_loaded_file(package, source);
     if( !file )
         return ERROR_FUNCTION_FAILED;
 
@@ -1325,7 +1381,7 @@ static UINT HANDLE_CustomType21_22(MSIPACKAGE *package, LPCWSTR source,
 
     TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
 
-    file = get_loaded_file(package,source);
+    file = msi_get_loaded_file(package, source);
     if (!file)
     {
 	ERR("invalid file key %s\n", debugstr_w(source));
diff --git a/dlls/msi/dialog.c b/dlls/msi/dialog.c
index d612acf..f624dae 100644
--- a/dlls/msi/dialog.c
+++ b/dlls/msi/dialog.c
@@ -2378,7 +2378,7 @@ static UINT msi_dialog_seltree_handler( msi_dialog *dialog,
     dir = MSI_RecordGetString( row, 7 );
     if (dir)
     {
-        folder = get_loaded_folder( dialog->package, dir );
+        folder = msi_get_loaded_folder( dialog->package, dir );
         if (!folder)
         {
             r = ERROR_FUNCTION_FAILED;
diff --git a/dlls/msi/files.c b/dlls/msi/files.c
index e85c921..6608874 100644
--- a/dlls/msi/files.c
+++ b/dlls/msi/files.c
@@ -58,9 +58,9 @@ static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *ac
     MSI_RecordSetStringW( uirow, 1, f->FileName );
     MSI_RecordSetStringW( uirow, 9, f->Component->Directory );
     MSI_RecordSetInteger( uirow, 6, f->FileSize );
-    ui_actiondata( package, action, uirow );
+    msi_ui_actiondata( package, action, uirow );
     msiobj_release( &uirow->hdr );
-    ui_progress( package, 2, f->FileSize, 0, 0 );
+    msi_ui_progress( package, 2, f->FileSize, 0, 0 );
 }
 
 static msi_file_state calculate_install_state( MSIFILE *file )
@@ -154,7 +154,7 @@ static void schedule_install_files(MSIPACKAGE *package)
             file->state = msifs_skipped;
         }
         comp->Action = INSTALLSTATE_LOCAL;
-        ui_progress( package, 2, file->FileSize, 0, 0 );
+        msi_ui_progress( package, 2, file->FileSize, 0, 0 );
     }
 }
 
@@ -237,10 +237,10 @@ static UINT msi_create_directory( MSIPACKAGE *package, const WCHAR *dir )
     install_path = msi_get_target_folder( package, dir );
     if (!install_path) return ERROR_FUNCTION_FAILED;
 
-    folder = get_loaded_folder( package, dir );
+    folder = msi_get_loaded_folder( package, dir );
     if (folder->State == 0)
     {
-        create_full_pathW( install_path );
+        msi_create_full_path( install_path );
         folder->State = 2;
     }
     return ERROR_SUCCESS;
@@ -254,7 +254,7 @@ static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
 
     if (action == MSICABEXTRACT_BEGINEXTRACT)
     {
-        f = get_loaded_file(package, file);
+        f = msi_get_loaded_file(package, file);
         if (!f)
         {
             TRACE("unknown file in cabinet (%s)\n", debugstr_w(file));
@@ -281,6 +281,27 @@ static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
     return TRUE;
 }
 
+WCHAR *msi_resolve_file_source( MSIPACKAGE *package, MSIFILE *file )
+{
+    WCHAR *p, *path;
+
+    TRACE("Working to resolve source of file %s\n", debugstr_w(file->File));
+
+    if (file->IsCompressed) return NULL;
+
+    p = msi_resolve_source_folder( package, file->Component->Directory, NULL );
+    path = msi_build_directory_name( 2, p, file->ShortName );
+
+    if (file->LongName && GetFileAttributesW( path ) == INVALID_FILE_ATTRIBUTES)
+    {
+        msi_free( path );
+        path = msi_build_directory_name( 2, p, file->LongName );
+    }
+    msi_free( p );
+    TRACE("file %s source resolves to %s\n", debugstr_w(file->File), debugstr_w(path));
+    return path;
+}
+
 /*
  * ACTION_InstallFiles()
  * 
@@ -296,10 +317,9 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
     MSIFILE *file;
 
     /* increment progress bar each time action data is sent */
-    ui_progress(package,1,1,0,0);
+    msi_ui_progress( package, 1, 1, 0, 0 );
 
     schedule_install_files(package);
-
     mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) );
 
     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
@@ -343,7 +363,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
 
         if (!file->IsCompressed)
         {
-            LPWSTR source = resolve_file_source(package, file);
+            WCHAR *source = msi_resolve_file_source(package, file);
 
             TRACE("copying %s to %s\n", debugstr_w(source), debugstr_w(file->TargetPath));
 
@@ -426,7 +446,7 @@ static BOOL patchfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action,
         if (temp_folder[0] == '\0')
             GetTempPathW(MAX_PATH, temp_folder);
 
-        p = get_loaded_filepatch(package, file);
+        p = msi_get_loaded_filepatch(package, file);
         if (!p)
         {
             TRACE("unknown file in cabinet (%s)\n", debugstr_w(file));
@@ -477,7 +497,7 @@ UINT ACTION_PatchFiles( MSIPACKAGE *package )
     TRACE("%p\n", package);
 
     /* increment progress bar each time action data is sent */
-    ui_progress(package,1,1,0,0);
+    msi_ui_progress( package, 1, 1, 0, 0 );
 
     mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) );
 
@@ -739,6 +759,12 @@ done:
     return res;
 }
 
+void msi_reduce_to_long_filename( WCHAR *filename )
+{
+    WCHAR *p = strchrW( filename, '|' );
+    if (p) memmove( filename, p + 1, (strlenW( p + 1 ) + 1) * sizeof(WCHAR) );
+}
+
 static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
 {
     MSIPACKAGE *package = param;
@@ -751,7 +777,7 @@ static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
     BOOL ret, wildcards;
 
     component = MSI_RecordGetString(rec, 2);
-    comp = get_loaded_component(package, component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -816,8 +842,7 @@ static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param )
     else
     {
         destname = strdupW(MSI_RecordGetString(rec, 4));
-        if (destname)
-            reduce_to_longfilename(destname);
+        if (destname) msi_reduce_to_long_filename(destname);
     }
 
     size = 0;
@@ -856,7 +881,7 @@ done:
     MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString(rec, 1) );
     MSI_RecordSetInteger( uirow, 6, 1 ); /* FIXME */
     MSI_RecordSetStringW( uirow, 9, destdir );
-    ui_actiondata( package, szMoveFiles, uirow );
+    msi_ui_actiondata( package, szMoveFiles, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(sourcedir);
@@ -903,7 +928,7 @@ static WCHAR *get_duplicate_filename( MSIPACKAGE *package, MSIRECORD *row, const
         MSI_RecordGetStringW( row, 4, NULL, &len );
         if (!(dst_name = msi_alloc( ++len * sizeof(WCHAR) ))) return NULL;
         MSI_RecordGetStringW( row, 4, dst_name, &len );
-        reduce_to_longfilename( dst_name );
+        msi_reduce_to_long_filename( dst_name );
     }
 
     if (MSI_RecordIsNull( row, 5 ))
@@ -931,8 +956,8 @@ static WCHAR *get_duplicate_filename( MSIPACKAGE *package, MSIRECORD *row, const
         }
     }
 
-    dst = build_directory_name( 2, dst_path, dst_name );
-    create_full_pathW( dst_path );
+    dst = msi_build_directory_name( 2, dst_path, dst_name );
+    msi_create_full_path( dst_path );
 
     msi_free( dst_name );
     msi_free( dst_path );
@@ -949,7 +974,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
     MSIFILE *file;
 
     component = MSI_RecordGetString(row,2);
-    comp = get_loaded_component(package,component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -974,7 +999,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
         return ERROR_FUNCTION_FAILED;
     }
 
-    file = get_loaded_file( package, file_key );
+    file = msi_get_loaded_file( package, file_key );
     if (!file)
     {
         ERR("Original file unknown %s\n", debugstr_w(file_key));
@@ -1002,7 +1027,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
     MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString( row, 1 ) );
     MSI_RecordSetInteger( uirow, 6, file->FileSize );
     MSI_RecordSetStringW( uirow, 9, MSI_RecordGetString( row, 5 ) );
-    ui_actiondata( package, szDuplicateFiles, uirow );
+    msi_ui_actiondata( package, szDuplicateFiles, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(dest);
@@ -1037,7 +1062,7 @@ static UINT ITERATE_RemoveDuplicateFiles( MSIRECORD *row, LPVOID param )
     MSIFILE *file;
 
     component = MSI_RecordGetString( row, 2 );
-    comp = get_loaded_component( package, component );
+    comp = msi_get_loaded_component( package, component );
     if (!comp)
         return ERROR_SUCCESS;
 
@@ -1062,7 +1087,7 @@ static UINT ITERATE_RemoveDuplicateFiles( MSIRECORD *row, LPVOID param )
         return ERROR_FUNCTION_FAILED;
     }
 
-    file = get_loaded_file( package, file_key );
+    file = msi_get_loaded_file( package, file_key );
     if (!file)
     {
         ERR("Original file unknown %s\n", debugstr_w(file_key));
@@ -1086,7 +1111,7 @@ static UINT ITERATE_RemoveDuplicateFiles( MSIRECORD *row, LPVOID param )
     uirow = MSI_CreateRecord( 9 );
     MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString( row, 1 ) );
     MSI_RecordSetStringW( uirow, 9, MSI_RecordGetString( row, 5 ) );
-    ui_actiondata( package, szRemoveDuplicateFiles, uirow );
+    msi_ui_actiondata( package, szRemoveDuplicateFiles, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(dest);
@@ -1152,7 +1177,7 @@ static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param)
     dirprop = MSI_RecordGetString(row, 4);
     install_mode = MSI_RecordGetInteger(row, 5);
 
-    comp = get_loaded_component(package, component);
+    comp = msi_get_loaded_component(package, component);
     if (!comp->Enabled)
     {
         TRACE("component is disabled\n");
@@ -1179,7 +1204,7 @@ static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param)
     size = 0;
     if ((filename = strdupW( MSI_RecordGetString(row, 3) )))
     {
-        reduce_to_longfilename( filename );
+        msi_reduce_to_long_filename( filename );
         size = lstrlenW( filename );
     }
     size += lstrlenW(dir) + 2;
@@ -1209,7 +1234,7 @@ done:
     uirow = MSI_CreateRecord( 9 );
     MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString(row, 1) );
     MSI_RecordSetStringW( uirow, 9, dir );
-    ui_actiondata( package, szRemoveFiles, uirow );
+    msi_ui_actiondata( package, szRemoveFiles, uirow );
     msiobj_release( &uirow->hdr );
 
     msi_free(filename);
@@ -1320,9 +1345,9 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
         uirow = MSI_CreateRecord( 9 );
         MSI_RecordSetStringW( uirow, 1, file->FileName );
         MSI_RecordSetStringW( uirow, 9, file->Component->Directory );
-        ui_actiondata( package, szRemoveFiles, uirow );
+        msi_ui_actiondata( package, szRemoveFiles, uirow );
         msiobj_release( &uirow->hdr );
-        /* FIXME: call ui_progress here? */
+        /* FIXME: call msi_ui_progress here? */
     }
 
     return ERROR_SUCCESS;
diff --git a/dlls/msi/font.c b/dlls/msi/font.c
index f74c59e..b5493a0 100644
--- a/dlls/msi/font.c
+++ b/dlls/msi/font.c
@@ -212,7 +212,7 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
     LPWSTR uipath, p;
 
     filename = MSI_RecordGetString( row, 1 );
-    file = get_loaded_file( package, filename );
+    file = msi_get_loaded_file( package, filename );
     if (!file)
     {
         ERR("Unable to load file\n");
@@ -256,10 +256,10 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
     if (p) p++;
     else p = uipath;
     MSI_RecordSetStringW( uirow, 1, p );
-    ui_actiondata( package, szRegisterFonts, uirow);
+    msi_ui_actiondata( package, szRegisterFonts, uirow );
     msiobj_release( &uirow->hdr );
     msi_free( uipath );
-    /* FIXME: call ui_progress? */
+    /* FIXME: call msi_ui_progress? */
 
     return ERROR_SUCCESS;
 }
@@ -296,7 +296,7 @@ static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param )
     LPWSTR uipath, p;
 
     filename = MSI_RecordGetString( row, 1 );
-    file = get_loaded_file( package, filename );
+    file = msi_get_loaded_file( package, filename );
     if (!file)
     {
         ERR("Unable to load file\n");
@@ -340,10 +340,10 @@ static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param )
     if (p) p++;
     else p = uipath;
     MSI_RecordSetStringW( uirow, 1, p );
-    ui_actiondata( package, szUnregisterFonts, uirow );
+    msi_ui_actiondata( package, szUnregisterFonts, uirow );
     msiobj_release( &uirow->hdr );
     msi_free( uipath );
-    /* FIXME: call ui_progress? */
+    /* FIXME: call msi_ui_progress? */
 
     return ERROR_SUCCESS;
 }
diff --git a/dlls/msi/format.c b/dlls/msi/format.c
index 7047433..8188f13 100644
--- a/dlls/msi/format.c
+++ b/dlls/msi/format.c
@@ -189,12 +189,12 @@ static LPWSTR deformat_component(FORMAT *format, FORMSTR *str)
     key = msi_alloc((str->len + 1) * sizeof(WCHAR));
     lstrcpynW(key, get_formstr_data(format, str), str->len + 1);
 
-    comp = get_loaded_component(format->package, key);
+    comp = msi_get_loaded_component(format->package, key);
     if (!comp)
         goto done;
 
     if (comp->Action == INSTALLSTATE_SOURCE)
-        ret = resolve_source_folder( format->package, comp->Directory, NULL );
+        ret = msi_resolve_source_folder( format->package, comp->Directory, NULL );
     else
         ret = strdupW( msi_get_target_folder( format->package, comp->Directory ) );
 
@@ -212,7 +212,7 @@ static LPWSTR deformat_file(FORMAT *format, FORMSTR *str, BOOL shortname)
     key = msi_alloc((str->len + 1) * sizeof(WCHAR));
     lstrcpynW(key, get_formstr_data(format, str), str->len + 1);
 
-    file = get_loaded_file(format->package, key);
+    file = msi_get_loaded_file(format->package, key);
     if (!file)
         goto done;
 
@@ -1020,3 +1020,26 @@ done:
     msi_free(value);
     return r;
 }
+
+/* wrapper to resist a need for a full rewrite right now */
+DWORD deformat_string( MSIPACKAGE *package, const WCHAR *ptr, WCHAR **data )
+{
+    if (ptr)
+    {
+        DWORD size = 0;
+        MSIRECORD *rec = MSI_CreateRecord( 1 );
+
+        MSI_RecordSetStringW( rec, 0, ptr );
+        MSI_FormatRecordW( package, rec, NULL, &size );
+
+        size++;
+        *data = msi_alloc( size * sizeof(WCHAR) );
+        if (size > 1) MSI_FormatRecordW( package, rec, *data, &size );
+        else *data[0] = 0;
+
+        msiobj_release( &rec->hdr );
+        return size * sizeof(WCHAR);
+    }
+    *data = NULL;
+    return 0;
+}
diff --git a/dlls/msi/helpers.c b/dlls/msi/helpers.c
deleted file mode 100644
index 9e7464e..0000000
--- a/dlls/msi/helpers.c
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
- * Implementation of the Microsoft Installer (msi.dll)
- *
- * Copyright 2005 Aric Stewart for CodeWeavers
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/*
- * Here are helper functions formally in action.c that are used by a variety of
- * actions and functions.
- */
-
-#include <stdarg.h>
-
-#include "windef.h"
-#include "wine/debug.h"
-#include "msipriv.h"
-#include "winuser.h"
-#include "wine/unicode.h"
-#include "msidefs.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
-
-LPWSTR build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name )
-{
-    LPWSTR SystemFolder, dest, FilePath;
-
-    static const WCHAR szMicrosoft[] =
-        {'M','i','c','r','o','s','o','f','t','\\',0};
-    static const WCHAR szInstaller[] = 
-        {'I','n','s','t','a','l','l','e','r','\\',0};
-    static const WCHAR szADFolder[] =
-        {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
-    static const WCHAR szWFolder[] =
-        {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
-
-    if(package->Context == MSIINSTALLCONTEXT_MACHINE)
-        SystemFolder = msi_dup_property( package->db, szWFolder );
-    else
-    {
-        LPWSTR ADTgt = msi_dup_property( package->db, szADFolder );
-        SystemFolder = build_directory_name(2, ADTgt, szMicrosoft);
-        msi_free(ADTgt);
-    }
-
-    dest = build_directory_name(3, SystemFolder, szInstaller, package->ProductCode);
-
-    create_full_pathW(dest);
-
-    FilePath = build_directory_name(2, dest, icon_name);
-
-    msi_free(SystemFolder);
-    msi_free(dest);
-    return FilePath;
-}
-
-LPWSTR msi_dup_record_field( MSIRECORD *rec, INT field )
-{
-    DWORD sz = 0;
-    LPWSTR str;
-    UINT r;
-
-    if (MSI_RecordIsNull( rec, field ))
-        return NULL;
-
-    r = MSI_RecordGetStringW( rec, field, NULL, &sz );
-    if (r != ERROR_SUCCESS)
-        return NULL;
-
-    sz ++;
-    str = msi_alloc( sz * sizeof (WCHAR) );
-    if (!str)
-        return str;
-    str[0] = 0;
-    r = MSI_RecordGetStringW( rec, field, str, &sz );
-    if (r != ERROR_SUCCESS)
-    {
-        ERR("failed to get string!\n");
-        msi_free( str );
-        return NULL;
-    }
-    return str;
-}
-
-MSICOMPONENT* get_loaded_component( MSIPACKAGE* package, LPCWSTR Component )
-{
-    MSICOMPONENT *comp;
-
-    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
-    {
-        if (!strcmpW( Component, comp->Component ))
-            return comp;
-    }
-    return NULL;
-}
-
-MSIFEATURE* get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
-{
-    MSIFEATURE *feature;
-
-    LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
-    {
-        if (!strcmpW( Feature, feature->Feature ))
-            return feature;
-    }
-    return NULL;
-}
-
-MSIFILE* get_loaded_file( MSIPACKAGE* package, LPCWSTR key )
-{
-    MSIFILE *file;
-
-    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
-    {
-        if (!strcmpW( key, file->File ))
-            return file;
-    }
-    return NULL;
-}
-
-MSIFILEPATCH* get_loaded_filepatch( MSIPACKAGE* package, LPCWSTR key )
-{
-    MSIFILEPATCH *patch;
-
-    /* FIXME: There might be more than one patch */
-
-    LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
-    {
-        if (!strcmpW( key, patch->File->File ))
-            return patch;
-    }
-    return NULL;
-}
-
-int track_tempfile( MSIPACKAGE *package, LPCWSTR path )
-{
-    MSITEMPFILE *temp;
-
-    TRACE("%s\n", debugstr_w(path));
-
-    LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry )
-        if (!strcmpW( path, temp->Path ))
-            return 0;
-
-    temp = msi_alloc_zero( sizeof (MSITEMPFILE) );
-    if (!temp)
-        return -1;
-
-    list_add_head( &package->tempfiles, &temp->entry );
-    temp->Path = strdupW( path );
-
-    return 0;
-}
-
-MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir )
-{
-    MSIFOLDER *folder;
-
-    LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
-    {
-        if (!strcmpW( dir, folder->Directory ))
-            return folder;
-    }
-    return NULL;
-}
-
-static LPWSTR get_source_root( MSIPACKAGE *package )
-{
-    LPWSTR path, p;
-
-    path = msi_dup_property( package->db, szSourceDir );
-    if (path)
-        return path;
-
-    path = msi_dup_property( package->db, szDatabase );
-    if (path)
-    {
-        p = strrchrW(path,'\\');
-        if (p)
-            *(p+1) = 0;
-    }
-    return path;
-}
-
-LPWSTR resolve_file_source(MSIPACKAGE *package, MSIFILE *file)
-{
-    LPWSTR p, path;
-
-    TRACE("Working to resolve source of file %s\n", debugstr_w(file->File));
-
-    if (file->IsCompressed)
-        return NULL;
-
-    p = resolve_source_folder( package, file->Component->Directory, NULL );
-    path = build_directory_name(2, p, file->ShortName);
-
-    if (file->LongName &&
-        GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES)
-    {
-        msi_free(path);
-        path = build_directory_name(2, p, file->LongName);
-    }
-
-    msi_free(p);
-
-    TRACE("file %s source resolves to %s\n", debugstr_w(file->File), debugstr_w(path));
-    return path;
-}
-
-LPWSTR resolve_source_folder( MSIPACKAGE *package, LPCWSTR name, MSIFOLDER **folder )
-{
-    MSIFOLDER *f;
-    LPWSTR p, path = NULL, parent;
-
-    TRACE("working to resolve %s\n", debugstr_w(name));
-
-    if (!strcmpW( name, szSourceDir ))
-        name = szTargetDir;
-
-    f = get_loaded_folder( package, name );
-    if (!f)
-        return NULL;
-
-    /* special resolving for Target and Source root dir */
-    if (!strcmpW( name, szTargetDir ))
-    {
-        if (!f->ResolvedSource)
-            f->ResolvedSource = get_source_root( package );
-    }
-
-    if (folder)
-        *folder = f;
-
-    if (f->ResolvedSource)
-    {
-        path = strdupW( f->ResolvedSource );
-        TRACE("   already resolved to %s\n", debugstr_w(path));
-        return path;
-    }
-
-    if (!f->Parent)
-        return path;
-
-    parent = f->Parent;
-    TRACE(" ! parent is %s\n", debugstr_w(parent));
-
-    p = resolve_source_folder( package, parent, NULL );
-
-    if (package->WordCount & msidbSumInfoSourceTypeCompressed)
-        path = get_source_root( package );
-    else if (package->WordCount & msidbSumInfoSourceTypeSFN)
-        path = build_directory_name( 3, p, f->SourceShortPath, NULL );
-    else
-        path = build_directory_name( 3, p, f->SourceLongPath, NULL );
-
-    TRACE("-> %s\n", debugstr_w(path));
-    f->ResolvedSource = strdupW( path );
-    msi_free( p );
-
-    return path;
-}
-
-/* wrapper to resist a need for a full rewrite right now */
-DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
-{
-    if (ptr)
-    {
-        MSIRECORD *rec = MSI_CreateRecord(1);
-        DWORD size = 0;
-
-        MSI_RecordSetStringW(rec,0,ptr);
-        MSI_FormatRecordW(package,rec,NULL,&size);
-
-        size++;
-        *data = msi_alloc(size*sizeof(WCHAR));
-        if (size > 1)
-            MSI_FormatRecordW(package,rec,*data,&size);
-        else
-            *data[0] = 0;
-
-        msiobj_release( &rec->hdr );
-        return sizeof(WCHAR)*size;
-    }
-
-    *data = NULL;
-    return 0;
-}
-
-UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
-{
-    UINT count;
-    LPWSTR *newbuf = NULL;
-    if (script >= TOTAL_SCRIPTS)
-    {
-        FIXME("Unknown script requested %i\n",script);
-        return ERROR_FUNCTION_FAILED;
-    }
-    TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script);
-    
-    count = package->script->ActionCount[script];
-    package->script->ActionCount[script]++;
-    if (count != 0)
-        newbuf = msi_realloc( package->script->Actions[script],
-                        package->script->ActionCount[script]* sizeof(LPWSTR));
-    else
-        newbuf = msi_alloc( sizeof(LPWSTR));
-
-    newbuf[count] = strdupW(action);
-    package->script->Actions[script] = newbuf;
-
-   return ERROR_SUCCESS;
-}
-
-void msi_free_action_script(MSIPACKAGE *package, UINT script)
-{
-    UINT i;
-    for (i = 0; i < package->script->ActionCount[script]; i++)
-        msi_free(package->script->Actions[script][i]);
-
-    msi_free(package->script->Actions[script]);
-    package->script->Actions[script] = NULL;
-    package->script->ActionCount[script] = 0;
-}
-
-/*
- *  build_directory_name()
- *
- *  This function is to save messing round with directory names
- *  It handles adding backslashes between path segments, 
- *   and can add \ at the end of the directory name if told to.
- *
- *  It takes a variable number of arguments.
- *  It always allocates a new string for the result, so make sure
- *   to free the return value when finished with it.
- *
- *  The first arg is the number of path segments that follow.
- *  The arguments following count are a list of path segments.
- *  A path segment may be NULL.
- *
- *  Path segments will be added with a \ separating them.
- *  A \ will not be added after the last segment, however if the
- *    last segment is NULL, then the last character will be a \
- * 
- */
-LPWSTR build_directory_name(DWORD count, ...)
-{
-    DWORD sz = 1, i;
-    LPWSTR dir;
-    va_list va;
-
-    va_start(va,count);
-    for(i=0; i<count; i++)
-    {
-        LPCWSTR str = va_arg(va,LPCWSTR);
-        if (str)
-            sz += strlenW(str) + 1;
-    }
-    va_end(va);
-
-    dir = msi_alloc(sz*sizeof(WCHAR));
-    dir[0]=0;
-
-    va_start(va,count);
-    for(i=0; i<count; i++)
-    {
-        LPCWSTR str = va_arg(va,LPCWSTR);
-        if (!str)
-            continue;
-        strcatW(dir, str);
-        if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
-            strcatW(dir, szBackSlash);
-    }
-    va_end(va);
-
-    return dir;
-}
-
-/***********************************************************************
- *            create_full_pathW
- *
- * Recursively create all directories in the path.
- *
- * shamelessly stolen from setupapi/queue.c
- */
-BOOL create_full_pathW(const WCHAR *path)
-{
-    BOOL ret = TRUE;
-    int len;
-    WCHAR *new_path;
-
-    new_path = msi_alloc( (strlenW(path) + 1) * sizeof(WCHAR));
-
-    strcpyW(new_path, path);
-
-    while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
-    new_path[len - 1] = 0;
-
-    while(!CreateDirectoryW(new_path, NULL))
-    {
-        WCHAR *slash;
-        DWORD last_error = GetLastError();
-        if(last_error == ERROR_ALREADY_EXISTS)
-            break;
-
-        if(last_error != ERROR_PATH_NOT_FOUND)
-        {
-            ret = FALSE;
-            break;
-        }
-
-        if(!(slash = strrchrW(new_path, '\\')))
-        {
-            ret = FALSE;
-            break;
-        }
-
-        len = slash - new_path;
-        new_path[len] = 0;
-        if(!create_full_pathW(new_path))
-        {
-            ret = FALSE;
-            break;
-        }
-        new_path[len] = '\\';
-    }
-
-    msi_free(new_path);
-    return ret;
-}
-
-void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
-{
-    MSIRECORD * row;
-
-    row = MSI_CreateRecord(4);
-    MSI_RecordSetInteger(row,1,a);
-    MSI_RecordSetInteger(row,2,b);
-    MSI_RecordSetInteger(row,3,c);
-    MSI_RecordSetInteger(row,4,d);
-    MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
-    msiobj_release(&row->hdr);
-
-    msi_dialog_check_messages(NULL);
-}
-
-void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
-{
-    static const WCHAR Query_t[] = 
-        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
-         '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
-         'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=', 
-         ' ','\'','%','s','\'',0};
-    WCHAR message[1024];
-    MSIRECORD * row = 0;
-    DWORD size;
-
-    if (!package->LastAction || strcmpW(package->LastAction, action))
-    {
-        row = MSI_QueryGetRecord(package->db, Query_t, action);
-        if (!row)
-            return;
-
-        if (MSI_RecordIsNull(row,3))
-        {
-            msiobj_release(&row->hdr);
-            return;
-        }
-
-        /* update the cached actionformat */
-        msi_free(package->ActionFormat);
-        package->ActionFormat = msi_dup_record_field(row,3);
-
-        msi_free(package->LastAction);
-        package->LastAction = strdupW(action);
-
-        msiobj_release(&row->hdr);
-    }
-
-    MSI_RecordSetStringW(record,0,package->ActionFormat);
-    size = 1024;
-    MSI_FormatRecordW(package,record,message,&size);
-
-    row = MSI_CreateRecord(1);
-    MSI_RecordSetStringW(row,1,message);
- 
-    MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
-
-    msiobj_release(&row->hdr);
-}
-
-void reduce_to_longfilename(WCHAR* filename)
-{
-    LPWSTR p = strchrW(filename,'|');
-    if (p)
-        memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
-}
-
-LPWSTR create_component_advertise_string(MSIPACKAGE* package, 
-                MSICOMPONENT* component, LPCWSTR feature)
-{
-    static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
-    WCHAR productid_85[21], component_85[21];
-    LPWSTR output = NULL;
-    DWORD sz = 0;
-    GUID clsid;
-
-    /* > is used if there is a component GUID and < if not.  */
-
-    productid_85[0] = 0;
-    component_85[0] = 0;
-
-    CLSIDFromString(package->ProductCode, &clsid);
-    encode_base85_guid(&clsid, productid_85);
-
-    if (component)
-    {
-        CLSIDFromString(component->ComponentId, &clsid);
-        encode_base85_guid(&clsid, component_85);
-    }
-
-    TRACE("prod=%s feat=%s comp=%s\n", debugstr_w(productid_85),
-          debugstr_w(feature), debugstr_w(component_85));
- 
-    sz = 20 + lstrlenW(feature) + 20 + 3;
-
-    output = msi_alloc_zero(sz*sizeof(WCHAR));
-
-    sprintfW(output, fmt, productid_85, feature,
-             component?'>':'<', component_85);
-    
-    return output;
-}
-
-/* update component state based on a feature change */
-void ACTION_UpdateComponentStates( MSIPACKAGE *package, MSIFEATURE *feature )
-{
-    INSTALLSTATE newstate;
-    ComponentList *cl;
-
-    newstate = feature->ActionRequest;
-
-    if (newstate == INSTALLSTATE_ABSENT)
-        newstate = INSTALLSTATE_UNKNOWN;
-
-    LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
-    {
-        MSICOMPONENT* component = cl->component;
-    
-        if (!component->Enabled) continue;
-
-        TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
-            newstate, debugstr_w(component->Component), component->Installed, 
-            component->Action, component->ActionRequest);
-        
-        if (newstate == INSTALLSTATE_LOCAL)
-        {
-            component->Action = INSTALLSTATE_LOCAL;
-            component->ActionRequest = INSTALLSTATE_LOCAL;
-        }
-        else 
-        {
-            ComponentList *clist;
-            MSIFEATURE *f;
-
-            component->hasLocalFeature = FALSE;
-
-            component->Action = newstate;
-            component->ActionRequest = newstate;
-
-            /* if any other feature wants it local we need to set it local */
-            LIST_FOR_EACH_ENTRY( f, &package->features, MSIFEATURE, entry )
-            {
-                if ( f->ActionRequest != INSTALLSTATE_LOCAL &&
-                     f->ActionRequest != INSTALLSTATE_SOURCE )
-                {
-                    continue;
-                }
-
-                LIST_FOR_EACH_ENTRY( clist, &f->Components, ComponentList, entry )
-                {
-                    if ( clist->component == component &&
-                         (f->ActionRequest == INSTALLSTATE_LOCAL ||
-                          f->ActionRequest == INSTALLSTATE_SOURCE) )
-                    {
-                        TRACE("Saved by %s\n", debugstr_w(f->Feature));
-                        component->hasLocalFeature = TRUE;
-
-                        if (component->Attributes & msidbComponentAttributesOptional)
-                        {
-                            if (f->Attributes & msidbFeatureAttributesFavorSource)
-                            {
-                                component->Action = INSTALLSTATE_SOURCE;
-                                component->ActionRequest = INSTALLSTATE_SOURCE;
-                            }
-                            else
-                            {
-                                component->Action = INSTALLSTATE_LOCAL;
-                                component->ActionRequest = INSTALLSTATE_LOCAL;
-                            }
-                        }
-                        else if (component->Attributes & msidbComponentAttributesSourceOnly)
-                        {
-                            component->Action = INSTALLSTATE_SOURCE;
-                            component->ActionRequest = INSTALLSTATE_SOURCE;
-                        }
-                        else
-                        {
-                            component->Action = INSTALLSTATE_LOCAL;
-                            component->ActionRequest = INSTALLSTATE_LOCAL;
-                        }
-                    }
-                }
-            }
-        }
-        TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
-            newstate, debugstr_w(component->Component), component->Installed, 
-            component->Action, component->ActionRequest);
-    } 
-}
-
-UINT register_unique_action(MSIPACKAGE *package, LPCWSTR action)
-{
-    UINT count;
-    LPWSTR *newbuf = NULL;
-
-    if (!package->script)
-        return FALSE;
-
-    TRACE("Registering %s as unique action\n", debugstr_w(action));
-    
-    count = package->script->UniqueActionsCount;
-    package->script->UniqueActionsCount++;
-    if (count != 0)
-        newbuf = msi_realloc( package->script->UniqueActions,
-                        package->script->UniqueActionsCount* sizeof(LPWSTR));
-    else
-        newbuf = msi_alloc( sizeof(LPWSTR));
-
-    newbuf[count] = strdupW(action);
-    package->script->UniqueActions = newbuf;
-
-    return ERROR_SUCCESS;
-}
-
-BOOL check_unique_action(const MSIPACKAGE *package, LPCWSTR action)
-{
-    UINT i;
-
-    if (!package->script)
-        return FALSE;
-
-    for (i = 0; i < package->script->UniqueActionsCount; i++)
-        if (!strcmpW(package->script->UniqueActions[i], action))
-            return TRUE;
-
-    return FALSE;
-}
-
-WCHAR* generate_error_string(MSIPACKAGE *package, UINT error, DWORD count, ... )
-{
-    static const WCHAR query[] = {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ','F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ','%','i',0};
-
-    MSIRECORD *rec;
-    MSIRECORD *row;
-    DWORD size = 0;
-    DWORD i;
-    va_list va;
-    LPCWSTR str;
-    LPWSTR data;
-
-    row = MSI_QueryGetRecord(package->db, query, error);
-    if (!row)
-        return 0;
-
-    rec = MSI_CreateRecord(count+2);
-
-    str = MSI_RecordGetString(row,1);
-    MSI_RecordSetStringW(rec,0,str);
-    msiobj_release( &row->hdr );
-    MSI_RecordSetInteger(rec,1,error);
-
-    va_start(va,count);
-    for (i = 0; i < count; i++)
-    {
-        str = va_arg(va,LPCWSTR);
-        MSI_RecordSetStringW(rec,(i+2),str);
-    }
-    va_end(va);
-
-    MSI_FormatRecordW(package,rec,NULL,&size);
-
-    size++;
-    data = msi_alloc(size*sizeof(WCHAR));
-    if (size > 1)
-        MSI_FormatRecordW(package,rec,data,&size);
-    else
-        data[0] = 0;
-    msiobj_release( &rec->hdr );
-    return data;
-}
diff --git a/dlls/msi/install.c b/dlls/msi/install.c
index 078e6df..686fc58 100644
--- a/dlls/msi/install.c
+++ b/dlls/msi/install.c
@@ -214,7 +214,7 @@ UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz )
 
 const WCHAR *msi_get_target_folder( MSIPACKAGE *package, const WCHAR *name )
 {
-    MSIFOLDER *folder = get_loaded_folder( package, name );
+    MSIFOLDER *folder = msi_get_loaded_folder( package, name );
     if (folder) return folder->ResolvedTarget;
     return NULL;
 }
@@ -339,6 +339,60 @@ UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder,
     return MSI_GetTargetPath( hInstall, szFolder, &path, pcchPathBuf );
 }
 
+static WCHAR *get_source_root( MSIDATABASE *db )
+{
+    WCHAR *path, *p;
+
+    if ((path = msi_dup_property( db, szSourceDir ))) return path;
+    if ((path = msi_dup_property( db, szDatabase )))
+    {
+        if ((p = strrchrW( path, '\\' ))) p[1] = 0;
+    }
+    return path;
+}
+
+WCHAR *msi_resolve_source_folder( MSIPACKAGE *package, const WCHAR *name, MSIFOLDER **folder )
+{
+    MSIFOLDER *f;
+    LPWSTR p, path = NULL, parent;
+
+    TRACE("working to resolve %s\n", debugstr_w(name));
+
+    if (!strcmpW( name, szSourceDir )) name = szTargetDir;
+    if (!(f = msi_get_loaded_folder( package, name ))) return NULL;
+
+    /* special resolving for root dir */
+    if (!strcmpW( name, szTargetDir ) && !f->ResolvedSource)
+    {
+        f->ResolvedSource = get_source_root( package->db );
+    }
+    if (folder) *folder = f;
+    if (f->ResolvedSource)
+    {
+        path = strdupW( f->ResolvedSource );
+        TRACE("   already resolved to %s\n", debugstr_w(path));
+        return path;
+    }
+    if (!f->Parent) return path;
+    parent = f->Parent;
+    TRACE(" ! parent is %s\n", debugstr_w(parent));
+
+    p = msi_resolve_source_folder( package, parent, NULL );
+
+    if (package->WordCount & msidbSumInfoSourceTypeCompressed)
+        path = get_source_root( package->db );
+    else if (package->WordCount & msidbSumInfoSourceTypeSFN)
+        path = msi_build_directory_name( 3, p, f->SourceShortPath, NULL );
+    else
+        path = msi_build_directory_name( 3, p, f->SourceLongPath, NULL );
+
+    TRACE("-> %s\n", debugstr_w(path));
+    f->ResolvedSource = strdupW( path );
+    msi_free( p );
+
+    return path;
+}
+
 /***********************************************************************
  * MSI_GetSourcePath   (internal)
  */
@@ -415,7 +469,7 @@ done:
         return ERROR_INVALID_PARAMETER;
     }
 
-    path = resolve_source_folder( package, szFolder, NULL );
+    path = msi_resolve_source_folder( package, szFolder, NULL );
     msiobj_release( &package->hdr );
 
     TRACE("path = %s\n", debugstr_w(path));
@@ -523,7 +577,7 @@ UINT MSI_SetTargetPathW( MSIPACKAGE *package, LPCWSTR szFolder, LPCWSTR szFolder
     {
         return ERROR_FUNCTION_FAILED;
     }
-    if (!(folder = get_loaded_folder( package, szFolder ))) return ERROR_DIRECTORY;
+    if (!(folder = msi_get_loaded_folder( package, szFolder ))) return ERROR_DIRECTORY;
 
     len = strlenW( szFolderPath );
     if (len && szFolderPath[len - 1] != '\\')
@@ -546,7 +600,7 @@ UINT MSI_SetTargetPathW( MSIPACKAGE *package, LPCWSTR szFolder, LPCWSTR szFolder
 
         dir = msi_get_target_folder( package, comp->Directory );
         msi_free( file->TargetPath );
-        file->TargetPath = build_directory_name( 2, dir, file->FileName );
+        file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
     }
     return ERROR_SUCCESS;
 }
@@ -792,17 +846,97 @@ UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
     return rc;
 }
 
+/* update component state based on a feature change */
+void ACTION_UpdateComponentStates( MSIPACKAGE *package, MSIFEATURE *feature )
+{
+    INSTALLSTATE newstate;
+    ComponentList *cl;
 
+    newstate = feature->ActionRequest;
+    if (newstate == INSTALLSTATE_ABSENT) newstate = INSTALLSTATE_UNKNOWN;
 
-UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
-                                INSTALLSTATE iState)
+    LIST_FOR_EACH_ENTRY(cl, &feature->Components, ComponentList, entry)
+    {
+        MSICOMPONENT *component = cl->component;
+
+        if (!component->Enabled) continue;
+
+        TRACE("Modifying (%d): Component %s (Installed %d, Action %d, Request %d)\n",
+            newstate, debugstr_w(component->Component), component->Installed,
+            component->Action, component->ActionRequest);
+
+        if (newstate == INSTALLSTATE_LOCAL)
+        {
+            component->Action = INSTALLSTATE_LOCAL;
+            component->ActionRequest = INSTALLSTATE_LOCAL;
+        }
+        else
+        {
+            ComponentList *clist;
+            MSIFEATURE *f;
+
+            component->hasLocalFeature = FALSE;
+
+            component->Action = newstate;
+            component->ActionRequest = newstate;
+            /* if any other feature wants it local we need to set it local */
+            LIST_FOR_EACH_ENTRY(f, &package->features, MSIFEATURE, entry)
+            {
+                if ( f->ActionRequest != INSTALLSTATE_LOCAL &&
+                     f->ActionRequest != INSTALLSTATE_SOURCE )
+                {
+                    continue;
+                }
+                LIST_FOR_EACH_ENTRY(clist, &f->Components, ComponentList, entry)
+                {
+                    if (clist->component == component &&
+                        (f->ActionRequest == INSTALLSTATE_LOCAL ||
+                         f->ActionRequest == INSTALLSTATE_SOURCE))
+                    {
+                        TRACE("Saved by %s\n", debugstr_w(f->Feature));
+                        component->hasLocalFeature = TRUE;
+
+                        if (component->Attributes & msidbComponentAttributesOptional)
+                        {
+                            if (f->Attributes & msidbFeatureAttributesFavorSource)
+                            {
+                                component->Action = INSTALLSTATE_SOURCE;
+                                component->ActionRequest = INSTALLSTATE_SOURCE;
+                            }
+                            else
+                            {
+                                component->Action = INSTALLSTATE_LOCAL;
+                                component->ActionRequest = INSTALLSTATE_LOCAL;
+                            }
+                        }
+                        else if (component->Attributes & msidbComponentAttributesSourceOnly)
+                        {
+                            component->Action = INSTALLSTATE_SOURCE;
+                            component->ActionRequest = INSTALLSTATE_SOURCE;
+                        }
+                        else
+                        {
+                            component->Action = INSTALLSTATE_LOCAL;
+                            component->ActionRequest = INSTALLSTATE_LOCAL;
+                        }
+                    }
+                }
+            }
+        }
+        TRACE("Result (%d): Component %s (Installed %d, Action %d, Request %d)\n",
+            newstate, debugstr_w(component->Component), component->Installed,
+            component->Action, component->ActionRequest);
+    }
+}
+
+UINT WINAPI MSI_SetFeatureStateW( MSIPACKAGE *package, LPCWSTR szFeature, INSTALLSTATE iState )
 {
     UINT rc = ERROR_SUCCESS;
     MSIFEATURE *feature, *child;
 
     TRACE("%s %i\n", debugstr_w(szFeature), iState);
 
-    feature = get_loaded_feature(package,szFeature);
+    feature = msi_get_loaded_feature( package, szFeature );
     if (!feature)
         return ERROR_UNKNOWN_FEATURE;
 
@@ -898,7 +1032,7 @@ UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPCWSTR szFeature,
 {
     MSIFEATURE *feature;
 
-    feature = get_loaded_feature(package,szFeature);
+    feature = msi_get_loaded_feature(package,szFeature);
     if (!feature)
         return ERROR_UNKNOWN_FEATURE;
 
@@ -1018,7 +1152,7 @@ UINT MSI_GetFeatureCost( MSIPACKAGE *package, MSIFEATURE *feature, MSICOSTTREE t
         const WCHAR *feature_parent = feature->Feature_Parent;
         for (;;)
         {
-            MSIFEATURE *parent = get_loaded_feature( package, feature_parent );
+            MSIFEATURE *parent = msi_get_loaded_feature( package, feature_parent );
             if (!parent)
                 break;
 
@@ -1091,7 +1225,7 @@ UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature,
         return ERROR_SUCCESS;
     }
 
-    feature = get_loaded_feature(package, szFeature);
+    feature = msi_get_loaded_feature(package, szFeature);
 
     if (feature)
         ret = MSI_GetFeatureCost(package, feature, iCostTree, iState, piCost);
@@ -1143,7 +1277,7 @@ static UINT MSI_SetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
 
     TRACE("%p %s %d\n", package, debugstr_w(szComponent), iState);
 
-    comp = get_loaded_component(package, szComponent);
+    comp = msi_get_loaded_component(package, szComponent);
     if (!comp)
         return ERROR_UNKNOWN_COMPONENT;
 
@@ -1161,7 +1295,7 @@ UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent,
     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent),
            piInstalled, piAction);
 
-    comp = get_loaded_component(package,szComponent);
+    comp = msi_get_loaded_component(package,szComponent);
     if (!comp)
         return ERROR_UNKNOWN_COMPONENT;
 
diff --git a/dlls/msi/media.c b/dlls/msi/media.c
index 712da26..bf0522a 100644
--- a/dlls/msi/media.c
+++ b/dlls/msi/media.c
@@ -83,7 +83,7 @@ static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi)
          INSTALLUILEVEL_NONE && !gUIHandlerA && !gUIHandlerW && !gUIHandlerRecord)
         return ERROR_SUCCESS;
 
-    error = generate_error_string(package, 1302, 1, mi->disk_prompt);
+    error = msi_build_error_string(package, 1302, 1, mi->disk_prompt);
     error_dialog = msi_dup_property(package->db, error_prop);
     source_dir = msi_dup_property(package->db, szSourceDir);
 
diff --git a/dlls/msi/msi.c b/dlls/msi/msi.c
index 7b90203..0f11024 100644
--- a/dlls/msi/msi.c
+++ b/dlls/msi/msi.c
@@ -1870,7 +1870,7 @@ UINT WINAPI MsiEnumComponentCostsW( MSIHANDLE handle, LPCWSTR component, DWORD i
         msiobj_release( &package->hdr );
         return ERROR_FUNCTION_NOT_CALLED;
     }
-    if (component && component[0] && !(comp = get_loaded_component( package, component )))
+    if (component && component[0] && !(comp = msi_get_loaded_component( package, component )))
     {
         msiobj_release( &package->hdr );
         return ERROR_UNKNOWN_COMPONENT;
@@ -1902,7 +1902,7 @@ UINT WINAPI MsiEnumComponentCostsW( MSIHANDLE handle, LPCWSTR component, DWORD i
             *buflen = 2;
             r = ERROR_SUCCESS;
         }
-        else if ((file = get_loaded_file( package, comp->KeyPath )))
+        else if ((file = msi_get_loaded_file( package, comp->KeyPath )))
         {
             *cost = max( 8, comp->Cost / 512 );
             drive[0] = file->TargetPath[0];
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 11b9d5b..78d1972 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -968,34 +968,33 @@ extern UINT ACTION_MsiUnpublishAssemblies(MSIPACKAGE *package) DECLSPEC_HIDDEN;
 
 /* Helpers */
 extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ) DECLSPEC_HIDDEN;
-extern LPWSTR msi_dup_record_field(MSIRECORD *row, INT index) DECLSPEC_HIDDEN;
+extern WCHAR *msi_dup_record_field(MSIRECORD *row, INT index) DECLSPEC_HIDDEN;
 extern LPWSTR msi_dup_property( MSIDATABASE *db, LPCWSTR prop ) DECLSPEC_HIDDEN;
 extern UINT msi_set_property( MSIDATABASE *, LPCWSTR, LPCWSTR ) DECLSPEC_HIDDEN;
 extern UINT msi_get_property( MSIDATABASE *, LPCWSTR, LPWSTR, LPDWORD ) DECLSPEC_HIDDEN;
 extern int msi_get_property_int( MSIDATABASE *package, LPCWSTR prop, int def ) DECLSPEC_HIDDEN;
-extern LPWSTR resolve_source_folder(MSIPACKAGE *package, LPCWSTR name, MSIFOLDER **folder) DECLSPEC_HIDDEN;
+extern WCHAR *msi_resolve_source_folder(MSIPACKAGE *package, const WCHAR *name, MSIFOLDER **folder) DECLSPEC_HIDDEN;
 extern void msi_resolve_target_folder(MSIPACKAGE *package, const WCHAR *name, BOOL load_prop) DECLSPEC_HIDDEN;
 extern void msi_clean_path( WCHAR *p ) DECLSPEC_HIDDEN;
-extern LPWSTR resolve_file_source(MSIPACKAGE *package, MSIFILE *file) DECLSPEC_HIDDEN;
+extern WCHAR *msi_resolve_file_source(MSIPACKAGE *package, MSIFILE *file) DECLSPEC_HIDDEN;
 extern const WCHAR *msi_get_target_folder(MSIPACKAGE *package, const WCHAR *name) DECLSPEC_HIDDEN;
 extern void msi_reset_folders( MSIPACKAGE *package, BOOL source ) DECLSPEC_HIDDEN;
-extern MSICOMPONENT *get_loaded_component( MSIPACKAGE* package, LPCWSTR Component ) DECLSPEC_HIDDEN;
-extern MSIFEATURE *get_loaded_feature( MSIPACKAGE* package, LPCWSTR Feature ) DECLSPEC_HIDDEN;
-extern MSIFILE *get_loaded_file( MSIPACKAGE* package, LPCWSTR file ) DECLSPEC_HIDDEN;
-extern MSIFILEPATCH *get_loaded_filepatch( MSIPACKAGE* package, LPCWSTR key ) DECLSPEC_HIDDEN;
-extern MSIFOLDER *get_loaded_folder( MSIPACKAGE *package, LPCWSTR dir ) DECLSPEC_HIDDEN;
-extern int track_tempfile(MSIPACKAGE *package, LPCWSTR path) DECLSPEC_HIDDEN;
-extern UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action) DECLSPEC_HIDDEN;
+extern MSICOMPONENT *msi_get_loaded_component(MSIPACKAGE *package, const WCHAR *Component) DECLSPEC_HIDDEN;
+extern MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE *package, const WCHAR *Feature) DECLSPEC_HIDDEN;
+extern MSIFILE *msi_get_loaded_file(MSIPACKAGE *package, const WCHAR *file) DECLSPEC_HIDDEN;
+extern MSIFILEPATCH *msi_get_loaded_filepatch(MSIPACKAGE* package, const WCHAR *key) DECLSPEC_HIDDEN;
+extern MSIFOLDER *msi_get_loaded_folder(MSIPACKAGE *package, const WCHAR *dir) DECLSPEC_HIDDEN;
+extern int msi_track_tempfile(MSIPACKAGE *package, const WCHAR *path) DECLSPEC_HIDDEN;
 extern void msi_free_action_script(MSIPACKAGE *package, UINT script) DECLSPEC_HIDDEN;
-extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR) DECLSPEC_HIDDEN;
-extern LPWSTR build_directory_name(DWORD , ...) DECLSPEC_HIDDEN;
-extern BOOL create_full_pathW(const WCHAR *path) DECLSPEC_HIDDEN;
-extern void reduce_to_longfilename(WCHAR*) DECLSPEC_HIDDEN;
-extern LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR) DECLSPEC_HIDDEN;
+extern WCHAR *msi_build_icon_path(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
+extern WCHAR *msi_build_directory_name(DWORD , ...) DECLSPEC_HIDDEN;
+extern BOOL msi_create_full_path(const WCHAR *path) DECLSPEC_HIDDEN;
+extern void msi_reduce_to_long_filename(WCHAR *) DECLSPEC_HIDDEN;
+extern WCHAR *msi_create_component_advertise_string(MSIPACKAGE *, MSICOMPONENT *, const WCHAR *) DECLSPEC_HIDDEN;
 extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, MSIFEATURE *feature) DECLSPEC_HIDDEN;
-extern UINT register_unique_action(MSIPACKAGE *, LPCWSTR) DECLSPEC_HIDDEN;
-extern BOOL check_unique_action(const MSIPACKAGE *, LPCWSTR) DECLSPEC_HIDDEN;
-extern WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... ) DECLSPEC_HIDDEN;
+extern UINT msi_register_unique_action(MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
+extern BOOL msi_action_is_unique(const MSIPACKAGE *, const WCHAR *) DECLSPEC_HIDDEN;
+extern WCHAR *msi_build_error_string(MSIPACKAGE *, UINT, DWORD, ...) DECLSPEC_HIDDEN;
 extern UINT msi_set_last_used_source(LPCWSTR product, LPCWSTR usersid,
                         MSIINSTALLCONTEXT context, DWORD options, LPCWSTR value) DECLSPEC_HIDDEN;
 extern UINT msi_get_local_package_name(LPWSTR path, LPCWSTR suffix) DECLSPEC_HIDDEN;
@@ -1043,9 +1042,9 @@ extern HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsi
 /* Scripting */
 extern DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action) DECLSPEC_HIDDEN;
 
-/* User Interface messages from the actions */
-extern void ui_progress(MSIPACKAGE *, int, int, int, int) DECLSPEC_HIDDEN;
-extern void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *) DECLSPEC_HIDDEN;
+/* User interface messages from the actions */
+extern void msi_ui_progress(MSIPACKAGE *, int, int, int, int) DECLSPEC_HIDDEN;
+extern void msi_ui_actiondata(MSIPACKAGE *, const WCHAR *, MSIRECORD *) DECLSPEC_HIDDEN;
 
 /* common strings */
 static const WCHAR szSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
@@ -1139,6 +1138,7 @@ static const WCHAR szStringData[] = {'_','S','t','r','i','n','g','D','a','t','a'
 static const WCHAR szStringPool[] = {'_','S','t','r','i','n','g','P','o','o','l',0};
 static const WCHAR szInstallLevel[] = {'I','N','S','T','A','L','L','L','E','V','E','L',0};
 static const WCHAR szCostInitialize[] = {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
+static const WCHAR szAppDataFolder[] = {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
 
 /* memory allocation macro functions */
 static void *msi_alloc( size_t len ) __WINE_ALLOC_SIZE(1);
diff --git a/dlls/msi/package.c b/dlls/msi/package.c
index e2476c5..9d7ab73 100644
--- a/dlls/msi/package.c
+++ b/dlls/msi/package.c
@@ -141,6 +141,17 @@ static void free_assembly( MSIASSEMBLY *assembly )
     msi_free( assembly );
 }
 
+void msi_free_action_script( MSIPACKAGE *package, UINT script )
+{
+    UINT i;
+    for (i = 0; i < package->script->ActionCount[script]; i++)
+        msi_free( package->script->Actions[script][i] );
+
+    msi_free( package->script->Actions[script] );
+    package->script->Actions[script] = NULL;
+    package->script->ActionCount[script] = 0;
+}
+
 static void free_package_structures( MSIPACKAGE *package )
 {
     INT i;
@@ -684,7 +695,6 @@ static VOID set_installer_properties(MSIPACKAGE *package)
     static const WCHAR szDesktopFolder[] = {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
     static const WCHAR szProgramMenuFolder[] = {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
     static const WCHAR szAdminToolsFolder[] = {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
-    static const WCHAR szAppDataFolder[] = {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
     static const WCHAR szSystemFolder[] = {'S','y','s','t','e','m','F','o','l','d','e','r',0};
     static const WCHAR szSystem16Folder[] = {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
     static const WCHAR szLocalAppDataFolder[] = {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
@@ -1443,6 +1453,22 @@ static UINT validate_package( MSIPACKAGE *package )
     return ERROR_INSTALL_LANGUAGE_UNSUPPORTED;
 }
 
+int msi_track_tempfile( MSIPACKAGE *package, const WCHAR *path )
+{
+    MSITEMPFILE *temp;
+
+    TRACE("%s\n", debugstr_w(path));
+
+    LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry )
+    {
+        if (!strcmpW( path, temp->Path )) return 0;
+    }
+    if (!(temp = msi_alloc_zero( sizeof (MSITEMPFILE) ))) return -1;
+    list_add_head( &package->tempfiles, &temp->entry );
+    temp->Path = strdupW( path );
+    return 0;
+}
+
 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
 {
     static const WCHAR dotmsi[] = {'.','m','s','i',0};
@@ -1552,7 +1578,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
     }
 
     if( file != szPackage )
-        track_tempfile( package, file );
+        msi_track_tempfile( package, file );
 
     si = MSI_GetSummaryInformationW( db->storage, 0 );
     if (!si)
diff --git a/dlls/msi/record.c b/dlls/msi/record.c
index fc30f79..e58bd82 100644
--- a/dlls/msi/record.c
+++ b/dlls/msi/record.c
@@ -1029,3 +1029,29 @@ BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
 
     return TRUE;
 }
+
+WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
+{
+    DWORD sz = 0;
+    WCHAR *str;
+    UINT r;
+
+    if (MSI_RecordIsNull( rec, field )) return NULL;
+
+    r = MSI_RecordGetStringW( rec, field, NULL, &sz );
+    if (r != ERROR_SUCCESS)
+        return NULL;
+
+    sz++;
+    str = msi_alloc( sz * sizeof(WCHAR) );
+    if (!str) return NULL;
+    str[0] = 0;
+    r = MSI_RecordGetStringW( rec, field, str, &sz );
+    if (r != ERROR_SUCCESS)
+    {
+        ERR("failed to get string!\n");
+        msi_free( str );
+        return NULL;
+    }
+    return str;
+}
diff --git a/dlls/msi/upgrade.c b/dlls/msi/upgrade.c
index 8e6b7ed..ef4f503 100644
--- a/dlls/msi/upgrade.c
+++ b/dlls/msi/upgrade.c
@@ -194,7 +194,7 @@ static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
             action_property = MSI_RecordGetString(rec, 7);
             append_productcode(package, action_property, productid);
             MSI_RecordSetStringW(uirow, 1, productid);
-            ui_actiondata(package, szFindRelatedProducts, uirow);
+            msi_ui_actiondata(package, szFindRelatedProducts, uirow);
         }
         index ++;
     }
@@ -218,13 +218,13 @@ UINT ACTION_FindRelatedProducts(MSIPACKAGE *package)
         return ERROR_SUCCESS;
     }
 
-    if (check_unique_action(package, szFindRelatedProducts))
+    if (msi_action_is_unique(package, szFindRelatedProducts))
     {
         TRACE("Skipping FindRelatedProducts action: already done in UI sequence\n");
         return ERROR_SUCCESS;
     }
     else
-        register_unique_action(package, szFindRelatedProducts);
+        msi_register_unique_action(package, szFindRelatedProducts);
 
     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
     if (rc != ERROR_SUCCESS)
-- 
1.7.4.1







More information about the wine-patches mailing list