wer: Add new stubbed wer.dll.
[wine/hramrach.git] / dlls / msi / tests / patch.c
blob998dc4b573f28bd20ce7d3a374868151c0fb6fc7
1 /*
2 * Copyright 2010 Hans Leidekker for CodeWeavers
4 * A test program for patching MSI products.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define _WIN32_MSI 300
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <windows.h>
27 #include <msiquery.h>
28 #include <msidefs.h>
29 #include <msi.h>
31 #include "wine/test.h"
33 static UINT (WINAPI *pMsiApplyPatchA)( LPCSTR, LPCSTR, INSTALLTYPE, LPCSTR );
34 static UINT (WINAPI *pMsiGetPatchInfoExA)( LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT,
35 LPCSTR, LPSTR, DWORD * );
36 static UINT (WINAPI *pMsiEnumPatchesExA)( LPCSTR, LPCSTR, DWORD, DWORD, DWORD, LPSTR,
37 LPSTR, MSIINSTALLCONTEXT *, LPSTR, LPDWORD );
38 static BOOL (WINAPI *pGetTokenInformation)( HANDLE, TOKEN_INFORMATION_CLASS, LPVOID, DWORD, PDWORD );
39 static BOOL (WINAPI *pOpenProcessToken)( HANDLE, DWORD, PHANDLE );
41 static const char *msifile = "winetest-patch.msi";
42 static const char *mspfile = "winetest-patch.msp";
44 static char CURR_DIR[MAX_PATH];
45 static char PROG_FILES_DIR[MAX_PATH];
46 static char COMMON_FILES_DIR[MAX_PATH];
48 /* msi database data */
50 static const char property_dat[] =
51 "Property\tValue\n"
52 "s72\tl0\n"
53 "Property\tProperty\n"
54 "Manufacturer\tWineHQ\n"
55 "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
56 "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
57 "ProductLanguage\t1033\n"
58 "ProductName\tmsitest\n"
59 "ProductVersion\t1.1.1\n"
60 "PATCHNEWSUMMARYSUBJECT\tInstaller Database\n";
62 static const char media_dat[] =
63 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
64 "i2\ti4\tL64\tS255\tS32\tS72\n"
65 "Media\tDiskId\n"
66 "1\t1\t\t\tDISK1\t\n";
68 static const char file_dat[] =
69 "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
70 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
71 "File\tFile\n"
72 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
74 static const char directory_dat[] =
75 "Directory\tDirectory_Parent\tDefaultDir\n"
76 "s72\tS72\tl255\n"
77 "Directory\tDirectory\n"
78 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
79 "ProgramFilesFolder\tTARGETDIR\t.\n"
80 "TARGETDIR\t\tSourceDir";
82 static const char component_dat[] =
83 "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
84 "s72\tS38\ts72\ti2\tS255\tS72\n"
85 "Component\tComponent\n"
86 "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n";
88 static const char feature_dat[] =
89 "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
90 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
91 "Feature\tFeature\n"
92 "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n";
94 static const char feature_comp_dat[] =
95 "Feature_\tComponent_\n"
96 "s38\ts72\n"
97 "FeatureComponents\tFeature_\tComponent_\n"
98 "patch\tpatch\n";
100 static const char install_exec_seq_dat[] =
101 "Action\tCondition\tSequence\n"
102 "s72\tS255\tI2\n"
103 "InstallExecuteSequence\tAction\n"
104 "LaunchConditions\t\t100\n"
105 "CostInitialize\t\t800\n"
106 "FileCost\t\t900\n"
107 "CostFinalize\t\t1000\n"
108 "InstallValidate\t\t1400\n"
109 "InstallInitialize\t\t1500\n"
110 "ProcessComponents\t\t1600\n"
111 "RemoveFiles\t\t1700\n"
112 "InstallFiles\t\t2000\n"
113 "RegisterUser\t\t3000\n"
114 "RegisterProduct\t\t3100\n"
115 "PublishFeatures\t\t5100\n"
116 "PublishProduct\t\t5200\n"
117 "InstallFinalize\t\t6000\n";
119 struct msi_table
121 const char *filename;
122 const char *data;
123 int size;
126 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
128 static const struct msi_table tables[] =
130 ADD_TABLE( directory ),
131 ADD_TABLE( file ),
132 ADD_TABLE( component ),
133 ADD_TABLE( feature ),
134 ADD_TABLE( feature_comp ),
135 ADD_TABLE( property ),
136 ADD_TABLE( install_exec_seq ),
137 ADD_TABLE( media )
140 static void init_function_pointers( void )
142 HMODULE hmsi = GetModuleHandleA( "msi.dll" );
143 HMODULE hadvapi32 = GetModuleHandleA( "advapi32.dll" );
145 #define GET_PROC( mod, func ) \
146 p ## func = (void *)GetProcAddress( mod, #func ); \
147 if (!p ## func) \
148 trace( "GetProcAddress(%s) failed\n", #func );
150 GET_PROC( hmsi, MsiApplyPatchA );
151 GET_PROC( hmsi, MsiGetPatchInfoExA );
152 GET_PROC( hmsi, MsiEnumPatchesExA );
154 GET_PROC( hadvapi32, GetTokenInformation );
155 GET_PROC( hadvapi32, OpenProcessToken );
156 #undef GET_PROC
159 static BOOL is_process_limited(void)
161 HANDLE token;
163 if (!pOpenProcessToken || !pGetTokenInformation) return FALSE;
165 if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
167 BOOL ret;
168 TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
169 DWORD size;
171 ret = pGetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
172 CloseHandle(token);
173 return (ret && type == TokenElevationTypeLimited);
175 return FALSE;
178 static BOOL get_program_files_dir( char *buf, char *buf2 )
180 HKEY hkey;
181 DWORD type, size;
183 if (RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
184 return FALSE;
186 size = MAX_PATH;
187 if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) &&
188 RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
190 RegCloseKey( hkey );
191 return FALSE;
193 size = MAX_PATH;
194 if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
196 RegCloseKey( hkey );
197 return FALSE;
199 RegCloseKey( hkey );
200 return TRUE;
203 static void create_file_data( const char *filename, const char *data, DWORD size )
205 HANDLE file;
206 DWORD written;
208 file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
209 if (file == INVALID_HANDLE_VALUE)
210 return;
212 WriteFile( file, data, strlen( data ), &written, NULL );
213 if (size)
215 SetFilePointer( file, size, NULL, FILE_BEGIN );
216 SetEndOfFile( file );
218 CloseHandle( file );
221 #define create_file( name, size ) create_file_data( name, name, size )
223 static BOOL delete_pf( const char *rel_path, BOOL is_file )
225 char path[MAX_PATH];
227 strcpy( path, PROG_FILES_DIR );
228 strcat( path, "\\" );
229 strcat( path, rel_path );
231 if (is_file)
232 return DeleteFileA( path );
233 else
234 return RemoveDirectoryA( path );
237 static DWORD get_pf_file_size( const char *filename )
239 char path[MAX_PATH];
240 HANDLE file;
241 DWORD size;
243 strcpy( path, PROG_FILES_DIR );
244 strcat( path, "\\");
245 strcat( path, filename );
247 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
248 if (file == INVALID_HANDLE_VALUE)
249 return INVALID_FILE_SIZE;
251 size = GetFileSize( file, NULL );
252 CloseHandle( file );
253 return size;
256 static void write_file( const char *filename, const char *data, DWORD data_size )
258 DWORD size;
259 HANDLE file = CreateFile( filename, GENERIC_WRITE, 0, NULL,
260 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
261 WriteFile( file, data, data_size, &size, NULL );
262 CloseHandle( file );
265 static void set_suminfo( const char *filename )
267 UINT r;
268 MSIHANDLE hsi, hdb;
270 r = MsiOpenDatabaseA( filename, MSIDBOPEN_DIRECT, &hdb );
271 ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
273 r = MsiGetSummaryInformation( hdb, NULL, 7, &hsi );
274 ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
276 r = MsiSummaryInfoSetProperty( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
277 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
279 r = MsiSummaryInfoSetProperty( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
280 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
282 r = MsiSummaryInfoSetProperty( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
283 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
285 r = MsiSummaryInfoSetProperty( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
286 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
288 r = MsiSummaryInfoSetProperty( hsi, 9, VT_LPSTR, 0, NULL, "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}" );
289 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
291 r = MsiSummaryInfoSetProperty( hsi, 14, VT_I4, 100, NULL, NULL );
292 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
294 r = MsiSummaryInfoSetProperty( hsi, 15, VT_I4, 0, NULL, NULL );
295 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
297 r = MsiSummaryInfoPersist( hsi );
298 ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
300 r = MsiCloseHandle( hsi );
301 ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
303 r = MsiCloseHandle( hdb );
304 ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
307 static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
309 MSIHANDLE hdb;
310 UINT r, i;
312 r = MsiOpenDatabaseA( filename, MSIDBOPEN_CREATE, &hdb );
313 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
315 /* import the tables into the database */
316 for (i = 0; i < num_tables; i++)
318 const struct msi_table *table = &tables[i];
320 write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
322 r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
323 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
325 DeleteFileA( table->filename );
328 r = MsiDatabaseCommit( hdb );
329 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
331 MsiCloseHandle( hdb );
332 set_suminfo( filename );
335 /* data for generating a patch */
337 /* table names - encoded as in an msi database file */
338 static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
339 static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
340 static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
341 static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
342 static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
343 static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
344 static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
345 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
346 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
347 /* substorage names */
348 static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
349 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
350 static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
351 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
353 /* data in each table */
354 static const WCHAR p_data0[] = { /* _Columns */
355 0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
356 0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
358 static const WCHAR p_data1[] = { /* _Tables */
359 0x0001
361 static const char p_data2[] = { /* _StringData */
362 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
364 static const WCHAR p_data3[] = { /* _StringPool */
365 /* len, refs */
366 0, 0, /* string 0 '' */
367 16, 5, /* string 1 'MsiPatchSequence' */
368 11, 1, /* string 2 'PatchFamily' */
369 11, 1, /* string 3 'ProductCode' */
370 8, 1, /* string 4 'Sequence' */
371 10, 1, /* string 5 'Attributes' */
372 15, 1, /* string 6 '1.1.19388.37230' */
373 32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
375 static const char p_data4[] = { /* CAB_msitest */
376 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00,
377 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
378 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9e,
379 0x03, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x12,
380 0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
381 0x3c, 0xd4, 0x80, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
382 0x74, 0x78, 0x74, 0x00, 0x0b, 0x3c, 0xd6, 0xc1, 0x4a, 0x00, 0xea,
383 0x03, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x10, 0xa1, 0x3e, 0x00, 0x00,
384 0x00, 0x00, 0x03, 0x00, 0x40, 0x30, 0x0c, 0x43, 0xf8, 0xb4, 0x85,
385 0x4d, 0x96, 0x08, 0x0a, 0x92, 0xf0, 0x52, 0xfb, 0xbb, 0x82, 0xf9,
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x31, 0x7d,
387 0x56, 0xdf, 0xf7, 0x48, 0x7c, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
388 0x00, 0x00, 0x41, 0x80, 0xdf, 0xf7, 0xd8, 0x72, 0xbf, 0xb9, 0x63,
389 0x91, 0x0e, 0x57, 0x1f, 0xfa, 0x1a, 0x66, 0x54, 0x55
391 static const WCHAR p_data5[] = { /* MsiPatchSequence */
392 0x0007, 0x0000, 0x0006, 0x8000
394 static const char p_data6[] = { /* SummaryInformation */
395 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
398 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
399 0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
400 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
401 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
402 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
403 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
404 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
405 0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
406 0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
407 0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
408 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
409 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
410 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
411 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
412 0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
413 0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
414 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
415 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
416 0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
417 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
418 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
419 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
422 struct table_data {
423 LPCWSTR name;
424 const void *data;
425 DWORD size;
428 static const struct table_data table_patch_data[] = {
429 { p_name0, p_data0, sizeof p_data0 },
430 { p_name1, p_data1, sizeof p_data1 },
431 { p_name2, p_data2, sizeof p_data2 - 1 },
432 { p_name3, p_data3, sizeof p_data3 },
433 { p_name4, p_data4, sizeof p_data4 },
434 { p_name5, p_data5, sizeof p_data5 },
435 { p_name6, p_data6, sizeof p_data6 }
438 #define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
440 static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
441 static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
442 static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
443 static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
444 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
445 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
447 static const WCHAR t1_data0[] = { /* File */
448 0x0008, 0x0001, 0x03ea, 0x8000
450 static const char t1_data1[] = { /* _StringData */
451 "patch.txt"
453 static const WCHAR t1_data2[] = { /* _StringPool */
454 /* len, refs */
455 0, 0, /* string 0 '' */
456 9, 1, /* string 1 'patch.txt' */
458 static const char t1_data3[] = { /* SummaryInformation */
459 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
461 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
462 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
463 0x30, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
464 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
465 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
466 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
467 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
468 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
469 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
470 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
471 0x04, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00,
472 0x00, 0x10, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x1e, 0x00,
473 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
474 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
475 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
476 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
477 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
478 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
479 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
480 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
481 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
482 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31,
485 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06,
486 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00,
487 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 0x39, 0x31,
488 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
489 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
490 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
491 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x39, 0x31,
492 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
493 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
494 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
495 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x41, 0x32,
496 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45, 0x32, 0x43,
497 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30, 0x39, 0x2d,
498 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35, 0x46, 0x34,
499 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
500 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x09
503 static const struct table_data table_transform1_data[] = {
504 { t1_name0, t1_data0, sizeof t1_data0 },
505 { t1_name1, t1_data1, sizeof t1_data1 - 1 },
506 { t1_name2, t1_data2, sizeof t1_data2 },
507 { t1_name3, t1_data3, sizeof t1_data3 }
510 #define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
512 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
513 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
514 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
515 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
516 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
517 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
518 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
519 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
520 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
521 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
522 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
523 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
524 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
526 static const WCHAR t2_data0[] = { /* File */
527 0x00c0, 0x0001, 0x9000, 0x83e8
529 static const WCHAR t2_data1[] = { /* Media */
530 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
532 static const WCHAR t2_data2[] = { /* _Columns */
533 0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
534 0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
535 0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
536 0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
537 0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
538 0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
539 0x000e, 0x8900
541 static const WCHAR t2_data3[] = { /* _Tables */
542 0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
544 static const WCHAR t2_data4[] = { /* Property */
545 0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
547 static const WCHAR t2_data5[] = { /* PatchPackage */
548 0x0201, 0x0013, 0x8002
550 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
551 0x0301, 0x0006, 0x0000, 0x87d1
553 static const char t2_data7[] = { /* _StringData */
554 "patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
555 "PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
556 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
558 static const WCHAR t2_data8[] = { /* _StringPool */
559 /* len, refs */
560 0, 0, /* string 0 '' */
561 9, 1, /* string 1 'patch.txt' */
562 22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
563 21, 1, /* string 3 'Installation Database' */
564 19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
565 38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
566 10, 1, /* string 6 'PatchFiles' */
567 12, 1, /* string 7 '#CAB_msitest' */
568 4, 1, /* string 8 'prop' */
569 5, 7, /* string 9 'Patch' */
570 5, 1, /* string 10 'File_' */
571 8, 1, /* string 11 'Sequence' */
572 9, 1, /* string 12 'PatchSize' */
573 10, 1, /* string 13 'Attributes' */
574 6, 2, /* string 14 'Header' */
575 10, 1, /* string 15 'StreamRef_' */
576 12, 3, /* string 16 'PatchPackage' */
577 7, 1, /* string 17 'PatchId' */
578 6, 1, /* string 18 'Media_' */
579 38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
580 15, 3, /* string 20 'MsiPatchHeaders' */
581 9, 1 /* string 21 'StreamRef' */
583 static const char t2_data9[] = { /* SummaryInformation */
584 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
587 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
588 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
589 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
590 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
591 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
592 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
593 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
594 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
595 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
596 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
597 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
600 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
601 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
604 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
605 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
606 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
607 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
608 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
609 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
610 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
611 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
612 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
613 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
614 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
615 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
616 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
617 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
618 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
619 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
622 static const struct table_data table_transform2_data[] = {
623 { t2_name0, t2_data0, sizeof t2_data0 },
624 { t2_name1, t2_data1, sizeof t2_data1 },
625 { t2_name2, t2_data2, sizeof t2_data2 },
626 { t2_name3, t2_data3, sizeof t2_data3 },
627 { t2_name4, t2_data4, sizeof t2_data4 },
628 { t2_name5, t2_data5, sizeof t2_data5 },
629 { t2_name6, t2_data6, sizeof t2_data6 },
630 { t2_name7, t2_data7, sizeof t2_data7 - 1 },
631 { t2_name8, t2_data8, sizeof t2_data8 },
632 { t2_name9, t2_data9, sizeof t2_data9 }
635 #define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
637 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
639 IStream *stm;
640 DWORD i, count;
641 HRESULT r;
643 for (i = 0; i < num_tables; i++)
645 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
646 if (FAILED( r ))
648 ok( 0, "failed to create stream 0x%08x\n", r );
649 continue;
652 r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
653 if (FAILED( r ) || count != tables[i].size)
654 ok( 0, "failed to write stream\n" );
655 IStream_Release( stm );
659 static void create_patch( const char *filename )
661 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
662 WCHAR *filenameW;
663 HRESULT r;
664 int len;
665 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
667 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
668 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
670 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
671 filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
672 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
674 r = StgCreateDocfile( filenameW, mode, 0, &stg );
675 HeapFree( GetProcessHeap(), 0, filenameW );
676 ok( r == S_OK, "failed to create storage 0x%08x\n", r );
677 if (!stg)
678 return;
680 r = IStorage_SetClass( stg, &CLSID_MsiPatch );
681 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
683 write_tables( stg, table_patch_data, NUM_PATCH_TABLES );
685 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
686 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
688 r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
689 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
691 write_tables( stg1, table_transform1_data, NUM_TRANSFORM1_TABLES );
692 IStorage_Release( stg1 );
694 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
695 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
697 r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
698 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
700 write_tables( stg2, table_transform2_data, NUM_TRANSFORM2_TABLES );
701 IStorage_Release( stg2 );
702 IStorage_Release( stg );
705 static void test_simple_patch( void )
707 UINT r;
708 DWORD size;
709 char path[MAX_PATH], install_source[MAX_PATH], buffer[32];
710 const char *query;
711 MSIHANDLE hpackage, hdb, hview, hrec;
713 if (!pMsiApplyPatchA)
715 win_skip("MsiApplyPatchA is not available\n");
716 return;
718 if (is_process_limited())
720 skip("process is limited\n");
721 return;
724 CreateDirectoryA( "msitest", NULL );
725 create_file( "msitest\\patch.txt", 1000 );
727 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
728 create_patch( mspfile );
730 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
732 r = MsiInstallProductA( msifile, NULL );
733 if (r != ERROR_SUCCESS)
735 skip("Product installation failed with error code %u\n", r);
736 goto cleanup;
739 size = get_pf_file_size( "msitest\\patch.txt" );
740 ok( size == 1000, "expected 1000, got %u\n", size );
742 size = sizeof(install_source);
743 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
744 "InstallSource", install_source, &size );
745 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
747 strcpy( path, CURR_DIR );
748 strcat( path, "\\" );
749 strcat( path, msifile );
751 r = MsiOpenPackageA( path, &hpackage );
752 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
754 hdb = MsiGetActiveDatabase( hpackage );
755 ok( hdb, "failed to get database handle\n" );
757 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
758 r = MsiDatabaseOpenView( hdb, query, &hview );
759 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
761 r = MsiViewExecute( hview, 0 );
762 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
764 r = MsiViewFetch( hview, &hrec );
765 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
767 MsiCloseHandle( hrec );
768 MsiViewClose( hview );
769 MsiCloseHandle( hview );
771 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
772 "AND `Value` = 'Installer Database'";
773 r = MsiDatabaseOpenView( hdb, query, &hview );
774 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
776 r = MsiViewExecute( hview, 0 );
777 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
779 r = MsiViewFetch( hview, &hrec );
780 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
782 MsiCloseHandle( hrec );
783 MsiViewClose( hview );
784 MsiCloseHandle( hview );
786 buffer[0] = 0;
787 size = sizeof(buffer);
788 r = MsiGetProperty( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
789 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
790 ok( !strcmp( buffer, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer );
792 MsiCloseHandle( hdb );
793 MsiCloseHandle( hpackage );
795 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
796 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
797 "expected ERROR_SUCCESS, got %u\n", r );
799 if (r == ERROR_PATCH_PACKAGE_INVALID)
801 win_skip("Windows Installer < 3.0 detected\n");
802 goto uninstall;
805 size = get_pf_file_size( "msitest\\patch.txt" );
806 ok( size == 1002, "expected 1002, got %u\n", size );
808 /* show that MsiOpenPackage applies registered patches */
809 r = MsiOpenPackageA( path, &hpackage );
810 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
812 hdb = MsiGetActiveDatabase( hpackage );
813 ok( hdb, "failed to get database handle\n" );
815 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
816 r = MsiDatabaseOpenView( hdb, query, &hview );
817 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
819 r = MsiViewExecute( hview, 0 );
820 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
822 r = MsiViewFetch( hview, &hrec );
823 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
825 MsiCloseHandle( hrec );
826 MsiViewClose( hview );
827 MsiCloseHandle( hview );
829 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
830 "AND `Value` = 'Installation Database'";
831 r = MsiDatabaseOpenView( hdb, query, &hview );
832 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
834 r = MsiViewExecute( hview, 0 );
835 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
837 r = MsiViewFetch( hview, &hrec );
838 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
840 MsiCloseHandle( hrec );
841 MsiViewClose( hview );
842 MsiCloseHandle( hview );
844 buffer[0] = 0;
845 size = sizeof(buffer);
846 r = MsiGetProperty( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
847 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
848 ok( !strcmp( buffer, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer );
850 MsiCloseHandle( hdb );
851 MsiCloseHandle( hpackage );
853 /* show that patches are not committed to the local package database */
854 size = sizeof(path);
855 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
856 "LocalPackage", path, &size );
857 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
859 r = MsiOpenDatabaseA( path, MSIDBOPEN_READONLY, &hdb );
860 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
862 r = MsiDatabaseOpenView( hdb, query, &hview );
863 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
865 r = MsiViewExecute( hview, 0 );
866 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
868 r = MsiViewFetch( hview, &hrec );
869 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
871 MsiCloseHandle( hrec );
872 MsiViewClose( hview );
873 MsiCloseHandle( hview );
874 MsiCloseHandle( hdb );
876 uninstall:
877 size = sizeof(path);
878 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
879 "InstallSource", path, &size );
880 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
881 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
883 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
884 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
886 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
887 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
889 cleanup:
890 DeleteFileA( msifile );
891 DeleteFileA( mspfile );
892 DeleteFileA( "msitest\\patch.txt" );
893 RemoveDirectoryA( "msitest" );
896 static void test_MsiOpenDatabase( void )
898 UINT r;
899 MSIHANDLE hdb;
901 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE, &hdb );
902 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
904 r = MsiDatabaseCommit( hdb );
905 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
906 MsiCloseHandle( hdb );
908 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
909 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
910 DeleteFileA( mspfile );
912 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
913 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
915 r = MsiDatabaseCommit( hdb );
916 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
917 MsiCloseHandle( hdb );
919 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
920 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
921 MsiCloseHandle( hdb );
922 DeleteFileA( mspfile );
924 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
925 create_patch( mspfile );
927 r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
928 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
930 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
931 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
932 MsiCloseHandle( hdb );
934 DeleteFileA( msifile );
935 DeleteFileA( mspfile );
938 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
940 static char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
941 char query[0x100];
942 UINT r;
943 MSIHANDLE hview, hrec;
945 sprintf( query, fmt, table, entry );
946 r = MsiDatabaseOpenView( hdb, query, &hview );
947 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
949 r = MsiViewExecute( hview, 0 );
950 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
952 r = MsiViewFetch( hview, &hrec );
953 MsiViewClose( hview );
954 MsiCloseHandle( hview );
955 MsiCloseHandle( hrec );
956 return r;
959 static void test_system_tables( void )
961 UINT r;
962 const char *query;
963 MSIHANDLE hproduct, hdb, hview, hrec;
965 if (!pMsiApplyPatchA)
967 win_skip("MsiApplyPatchA is not available\n");
968 return;
970 if (is_process_limited())
972 skip("process is limited\n");
973 return;
976 CreateDirectoryA( "msitest", NULL );
977 create_file( "msitest\\patch.txt", 1000 );
979 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
980 create_patch( mspfile );
982 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
984 r = MsiInstallProductA( msifile, NULL );
985 if (r != ERROR_SUCCESS)
987 skip("Product installation failed with error code %d\n", r);
988 goto cleanup;
991 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
992 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
994 hdb = MsiGetActiveDatabase( hproduct );
995 ok( hdb, "failed to get database handle\n" );
997 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
998 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1000 query = "SELECT * FROM `_Storages`";
1001 r = MsiDatabaseOpenView( hdb, query, &hview );
1002 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1004 r = MsiViewExecute( hview, 0 );
1005 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1007 r = MsiViewFetch( hview, &hrec );
1008 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1010 r = find_entry( hdb, "_Tables", "Directory" );
1011 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1013 r = find_entry( hdb, "_Tables", "File" );
1014 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1016 r = find_entry( hdb, "_Tables", "Component" );
1017 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1019 r = find_entry( hdb, "_Tables", "Feature" );
1020 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1022 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1023 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1025 r = find_entry( hdb, "_Tables", "Property" );
1026 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1028 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1029 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1031 r = find_entry( hdb, "_Tables", "Media" );
1032 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1034 r = find_entry( hdb, "_Tables", "_Property" );
1035 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1037 MsiCloseHandle( hrec );
1038 MsiViewClose( hview );
1039 MsiCloseHandle( hview );
1040 MsiCloseHandle( hdb );
1041 MsiCloseHandle( hproduct );
1043 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1044 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1045 "expected ERROR_SUCCESS, got %u\n", r );
1047 if (r == ERROR_PATCH_PACKAGE_INVALID)
1049 win_skip("Windows Installer < 3.0 detected\n");
1050 goto uninstall;
1053 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1054 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1056 hdb = MsiGetActiveDatabase( hproduct );
1057 ok( hdb, "failed to get database handle\n" );
1059 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1060 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1062 query = "SELECT * FROM `_Storages`";
1063 r = MsiDatabaseOpenView( hdb, query, &hview );
1064 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1066 r = MsiViewExecute( hview, 0 );
1067 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1069 r = MsiViewFetch( hview, &hrec );
1070 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1072 r = find_entry( hdb, "_Tables", "Directory" );
1073 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1075 r = find_entry( hdb, "_Tables", "File" );
1076 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1078 r = find_entry( hdb, "_Tables", "Component" );
1079 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1081 r = find_entry( hdb, "_Tables", "Feature" );
1082 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1084 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1085 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1087 r = find_entry( hdb, "_Tables", "Property" );
1088 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1090 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1091 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1093 r = find_entry( hdb, "_Tables", "Media" );
1094 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1096 r = find_entry( hdb, "_Tables", "_Property" );
1097 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1099 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1100 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1102 r = find_entry( hdb, "_Tables", "Patch" );
1103 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1105 r = find_entry( hdb, "_Tables", "PatchPackage" );
1106 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1108 MsiCloseHandle( hrec );
1109 MsiViewClose( hview );
1110 MsiCloseHandle( hview );
1111 MsiCloseHandle( hdb );
1112 MsiCloseHandle( hproduct );
1114 uninstall:
1115 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1116 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1118 cleanup:
1119 DeleteFileA( msifile );
1120 DeleteFileA( mspfile );
1121 DeleteFileA( "msitest\\patch.txt" );
1122 RemoveDirectoryA( "msitest" );
1125 static void test_patch_registration( void )
1127 UINT r, size;
1128 char buffer[MAX_PATH], patch_code[39];
1130 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1132 win_skip("required functions not available\n");
1133 return;
1135 if (is_process_limited())
1137 skip("process is limited\n");
1138 return;
1141 CreateDirectoryA( "msitest", NULL );
1142 create_file( "msitest\\patch.txt", 1000 );
1144 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1145 create_patch( mspfile );
1147 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1149 r = MsiInstallProductA( msifile, NULL );
1150 if (r != ERROR_SUCCESS)
1152 skip("Product installation failed with error code %d\n", r);
1153 goto cleanup;
1156 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1157 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1158 "expected ERROR_SUCCESS, got %u\n", r );
1160 if (r == ERROR_PATCH_PACKAGE_INVALID)
1162 win_skip("Windows Installer < 3.0 detected\n");
1163 goto uninstall;
1166 buffer[0] = 0;
1167 size = sizeof(buffer);
1168 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1169 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1170 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1171 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1172 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1173 ok( buffer[0], "buffer empty\n" );
1175 buffer[0] = 0;
1176 size = sizeof(buffer);
1177 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1178 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1179 NULL, MSIINSTALLCONTEXT_MACHINE,
1180 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1181 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1183 buffer[0] = 0;
1184 size = sizeof(buffer);
1185 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1186 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1187 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1188 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1189 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1190 ok( !buffer[0], "got %s\n", buffer );
1192 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1193 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1194 0, patch_code, NULL, NULL, NULL, NULL );
1195 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1196 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1198 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1199 NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1200 0, patch_code, NULL, NULL, NULL, NULL );
1201 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1203 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1204 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1205 0, patch_code, NULL, NULL, NULL, NULL );
1206 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1208 uninstall:
1209 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1210 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1212 buffer[0] = 0;
1213 size = sizeof(buffer);
1214 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1215 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1216 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1217 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1218 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1220 cleanup:
1221 DeleteFileA( msifile );
1222 DeleteFileA( mspfile );
1223 DeleteFileA( "msitest\\patch.txt" );
1224 RemoveDirectoryA( "msitest" );
1227 START_TEST(patch)
1229 DWORD len;
1230 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1232 init_function_pointers();
1234 GetCurrentDirectoryA( MAX_PATH, prev_path );
1235 GetTempPath( MAX_PATH, temp_path );
1236 SetCurrentDirectoryA( temp_path );
1238 strcpy( CURR_DIR, temp_path );
1239 len = strlen( CURR_DIR );
1241 if (len && (CURR_DIR[len - 1] == '\\'))
1242 CURR_DIR[len - 1] = 0;
1244 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1246 test_simple_patch();
1247 test_MsiOpenDatabase();
1248 test_system_tables();
1249 test_patch_registration();
1251 SetCurrentDirectoryA( prev_path );