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