action.c

来自「一个类似windows」· C语言 代码 · 共 2,053 行 · 第 1/5 页

C
2,053
字号
    BOOL override = FALSE;
    MSICOMPONENT* component;
    MSIFEATURE *feature;


    /* I do not know if this is where it should happen.. but */

    TRACE("Checking Install Level\n");

    install_level = msi_get_property_int( package, szlevel, 1 );

    /* ok hereis the _real_ rub
     * all these activation/deactivation things happen in order and things
     * later on the list override things earlier on the list.
     * 1) INSTALLLEVEL processing
     * 2) ADDLOCAL
     * 3) REMOVE
     * 4) ADDSOURCE
     * 5) ADDDEFAULT
     * 6) REINSTALL
     * 7) COMPADDLOCAL
     * 8) COMPADDSOURCE
     * 9) FILEADDLOCAL
     * 10) FILEADDSOURCE
     * 11) FILEADDDEFAULT
     * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
     * ignored for all the features. seems strange, especially since it is not
     * documented anywhere, but it is how it works. 
     *
     * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
     * REMOVE are the big ones, since we don't handle administrative installs
     * yet anyway.
     */
    override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
    override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
    override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);

    if (!override)
    {
        LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
        {
            BOOL feature_state = ((feature->Level > 0) &&
                             (feature->Level <= install_level));

            if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
            {
                if (feature->Attributes & msidbFeatureAttributesFavorSource)
                {
                    feature->ActionRequest = INSTALLSTATE_SOURCE;
                    feature->Action = INSTALLSTATE_SOURCE;
                }
                else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
                {
                    feature->ActionRequest = INSTALLSTATE_ADVERTISED;
                    feature->Action = INSTALLSTATE_ADVERTISED;
                }
                else
                {
                    feature->ActionRequest = INSTALLSTATE_LOCAL;
                    feature->Action = INSTALLSTATE_LOCAL;
                }
            }
        }
    }
    else
    {
        /* set the Preselected Property */
        static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
        static const WCHAR szOne[] = { '1', 0 };

        MSI_SetPropertyW(package,szPreselected,szOne);
    }

    /*
     * now we want to enable or disable components base on feature 
    */

    LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
    {
        ComponentList *cl;

        TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
            debugstr_w(feature->Feature), feature->Installed, feature->Action,
            feature->ActionRequest);

        LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
        {
            component = cl->component;

            if (!component->Enabled)
            {
                component->Action = INSTALLSTATE_UNKNOWN;
                component->ActionRequest = INSTALLSTATE_UNKNOWN;
            }
            else
            {
                if (feature->Action == INSTALLSTATE_LOCAL)
                {
                    component->Action = INSTALLSTATE_LOCAL;
                    component->ActionRequest = INSTALLSTATE_LOCAL;
                }
                else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
                {
                    if ((component->Action == INSTALLSTATE_UNKNOWN) ||
                        (component->Action == INSTALLSTATE_ABSENT) ||
                        (component->Action == INSTALLSTATE_ADVERTISED))
                           
                    {
                        component->Action = INSTALLSTATE_SOURCE;
                        component->ActionRequest = INSTALLSTATE_SOURCE;
                    }
                }
                else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
                {
                    if ((component->Action == INSTALLSTATE_UNKNOWN) ||
                        (component->Action == INSTALLSTATE_ABSENT))
                           
                    {
                        component->Action = INSTALLSTATE_ADVERTISED;
                        component->ActionRequest = INSTALLSTATE_ADVERTISED;
                    }
                }
                else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
                {
                    if (component->Action == INSTALLSTATE_UNKNOWN)
                    {
                        component->Action = INSTALLSTATE_ABSENT;
                        component->ActionRequest = INSTALLSTATE_ABSENT;
                    }
                }
            }
        }
    } 

    LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
    {
        TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
            debugstr_w(component->Component), component->Installed, 
            component->Action, component->ActionRequest);
    }


    return ERROR_SUCCESS;
}

static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
{
    MSIPACKAGE *package = (MSIPACKAGE*)param;
    LPCWSTR name;
    LPWSTR path;

    name = MSI_RecordGetString(row,1);

    /* This helper function now does ALL the work */
    TRACE("Dir %s ...\n",debugstr_w(name));
    load_folder(package,name);
    path = resolve_folder(package,name,FALSE,TRUE,NULL);
    TRACE("resolves to %s\n",debugstr_w(path));
    msi_free(path);

    return ERROR_SUCCESS;
}

static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
{
    MSIPACKAGE *package = (MSIPACKAGE*)param;
    LPCWSTR name;
    MSIFEATURE *feature;

    name = MSI_RecordGetString( row, 1 );

    feature = get_loaded_feature( package, name );
    if (!feature)
        ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
    else
    {
        LPCWSTR Condition;
        Condition = MSI_RecordGetString(row,3);

        if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
        {
            int level = MSI_RecordGetInteger(row,2);
            TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
            feature->Level = level;
        }
    }
    return ERROR_SUCCESS;
}


/* 
 * A lot is done in this function aside from just the costing.
 * The costing needs to be implemented at some point but for now I am going
 * to focus on the directory building
 *
 */
