Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2010 Hans Leidekker for CodeWeavers
|
|
|
|
*
|
|
|
|
* A test program for patching MSI products.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define _WIN32_MSI 300
|
|
|
|
#define COBJMACROS
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <msiquery.h>
|
|
|
|
#include <msidefs.h>
|
|
|
|
#include <msi.h>
|
|
|
|
|
|
|
|
#include "wine/test.h"
|
|
|
|
|
|
|
|
static UINT (WINAPI *pMsiApplyPatchA)( LPCSTR, LPCSTR, INSTALLTYPE, LPCSTR );
|
|
|
|
static UINT (WINAPI *pMsiGetPatchInfoExA)( LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT,
|
|
|
|
LPCSTR, LPSTR, DWORD * );
|
|
|
|
static UINT (WINAPI *pMsiEnumPatchesExA)( LPCSTR, LPCSTR, DWORD, DWORD, DWORD, LPSTR,
|
|
|
|
LPSTR, MSIINSTALLCONTEXT *, LPSTR, LPDWORD );
|
|
|
|
|
|
|
|
static const char *msifile = "winetest-patch.msi";
|
|
|
|
static const char *mspfile = "winetest-patch.msp";
|
|
|
|
|
|
|
|
static char CURR_DIR[MAX_PATH];
|
|
|
|
static char PROG_FILES_DIR[MAX_PATH];
|
|
|
|
static char COMMON_FILES_DIR[MAX_PATH];
|
|
|
|
|
|
|
|
/* msi database data */
|
|
|
|
|
|
|
|
static const char property_dat[] =
|
|
|
|
"Property\tValue\n"
|
|
|
|
"s72\tl0\n"
|
|
|
|
"Property\tProperty\n"
|
|
|
|
"Manufacturer\tWineHQ\n"
|
|
|
|
"ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
|
|
|
|
"UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
|
|
|
|
"ProductLanguage\t1033\n"
|
|
|
|
"ProductName\tmsitest\n"
|
|
|
|
"ProductVersion\t1.1.1\n"
|
|
|
|
"PATCHNEWSUMMARYSUBJECT\tInstaller Database\n";
|
|
|
|
|
|
|
|
static const char media_dat[] =
|
|
|
|
"DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
|
|
|
|
"i2\ti4\tL64\tS255\tS32\tS72\n"
|
|
|
|
"Media\tDiskId\n"
|
|
|
|
"1\t1\t\t\tDISK1\t\n";
|
|
|
|
|
|
|
|
static const char file_dat[] =
|
|
|
|
"File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
|
|
|
|
"s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
|
|
|
|
"File\tFile\n"
|
|
|
|
"patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
|
|
|
|
|
|
|
|
static const char directory_dat[] =
|
|
|
|
"Directory\tDirectory_Parent\tDefaultDir\n"
|
|
|
|
"s72\tS72\tl255\n"
|
|
|
|
"Directory\tDirectory\n"
|
|
|
|
"MSITESTDIR\tProgramFilesFolder\tmsitest\n"
|
|
|
|
"ProgramFilesFolder\tTARGETDIR\t.\n"
|
|
|
|
"TARGETDIR\t\tSourceDir";
|
|
|
|
|
|
|
|
static const char component_dat[] =
|
|
|
|
"Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
|
|
|
|
"s72\tS38\ts72\ti2\tS255\tS72\n"
|
|
|
|
"Component\tComponent\n"
|
|
|
|
"patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n";
|
|
|
|
|
|
|
|
static const char feature_dat[] =
|
|
|
|
"Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
|
|
|
|
"s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
|
|
|
|
"Feature\tFeature\n"
|
|
|
|
"patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n";
|
|
|
|
|
|
|
|
static const char feature_comp_dat[] =
|
|
|
|
"Feature_\tComponent_\n"
|
|
|
|
"s38\ts72\n"
|
|
|
|
"FeatureComponents\tFeature_\tComponent_\n"
|
|
|
|
"patch\tpatch\n";
|
|
|
|
|
|
|
|
static const char install_exec_seq_dat[] =
|
|
|
|
"Action\tCondition\tSequence\n"
|
|
|
|
"s72\tS255\tI2\n"
|
|
|
|
"InstallExecuteSequence\tAction\n"
|
|
|
|
"LaunchConditions\t\t100\n"
|
|
|
|
"CostInitialize\t\t800\n"
|
|
|
|
"FileCost\t\t900\n"
|
|
|
|
"CostFinalize\t\t1000\n"
|
|
|
|
"InstallValidate\t\t1400\n"
|
|
|
|
"InstallInitialize\t\t1500\n"
|
|
|
|
"ProcessComponents\t\t1600\n"
|
|
|
|
"RemoveFiles\t\t1700\n"
|
|
|
|
"InstallFiles\t\t2000\n"
|
|
|
|
"RegisterUser\t\t3000\n"
|
|
|
|
"RegisterProduct\t\t3100\n"
|
|
|
|
"PublishFeatures\t\t5100\n"
|
|
|
|
"PublishProduct\t\t5200\n"
|
|
|
|
"InstallFinalize\t\t6000\n";
|
|
|
|
|
|
|
|
struct msi_table
|
|
|
|
{
|
|
|
|
const char *filename;
|
|
|
|
const char *data;
|
|
|
|
int size;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
|
|
|
|
|
|
|
|
static const struct msi_table tables[] =
|
|
|
|
{
|
|
|
|
ADD_TABLE( directory ),
|
|
|
|
ADD_TABLE( file ),
|
|
|
|
ADD_TABLE( component ),
|
|
|
|
ADD_TABLE( feature ),
|
|
|
|
ADD_TABLE( feature_comp ),
|
|
|
|
ADD_TABLE( property ),
|
|
|
|
ADD_TABLE( install_exec_seq ),
|
|
|
|
ADD_TABLE( media )
|
|
|
|
};
|
|
|
|
|
|
|
|
static void init_function_pointers( void )
|
|
|
|
{
|
|
|
|
HMODULE hmsi = GetModuleHandleA( "msi.dll" );
|
|
|
|
|
|
|
|
#define GET_PROC( mod, func ) \
|
|
|
|
p ## func = (void *)GetProcAddress( mod, #func ); \
|
|
|
|
if (!p ## func) \
|
|
|
|
trace( "GetProcAddress(%s) failed\n", #func );
|
|
|
|
|
|
|
|
GET_PROC( hmsi, MsiApplyPatchA );
|
|
|
|
GET_PROC( hmsi, MsiGetPatchInfoExA );
|
|
|
|
GET_PROC( hmsi, MsiEnumPatchesExA );
|
|
|
|
#undef GET_PROC
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL get_program_files_dir( char *buf, char *buf2 )
|
|
|
|
{
|
|
|
|
HKEY hkey;
|
|
|
|
DWORD type, size;
|
|
|
|
|
|
|
|
if (RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
size = MAX_PATH;
|
Sync advapi32, gdi32, gdiplus, inetmib1, kernel32, mlang, msi, msvcrt, ntdll, oleaut32, rpcrt4, secur32, setupapi, shdocvw, shlwapi, snmpapi, twain_32, urlmon, user32, userenv, usp10, winhttp, wininet, wintrust, ws2_32 winetests to Wine 1.2rc6
svn path=/trunk/; revision=47939
2010-07-04 19:08:47 +00:00
|
|
|
if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) &&
|
|
|
|
RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
|
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
|
|
|
{
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
size = MAX_PATH;
|
|
|
|
if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
|
|
|
|
{
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void create_file_data( const char *filename, const char *data, DWORD size )
|
|
|
|
{
|
|
|
|
HANDLE file;
|
|
|
|
DWORD written;
|
|
|
|
|
|
|
|
file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
|
|
|
|
if (file == INVALID_HANDLE_VALUE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
WriteFile( file, data, strlen( data ), &written, NULL );
|
|
|
|
if (size)
|
|
|
|
{
|
|
|
|
SetFilePointer( file, size, NULL, FILE_BEGIN );
|
|
|
|
SetEndOfFile( file );
|
|
|
|
}
|
|
|
|
CloseHandle( file );
|
|
|
|
}
|
|
|
|
|
|
|
|
#define create_file( name, size ) create_file_data( name, name, size )
|
|
|
|
|
|
|
|
static BOOL delete_pf( const char *rel_path, BOOL is_file )
|
|
|
|
{
|
|
|
|
char path[MAX_PATH];
|
|
|
|
|
|
|
|
strcpy( path, PROG_FILES_DIR );
|
|
|
|
strcat( path, "\\" );
|
|
|
|
strcat( path, rel_path );
|
|
|
|
|
|
|
|
if (is_file)
|
|
|
|
return DeleteFileA( path );
|
|
|
|
else
|
|
|
|
return RemoveDirectoryA( path );
|
|
|
|
}
|
|
|
|
|
|
|
|
static DWORD get_pf_file_size( const char *filename )
|
|
|
|
{
|
|
|
|
char path[MAX_PATH];
|
|
|
|
HANDLE file;
|
|
|
|
DWORD size;
|
|
|
|
|
|
|
|
strcpy( path, PROG_FILES_DIR );
|
|
|
|
strcat( path, "\\");
|
|
|
|
strcat( path, filename );
|
|
|
|
|
|
|
|
file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
|
|
|
|
if (file == INVALID_HANDLE_VALUE)
|
|
|
|
return INVALID_FILE_SIZE;
|
|
|
|
|
|
|
|
size = GetFileSize( file, NULL );
|
|
|
|
CloseHandle( file );
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void write_file( const char *filename, const char *data, DWORD data_size )
|
|
|
|
{
|
|
|
|
DWORD size;
|
|
|
|
HANDLE file = CreateFile( filename, GENERIC_WRITE, 0, NULL,
|
|
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
|
|
|
|
WriteFile( file, data, data_size, &size, NULL );
|
|
|
|
CloseHandle( file );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_suminfo( const char *filename )
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
MSIHANDLE hsi, hdb;
|
|
|
|
|
|
|
|
r = MsiOpenDatabaseA( filename, MSIDBOPEN_DIRECT, &hdb );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
|
|
|
|
|
|
|
|
r = MsiGetSummaryInformation( hdb, NULL, 7, &hsi );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
|
|
|
|
|
|
|
|
r = MsiSummaryInfoSetProperty( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
|
|
|
|
|
|
|
|
r = MsiSummaryInfoSetProperty( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
|
|
|
|
|
|
|
|
r = MsiSummaryInfoSetProperty( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
|
|
|
|
|
|
|
|
r = MsiSummaryInfoSetProperty( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
|
|
|
|
|
|
|
|
r = MsiSummaryInfoSetProperty( hsi, 9, VT_LPSTR, 0, NULL, "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
|
|
|
|
|
|
|
|
r = MsiSummaryInfoSetProperty( hsi, 14, VT_I4, 100, NULL, NULL );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
|
|
|
|
|
|
|
|
r = MsiSummaryInfoSetProperty( hsi, 15, VT_I4, 0, NULL, NULL );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
|
|
|
|
|
|
|
|
r = MsiSummaryInfoPersist( hsi );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
|
|
|
|
|
|
|
|
r = MsiCloseHandle( hsi );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
|
|
|
|
|
|
|
|
r = MsiCloseHandle( hdb );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
|
|
|
|
{
|
|
|
|
MSIHANDLE hdb;
|
|
|
|
UINT r, i;
|
|
|
|
|
|
|
|
r = MsiOpenDatabaseA( filename, MSIDBOPEN_CREATE, &hdb );
|
|
|
|
ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
|
|
|
|
|
|
|
|
/* import the tables into the database */
|
|
|
|
for (i = 0; i < num_tables; i++)
|
|
|
|
{
|
|
|
|
const struct msi_table *table = &tables[i];
|
|
|
|
|
|
|
|
write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
|
|
|
|
|
|
|
|
r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
|
|
|
|
ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
|
|
|
|
|
|
|
|
DeleteFileA( table->filename );
|
|
|
|
}
|
|
|
|
|
|
|
|
r = MsiDatabaseCommit( hdb );
|
|
|
|
ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
|
|
|
|
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
set_suminfo( filename );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* data for generating a patch */
|
|
|
|
|
|
|
|
/* table names - encoded as in an msi database file */
|
|
|
|
static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
|
|
|
|
static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
|
|
|
|
static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
|
|
|
|
static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
|
|
|
|
static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
|
|
|
|
static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
|
|
|
|
static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
|
|
|
|
0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
|
|
|
|
0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
|
|
|
|
/* substorage names */
|
|
|
|
static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
|
|
|
|
0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
|
|
|
|
static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
|
|
|
|
0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
|
|
|
|
|
|
|
|
/* data in each table */
|
|
|
|
static const WCHAR p_data0[] = { /* _Columns */
|
|
|
|
0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
|
|
|
|
0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
|
|
|
|
};
|
|
|
|
static const WCHAR p_data1[] = { /* _Tables */
|
|
|
|
0x0001
|
|
|
|
};
|
|
|
|
static const char p_data2[] = { /* _StringData */
|
|
|
|
"MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
|
|
|
|
};
|
|
|
|
static const WCHAR p_data3[] = { /* _StringPool */
|
|
|
|
/* len, refs */
|
|
|
|
0, 0, /* string 0 '' */
|
|
|
|
16, 5, /* string 1 'MsiPatchSequence' */
|
|
|
|
11, 1, /* string 2 'PatchFamily' */
|
|
|
|
11, 1, /* string 3 'ProductCode' */
|
|
|
|
8, 1, /* string 4 'Sequence' */
|
|
|
|
10, 1, /* string 5 'Attributes' */
|
|
|
|
15, 1, /* string 6 '1.1.19388.37230' */
|
|
|
|
32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
|
|
|
|
};
|
|
|
|
static const char p_data4[] = { /* CAB_msitest */
|
|
|
|
0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9e,
|
|
|
|
0x03, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x12,
|
|
|
|
0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
|
|
|
|
0x3c, 0xd4, 0x80, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
|
|
|
|
0x74, 0x78, 0x74, 0x00, 0x0b, 0x3c, 0xd6, 0xc1, 0x4a, 0x00, 0xea,
|
|
|
|
0x03, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x10, 0xa1, 0x3e, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x03, 0x00, 0x40, 0x30, 0x0c, 0x43, 0xf8, 0xb4, 0x85,
|
|
|
|
0x4d, 0x96, 0x08, 0x0a, 0x92, 0xf0, 0x52, 0xfb, 0xbb, 0x82, 0xf9,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x31, 0x7d,
|
|
|
|
0x56, 0xdf, 0xf7, 0x48, 0x7c, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x41, 0x80, 0xdf, 0xf7, 0xd8, 0x72, 0xbf, 0xb9, 0x63,
|
|
|
|
0x91, 0x0e, 0x57, 0x1f, 0xfa, 0x1a, 0x66, 0x54, 0x55
|
|
|
|
};
|
|
|
|
static const WCHAR p_data5[] = { /* MsiPatchSequence */
|
|
|
|
0x0007, 0x0000, 0x0006, 0x8000
|
|
|
|
};
|
|
|
|
static const char p_data6[] = { /* SummaryInformation */
|
|
|
|
0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
|
|
|
|
0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
|
|
|
|
0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
|
|
|
|
0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
|
|
|
|
0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
|
|
|
|
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
|
|
|
|
0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
|
|
|
|
0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
|
|
|
|
0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
|
|
|
|
0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
|
|
|
|
0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
|
|
|
|
0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
|
|
|
|
0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
|
|
|
|
0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
|
|
|
|
0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
|
|
|
|
0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
|
|
|
|
0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
|
|
|
|
0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
|
|
|
|
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
|
|
|
|
0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
|
|
|
|
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
|
|
|
|
0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
|
|
|
|
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
|
|
|
|
};
|
|
|
|
|
|
|
|
struct table_data {
|
|
|
|
LPCWSTR name;
|
|
|
|
const void *data;
|
|
|
|
DWORD size;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct table_data table_patch_data[] = {
|
|
|
|
{ p_name0, p_data0, sizeof p_data0 },
|
|
|
|
{ p_name1, p_data1, sizeof p_data1 },
|
|
|
|
{ p_name2, p_data2, sizeof p_data2 - 1 },
|
|
|
|
{ p_name3, p_data3, sizeof p_data3 },
|
|
|
|
{ p_name4, p_data4, sizeof p_data4 },
|
|
|
|
{ p_name5, p_data5, sizeof p_data5 },
|
|
|
|
{ p_name6, p_data6, sizeof p_data6 }
|
|
|
|
};
|
|
|
|
|
|
|
|
#define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
|
|
|
|
|
|
|
|
static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
|
|
|
|
static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
|
|
|
|
static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
|
|
|
|
static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
|
|
|
|
0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
|
|
|
|
0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
|
|
|
|
|
|
|
|
static const WCHAR t1_data0[] = { /* File */
|
|
|
|
0x0008, 0x0001, 0x03ea, 0x8000
|
|
|
|
};
|
|
|
|
static const char t1_data1[] = { /* _StringData */
|
|
|
|
"patch.txt"
|
|
|
|
};
|
|
|
|
static const WCHAR t1_data2[] = { /* _StringPool */
|
|
|
|
/* len, refs */
|
|
|
|
0, 0, /* string 0 '' */
|
|
|
|
9, 1, /* string 1 'patch.txt' */
|
|
|
|
};
|
|
|
|
static const char t1_data3[] = { /* SummaryInformation */
|
|
|
|
0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
|
|
|
|
0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
|
|
|
|
0x30, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
|
|
|
|
0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
|
|
|
|
0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
|
|
|
|
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
|
|
|
|
0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
|
|
|
|
0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
|
|
|
|
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
|
|
|
|
0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
|
|
|
|
0x04, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00,
|
|
|
|
0x00, 0x10, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x1e, 0x00,
|
|
|
|
0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
|
|
|
|
0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
|
|
|
|
0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
|
|
|
|
0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
|
|
|
|
0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
|
|
|
|
0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
|
|
|
0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
|
|
|
|
0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x1e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31,
|
|
|
|
0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06,
|
|
|
|
0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00,
|
|
|
|
0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 0x39, 0x31,
|
|
|
|
0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
|
|
|
|
0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
|
|
|
|
0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
|
|
|
|
0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x39, 0x31,
|
|
|
|
0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
|
|
|
|
0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
|
|
|
|
0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
|
|
|
|
0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x41, 0x32,
|
|
|
|
0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45, 0x32, 0x43,
|
|
|
|
0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30, 0x39, 0x2d,
|
|
|
|
0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35, 0x46, 0x34,
|
|
|
|
0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
|
|
|
|
0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x09
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct table_data table_transform1_data[] = {
|
|
|
|
{ t1_name0, t1_data0, sizeof t1_data0 },
|
|
|
|
{ t1_name1, t1_data1, sizeof t1_data1 - 1 },
|
|
|
|
{ t1_name2, t1_data2, sizeof t1_data2 },
|
|
|
|
{ t1_name3, t1_data3, sizeof t1_data3 }
|
|
|
|
};
|
|
|
|
|
|
|
|
#define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
|
|
|
|
|
|
|
|
static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
|
|
|
|
static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
|
|
|
|
static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
|
|
|
|
static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
|
|
|
|
static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
|
|
|
|
static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
|
|
|
|
static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
|
|
|
|
0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
|
|
|
|
static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
|
|
|
|
static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
|
|
|
|
static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
|
|
|
|
0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
|
|
|
|
0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
|
|
|
|
|
|
|
|
static const WCHAR t2_data0[] = { /* File */
|
|
|
|
0x00c0, 0x0001, 0x9000, 0x83e8
|
|
|
|
};
|
|
|
|
static const WCHAR t2_data1[] = { /* Media */
|
|
|
|
0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
|
|
|
|
};
|
|
|
|
static const WCHAR t2_data2[] = { /* _Columns */
|
|
|
|
0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
|
|
|
|
0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
|
|
|
|
0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
|
|
|
|
0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
|
|
|
|
0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
|
|
|
|
0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
|
|
|
|
0x000e, 0x8900
|
|
|
|
};
|
|
|
|
static const WCHAR t2_data3[] = { /* _Tables */
|
|
|
|
0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
|
|
|
|
};
|
|
|
|
static const WCHAR t2_data4[] = { /* Property */
|
|
|
|
0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
|
|
|
|
};
|
|
|
|
static const WCHAR t2_data5[] = { /* PatchPackage */
|
|
|
|
0x0201, 0x0013, 0x8002
|
|
|
|
};
|
|
|
|
static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
|
|
|
|
0x0301, 0x0006, 0x0000, 0x87d1
|
|
|
|
};
|
|
|
|
static const char t2_data7[] = { /* _StringData */
|
|
|
|
"patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
|
|
|
|
"PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
|
|
|
|
"{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
|
|
|
|
};
|
|
|
|
static const WCHAR t2_data8[] = { /* _StringPool */
|
|
|
|
/* len, refs */
|
|
|
|
0, 0, /* string 0 '' */
|
|
|
|
9, 1, /* string 1 'patch.txt' */
|
|
|
|
22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
|
|
|
|
21, 1, /* string 3 'Installation Database' */
|
|
|
|
19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
|
|
|
|
38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
|
|
|
|
10, 1, /* string 6 'PatchFiles' */
|
|
|
|
12, 1, /* string 7 '#CAB_msitest' */
|
|
|
|
4, 1, /* string 8 'prop' */
|
|
|
|
5, 7, /* string 9 'Patch' */
|
|
|
|
5, 1, /* string 10 'File_' */
|
|
|
|
8, 1, /* string 11 'Sequence' */
|
|
|
|
9, 1, /* string 12 'PatchSize' */
|
|
|
|
10, 1, /* string 13 'Attributes' */
|
|
|
|
6, 2, /* string 14 'Header' */
|
|
|
|
10, 1, /* string 15 'StreamRef_' */
|
|
|
|
12, 3, /* string 16 'PatchPackage' */
|
|
|
|
7, 1, /* string 17 'PatchId' */
|
|
|
|
6, 1, /* string 18 'Media_' */
|
|
|
|
38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
|
|
|
|
15, 3, /* string 20 'MsiPatchHeaders' */
|
|
|
|
9, 1 /* string 21 'StreamRef' */
|
|
|
|
};
|
|
|
|
static const char t2_data9[] = { /* SummaryInformation */
|
|
|
|
0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
|
|
|
|
0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
|
|
|
|
0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
|
|
|
|
0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
|
|
|
|
0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
|
|
|
|
0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
|
|
|
|
0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
|
|
|
|
0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
|
|
|
|
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
|
|
|
|
0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
|
|
|
0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
|
|
|
|
0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
|
|
|
0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
|
|
|
|
0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
|
|
|
|
0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
|
|
|
|
0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
|
|
|
|
0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
|
|
|
|
0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
|
|
|
|
0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
|
|
|
|
0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
|
|
|
|
0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
|
|
|
|
0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
|
|
|
|
0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
|
|
|
|
0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
|
|
|
|
0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
|
|
|
|
0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
|
|
|
|
0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct table_data table_transform2_data[] = {
|
|
|
|
{ t2_name0, t2_data0, sizeof t2_data0 },
|
|
|
|
{ t2_name1, t2_data1, sizeof t2_data1 },
|
|
|
|
{ t2_name2, t2_data2, sizeof t2_data2 },
|
|
|
|
{ t2_name3, t2_data3, sizeof t2_data3 },
|
|
|
|
{ t2_name4, t2_data4, sizeof t2_data4 },
|
|
|
|
{ t2_name5, t2_data5, sizeof t2_data5 },
|
|
|
|
{ t2_name6, t2_data6, sizeof t2_data6 },
|
|
|
|
{ t2_name7, t2_data7, sizeof t2_data7 - 1 },
|
|
|
|
{ t2_name8, t2_data8, sizeof t2_data8 },
|
|
|
|
{ t2_name9, t2_data9, sizeof t2_data9 }
|
|
|
|
};
|
|
|
|
|
|
|
|
#define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
|
|
|
|
|
|
|
|
static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
|
|
|
|
{
|
|
|
|
IStream *stm;
|
|
|
|
DWORD i, count;
|
|
|
|
HRESULT r;
|
|
|
|
|
|
|
|
for (i = 0; i < num_tables; i++)
|
|
|
|
{
|
|
|
|
r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
|
|
|
|
if (FAILED( r ))
|
|
|
|
{
|
|
|
|
ok( 0, "failed to create stream 0x%08x\n", r );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
|
|
|
|
if (FAILED( r ) || count != tables[i].size)
|
|
|
|
ok( 0, "failed to write stream\n" );
|
|
|
|
IStream_Release( stm );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void create_patch( const char *filename )
|
|
|
|
{
|
|
|
|
IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
|
|
|
|
WCHAR *filenameW;
|
|
|
|
HRESULT r;
|
|
|
|
int len;
|
|
|
|
const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
|
|
|
|
|
|
|
|
const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
|
|
|
|
const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
|
|
|
|
|
|
|
|
len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
|
|
|
|
filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
|
|
|
|
MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
|
|
|
|
|
|
|
|
r = StgCreateDocfile( filenameW, mode, 0, &stg );
|
|
|
|
HeapFree( GetProcessHeap(), 0, filenameW );
|
|
|
|
ok( r == S_OK, "failed to create storage 0x%08x\n", r );
|
|
|
|
if (!stg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
r = IStorage_SetClass( stg, &CLSID_MsiPatch );
|
|
|
|
ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
|
|
|
|
|
|
|
|
write_tables( stg, table_patch_data, NUM_PATCH_TABLES );
|
|
|
|
|
|
|
|
r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
|
|
|
|
ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
|
|
|
|
|
|
|
|
r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
|
|
|
|
ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
|
|
|
|
|
|
|
|
write_tables( stg1, table_transform1_data, NUM_TRANSFORM1_TABLES );
|
|
|
|
IStorage_Release( stg1 );
|
|
|
|
|
|
|
|
r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
|
|
|
|
ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
|
|
|
|
|
|
|
|
r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
|
|
|
|
ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
|
|
|
|
|
|
|
|
write_tables( stg2, table_transform2_data, NUM_TRANSFORM2_TABLES );
|
|
|
|
IStorage_Release( stg2 );
|
|
|
|
IStorage_Release( stg );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_simple_patch( void )
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
DWORD size;
|
|
|
|
char path[MAX_PATH], install_source[MAX_PATH];
|
|
|
|
const char *query;
|
|
|
|
MSIHANDLE hpackage, hdb, hview, hrec;
|
|
|
|
|
|
|
|
if (!pMsiApplyPatchA)
|
|
|
|
{
|
|
|
|
win_skip("MsiApplyPatchA is not available\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CreateDirectoryA( "msitest", NULL );
|
|
|
|
create_file( "msitest\\patch.txt", 1000 );
|
|
|
|
|
|
|
|
create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
|
|
|
|
create_patch( mspfile );
|
|
|
|
|
|
|
|
MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
|
|
|
|
|
|
|
|
r = MsiInstallProductA( msifile, NULL );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
size = get_pf_file_size( "msitest\\patch.txt" );
|
|
|
|
ok( size == 1000, "expected 1000, got %u\n", size );
|
|
|
|
|
|
|
|
size = sizeof(install_source);
|
|
|
|
r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
"InstallSource", install_source, &size );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
strcpy( path, CURR_DIR );
|
|
|
|
strcat( path, "\\" );
|
|
|
|
strcat( path, msifile );
|
|
|
|
|
|
|
|
r = MsiOpenPackageA( path, &hpackage );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
hdb = MsiGetActiveDatabase( hpackage );
|
|
|
|
ok( hdb, "failed to get database handle\n" );
|
|
|
|
|
|
|
|
query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
|
|
|
|
r = MsiDatabaseOpenView( hdb, query, &hview );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewExecute( hview, 0 );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewFetch( hview, &hrec );
|
|
|
|
ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
|
|
|
|
|
|
|
|
MsiCloseHandle( hrec );
|
|
|
|
MsiViewClose( hview );
|
|
|
|
MsiCloseHandle( hview );
|
|
|
|
|
|
|
|
query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
|
|
|
|
"AND `Value` = 'Installer Database'";
|
|
|
|
r = MsiDatabaseOpenView( hdb, query, &hview );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewExecute( hview, 0 );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewFetch( hview, &hrec );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
MsiCloseHandle( hrec );
|
|
|
|
MsiViewClose( hview );
|
|
|
|
MsiCloseHandle( hview );
|
|
|
|
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
MsiCloseHandle( hpackage );
|
|
|
|
|
|
|
|
r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
|
|
|
|
ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
|
|
|
|
"expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
if (r == ERROR_PATCH_PACKAGE_INVALID)
|
|
|
|
{
|
|
|
|
win_skip("Windows Installer < 3.0 detected\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = get_pf_file_size( "msitest\\patch.txt" );
|
|
|
|
ok( size == 1002, "expected 1002, got %u\n", size );
|
|
|
|
|
|
|
|
/* show that MsiOpenPackage applies registered patches */
|
|
|
|
r = MsiOpenPackageA( path, &hpackage );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
hdb = MsiGetActiveDatabase( hpackage );
|
|
|
|
ok( hdb, "failed to get database handle\n" );
|
|
|
|
|
|
|
|
query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
|
|
|
|
r = MsiDatabaseOpenView( hdb, query, &hview );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewExecute( hview, 0 );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewFetch( hview, &hrec );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
MsiCloseHandle( hrec );
|
|
|
|
MsiViewClose( hview );
|
|
|
|
MsiCloseHandle( hview );
|
|
|
|
|
|
|
|
query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
|
|
|
|
"AND `Value` = 'Installation Database'";
|
|
|
|
r = MsiDatabaseOpenView( hdb, query, &hview );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewExecute( hview, 0 );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewFetch( hview, &hrec );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
MsiCloseHandle( hrec );
|
|
|
|
MsiViewClose( hview );
|
|
|
|
MsiCloseHandle( hview );
|
|
|
|
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
MsiCloseHandle( hpackage );
|
|
|
|
|
|
|
|
/* show that patches are not committed to the local package database */
|
|
|
|
size = sizeof(path);
|
|
|
|
r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
"LocalPackage", path, &size );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiOpenDatabaseA( path, MSIDBOPEN_READONLY, &hdb );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiDatabaseOpenView( hdb, query, &hview );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewExecute( hview, 0 );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewFetch( hview, &hrec );
|
|
|
|
ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
|
|
|
|
|
|
|
|
MsiCloseHandle( hrec );
|
|
|
|
MsiViewClose( hview );
|
|
|
|
MsiCloseHandle( hview );
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
|
|
|
|
size = sizeof(path);
|
|
|
|
r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
"InstallSource", path, &size );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
|
|
|
|
|
|
|
|
r = MsiInstallProductA( msifile, "REMOVE=ALL" );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
|
|
|
|
ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
|
|
|
|
|
|
|
|
DeleteFileA( msifile );
|
|
|
|
DeleteFileA( mspfile );
|
|
|
|
RemoveDirectoryA( "msitest" );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_MsiOpenDatabase( void )
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
MSIHANDLE hdb;
|
|
|
|
|
|
|
|
r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE, &hdb );
|
|
|
|
ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
|
|
|
|
|
|
|
|
r = MsiDatabaseCommit( hdb );
|
|
|
|
ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
|
|
|
|
r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
|
|
|
|
ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
|
|
|
|
DeleteFileA( mspfile );
|
|
|
|
|
|
|
|
r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
|
|
|
|
ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
|
|
|
|
|
|
|
|
r = MsiDatabaseCommit( hdb );
|
|
|
|
ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
|
|
|
|
r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
|
|
|
|
ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
DeleteFileA( mspfile );
|
|
|
|
|
|
|
|
create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
|
|
|
|
create_patch( mspfile );
|
|
|
|
|
|
|
|
r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
|
|
|
|
ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
|
|
|
|
|
|
|
|
r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
|
|
|
|
ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
|
|
|
|
DeleteFileA( msifile );
|
|
|
|
DeleteFileA( mspfile );
|
|
|
|
}
|
|
|
|
|
|
|
|
static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
|
|
|
|
{
|
|
|
|
static char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
|
|
|
|
char query[0x100];
|
|
|
|
UINT r;
|
|
|
|
MSIHANDLE hview, hrec;
|
|
|
|
|
|
|
|
sprintf( query, fmt, table, entry );
|
|
|
|
r = MsiDatabaseOpenView( hdb, query, &hview );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewExecute( hview, 0 );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewFetch( hview, &hrec );
|
|
|
|
MsiViewClose( hview );
|
|
|
|
MsiCloseHandle( hview );
|
|
|
|
MsiCloseHandle( hrec );
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_system_tables( void )
|
|
|
|
{
|
|
|
|
UINT r;
|
|
|
|
const char *query;
|
|
|
|
MSIHANDLE hproduct, hdb, hview, hrec;
|
|
|
|
|
|
|
|
if (!pMsiApplyPatchA)
|
|
|
|
{
|
|
|
|
win_skip("MsiApplyPatchA is not available\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CreateDirectoryA( "msitest", NULL );
|
|
|
|
create_file( "msitest\\patch.txt", 1000 );
|
|
|
|
|
|
|
|
create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
|
|
|
|
create_patch( mspfile );
|
|
|
|
|
|
|
|
MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
|
|
|
|
|
|
|
|
r = MsiInstallProductA( msifile, NULL );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
hdb = MsiGetActiveDatabase( hproduct );
|
|
|
|
ok( hdb, "failed to get database handle\n" );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
query = "SELECT * FROM `_Storages`";
|
|
|
|
r = MsiDatabaseOpenView( hdb, query, &hview );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewExecute( hview, 0 );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewFetch( hview, &hrec );
|
|
|
|
ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Directory" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "File" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Component" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Feature" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "FeatureComponents" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Property" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Media" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "_Property" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
MsiCloseHandle( hrec );
|
|
|
|
MsiViewClose( hview );
|
|
|
|
MsiCloseHandle( hview );
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
MsiCloseHandle( hproduct );
|
|
|
|
|
|
|
|
r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
|
|
|
|
ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
|
|
|
|
"expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
if (r == ERROR_PATCH_PACKAGE_INVALID)
|
|
|
|
{
|
|
|
|
win_skip("Windows Installer < 3.0 detected\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
hdb = MsiGetActiveDatabase( hproduct );
|
|
|
|
ok( hdb, "failed to get database handle\n" );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
query = "SELECT * FROM `_Storages`";
|
|
|
|
r = MsiDatabaseOpenView( hdb, query, &hview );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewExecute( hview, 0 );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiViewFetch( hview, &hrec );
|
|
|
|
ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Directory" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "File" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Component" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Feature" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "FeatureComponents" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Property" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Media" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "_Property" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "Patch" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
r = find_entry( hdb, "_Tables", "PatchPackage" );
|
|
|
|
ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
|
|
|
|
|
|
|
|
MsiCloseHandle( hrec );
|
|
|
|
MsiViewClose( hview );
|
|
|
|
MsiCloseHandle( hview );
|
|
|
|
MsiCloseHandle( hdb );
|
|
|
|
MsiCloseHandle( hproduct );
|
|
|
|
|
|
|
|
r = MsiInstallProductA( msifile, "REMOVE=ALL" );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
DeleteFileA( msifile );
|
|
|
|
DeleteFileA( mspfile );
|
|
|
|
RemoveDirectoryA( "msitest" );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_patch_registration( void )
|
|
|
|
{
|
|
|
|
UINT r, size;
|
|
|
|
char buffer[MAX_PATH], patch_code[39];
|
|
|
|
|
|
|
|
if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
|
|
|
|
{
|
|
|
|
win_skip("required functions not available\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CreateDirectoryA( "msitest", NULL );
|
|
|
|
create_file( "msitest\\patch.txt", 1000 );
|
|
|
|
|
|
|
|
create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
|
|
|
|
create_patch( mspfile );
|
|
|
|
|
|
|
|
MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
|
|
|
|
|
|
|
|
r = MsiInstallProductA( msifile, NULL );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
|
|
|
|
ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
|
|
|
|
"expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
if (r == ERROR_PATCH_PACKAGE_INVALID)
|
|
|
|
{
|
|
|
|
win_skip("Windows Installer < 3.0 detected\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer[0] = 0;
|
|
|
|
size = sizeof(buffer);
|
|
|
|
r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
|
|
|
|
"{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
|
|
|
|
INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
ok( buffer[0], "buffer empty\n" );
|
|
|
|
|
|
|
|
buffer[0] = 0;
|
|
|
|
size = sizeof(buffer);
|
|
|
|
r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
|
|
|
|
"{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
NULL, MSIINSTALLCONTEXT_MACHINE,
|
|
|
|
INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
|
|
|
|
ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
|
|
|
|
|
|
|
|
buffer[0] = 0;
|
|
|
|
size = sizeof(buffer);
|
|
|
|
r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
|
|
|
|
"{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
NULL, MSIINSTALLCONTEXT_USERMANAGED,
|
|
|
|
INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
ok( !buffer[0], "got %s\n", buffer );
|
|
|
|
|
|
|
|
r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
|
|
|
|
0, patch_code, NULL, NULL, NULL, NULL );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
|
|
|
|
|
|
|
|
r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
|
|
|
|
0, patch_code, NULL, NULL, NULL, NULL );
|
|
|
|
ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
|
|
|
|
|
|
|
|
r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
|
|
|
|
0, patch_code, NULL, NULL, NULL, NULL );
|
|
|
|
ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
|
|
|
|
|
|
|
|
r = MsiInstallProductA( msifile, "REMOVE=ALL" );
|
|
|
|
ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
|
|
|
|
|
|
|
|
buffer[0] = 0;
|
|
|
|
size = sizeof(buffer);
|
|
|
|
r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
|
|
|
|
"{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
|
|
|
|
NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
|
|
|
|
INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
|
|
|
|
ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
|
|
|
|
|
|
|
|
DeleteFileA( msifile );
|
|
|
|
DeleteFileA( mspfile );
|
|
|
|
RemoveDirectoryA( "msitest" );
|
|
|
|
}
|
|
|
|
|
|
|
|
START_TEST(patch)
|
|
|
|
{
|
|
|
|
DWORD len;
|
|
|
|
char temp_path[MAX_PATH], prev_path[MAX_PATH];
|
|
|
|
|
|
|
|
init_function_pointers();
|
|
|
|
|
|
|
|
GetCurrentDirectoryA( MAX_PATH, prev_path );
|
|
|
|
GetTempPath( MAX_PATH, temp_path );
|
|
|
|
SetCurrentDirectoryA( temp_path );
|
|
|
|
|
|
|
|
strcpy( CURR_DIR, temp_path );
|
|
|
|
len = strlen( CURR_DIR );
|
|
|
|
|
|
|
|
if (len && (CURR_DIR[len - 1] == '\\'))
|
|
|
|
CURR_DIR[len - 1] = 0;
|
|
|
|
|
|
|
|
get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
|
|
|
|
|
|
|
|
test_simple_patch();
|
|
|
|
test_MsiOpenDatabase();
|
|
|
|
test_system_tables();
|
|
|
|
test_patch_registration();
|
|
|
|
|
|
|
|
SetCurrentDirectoryA( prev_path );
|
|
|
|
}
|