Exemplo n.º 1
0
UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
{
    LPWSTR wstr = NULL;
    UINT ret;

    TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));

    if( szFilename )
    {
        wstr = strdupAtoW( szFilename );
        if( !wstr )
             return ERROR_OUTOFMEMORY;
    }
    ret = MsiRecordSetStreamW(hRecord, iField, wstr);
    msi_free(wstr);

    return ret;
}
Exemplo n.º 2
0
BOOL WINAPI SetupGetSourceFileLocationA( HINF hinf, PINFCONTEXT context, PCSTR filename,
                                         PUINT source_id, PSTR buffer, DWORD buffer_size,
                                         PDWORD required_size )
{
    BOOL ret = FALSE;
    WCHAR *filenameW = NULL, *bufferW = NULL;
    DWORD required;
    INT size;

    TRACE("%p, %p, %s, %p, %p, 0x%08x, %p\n", hinf, context, debugstr_a(filename), source_id,
          buffer, buffer_size, required_size);

    if (filename && *filename && !(filenameW = strdupAtoW( filename )))
        return FALSE;

    if (!SetupGetSourceFileLocationW( hinf, context, filenameW, source_id, NULL, 0, &required ))
        goto done;

    if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) )))
        goto done;

    if (!SetupGetSourceFileLocationW( hinf, context, filenameW, source_id, bufferW, required, NULL ))
        goto done;

    size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
    if (required_size) *required_size = size;

    if (buffer)
    {
        if (buffer_size >= size)
            WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, buffer_size, NULL, NULL );
        else
        {
            SetLastError( ERROR_INSUFFICIENT_BUFFER );
            goto done;
        }
    }
    ret = TRUE;

 done:
    HeapFree( GetProcessHeap(), 0, filenameW );
    HeapFree( GetProcessHeap(), 0, bufferW );
    return ret;
}
Exemplo n.º 3
0
BOOL WINAPI SetupGetTargetPathA( HINF hinf, PINFCONTEXT context, PCSTR section, PSTR buffer,
                                 DWORD buffer_size, PDWORD required_size )
{
    BOOL ret = FALSE;
    WCHAR *sectionW = NULL, *bufferW = NULL;
    DWORD required;
    INT size;

    TRACE("%p, %p, %s, %p, 0x%08x, %p\n", hinf, context, debugstr_a(section), buffer,
          buffer_size, required_size);

    if (section && !(sectionW = strdupAtoW( section )))
        return FALSE;

    if (!SetupGetTargetPathW( hinf, context, sectionW, NULL, 0, &required ))
        goto done;

    if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) )))
        goto done;

    if (!SetupGetTargetPathW( hinf, context, sectionW, bufferW, required, NULL ))
        goto done;

    size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
    if (required_size) *required_size = size;

    if (buffer)
    {
        if (buffer_size >= size)
            WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, buffer_size, NULL, NULL );
        else
        {
            SetLastError( ERROR_INSUFFICIENT_BUFFER );
            goto done;
        }
    }
    ret = TRUE;

 done:
    HeapFree( GetProcessHeap(), 0, sectionW );
    HeapFree( GetProcessHeap(), 0, bufferW );
    return ret;
}
Exemplo n.º 4
0
UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
                LPSTR szFeature, LPSTR szComponent, LPDWORD pUsed )
{
    WCHAR product[MAX_FEATURE_CHARS+1];
    WCHAR feature[MAX_FEATURE_CHARS+1];
    WCHAR component[MAX_FEATURE_CHARS+1];
    LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
    UINT r;

    TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
          szFeature, szComponent, pUsed);

    str = strdupAtoW( szDescriptor );
    if( szDescriptor && !str )
        return ERROR_OUTOFMEMORY;

    if (szProduct)
        p = product;
    if (szFeature)
        f = feature;
    if (szComponent)
        c = component;

    r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );

    if (r == ERROR_SUCCESS)
    {
        WideCharToMultiByte( CP_ACP, 0, p, -1,
                             szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
        WideCharToMultiByte( CP_ACP, 0, f, -1,
                             szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
        WideCharToMultiByte( CP_ACP, 0, c, -1,
                             szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
    }

    msi_free( str );

    return r;
}
Exemplo n.º 5
0
UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
{
    WCHAR *valueW = NULL;
    MSIRECORD *rec;
    UINT ret;

    TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));

    if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;

    rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
    if( !rec )
    {
        msi_free( valueW );
        return ERROR_INVALID_HANDLE;
    }
    msiobj_lock( &rec->hdr );
    ret = MSI_RecordSetStringW( rec, iField, valueW );
    msiobj_unlock( &rec->hdr );
    msiobj_release( &rec->hdr );
    msi_free( valueW );
    return ret;
}
Exemplo n.º 6
0
static UINT MSI_RecordSetStringA( MSIRECORD *rec, UINT iField, LPCSTR szValue )
{
    LPWSTR str;

    TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue));

    if( iField > rec->count )
        return ERROR_INVALID_FIELD;

    MSI_FreeField( &rec->fields[iField] );
    if( szValue && szValue[0] )
    {
        str = strdupAtoW( szValue );
        rec->fields[iField].type = MSIFIELD_WSTR;
        rec->fields[iField].u.szwVal = str;
    }
    else
    {
        rec->fields[iField].type = MSIFIELD_NULL;
        rec->fields[iField].u.szwVal = NULL;
    }

    return 0;
}
Exemplo n.º 7
0
static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
                                 MetadataItem **items, DWORD *count)
{
#include "pshpack1.h"
    struct logical_screen_descriptor
    {
        char signature[6];
        USHORT width;
        USHORT height;
        BYTE packed;
        /* global_color_table_flag : 1;
         * color_resolution : 3;
         * sort_flag : 1;
         * global_color_table_size : 3;
         */
        BYTE background_color_index;
        BYTE pixel_aspect_ratio;
    } lsd_data;
#include "poppack.h"
    HRESULT hr;
    ULONG bytesread, i;
    MetadataItem *result;

    *items = NULL;
    *count = 0;

    hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread);
    if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK;

    result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 9);
    if (!result) return E_OUTOFMEMORY;

    for (i = 0; i < 9; i++)
    {
        PropVariantInit(&result[i].schema);
        PropVariantInit(&result[i].id);
        PropVariantInit(&result[i].value);
    }

    result[0].id.vt = VT_LPWSTR;
    result[0].id.u.pwszVal = strdupAtoW("Signature");
    result[0].value.vt = VT_UI1|VT_VECTOR;
    result[0].value.u.caub.cElems = sizeof(lsd_data.signature);
    result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data.signature));
    memcpy(result[0].value.u.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature));

    result[1].id.vt = VT_LPWSTR;
    result[1].id.u.pwszVal = strdupAtoW("Width");
    result[1].value.vt = VT_UI2;
    result[1].value.u.uiVal = lsd_data.width;

    result[2].id.vt = VT_LPWSTR;
    result[2].id.u.pwszVal = strdupAtoW("Height");
    result[2].value.vt = VT_UI2;
    result[2].value.u.uiVal = lsd_data.height;

    result[3].id.vt = VT_LPWSTR;
    result[3].id.u.pwszVal = strdupAtoW("GlobalColorTableFlag");
    result[3].value.vt = VT_BOOL;
    result[3].value.u.boolVal = (lsd_data.packed >> 7) & 1;

    result[4].id.vt = VT_LPWSTR;
    result[4].id.u.pwszVal = strdupAtoW("ColorResolution");
    result[4].value.vt = VT_UI1;
    result[4].value.u.bVal = (lsd_data.packed >> 4) & 7;

    result[5].id.vt = VT_LPWSTR;
    result[5].id.u.pwszVal = strdupAtoW("SortFlag");
    result[5].value.vt = VT_BOOL;
    result[5].value.u.boolVal = (lsd_data.packed >> 3) & 1;

    result[6].id.vt = VT_LPWSTR;
    result[6].id.u.pwszVal = strdupAtoW("GlobalColorTableSize");
    result[6].value.vt = VT_UI1;
    result[6].value.u.bVal = lsd_data.packed & 7;

    result[7].id.vt = VT_LPWSTR;
    result[7].id.u.pwszVal = strdupAtoW("BackgroundColorIndex");
    result[7].value.vt = VT_UI1;
    result[7].value.u.bVal = lsd_data.background_color_index;

    result[8].id.vt = VT_LPWSTR;
    result[8].id.u.pwszVal = strdupAtoW("PixelAspectRatio");
    result[8].value.vt = VT_UI1;
    result[8].value.u.bVal = lsd_data.pixel_aspect_ratio;

    *items = result;
    *count = 9;

    return S_OK;
}
Exemplo n.º 8
0
Arquivo: msidb.c Projeto: CaoMomo/core
/***********************************************************************
 * msidbImportTables
 *
 * Takes a list of tables or '*' (for all) to import from text archive
 * files in specified folder
 *
 * For each table, a file called <tablename>.idt is imported containing
 * tab separated ASCII.
 *
 * Examples (note wildcard escape for *nix/bash):
 * msidb -d <pathtomsi>.msi -f <workdir> -i \*
 * msidb -d <pathtomsi>.msi -f <workdir> -i File Directory Binary
 **********************************************************************/