static UINT ACTION_CostFinalize(MSIPACKAGE *package)
{
    static const WCHAR ExecSeqQuery[] =
        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
         '`','D','i','r','e','c','t','o','r','y','`',0};
    static const WCHAR ConditionQuery[] =
        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
         '`','C','o','n','d','i','t','i','o','n','`',0};
    static const WCHAR szCosting[] =
        {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
    static const WCHAR szlevel[] =
        {'I','N','S','T','A','L','L','L','E','V','E','L',0};
    static const WCHAR szOne[] = { '1', 0 };
    MSICOMPONENT *comp;
    MSIFILE *file;
    UINT rc;
    MSIQUERY * view;
    LPWSTR level;

    if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
        return ERROR_SUCCESS;
    
    TRACE("Building Directory properties\n");

    rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
    if (rc == ERROR_SUCCESS)
    {
        rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
                        package);
        msiobj_release(&view->hdr);
    }

    TRACE("File calculations\n");

    LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
    {
        MSICOMPONENT* comp = file->Component;
        LPWSTR p;

        if (!comp)
            continue;

        /* calculate target */
        p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);

        msi_free(file->TargetPath);

        TRACE("file %s is named %s\n",
               debugstr_w(file->File),debugstr_w(file->FileName));       

        file->TargetPath = build_directory_name(2, p, file->FileName);

        msi_free(p);

        TRACE("file %s resolves to %s\n",
               debugstr_w(file->File),debugstr_w(file->TargetPath));       

        if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
        {
            file->state = msifs_missing;
            comp->Cost += file->FileSize;
            continue;
        }

        if (file->Version)
        {
            DWORD handle;
            DWORD versize;
            UINT sz;
            LPVOID version;
            static WCHAR name[] = {'\\',0};
            static const WCHAR name_fmt[] = 
                {'%','u','.','%','u','.','%','u','.','%','u',0};
            WCHAR filever[0x100];
            VS_FIXEDFILEINFO *lpVer;

            TRACE("Version comparison..\n");
            versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
            version = msi_alloc(versize);
            GetFileVersionInfoW(file->TargetPath, 0, versize, version);

            VerQueryValueW(version, (LPWSTR)name, (LPVOID*)&lpVer, &sz);

            sprintfW(filever,name_fmt,
                HIWORD(lpVer->dwFileVersionMS),
                LOWORD(lpVer->dwFileVersionMS),
                HIWORD(lpVer->dwFileVersionLS),
                LOWORD(lpVer->dwFileVersionLS));

            TRACE("new %s old %s\n", debugstr_w(file->Version),
                  debugstr_w(filever));
            if (strcmpiW(filever,file->Version)<0)
            {
                file->state = msifs_overwrite;
                /* FIXME: cost should be diff in size */
                comp->Cost += file->FileSize;
            }
            else
                file->state = msifs_present;
            msi_free(version);
        }
        else
            file->state = msifs_present;
    }

    TRACE("Evaluating Condition Table\n");

    rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
    if (rc == ERROR_SUCCESS)
    {
        rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
                    package);
        msiobj_release(&view->hdr);
    }

    TRACE("Enabling or Disabling Components\n");
    LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
    {
        if (comp->Condition)
        {
            if (MSI_EvaluateConditionW(package,
                comp->Condition) == MSICONDITION_FALSE)
            {
                TRACE("Disabling component %s\n", debugstr_w(comp->Component));
                comp->Enabled = FALSE;
            }
        }
    }

    MSI_SetPropertyW(package,szCosting,szOne);
    /* set default run level if not set */
    level = msi_dup_property( package, szlevel );
    if (!level)
        MSI_SetPropertyW(package,szlevel, szOne);
    msi_free(level);

    ACTION_UpdateInstallStates(package);

    return SetFeatureStates(package);
}

/* OK this value is "interpreted" and then formatted based on the 
   first few characters */
static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, 
                         DWORD *size)
{
    LPSTR data = NULL;
    if (value[0]=='#' && value[1]!='#' && value[1]!='%')
    {
        if (value[1]=='x')
        {
            LPWSTR ptr;
            CHAR byte[5];
            LPWSTR deformated = NULL;
            int count;

            deformat_string(package, &value[2], &deformated);

            /* binary value type */
            ptr = deformated;
            *type = REG_BINARY;
            if (strlenW(ptr)%2)
                *size = (strlenW(ptr)/2)+1;
            else
                *size = strlenW(ptr)/2;

            data = msi_alloc(*size);

            byte[0] = '0'; 
            byte[1] = 'x'; 
            byte[4] = 0; 
            count = 0;
            /* if uneven pad with a zero in front */
            if (strlenW(ptr)%2)
            {
                byte[2]= '0';
                byte[3]= *ptr;
                ptr++;
                data[count] = (BYTE)strtol(byte,NULL,0);
                count ++;
                TRACE("Uneven byte count\n");
            }
            while (*ptr)
            {
                byte[2]= *ptr;
                ptr++;
                byte[3]= *ptr;
                ptr++;
                data[count] = (BYTE)strtol(byte,NULL,0);
                count ++;
            }
            msi_free(deformated);

            TRACE("Data %li bytes(%i)\n",*size,count);
        }
        else
        {
            LPWSTR deformated;
            LPWSTR p;
            DWORD d = 0;
            deformat_string(package, &value[1], &deformated);

            *type=REG_DWORD; 
            *size = sizeof(DWORD);
            data = msi_alloc(*size);
            p = deformated;
            if (*p == '-')
                p++;
            while (*p)
            {
                if ( (*p < '0') || (*p > '9') )
                    break;
                d *= 10;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?