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
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 * );
37 static const char *msifile = "winetest-patch.msi";
38 static const char *mspfile = "winetest-patch.msp";
40 static char CURR_DIR[MAX_PATH];
41 static char PROG_FILES_DIR[MAX_PATH];
42 static char COMMON_FILES_DIR[MAX_PATH];
44 /* msi database data */
46 static const char property_dat[] =
49 "Property\tProperty\n"
50 "Manufacturer\tWineHQ\n"
51 "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
52 "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
53 "ProductLanguage\t1033\n"
54 "ProductName\tmsitest\n"
55 "ProductVersion\t1.1.1\n";
57 static const char media_dat[] =
58 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
59 "i2\ti4\tL64\tS255\tS32\tS72\n"
61 "1\t1\t\t\tDISK1\t\n";
63 static const char file_dat[] =
64 "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
65 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
67 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
69 static const char directory_dat[] =
70 "Directory\tDirectory_Parent\tDefaultDir\n"
72 "Directory\tDirectory\n"
73 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
74 "ProgramFilesFolder\tTARGETDIR\t.\n"
75 "TARGETDIR\t\tSourceDir";
77 static const char component_dat[] =
78 "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
79 "s72\tS38\ts72\ti2\tS255\tS72\n"
80 "Component\tComponent\n"
81 "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n";
83 static const char feature_dat[] =
84 "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
85 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
87 "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n";
89 static const char feature_comp_dat[] =
90 "Feature_\tComponent_\n"
92 "FeatureComponents\tFeature_\tComponent_\n"
95 static const char install_exec_seq_dat[] =
96 "Action\tCondition\tSequence\n"
98 "InstallExecuteSequence\tAction\n"
99 "LaunchConditions\t\t100\n"
100 "CostInitialize\t\t800\n"
102 "CostFinalize\t\t1000\n"
103 "InstallValidate\t\t1400\n"
104 "InstallInitialize\t\t1500\n"
105 "ProcessComponents\t\t1600\n"
106 "RemoveFiles\t\t1700\n"
107 "InstallFiles\t\t2000\n"
108 "RegisterUser\t\t3000\n"
109 "RegisterProduct\t\t3100\n"
110 "PublishFeatures\t\t5100\n"
111 "PublishProduct\t\t5200\n"
112 "InstallFinalize\t\t6000\n";
116 const char *filename;
121 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
123 static const struct msi_table tables[] =
125 ADD_TABLE( directory ),
127 ADD_TABLE( component ),
128 ADD_TABLE( feature ),
129 ADD_TABLE( feature_comp ),
130 ADD_TABLE( property ),
131 ADD_TABLE( install_exec_seq ),
135 static void init_function_pointers( void )
137 HMODULE hmsi = GetModuleHandleA( "msi.dll" );
139 #define GET_PROC( mod, func ) \
140 p ## func = (void *)GetProcAddress( mod, #func ); \
142 trace( "GetProcAddress(%s) failed\n", #func );
144 GET_PROC( hmsi, MsiApplyPatchA );
145 GET_PROC( hmsi, MsiGetPatchInfoExA );
149 static BOOL get_program_files_dir( char *buf, char *buf2 )
154 if (RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
158 if (RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
164 if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
173 static void create_file_data( const char *filename, const char *data, DWORD size )
178 file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
179 if (file == INVALID_HANDLE_VALUE)
182 WriteFile( file, data, strlen( data ), &written, NULL );
185 SetFilePointer( file, size, NULL, FILE_BEGIN );
186 SetEndOfFile( file );
191 #define create_file( name, size ) create_file_data( name, name, size )
193 static BOOL delete_pf( const char *rel_path, BOOL is_file )
197 strcpy( path, PROG_FILES_DIR );
198 strcat( path, "\\" );
199 strcat( path, rel_path );
202 return DeleteFileA( path );
204 return RemoveDirectoryA( path );
207 static DWORD get_pf_file_size( const char *filename )
213 strcpy( path, PROG_FILES_DIR );
215 strcat( path, filename );
217 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
218 if (file == INVALID_HANDLE_VALUE)
219 return INVALID_FILE_SIZE;
221 size = GetFileSize( file, NULL );
226 static void write_file( const char *filename, const char *data, DWORD data_size )
229 HANDLE file = CreateFile( filename, GENERIC_WRITE, 0, NULL,
230 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
231 WriteFile( file, data, data_size, &size, NULL );
235 static void set_suminfo( const char *filename )
240 r = MsiOpenDatabaseA( filename, MSIDBOPEN_DIRECT, &hdb );
241 ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
243 r = MsiGetSummaryInformation( hdb, NULL, 7, &hsi );
244 ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
246 r = MsiSummaryInfoSetProperty( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
247 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
249 r = MsiSummaryInfoSetProperty( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
250 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
252 r = MsiSummaryInfoSetProperty( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
253 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
255 r = MsiSummaryInfoSetProperty( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
256 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
258 r = MsiSummaryInfoSetProperty( hsi, 9, VT_LPSTR, 0, NULL, "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}" );
259 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
261 r = MsiSummaryInfoSetProperty( hsi, 14, VT_I4, 100, NULL, NULL );
262 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
264 r = MsiSummaryInfoSetProperty( hsi, 15, VT_I4, 0, NULL, NULL );
265 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
267 r = MsiSummaryInfoPersist( hsi );
268 ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
270 r = MsiCloseHandle( hsi );
271 ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
273 r = MsiCloseHandle( hdb );
274 ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
277 static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
282 r = MsiOpenDatabaseA( filename, MSIDBOPEN_CREATE, &hdb );
283 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
285 /* import the tables into the database */
286 for (i = 0; i < num_tables; i++)
288 const struct msi_table *table = &tables[i];
290 write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
292 r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
293 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
295 DeleteFileA( table->filename );
298 r = MsiDatabaseCommit( hdb );
299 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
301 MsiCloseHandle( hdb );
302 set_suminfo( filename );
305 /* data for generating a patch */
307 /* table names - encoded as in an msi database file */
308 static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
309 static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
310 static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
311 static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
312 static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
313 static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
314 static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
315 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
316 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
317 /* substorage names */
318 static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
319 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
320 static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
321 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
323 /* data in each table */
324 static const WCHAR p_data0[] = { /* _Columns */
325 0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
326 0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
328 static const WCHAR p_data1[] = { /* _Tables */
331 static const char p_data2[] = { /* _StringData */
332 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
334 static const WCHAR p_data3[] = { /* _StringPool */
336 0, 0, /* string 0 '' */
337 16, 5, /* string 1 'MsiPatchSequence' */
338 11, 1, /* string 2 'PatchFamily' */
339 11, 1, /* string 3 'ProductCode' */
340 8, 1, /* string 4 'Sequence' */
341 10, 1, /* string 5 'Attributes' */
342 15, 1, /* string 6 '1.1.19388.37230' */
343 32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
345 static const char p_data4[] = { /* CAB_msitest */
346 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00,
347 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
348 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9e,
349 0x03, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x12,
350 0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
351 0x3c, 0xd4, 0x80, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
352 0x74, 0x78, 0x74, 0x00, 0x0b, 0x3c, 0xd6, 0xc1, 0x4a, 0x00, 0xea,
353 0x03, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x10, 0xa1, 0x3e, 0x00, 0x00,
354 0x00, 0x00, 0x03, 0x00, 0x40, 0x30, 0x0c, 0x43, 0xf8, 0xb4, 0x85,
355 0x4d, 0x96, 0x08, 0x0a, 0x92, 0xf0, 0x52, 0xfb, 0xbb, 0x82, 0xf9,
356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x31, 0x7d,
357 0x56, 0xdf, 0xf7, 0x48, 0x7c, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x41, 0x80, 0xdf, 0xf7, 0xd8, 0x72, 0xbf, 0xb9, 0x63,
359 0x91, 0x0e, 0x57, 0x1f, 0xfa, 0x1a, 0x66, 0x54, 0x55
361 static const WCHAR p_data5[] = { /* MsiPatchSequence */
362 0x0007, 0x0000, 0x0006, 0x8000
364 static const char p_data6[] = { /* SummaryInformation */
365 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
368 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
369 0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
370 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
371 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
372 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
373 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
374 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
375 0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
376 0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
377 0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
378 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
379 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
380 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
381 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
382 0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
383 0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
384 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
385 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
386 0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
387 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
388 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
389 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
398 static const struct table_data table_patch_data[] = {
399 { p_name0, p_data0, sizeof p_data0 },
400 { p_name1, p_data1, sizeof p_data1 },
401 { p_name2, p_data2, sizeof p_data2 - 1 },
402 { p_name3, p_data3, sizeof p_data3 },
403 { p_name4, p_data4, sizeof p_data4 },
404 { p_name5, p_data5, sizeof p_data5 },
405 { p_name6, p_data6, sizeof p_data6 }
408 #define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
410 static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
411 static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
412 static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
413 static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
414 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
415 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
417 static const WCHAR t1_data0[] = { /* File */
418 0x0008, 0x0001, 0x03ea, 0x8000
420 static const char t1_data1[] = { /* _StringData */
423 static const WCHAR t1_data2[] = { /* _StringPool */
425 0, 0, /* string 0 '' */
426 9, 1, /* string 1 'patch.txt' */
428 static const char t1_data3[] = { /* SummaryInformation */
429 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
430 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
431 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
432 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
433 0x30, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
434 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
435 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
436 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
437 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
438 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
439 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
440 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
441 0x04, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00,
442 0x00, 0x10, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x1e, 0x00,
443 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
444 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
445 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
446 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
447 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
448 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
449 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
450 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
451 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
452 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
453 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
454 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31,
455 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06,
456 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00,
457 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 0x39, 0x31,
458 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
459 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
460 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
461 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x39, 0x31,
462 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
463 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
464 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
465 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x41, 0x32,
466 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45, 0x32, 0x43,
467 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30, 0x39, 0x2d,
468 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35, 0x46, 0x34,
469 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
470 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x09
473 static const struct table_data table_transform1_data[] = {
474 { t1_name0, t1_data0, sizeof t1_data0 },
475 { t1_name1, t1_data1, sizeof t1_data1 - 1 },
476 { t1_name2, t1_data2, sizeof t1_data2 },
477 { t1_name3, t1_data3, sizeof t1_data3 }
480 #define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
482 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
483 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
484 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
485 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
486 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
487 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
488 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
489 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
490 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
491 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
492 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
493 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
494 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
496 static const WCHAR t2_data0[] = { /* File */
497 0x00c0, 0x0001, 0x9000, 0x83e8
499 static const WCHAR t2_data1[] = { /* Media */
500 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
502 static const WCHAR t2_data2[] = { /* _Columns */
503 0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
504 0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
505 0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
506 0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
507 0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
508 0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
511 static const WCHAR t2_data3[] = { /* _Tables */
512 0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
514 static const WCHAR t2_data4[] = { /* Property */
515 0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
517 static const WCHAR t2_data5[] = { /* PatchPackage */
518 0x0201, 0x0013, 0x8002
520 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
521 0x0301, 0x0006, 0x0000, 0x87d1
523 static const char t2_data7[] = { /* _StringData */
524 "patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
525 "PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
526 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
528 static const WCHAR t2_data8[] = { /* _StringPool */
530 0, 0, /* string 0 '' */
531 9, 1, /* string 1 'patch.txt' */
532 22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
533 21, 1, /* string 3 'Installation Database' */
534 19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
535 38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
536 10, 1, /* string 6 'PatchFiles' */
537 12, 1, /* string 7 '#CAB_msitest' */
538 4, 1, /* string 8 'prop' */
539 5, 7, /* string 9 'Patch' */
540 5, 1, /* string 10 'File_' */
541 8, 1, /* string 11 'Sequence' */
542 9, 1, /* string 12 'PatchSize' */
543 10, 1, /* string 13 'Attributes' */
544 6, 2, /* string 14 'Header' */
545 10, 1, /* string 15 'StreamRef_' */
546 12, 3, /* string 16 'PatchPackage' */
547 7, 1, /* string 17 'PatchId' */
548 6, 1, /* string 18 'Media_' */
549 38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
550 15, 3, /* string 20 'MsiPatchHeaders' */
551 9, 1 /* string 21 'StreamRef' */
553 static const char t2_data9[] = { /* SummaryInformation */
554 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
557 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
558 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
559 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
560 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
561 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
562 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
563 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
564 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
565 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
566 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
567 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
574 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
575 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
577 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
578 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
579 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
580 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
581 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
582 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
583 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
584 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
585 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
586 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
587 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
588 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
589 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
592 static const struct table_data table_transform2_data[] = {
593 { t2_name0, t2_data0, sizeof t2_data0 },
594 { t2_name1, t2_data1, sizeof t2_data1 },
595 { t2_name2, t2_data2, sizeof t2_data2 },
596 { t2_name3, t2_data3, sizeof t2_data3 },
597 { t2_name4, t2_data4, sizeof t2_data4 },
598 { t2_name5, t2_data5, sizeof t2_data5 },
599 { t2_name6, t2_data6, sizeof t2_data6 },
600 { t2_name7, t2_data7, sizeof t2_data7 - 1 },
601 { t2_name8, t2_data8, sizeof t2_data8 },
602 { t2_name9, t2_data9, sizeof t2_data9 }
605 #define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
607 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
613 for (i = 0; i < num_tables; i++)
615 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
618 ok( 0, "failed to create stream 0x%08x\n", r );
622 r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
623 if (FAILED( r ) || count != tables[i].size)
624 ok( 0, "failed to write stream\n" );
625 IStream_Release( stm );
629 static void create_patch( const char *filename )
631 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
635 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
637 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
638 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
640 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
641 filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
642 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
644 r = StgCreateDocfile( filenameW, mode, 0, &stg );
645 HeapFree( GetProcessHeap(), 0, filenameW );
646 ok( r == S_OK, "failed to create storage 0x%08x\n", r );
650 r = IStorage_SetClass( stg, &CLSID_MsiPatch );
651 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
653 write_tables( stg, table_patch_data, NUM_PATCH_TABLES );
655 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
656 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
658 r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
659 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
661 write_tables( stg1, table_transform1_data, NUM_TRANSFORM1_TABLES );
662 IStorage_Release( stg1 );
664 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
665 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
667 r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
668 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
670 write_tables( stg2, table_transform2_data, NUM_TRANSFORM2_TABLES );
671 IStorage_Release( stg2 );
672 IStorage_Release( stg );
675 static void test_simple_patch( void )
681 MSIHANDLE hpackage, hdb, hview, hrec;
683 if (!pMsiApplyPatchA)
685 win_skip("MsiApplyPatchA is not available\n");
689 CreateDirectoryA( "msitest", NULL );
690 create_file( "msitest\\patch.txt", 1000 );
692 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
693 create_patch( mspfile );
695 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
697 r = MsiInstallProductA( msifile, NULL );
698 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
700 size = get_pf_file_size( "msitest\\patch.txt" );
701 ok( size == 1000, "expected 1000, got %u\n", size );
703 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
704 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
705 "expected ERROR_SUCCESS, got %u\n", r );
707 if (r == ERROR_PATCH_PACKAGE_INVALID)
709 win_skip("Windows Installer < 3.0 detected\n");
713 size = get_pf_file_size( "msitest\\patch.txt" );
714 ok( size == 1002, "expected 1002, got %u\n", size );
716 strcpy( path, CURR_DIR );
717 strcat( path, "\\" );
718 strcat( path, msifile );
720 /* show that MsiOpenPackage applies registered patches */
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_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
737 MsiCloseHandle( hrec );
738 MsiViewClose( hview );
739 MsiCloseHandle( hview );
740 MsiCloseHandle( hdb );
741 MsiCloseHandle( hpackage );
743 /* show that patches are not committed to the local package database */
745 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
746 "LocalPackage", path, &size );
747 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
749 r = MsiOpenDatabaseA( path, MSIDBOPEN_READONLY, &hdb );
750 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
752 r = MsiDatabaseOpenView( hdb, query, &hview );
753 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
755 r = MsiViewExecute( hview, 0 );
756 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
758 r = MsiViewFetch( hview, &hrec );
759 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
761 MsiCloseHandle( hrec );
762 MsiViewClose( hview );
763 MsiCloseHandle( hview );
764 MsiCloseHandle( hdb );
766 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
767 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
769 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
770 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
772 DeleteFileA( msifile );
773 DeleteFileA( mspfile );
774 RemoveDirectoryA( "msitest" );
777 static void test_MsiOpenDatabase( void )
782 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE, &hdb );
783 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
785 r = MsiDatabaseCommit( hdb );
786 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
787 MsiCloseHandle( hdb );
789 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
790 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
791 DeleteFileA( mspfile );
793 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
794 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
796 r = MsiDatabaseCommit( hdb );
797 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
798 MsiCloseHandle( hdb );
800 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
801 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
802 MsiCloseHandle( hdb );
803 DeleteFileA( mspfile );
805 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
806 create_patch( mspfile );
808 r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
809 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
811 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
812 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
813 MsiCloseHandle( hdb );
815 DeleteFileA( msifile );
816 DeleteFileA( mspfile );
819 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
821 static char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
824 MSIHANDLE hview, hrec;
826 sprintf( query, fmt, table, entry );
827 r = MsiDatabaseOpenView( hdb, query, &hview );
828 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
830 r = MsiViewExecute( hview, 0 );
831 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
833 r = MsiViewFetch( hview, &hrec );
834 MsiViewClose( hview );
835 MsiCloseHandle( hview );
836 MsiCloseHandle( hrec );
840 static void test_system_tables( void )
844 MSIHANDLE hproduct, hdb, hview, hrec;
846 if (!pMsiApplyPatchA)
848 win_skip("MsiApplyPatchA is not available\n");
852 CreateDirectoryA( "msitest", NULL );
853 create_file( "msitest\\patch.txt", 1000 );
855 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
856 create_patch( mspfile );
858 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
860 r = MsiInstallProductA( msifile, NULL );
861 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
863 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
864 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
866 hdb = MsiGetActiveDatabase( hproduct );
867 ok( hdb, "failed to get database handle\n" );
869 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
870 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
872 query = "SELECT * FROM `_Storages`";
873 r = MsiDatabaseOpenView( hdb, query, &hview );
874 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
876 r = MsiViewExecute( hview, 0 );
877 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
879 r = MsiViewFetch( hview, &hrec );
880 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
882 r = find_entry( hdb, "_Tables", "Directory" );
883 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
885 r = find_entry( hdb, "_Tables", "File" );
886 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
888 r = find_entry( hdb, "_Tables", "Component" );
889 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
891 r = find_entry( hdb, "_Tables", "Feature" );
892 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
894 r = find_entry( hdb, "_Tables", "FeatureComponents" );
895 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
897 r = find_entry( hdb, "_Tables", "Property" );
898 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
900 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
901 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
903 r = find_entry( hdb, "_Tables", "Media" );
904 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
906 r = find_entry( hdb, "_Tables", "_Property" );
907 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
909 MsiCloseHandle( hdb );
910 MsiCloseHandle( hproduct );
912 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
913 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
914 "expected ERROR_SUCCESS, got %u\n", r );
916 if (r == ERROR_PATCH_PACKAGE_INVALID)
918 win_skip("Windows Installer < 3.0 detected\n");
922 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
923 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
925 hdb = MsiGetActiveDatabase( hproduct );
926 ok( hdb, "failed to get database handle\n" );
928 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
929 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
931 query = "SELECT * FROM `_Storages`";
932 r = MsiDatabaseOpenView( hdb, query, &hview );
933 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
935 r = MsiViewExecute( hview, 0 );
936 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
938 r = MsiViewFetch( hview, &hrec );
939 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
941 r = find_entry( hdb, "_Tables", "Directory" );
942 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
944 r = find_entry( hdb, "_Tables", "File" );
945 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
947 r = find_entry( hdb, "_Tables", "Component" );
948 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
950 r = find_entry( hdb, "_Tables", "Feature" );
951 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
953 r = find_entry( hdb, "_Tables", "FeatureComponents" );
954 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
956 r = find_entry( hdb, "_Tables", "Property" );
957 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
959 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
960 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
962 r = find_entry( hdb, "_Tables", "Media" );
963 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
965 r = find_entry( hdb, "_Tables", "_Property" );
966 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
968 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
969 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
971 r = find_entry( hdb, "_Tables", "Patch" );
972 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
974 r = find_entry( hdb, "_Tables", "PatchPackage" );
975 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
977 MsiCloseHandle( hdb );
978 MsiCloseHandle( hproduct );
980 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
981 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
983 DeleteFileA( msifile );
984 DeleteFileA( mspfile );
985 RemoveDirectoryA( "msitest" );
988 static void test_patch_registration( void )
991 char buffer[MAX_PATH];
993 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA)
995 win_skip("required functions not available\n");
999 CreateDirectoryA( "msitest", NULL );
1000 create_file( "msitest\\patch.txt", 1000 );
1002 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1003 create_patch( mspfile );
1005 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1007 r = MsiInstallProductA( msifile, NULL );
1008 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1010 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1011 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1012 "expected ERROR_SUCCESS, got %u\n", r );
1014 if (r == ERROR_PATCH_PACKAGE_INVALID)
1016 win_skip("Windows Installer < 3.0 detected\n");
1021 size = sizeof(buffer);
1022 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1023 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1024 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1025 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1026 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1027 ok( buffer[0], "buffer empty\n" );
1030 size = sizeof(buffer);
1031 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1032 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1033 NULL, MSIINSTALLCONTEXT_MACHINE,
1034 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1035 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1038 size = sizeof(buffer);
1039 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1040 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1041 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1042 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1043 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1044 ok( !buffer[0], "got %s\n", buffer );
1046 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1047 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1050 size = sizeof(buffer);
1051 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1052 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1053 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1054 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1055 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1057 DeleteFileA( msifile );
1058 DeleteFileA( mspfile );
1059 RemoveDirectoryA( "msitest" );
1065 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1067 init_function_pointers();
1069 GetCurrentDirectoryA( MAX_PATH, prev_path );
1070 GetTempPath( MAX_PATH, temp_path );
1071 SetCurrentDirectoryA( temp_path );
1073 strcpy( CURR_DIR, temp_path );
1074 len = strlen( CURR_DIR );
1076 if (len && (CURR_DIR[len - 1] == '\\'))
1077 CURR_DIR[len - 1] = 0;
1079 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1081 test_simple_patch();
1082 test_MsiOpenDatabase();
1083 test_system_tables();
1084 test_patch_registration();
1086 SetCurrentDirectoryA( prev_path );