1 /* 2 * Copyright 2010 Hans Leidekker for CodeWeavers 3 * 4 * A test program for patching MSI products. 5 * 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. 10 * 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. 15 * 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 19 */ 20 21 #define _WIN32_MSI 300 22 #define COBJMACROS 23 24 #include <stdio.h> 25 26 #include <windows.h> 27 #include <msiquery.h> 28 #include <msidefs.h> 29 #include <msi.h> 30 #include <wtypes.h> 31 32 #include "wine/test.h" 33 #include "utils.h" 34 35 static const char *msifile = "winetest-patch.msi"; 36 static const char *mspfile = "winetest-patch.msp"; 37 static const WCHAR msifileW[] = L"winetest-patch.msi"; 38 static const WCHAR mspfileW[] = L"winetest-patch.msp"; 39 40 /* msi database data */ 41 42 static const char property_dat[] = 43 "Property\tValue\n" 44 "s72\tl0\n" 45 "Property\tProperty\n" 46 "Manufacturer\tWineHQ\n" 47 "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n" 48 "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n" 49 "ProductLanguage\t1033\n" 50 "ProductName\tmsitest\n" 51 "ProductVersion\t1.1.1\n" 52 "PATCHNEWSUMMARYSUBJECT\tInstaller Database\n" 53 "MSIFASTINSTALL\t1\n"; 54 55 static const char media_dat[] = 56 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n" 57 "i2\ti4\tL64\tS255\tS32\tS72\n" 58 "Media\tDiskId\n" 59 "1\t1\t\t\tDISK1\t\n"; 60 61 static const char file_dat[] = 62 "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" 63 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" 64 "File\tFile\n" 65 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n" 66 "disable.txt\tdisable\tdisable.txt\t1000\t\t\t0\t1\n"; 67 68 static const char directory_dat[] = 69 "Directory\tDirectory_Parent\tDefaultDir\n" 70 "s72\tS72\tl255\n" 71 "Directory\tDirectory\n" 72 "MSITESTDIR\tProgramFilesFolder\tmsitest\n" 73 "ProgramFilesFolder\tTARGETDIR\t.\n" 74 "TARGETDIR\t\tSourceDir"; 75 76 static const char component_dat[] = 77 "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" 78 "s72\tS38\ts72\ti2\tS255\tS72\n" 79 "Component\tComponent\n" 80 "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n" 81 "disable\t{BDDBA0EE-0031-4591-ADC0-33308175AC19}\tMSITESTDIR\t0\t\tdisable.txt\n"; 82 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" 86 "Feature\tFeature\n" 87 "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n" 88 "disable\t\t\tdisabled feature\t1\t1\tMSITESTDIR\t0\n"; 89 90 static const char feature_comp_dat[] = 91 "Feature_\tComponent_\n" 92 "s38\ts72\n" 93 "FeatureComponents\tFeature_\tComponent_\n" 94 "patch\tpatch\n" 95 "disable\tdisable\n"; 96 97 static const char install_exec_seq_dat[] = 98 "Action\tCondition\tSequence\n" 99 "s72\tS255\tI2\n" 100 "InstallExecuteSequence\tAction\n" 101 "LaunchConditions\t\t100\n" 102 "CostInitialize\t\t800\n" 103 "FileCost\t\t900\n" 104 "CostFinalize\t\t1000\n" 105 "InstallValidate\t\t1400\n" 106 "InstallInitialize\t\t1500\n" 107 "ProcessComponents\t\t1600\n" 108 "RemoveFiles\t\t1700\n" 109 "InstallFiles\t\t2000\n" 110 "RegisterUser\t\t3000\n" 111 "RegisterProduct\t\t3100\n" 112 "PublishFeatures\t\t5100\n" 113 "PublishProduct\t\t5200\n" 114 "UnpublishFeatures\t\t5300\n" 115 "InstallFinalize\t\t6000\n"; 116 117 static const char condition_dat[] = 118 "Feature_\tLevel\tCondition\n" 119 "s38\ti2\tS255\n" 120 "Condition\tFeature_\tLevel\n" 121 "disable\t0\tDISABLE_FEATURE\n"; 122 123 struct msi_table 124 { 125 const char *filename; 126 const char *data; 127 int size; 128 }; 129 130 static const struct msi_table tables[] = 131 { 132 ADD_TABLE( directory ), 133 ADD_TABLE( file ), 134 ADD_TABLE( component ), 135 ADD_TABLE( feature ), 136 ADD_TABLE( feature_comp ), 137 ADD_TABLE( property ), 138 ADD_TABLE( install_exec_seq ), 139 ADD_TABLE( media ), 140 ADD_TABLE( condition ) 141 }; 142 143 static BOOL get_program_files_dir( char *buf, char *buf2 ) 144 { 145 HKEY hkey; 146 DWORD type, size; 147 148 if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey )) 149 return FALSE; 150 151 size = MAX_PATH; 152 if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) && 153 RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size )) 154 { 155 RegCloseKey( hkey ); 156 return FALSE; 157 } 158 size = MAX_PATH; 159 if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size )) 160 { 161 RegCloseKey( hkey ); 162 return FALSE; 163 } 164 RegCloseKey( hkey ); 165 return TRUE; 166 } 167 168 static DWORD get_pf_file_size( const char *filename ) 169 { 170 char path[MAX_PATH]; 171 HANDLE file; 172 DWORD size; 173 174 strcpy( path, PROG_FILES_DIR ); 175 strcat( path, "\\"); 176 strcat( path, filename ); 177 178 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); 179 if (file == INVALID_HANDLE_VALUE) 180 return INVALID_FILE_SIZE; 181 182 size = GetFileSize( file, NULL ); 183 CloseHandle( file ); 184 return size; 185 } 186 187 static void write_file( const char *filename, const char *data, DWORD data_size ) 188 { 189 DWORD size; 190 HANDLE file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, 191 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); 192 WriteFile( file, data, data_size, &size, NULL ); 193 CloseHandle( file ); 194 } 195 196 static void set_suminfo( const WCHAR *filename ) 197 { 198 UINT r; 199 MSIHANDLE hsi, hdb; 200 201 r = MsiOpenDatabaseW( filename, MSIDBOPEN_DIRECT, &hdb ); 202 ok( r == ERROR_SUCCESS, "failed to open database %u\n", r ); 203 204 r = MsiGetSummaryInformationA( hdb, NULL, 7, &hsi ); 205 ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r ); 206 207 r = MsiSummaryInfoSetPropertyA( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" ); 208 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r ); 209 210 r = MsiSummaryInfoSetPropertyA( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" ); 211 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r ); 212 213 r = MsiSummaryInfoSetPropertyA( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" ); 214 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r ); 215 216 r = MsiSummaryInfoSetPropertyA( hsi, 7, VT_LPSTR, 0, NULL, ";1033" ); 217 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r ); 218 219 r = MsiSummaryInfoSetPropertyA( hsi, 9, VT_LPSTR, 0, NULL, "{E528DDD6-4801-4BEC-BBB6-C5EE0FD097E9}" ); 220 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r ); 221 222 r = MsiSummaryInfoSetPropertyA( hsi, 14, VT_I4, 100, NULL, NULL ); 223 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r ); 224 225 r = MsiSummaryInfoSetPropertyA( hsi, 15, VT_I4, 0, NULL, NULL ); 226 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r ); 227 228 r = MsiSummaryInfoPersist( hsi ); 229 ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r ); 230 231 r = MsiCloseHandle( hsi ); 232 ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r ); 233 234 r = MsiCloseHandle( hdb ); 235 ok( r == ERROR_SUCCESS, "failed to close database %u\n", r ); 236 } 237 238 static void create_database_suminfo( const char *filename, const struct msi_table *tables, UINT num_tables ) 239 { 240 MSIHANDLE hdb; 241 UINT r, i; 242 WCHAR *filenameW; 243 int len; 244 245 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 ); 246 if (!(filenameW = malloc( len * sizeof(WCHAR) ))) return; 247 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len ); 248 249 r = MsiOpenDatabaseW( filenameW, MSIDBOPEN_CREATE, &hdb ); 250 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r); 251 252 /* import the tables into the database */ 253 for (i = 0; i < num_tables; i++) 254 { 255 const struct msi_table *table = &tables[i]; 256 257 write_file( table->filename, table->data, (table->size - 1) * sizeof(char) ); 258 259 r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename ); 260 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r); 261 262 DeleteFileA( table->filename ); 263 } 264 265 r = MsiDatabaseCommit( hdb ); 266 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r); 267 268 MsiCloseHandle( hdb ); 269 set_suminfo( filenameW ); 270 free( filenameW ); 271 } 272 273 /* data for generating a patch */ 274 275 /* table names - encoded as in an msi database file */ 276 static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */ 277 static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */ 278 static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */ 279 static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */ 280 static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */ 281 static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */ 282 static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072, 283 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d, 284 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */ 285 /* substorage names */ 286 static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070, 287 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */ 288 static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 289 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */ 290 291 /* data in each table */ 292 static const WCHAR p_data0[] = { /* _Columns */ 293 0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004, 294 0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502 295 }; 296 static const WCHAR p_data1[] = { /* _Tables */ 297 0x0001 298 }; 299 static const char p_data2[] = { /* _StringData */ 300 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74" 301 }; 302 static const WCHAR p_data3[] = { /* _StringPool */ 303 /* len, refs */ 304 0, 0, /* string 0 '' */ 305 16, 5, /* string 1 'MsiPatchSequence' */ 306 11, 1, /* string 2 'PatchFamily' */ 307 11, 1, /* string 3 'ProductCode' */ 308 8, 1, /* string 4 'Sequence' */ 309 10, 1, /* string 5 'Attributes' */ 310 15, 1, /* string 6 '1.1.19388.37230' */ 311 32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */ 312 }; 313 static const char p_data4[] = { /* CAB_msitest */ 314 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 315 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 316 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 317 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 318 0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 319 0x3c, 0xd4, 0xb8, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e, 320 0x74, 0x78, 0x74, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xea, 0x03, 0x00, 321 0x00, 0x00, 0x00, 0xcb, 0x50, 0x17, 0x7e, 0x20, 0x00, 0x66, 0x69, 322 0x6c, 0x65, 0x2e, 0x74, 0x78, 0x74, 0x00, 0xb0, 0xb2, 0xb2, 0x25, 323 0x2d, 0x00, 0xd2, 0x07, 0x43, 0x4b, 0xcb, 0x2d, 0xce, 0x2c, 0x49, 324 0x2d, 0x2e, 0x89, 0x29, 0x48, 0x2c, 0x49, 0xce, 0x48, 0x4d, 0xd1, 325 0x2b, 0xa9, 0x28, 0x51, 0x18, 0x05, 0xa3, 0x60, 0x14, 0x0c, 0x37, 326 0x90, 0x8b, 0x9c, 0xd3, 0x41, 0xf9, 0x9c, 0x61, 0x14, 0x8c, 0x82, 327 0x51, 0x30, 0xdc, 0x00, 0x00 328 }; 329 static const WCHAR p_data5[] = { /* MsiPatchSequence */ 330 0x0007, 0x0000, 0x0006, 0x8000 331 }; 332 static const char p_data6[] = { /* SummaryInformation */ 333 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 335 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9, 336 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9, 337 0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 338 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 339 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90, 340 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 341 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 342 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43, 343 0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33, 344 0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39, 345 0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00, 346 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39, 347 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 348 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 349 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 350 0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00, 351 0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 352 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23, 353 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67, 354 0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 355 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68, 356 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00, 357 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 358 }; 359 360 struct table_data { 361 LPCWSTR name; 362 const void *data; 363 DWORD size; 364 }; 365 366 static const struct table_data table_patch_data[] = { 367 { p_name0, p_data0, sizeof p_data0 }, 368 { p_name1, p_data1, sizeof p_data1 }, 369 { p_name2, p_data2, sizeof p_data2 - 1 }, 370 { p_name3, p_data3, sizeof p_data3 }, 371 { p_name4, p_data4, sizeof p_data4 }, 372 { p_name5, p_data5, sizeof p_data5 }, 373 { p_name6, p_data6, sizeof p_data6 } 374 }; 375 376 static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */ 377 static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */ 378 static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */ 379 static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072, 380 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d, 381 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */ 382 383 static const WCHAR t1_data0[] = { /* File */ 384 0x0008, 0x0001, 0x03ea, 0x8000 385 }; 386 static const char t1_data1[] = { /* _StringData */ 387 "patch.txt" 388 }; 389 static const WCHAR t1_data2[] = { /* _StringPool */ 390 /* len, refs */ 391 0, 0, /* string 0 '' */ 392 9, 1, /* string 1 'patch.txt' */ 393 }; 394 static const char t1_data3[] = { /* SummaryInformation */ 395 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 397 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9, 398 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9, 399 0x30, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 400 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 401 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8, 402 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 403 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 404 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00, 405 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08, 406 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 407 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00, 408 0x00, 0x10, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x1e, 0x00, 409 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 410 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 411 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 412 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 413 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61, 414 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 415 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00, 416 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 417 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 418 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 419 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 420 0x00, 0x1e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x78, 0x38, 421 0x36, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00, 422 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 423 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 424 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 425 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 426 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 427 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 428 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 429 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 430 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 431 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 432 0x7b, 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 433 0x45, 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 434 0x30, 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 435 0x35, 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 436 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 437 0x09 438 }; 439 440 static const struct table_data table_transform1_data[] = { 441 { t1_name0, t1_data0, sizeof t1_data0 }, 442 { t1_name1, t1_data1, sizeof t1_data1 - 1 }, 443 { t1_name2, t1_data2, sizeof t1_data2 }, 444 { t1_name3, t1_data3, sizeof t1_data3 } 445 }; 446 447 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */ 448 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */ 449 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */ 450 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */ 451 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */ 452 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */ 453 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626, 454 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */ 455 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */ 456 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */ 457 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072, 458 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d, 459 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */ 460 static const WCHAR t2_name10[] = { 0x4840, 0x420f, 0x45e4, 0x4578, 0x3b28, 0x4432, 0x44b3, 461 0x4231, 0x45f1, 0x4836, 0 }; /* FeatureComponents */ 462 static const WCHAR t2_name11[] = { 0x4840, 0x448c, 0x44f0, 0x4472, 0x4468, 0x4837, 0 }; /* Component */ 463 static const WCHAR t2_name12[] = { 0x4840, 0x420f, 0x45e4, 0x4578, 0x4828, 0 }; /* Feature */ 464 465 static const WCHAR t2_data0[] = { /* File */ 466 0x00c0, 0x0001, 0x9000, 0x83e8, 0x0801, 0x0002, 0x0003, 0x0002, 467 0x03e8, 0x8000, 0x0000, 0x0000, 0x9000, 0x83e9 468 }; 469 static const WCHAR t2_data1[] = { /* Media */ 470 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x000d, 0x0000, 0x000e 471 }; 472 static const WCHAR t2_data2[] = { /* _Columns */ 473 0x0401, 0x000f, 0x0000, 0x0010, 0xad48, 0x0401, 0x000f, 0x0000, /* 0x0401 = add row (1), 4 shorts */ 474 0x0011, 0xa502, 0x0401, 0x000f, 0x0000, 0x0012, 0x8104, 0x0401, 475 0x000f, 0x0000, 0x0013, 0x8502, 0x0401, 0x000f, 0x0000, 0x0014, 476 0x9900, 0x0401, 0x000f, 0x0000, 0x0015, 0x9d48, 0x0401, 0x0016, 477 0x0000, 0x0017, 0xad26, 0x0401, 0x0016, 0x0000, 0x0018, 0x8502, 478 0x0401, 0x001a, 0x0000, 0x001b, 0xad26, 0x0401, 0x001a, 0x0000, 479 0x0014, 0x8900 480 }; 481 static const WCHAR t2_data3[] = { /* _Tables */ 482 0x0101, 0x000f, 0x0101, 0x0016, 0x0101, 0x001a 483 }; 484 static const WCHAR t2_data4[] = { /* Property */ 485 0x0002, 0x0008, 0x0009, 0x0201, 0x000a, 0x000b 486 }; 487 static const WCHAR t2_data5[] = { /* PatchPackage */ 488 0x0201, 0x0019, 0x8002 489 }; 490 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */ 491 0x0301, 0x000c, 0x0000, 0x87d1 492 }; 493 static const char t2_data7[] = { /* _StringData */ 494 "patch.txtfile.txtfile{327d9640-674f-4b9f-8b8a-547a0f6f8518}MSITESTDIRnewnew featurePATCHNEWSUMMARYSUBJECT" 495 "Installation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}PatchFiles#CAB_msitestprop" 496 "PatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_" 497 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef" 498 }; 499 static const WCHAR t2_data8[] = { /* _StringPool */ 500 /* len, refs */ 501 0, 0, /* string 0 '' */ 502 9, 1, /* string 1 'patch.txt' */ 503 8, 3, /* string 2 'file.txt' */ 504 4, 3, /* string 3 'file' */ 505 38, 1, /* string 4 '{327d9640-674f-4b9f-8b8a-547a0f6f8518}' */ 506 10, 2, /* string 5 'MSITESTDIR' */ 507 3, 2, /* string 6 'new' */ 508 11, 1, /* string 7 'new feature' */ 509 22, 1, /* string 8 'PATCHNEWSUMMARYSUBJECT' */ 510 21, 1, /* string 9 'Installation Database' */ 511 19, 1, /* string 10 'PATCHNEWPACKAGECODE' */ 512 38, 1, /* string 11 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */ 513 10, 1, /* string 12 'PatchFiles' */ 514 12, 1, /* string 13 '#CAB_msitest' */ 515 4, 1, /* string 14 'prop' */ 516 5, 7, /* string 15 'Patch' */ 517 5, 1, /* string 16 'File_' */ 518 8, 1, /* string 17 'Sequence' */ 519 9, 1, /* string 18 'PatchSize' */ 520 10, 1, /* string 19 'Attributes' */ 521 6, 2, /* string 20 'Header' */ 522 10, 1, /* string 21 'StreamRef_' */ 523 12, 3, /* string 22 'PatchPackage' */ 524 7, 1, /* string 23 'PatchId' */ 525 6, 1, /* string 24 'Media_' */ 526 38, 1, /* string 25 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */ 527 15, 3, /* string 26 'MsiPatchHeaders' */ 528 9, 1 /* string 27 'StreamRef' */ 529 }; 530 static const char t2_data9[] = { /* SummaryInformation */ 531 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 532 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 533 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9, 534 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9, 535 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 536 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 537 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78, 538 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 539 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 540 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00, 541 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09, 542 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 543 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 544 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 545 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 546 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 547 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 548 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 550 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 551 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 552 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 553 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 554 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 555 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 556 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 557 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 558 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 559 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 560 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 561 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 562 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45, 563 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30, 564 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35, 565 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d, 566 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09 567 }; 568 static const WCHAR t2_data10[] = { /* FeatureComponents */ 569 0x0201, 0x0006, 0x0003 570 }; 571 static const WCHAR t2_data11[] = { /* Component */ 572 0x0601, 0x0003, 0x0004, 0x0005, 0x8000, 0x0000, 0x0002 573 }; 574 static const WCHAR t2_data12[] = { /* Feature */ 575 0x0801, 0x0006, 0x0000, 0x0000, 0x0007, 0x8001, 0x8001, 0x0005, 576 0x8000 577 }; 578 579 static const struct table_data table_transform2_data[] = { 580 { t2_name0, t2_data0, sizeof t2_data0 }, 581 { t2_name1, t2_data1, sizeof t2_data1 }, 582 { t2_name2, t2_data2, sizeof t2_data2 }, 583 { t2_name3, t2_data3, sizeof t2_data3 }, 584 { t2_name4, t2_data4, sizeof t2_data4 }, 585 { t2_name5, t2_data5, sizeof t2_data5 }, 586 { t2_name6, t2_data6, sizeof t2_data6 }, 587 { t2_name7, t2_data7, sizeof t2_data7 - 1 }, 588 { t2_name8, t2_data8, sizeof t2_data8 }, 589 { t2_name9, t2_data9, sizeof t2_data9 }, 590 { t2_name10, t2_data10, sizeof t2_data10 }, 591 { t2_name11, t2_data11, sizeof t2_data11 }, 592 { t2_name12, t2_data12, sizeof t2_data12 }, 593 }; 594 595 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables ) 596 { 597 IStream *stm; 598 DWORD i, count; 599 HRESULT r; 600 601 for (i = 0; i < num_tables; i++) 602 { 603 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm ); 604 if (FAILED( r )) 605 { 606 ok( 0, "failed to create stream %#lx\n", r ); 607 continue; 608 } 609 610 r = IStream_Write( stm, tables[i].data, tables[i].size, &count ); 611 if (FAILED( r ) || count != tables[i].size) 612 ok( 0, "failed to write stream\n" ); 613 IStream_Release( stm ); 614 } 615 } 616 617 static void create_patch( const char *filename ) 618 { 619 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL; 620 WCHAR *filenameW; 621 HRESULT r; 622 int len; 623 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE; 624 625 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}}; 626 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}}; 627 628 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 ); 629 filenameW = malloc( len * sizeof(WCHAR) ); 630 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len ); 631 632 r = StgCreateDocfile( filenameW, mode, 0, &stg ); 633 free( filenameW ); 634 ok( r == S_OK, "failed to create storage %#lx\n", r ); 635 if (!stg) 636 return; 637 638 r = IStorage_SetClass( stg, &CLSID_MsiPatch ); 639 ok( r == S_OK, "failed to set storage type %#lx\n", r ); 640 641 write_tables( stg, table_patch_data, ARRAY_SIZE( table_patch_data )); 642 643 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 ); 644 ok( r == S_OK, "failed to create substorage %#lx\n", r ); 645 646 r = IStorage_SetClass( stg1, &CLSID_MsiTransform ); 647 ok( r == S_OK, "failed to set storage type %#lx\n", r ); 648 649 write_tables( stg1, table_transform1_data, ARRAY_SIZE( table_transform1_data )); 650 IStorage_Release( stg1 ); 651 652 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 ); 653 ok( r == S_OK, "failed to create substorage %#lx\n", r ); 654 655 r = IStorage_SetClass( stg2, &CLSID_MsiTransform ); 656 ok( r == S_OK, "failed to set storage type %#lx\n", r ); 657 658 write_tables( stg2, table_transform2_data, ARRAY_SIZE( table_transform2_data )); 659 IStorage_Release( stg2 ); 660 IStorage_Release( stg ); 661 } 662 663 static void test_simple_patch( void ) 664 { 665 UINT r; 666 DWORD size; 667 char path[MAX_PATH], install_source[MAX_PATH], buffer[32]; 668 const char *query; 669 WCHAR pathW[MAX_PATH]; 670 MSIHANDLE hpackage, hdb, hview, hrec; 671 672 if (!is_process_elevated()) 673 { 674 skip("process is limited\n"); 675 return; 676 } 677 678 CreateDirectoryA( "msitest", NULL ); 679 create_file( "msitest\\patch.txt", 1000 ); 680 681 create_database_suminfo( msifile, tables, ARRAY_SIZE(tables) ); 682 create_patch( mspfile ); 683 684 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL ); 685 686 r = MsiInstallProductA( msifile, "DISABLE_FEATURE=1" ); 687 if (r != ERROR_SUCCESS) 688 { 689 skip("Product installation failed with error code %u\n", r); 690 goto cleanup; 691 } 692 693 size = get_pf_file_size( "msitest\\patch.txt" ); 694 ok( size == 1000, "expected 1000, got %lu\n", size ); 695 696 size = sizeof(install_source); 697 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 698 "InstallSource", install_source, &size ); 699 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 700 701 strcpy( path, CURR_DIR ); 702 strcat( path, "\\" ); 703 strcat( path, msifile ); 704 705 r = MsiOpenPackageA( path, &hpackage ); 706 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 707 708 hdb = MsiGetActiveDatabase( hpackage ); 709 ok( hdb, "failed to get database handle\n" ); 710 711 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'"; 712 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 713 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 714 715 r = MsiViewExecute( hview, 0 ); 716 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 717 718 r = MsiViewFetch( hview, &hrec ); 719 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r ); 720 721 MsiCloseHandle( hrec ); 722 MsiViewClose( hview ); 723 MsiCloseHandle( hview ); 724 725 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' " 726 "AND `Value` = 'Installer Database'"; 727 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 728 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 729 730 r = MsiViewExecute( hview, 0 ); 731 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 732 733 r = MsiViewFetch( hview, &hrec ); 734 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 735 736 MsiCloseHandle( hrec ); 737 MsiViewClose( hview ); 738 MsiCloseHandle( hview ); 739 740 buffer[0] = 0; 741 size = sizeof(buffer); 742 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size ); 743 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 744 ok( !strcmp( buffer, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer ); 745 746 MsiCloseHandle( hdb ); 747 MsiCloseHandle( hpackage ); 748 749 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL ); 750 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 751 752 size = get_pf_file_size( "msitest\\patch.txt" ); 753 ok( size == 1002, "expected 1002, got %lu\n", size ); 754 size = get_pf_file_size( "msitest\\file.txt" ); 755 ok( size == 1000, "expected 1000, got %lu\n", size ); 756 757 /* show that MsiOpenPackage applies registered patches */ 758 r = MsiOpenPackageA( path, &hpackage ); 759 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 760 761 hdb = MsiGetActiveDatabase( hpackage ); 762 ok( hdb, "failed to get database handle\n" ); 763 764 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'"; 765 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 766 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 767 768 r = MsiViewExecute( hview, 0 ); 769 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 770 771 r = MsiViewFetch( hview, &hrec ); 772 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 773 774 MsiCloseHandle( hrec ); 775 MsiViewClose( hview ); 776 MsiCloseHandle( hview ); 777 778 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' " 779 "AND `Value` = 'Installation Database'"; 780 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 781 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 782 783 r = MsiViewExecute( hview, 0 ); 784 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 785 786 r = MsiViewFetch( hview, &hrec ); 787 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 788 789 MsiCloseHandle( hrec ); 790 MsiViewClose( hview ); 791 MsiCloseHandle( hview ); 792 793 buffer[0] = 0; 794 size = sizeof(buffer); 795 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size ); 796 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 797 ok( !strcmp( buffer, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer ); 798 799 MsiCloseHandle( hdb ); 800 MsiCloseHandle( hpackage ); 801 802 /* show that patches are not committed to the local package database */ 803 size = sizeof(path); 804 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 805 "LocalPackage", path, &size ); 806 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 807 808 MultiByteToWideChar( CP_ACP, 0, path, -1, pathW, MAX_PATH ); 809 r = MsiOpenDatabaseW( pathW, MSIDBOPEN_READONLY, &hdb ); 810 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 811 812 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 813 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 814 815 r = MsiViewExecute( hview, 0 ); 816 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 817 818 r = MsiViewFetch( hview, &hrec ); 819 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r ); 820 821 MsiCloseHandle( hrec ); 822 MsiViewClose( hview ); 823 MsiCloseHandle( hview ); 824 MsiCloseHandle( hdb ); 825 826 size = sizeof(path); 827 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 828 "InstallSource", path, &size ); 829 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 830 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path ); 831 832 r = MsiInstallProductA( msifile, "REMOVE=ALL" ); 833 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 834 835 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" ); 836 ok( !delete_pf( "msitest\\file.txt", TRUE ), "file not removed\n" ); 837 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" ); 838 839 cleanup: 840 DeleteFileA( msifile ); 841 DeleteFileA( mspfile ); 842 DeleteFileA( "msitest\\patch.txt" ); 843 RemoveDirectoryA( "msitest" ); 844 } 845 846 static void test_MsiOpenDatabase( void ) 847 { 848 UINT r; 849 MSIHANDLE hdb; 850 851 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE, &hdb ); 852 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r); 853 854 r = MsiDatabaseCommit( hdb ); 855 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r); 856 MsiCloseHandle( hdb ); 857 858 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb ); 859 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r); 860 DeleteFileA( mspfile ); 861 862 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb ); 863 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r); 864 865 r = MsiDatabaseCommit( hdb ); 866 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r); 867 MsiCloseHandle( hdb ); 868 869 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb ); 870 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r); 871 MsiCloseHandle( hdb ); 872 DeleteFileA( mspfile ); 873 874 create_database_suminfo( msifile, tables, ARRAY_SIZE(tables) ); 875 create_patch( mspfile ); 876 877 r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb ); 878 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r ); 879 880 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb ); 881 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r ); 882 MsiCloseHandle( hdb ); 883 884 DeleteFileA( msifile ); 885 DeleteFileA( mspfile ); 886 } 887 888 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry ) 889 { 890 static const char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'"; 891 char query[0x100]; 892 UINT r; 893 MSIHANDLE hview, hrec; 894 895 sprintf( query, fmt, table, entry ); 896 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 897 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 898 899 r = MsiViewExecute( hview, 0 ); 900 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 901 902 r = MsiViewFetch( hview, &hrec ); 903 MsiViewClose( hview ); 904 MsiCloseHandle( hview ); 905 MsiCloseHandle( hrec ); 906 return r; 907 } 908 909 static UINT find_entryW( MSIHANDLE hdb, const WCHAR *table, const WCHAR *entry ) 910 { 911 WCHAR query[0x100]; 912 MSIHANDLE hview, hrec; 913 UINT r; 914 915 wsprintfW( query, L"SELECT * FROM `%s` WHERE `Name` = '%s'", table, entry ); 916 r = MsiDatabaseOpenViewW( hdb, query, &hview ); 917 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 918 919 r = MsiViewExecute( hview, 0 ); 920 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 921 922 r = MsiViewFetch( hview, &hrec ); 923 MsiViewClose( hview ); 924 MsiCloseHandle( hview ); 925 MsiCloseHandle( hrec ); 926 return r; 927 } 928 929 static INT get_integer( MSIHANDLE hdb, UINT field, const char *query) 930 { 931 UINT r; 932 INT ret = -1; 933 MSIHANDLE hview, hrec; 934 935 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 936 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 937 938 r = MsiViewExecute( hview, 0 ); 939 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 940 941 r = MsiViewFetch( hview, &hrec ); 942 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 943 if (r == ERROR_SUCCESS) 944 { 945 UINT r_tmp; 946 ret = MsiRecordGetInteger( hrec, field ); 947 MsiCloseHandle( hrec ); 948 949 r_tmp = MsiViewFetch( hview, &hrec ); 950 ok( r_tmp == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r); 951 } 952 953 MsiViewClose( hview ); 954 MsiCloseHandle( hview ); 955 return ret; 956 } 957 958 static char *get_string( MSIHANDLE hdb, UINT field, const char *query) 959 { 960 UINT r; 961 static char ret[MAX_PATH]; 962 MSIHANDLE hview, hrec; 963 964 ret[0] = '\0'; 965 966 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 967 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 968 969 r = MsiViewExecute( hview, 0 ); 970 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 971 972 r = MsiViewFetch( hview, &hrec ); 973 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 974 if (r == ERROR_SUCCESS) 975 { 976 DWORD size = MAX_PATH; 977 r = MsiRecordGetStringA( hrec, field, ret, &size ); 978 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r); 979 MsiCloseHandle( hrec ); 980 981 r = MsiViewFetch( hview, &hrec ); 982 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r); 983 } 984 985 MsiViewClose( hview ); 986 MsiCloseHandle( hview ); 987 return ret; 988 } 989 990 static void test_system_tables( void ) 991 { 992 static const char patchsource[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7"; 993 UINT r; 994 char *cr; 995 const char *query; 996 MSIHANDLE hproduct, hdb, hview, hrec; 997 998 if (!is_process_elevated()) 999 { 1000 skip("process is limited\n"); 1001 return; 1002 } 1003 1004 CreateDirectoryA( "msitest", NULL ); 1005 create_file( "msitest\\patch.txt", 1000 ); 1006 1007 create_database_suminfo( msifile, tables, ARRAY_SIZE(tables) ); 1008 create_patch( mspfile ); 1009 1010 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL ); 1011 1012 r = MsiInstallProductA( msifile, "DISABLE_FEATURE=1" ); 1013 if (r != ERROR_SUCCESS) 1014 { 1015 skip("Product installation failed with error code %d\n", r); 1016 goto cleanup; 1017 } 1018 1019 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct ); 1020 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1021 1022 hdb = MsiGetActiveDatabase( hproduct ); 1023 ok( hdb, "failed to get database handle\n" ); 1024 1025 r = find_entry( hdb, "_Streams", "\5SummaryInformation" ); 1026 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1027 1028 query = "SELECT * FROM `_Storages`"; 1029 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 1030 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1031 1032 r = MsiViewExecute( hview, 0 ); 1033 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1034 1035 r = MsiViewFetch( hview, &hrec ); 1036 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r ); 1037 1038 r = find_entry( hdb, "_Tables", "Directory" ); 1039 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1040 1041 r = find_entry( hdb, "_Tables", "File" ); 1042 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1043 1044 r = find_entry( hdb, "_Tables", "Component" ); 1045 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1046 1047 r = find_entry( hdb, "_Tables", "Feature" ); 1048 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1049 1050 r = find_entry( hdb, "_Tables", "FeatureComponents" ); 1051 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1052 1053 r = find_entry( hdb, "_Tables", "Property" ); 1054 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1055 1056 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" ); 1057 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1058 1059 r = find_entry( hdb, "_Tables", "Media" ); 1060 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1061 1062 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'"); 1063 ok( r == 1, "Got %u\n", r ); 1064 1065 r = find_entry( hdb, "_Tables", "_Property" ); 1066 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1067 1068 MsiCloseHandle( hrec ); 1069 MsiViewClose( hview ); 1070 MsiCloseHandle( hview ); 1071 MsiCloseHandle( hdb ); 1072 MsiCloseHandle( hproduct ); 1073 1074 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL ); 1075 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1076 1077 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct ); 1078 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1079 1080 hdb = MsiGetActiveDatabase( hproduct ); 1081 ok( hdb, "failed to get database handle\n" ); 1082 1083 r = find_entry( hdb, "_Streams", "\5SummaryInformation" ); 1084 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1085 1086 r = find_entryW( hdb, L"_Streams", L"\x3a8c\x47cb\x45b0\x45ec\x45a8\x4837" ); 1087 ok( r == ERROR_NO_MORE_ITEMS, "failed to find entry %u\n", r ); 1088 1089 query = "SELECT * FROM `_Storages`"; 1090 r = MsiDatabaseOpenViewA( hdb, query, &hview ); 1091 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1092 1093 r = MsiViewExecute( hview, 0 ); 1094 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1095 1096 r = MsiViewFetch( hview, &hrec ); 1097 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r ); 1098 1099 r = find_entry( hdb, "_Tables", "Directory" ); 1100 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1101 1102 r = find_entry( hdb, "_Tables", "File" ); 1103 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1104 1105 r = find_entry( hdb, "_Tables", "Component" ); 1106 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1107 1108 r = find_entry( hdb, "_Tables", "Feature" ); 1109 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1110 1111 r = find_entry( hdb, "_Tables", "FeatureComponents" ); 1112 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1113 1114 r = find_entry( hdb, "_Tables", "Property" ); 1115 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1116 1117 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" ); 1118 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1119 1120 r = find_entry( hdb, "_Tables", "Media" ); 1121 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1122 1123 r = find_entry( hdb, "_Tables", "_Property" ); 1124 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1125 1126 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" ); 1127 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1128 1129 r = find_entry( hdb, "_Tables", "Patch" ); 1130 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1131 1132 r = find_entry( hdb, "_Tables", "PatchPackage" ); 1133 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r ); 1134 1135 cr = get_string( hdb, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL"); 1136 todo_wine ok( !strcmp(cr, patchsource), "Expected \"%s\", got \"%s\"\n", patchsource, cr ); 1137 1138 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL"); 1139 todo_wine ok( r == 100, "Got %u\n", r ); 1140 1141 r = get_integer( hdb, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL"); 1142 todo_wine ok( r == 10001, "Got %u\n", r ); 1143 1144 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'"); 1145 ok( r == 1, "Got %u\n", r ); 1146 1147 cr = get_string( hdb, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL"); 1148 ok( !strcmp(cr, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr ); 1149 1150 r = get_integer( hdb, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'"); 1151 ok( r == 10000, "Got %u\n", r ); 1152 1153 MsiCloseHandle( hrec ); 1154 MsiViewClose( hview ); 1155 MsiCloseHandle( hview ); 1156 MsiCloseHandle( hdb ); 1157 MsiCloseHandle( hproduct ); 1158 1159 r = MsiInstallProductA( msifile, "REMOVE=ALL" ); 1160 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1161 1162 cleanup: 1163 DeleteFileA( msifile ); 1164 DeleteFileA( mspfile ); 1165 DeleteFileA( "msitest\\patch.txt" ); 1166 RemoveDirectoryA( "msitest" ); 1167 } 1168 1169 static void test_patch_registration( void ) 1170 { 1171 UINT r; 1172 DWORD size; 1173 char buffer[MAX_PATH], patch_code[39]; 1174 1175 if (!is_process_elevated()) 1176 { 1177 skip("process is limited\n"); 1178 return; 1179 } 1180 1181 CreateDirectoryA( "msitest", NULL ); 1182 create_file( "msitest\\patch.txt", 1000 ); 1183 1184 create_database_suminfo( msifile, tables, ARRAY_SIZE(tables) ); 1185 create_patch( mspfile ); 1186 1187 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL ); 1188 1189 r = MsiInstallProductA( msifile, "DISABLE_FEATURE=1" ); 1190 if (r != ERROR_SUCCESS) 1191 { 1192 skip("Product installation failed with error code %d\n", r); 1193 goto cleanup; 1194 } 1195 1196 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL ); 1197 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1198 1199 buffer[0] = 0; 1200 size = sizeof(buffer); 1201 r = MsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}", 1202 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 1203 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, 1204 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size ); 1205 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1206 ok( buffer[0], "buffer empty\n" ); 1207 1208 buffer[0] = 0; 1209 size = sizeof(buffer); 1210 r = MsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}", 1211 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 1212 NULL, MSIINSTALLCONTEXT_MACHINE, 1213 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size ); 1214 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r ); 1215 1216 buffer[0] = 0; 1217 size = sizeof(buffer); 1218 r = MsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}", 1219 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 1220 NULL, MSIINSTALLCONTEXT_USERMANAGED, 1221 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size ); 1222 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1223 ok( !buffer[0], "got %s\n", buffer ); 1224 1225 r = MsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 1226 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED, 1227 0, patch_code, NULL, NULL, NULL, NULL ); 1228 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1229 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" ); 1230 1231 r = MsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 1232 NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED, 1233 0, patch_code, NULL, NULL, NULL, NULL ); 1234 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r ); 1235 1236 r = MsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 1237 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED, 1238 0, patch_code, NULL, NULL, NULL, NULL ); 1239 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r ); 1240 1241 r = MsiInstallProductA( msifile, "REMOVE=ALL" ); 1242 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r ); 1243 1244 buffer[0] = 0; 1245 size = sizeof(buffer); 1246 r = MsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}", 1247 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", 1248 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, 1249 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size ); 1250 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r ); 1251 1252 cleanup: 1253 DeleteFileA( msifile ); 1254 DeleteFileA( mspfile ); 1255 DeleteFileA( "msitest\\patch.txt" ); 1256 RemoveDirectoryA( "msitest" ); 1257 } 1258 1259 START_TEST(patch) 1260 { 1261 DWORD len; 1262 char temp_path[MAX_PATH], prev_path[MAX_PATH]; 1263 1264 if (!is_process_elevated()) restart_as_admin_elevated(); 1265 1266 GetCurrentDirectoryA( MAX_PATH, prev_path ); 1267 GetTempPathA( MAX_PATH, temp_path ); 1268 SetCurrentDirectoryA( temp_path ); 1269 1270 strcpy( CURR_DIR, temp_path ); 1271 len = strlen( CURR_DIR ); 1272 1273 if (len && (CURR_DIR[len - 1] == '\\')) 1274 CURR_DIR[len - 1] = 0; 1275 1276 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR ); 1277 1278 test_simple_patch(); 1279 test_MsiOpenDatabase(); 1280 test_system_tables(); 1281 test_patch_registration(); 1282 1283 SetCurrentDirectoryA( prev_path ); 1284 } 1285