MSI: resubmit, part 1 breaking up action.c

Aric Stewart aric at codeweavers.com
Wed Jun 15 09:49:43 CDT 2005


Breaking my last mondo patch up into smaller chunks.
Part 1: break out all the helper functions into helper.c
-------------- next part --------------
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.28
diff -u -r1.28 Makefile.in
--- dlls/msi/Makefile.in	9 Jun 2005 12:05:27 -0000	1.28
+++ dlls/msi/Makefile.in	15 Jun 2005 14:47:56 -0000
@@ -19,6 +19,7 @@
 	events.c \
 	format.c \
 	handle.c \
+	helpers.c \
 	insert.c \
 	msi.c \
 	msiquery.c \
Index: dlls/msi/action.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.c,v
retrieving revision 1.145
diff -u -r1.145 action.c
--- dlls/msi/action.c	9 Jun 2005 20:30:59 -0000	1.145
+++ dlls/msi/action.c	15 Jun 2005 14:47:58 -0000
@@ -62,8 +62,6 @@
 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
-static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
-                            LPWSTR *FilePath);
 
 /* 
  * action handlers
@@ -105,14 +103,8 @@
 /*
  * consts and values used
  */
-static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
-static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
-static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
-static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
 static const WCHAR c_colon[] = {'C',':','\\',0};
-static const WCHAR szProductCode[]=
-    {'P','r','o','d','u','c','t','C','o','d','e',0};
 static const WCHAR cszbs[]={'\\',0};
 const static WCHAR szCreateFolders[] =
     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
@@ -370,372 +362,6 @@
     { NULL, NULL},
 };
 
