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