static BOOL msidbImportTables(LPCWSTR dbfile, LPCWSTR wdir, LPWSTR tables[], BOOL create)
{
    static const WCHAR ext[] = {'.', 'i', 'd', 't', 0};
    static const WCHAR all[] = {'*', 0};

    UINT r, len;
    char *dirNameA;
    char *fileName;
    DIR *dir;
    struct dirent *ent;

    int i = 0;
    MSIHANDLE dbhandle;

    LPWSTR tableFile = 0;
    LPCWSTR oFlag = (LPCWSTR) MSIDBOPEN_TRANSACT;

    if (create == TRUE) oFlag = (LPCWSTR) MSIDBOPEN_CREATE;
    r = MsiOpenDatabaseW(dbfile, oFlag, &dbhandle);

    if (r != ERROR_SUCCESS)
    {
        return FALSE;
    }

    if (strcmpW(tables[0], all) == 0)
    {
        dirNameA = strdupWtoA(CP_ACP, wdir);
        dir = opendir(dirNameA);

        if (dir)
        {
            while ((ent = readdir(dir)) != NULL)
            {
                if (ent->d_type != DT_REG) continue;
                fileName = ent->d_name;
                if (strcmp(fileName+strlen(fileName)-4*sizeof(fileName[0]), ".idt") != 0) continue;
                if (strcmp(fileName, ".") == 0 || strcmp(fileName, "..") == 0) continue;
                tableFile = strdupAtoW(CP_ACP, fileName);
                r = MsiDatabaseImportW(dbhandle, wdir, tableFile);
                free(tableFile);
            }
        }
        else
            return FALSE;
        closedir(dir);
        free(dirNameA);
    }
    else
    {
        for (i = 0; i < MAX_TABLES && tables[i] != 0; ++i)
        {
            len = lstrlenW(tables[i]) + 5;
            tableFile = malloc(len * sizeof (WCHAR));
            if (tableFile == NULL) return FALSE;

            lstrcpyW(tableFile, tables[i]);
            lstrcatW(tableFile, ext);
            r = MsiDatabaseImportW(dbhandle, wdir, tableFile);
            free(tableFile);

            if (r != ERROR_SUCCESS)
            {
                return FALSE;
            }
        }
    }

    MsiDatabaseCommit(dbhandle);
    MsiCloseHandle(dbhandle);
    return TRUE;
}
Exemplo n.º 9
0
/*
 * Code based off of code located here
 * http://www.codeproject.com/gdi/fontnamefromfile.asp
 */
