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 * );
36 static UINT (WINAPI *pMsiEnumPatchesExA)( LPCSTR, LPCSTR, DWORD, DWORD, DWORD, LPSTR,
37 LPSTR, MSIINSTALLCONTEXT *, LPSTR, LPDWORD );
38 static BOOL (WINAPI *pGetTokenInformation)( HANDLE, TOKEN_INFORMATION_CLASS, LPVOID, DWORD, PDWORD );
39 static BOOL (WINAPI *pOpenProcessToken)( HANDLE, DWORD, PHANDLE );
41 static const char *msifile = "winetest-patch.msi";
42 static const char *mspfile = "winetest-patch.msp";
44 static char CURR_DIR[MAX_PATH];
45 static char PROG_FILES_DIR[MAX_PATH];
46 static char COMMON_FILES_DIR[MAX_PATH];
48 /* msi database data */
50 static const char property_dat[] =
53 "Property\tProperty\n"
54 "Manufacturer\tWineHQ\n"
55 "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
56 "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
57 "ProductLanguage\t1033\n"
58 "ProductName\tmsitest\n"
59 "ProductVersion\t1.1.1\n"
60 "PATCHNEWSUMMARYSUBJECT\tInstaller Database\n"
61 "MSIFASTINSTALL\t1\n";
63 static const char media_dat[] =
64 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
65 "i2\ti4\tL64\tS255\tS32\tS72\n"
67 "1\t1\t\t\tDISK1\t\n";
69 static const char file_dat[] =
70 "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
71 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
73 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
75 static const char directory_dat[] =
76 "Directory\tDirectory_Parent\tDefaultDir\n"
78 "Directory\tDirectory\n"
79 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
80 "ProgramFilesFolder\tTARGETDIR\t.\n"
81 "TARGETDIR\t\tSourceDir";
83 static const char component_dat[] =
84 "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
85 "s72\tS38\ts72\ti2\tS255\tS72\n"
86 "Component\tComponent\n"
87 "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n";
89 static const char feature_dat[] =
90 "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
91 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
93 "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n";
95 static const char feature_comp_dat[] =
96 "Feature_\tComponent_\n"
98 "FeatureComponents\tFeature_\tComponent_\n"
101 static const char install_exec_seq_dat[] =
102 "Action\tCondition\tSequence\n"
104 "InstallExecuteSequence\tAction\n"
105 "LaunchConditions\t\t100\n"
106 "CostInitialize\t\t800\n"
108 "CostFinalize\t\t1000\n"
109 "InstallValidate\t\t1400\n"
110 "InstallInitialize\t\t1500\n"
111 "ProcessComponents\t\t1600\n"
112 "RemoveFiles\t\t1700\n"
113 "InstallFiles\t\t2000\n"
114 "RegisterUser\t\t3000\n"
115 "RegisterProduct\t\t3100\n"
116 "PublishFeatures\t\t5100\n"
117 "PublishProduct\t\t5200\n"
118 "InstallFinalize\t\t6000\n";
122 const char *filename;
127 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
129 static const struct msi_table tables[] =
131 ADD_TABLE( directory ),
133 ADD_TABLE( component ),
134 ADD_TABLE( feature ),
135 ADD_TABLE( feature_comp ),
136 ADD_TABLE( property ),
137 ADD_TABLE( install_exec_seq ),
141 static void init_function_pointers( void )
143 HMODULE hmsi = GetModuleHandleA( "msi.dll" );
144 HMODULE hadvapi32 = GetModuleHandleA( "advapi32.dll" );
146 #define GET_PROC( mod, func ) \
147 p ## func = (void *)GetProcAddress( mod, #func ); \
149 trace( "GetProcAddress(%s) failed\n", #func );
151 GET_PROC( hmsi, MsiApplyPatchA );
152 GET_PROC( hmsi, MsiGetPatchInfoExA );
153 GET_PROC( hmsi, MsiEnumPatchesExA );
155 GET_PROC( hadvapi32, GetTokenInformation );
156 GET_PROC( hadvapi32, OpenProcessToken );
160 static BOOL is_process_limited(void)
164 if (!pOpenProcessToken || !pGetTokenInformation) return FALSE;
166 if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
169 TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
172 ret = pGetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
174 return (ret && type == TokenElevationTypeLimited);
179 static BOOL get_program_files_dir( char *buf, char *buf2 )
184 if (RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
188 if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) &&
189 RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
195 if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
204 static void create_file_data( const char *filename, const char *data, DWORD size )
209 file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
210 if (file == INVALID_HANDLE_VALUE)
213 WriteFile( file, data, strlen( data ), &written, NULL );
216 SetFilePointer( file, size, NULL, FILE_BEGIN );
217 SetEndOfFile( file );
222 #define create_file( name, size ) create_file_data( name, name, size )
224 static BOOL delete_pf( const char *rel_path, BOOL is_file )
228 strcpy( path, PROG_FILES_DIR );
229 strcat( path, "\\" );
230 strcat( path, rel_path );
233 return DeleteFileA( path );
235 return RemoveDirectoryA( path );
238 static DWORD get_pf_file_size( const char *filename )
244 strcpy( path, PROG_FILES_DIR );
246 strcat( path, filename );
248 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
249 if (file == INVALID_HANDLE_VALUE)
250 return INVALID_FILE_SIZE;
252 size = GetFileSize( file, NULL );
257 static void write_file( const char *filename, const char *data, DWORD data_size )
260 HANDLE file = CreateFile( filename, GENERIC_WRITE, 0, NULL,
261 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
262 WriteFile( file, data, data_size, &size, NULL );
266 static void set_suminfo( const char *filename )
271 r = MsiOpenDatabaseA( filename, MSIDBOPEN_DIRECT, &hdb );
272 ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
274 r = MsiGetSummaryInformation( hdb, NULL, 7, &hsi );
275 ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
277 r = MsiSummaryInfoSetProperty( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
278 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
280 r = MsiSummaryInfoSetProperty( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
281 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
283 r = MsiSummaryInfoSetProperty( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
284 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
286 r = MsiSummaryInfoSetProperty( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
287 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
289 r = MsiSummaryInfoSetProperty( hsi, 9, VT_LPSTR, 0, NULL, "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}" );
290 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
292 r = MsiSummaryInfoSetProperty( hsi, 14, VT_I4, 100, NULL, NULL );
293 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
295 r = MsiSummaryInfoSetProperty( hsi, 15, VT_I4, 0, NULL, NULL );
296 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
298 r = MsiSummaryInfoPersist( hsi );
299 ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
301 r = MsiCloseHandle( hsi );
302 ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
304 r = MsiCloseHandle( hdb );
305 ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
308 static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
313 r = MsiOpenDatabaseA( filename, MSIDBOPEN_CREATE, &hdb );
314 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
316 /* import the tables into the database */
317 for (i = 0; i < num_tables; i++)
319 const struct msi_table *table = &tables[i];
321 write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
323 r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
324 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
326 DeleteFileA( table->filename );
329 r = MsiDatabaseCommit( hdb );
330 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
332 MsiCloseHandle( hdb );
333 set_suminfo( filename );
336 /* data for generating a patch */
338 /* table names - encoded as in an msi database file */
339 static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
340 static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
341 static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
342 static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
343 static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
344 static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
345 static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
346 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
347 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
348 /* substorage names */
349 static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
350 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
351 static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
352 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
354 /* data in each table */
355 static const WCHAR p_data0[] = { /* _Columns */
356 0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
357 0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
359 static const WCHAR p_data1[] = { /* _Tables */
362 static const char p_data2[] = { /* _StringData */
363 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
365 static const WCHAR p_data3[] = { /* _StringPool */
367 0, 0, /* string 0 '' */
368 16, 5, /* string 1 'MsiPatchSequence' */
369 11, 1, /* string 2 'PatchFamily' */
370 11, 1, /* string 3 'ProductCode' */
371 8, 1, /* string 4 'Sequence' */
372 10, 1, /* string 5 'Attributes' */
373 15, 1, /* string 6 '1.1.19388.37230' */
374 32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
376 static const char p_data4[] = { /* CAB_msitest */
377 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00,
378 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
379 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9e,
380 0x03, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x12,
381 0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
382 0x3c, 0xd4, 0x80, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
383 0x74, 0x78, 0x74, 0x00, 0x0b, 0x3c, 0xd6, 0xc1, 0x4a, 0x00, 0xea,
384 0x03, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x10, 0xa1, 0x3e, 0x00, 0x00,
385 0x00, 0x00, 0x03, 0x00, 0x40, 0x30, 0x0c, 0x43, 0xf8, 0xb4, 0x85,
386 0x4d, 0x96, 0x08, 0x0a, 0x92, 0xf0, 0x52, 0xfb, 0xbb, 0x82, 0xf9,
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x31, 0x7d,
388 0x56, 0xdf, 0xf7, 0x48, 0x7c, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x41, 0x80, 0xdf, 0xf7, 0xd8, 0x72, 0xbf, 0xb9, 0x63,
390 0x91, 0x0e, 0x57, 0x1f, 0xfa, 0x1a, 0x66, 0x54, 0x55
392 static const WCHAR p_data5[] = { /* MsiPatchSequence */
393 0x0007, 0x0000, 0x0006, 0x8000
395 static const char p_data6[] = { /* SummaryInformation */
396 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
399 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
400 0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
401 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
402 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
403 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
404 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
405 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
406 0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
407 0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
408 0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
409 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
410 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
411 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
412 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
413 0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
414 0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
415 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
416 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
417 0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
418 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
419 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
420 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
429 static const struct table_data table_patch_data[] = {
430 { p_name0, p_data0, sizeof p_data0 },
431 { p_name1, p_data1, sizeof p_data1 },
432 { p_name2, p_data2, sizeof p_data2 - 1 },
433 { p_name3, p_data3, sizeof p_data3 },
434 { p_name4, p_data4, sizeof p_data4 },
435 { p_name5, p_data5, sizeof p_data5 },
436 { p_name6, p_data6, sizeof p_data6 }
439 #define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
441 static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
442 static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
443 static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
444 static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
445 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
446 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
448 static const WCHAR t1_data0[] = { /* File */
449 0x0008, 0x0001, 0x03ea, 0x8000
451 static const char t1_data1[] = { /* _StringData */
454 static const WCHAR t1_data2[] = { /* _StringPool */
456 0, 0, /* string 0 '' */
457 9, 1, /* string 1 'patch.txt' */
459 static const char t1_data3[] = { /* SummaryInformation */
460 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
462 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
463 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
464 0x30, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
465 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
466 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
467 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
468 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
469 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
470 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
471 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
472 0x04, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00,
473 0x00, 0x10, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x1e, 0x00,
474 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
475 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
476 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
477 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
478 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
479 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
480 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
481 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
482 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
484 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31,
486 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06,
487 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00,
488 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 0x39, 0x31,
489 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
490 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
491 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
492 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x39, 0x31,
493 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
494 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
495 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
496 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x41, 0x32,
497 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45, 0x32, 0x43,
498 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30, 0x39, 0x2d,
499 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35, 0x46, 0x34,
500 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
501 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x09
504 static const struct table_data table_transform1_data[] = {
505 { t1_name0, t1_data0, sizeof t1_data0 },
506 { t1_name1, t1_data1, sizeof t1_data1 - 1 },
507 { t1_name2, t1_data2, sizeof t1_data2 },
508 { t1_name3, t1_data3, sizeof t1_data3 }
511 #define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
513 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
514 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
515 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
516 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
517 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
518 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
519 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
520 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
521 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
522 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
523 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
524 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
525 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
527 static const WCHAR t2_data0[] = { /* File */
528 0x00c0, 0x0001, 0x9000, 0x83e8
530 static const WCHAR t2_data1[] = { /* Media */
531 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
533 static const WCHAR t2_data2[] = { /* _Columns */
534 0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
535 0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
536 0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
537 0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
538 0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
539 0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
542 static const WCHAR t2_data3[] = { /* _Tables */
543 0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
545 static const WCHAR t2_data4[] = { /* Property */
546 0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
548 static const WCHAR t2_data5[] = { /* PatchPackage */
549 0x0201, 0x0013, 0x8002
551 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
552 0x0301, 0x0006, 0x0000, 0x87d1
554 static const char t2_data7[] = { /* _StringData */
555 "patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
556 "PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
557 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
559 static const WCHAR t2_data8[] = { /* _StringPool */
561 0, 0, /* string 0 '' */
562 9, 1, /* string 1 'patch.txt' */
563 22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
564 21, 1, /* string 3 'Installation Database' */
565 19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
566 38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
567 10, 1, /* string 6 'PatchFiles' */
568 12, 1, /* string 7 '#CAB_msitest' */
569 4, 1, /* string 8 'prop' */
570 5, 7, /* string 9 'Patch' */
571 5, 1, /* string 10 'File_' */
572 8, 1, /* string 11 'Sequence' */
573 9, 1, /* string 12 'PatchSize' */
574 10, 1, /* string 13 'Attributes' */
575 6, 2, /* string 14 'Header' */
576 10, 1, /* string 15 'StreamRef_' */
577 12, 3, /* string 16 'PatchPackage' */
578 7, 1, /* string 17 'PatchId' */
579 6, 1, /* string 18 'Media_' */
580 38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
581 15, 3, /* string 20 'MsiPatchHeaders' */
582 9, 1 /* string 21 'StreamRef' */
584 static const char t2_data9[] = { /* SummaryInformation */
585 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
588 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
589 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
590 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
591 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
592 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
593 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
594 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
595 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
596 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
597 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
598 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
600 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
601 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
605 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
606 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
608 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
609 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
610 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
611 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
612 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
613 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
614 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
615 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
616 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
617 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
618 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
619 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
620 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
623 static const struct table_data table_transform2_data[] = {
624 { t2_name0, t2_data0, sizeof t2_data0 },
625 { t2_name1, t2_data1, sizeof t2_data1 },
626 { t2_name2, t2_data2, sizeof t2_data2 },
627 { t2_name3, t2_data3, sizeof t2_data3 },
628 { t2_name4, t2_data4, sizeof t2_data4 },
629 { t2_name5, t2_data5, sizeof t2_data5 },
630 { t2_name6, t2_data6, sizeof t2_data6 },
631 { t2_name7, t2_data7, sizeof t2_data7 - 1 },
632 { t2_name8, t2_data8, sizeof t2_data8 },
633 { t2_name9, t2_data9, sizeof t2_data9 }
636 #define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
638 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
644 for (i = 0; i < num_tables; i++)
646 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
649 ok( 0, "failed to create stream 0x%08x\n", r );
653 r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
654 if (FAILED( r ) || count != tables[i].size)
655 ok( 0, "failed to write stream\n" );
656 IStream_Release( stm );
660 static void create_patch( const char *filename )
662 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
666 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
668 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
669 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
671 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
672 filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
673 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
675 r = StgCreateDocfile( filenameW, mode, 0, &stg );
676 HeapFree( GetProcessHeap(), 0, filenameW );
677 ok( r == S_OK, "failed to create storage 0x%08x\n", r );
681 r = IStorage_SetClass( stg, &CLSID_MsiPatch );
682 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
684 write_tables( stg, table_patch_data, NUM_PATCH_TABLES );
686 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
687 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
689 r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
690 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
692 write_tables( stg1, table_transform1_data, NUM_TRANSFORM1_TABLES );
693 IStorage_Release( stg1 );
695 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
696 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
698 r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
699 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
701 write_tables( stg2, table_transform2_data, NUM_TRANSFORM2_TABLES );
702 IStorage_Release( stg2 );
703 IStorage_Release( stg );
706 static void test_simple_patch( void )
710 char path[MAX_PATH], install_source[MAX_PATH], buffer[32];
712 MSIHANDLE hpackage, hdb, hview, hrec;
714 if (!pMsiApplyPatchA)
716 win_skip("MsiApplyPatchA is not available\n");
719 if (is_process_limited())
721 skip("process is limited\n");
725 CreateDirectoryA( "msitest", NULL );
726 create_file( "msitest\\patch.txt", 1000 );
728 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
729 create_patch( mspfile );
731 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
733 r = MsiInstallProductA( msifile, NULL );
734 if (r != ERROR_SUCCESS)
736 skip("Product installation failed with error code %u\n", r);
740 size = get_pf_file_size( "msitest\\patch.txt" );
741 ok( size == 1000, "expected 1000, got %u\n", size );
743 size = sizeof(install_source);
744 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
745 "InstallSource", install_source, &size );
746 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
748 strcpy( path, CURR_DIR );
749 strcat( path, "\\" );
750 strcat( path, msifile );
752 r = MsiOpenPackageA( path, &hpackage );
753 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
755 hdb = MsiGetActiveDatabase( hpackage );
756 ok( hdb, "failed to get database handle\n" );
758 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
759 r = MsiDatabaseOpenView( hdb, query, &hview );
760 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
762 r = MsiViewExecute( hview, 0 );
763 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
765 r = MsiViewFetch( hview, &hrec );
766 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
768 MsiCloseHandle( hrec );
769 MsiViewClose( hview );
770 MsiCloseHandle( hview );
772 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
773 "AND `Value` = 'Installer Database'";
774 r = MsiDatabaseOpenView( hdb, query, &hview );
775 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
777 r = MsiViewExecute( hview, 0 );
778 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
780 r = MsiViewFetch( hview, &hrec );
781 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
783 MsiCloseHandle( hrec );
784 MsiViewClose( hview );
785 MsiCloseHandle( hview );
788 size = sizeof(buffer);
789 r = MsiGetProperty( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
790 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
791 ok( !strcmp( buffer, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer );
793 MsiCloseHandle( hdb );
794 MsiCloseHandle( hpackage );
796 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
797 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
798 "expected ERROR_SUCCESS, got %u\n", r );
800 if (r == ERROR_PATCH_PACKAGE_INVALID)
802 win_skip("Windows Installer < 3.0 detected\n");
806 size = get_pf_file_size( "msitest\\patch.txt" );
807 ok( size == 1002, "expected 1002, got %u\n", size );
809 /* show that MsiOpenPackage applies registered patches */
810 r = MsiOpenPackageA( path, &hpackage );
811 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
813 hdb = MsiGetActiveDatabase( hpackage );
814 ok( hdb, "failed to get database handle\n" );
816 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
817 r = MsiDatabaseOpenView( hdb, query, &hview );
818 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
820 r = MsiViewExecute( hview, 0 );
821 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
823 r = MsiViewFetch( hview, &hrec );
824 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
826 MsiCloseHandle( hrec );
827 MsiViewClose( hview );
828 MsiCloseHandle( hview );
830 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
831 "AND `Value` = 'Installation Database'";
832 r = MsiDatabaseOpenView( hdb, query, &hview );
833 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
835 r = MsiViewExecute( hview, 0 );
836 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
838 r = MsiViewFetch( hview, &hrec );
839 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
841 MsiCloseHandle( hrec );
842 MsiViewClose( hview );
843 MsiCloseHandle( hview );
846 size = sizeof(buffer);
847 r = MsiGetProperty( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
848 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
849 ok( !strcmp( buffer, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer );
851 MsiCloseHandle( hdb );
852 MsiCloseHandle( hpackage );
854 /* show that patches are not committed to the local package database */
856 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
857 "LocalPackage", path, &size );
858 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
860 r = MsiOpenDatabaseA( path, MSIDBOPEN_READONLY, &hdb );
861 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
863 r = MsiDatabaseOpenView( hdb, query, &hview );
864 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
866 r = MsiViewExecute( hview, 0 );
867 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
869 r = MsiViewFetch( hview, &hrec );
870 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
872 MsiCloseHandle( hrec );
873 MsiViewClose( hview );
874 MsiCloseHandle( hview );
875 MsiCloseHandle( hdb );
879 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
880 "InstallSource", path, &size );
881 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
882 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
884 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
885 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
887 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
888 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
891 DeleteFileA( msifile );
892 DeleteFileA( mspfile );
893 DeleteFileA( "msitest\\patch.txt" );
894 RemoveDirectoryA( "msitest" );
897 static void test_MsiOpenDatabase( void )
902 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE, &hdb );
903 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
905 r = MsiDatabaseCommit( hdb );
906 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
907 MsiCloseHandle( hdb );
909 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
910 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
911 DeleteFileA( mspfile );
913 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
914 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
916 r = MsiDatabaseCommit( hdb );
917 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
918 MsiCloseHandle( hdb );
920 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
921 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
922 MsiCloseHandle( hdb );
923 DeleteFileA( mspfile );
925 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
926 create_patch( mspfile );
928 r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
929 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
931 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
932 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
933 MsiCloseHandle( hdb );
935 DeleteFileA( msifile );
936 DeleteFileA( mspfile );
939 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
941 static char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
944 MSIHANDLE hview, hrec;
946 sprintf( query, fmt, table, entry );
947 r = MsiDatabaseOpenView( hdb, query, &hview );
948 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
950 r = MsiViewExecute( hview, 0 );
951 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
953 r = MsiViewFetch( hview, &hrec );
954 MsiViewClose( hview );
955 MsiCloseHandle( hview );
956 MsiCloseHandle( hrec );
960 static void test_system_tables( void )
964 MSIHANDLE hproduct, hdb, hview, hrec;
966 if (!pMsiApplyPatchA)
968 win_skip("MsiApplyPatchA is not available\n");
971 if (is_process_limited())
973 skip("process is limited\n");
977 CreateDirectoryA( "msitest", NULL );
978 create_file( "msitest\\patch.txt", 1000 );
980 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
981 create_patch( mspfile );
983 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
985 r = MsiInstallProductA( msifile, NULL );
986 if (r != ERROR_SUCCESS)
988 skip("Product installation failed with error code %d\n", r);
992 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
993 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
995 hdb = MsiGetActiveDatabase( hproduct );
996 ok( hdb, "failed to get database handle\n" );
998 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
999 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1001 query = "SELECT * FROM `_Storages`";
1002 r = MsiDatabaseOpenView( hdb, query, &hview );
1003 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1005 r = MsiViewExecute( hview, 0 );
1006 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1008 r = MsiViewFetch( hview, &hrec );
1009 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1011 r = find_entry( hdb, "_Tables", "Directory" );
1012 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1014 r = find_entry( hdb, "_Tables", "File" );
1015 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1017 r = find_entry( hdb, "_Tables", "Component" );
1018 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1020 r = find_entry( hdb, "_Tables", "Feature" );
1021 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1023 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1024 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1026 r = find_entry( hdb, "_Tables", "Property" );
1027 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1029 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1030 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1032 r = find_entry( hdb, "_Tables", "Media" );
1033 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1035 r = find_entry( hdb, "_Tables", "_Property" );
1036 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1038 MsiCloseHandle( hrec );
1039 MsiViewClose( hview );
1040 MsiCloseHandle( hview );
1041 MsiCloseHandle( hdb );
1042 MsiCloseHandle( hproduct );
1044 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1045 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1046 "expected ERROR_SUCCESS, got %u\n", r );
1048 if (r == ERROR_PATCH_PACKAGE_INVALID)
1050 win_skip("Windows Installer < 3.0 detected\n");
1054 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1055 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1057 hdb = MsiGetActiveDatabase( hproduct );
1058 ok( hdb, "failed to get database handle\n" );
1060 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1061 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1063 query = "SELECT * FROM `_Storages`";
1064 r = MsiDatabaseOpenView( hdb, query, &hview );
1065 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1067 r = MsiViewExecute( hview, 0 );
1068 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1070 r = MsiViewFetch( hview, &hrec );
1071 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1073 r = find_entry( hdb, "_Tables", "Directory" );
1074 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1076 r = find_entry( hdb, "_Tables", "File" );
1077 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1079 r = find_entry( hdb, "_Tables", "Component" );
1080 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1082 r = find_entry( hdb, "_Tables", "Feature" );
1083 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1085 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1086 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1088 r = find_entry( hdb, "_Tables", "Property" );
1089 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1091 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1092 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1094 r = find_entry( hdb, "_Tables", "Media" );
1095 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1097 r = find_entry( hdb, "_Tables", "_Property" );
1098 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1100 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1101 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1103 r = find_entry( hdb, "_Tables", "Patch" );
1104 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1106 r = find_entry( hdb, "_Tables", "PatchPackage" );
1107 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1109 MsiCloseHandle( hrec );
1110 MsiViewClose( hview );
1111 MsiCloseHandle( hview );
1112 MsiCloseHandle( hdb );
1113 MsiCloseHandle( hproduct );
1116 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1117 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1120 DeleteFileA( msifile );
1121 DeleteFileA( mspfile );
1122 DeleteFileA( "msitest\\patch.txt" );
1123 RemoveDirectoryA( "msitest" );
1126 static void test_patch_registration( void )
1129 char buffer[MAX_PATH], patch_code[39];
1131 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1133 win_skip("required functions not available\n");
1136 if (is_process_limited())
1138 skip("process is limited\n");
1142 CreateDirectoryA( "msitest", NULL );
1143 create_file( "msitest\\patch.txt", 1000 );
1145 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1146 create_patch( mspfile );
1148 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1150 r = MsiInstallProductA( msifile, NULL );
1151 if (r != ERROR_SUCCESS)
1153 skip("Product installation failed with error code %d\n", r);
1157 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1158 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1159 "expected ERROR_SUCCESS, got %u\n", r );
1161 if (r == ERROR_PATCH_PACKAGE_INVALID)
1163 win_skip("Windows Installer < 3.0 detected\n");
1168 size = sizeof(buffer);
1169 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1170 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1171 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1172 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1173 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1174 ok( buffer[0], "buffer empty\n" );
1177 size = sizeof(buffer);
1178 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1179 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1180 NULL, MSIINSTALLCONTEXT_MACHINE,
1181 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1182 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1185 size = sizeof(buffer);
1186 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1187 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1188 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1189 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1190 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1191 ok( !buffer[0], "got %s\n", buffer );
1193 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1194 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1195 0, patch_code, NULL, NULL, NULL, NULL );
1196 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1197 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1199 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1200 NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1201 0, patch_code, NULL, NULL, NULL, NULL );
1202 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1204 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1205 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1206 0, patch_code, NULL, NULL, NULL, NULL );
1207 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1210 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1211 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1214 size = sizeof(buffer);
1215 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1216 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1217 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1218 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1219 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1222 DeleteFileA( msifile );
1223 DeleteFileA( mspfile );
1224 DeleteFileA( "msitest\\patch.txt" );
1225 RemoveDirectoryA( "msitest" );
1231 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1233 init_function_pointers();
1235 GetCurrentDirectoryA( MAX_PATH, prev_path );
1236 GetTempPath( MAX_PATH, temp_path );
1237 SetCurrentDirectoryA( temp_path );
1239 strcpy( CURR_DIR, temp_path );
1240 len = strlen( CURR_DIR );
1242 if (len && (CURR_DIR[len - 1] == '\\'))
1243 CURR_DIR[len - 1] = 0;
1245 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1247 test_simple_patch();
1248 test_MsiOpenDatabase();
1249 test_system_tables();
1250 test_patch_registration();
1252 SetCurrentDirectoryA( prev_path );