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