WCHAR *load_ttf_name_id( const WCHAR *filename, DWORD id )
{
    TT_TABLE_DIRECTORY tblDir;
    BOOL bFound = FALSE;
    TT_OFFSET_TABLE ttOffsetTable;
    TT_NAME_TABLE_HEADER ttNTHeader;
    TT_NAME_RECORD ttRecord;
    DWORD dwRead;
    HANDLE handle;
    LPWSTR ret = NULL;
    int i;

    handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL, 0 );
    if (handle == INVALID_HANDLE_VALUE)
    {
        ERR("Unable to open font file %s\n", debugstr_w(filename));
        return NULL;
    }

    if (!ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL))
        goto end;

    ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
    ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
    ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);

    if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0)
        goto end;

    for (i=0; i< ttOffsetTable.uNumOfTables; i++)
    {
        if (!ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL))
            break;
        if (memcmp(tblDir.szTag,"name",4)==0)
        {
            bFound = TRUE;
            tblDir.uLength = SWAPLONG(tblDir.uLength);
            tblDir.uOffset = SWAPLONG(tblDir.uOffset);
            break;
        }
    }

    if (!bFound)
        goto end;

    SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
    if (!ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER), &dwRead,NULL))
        goto end;

    ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
    ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
    bFound = FALSE;
    for(i=0; i<ttNTHeader.uNRCount; i++)
    {
        if (!ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL))
            break;

        ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
        if (ttRecord.uNameID == id)
        {
            int nPos;
            LPSTR buf;

            ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
            ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
            nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
            SetFilePointer(handle, tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset,
                           NULL, FILE_BEGIN);
            buf = msi_alloc_zero( ttRecord.uStringLength + 1 );
            ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL);
            if (strlen(buf) > 0)
            {
                ret = strdupAtoW(buf);
                msi_free(buf);
                break;
            }
            msi_free(buf);
            SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
        }
    }

