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