msi/tests: Skip patch tests if product installation failed.
[wine/hacks.git] / dlls / msi / tests / patch.c
blob6b4faf1cb781052160cf26f48e2e59decf21c481
1 /*
2 * Copyright 2010 Hans Leidekker for CodeWeavers
4 * A test program for patching MSI products.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define _WIN32_MSI 300
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <windows.h>
27 #include <msiquery.h>
28 #include <msidefs.h>
29 #include <msi.h>
31 #include "wine/test.h"
33 static UINT (WINAPI *pMsiApplyPatchA)( LPCSTR, LPCSTR, INSTALLTYPE, LPCSTR );
34 static UINT (WINAPI *pMsiGetPatchInfoExA)( LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT,
35 LPCSTR, LPSTR, DWORD * );
36 static UINT (WINAPI *pMsiEnumPatchesExA)( LPCSTR, LPCSTR, DWORD, DWORD, DWORD, LPSTR,
37 LPSTR, MSIINSTALLCONTEXT *, LPSTR, LPDWORD );
39 static const char *msifile = "winetest-patch.msi";
40 static const char *mspfile = "winetest-patch.msp";
42 static char CURR_DIR[MAX_PATH];
43 static char PROG_FILES_DIR[MAX_PATH];
44 static char COMMON_FILES_DIR[MAX_PATH];
46 /* msi database data */
48 static const char property_dat[] =
49 "Property\tValue\n"
50 "s72\tl0\n"
51 "Property\tProperty\n"
52 "Manufacturer\tWineHQ\n"
53 "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
54 "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
55 "ProductLanguage\t1033\n"
56 "ProductName\tmsitest\n"
57 "ProductVersion\t1.1.1\n"
58 "PATCHNEWSUMMARYSUBJECT\tInstaller Database\n";
60 static const char media_dat[] =
61 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
62 "i2\ti4\tL64\tS255\tS32\tS72\n"
63 "Media\tDiskId\n"
64 "1\t1\t\t\tDISK1\t\n";
66 static const char file_dat[] =
67 "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
68 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
69 "File\tFile\n"
70 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
72 static const char directory_dat[] =
73 "Directory\tDirectory_Parent\tDefaultDir\n"
74 "s72\tS72\tl255\n"
75 "Directory\tDirectory\n"
76 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
77 "ProgramFilesFolder\tTARGETDIR\t.\n"
78 "TARGETDIR\t\tSourceDir";
80 static const char component_dat[] =
81 "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
82 "s72\tS38\ts72\ti2\tS255\tS72\n"
83 "Component\tComponent\n"
84 "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n";
86 static const char feature_dat[] =
87 "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
88 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
89 "Feature\tFeature\n"
90 "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n";
92 static const char feature_comp_dat[] =
93 "Feature_\tComponent_\n"
94 "s38\ts72\n"
95 "FeatureComponents\tFeature_\tComponent_\n"
96 "patch\tpatch\n";
98 static const char install_exec_seq_dat[] =
99 "Action\tCondition\tSequence\n"
100 "s72\tS255\tI2\n"
101 "InstallExecuteSequence\tAction\n"
102 "LaunchConditions\t\t100\n"
103 "CostInitialize\t\t800\n"
104 "FileCost\t\t900\n"
105 "CostFinalize\t\t1000\n"
106 "InstallValidate\t\t1400\n"
107 "InstallInitialize\t\t1500\n"
108 "ProcessComponents\t\t1600\n"
109 "RemoveFiles\t\t1700\n"
110 "InstallFiles\t\t2000\n"
111 "RegisterUser\t\t3000\n"
112 "RegisterProduct\t\t3100\n"
113 "PublishFeatures\t\t5100\n"
114 "PublishProduct\t\t5200\n"
115 "InstallFinalize\t\t6000\n";
117 struct msi_table
119 const char *filename;
120 const char *data;
121 int size;
124 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
126 static const struct msi_table tables[] =
128 ADD_TABLE( directory ),
129 ADD_TABLE( file ),
130 ADD_TABLE( component ),
131 ADD_TABLE( feature ),
132 ADD_TABLE( feature_comp ),
133 ADD_TABLE( property ),
134 ADD_TABLE( install_exec_seq ),
135 ADD_TABLE( media )
138 static void init_function_pointers( void )
140 HMODULE hmsi = GetModuleHandleA( "msi.dll" );
142 #define GET_PROC( mod, func ) \
143 p ## func = (void *)GetProcAddress( mod, #func ); \
144 if (!p ## func) \
145 trace( "GetProcAddress(%s) failed\n", #func );
147 GET_PROC( hmsi, MsiApplyPatchA );
148 GET_PROC( hmsi, MsiGetPatchInfoExA );
149 GET_PROC( hmsi, MsiEnumPatchesExA );
150 #undef GET_PROC
153 static BOOL get_program_files_dir( char *buf, char *buf2 )
155 HKEY hkey;
156 DWORD type, size;
158 if (RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
159 return FALSE;
161 size = MAX_PATH;
162 if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) &&
163 RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
165 RegCloseKey( hkey );
166 return FALSE;
168 size = MAX_PATH;
169 if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
171 RegCloseKey( hkey );
172 return FALSE;
174 RegCloseKey( hkey );
175 return TRUE;
178 static void create_file_data( const char *filename, const char *data, DWORD size )
180 HANDLE file;
181 DWORD written;
183 file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
184 if (file == INVALID_HANDLE_VALUE)
185 return;
187 WriteFile( file, data, strlen( data ), &written, NULL );
188 if (size)
190 SetFilePointer( file, size, NULL, FILE_BEGIN );
191 SetEndOfFile( file );
193 CloseHandle( file );
196 #define create_file( name, size ) create_file_data( name, name, size )
198 static BOOL delete_pf( const char *rel_path, BOOL is_file )
200 char path[MAX_PATH];
202 strcpy( path, PROG_FILES_DIR );
203 strcat( path, "\\" );
204 strcat( path, rel_path );
206 if (is_file)
207 return DeleteFileA( path );
208 else
209 return RemoveDirectoryA( path );
212 static DWORD get_pf_file_size( const char *filename )
214 char path[MAX_PATH];
215 HANDLE file;
216 DWORD size;
218 strcpy( path, PROG_FILES_DIR );
219 strcat( path, "\\");
220 strcat( path, filename );
222 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
223 if (file == INVALID_HANDLE_VALUE)
224 return INVALID_FILE_SIZE;
226 size = GetFileSize( file, NULL );
227 CloseHandle( file );
228 return size;
231 static void write_file( const char *filename, const char *data, DWORD data_size )
233 DWORD size;
234 HANDLE file = CreateFile( filename, GENERIC_WRITE, 0, NULL,
235 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
236 WriteFile( file, data, data_size, &size, NULL );
237 CloseHandle( file );
240 static void set_suminfo( const char *filename )
242 UINT r;
243 MSIHANDLE hsi, hdb;
245 r = MsiOpenDatabaseA( filename, MSIDBOPEN_DIRECT, &hdb );
246 ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
248 r = MsiGetSummaryInformation( hdb, NULL, 7, &hsi );
249 ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
251 r = MsiSummaryInfoSetProperty( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
252 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
254 r = MsiSummaryInfoSetProperty( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
255 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
257 r = MsiSummaryInfoSetProperty( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
258 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
260 r = MsiSummaryInfoSetProperty( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
261 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
263 r = MsiSummaryInfoSetProperty( hsi, 9, VT_LPSTR, 0, NULL, "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}" );
264 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
266 r = MsiSummaryInfoSetProperty( hsi, 14, VT_I4, 100, NULL, NULL );
267 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
269 r = MsiSummaryInfoSetProperty( hsi, 15, VT_I4, 0, NULL, NULL );
270 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
272 r = MsiSummaryInfoPersist( hsi );
273 ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
275 r = MsiCloseHandle( hsi );
276 ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
278 r = MsiCloseHandle( hdb );
279 ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
282 static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
284 MSIHANDLE hdb;
285 UINT r, i;
287 r = MsiOpenDatabaseA( filename, MSIDBOPEN_CREATE, &hdb );
288 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
290 /* import the tables into the database */
291 for (i = 0; i < num_tables; i++)
293 const struct msi_table *table = &tables[i];
295 write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
297 r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
298 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
300 DeleteFileA( table->filename );
303 r = MsiDatabaseCommit( hdb );
304 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
306 MsiCloseHandle( hdb );
307 set_suminfo( filename );
310 /* data for generating a patch */
312 /* table names - encoded as in an msi database file */
313 static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
314 static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
315 static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
316 static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
317 static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
318 static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
319 static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
320 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
321 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
322 /* substorage names */
323 static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
324 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
325 static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
326 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
328 /* data in each table */
329 static const WCHAR p_data0[] = { /* _Columns */
330 0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
331 0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
333 static const WCHAR p_data1[] = { /* _Tables */
334 0x0001
336 static const char p_data2[] = { /* _StringData */
337 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
339 static const WCHAR p_data3[] = { /* _StringPool */
340 /* len, refs */
341 0, 0, /* string 0 '' */
342 16, 5, /* string 1 'MsiPatchSequence' */
343 11, 1, /* string 2 'PatchFamily' */
344 11, 1, /* string 3 'ProductCode' */
345 8, 1, /* string 4 'Sequence' */
346 10, 1, /* string 5 'Attributes' */
347 15, 1, /* string 6 '1.1.19388.37230' */
348 32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
350 static const char p_data4[] = { /* CAB_msitest */
351 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9e,
354 0x03, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x12,
355 0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
356 0x3c, 0xd4, 0x80, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
357 0x74, 0x78, 0x74, 0x00, 0x0b, 0x3c, 0xd6, 0xc1, 0x4a, 0x00, 0xea,
358 0x03, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x10, 0xa1, 0x3e, 0x00, 0x00,
359 0x00, 0x00, 0x03, 0x00, 0x40, 0x30, 0x0c, 0x43, 0xf8, 0xb4, 0x85,
360 0x4d, 0x96, 0x08, 0x0a, 0x92, 0xf0, 0x52, 0xfb, 0xbb, 0x82, 0xf9,
361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x31, 0x7d,
362 0x56, 0xdf, 0xf7, 0x48, 0x7c, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
363 0x00, 0x00, 0x41, 0x80, 0xdf, 0xf7, 0xd8, 0x72, 0xbf, 0xb9, 0x63,
364 0x91, 0x0e, 0x57, 0x1f, 0xfa, 0x1a, 0x66, 0x54, 0x55
366 static const WCHAR p_data5[] = { /* MsiPatchSequence */
367 0x0007, 0x0000, 0x0006, 0x8000
369 static const char p_data6[] = { /* SummaryInformation */
370 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
371 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
372 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
373 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
374 0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
375 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
376 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
377 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
378 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
379 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
380 0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
381 0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
382 0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
383 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
384 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
385 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
386 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
387 0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
388 0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
389 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
390 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
391 0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
392 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
393 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
394 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
397 struct table_data {
398 LPCWSTR name;
399 const void *data;
400 DWORD size;
403 static const struct table_data table_patch_data[] = {
404 { p_name0, p_data0, sizeof p_data0 },
405 { p_name1, p_data1, sizeof p_data1 },
406 { p_name2, p_data2, sizeof p_data2 - 1 },
407 { p_name3, p_data3, sizeof p_data3 },
408 { p_name4, p_data4, sizeof p_data4 },
409 { p_name5, p_data5, sizeof p_data5 },
410 { p_name6, p_data6, sizeof p_data6 }
413 #define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
415 static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
416 static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
417 static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
418 static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
419 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
420 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
422 static const WCHAR t1_data0[] = { /* File */
423 0x0008, 0x0001, 0x03ea, 0x8000
425 static const char t1_data1[] = { /* _StringData */
426 "patch.txt"
428 static const WCHAR t1_data2[] = { /* _StringPool */
429 /* len, refs */
430 0, 0, /* string 0 '' */
431 9, 1, /* string 1 'patch.txt' */
433 static const char t1_data3[] = { /* SummaryInformation */
434 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
435 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
436 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
437 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
438 0x30, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
439 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
440 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
441 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
442 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
443 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
444 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
445 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
446 0x04, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00,
447 0x00, 0x10, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x1e, 0x00,
448 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
449 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
450 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
451 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
452 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
453 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
454 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
455 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
456 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
457 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
458 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31,
460 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06,
461 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00,
462 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 0x39, 0x31,
463 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
464 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
465 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
466 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x39, 0x31,
467 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
468 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
469 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
470 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x41, 0x32,
471 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45, 0x32, 0x43,
472 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30, 0x39, 0x2d,
473 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35, 0x46, 0x34,
474 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
475 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x09
478 static const struct table_data table_transform1_data[] = {
479 { t1_name0, t1_data0, sizeof t1_data0 },
480 { t1_name1, t1_data1, sizeof t1_data1 - 1 },
481 { t1_name2, t1_data2, sizeof t1_data2 },
482 { t1_name3, t1_data3, sizeof t1_data3 }
485 #define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
487 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
488 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
489 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
490 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
491 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
492 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
493 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
494 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
495 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
496 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
497 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
498 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
499 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
501 static const WCHAR t2_data0[] = { /* File */
502 0x00c0, 0x0001, 0x9000, 0x83e8
504 static const WCHAR t2_data1[] = { /* Media */
505 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
507 static const WCHAR t2_data2[] = { /* _Columns */
508 0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
509 0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
510 0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
511 0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
512 0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
513 0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
514 0x000e, 0x8900
516 static const WCHAR t2_data3[] = { /* _Tables */
517 0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
519 static const WCHAR t2_data4[] = { /* Property */
520 0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
522 static const WCHAR t2_data5[] = { /* PatchPackage */
523 0x0201, 0x0013, 0x8002
525 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
526 0x0301, 0x0006, 0x0000, 0x87d1
528 static const char t2_data7[] = { /* _StringData */
529 "patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
530 "PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
531 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
533 static const WCHAR t2_data8[] = { /* _StringPool */
534 /* len, refs */
535 0, 0, /* string 0 '' */
536 9, 1, /* string 1 'patch.txt' */
537 22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
538 21, 1, /* string 3 'Installation Database' */
539 19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
540 38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
541 10, 1, /* string 6 'PatchFiles' */
542 12, 1, /* string 7 '#CAB_msitest' */
543 4, 1, /* string 8 'prop' */
544 5, 7, /* string 9 'Patch' */
545 5, 1, /* string 10 'File_' */
546 8, 1, /* string 11 'Sequence' */
547 9, 1, /* string 12 'PatchSize' */
548 10, 1, /* string 13 'Attributes' */
549 6, 2, /* string 14 'Header' */
550 10, 1, /* string 15 'StreamRef_' */
551 12, 3, /* string 16 'PatchPackage' */
552 7, 1, /* string 17 'PatchId' */
553 6, 1, /* string 18 'Media_' */
554 38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
555 15, 3, /* string 20 'MsiPatchHeaders' */
556 9, 1 /* string 21 'StreamRef' */
558 static const char t2_data9[] = { /* SummaryInformation */
559 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
562 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
563 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
564 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
565 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
566 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
567 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
568 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
569 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
570 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
571 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
572 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
575 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
576 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
579 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
580 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
581 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
582 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
583 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
584 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
585 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
586 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
587 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
588 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
589 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
590 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
591 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
592 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
593 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
594 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
597 static const struct table_data table_transform2_data[] = {
598 { t2_name0, t2_data0, sizeof t2_data0 },
599 { t2_name1, t2_data1, sizeof t2_data1 },
600 { t2_name2, t2_data2, sizeof t2_data2 },
601 { t2_name3, t2_data3, sizeof t2_data3 },
602 { t2_name4, t2_data4, sizeof t2_data4 },
603 { t2_name5, t2_data5, sizeof t2_data5 },
604 { t2_name6, t2_data6, sizeof t2_data6 },
605 { t2_name7, t2_data7, sizeof t2_data7 - 1 },
606 { t2_name8, t2_data8, sizeof t2_data8 },
607 { t2_name9, t2_data9, sizeof t2_data9 }
610 #define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
612 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
614 IStream *stm;
615 DWORD i, count;
616 HRESULT r;
618 for (i = 0; i < num_tables; i++)
620 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
621 if (FAILED( r ))
623 ok( 0, "failed to create stream 0x%08x\n", r );
624 continue;
627 r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
628 if (FAILED( r ) || count != tables[i].size)
629 ok( 0, "failed to write stream\n" );
630 IStream_Release( stm );
634 static void create_patch( const char *filename )
636 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
637 WCHAR *filenameW;
638 HRESULT r;
639 int len;
640 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
642 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
643 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
645 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
646 filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
647 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
649 r = StgCreateDocfile( filenameW, mode, 0, &stg );
650 HeapFree( GetProcessHeap(), 0, filenameW );
651 ok( r == S_OK, "failed to create storage 0x%08x\n", r );
652 if (!stg)
653 return;
655 r = IStorage_SetClass( stg, &CLSID_MsiPatch );
656 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
658 write_tables( stg, table_patch_data, NUM_PATCH_TABLES );
660 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
661 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
663 r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
664 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
666 write_tables( stg1, table_transform1_data, NUM_TRANSFORM1_TABLES );
667 IStorage_Release( stg1 );
669 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
670 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
672 r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
673 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
675 write_tables( stg2, table_transform2_data, NUM_TRANSFORM2_TABLES );
676 IStorage_Release( stg2 );
677 IStorage_Release( stg );
680 static void test_simple_patch( void )
682 UINT r;
683 DWORD size;
684 char path[MAX_PATH], install_source[MAX_PATH];
685 const char *query;
686 MSIHANDLE hpackage, hdb, hview, hrec;
688 if (!pMsiApplyPatchA)
690 win_skip("MsiApplyPatchA is not available\n");
691 return;
694 CreateDirectoryA( "msitest", NULL );
695 create_file( "msitest\\patch.txt", 1000 );
697 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
698 create_patch( mspfile );
700 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
702 r = MsiInstallProductA( msifile, NULL );
703 if (r != ERROR_SUCCESS)
705 skip("Product installation failed with error code %u\n", r);
706 goto cleanup;
709 size = get_pf_file_size( "msitest\\patch.txt" );
710 ok( size == 1000, "expected 1000, got %u\n", size );
712 size = sizeof(install_source);
713 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
714 "InstallSource", install_source, &size );
715 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
717 strcpy( path, CURR_DIR );
718 strcat( path, "\\" );
719 strcat( path, msifile );
721 r = MsiOpenPackageA( path, &hpackage );
722 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
724 hdb = MsiGetActiveDatabase( hpackage );
725 ok( hdb, "failed to get database handle\n" );
727 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
728 r = MsiDatabaseOpenView( hdb, query, &hview );
729 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
731 r = MsiViewExecute( hview, 0 );
732 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
734 r = MsiViewFetch( hview, &hrec );
735 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
737 MsiCloseHandle( hrec );
738 MsiViewClose( hview );
739 MsiCloseHandle( hview );
741 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
742 "AND `Value` = 'Installer Database'";
743 r = MsiDatabaseOpenView( hdb, query, &hview );
744 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
746 r = MsiViewExecute( hview, 0 );
747 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
749 r = MsiViewFetch( hview, &hrec );
750 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
752 MsiCloseHandle( hrec );
753 MsiViewClose( hview );
754 MsiCloseHandle( hview );
756 MsiCloseHandle( hdb );
757 MsiCloseHandle( hpackage );
759 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
760 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
761 "expected ERROR_SUCCESS, got %u\n", r );
763 if (r == ERROR_PATCH_PACKAGE_INVALID)
765 win_skip("Windows Installer < 3.0 detected\n");
766 goto uninstall;
769 size = get_pf_file_size( "msitest\\patch.txt" );
770 ok( size == 1002, "expected 1002, got %u\n", size );
772 /* show that MsiOpenPackage applies registered patches */
773 r = MsiOpenPackageA( path, &hpackage );
774 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
776 hdb = MsiGetActiveDatabase( hpackage );
777 ok( hdb, "failed to get database handle\n" );
779 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
780 r = MsiDatabaseOpenView( hdb, query, &hview );
781 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
783 r = MsiViewExecute( hview, 0 );
784 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
786 r = MsiViewFetch( hview, &hrec );
787 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
789 MsiCloseHandle( hrec );
790 MsiViewClose( hview );
791 MsiCloseHandle( hview );
793 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
794 "AND `Value` = 'Installation Database'";
795 r = MsiDatabaseOpenView( hdb, query, &hview );
796 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
798 r = MsiViewExecute( hview, 0 );
799 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
801 r = MsiViewFetch( hview, &hrec );
802 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
804 MsiCloseHandle( hrec );
805 MsiViewClose( hview );
806 MsiCloseHandle( hview );
808 MsiCloseHandle( hdb );
809 MsiCloseHandle( hpackage );
811 /* show that patches are not committed to the local package database */
812 size = sizeof(path);
813 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
814 "LocalPackage", path, &size );
815 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
817 r = MsiOpenDatabaseA( path, MSIDBOPEN_READONLY, &hdb );
818 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
820 r = MsiDatabaseOpenView( hdb, query, &hview );
821 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
823 r = MsiViewExecute( hview, 0 );
824 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
826 r = MsiViewFetch( hview, &hrec );
827 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
829 MsiCloseHandle( hrec );
830 MsiViewClose( hview );
831 MsiCloseHandle( hview );
832 MsiCloseHandle( hdb );
834 uninstall:
835 size = sizeof(path);
836 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
837 "InstallSource", path, &size );
838 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
839 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
841 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
842 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
844 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
845 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
847 cleanup:
848 DeleteFileA( msifile );
849 DeleteFileA( mspfile );
850 DeleteFileA( "msitest\\patch.txt" );
851 RemoveDirectoryA( "msitest" );
854 static void test_MsiOpenDatabase( void )
856 UINT r;
857 MSIHANDLE hdb;
859 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE, &hdb );
860 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
862 r = MsiDatabaseCommit( hdb );
863 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
864 MsiCloseHandle( hdb );
866 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
867 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
868 DeleteFileA( mspfile );
870 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
871 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
873 r = MsiDatabaseCommit( hdb );
874 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
875 MsiCloseHandle( hdb );
877 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
878 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
879 MsiCloseHandle( hdb );
880 DeleteFileA( mspfile );
882 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
883 create_patch( mspfile );
885 r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
886 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
888 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
889 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
890 MsiCloseHandle( hdb );
892 DeleteFileA( msifile );
893 DeleteFileA( mspfile );
896 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
898 static char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
899 char query[0x100];
900 UINT r;
901 MSIHANDLE hview, hrec;
903 sprintf( query, fmt, table, entry );
904 r = MsiDatabaseOpenView( hdb, query, &hview );
905 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
907 r = MsiViewExecute( hview, 0 );
908 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
910 r = MsiViewFetch( hview, &hrec );
911 MsiViewClose( hview );
912 MsiCloseHandle( hview );
913 MsiCloseHandle( hrec );
914 return r;
917 static void test_system_tables( void )
919 UINT r;
920 const char *query;
921 MSIHANDLE hproduct, hdb, hview, hrec;
923 if (!pMsiApplyPatchA)
925 win_skip("MsiApplyPatchA is not available\n");
926 return;
929 CreateDirectoryA( "msitest", NULL );
930 create_file( "msitest\\patch.txt", 1000 );
932 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
933 create_patch( mspfile );
935 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
937 r = MsiInstallProductA( msifile, NULL );
938 if (r != ERROR_SUCCESS)
940 skip("Product installation failed with error code %d\n", r);
941 goto cleanup;
944 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
945 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
947 hdb = MsiGetActiveDatabase( hproduct );
948 ok( hdb, "failed to get database handle\n" );
950 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
951 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
953 query = "SELECT * FROM `_Storages`";
954 r = MsiDatabaseOpenView( hdb, query, &hview );
955 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
957 r = MsiViewExecute( hview, 0 );
958 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
960 r = MsiViewFetch( hview, &hrec );
961 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
963 r = find_entry( hdb, "_Tables", "Directory" );
964 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
966 r = find_entry( hdb, "_Tables", "File" );
967 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
969 r = find_entry( hdb, "_Tables", "Component" );
970 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
972 r = find_entry( hdb, "_Tables", "Feature" );
973 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
975 r = find_entry( hdb, "_Tables", "FeatureComponents" );
976 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
978 r = find_entry( hdb, "_Tables", "Property" );
979 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
981 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
982 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
984 r = find_entry( hdb, "_Tables", "Media" );
985 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
987 r = find_entry( hdb, "_Tables", "_Property" );
988 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
990 MsiCloseHandle( hrec );
991 MsiViewClose( hview );
992 MsiCloseHandle( hview );
993 MsiCloseHandle( hdb );
994 MsiCloseHandle( hproduct );
996 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
997 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
998 "expected ERROR_SUCCESS, got %u\n", r );
1000 if (r == ERROR_PATCH_PACKAGE_INVALID)
1002 win_skip("Windows Installer < 3.0 detected\n");
1003 goto uninstall;
1006 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1007 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1009 hdb = MsiGetActiveDatabase( hproduct );
1010 ok( hdb, "failed to get database handle\n" );
1012 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1013 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1015 query = "SELECT * FROM `_Storages`";
1016 r = MsiDatabaseOpenView( hdb, query, &hview );
1017 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1019 r = MsiViewExecute( hview, 0 );
1020 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1022 r = MsiViewFetch( hview, &hrec );
1023 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1025 r = find_entry( hdb, "_Tables", "Directory" );
1026 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1028 r = find_entry( hdb, "_Tables", "File" );
1029 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1031 r = find_entry( hdb, "_Tables", "Component" );
1032 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1034 r = find_entry( hdb, "_Tables", "Feature" );
1035 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1037 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1038 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1040 r = find_entry( hdb, "_Tables", "Property" );
1041 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1043 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1044 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1046 r = find_entry( hdb, "_Tables", "Media" );
1047 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1049 r = find_entry( hdb, "_Tables", "_Property" );
1050 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1052 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1053 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1055 r = find_entry( hdb, "_Tables", "Patch" );
1056 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1058 r = find_entry( hdb, "_Tables", "PatchPackage" );
1059 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1061 MsiCloseHandle( hrec );
1062 MsiViewClose( hview );
1063 MsiCloseHandle( hview );
1064 MsiCloseHandle( hdb );
1065 MsiCloseHandle( hproduct );
1067 uninstall:
1068 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1069 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1071 cleanup:
1072 DeleteFileA( msifile );
1073 DeleteFileA( mspfile );
1074 DeleteFileA( "msitest\\patch.txt" );
1075 RemoveDirectoryA( "msitest" );
1078 static void test_patch_registration( void )
1080 UINT r, size;
1081 char buffer[MAX_PATH], patch_code[39];
1083 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1085 win_skip("required functions not available\n");
1086 return;
1089 CreateDirectoryA( "msitest", NULL );
1090 create_file( "msitest\\patch.txt", 1000 );
1092 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1093 create_patch( mspfile );
1095 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1097 r = MsiInstallProductA( msifile, NULL );
1098 if (r != ERROR_SUCCESS)
1100 skip("Product installation failed with error code %d\n", r);
1101 goto cleanup;
1104 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1105 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1106 "expected ERROR_SUCCESS, got %u\n", r );
1108 if (r == ERROR_PATCH_PACKAGE_INVALID)
1110 win_skip("Windows Installer < 3.0 detected\n");
1111 goto uninstall;
1114 buffer[0] = 0;
1115 size = sizeof(buffer);
1116 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1117 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1118 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1119 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1120 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1121 ok( buffer[0], "buffer empty\n" );
1123 buffer[0] = 0;
1124 size = sizeof(buffer);
1125 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1126 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1127 NULL, MSIINSTALLCONTEXT_MACHINE,
1128 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1129 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1131 buffer[0] = 0;
1132 size = sizeof(buffer);
1133 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1134 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1135 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1136 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1137 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1138 ok( !buffer[0], "got %s\n", buffer );
1140 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1141 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1142 0, patch_code, NULL, NULL, NULL, NULL );
1143 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1144 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1146 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1147 NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1148 0, patch_code, NULL, NULL, NULL, NULL );
1149 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1151 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1152 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1153 0, patch_code, NULL, NULL, NULL, NULL );
1154 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1156 uninstall:
1157 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1158 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1160 buffer[0] = 0;
1161 size = sizeof(buffer);
1162 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1163 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1164 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1165 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1166 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1168 cleanup:
1169 DeleteFileA( msifile );
1170 DeleteFileA( mspfile );
1171 DeleteFileA( "msitest\\patch.txt" );
1172 RemoveDirectoryA( "msitest" );
1175 START_TEST(patch)
1177 DWORD len;
1178 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1180 init_function_pointers();
1182 GetCurrentDirectoryA( MAX_PATH, prev_path );
1183 GetTempPath( MAX_PATH, temp_path );
1184 SetCurrentDirectoryA( temp_path );
1186 strcpy( CURR_DIR, temp_path );
1187 len = strlen( CURR_DIR );
1189 if (len && (CURR_DIR[len - 1] == '\\'))
1190 CURR_DIR[len - 1] = 0;
1192 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1194 test_simple_patch();
1195 test_MsiOpenDatabase();
1196 test_system_tables();
1197 test_patch_registration();
1199 SetCurrentDirectoryA( prev_path );