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