windowscodecs: Handle TIFF's with RowsPerStrip greater than Height.
[wine] / dlls / msi / tests / patch.c
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
31 #include "wine/test.h"
32
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 );
40
41 static const char *msifile = "winetest-patch.msi";
42 static const char *mspfile = "winetest-patch.msp";
43
44 static char CURR_DIR[MAX_PATH];
45 static char PROG_FILES_DIR[MAX_PATH];
46 static char COMMON_FILES_DIR[MAX_PATH];
47
48 /* msi database data */
49
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";
61
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";
67
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";
73
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";
81
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";
87
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";
93
94 static const char feature_comp_dat[] =
95     "Feature_\tComponent_\n"
96     "s38\ts72\n"
97     "FeatureComponents\tFeature_\tComponent_\n"
98     "patch\tpatch\n";
99
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";
118
119 struct msi_table
120 {
121     const char *filename;
122     const char *data;
123     int size;
124 };
125
126 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
127
128 static const struct msi_table tables[] =
129 {
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 )
138 };
139
140 static void init_function_pointers( void )
141 {
142     HMODULE hmsi = GetModuleHandleA( "msi.dll" );
143     HMODULE hadvapi32 = GetModuleHandleA( "advapi32.dll" );
144
145 #define GET_PROC( mod, func ) \
146     p ## func = (void *)GetProcAddress( mod, #func ); \
147     if (!p ## func) \
148         trace( "GetProcAddress(%s) failed\n", #func );
149
150     GET_PROC( hmsi, MsiApplyPatchA );
151     GET_PROC( hmsi, MsiGetPatchInfoExA );
152     GET_PROC( hmsi, MsiEnumPatchesExA );
153
154     GET_PROC( hadvapi32, GetTokenInformation );
155     GET_PROC( hadvapi32, OpenProcessToken );
156 #undef GET_PROC
157 }
158
159 static BOOL is_process_limited(void)
160 {
161     HANDLE token;
162
163     if (!pOpenProcessToken || !pGetTokenInformation) return FALSE;
164
165     if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
166     {
167         BOOL ret;
168         TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
169         DWORD size;
170
171         ret = pGetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
172         CloseHandle(token);
173         return (ret && type == TokenElevationTypeLimited);
174     }
175     return FALSE;
176 }
177
178 static BOOL get_program_files_dir( char *buf, char *buf2 )
179 {
180     HKEY hkey;
181     DWORD type, size;
182
183     if (RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
184         return FALSE;
185
186     size = MAX_PATH;
187     if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) &&
188         RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
189     {
190         RegCloseKey( hkey );
191         return FALSE;
192     }
193     size = MAX_PATH;
194     if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
195     {
196         RegCloseKey( hkey );
197         return FALSE;
198     }
199     RegCloseKey( hkey );
200     return TRUE;
201 }
202
203 static void create_file_data( const char *filename, const char *data, DWORD size )
204 {
205     HANDLE file;
206     DWORD written;
207
208     file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
209     if (file == INVALID_HANDLE_VALUE)
210         return;
211
212     WriteFile( file, data, strlen( data ), &written, NULL );
213     if (size)
214     {
215         SetFilePointer( file, size, NULL, FILE_BEGIN );
216         SetEndOfFile( file );
217     }
218     CloseHandle( file );
219 }
220
221 #define create_file( name, size ) create_file_data( name, name, size )
222
223 static BOOL delete_pf( const char *rel_path, BOOL is_file )
224 {
225     char path[MAX_PATH];
226
227     strcpy( path, PROG_FILES_DIR );
228     strcat( path, "\\" );
229     strcat( path, rel_path );
230
231     if (is_file)
232         return DeleteFileA( path );
233     else
234         return RemoveDirectoryA( path );
235 }
236
237 static DWORD get_pf_file_size( const char *filename )
238 {
239     char path[MAX_PATH];
240     HANDLE file;
241     DWORD size;
242
243     strcpy( path, PROG_FILES_DIR );
244     strcat( path, "\\");
245     strcat( path, filename );
246
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;
250
251     size = GetFileSize( file, NULL );
252     CloseHandle( file );
253     return size;
254 }
255
256 static void write_file( const char *filename, const char *data, DWORD data_size )
257 {
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 );
263 }
264
265 static void set_suminfo( const char *filename )
266 {
267     UINT r;
268     MSIHANDLE hsi, hdb;
269
270     r = MsiOpenDatabaseA( filename, MSIDBOPEN_DIRECT, &hdb );
271     ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
272
273     r = MsiGetSummaryInformation( hdb, NULL, 7, &hsi );
274     ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
275
276     r = MsiSummaryInfoSetProperty( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
277     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
278
279     r = MsiSummaryInfoSetProperty( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
280     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
281
282     r = MsiSummaryInfoSetProperty( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
283     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
284
285     r = MsiSummaryInfoSetProperty( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
286     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
287
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 );
290
291     r = MsiSummaryInfoSetProperty( hsi, 14, VT_I4, 100, NULL, NULL );
292     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
293
294     r = MsiSummaryInfoSetProperty( hsi, 15, VT_I4, 0, NULL, NULL );
295     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
296
297     r = MsiSummaryInfoPersist( hsi );
298     ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
299
300     r = MsiCloseHandle( hsi );
301     ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
302
303     r = MsiCloseHandle( hdb );
304     ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
305 }
306
307 static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
308 {
309     MSIHANDLE hdb;
310     UINT r, i;
311
312     r = MsiOpenDatabaseA( filename, MSIDBOPEN_CREATE, &hdb );
313     ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
314
315     /* import the tables into the database */
316     for (i = 0; i < num_tables; i++)
317     {
318         const struct msi_table *table = &tables[i];
319
320         write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
321
322         r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
323         ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
324
325         DeleteFileA( table->filename );
326     }
327
328     r = MsiDatabaseCommit( hdb );
329     ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
330
331     MsiCloseHandle( hdb );
332     set_suminfo( filename );
333 }
334
335 /* data for generating a patch */
336
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 */
352
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
357 };
358 static const WCHAR p_data1[] = { /* _Tables */
359     0x0001
360 };
361 static const char p_data2[] = { /* _StringData */
362     "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
363 };
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' */
374 };
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
390 };
391 static const WCHAR p_data5[] = { /* MsiPatchSequence */
392     0x0007, 0x0000, 0x0006, 0x8000
393 };
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
420 };
421
422 struct table_data {
423     LPCWSTR name;
424     const void *data;
425     DWORD size;
426 };
427
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 }
436 };
437
438 #define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
439
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 */
446
447 static const WCHAR t1_data0[] = { /* File */
448     0x0008, 0x0001, 0x03ea, 0x8000
449 };
450 static const char t1_data1[] = { /* _StringData */
451     "patch.txt"
452 };
453 static const WCHAR t1_data2[] = { /* _StringPool */
454 /* len, refs */
455      0,  0,     /* string 0 '' */
456      9,  1,     /* string 1 'patch.txt' */
457 };
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
501 };
502
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 }
508 };
509
510 #define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
511
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 */
525
526 static const WCHAR t2_data0[] = { /* File */
527     0x00c0, 0x0001, 0x9000, 0x83e8
528 };
529 static const WCHAR t2_data1[] = { /* Media */
530     0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
531 };
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
540 };
541 static const WCHAR t2_data3[] = { /* _Tables */
542     0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
543 };
544 static const WCHAR t2_data4[] = { /* Property */
545     0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
546 };
547 static const WCHAR t2_data5[] = { /* PatchPackage */
548     0x0201, 0x0013, 0x8002
549 };
550 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
551     0x0301, 0x0006, 0x0000, 0x87d1
552 };
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"
557 };
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' */
582 };
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
620 };
621
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 }
633 };
634
635 #define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
636
637 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
638 {
639     IStream *stm;
640     DWORD i, count;
641     HRESULT r;
642
643     for (i = 0; i < num_tables; i++)
644     {
645         r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
646         if (FAILED( r ))
647         {
648             ok( 0, "failed to create stream 0x%08x\n", r );
649             continue;
650         }
651
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 );
656     }
657 }
658
659 static void create_patch( const char *filename )
660 {
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;
666
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}};
669
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 );
673
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;
679
680     r = IStorage_SetClass( stg, &CLSID_MsiPatch );
681     ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
682
683     write_tables( stg, table_patch_data, NUM_PATCH_TABLES );
684
685     r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
686     ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
687
688     r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
689     ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
690
691     write_tables( stg1, table_transform1_data, NUM_TRANSFORM1_TABLES );
692     IStorage_Release( stg1 );
693
694     r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
695     ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
696
697     r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
698     ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
699
700     write_tables( stg2, table_transform2_data, NUM_TRANSFORM2_TABLES );
701     IStorage_Release( stg2 );
702     IStorage_Release( stg );
703 }
704
705 static void test_simple_patch( void )
706 {
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;
712
713     if (!pMsiApplyPatchA)
714     {
715         win_skip("MsiApplyPatchA is not available\n");
716         return;
717     }
718     if (is_process_limited())
719     {
720         skip("process is limited\n");
721         return;
722     }
723
724     CreateDirectoryA( "msitest", NULL );
725     create_file( "msitest\\patch.txt", 1000 );
726
727     create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
728     create_patch( mspfile );
729
730     MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
731
732     r = MsiInstallProductA( msifile, NULL );
733     if (r != ERROR_SUCCESS)
734     {
735         skip("Product installation failed with error code %u\n", r);
736         goto cleanup;
737     }
738
739     size = get_pf_file_size( "msitest\\patch.txt" );
740     ok( size == 1000, "expected 1000, got %u\n", size );
741
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 );
746
747     strcpy( path, CURR_DIR );
748     strcat( path, "\\" );
749     strcat( path, msifile );
750
751     r = MsiOpenPackageA( path, &hpackage );
752     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
753
754     hdb = MsiGetActiveDatabase( hpackage );
755     ok( hdb, "failed to get database handle\n" );
756
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 );
760
761     r = MsiViewExecute( hview, 0 );
762     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
763
764     r = MsiViewFetch( hview, &hrec );
765     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
766
767     MsiCloseHandle( hrec );
768     MsiViewClose( hview );
769     MsiCloseHandle( hview );
770
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 );
775
776     r = MsiViewExecute( hview, 0 );
777     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
778
779     r = MsiViewFetch( hview, &hrec );
780     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
781
782     MsiCloseHandle( hrec );
783     MsiViewClose( hview );
784     MsiCloseHandle( hview );
785
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 );
791
792     MsiCloseHandle( hdb );
793     MsiCloseHandle( hpackage );
794
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 );
798
799     if (r == ERROR_PATCH_PACKAGE_INVALID)
800     {
801         win_skip("Windows Installer < 3.0 detected\n");
802         goto uninstall;
803     }
804
805     size = get_pf_file_size( "msitest\\patch.txt" );
806     ok( size == 1002, "expected 1002, got %u\n", size );
807
808     /* show that MsiOpenPackage applies registered patches */
809     r = MsiOpenPackageA( path, &hpackage );
810     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
811
812     hdb = MsiGetActiveDatabase( hpackage );
813     ok( hdb, "failed to get database handle\n" );
814
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 );
818
819     r = MsiViewExecute( hview, 0 );
820     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
821
822     r = MsiViewFetch( hview, &hrec );
823     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
824
825     MsiCloseHandle( hrec );
826     MsiViewClose( hview );
827     MsiCloseHandle( hview );
828
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 );
833
834     r = MsiViewExecute( hview, 0 );
835     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
836
837     r = MsiViewFetch( hview, &hrec );
838     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
839
840     MsiCloseHandle( hrec );
841     MsiViewClose( hview );
842     MsiCloseHandle( hview );
843
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 );
849
850     MsiCloseHandle( hdb );
851     MsiCloseHandle( hpackage );
852
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 );
858
859     r = MsiOpenDatabaseA( path, MSIDBOPEN_READONLY, &hdb );
860     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
861
862     r = MsiDatabaseOpenView( hdb, query, &hview );
863     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
864
865     r = MsiViewExecute( hview, 0 );
866     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
867
868     r = MsiViewFetch( hview, &hrec );
869     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
870
871     MsiCloseHandle( hrec );
872     MsiViewClose( hview );
873     MsiCloseHandle( hview );
874     MsiCloseHandle( hdb );
875
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 );
882
883     r = MsiInstallProductA( msifile, "REMOVE=ALL" );
884     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
885
886     ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
887     ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
888
889 cleanup:
890     DeleteFileA( msifile );
891     DeleteFileA( mspfile );
892     DeleteFileA( "msitest\\patch.txt" );
893     RemoveDirectoryA( "msitest" );
894 }
895
896 static void test_MsiOpenDatabase( void )
897 {
898     UINT r;
899     MSIHANDLE hdb;
900
901     r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE, &hdb );
902     ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
903
904     r = MsiDatabaseCommit( hdb );
905     ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
906     MsiCloseHandle( hdb );
907
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 );
911
912     r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
913     ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
914
915     r = MsiDatabaseCommit( hdb );
916     ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
917     MsiCloseHandle( hdb );
918
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 );
923
924     create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
925     create_patch( mspfile );
926
927     r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
928     ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
929
930     r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
931     ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
932     MsiCloseHandle( hdb );
933
934     DeleteFileA( msifile );
935     DeleteFileA( mspfile );
936 }
937
938 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
939 {
940     static char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
941     char query[0x100];
942     UINT r;
943     MSIHANDLE hview, hrec;
944
945     sprintf( query, fmt, table, entry );
946     r = MsiDatabaseOpenView( hdb, query, &hview );
947     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
948
949     r = MsiViewExecute( hview, 0 );
950     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
951
952     r = MsiViewFetch( hview, &hrec );
953     MsiViewClose( hview );
954     MsiCloseHandle( hview );
955     MsiCloseHandle( hrec );
956     return r;
957 }
958
959 static void test_system_tables( void )
960 {
961     UINT r;
962     const char *query;
963     MSIHANDLE hproduct, hdb, hview, hrec;
964
965     if (!pMsiApplyPatchA)
966     {
967         win_skip("MsiApplyPatchA is not available\n");
968         return;
969     }
970     if (is_process_limited())
971     {
972         skip("process is limited\n");
973         return;
974     }
975
976     CreateDirectoryA( "msitest", NULL );
977     create_file( "msitest\\patch.txt", 1000 );
978
979     create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
980     create_patch( mspfile );
981
982     MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
983
984     r = MsiInstallProductA( msifile, NULL );
985     if (r != ERROR_SUCCESS)
986     {
987         skip("Product installation failed with error code %d\n", r);
988         goto cleanup;
989     }
990
991     r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
992     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
993
994     hdb = MsiGetActiveDatabase( hproduct );
995     ok( hdb, "failed to get database handle\n" );
996
997     r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
998     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
999
1000     query = "SELECT * FROM `_Storages`";
1001     r = MsiDatabaseOpenView( hdb, query, &hview );
1002     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1003
1004     r = MsiViewExecute( hview, 0 );
1005     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1006
1007     r = MsiViewFetch( hview, &hrec );
1008     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1009
1010     r = find_entry( hdb, "_Tables", "Directory" );
1011     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1012
1013     r = find_entry( hdb, "_Tables", "File" );
1014     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1015
1016     r = find_entry( hdb, "_Tables", "Component" );
1017     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1018
1019     r = find_entry( hdb, "_Tables", "Feature" );
1020     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1021
1022     r = find_entry( hdb, "_Tables", "FeatureComponents" );
1023     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1024
1025     r = find_entry( hdb, "_Tables", "Property" );
1026     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1027
1028     r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1029     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1030
1031     r = find_entry( hdb, "_Tables", "Media" );
1032     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1033
1034     r = find_entry( hdb, "_Tables", "_Property" );
1035     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1036
1037     MsiCloseHandle( hrec );
1038     MsiViewClose( hview );
1039     MsiCloseHandle( hview );
1040     MsiCloseHandle( hdb );
1041     MsiCloseHandle( hproduct );
1042
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 );
1046
1047     if (r == ERROR_PATCH_PACKAGE_INVALID)
1048     {
1049         win_skip("Windows Installer < 3.0 detected\n");
1050         goto uninstall;
1051     }
1052
1053     r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1054     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1055
1056     hdb = MsiGetActiveDatabase( hproduct );
1057     ok( hdb, "failed to get database handle\n" );
1058
1059     r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1060     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1061
1062     query = "SELECT * FROM `_Storages`";
1063     r = MsiDatabaseOpenView( hdb, query, &hview );
1064     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1065
1066     r = MsiViewExecute( hview, 0 );
1067     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1068
1069     r = MsiViewFetch( hview, &hrec );
1070     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1071
1072     r = find_entry( hdb, "_Tables", "Directory" );
1073     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1074
1075     r = find_entry( hdb, "_Tables", "File" );
1076     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1077
1078     r = find_entry( hdb, "_Tables", "Component" );
1079     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1080
1081     r = find_entry( hdb, "_Tables", "Feature" );
1082     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1083
1084     r = find_entry( hdb, "_Tables", "FeatureComponents" );
1085     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1086
1087     r = find_entry( hdb, "_Tables", "Property" );
1088     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1089
1090     r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1091     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1092
1093     r = find_entry( hdb, "_Tables", "Media" );
1094     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1095
1096     r = find_entry( hdb, "_Tables", "_Property" );
1097     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1098
1099     r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1100     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1101
1102     r = find_entry( hdb, "_Tables", "Patch" );
1103     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1104
1105     r = find_entry( hdb, "_Tables", "PatchPackage" );
1106     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1107
1108     MsiCloseHandle( hrec );
1109     MsiViewClose( hview );
1110     MsiCloseHandle( hview );
1111     MsiCloseHandle( hdb );
1112     MsiCloseHandle( hproduct );
1113
1114 uninstall:
1115     r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1116     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1117
1118 cleanup:
1119     DeleteFileA( msifile );
1120     DeleteFileA( mspfile );
1121     DeleteFileA( "msitest\\patch.txt" );
1122     RemoveDirectoryA( "msitest" );
1123 }
1124
1125 static void test_patch_registration( void )
1126 {
1127     UINT r, size;
1128     char buffer[MAX_PATH], patch_code[39];
1129
1130     if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1131     {
1132         win_skip("required functions not available\n");
1133         return;
1134     }
1135     if (is_process_limited())
1136     {
1137         skip("process is limited\n");
1138         return;
1139     }
1140
1141     CreateDirectoryA( "msitest", NULL );
1142     create_file( "msitest\\patch.txt", 1000 );
1143
1144     create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1145     create_patch( mspfile );
1146
1147     MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1148
1149     r = MsiInstallProductA( msifile, NULL );
1150     if (r != ERROR_SUCCESS)
1151     {
1152         skip("Product installation failed with error code %d\n", r);
1153         goto cleanup;
1154     }
1155
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 );
1159
1160     if (r == ERROR_PATCH_PACKAGE_INVALID)
1161     {
1162         win_skip("Windows Installer < 3.0 detected\n");
1163         goto uninstall;
1164     }
1165
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" );
1174
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 );
1182
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 );
1191
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" );
1197
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 );
1202
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 );
1207
1208 uninstall:
1209     r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1210     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1211
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 );
1219
1220 cleanup:
1221     DeleteFileA( msifile );
1222     DeleteFileA( mspfile );
1223     DeleteFileA( "msitest\\patch.txt" );
1224     RemoveDirectoryA( "msitest" );
1225 }
1226
1227 START_TEST(patch)
1228 {
1229     DWORD len;
1230     char temp_path[MAX_PATH], prev_path[MAX_PATH];
1231
1232     init_function_pointers();
1233
1234     GetCurrentDirectoryA( MAX_PATH, prev_path );
1235     GetTempPath( MAX_PATH, temp_path );
1236     SetCurrentDirectoryA( temp_path );
1237
1238     strcpy( CURR_DIR, temp_path );
1239     len = strlen( CURR_DIR );
1240
1241     if (len && (CURR_DIR[len - 1] == '\\'))
1242         CURR_DIR[len - 1] = 0;
1243
1244     get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1245
1246     test_simple_patch();
1247     test_MsiOpenDatabase();
1248     test_system_tables();
1249     test_patch_registration();
1250
1251     SetCurrentDirectoryA( prev_path );
1252 }