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