user32: Use the stored color and mask bitmaps instead of the raw bits in GetIconInfo.
[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( hdb );
924     MsiCloseHandle( hproduct );
925
926     r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
927     ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
928         "expected ERROR_SUCCESS, got %u\n", r );
929
930     if (r == ERROR_PATCH_PACKAGE_INVALID)
931     {
932         win_skip("Windows Installer < 3.0 detected\n");
933         return;
934     }
935
936     r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
937     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
938
939     hdb = MsiGetActiveDatabase( hproduct );
940     ok( hdb, "failed to get database handle\n" );
941
942     r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
943     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
944
945     query = "SELECT * FROM `_Storages`";
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     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
954
955     r = find_entry( hdb, "_Tables", "Directory" );
956     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
957
958     r = find_entry( hdb, "_Tables", "File" );
959     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
960
961     r = find_entry( hdb, "_Tables", "Component" );
962     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
963
964     r = find_entry( hdb, "_Tables", "Feature" );
965     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
966
967     r = find_entry( hdb, "_Tables", "FeatureComponents" );
968     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
969
970     r = find_entry( hdb, "_Tables", "Property" );
971     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
972
973     r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
974     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
975
976     r = find_entry( hdb, "_Tables", "Media" );
977     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
978
979     r = find_entry( hdb, "_Tables", "_Property" );
980     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
981
982     r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
983     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
984
985     r = find_entry( hdb, "_Tables", "Patch" );
986     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
987
988     r = find_entry( hdb, "_Tables", "PatchPackage" );
989     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
990
991     MsiCloseHandle( hdb );
992     MsiCloseHandle( hproduct );
993
994     r = MsiInstallProductA( msifile, "REMOVE=ALL" );
995     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
996
997     DeleteFileA( msifile );
998     DeleteFileA( mspfile );
999     RemoveDirectoryA( "msitest" );
1000 }
1001
1002 static void test_patch_registration( void )
1003 {
1004     UINT r, size;
1005     char buffer[MAX_PATH], patch_code[39];
1006
1007     if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1008     {
1009         win_skip("required functions not available\n");
1010         return;
1011     }
1012
1013     CreateDirectoryA( "msitest", NULL );
1014     create_file( "msitest\\patch.txt", 1000 );
1015
1016     create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1017     create_patch( mspfile );
1018
1019     MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1020
1021     r = MsiInstallProductA( msifile, NULL );
1022     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1023
1024     r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1025     ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1026         "expected ERROR_SUCCESS, got %u\n", r );
1027
1028     if (r == ERROR_PATCH_PACKAGE_INVALID)
1029     {
1030         win_skip("Windows Installer < 3.0 detected\n");
1031         return;
1032     }
1033
1034     buffer[0] = 0;
1035     size = sizeof(buffer);
1036     r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1037                              "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1038                               NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1039                               INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1040     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1041     ok( buffer[0], "buffer empty\n" );
1042
1043     buffer[0] = 0;
1044     size = sizeof(buffer);
1045     r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1046                              "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1047                              NULL, MSIINSTALLCONTEXT_MACHINE,
1048                              INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1049     ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1050
1051     buffer[0] = 0;
1052     size = sizeof(buffer);
1053     r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1054                              "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1055                              NULL, MSIINSTALLCONTEXT_USERMANAGED,
1056                              INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1057     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1058     ok( !buffer[0], "got %s\n", buffer );
1059
1060     r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1061                            NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1062                            0, patch_code, NULL, NULL, NULL, NULL );
1063     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1064     ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1065
1066     r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1067                            NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1068                            0, patch_code, NULL, NULL, NULL, NULL );
1069     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1070
1071     r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1072                            NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1073                            0, patch_code, NULL, NULL, NULL, NULL );
1074     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1075
1076     r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1077     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1078
1079     buffer[0] = 0;
1080     size = sizeof(buffer);
1081     r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1082                              "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1083                               NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1084                               INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1085     ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1086
1087     DeleteFileA( msifile );
1088     DeleteFileA( mspfile );
1089     RemoveDirectoryA( "msitest" );
1090 }
1091
1092 START_TEST(patch)
1093 {
1094     DWORD len;
1095     char temp_path[MAX_PATH], prev_path[MAX_PATH];
1096
1097     init_function_pointers();
1098
1099     GetCurrentDirectoryA( MAX_PATH, prev_path );
1100     GetTempPath( MAX_PATH, temp_path );
1101     SetCurrentDirectoryA( temp_path );
1102
1103     strcpy( CURR_DIR, temp_path );
1104     len = strlen( CURR_DIR );
1105
1106     if (len && (CURR_DIR[len - 1] == '\\'))
1107         CURR_DIR[len - 1] = 0;
1108
1109     get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1110
1111     test_simple_patch();
1112     test_MsiOpenDatabase();
1113     test_system_tables();
1114     test_patch_registration();
1115
1116     SetCurrentDirectoryA( prev_path );
1117 }