-
-/******************************************************** 
- * helper functions to get around current HACKS and such
- ********************************************************/
-inline static void reduce_to_longfilename(WCHAR* filename)
-{
-    LPWSTR p = strchrW(filename,'|');
-    if (p)
-        memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
-}
-
-inline static void reduce_to_shortfilename(WCHAR* filename)
-{
-    LPWSTR p = strchrW(filename,'|');
-    if (p)
-        *p = 0;
-}
-
-WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
-{
-    UINT rc;
-    DWORD sz;
-    LPWSTR ret;
-   
-    sz = 0; 
-    if (MSI_RecordIsNull(row,index))
-        return NULL;
-
-    rc = MSI_RecordGetStringW(row,index,NULL,&sz);
-
-    /* having an empty string is different than NULL */
-    if (sz == 0)
-    {
-        ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
-        ret[0] = 0;
-        return ret;
-    }
-
-    sz ++;
-    ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
-    rc = MSI_RecordGetStringW(row,index,ret,&sz);
-    if (rc!=ERROR_SUCCESS)
-    {
-        ERR("Unable to load dynamic string\n");
-        HeapFree(GetProcessHeap(), 0, ret);
-        ret = NULL;
-    }
-    return ret;
-}
-
-LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
-{
-    DWORD sz = 0;
-    LPWSTR str;
-    UINT r;
-
-    r = MSI_GetPropertyW(package, prop, NULL, &sz);
-    if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
-    {
-        if (rc)
-            *rc = r;
-        return NULL;
-    }
-    sz++;
-    str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
-    r = MSI_GetPropertyW(package, prop, str, &sz);
-    if (r != ERROR_SUCCESS)
-    {
-        HeapFree(GetProcessHeap(),0,str);
-        str = NULL;
-    }
-    if (rc)
-        *rc = r;
-    return str;
-}
-
-int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
-{
-    int rc = -1;
-    DWORD i;
-
-    for (i = 0; i < package->loaded_components; i++)
-    {
-        if (strcmpW(Component,package->components[i].Component)==0)
-        {
-            rc = i;
-            break;
-        }
-    }
-    return rc;
-}
-
-int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
-{
-    int rc = -1;
-    DWORD i;
-
-    for (i = 0; i < package->loaded_features; i++)
-    {
-        if (strcmpW(Feature,package->features[i].Feature)==0)
-        {
-            rc = i;
-            break;
-        }
-    }
-    return rc;
-}
-
-int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
-{
-    int rc = -1;
-    DWORD i;
-
-    for (i = 0; i < package->loaded_files; i++)
-    {
-        if (strcmpW(file,package->files[i].File)==0)
-        {
-            rc = i;
-            break;
-        }
-    }
-    return rc;
-}
-
-int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
-{
-    DWORD i;
-    DWORD index;
-
-    if (!package)
-        return -2;
-
-    for (i=0; i < package->loaded_files; i++)
-        if (strcmpW(package->files[i].File,name)==0)
-            return -1;
-
-    index = package->loaded_files;
-    package->loaded_files++;
-    if (package->loaded_files== 1)
-        package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
-    else
-        package->files = HeapReAlloc(GetProcessHeap(),0,
-            package->files , package->loaded_files * sizeof(MSIFILE));
-
-    memset(&package->files[index],0,sizeof(MSIFILE));
-
-    package->files[index].File = strdupW(name);
-    package->files[index].TargetPath = strdupW(path);
-    package->files[index].Temporary = TRUE;
-
-    TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));  
-
-    return 0;
-}
-
-static void remove_tracked_tempfiles(MSIPACKAGE* package)
-{
-    DWORD i;
-
-    if (!package)
-        return;
-
-    for (i = 0; i < package->loaded_files; i++)
-    {
-        if (package->files[i].Temporary)
-        {
-            TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
-            DeleteFileW(package->files[i].TargetPath);
-        }
-
-    }
-}
-
-/* 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);
-        if (size >= 0)
-        {
-            size++;
-            *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
-            if (size > 1)
-                MSI_FormatRecordW(package,rec,*data,&size);
-            else
-                *data[0] = 0;
-            msiobj_release( &rec->hdr );
-            return sizeof(WCHAR)*size;
-        }
-        msiobj_release( &rec->hdr );
-    }
-
-    *data = NULL;
-    return 0;
-}
-
-DWORD build_version_dword(LPCWSTR version_string)
-{
-    SHORT major,minor;
-    WORD build;
-    DWORD rc = 0x00000000;
-    LPCWSTR ptr1;
-
-    ptr1 = version_string;
-
-    if (!ptr1)
-        return rc;
-    else
-        major = atoiW(ptr1);
-
-
-    if(ptr1)
-        ptr1 = strchrW(ptr1,'.');
-    if (ptr1)
-    {
-        ptr1++;
-        minor = atoiW(ptr1);
-    }
-    else
-        minor = 0;
-
-    if (ptr1)
-        ptr1 = strchrW(ptr1,'.');
-
-    if (ptr1)
-    {
-        ptr1++;
-        build = atoiW(ptr1);
-    }
-    else
-        build = 0;
-
-    rc = MAKELONG(build,MAKEWORD(minor,major));
-    TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc);
-    return rc;
-}
-
-/* Called when the package is being closed */
-void ACTION_free_package_structures( MSIPACKAGE* package)
-{
-    INT i;
-    
-    TRACE("Freeing package action data\n");
-
-    remove_tracked_tempfiles(package);
-
-    /* No dynamic buffers in features */
-    if (package->features && package->loaded_features > 0)
-        HeapFree(GetProcessHeap(),0,package->features);
-
-    for (i = 0; i < package->loaded_folders; i++)
-    {
-        HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
-        HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
-        HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
-        HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
-        HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
-        HeapFree(GetProcessHeap(),0,package->folders[i].Property);
-    }
-    if (package->folders && package->loaded_folders > 0)
-        HeapFree(GetProcessHeap(),0,package->folders);
-
-    for (i = 0; i < package->loaded_components; i++)
-        HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
-
-    if (package->components && package->loaded_components > 0)
-        HeapFree(GetProcessHeap(),0,package->components);
-
-    for (i = 0; i < package->loaded_files; i++)
-    {
-        HeapFree(GetProcessHeap(),0,package->files[i].File);
-        HeapFree(GetProcessHeap(),0,package->files[i].FileName);
-        HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
-        HeapFree(GetProcessHeap(),0,package->files[i].Version);
-        HeapFree(GetProcessHeap(),0,package->files[i].Language);
-        HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
-        HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
-    }
-
-    if (package->files && package->loaded_files > 0)
-        HeapFree(GetProcessHeap(),0,package->files);
-
-    /* clean up extension, progid, class and verb structures */
-    for (i = 0; i < package->loaded_classes; i++)
-    {
-        HeapFree(GetProcessHeap(),0,package->classes[i].Description);
-        HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
-        HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
-        HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
-        HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
-        HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
-        HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
-    }
-
-    if (package->classes && package->loaded_classes > 0)
-        HeapFree(GetProcessHeap(),0,package->classes);
-
-    for (i = 0; i < package->loaded_extensions; i++)
-    {
-        HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
-    }
-
-    if (package->extensions && package->loaded_extensions > 0)
-        HeapFree(GetProcessHeap(),0,package->extensions);
-
-    for (i = 0; i < package->loaded_progids; i++)
-    {
-        HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
-        HeapFree(GetProcessHeap(),0,package->progids[i].Description);
-        HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
-    }
-
-    if (package->progids && package->loaded_progids > 0)
-        HeapFree(GetProcessHeap(),0,package->progids);
-
-    for (i = 0; i < package->loaded_verbs; i++)
-    {
-        HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
-        HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
-        HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
-    }
-
-    if (package->verbs && package->loaded_verbs > 0)
-        HeapFree(GetProcessHeap(),0,package->verbs);
-
-    for (i = 0; i < package->loaded_mimes; i++)
-        HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
-
-    if (package->mimes && package->loaded_mimes > 0)
-        HeapFree(GetProcessHeap(),0,package->mimes);
-
-    for (i = 0; i < package->loaded_appids; i++)
-    {
-        HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
-        HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
-        HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
-        HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
-    }
-
-    if (package->appids && package->loaded_appids > 0)
-        HeapFree(GetProcessHeap(),0,package->appids);
-
-    if (package->script)
-    {
-        for (i = 0; i < TOTAL_SCRIPTS; i++)
-        {
-            int j;
-            for (j = 0; j < package->script->ActionCount[i]; j++)
-                HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]);
-        
-            HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
-        }
-        HeapFree(GetProcessHeap(),0,package->script);
-    }
-
-    HeapFree(GetProcessHeap(),0,package->PackagePath);
-
-    /* cleanup control event subscriptions */
-    ControlEvent_CleanupSubscriptions(package);
-}
-
 static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
 {
     static const WCHAR szActionText[] = 
@@ -748,71 +374,6 @@
     msiobj_release(&row->hdr);
 }
 
