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