Sync advapi32, gdi32, gdiplus, inetmib1, kernel32, mlang, msi, msvcrt, ntdll, oleaut3...
[reactos.git] / rostests / winetests / msi / 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 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
704
705 size = get_pf_file_size( "msitest\\patch.txt" );
706 ok( size == 1000, "expected 1000, got %u\n", size );
707
708 size = sizeof(install_source);
709 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
710 "InstallSource", install_source, &size );
711 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
712
713 strcpy( path, CURR_DIR );
714 strcat( path, "\\" );
715 strcat( path, msifile );
716
717 r = MsiOpenPackageA( path, &hpackage );
718 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
719
720 hdb = MsiGetActiveDatabase( hpackage );
721 ok( hdb, "failed to get database handle\n" );
722
723 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
724 r = MsiDatabaseOpenView( hdb, query, &hview );
725 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
726
727 r = MsiViewExecute( hview, 0 );
728 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
729
730 r = MsiViewFetch( hview, &hrec );
731 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
732
733 MsiCloseHandle( hrec );
734 MsiViewClose( hview );
735 MsiCloseHandle( hview );
736
737 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
738 "AND `Value` = 'Installer Database'";
739 r = MsiDatabaseOpenView( hdb, query, &hview );
740 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
741
742 r = MsiViewExecute( hview, 0 );
743 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
744
745 r = MsiViewFetch( hview, &hrec );
746 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
747
748 MsiCloseHandle( hrec );
749 MsiViewClose( hview );
750 MsiCloseHandle( hview );
751
752 MsiCloseHandle( hdb );
753 MsiCloseHandle( hpackage );
754
755 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
756 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
757 "expected ERROR_SUCCESS, got %u\n", r );
758
759 if (r == ERROR_PATCH_PACKAGE_INVALID)
760 {
761 win_skip("Windows Installer < 3.0 detected\n");
762 return;
763 }
764
765 size = get_pf_file_size( "msitest\\patch.txt" );
766 ok( size == 1002, "expected 1002, got %u\n", size );
767
768 /* show that MsiOpenPackage applies registered patches */
769 r = MsiOpenPackageA( path, &hpackage );
770 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
771
772 hdb = MsiGetActiveDatabase( hpackage );
773 ok( hdb, "failed to get database handle\n" );
774
775 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
776 r = MsiDatabaseOpenView( hdb, query, &hview );
777 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
778
779 r = MsiViewExecute( hview, 0 );
780 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
781
782 r = MsiViewFetch( hview, &hrec );
783 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
784
785 MsiCloseHandle( hrec );
786 MsiViewClose( hview );
787 MsiCloseHandle( hview );
788
789 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
790 "AND `Value` = 'Installation Database'";
791 r = MsiDatabaseOpenView( hdb, query, &hview );
792 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
793
794 r = MsiViewExecute( hview, 0 );
795 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
796
797 r = MsiViewFetch( hview, &hrec );
798 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
799
800 MsiCloseHandle( hrec );
801 MsiViewClose( hview );
802 MsiCloseHandle( hview );
803
804 MsiCloseHandle( hdb );
805 MsiCloseHandle( hpackage );
806
807 /* show that patches are not committed to the local package database */
808 size = sizeof(path);
809 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
810 "LocalPackage", path, &size );
811 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
812
813 r = MsiOpenDatabaseA( path, MSIDBOPEN_READONLY, &hdb );
814 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
815
816 r = MsiDatabaseOpenView( hdb, query, &hview );
817 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
818
819 r = MsiViewExecute( hview, 0 );
820 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
821
822 r = MsiViewFetch( hview, &hrec );
823 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
824
825 MsiCloseHandle( hrec );
826 MsiViewClose( hview );
827 MsiCloseHandle( hview );
828 MsiCloseHandle( hdb );
829
830 size = sizeof(path);
831 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
832 "InstallSource", path, &size );
833 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
834 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
835
836 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
837 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
838
839 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
840 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
841
842 DeleteFileA( msifile );
843 DeleteFileA( mspfile );
844 RemoveDirectoryA( "msitest" );
845 }
846
847 static void test_MsiOpenDatabase( void )
848 {
849 UINT r;
850 MSIHANDLE hdb;
851
852 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE, &hdb );
853 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
854
855 r = MsiDatabaseCommit( hdb );
856 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
857 MsiCloseHandle( hdb );
858
859 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
860 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
861 DeleteFileA( mspfile );
862
863 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
864 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
865
866 r = MsiDatabaseCommit( hdb );
867 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
868 MsiCloseHandle( hdb );
869
870 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
871 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
872 MsiCloseHandle( hdb );
873 DeleteFileA( mspfile );
874
875 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
876 create_patch( mspfile );
877
878 r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
879 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
880
881 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
882 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
883 MsiCloseHandle( hdb );
884
885 DeleteFileA( msifile );
886 DeleteFileA( mspfile );
887 }
888
889 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
890 {
891 static char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
892 char query[0x100];
893 UINT r;
894 MSIHANDLE hview, hrec;
895
896 sprintf( query, fmt, table, entry );
897 r = MsiDatabaseOpenView( hdb, query, &hview );
898 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
899
900 r = MsiViewExecute( hview, 0 );
901 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
902
903 r = MsiViewFetch( hview, &hrec );
904 MsiViewClose( hview );
905 MsiCloseHandle( hview );
906 MsiCloseHandle( hrec );
907 return r;
908 }
909
910 static void test_system_tables( void )
911 {
912 UINT r;
913 const char *query;
914 MSIHANDLE hproduct, hdb, hview, hrec;
915
916 if (!pMsiApplyPatchA)
917 {
918 win_skip("MsiApplyPatchA is not available\n");
919 return;
920 }
921
922 CreateDirectoryA( "msitest", NULL );
923 create_file( "msitest\\patch.txt", 1000 );
924
925 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
926 create_patch( mspfile );
927
928 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
929
930 r = MsiInstallProductA( msifile, NULL );
931 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
932
933 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
934 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
935
936 hdb = MsiGetActiveDatabase( hproduct );
937 ok( hdb, "failed to get database handle\n" );
938
939 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
940 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
941
942 query = "SELECT * FROM `_Storages`";
943 r = MsiDatabaseOpenView( hdb, query, &hview );
944 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
945
946 r = MsiViewExecute( hview, 0 );
947 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
948
949 r = MsiViewFetch( hview, &hrec );
950 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
951
952 r = find_entry( hdb, "_Tables", "Directory" );
953 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
954
955 r = find_entry( hdb, "_Tables", "File" );
956 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
957
958 r = find_entry( hdb, "_Tables", "Component" );
959 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
960
961 r = find_entry( hdb, "_Tables", "Feature" );
962 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
963
964 r = find_entry( hdb, "_Tables", "FeatureComponents" );
965 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
966
967 r = find_entry( hdb, "_Tables", "Property" );
968 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
969
970 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
971 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
972
973 r = find_entry( hdb, "_Tables", "Media" );
974 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
975
976 r = find_entry( hdb, "_Tables", "_Property" );
977 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
978
979 MsiCloseHandle( hrec );
980 MsiViewClose( hview );
981 MsiCloseHandle( hview );
982 MsiCloseHandle( hdb );
983 MsiCloseHandle( hproduct );
984
985 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
986 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
987 "expected ERROR_SUCCESS, got %u\n", r );
988
989 if (r == ERROR_PATCH_PACKAGE_INVALID)
990 {
991 win_skip("Windows Installer < 3.0 detected\n");
992 return;
993 }
994
995 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
996 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
997
998 hdb = MsiGetActiveDatabase( hproduct );
999 ok( hdb, "failed to get database handle\n" );
1000
1001 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1002 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1003
1004 query = "SELECT * FROM `_Storages`";
1005 r = MsiDatabaseOpenView( hdb, query, &hview );
1006 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1007
1008 r = MsiViewExecute( hview, 0 );
1009 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1010
1011 r = MsiViewFetch( hview, &hrec );
1012 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1013
1014 r = find_entry( hdb, "_Tables", "Directory" );
1015 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1016
1017 r = find_entry( hdb, "_Tables", "File" );
1018 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1019
1020 r = find_entry( hdb, "_Tables", "Component" );
1021 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1022
1023 r = find_entry( hdb, "_Tables", "Feature" );
1024 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1025
1026 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1027 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1028
1029 r = find_entry( hdb, "_Tables", "Property" );
1030 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1031
1032 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1033 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1034
1035 r = find_entry( hdb, "_Tables", "Media" );
1036 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1037
1038 r = find_entry( hdb, "_Tables", "_Property" );
1039 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1040
1041 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1042 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1043
1044 r = find_entry( hdb, "_Tables", "Patch" );
1045 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1046
1047 r = find_entry( hdb, "_Tables", "PatchPackage" );
1048 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1049
1050 MsiCloseHandle( hrec );
1051 MsiViewClose( hview );
1052 MsiCloseHandle( hview );
1053 MsiCloseHandle( hdb );
1054 MsiCloseHandle( hproduct );
1055
1056 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1057 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1058
1059 DeleteFileA( msifile );
1060 DeleteFileA( mspfile );
1061 RemoveDirectoryA( "msitest" );
1062 }
1063
1064 static void test_patch_registration( void )
1065 {
1066 UINT r, size;
1067 char buffer[MAX_PATH], patch_code[39];
1068
1069 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1070 {
1071 win_skip("required functions not available\n");
1072 return;
1073 }
1074
1075 CreateDirectoryA( "msitest", NULL );
1076 create_file( "msitest\\patch.txt", 1000 );
1077
1078 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1079 create_patch( mspfile );
1080
1081 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1082
1083 r = MsiInstallProductA( msifile, NULL );
1084 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1085
1086 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1087 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1088 "expected ERROR_SUCCESS, got %u\n", r );
1089
1090 if (r == ERROR_PATCH_PACKAGE_INVALID)
1091 {
1092 win_skip("Windows Installer < 3.0 detected\n");
1093 return;
1094 }
1095
1096 buffer[0] = 0;
1097 size = sizeof(buffer);
1098 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1099 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1100 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1101 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1102 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1103 ok( buffer[0], "buffer empty\n" );
1104
1105 buffer[0] = 0;
1106 size = sizeof(buffer);
1107 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1108 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1109 NULL, MSIINSTALLCONTEXT_MACHINE,
1110 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1111 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1112
1113 buffer[0] = 0;
1114 size = sizeof(buffer);
1115 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1116 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1117 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1118 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1119 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1120 ok( !buffer[0], "got %s\n", buffer );
1121
1122 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1123 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1124 0, patch_code, NULL, NULL, NULL, NULL );
1125 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1126 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1127
1128 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1129 NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1130 0, patch_code, NULL, NULL, NULL, NULL );
1131 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1132
1133 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1134 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1135 0, patch_code, NULL, NULL, NULL, NULL );
1136 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1137
1138 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1139 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1140
1141 buffer[0] = 0;
1142 size = sizeof(buffer);
1143 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1144 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1145 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1146 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1147 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1148
1149 DeleteFileA( msifile );
1150 DeleteFileA( mspfile );
1151 RemoveDirectoryA( "msitest" );
1152 }
1153
1154 START_TEST(patch)
1155 {
1156 DWORD len;
1157 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1158
1159 init_function_pointers();
1160
1161 GetCurrentDirectoryA( MAX_PATH, prev_path );
1162 GetTempPath( MAX_PATH, temp_path );
1163 SetCurrentDirectoryA( temp_path );
1164
1165 strcpy( CURR_DIR, temp_path );
1166 len = strlen( CURR_DIR );
1167
1168 if (len && (CURR_DIR[len - 1] == '\\'))
1169 CURR_DIR[len - 1] = 0;
1170
1171 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1172
1173 test_simple_patch();
1174 test_MsiOpenDatabase();
1175 test_system_tables();
1176 test_patch_registration();
1177
1178 SetCurrentDirectoryA( prev_path );
1179 }