-static 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);
-}
-
-static 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;
-    static const WCHAR szActionData[] = 
-        {'A','c','t','i','o','n','D','a','t','a',0};
-
-    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 */
-        HeapFree(GetProcessHeap(),0,package->ActionFormat);
-        package->ActionFormat = load_dynamic_stringW(row,3);
-
-        HeapFree(GetProcessHeap(),0,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);
-
-    ControlEvent_FireSubscribedEvent(package,szActionData, row);
-
-    msiobj_release(&row->hdr);
-}
-
-
 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
 {
     static const WCHAR template_s[]=
@@ -877,82 +438,6 @@
     msiobj_release(&row->hdr);
 }
 
-/*
- *  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 \
- * 
- */
-static 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 = HeapAlloc(GetProcessHeap(), 0, 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, cszbs);
-    }
-    return dir;
-}
-
-static BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index, 
-                                            INSTALLSTATE check )
-{
-    if (package->components[index].Installed == check)
-        return FALSE;
-
-    if (package->components[index].ActionRequest == check)
-        return TRUE;
-    else
-        return FALSE;
-}
-
-static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, 
-                                            INSTALLSTATE check )
-{
-    if (package->features[index].Installed == check)
-        return FALSE;
-
-    if (package->features[index].ActionRequest == check)
-        return TRUE;
-    else
-        return FALSE;
-}
-
-
 /****************************************************
  * TOP level entry points 
  *****************************************************/
@@ -1493,60 +978,6 @@
     return rc;
 }
 
-/***********************************************************************
- *            create_full_pathW
- *
- * Recursively create all directories in the path.
- *
- * shamelessly stolen from setupapi/queue.c
- */
-static BOOL create_full_pathW(const WCHAR *path)
-{
-    BOOL ret = TRUE;
-    int len;
-    WCHAR *new_path;
-
-    new_path = HeapAlloc(GetProcessHeap(), 0, (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] = '\\';
-    }
-
-    HeapFree(GetProcessHeap(), 0, new_path);
-    return ret;
-}
-
 /*
  * Also we cannot enable/disable components either, so for now I am just going 
  * to do all the directories for all the components.
@@ -1963,32 +1394,6 @@
     return ERROR_SUCCESS;
 }
 
-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 = HeapReAlloc(GetProcessHeap(),0,
-                        package->script->Actions[script],
-                        package->script->ActionCount[script]* sizeof(LPWSTR));
-    else
-        newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
-
-    newbuf[count] = strdupW(action);
-    package->script->Actions[script] = newbuf;
-
-   return ERROR_SUCCESS;
-}
-
 static UINT execute_script(MSIPACKAGE *package, UINT script )
 {
     int i;
@@ -2135,128 +1540,6 @@
     return index;
 }
 
-
-LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
-                      BOOL set_prop, MSIFOLDER **folder)
-{
-    DWORD i;
-    LPWSTR p, path = NULL;
-
-    TRACE("Working to resolve %s\n",debugstr_w(name));
-
-    if (!name)
-        return NULL;
-
-    /* special resolving for Target and Source root dir */
-    if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
-    {
-        if (!source)
-        {
-            path = load_dynamic_property(package,cszTargetDir,NULL);
-            if (!path)
-            {
-                path = load_dynamic_property(package,cszRootDrive,NULL);
-                if (set_prop)
-                    MSI_SetPropertyW(package,cszTargetDir,path);
-            }
-            if (folder)
-            {
-                for (i = 0; i < package->loaded_folders; i++)
-                {
-                    if (strcmpW(package->folders[i].Directory,name)==0)
-                        break;
-                }
-                *folder = &(package->folders[i]);
-            }
-            return path;
-        }
-        else
-        {
-            path = load_dynamic_property(package,cszSourceDir,NULL);
-            if (!path)
-            {
-                path = load_dynamic_property(package,cszDatabase,NULL);
-                if (path)
-                {
-                    p = strrchrW(path,'\\');
-                    if (p)
-                        *(p+1) = 0;
-                }
-            }
-            if (folder)
-            {
-                for (i = 0; i < package->loaded_folders; i++)
-                {
-                    if (strcmpW(package->folders[i].Directory,name)==0)
-                        break;
-                }
-                *folder = &(package->folders[i]);
-            }
-            return path;
-        }
-    }
-
-    for (i = 0; i < package->loaded_folders; i++)
-    {
-        if (strcmpW(package->folders[i].Directory,name)==0)
-            break;
-    }
-
-    if (i >= package->loaded_folders)
-        return NULL;
-
-    if (folder)
-        *folder = &(package->folders[i]);
-
-    if (!source && package->folders[i].ResolvedTarget)
-    {
-        path = strdupW(package->folders[i].ResolvedTarget);
-        TRACE("   already resolved to %s\n",debugstr_w(path));
-        return path;
-    }
-    else if (source && package->folders[i].ResolvedSource)
-    {
-        path = strdupW(package->folders[i].ResolvedSource);
-        TRACE("   (source)already resolved to %s\n",debugstr_w(path));
-        return path;
-    }
-    else if (!source && package->folders[i].Property)
-    {
-        path = build_directory_name(2, package->folders[i].Property, NULL);
-                    
-        TRACE("   internally set to %s\n",debugstr_w(path));
-        if (set_prop)
-            MSI_SetPropertyW(package,name,path);
-        return path;
-    }
-
-    if (package->folders[i].ParentIndex >= 0)
-    {
-        LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
-
-        TRACE(" ! Parent is %s\n", debugstr_w(parent));
-
-        p = resolve_folder(package, parent, source, set_prop, NULL);
-        if (!source)
-        {
-            TRACE("   TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
-            path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
-            package->folders[i].ResolvedTarget = strdupW(path);
-            TRACE("   resolved into %s\n",debugstr_w(path));
-            if (set_prop)
-                MSI_SetPropertyW(package,name,path);
-        }
-        else 
-        {
-            path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
-            TRACE("   (source)resolved into %s\n",debugstr_w(path));
-            package->folders[i].ResolvedSource = strdupW(path);
-        }
-        HeapFree(GetProcessHeap(),0,p);
-    }
-    return path;
-}
-
 /* scan for and update current install states */
 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
 {
@@ -2297,72 +1580,6 @@
     }
 }
 
