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