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