-/* update compoennt state based on a feature change */
-void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
-{
-    int i;
-    INSTALLSTATE newstate;
-    MSIFEATURE *feature;
-
-    i = get_loaded_feature(package,szFeature);
-    if (i < 0)
-        return;
-
-    feature = &package->features[i];
-    newstate = feature->ActionRequest;
-
-    for( i = 0; i < feature->ComponentCount; i++)
-    {
-        MSICOMPONENT* component = &package->components[feature->Components[i]];
-
-        TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
-            newstate, debugstr_w(component->Component), component->Installed, 
-            component->Action, component->ActionRequest);
-        
-        if (!component->Enabled)
-            continue;
-        else
-        {
-            if (newstate == INSTALLSTATE_LOCAL)
-            {
-                component->ActionRequest = INSTALLSTATE_LOCAL;
-                component->Action = INSTALLSTATE_LOCAL;
-            }
-            else 
-            {
-                int j,k;
-
-                component->ActionRequest = newstate;
-                component->Action = newstate;
-
-                /*if any other feature wants is local we need to set it local*/
-                for (j = 0; 
-                     j < package->loaded_features &&
-                     component->ActionRequest != INSTALLSTATE_LOCAL; 
-                     j++)
-                {
-                    for (k = 0; k < package->features[j].ComponentCount; k++)
-                        if ( package->features[j].Components[k] ==
-                             feature->Components[i] )
-                        {
-                            if (package->features[j].ActionRequest == 
-                                INSTALLSTATE_LOCAL)
-                            {
-                                TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
-                                component->ActionRequest = INSTALLSTATE_LOCAL;
-                                component->Action = INSTALLSTATE_LOCAL;
-                            }
-                            break;
-                        }
-                }
-            }
-        }
-        TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
-            newstate, debugstr_w(component->Component), component->Installed, 
-            component->Action, component->ActionRequest);
-    } 
-}
-
 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property, 
                                     INSTALLSTATE state)
 {
@@ -5669,38 +4886,6 @@
     return ERROR_SUCCESS;
 }
 
-static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
-                            LPWSTR *FilePath)
-{
-    LPWSTR ProductCode;
-    LPWSTR SystemFolder;
-    LPWSTR dest;
-    UINT rc;
-
-    static const WCHAR szInstaller[] = 
-        {'M','i','c','r','o','s','o','f','t','\\',
-         'I','n','s','t','a','l','l','e','r','\\',0};
-    static const WCHAR szFolder[] =
-        {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
-
-    ProductCode = load_dynamic_property(package,szProductCode,&rc);
-    if (!ProductCode)
-        return rc;
-
-    SystemFolder = load_dynamic_property(package,szFolder,NULL);
-
-    dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
-
-    create_full_pathW(dest);
-
-    *FilePath = build_directory_name(2, dest, icon_name);
-
-    HeapFree(GetProcessHeap(),0,SystemFolder);
-    HeapFree(GetProcessHeap(),0,ProductCode);
-    HeapFree(GetProcessHeap(),0,dest);
-    return ERROR_SUCCESS;
-}
-
 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
 {
     UINT rc;
@@ -6691,60 +5876,6 @@
      * however for Adminastrative and uninstalls this step will be needed
      */
     return ERROR_SUCCESS;
-}
-
-static LPWSTR create_component_advertise_string(MSIPACKAGE* package, 
-                MSICOMPONENT* component, LPCWSTR feature)
-{
-    LPWSTR productid=NULL;
-    GUID clsid;
-    WCHAR productid_85[21];
-    WCHAR component_85[21];
-    /*
-     * I have a fair bit of confusion as to when a < is used and when a > is
-     * used. I do not think i have it right...
-     *
-     * Ok it appears that the > is used if there is a guid for the compoenent
-     * and the < is used if not.
-     */
-    static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
-    static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
-    LPWSTR output = NULL;
-    DWORD sz = 0;
-
-    memset(productid_85,0,sizeof(productid_85));
-    memset(component_85,0,sizeof(component_85));
-
-    productid = load_dynamic_property(package,szProductCode,NULL);
-    CLSIDFromString(productid, &clsid);
-    
-    encode_base85_guid(&clsid,productid_85);
-
-    CLSIDFromString(component->ComponentId, &clsid);
-    encode_base85_guid(&clsid,component_85);
-
-    TRACE("Doing something with this... %s %s %s\n", 
-            debugstr_w(productid_85), debugstr_w(feature),
-            debugstr_w(component_85));
- 
-    sz = lstrlenW(productid_85) + lstrlenW(feature);
-    if (component)
-        sz += lstrlenW(component_85);
-
-    sz+=3;
-    sz *= sizeof(WCHAR);
-           
-    output = HeapAlloc(GetProcessHeap(),0,sz);
-    memset(output,0,sz);
-
-    if (component)
-        sprintfW(output,fmt2,productid_85,feature,component_85);
-    else
-        sprintfW(output,fmt1,productid_85,feature);
-
-    HeapFree(GetProcessHeap(),0,productid);
-    
-    return output;
 }
 
 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 
Index: dlls/msi/action.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.h,v
retrieving revision 1.16
diff -u -r1.16 action.h
--- dlls/msi/action.h	9 Jun 2005 12:05:27 -0000	1.16
+++ dlls/msi/action.h	15 Jun 2005 14:47:58 -0000
@@ -205,6 +205,8 @@
 UINT ACTION_AppSearch(MSIPACKAGE *package);
 UINT ACTION_FindRelatedProducts(MSIPACKAGE *package);
 
+
+/* Helpers */
 DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
 WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index);
 LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc);