end:
    CloseHandle(handle);
    TRACE("Returning %s\n", debugstr_w(ret));
    return ret;
}
Exemplo n.º 10
0
static INT_PTR CDECL extract_notify( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin )
{
    WCHAR *file, *nameW, *path = NULL;
    INT_PTR ret;

    switch (fdint)
    {
    case fdintCABINET_INFO:
        return 0;

    case fdintCOPY_FILE:
        nameW = strdupAtoW( (pfdin->attribs & _A_NAME_IS_UTF) ? CP_UTF8 : CP_ACP, pfdin->psz1 );
        if (opt_preserve_paths)
        {
            file = nameW;
            while (*file == '\\') file++;  /* remove leading backslashes */
        }
        else
        {
            if ((file = strrchrW( nameW, '\\' ))) file++;
            else file = nameW;
        }

        if (opt_dest_dir)
        {
            path = cab_alloc( (strlenW(opt_dest_dir) + strlenW(file) + 1) * sizeof(WCHAR) );
            strcpyW( path, opt_dest_dir );
            strcatW( path, file );
        }
        else path = file;

        if (match_files( file ))
        {
            if (opt_verbose)
            {
                char *nameU = strdupWtoA( CP_UNIXCP, path );
                printf( "extracting %s\n", nameU );
                cab_free( nameU );
            }
            create_directories( path );
            /* FIXME: check for existing file and overwrite mode */
            ret = (INT_PTR)CreateFileW( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
                                        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
        }
        else ret = 0;

        cab_free( nameW );
        if (path != file) cab_free( path );
        return ret;

    case fdintCLOSE_FILE_INFO:
        CloseHandle( (HANDLE)pfdin->hf );
        return 0;

    case fdintNEXT_CABINET:
        WINE_TRACE("Next cab: status %u, path '%s', file '%s'\n", pfdin->fdie, pfdin->psz3, pfdin->psz1);
        return pfdin->fdie == FDIERROR_NONE ? 0 : -1;

    case fdintENUMERATE:
        return 0;

    default:
        WINE_FIXME( "Unexpected notification type %d.\n", fdint );
        return 0;
    }
}
Exemplo n.º 11
0
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{
    TRACE("(%d)\n", fdint);

    switch (fdint)
    {
    case fdintPARTIAL_FILE:
    {
        CabData *data = (CabData *)pfdin->pv;
        data->mi->is_continuous = FALSE;
        return 0;
    }
    case fdintNEXT_CABINET:
    {
        CabData *data = (CabData *)pfdin->pv;
        struct media_info *mi = data->mi;
        LPWSTR cab = strdupAtoW(pfdin->psz1);
        UINT rc;

        msi_free(mi->disk_prompt);
        msi_free(mi->cabinet);
        msi_free(mi->volume_label);
        mi->disk_prompt = NULL;
        mi->cabinet = NULL;
        mi->volume_label = NULL;

        mi->disk_id++;
        mi->is_continuous = TRUE;

        rc = msi_media_get_disk_info(data->package, mi);
        if (rc != ERROR_SUCCESS)
        {
            msi_free(cab);
            ERR("Failed to get next cabinet information: %d\n", rc);
            return -1;
        }

        if (lstrcmpiW(mi->cabinet, cab))
        {
            msi_free(cab);
            ERR("Continuous cabinet does not match the next cabinet in the Media table\n");
            return -1;
        }

        msi_free(cab);

        TRACE("Searching for %s\n", debugstr_w(mi->source));

        if (GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES)
            rc = msi_change_media(data->package, mi);

        if (rc != ERROR_SUCCESS)
            return -1;

        return 0;
    }
    case fdintCOPY_FILE:
    {
        CabData *data = (CabData*) pfdin->pv;
        HANDLE handle;
        LPWSTR file;
        MSIFILE *f;
        DWORD attrs;

        file = strdupAtoW(pfdin->psz1);
        f = get_loaded_file(data->package, file);
        msi_free(file);

        if (!f)
        {
            WARN("unknown file in cabinet (%s)\n",debugstr_a(pfdin->psz1));
            return 0;
        }

        if (f->state != msifs_missing && f->state != msifs_overwrite)
        {
            TRACE("Skipping extraction of %s\n",debugstr_a(pfdin->psz1));
            return 0;
        }

        msi_file_update_ui( data->package, f, szInstallFiles );

        TRACE("extracting %s\n", debugstr_w(f->TargetPath) );

        attrs = f->Attributes & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
        if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;

        handle = CreateFileW( f->TargetPath, GENERIC_READ | GENERIC_WRITE, 0,
                              NULL, CREATE_ALWAYS, attrs, NULL );
        if ( handle == INVALID_HANDLE_VALUE )
        {
            if ( GetFileAttributesW( f->TargetPath ) != INVALID_FILE_ATTRIBUTES )
                f->state = msifs_installed;
            else
                ERR("failed to create %s (error %d)\n",
                    debugstr_w( f->TargetPath ), GetLastError() );

            return 0;
        }

        f->state = msifs_installed;
        return (INT_PTR) handle;
    }
    case fdintCLOSE_FILE_INFO:
    {
        CabData *data = (CabData*) pfdin->pv;
        FILETIME ft;
        FILETIME ftLocal;
        HANDLE handle = (HANDLE) pfdin->hf;

        data->mi->is_continuous = FALSE;

        if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
            return -1;
        if (!LocalFileTimeToFileTime(&ft, &ftLocal))
            return -1;
        if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
            return -1;
        CloseHandle(handle);
        return 1;
    }
    default:
        return 0;
    }
}
Exemplo n.º 12
0
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
{
    switch (fdint)
    {
    case fdintCOPY_FILE:
    {
        CabData *data = (CabData*) pfdin->pv;
        HANDLE handle;
        LPWSTR file;
        MSIFILE *f;
        DWORD attrs;

        file = strdupAtoW(pfdin->psz1);
        f = get_loaded_file(data->package, file);
        msi_free(file);

        if (!f)
        {
            WARN("unknown file in cabinet (%s)\n",debugstr_a(pfdin->psz1));
            return 0;
        }

        if (f->state != msifs_missing && f->state != msifs_overwrite)
        {
            TRACE("Skipping extraction of %s\n",debugstr_a(pfdin->psz1));
            return 0;
        }

        msi_file_update_ui( data->package, f, szInstallFiles );

        TRACE("extracting %s\n", debugstr_w(f->TargetPath) );

        attrs = f->Attributes & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM);
        if (!attrs) attrs = FILE_ATTRIBUTE_NORMAL;

        handle = CreateFileW( f->TargetPath, GENERIC_READ | GENERIC_WRITE, 0,
                              NULL, CREATE_ALWAYS, attrs, NULL );
        if ( handle == INVALID_HANDLE_VALUE )
        {
            ERR("failed to create %s (error %ld)\n",
                debugstr_w( f->TargetPath ), GetLastError() );
            return 0;
        }

        f->state = msifs_installed;
        return (INT_PTR) handle;
    }
    case fdintCLOSE_FILE_INFO:
    {
        FILETIME ft;
        FILETIME ftLocal;
        HANDLE handle = (HANDLE) pfdin->hf;

        if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
            return -1;
        if (!LocalFileTimeToFileTime(&ft, &ftLocal))
            return -1;
        if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
            return -1;
        CloseHandle(handle);
        return 1;
    }
    default:
        return 0;
    }
}