@@ -215,6 +217,17 @@
 int get_loaded_file(MSIPACKAGE* package, LPCWSTR file);
 int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
 UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action);
+UINT build_icon_path(MSIPACKAGE *, LPCWSTR, LPWSTR *);
+DWORD build_version_dword(LPCWSTR);
+LPWSTR build_directory_name(DWORD , ...);
+BOOL create_full_pathW(const WCHAR *path);
+BOOL ACTION_VerifyComponentForAction(MSIPACKAGE*, INT, INSTALLSTATE);
+BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE*, INT, INSTALLSTATE);
+void reduce_to_longfilename(WCHAR*);
+void reduce_to_shortfilename(WCHAR*);
+LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR);
+void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
+
 
 /* control event stuff */
 VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event,
@@ -225,5 +238,14 @@
 VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
                                       LPCWSTR control, LPCWSTR attribute );
 
-/* version stuff for upgrades */
-DWORD build_version_dword(LPCWSTR version_string);
+/* User Interface messages from the actions */
+void ui_progress(MSIPACKAGE *, int, int, int, int);
+void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *);
+
+
+/* string consts use a number of places  and defined in helpers.c*/
+extern const WCHAR cszSourceDir[];
+extern const WCHAR szProductCode[];
+extern const WCHAR cszRootDrive[];
+extern const WCHAR cszbs[];
+
--- /dev/null	2005-03-17 08:20:53.000000000 -0600
+++ dlls/msi/helpers.c	2005-06-15 09:46:37.000000000 -0500
@@ -0,0 +1,927 @@
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Here are helper functions formally in action.c that are used by a variaty of
+ * actions and functions.
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msipriv.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+#include "action.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
+static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
+
+const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
+const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0};
+const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
+const WCHAR cszbs[]={'\\',0};
+
+DWORD build_version_dword(LPCWSTR version_string)
+{
+    SHORT major,minor;
+    WORD build;
+    DWORD rc = 0x00000000;
+    LPCWSTR ptr1;
+
+    ptr1 = version_string;
+
+    if (!ptr1)
+        return rc;
+    else
+        major = atoiW(ptr1);
+
+
+    if(ptr1)
+        ptr1 = strchrW(ptr1,'.');
+    if (ptr1)
+    {
+        ptr1++;
+        minor = atoiW(ptr1);
+    }
+    else
+        minor = 0;
+
+    if (ptr1)
+        ptr1 = strchrW(ptr1,'.');
+
+    if (ptr1)
+    {
+        ptr1++;
+        build = atoiW(ptr1);
+    }
+    else
+        build = 0;
+
+    rc = MAKELONG(build,MAKEWORD(minor,major));
+    TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc);
+    return rc;
+}
+
+UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
+                            LPWSTR *FilePath)
+{
+    LPWSTR ProductCode;
+    LPWSTR SystemFolder;
+    LPWSTR dest;
+    UINT rc;
+
+    static const WCHAR szInstaller[] = 
+        {'M','i','c','r','o','s','o','f','t','\\',
+         'I','n','s','t','a','l','l','e','r','\\',0};
+    static const WCHAR szFolder[] =
+        {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
+
+    ProductCode = load_dynamic_property(package,szProductCode,&rc);
+    if (!ProductCode)
+        return rc;
+
+    SystemFolder = load_dynamic_property(package,szFolder,NULL);
+
+    dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
+
+    create_full_pathW(dest);
+
+    *FilePath = build_directory_name(2, dest, icon_name);
+
+    HeapFree(GetProcessHeap(),0,SystemFolder);
+    HeapFree(GetProcessHeap(),0,ProductCode);
+    HeapFree(GetProcessHeap(),0,dest);
+    return ERROR_SUCCESS;
+}
+
+WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
+{
+    UINT rc;
+    DWORD sz;
+    LPWSTR ret;
+   
+    sz = 0; 
+    if (MSI_RecordIsNull(row,index))
+        return NULL;
+
+    rc = MSI_RecordGetStringW(row,index,NULL,&sz);
+
+    /* having an empty string is different than NULL */
+    if (sz == 0)
+    {
+        ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
+        ret[0] = 0;
+        return ret;
+    }
+
+    sz ++;
+    ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
+    rc = MSI_RecordGetStringW(row,index,ret,&sz);
+    if (rc!=ERROR_SUCCESS)
+    {
+        ERR("Unable to load dynamic string\n");
+        HeapFree(GetProcessHeap(), 0, ret);
+        ret = NULL;
+    }
+    return ret;
+}
+
+LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
+{
+    DWORD sz = 0;
+    LPWSTR str;
+    UINT r;
+
+    r = MSI_GetPropertyW(package, prop, NULL, &sz);
+    if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
+    {
+        if (rc)
+            *rc = r;
+        return NULL;
+    }
+    sz++;
+    str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
+    r = MSI_GetPropertyW(package, prop, str, &sz);
+    if (r != ERROR_SUCCESS)
+    {
+        HeapFree(GetProcessHeap(),0,str);
+        str = NULL;
+    }
+    if (rc)
+        *rc = r;
+    return str;
+}
+
+int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
+{
+    int rc = -1;
+    DWORD i;
+
+    for (i = 0; i < package->loaded_components; i++)
+    {
+        if (strcmpW(Component,package->components[i].Component)==0)
+        {
+            rc = i;
+            break;
+        }
+    }
+    return rc;
+}
+
+int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
+{
+    int rc = -1;
+    DWORD i;
+
+    for (i = 0; i < package->loaded_features; i++)
+    {
+        if (strcmpW(Feature,package->features[i].Feature)==0)
+        {
+            rc = i;
+            break;
+        }
+    }
+    return rc;
+}
+
+int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
+{
+    int rc = -1;
+    DWORD i;
+
+    for (i = 0; i < package->loaded_files; i++)
+    {
+        if (strcmpW(file,package->files[i].File)==0)
+        {
+            rc = i;
+            break;
+        }
+    }
+    return rc;
+}
+
+int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
+{
+    DWORD i;
+    DWORD index;
+
+    if (!package)
+        return -2;
+
+    for (i=0; i < package->loaded_files; i++)
+        if (strcmpW(package->files[i].File,name)==0)
+            return -1;
+
+    index = package->loaded_files;
+    package->loaded_files++;
+    if (package->loaded_files== 1)
+        package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
+    else
+        package->files = HeapReAlloc(GetProcessHeap(),0,
+            package->files , package->loaded_files * sizeof(MSIFILE));
+
+    memset(&package->files[index],0,sizeof(MSIFILE));
+
+    package->files[index].File = strdupW(name);
+    package->files[index].TargetPath = strdupW(path);
+    package->files[index].Temporary = TRUE;
+
+    TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));  
+
+    return 0;
+}
+
+LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
+                      BOOL set_prop, MSIFOLDER **folder)
+{
+    DWORD i;
+    LPWSTR p, path = NULL;
+
+    TRACE("Working to resolve %s\n",debugstr_w(name));
+
+    if (!name)
+        return NULL;
+
+    /* special resolving for Target and Source root dir */
+    if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
+    {
+        if (!source)
+        {
+            path = load_dynamic_property(package,cszTargetDir,NULL);
+            if (!path)
+            {
+                path = load_dynamic_property(package,cszRootDrive,NULL);
+                if (set_prop)
+                    MSI_SetPropertyW(package,cszTargetDir,path);
+            }
+            if (folder)
+            {
+                for (i = 0; i < package->loaded_folders; i++)
+                {
+                    if (strcmpW(package->folders[i].Directory,name)==0)
+                        break;
+                }
+                *folder = &(package->folders[i]);
+            }
+            return path;
+        }
+        else
+        {
+            path = load_dynamic_property(package,cszSourceDir,NULL);
+            if (!path)
+            {
+                path = load_dynamic_property(package,cszDatabase,NULL);
+                if (path)
+                {
+                    p = strrchrW(path,'\\');
+                    if (p)
+                        *(p+1) = 0;
+                }
+            }
+            if (folder)
+            {
+                for (i = 0; i < package->loaded_folders; i++)
+                {
+                    if (strcmpW(package->folders[i].Directory,name)==0)
+                        break;
+                }
+                *folder = &(package->folders[i]);
+            }
+            return path;
+        }
+    }
+
+    for (i = 0; i < package->loaded_folders; i++)
+    {
+        if (strcmpW(package->folders[i].Directory,name)==0)
+            break;
+    }
+
+    if (i >= package->loaded_folders)
+        return NULL;
+
+    if (folder)
+        *folder = &(package->folders[i]);
+
+    if (!source && package->folders[i].ResolvedTarget)
+    {
+        path = strdupW(package->folders[i].ResolvedTarget);
+        TRACE("   already resolved to %s\n",debugstr_w(path));
+        return path;
+    }
+    else if (source && package->folders[i].ResolvedSource)
+    {
+        path = strdupW(package->folders[i].ResolvedSource);
+        TRACE("   (source)already resolved to %s\n",debugstr_w(path));
+        return path;
+    }
+    else if (!source && package->folders[i].Property)
+    {
+        path = build_directory_name(2, package->folders[i].Property, NULL);
+                    
+        TRACE("   internally set to %s\n",debugstr_w(path));
+        if (set_prop)
+            MSI_SetPropertyW(package,name,path);
+        return path;
+    }
+
+    if (package->folders[i].ParentIndex >= 0)
+    {
+        LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
+
+        TRACE(" ! Parent is %s\n", debugstr_w(parent));
+
+        p = resolve_folder(package, parent, source, set_prop, NULL);
+        if (!source)
+        {
+            WCHAR szShellObjectFolder[] = 
+{'S','H','E','L','L','_','O','B','J','E','C','T','_','F','O','L','D','E','R',0};
+
+            TRACE("   TargetDefault = %s\n",
+                    debugstr_w(package->folders[i].TargetDefault));
+
+            /* hack for GUPTA */
+            if (package->folders[i].TargetDefault &&
+                strcmpW(package->folders[i].TargetDefault,
+                                              szShellObjectFolder)==0)
+            {
+                LPWSTR sof = load_dynamic_property(package,szShellObjectFolder, 
+                                                    NULL);
+                if (sof)
+                {
+                    path = build_directory_name(3, p, sof, NULL);
+                    HeapFree(GetProcessHeap(),0,sof);
+                }
+                else
+                    path = build_directory_name(3, p, 
+                                package->folders[i].TargetDefault, NULL);
+            }
+            else
+                path = build_directory_name(3, p, 
+                            package->folders[i].TargetDefault, NULL);
+
+            package->folders[i].ResolvedTarget = strdupW(path);
+            TRACE("   resolved into %s\n",debugstr_w(path));
+            if (set_prop)
+                MSI_SetPropertyW(package,name,path);
+        }
+        else 
+        {
+            if (package->folders[i].SourceDefault && 
+                package->folders[i].SourceDefault[0]!='.')
+                path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
+            else
+                path = strdupW(p);
+            TRACE("   (source)resolved into %s\n",debugstr_w(path));
+            package->folders[i].ResolvedSource = strdupW(path);
+        }
+        HeapFree(GetProcessHeap(),0,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);
+        if (size >= 0)
+        {
+            size++;
+            *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
+            if (size > 1)
+                MSI_FormatRecordW(package,rec,*data,&size);
+            else
+                *data[0] = 0;
+            msiobj_release( &rec->hdr );
+            return sizeof(WCHAR)*size;
+        }
+        msiobj_release( &rec->hdr );
+    }
+
+    *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 = HeapReAlloc(GetProcessHeap(),0,
+                        package->script->Actions[script],
+                        package->script->ActionCount[script]* sizeof(LPWSTR));
+    else
+        newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
+
+    newbuf[count] = strdupW(action);
+    package->script->Actions[script] = newbuf;
+
+   return ERROR_SUCCESS;
+}
+
+static void remove_tracked_tempfiles(MSIPACKAGE* package)
+{
+    DWORD i;
+
+    if (!package)
+        return;
+
+    for (i = 0; i < package->loaded_files; i++)
+    {
+        if (package->files[i].Temporary)
+        {
+            TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
+            DeleteFileW(package->files[i].TargetPath);
+        }
+
+    }
+}
+
+/* Called when the package is being closed */
+void ACTION_free_package_structures( MSIPACKAGE* package)
+{
+    INT i;
+    
+    TRACE("Freeing package action data\n");
+
+    remove_tracked_tempfiles(package);
+
+    /* No dynamic buffers in features */
+    if (package->features && package->loaded_features > 0)
+        HeapFree(GetProcessHeap(),0,package->features);
+
+    for (i = 0; i < package->loaded_folders; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
+        HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
+        HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
+        HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
+        HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
+        HeapFree(GetProcessHeap(),0,package->folders[i].Property);
+    }
+    if (package->folders && package->loaded_folders > 0)
+        HeapFree(GetProcessHeap(),0,package->folders);
+
+    for (i = 0; i < package->loaded_components; i++)
+        HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
+
+    if (package->components && package->loaded_components > 0)
+        HeapFree(GetProcessHeap(),0,package->components);
+
+    for (i = 0; i < package->loaded_files; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->files[i].File);
+        HeapFree(GetProcessHeap(),0,package->files[i].FileName);
+        HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
+        HeapFree(GetProcessHeap(),0,package->files[i].Version);
+        HeapFree(GetProcessHeap(),0,package->files[i].Language);
+        HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
+        HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
+    }
+
+    if (package->files && package->loaded_files > 0)
+        HeapFree(GetProcessHeap(),0,package->files);
+
+    /* clean up extension, progid, class and verb structures */
+    for (i = 0; i < package->loaded_classes; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->classes[i].Description);
+        HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
+        HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
+        HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
+        HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
+        HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
+        HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
+    }
+
+    if (package->classes && package->loaded_classes > 0)
+        HeapFree(GetProcessHeap(),0,package->classes);
+
+    for (i = 0; i < package->loaded_extensions; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
+    }
+
+    if (package->extensions && package->loaded_extensions > 0)
+        HeapFree(GetProcessHeap(),0,package->extensions);
+
+    for (i = 0; i < package->loaded_progids; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
+        HeapFree(GetProcessHeap(),0,package->progids[i].Description);
+        HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
+    }
+
+    if (package->progids && package->loaded_progids > 0)
+        HeapFree(GetProcessHeap(),0,package->progids);
+
+    for (i = 0; i < package->loaded_verbs; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
+        HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
+        HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
+    }
+
+    if (package->verbs && package->loaded_verbs > 0)
+        HeapFree(GetProcessHeap(),0,package->verbs);
+
+    for (i = 0; i < package->loaded_mimes; i++)
+        HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
+
+    if (package->mimes && package->loaded_mimes > 0)
+        HeapFree(GetProcessHeap(),0,package->mimes);
+
+    for (i = 0; i < package->loaded_appids; i++)
+    {
+        HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
+        HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
+        HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
+        HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
+    }
+
+    if (package->appids && package->loaded_appids > 0)
+        HeapFree(GetProcessHeap(),0,package->appids);
+
+    if (package->script)
+    {
+        for (i = 0; i < TOTAL_SCRIPTS; i++)
+        {
+            int j;
+            for (j = 0; j < package->script->ActionCount[i]; j++)
+                HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]);
+        
+            HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
+        }
+        HeapFree(GetProcessHeap(),0,package->script);
+    }
+
+    HeapFree(GetProcessHeap(),0,package->PackagePath);
+
+    /* cleanup control event subscriptions */
+    ControlEvent_CleanupSubscriptions(package);
+}
+
+/*
+ *  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 = HeapAlloc(GetProcessHeap(), 0, 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, cszbs);
+    }
+    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 = HeapAlloc(GetProcessHeap(), 0, (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] = '\\';
+    }
+
+    HeapFree(GetProcessHeap(), 0, 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;
+    static const WCHAR szActionData[] = 
+        {'A','c','t','i','o','n','D','a','t','a',0};
+
+    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 */
+        HeapFree(GetProcessHeap(),0,package->ActionFormat);
+        package->ActionFormat = load_dynamic_stringW(row,3);
+
+        HeapFree(GetProcessHeap(),0,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);
+
+    ControlEvent_FireSubscribedEvent(package,szActionData, row);
+
+    msiobj_release(&row->hdr);
+}
+
+BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index, 
+                                            INSTALLSTATE check )
+{
+    if (package->components[index].Installed == check)
+        return FALSE;
+
+    if (package->components[index].ActionRequest == check)
+        return TRUE;
+    else
+        return FALSE;
+}
+
+BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, 
+                                            INSTALLSTATE check )
+{
+    if (package->features[index].Installed == check)
+        return FALSE;
+
+    if (package->features[index].ActionRequest == check)
+        return TRUE;
+    else
+        return FALSE;
+}
+
+void reduce_to_longfilename(WCHAR* filename)
+{
+    LPWSTR p = strchrW(filename,'|');
+    if (p)
+        memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
+}
+
+void reduce_to_shortfilename(WCHAR* filename)
+{
+    LPWSTR p = strchrW(filename,'|');
+    if (p)
+        *p = 0;
+}
+
+LPWSTR create_component_advertise_string(MSIPACKAGE* package, 
+                MSICOMPONENT* component, LPCWSTR feature)
+{
+    LPWSTR productid=NULL;
+    GUID clsid;
+    WCHAR productid_85[21];
+    WCHAR component_85[21];
+    /*
+     * I have a fair bit of confusion as to when a < is used and when a > is
+     * used. I do not think i have it right...
+     *
+     * Ok it appears that the > is used if there is a guid for the compoenent
+     * and the < is used if not.
+     */
+    static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
+    static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
+    LPWSTR output = NULL;
+    DWORD sz = 0;
+
+    memset(productid_85,0,sizeof(productid_85));
+    memset(component_85,0,sizeof(component_85));
+
+    productid = load_dynamic_property(package,szProductCode,NULL);
+    CLSIDFromString(productid, &clsid);
+    
+    encode_base85_guid(&clsid,productid_85);
+
+    CLSIDFromString(component->ComponentId, &clsid);
+    encode_base85_guid(&clsid,component_85);
+
+    TRACE("Doing something with this... %s %s %s\n", 
+            debugstr_w(productid_85), debugstr_w(feature),
+            debugstr_w(component_85));
+ 
+    sz = lstrlenW(productid_85) + lstrlenW(feature);
+    if (component)
+        sz += lstrlenW(component_85);
+
+    sz+=3;
+    sz *= sizeof(WCHAR);
+           
+    output = HeapAlloc(GetProcessHeap(),0,sz);
+    memset(output,0,sz);
+
+    if (component)
+        sprintfW(output,fmt2,productid_85,feature,component_85);
+    else
+        sprintfW(output,fmt1,productid_85,feature);
+
+    HeapFree(GetProcessHeap(),0,productid);
+    
+    return output;
+}
+
+/* update compoennt state based on a feature change */
+void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
+{
+    int i;
+    INSTALLSTATE newstate;
+    MSIFEATURE *feature;
+
+    i = get_loaded_feature(package,szFeature);
+    if (i < 0)
+        return;
+
+    feature = &package->features[i];
+    newstate = feature->ActionRequest;
+
+    for( i = 0; i < feature->ComponentCount; i++)
+    {
+        MSICOMPONENT* component = &package->components[feature->Components[i]];
+
+        TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
+            newstate, debugstr_w(component->Component), component->Installed, 
+            component->Action, component->ActionRequest);
+        
+        if (!component->Enabled)
+            continue;
+        else
+        {
+            if (newstate == INSTALLSTATE_LOCAL)
+            {
+                component->ActionRequest = INSTALLSTATE_LOCAL;
+                component->Action = INSTALLSTATE_LOCAL;
+            }
+            else 
+            {
+                int j,k;
+
+                component->ActionRequest = newstate;
+                component->Action = newstate;
+
+                /*if any other feature wants is local we need to set it local*/
+                for (j = 0; 
+                     j < package->loaded_features &&
+                     component->ActionRequest != INSTALLSTATE_LOCAL; 
+                     j++)
+                {
+                    for (k = 0; k < package->features[j].ComponentCount; k++)
+                        if ( package->features[j].Components[k] ==
+                             feature->Components[i] )
+                        {
+                            if (package->features[j].ActionRequest == 
+                                INSTALLSTATE_LOCAL)
+                            {
+                                TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
+                                component->ActionRequest = INSTALLSTATE_LOCAL;
+                                component->Action = INSTALLSTATE_LOCAL;
+                            }
+                            break;
+                        }
+                }
+            }
+        }
+        TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
+            newstate, debugstr_w(component->Component), component->Installed, 
+            component->Action, component->ActionRequest);
+    } 
+}


More information about the wine-patches mailing list