2 * Copyright 2010 Hans Leidekker for CodeWeavers
4 * A test program for patching MSI products.
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.
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.
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
21 #define _WIN32_MSI 300
31 #include "wine/test.h"
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
);
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};
47 static char CURR_DIR
[MAX_PATH
];
48 static char PROG_FILES_DIR
[MAX_PATH
];
49 static char COMMON_FILES_DIR
[MAX_PATH
];
51 /* msi database data */
53 static const char property_dat
[] =
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";
66 static const char media_dat
[] =
67 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
68 "i2\ti4\tL64\tS255\tS32\tS72\n"
70 "1\t1\t\t\tDISK1\t\n";
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"
76 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
78 static const char directory_dat
[] =
79 "Directory\tDirectory_Parent\tDefaultDir\n"
81 "Directory\tDirectory\n"
82 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
83 "ProgramFilesFolder\tTARGETDIR\t.\n"
84 "TARGETDIR\t\tSourceDir";
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";
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"
96 "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n";
98 static const char feature_comp_dat
[] =
99 "Feature_\tComponent_\n"
101 "FeatureComponents\tFeature_\tComponent_\n"
104 static const char install_exec_seq_dat
[] =
105 "Action\tCondition\tSequence\n"
107 "InstallExecuteSequence\tAction\n"
108 "LaunchConditions\t\t100\n"
109 "CostInitialize\t\t800\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";
125 const char *filename
;
130 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
132 static const struct msi_table tables
[] =
134 ADD_TABLE( directory
),
136 ADD_TABLE( component
),
137 ADD_TABLE( feature
),
138 ADD_TABLE( feature_comp
),
139 ADD_TABLE( property
),
140 ADD_TABLE( install_exec_seq
),
144 static void init_function_pointers( void )
146 HMODULE hmsi
= GetModuleHandleA( "msi.dll" );
147 HMODULE hadvapi32
= GetModuleHandleA( "advapi32.dll" );
149 #define GET_PROC( mod, func ) \
150 p ## func = (void *)GetProcAddress( mod, #func ); \
152 trace( "GetProcAddress(%s) failed\n", #func );
154 GET_PROC( hmsi
, MsiApplyPatchA
);
155 GET_PROC( hmsi
, MsiGetPatchInfoExA
);
156 GET_PROC( hmsi
, MsiEnumPatchesExA
);
158 GET_PROC( hadvapi32
, OpenProcessToken
);
162 static BOOL
is_process_limited(void)
166 if (!pOpenProcessToken
) return FALSE
;
168 if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &token
))
171 TOKEN_ELEVATION_TYPE type
= TokenElevationTypeDefault
;
174 ret
= GetTokenInformation(token
, TokenElevationType
, &type
, sizeof(type
), &size
);
176 return (ret
&& type
== TokenElevationTypeLimited
);
181 static BOOL
get_program_files_dir( char *buf
, char *buf2
)
186 if (RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey
))
190 if (RegQueryValueExA( hkey
, "ProgramFilesDir (x86)", 0, &type
, (LPBYTE
)buf
, &size
) &&
191 RegQueryValueExA( hkey
, "ProgramFilesDir", 0, &type
, (LPBYTE
)buf
, &size
))
197 if (RegQueryValueExA( hkey
, "CommonFilesDir", 0, &type
, (LPBYTE
)buf2
, &size
))
206 static void create_file_data( const char *filename
, const char *data
, DWORD size
)
211 file
= CreateFileA( filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
212 if (file
== INVALID_HANDLE_VALUE
)
215 WriteFile( file
, data
, strlen( data
), &written
, NULL
);
218 SetFilePointer( file
, size
, NULL
, FILE_BEGIN
);
219 SetEndOfFile( file
);
224 #define create_file( name, size ) create_file_data( name, name, size )
226 static BOOL
delete_pf( const char *rel_path
, BOOL is_file
)
230 strcpy( path
, PROG_FILES_DIR
);
231 strcat( path
, "\\" );
232 strcat( path
, rel_path
);
235 return DeleteFileA( path
);
237 return RemoveDirectoryA( path
);
240 static DWORD
get_pf_file_size( const char *filename
)
246 strcpy( path
, PROG_FILES_DIR
);
248 strcat( path
, filename
);
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
;
254 size
= GetFileSize( file
, NULL
);
259 static void write_file( const char *filename
, const char *data
, DWORD data_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
);
268 static void set_suminfo( const WCHAR
*filename
)
273 r
= MsiOpenDatabaseW( filename
, MSIDBOPEN_DIRECT
, &hdb
);
274 ok( r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
276 r
= MsiGetSummaryInformationA( hdb
, NULL
, 7, &hsi
);
277 ok( r
== ERROR_SUCCESS
, "failed to open summaryinfo %u\n", r
);
279 r
= MsiSummaryInfoSetPropertyA( hsi
, 2, VT_LPSTR
, 0, NULL
, "Installation Database" );
280 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
282 r
= MsiSummaryInfoSetPropertyA( hsi
, 3, VT_LPSTR
, 0, NULL
, "Installation Database" );
283 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
285 r
= MsiSummaryInfoSetPropertyA( hsi
, 4, VT_LPSTR
, 0, NULL
, "WineHQ" );
286 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
288 r
= MsiSummaryInfoSetPropertyA( hsi
, 7, VT_LPSTR
, 0, NULL
, ";1033" );
289 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
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
);
294 r
= MsiSummaryInfoSetPropertyA( hsi
, 14, VT_I4
, 100, NULL
, NULL
);
295 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
297 r
= MsiSummaryInfoSetPropertyA( hsi
, 15, VT_I4
, 0, NULL
, NULL
);
298 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
300 r
= MsiSummaryInfoPersist( hsi
);
301 ok( r
== ERROR_SUCCESS
, "failed to persist suminfo %u\n", r
);
303 r
= MsiCloseHandle( hsi
);
304 ok( r
== ERROR_SUCCESS
, "failed to close suminfo %u\n", r
);
306 r
= MsiCloseHandle( hdb
);
307 ok( r
== ERROR_SUCCESS
, "failed to close database %u\n", r
);
310 static void create_database( const char *filename
, const struct msi_table
*tables
, UINT num_tables
)
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
);
321 r
= MsiOpenDatabaseW( filenameW
, MSIDBOPEN_CREATE
, &hdb
);
322 ok(r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
324 /* import the tables into the database */
325 for (i
= 0; i
< num_tables
; i
++)
327 const struct msi_table
*table
= &tables
[i
];
329 write_file( table
->filename
, table
->data
, (table
->size
- 1) * sizeof(char) );
331 r
= MsiDatabaseImportA( hdb
, CURR_DIR
, table
->filename
);
332 ok(r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
334 DeleteFileA( table
->filename
);
337 r
= MsiDatabaseCommit( hdb
);
338 ok(r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
340 MsiCloseHandle( hdb
);
341 set_suminfo( filenameW
);
342 HeapFree( GetProcessHeap(), 0, filenameW
);
345 /* data for generating a patch */
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 */
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
368 static const WCHAR p_data1
[] = { /* _Tables */
371 static const char p_data2
[] = { /* _StringData */
372 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
374 static const WCHAR p_data3
[] = { /* _StringPool */
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' */
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
401 static const WCHAR p_data5
[] = { /* MsiPatchSequence */
402 0x0007, 0x0000, 0x0006, 0x8000
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
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
}
448 #define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
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 */
457 static const WCHAR t1_data0
[] = { /* File */
458 0x0008, 0x0001, 0x03ea, 0x8000
460 static const char t1_data1
[] = { /* _StringData */
463 static const WCHAR t1_data2
[] = { /* _StringPool */
465 0, 0, /* string 0 '' */
466 9, 1, /* string 1 'patch.txt' */
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, 0x9c, 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, 0xf4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
481 0x04, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00,
482 0x00, 0x10, 0x00, 0x00, 0x00, 0x94, 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, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31,
495 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06,
496 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00,
497 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 0x39, 0x31,
498 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
499 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
500 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
501 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x39, 0x31,
502 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
503 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
504 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
505 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x41, 0x32,
506 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45, 0x32, 0x43,
507 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30, 0x39, 0x2d,
508 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35, 0x46, 0x34,
509 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
510 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x09
513 static const struct table_data table_transform1_data
[] = {
514 { t1_name0
, t1_data0
, sizeof t1_data0
},
515 { t1_name1
, t1_data1
, sizeof t1_data1
- 1 },
516 { t1_name2
, t1_data2
, sizeof t1_data2
},
517 { t1_name3
, t1_data3
, sizeof t1_data3
}
520 #define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
522 static const WCHAR t2_name0
[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
523 static const WCHAR t2_name1
[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
524 static const WCHAR t2_name2
[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
525 static const WCHAR t2_name3
[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
526 static const WCHAR t2_name4
[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
527 static const WCHAR t2_name5
[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
528 static const WCHAR t2_name6
[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
529 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
530 static const WCHAR t2_name7
[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
531 static const WCHAR t2_name8
[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
532 static const WCHAR t2_name9
[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
533 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
534 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
536 static const WCHAR t2_data0
[] = { /* File */
537 0x00c0, 0x0001, 0x9000, 0x83e8
539 static const WCHAR t2_data1
[] = { /* Media */
540 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
542 static const WCHAR t2_data2
[] = { /* _Columns */
543 0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
544 0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
545 0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
546 0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
547 0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
548 0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
551 static const WCHAR t2_data3
[] = { /* _Tables */
552 0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
554 static const WCHAR t2_data4
[] = { /* Property */
555 0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
557 static const WCHAR t2_data5
[] = { /* PatchPackage */
558 0x0201, 0x0013, 0x8002
560 static const WCHAR t2_data6
[] = { /* InstallExecuteSequence */
561 0x0301, 0x0006, 0x0000, 0x87d1
563 static const char t2_data7
[] = { /* _StringData */
564 "patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
565 "PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
566 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
568 static const WCHAR t2_data8
[] = { /* _StringPool */
570 0, 0, /* string 0 '' */
571 9, 1, /* string 1 'patch.txt' */
572 22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
573 21, 1, /* string 3 'Installation Database' */
574 19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
575 38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
576 10, 1, /* string 6 'PatchFiles' */
577 12, 1, /* string 7 '#CAB_msitest' */
578 4, 1, /* string 8 'prop' */
579 5, 7, /* string 9 'Patch' */
580 5, 1, /* string 10 'File_' */
581 8, 1, /* string 11 'Sequence' */
582 9, 1, /* string 12 'PatchSize' */
583 10, 1, /* string 13 'Attributes' */
584 6, 2, /* string 14 'Header' */
585 10, 1, /* string 15 'StreamRef_' */
586 12, 3, /* string 16 'PatchPackage' */
587 7, 1, /* string 17 'PatchId' */
588 6, 1, /* string 18 'Media_' */
589 38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
590 15, 3, /* string 20 'MsiPatchHeaders' */
591 9, 1 /* string 21 'StreamRef' */
593 static const char t2_data9
[] = { /* SummaryInformation */
594 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
597 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
598 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
599 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
600 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
601 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
602 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
603 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
604 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
605 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
606 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
607 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
611 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
614 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
615 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
617 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
618 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
619 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
620 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
621 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
622 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
623 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
624 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
625 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
626 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
627 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
628 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
629 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
632 static const struct table_data table_transform2_data
[] = {
633 { t2_name0
, t2_data0
, sizeof t2_data0
},
634 { t2_name1
, t2_data1
, sizeof t2_data1
},
635 { t2_name2
, t2_data2
, sizeof t2_data2
},
636 { t2_name3
, t2_data3
, sizeof t2_data3
},
637 { t2_name4
, t2_data4
, sizeof t2_data4
},
638 { t2_name5
, t2_data5
, sizeof t2_data5
},
639 { t2_name6
, t2_data6
, sizeof t2_data6
},
640 { t2_name7
, t2_data7
, sizeof t2_data7
- 1 },
641 { t2_name8
, t2_data8
, sizeof t2_data8
},
642 { t2_name9
, t2_data9
, sizeof t2_data9
}
645 #define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
647 static void write_tables( IStorage
*stg
, const struct table_data
*tables
, UINT num_tables
)
653 for (i
= 0; i
< num_tables
; i
++)
655 r
= IStorage_CreateStream( stg
, tables
[i
].name
, STGM_WRITE
|STGM_SHARE_EXCLUSIVE
, 0, 0, &stm
);
658 ok( 0, "failed to create stream 0x%08x\n", r
);
662 r
= IStream_Write( stm
, tables
[i
].data
, tables
[i
].size
, &count
);
663 if (FAILED( r
) || count
!= tables
[i
].size
)
664 ok( 0, "failed to write stream\n" );
665 IStream_Release( stm
);
669 static void create_patch( const char *filename
)
671 IStorage
*stg
= NULL
, *stg1
= NULL
, *stg2
= NULL
;
675 const DWORD mode
= STGM_CREATE
|STGM_READWRITE
|STGM_DIRECT
|STGM_SHARE_EXCLUSIVE
;
677 const CLSID CLSID_MsiPatch
= {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
678 const CLSID CLSID_MsiTransform
= {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
680 len
= MultiByteToWideChar( CP_ACP
, 0, filename
, -1, NULL
, 0 );
681 filenameW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
682 MultiByteToWideChar( CP_ACP
, 0, filename
, -1, filenameW
, len
);
684 r
= StgCreateDocfile( filenameW
, mode
, 0, &stg
);
685 HeapFree( GetProcessHeap(), 0, filenameW
);
686 ok( r
== S_OK
, "failed to create storage 0x%08x\n", r
);
690 r
= IStorage_SetClass( stg
, &CLSID_MsiPatch
);
691 ok( r
== S_OK
, "failed to set storage type 0x%08x\n", r
);
693 write_tables( stg
, table_patch_data
, NUM_PATCH_TABLES
);
695 r
= IStorage_CreateStorage( stg
, p_name7
, mode
, 0, 0, &stg1
);
696 ok( r
== S_OK
, "failed to create substorage 0x%08x\n", r
);
698 r
= IStorage_SetClass( stg1
, &CLSID_MsiTransform
);
699 ok( r
== S_OK
, "failed to set storage type 0x%08x\n", r
);
701 write_tables( stg1
, table_transform1_data
, NUM_TRANSFORM1_TABLES
);
702 IStorage_Release( stg1
);
704 r
= IStorage_CreateStorage( stg
, p_name8
, mode
, 0, 0, &stg2
);
705 ok( r
== S_OK
, "failed to create substorage 0x%08x\n", r
);
707 r
= IStorage_SetClass( stg2
, &CLSID_MsiTransform
);
708 ok( r
== S_OK
, "failed to set storage type 0x%08x\n", r
);
710 write_tables( stg2
, table_transform2_data
, NUM_TRANSFORM2_TABLES
);
711 IStorage_Release( stg2
);
712 IStorage_Release( stg
);
715 static void test_simple_patch( void )
719 char path
[MAX_PATH
], install_source
[MAX_PATH
], buffer
[32];
721 WCHAR pathW
[MAX_PATH
];
722 MSIHANDLE hpackage
, hdb
, hview
, hrec
;
724 if (!pMsiApplyPatchA
)
726 win_skip("MsiApplyPatchA is not available\n");
729 if (is_process_limited())
731 skip("process is limited\n");
735 CreateDirectoryA( "msitest", NULL
);
736 create_file( "msitest\\patch.txt", 1000 );
738 create_database( msifile
, tables
, sizeof(tables
) / sizeof(struct msi_table
) );
739 create_patch( mspfile
);
741 MsiSetInternalUI( INSTALLUILEVEL_NONE
, NULL
);
743 r
= MsiInstallProductA( msifile
, NULL
);
744 if (r
!= ERROR_SUCCESS
)
746 skip("Product installation failed with error code %u\n", r
);
750 size
= get_pf_file_size( "msitest\\patch.txt" );
751 ok( size
== 1000, "expected 1000, got %u\n", size
);
753 size
= sizeof(install_source
);
754 r
= MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
755 "InstallSource", install_source
, &size
);
756 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
758 strcpy( path
, CURR_DIR
);
759 strcat( path
, "\\" );
760 strcat( path
, msifile
);
762 r
= MsiOpenPackageA( path
, &hpackage
);
763 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
765 hdb
= MsiGetActiveDatabase( hpackage
);
766 ok( hdb
, "failed to get database handle\n" );
768 query
= "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
769 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
770 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
772 r
= MsiViewExecute( hview
, 0 );
773 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
775 r
= MsiViewFetch( hview
, &hrec
);
776 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
778 MsiCloseHandle( hrec
);
779 MsiViewClose( hview
);
780 MsiCloseHandle( hview
);
782 query
= "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
783 "AND `Value` = 'Installer Database'";
784 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
785 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
787 r
= MsiViewExecute( hview
, 0 );
788 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
790 r
= MsiViewFetch( hview
, &hrec
);
791 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
793 MsiCloseHandle( hrec
);
794 MsiViewClose( hview
);
795 MsiCloseHandle( hview
);
798 size
= sizeof(buffer
);
799 r
= MsiGetPropertyA( hpackage
, "PATCHNEWSUMMARYSUBJECT", buffer
, &size
);
800 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
801 ok( !strcmp( buffer
, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer
);
803 MsiCloseHandle( hdb
);
804 MsiCloseHandle( hpackage
);
806 r
= MsiApplyPatchA( mspfile
, NULL
, INSTALLTYPE_DEFAULT
, NULL
);
807 ok( r
== ERROR_SUCCESS
|| broken( r
== ERROR_PATCH_PACKAGE_INVALID
), /* version 2.0 */
808 "expected ERROR_SUCCESS, got %u\n", r
);
810 if (r
== ERROR_PATCH_PACKAGE_INVALID
)
812 win_skip("Windows Installer < 3.0 detected\n");
816 size
= get_pf_file_size( "msitest\\patch.txt" );
817 ok( size
== 1002, "expected 1002, got %u\n", size
);
819 /* show that MsiOpenPackage applies registered patches */
820 r
= MsiOpenPackageA( path
, &hpackage
);
821 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
823 hdb
= MsiGetActiveDatabase( hpackage
);
824 ok( hdb
, "failed to get database handle\n" );
826 query
= "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
827 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
828 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
830 r
= MsiViewExecute( hview
, 0 );
831 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
833 r
= MsiViewFetch( hview
, &hrec
);
834 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
836 MsiCloseHandle( hrec
);
837 MsiViewClose( hview
);
838 MsiCloseHandle( hview
);
840 query
= "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
841 "AND `Value` = 'Installation Database'";
842 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
843 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
845 r
= MsiViewExecute( hview
, 0 );
846 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
848 r
= MsiViewFetch( hview
, &hrec
);
849 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
851 MsiCloseHandle( hrec
);
852 MsiViewClose( hview
);
853 MsiCloseHandle( hview
);
856 size
= sizeof(buffer
);
857 r
= MsiGetPropertyA( hpackage
, "PATCHNEWSUMMARYSUBJECT", buffer
, &size
);
858 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
859 ok( !strcmp( buffer
, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer
);
861 MsiCloseHandle( hdb
);
862 MsiCloseHandle( hpackage
);
864 /* show that patches are not committed to the local package database */
866 r
= MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
867 "LocalPackage", path
, &size
);
868 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
870 MultiByteToWideChar( CP_ACP
, 0, path
, -1, pathW
, MAX_PATH
);
871 r
= MsiOpenDatabaseW( pathW
, MSIDBOPEN_READONLY
, &hdb
);
872 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
874 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
875 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
877 r
= MsiViewExecute( hview
, 0 );
878 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
880 r
= MsiViewFetch( hview
, &hrec
);
881 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
883 MsiCloseHandle( hrec
);
884 MsiViewClose( hview
);
885 MsiCloseHandle( hview
);
886 MsiCloseHandle( hdb
);
890 r
= MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
891 "InstallSource", path
, &size
);
892 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
893 ok( !strcasecmp( path
, install_source
), "wrong path %s\n", path
);
895 r
= MsiInstallProductA( msifile
, "REMOVE=ALL" );
896 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
898 ok( !delete_pf( "msitest\\patch.txt", TRUE
), "file not removed\n" );
899 ok( !delete_pf( "msitest", FALSE
), "directory not removed\n" );
902 DeleteFileA( msifile
);
903 DeleteFileA( mspfile
);
904 DeleteFileA( "msitest\\patch.txt" );
905 RemoveDirectoryA( "msitest" );
908 static void test_MsiOpenDatabase( void )
913 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_CREATE
, &hdb
);
914 ok(r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
916 r
= MsiDatabaseCommit( hdb
);
917 ok(r
== ERROR_SUCCESS
, "failed to commit database %u\n", r
);
918 MsiCloseHandle( hdb
);
920 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &hdb
);
921 ok(r
== ERROR_OPEN_FAILED
, "expected ERROR_OPEN_FAILED, got %u\n", r
);
922 DeleteFileA( mspfile
);
924 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_CREATE
+ MSIDBOPEN_PATCHFILE
, &hdb
);
925 ok(r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
927 r
= MsiDatabaseCommit( hdb
);
928 ok(r
== ERROR_SUCCESS
, "failed to commit database %u\n", r
);
929 MsiCloseHandle( hdb
);
931 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &hdb
);
932 ok(r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
933 MsiCloseHandle( hdb
);
934 DeleteFileA( mspfile
);
936 create_database( msifile
, tables
, sizeof(tables
) / sizeof(struct msi_table
) );
937 create_patch( mspfile
);
939 r
= MsiOpenDatabaseW( msifileW
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &hdb
);
940 ok(r
== ERROR_OPEN_FAILED
, "failed to open database %u\n", r
);
942 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &hdb
);
943 ok(r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
944 MsiCloseHandle( hdb
);
946 DeleteFileA( msifile
);
947 DeleteFileA( mspfile
);
950 static UINT
find_entry( MSIHANDLE hdb
, const char *table
, const char *entry
)
952 static const char fmt
[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
955 MSIHANDLE hview
, hrec
;
957 sprintf( query
, fmt
, table
, entry
);
958 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
959 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
961 r
= MsiViewExecute( hview
, 0 );
962 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
964 r
= MsiViewFetch( hview
, &hrec
);
965 MsiViewClose( hview
);
966 MsiCloseHandle( hview
);
967 MsiCloseHandle( hrec
);
971 static UINT
find_entryW( MSIHANDLE hdb
, const WCHAR
*table
, const WCHAR
*entry
)
973 static const WCHAR fmt
[] =
974 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',' ',
975 'W','H','E','R','E',' ','`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
977 MSIHANDLE hview
, hrec
;
980 wsprintfW( query
, fmt
, table
, entry
);
981 r
= MsiDatabaseOpenViewW( hdb
, query
, &hview
);
982 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
984 r
= MsiViewExecute( hview
, 0 );
985 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
987 r
= MsiViewFetch( hview
, &hrec
);
988 MsiViewClose( hview
);
989 MsiCloseHandle( hview
);
990 MsiCloseHandle( hrec
);
994 static INT
get_integer( MSIHANDLE hdb
, UINT field
, const char *query
)
998 MSIHANDLE hview
, hrec
;
1000 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
1001 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1003 r
= MsiViewExecute( hview
, 0 );
1004 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1006 r
= MsiViewFetch( hview
, &hrec
);
1007 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1008 if (r
== ERROR_SUCCESS
)
1011 ret
= MsiRecordGetInteger( hrec
, field
);
1012 MsiCloseHandle( hrec
);
1014 r_tmp
= MsiViewFetch( hview
, &hrec
);
1015 ok( r_tmp
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1018 MsiViewClose( hview
);
1019 MsiCloseHandle( hview
);
1023 static char *get_string( MSIHANDLE hdb
, UINT field
, const char *query
)
1026 static char ret
[MAX_PATH
];
1027 MSIHANDLE hview
, hrec
;
1031 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
1032 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1034 r
= MsiViewExecute( hview
, 0 );
1035 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1037 r
= MsiViewFetch( hview
, &hrec
);
1038 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1039 if (r
== ERROR_SUCCESS
)
1041 UINT size
= MAX_PATH
;
1042 r
= MsiRecordGetStringA( hrec
, field
, ret
, &size
);
1043 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1044 MsiCloseHandle( hrec
);
1046 r
= MsiViewFetch( hview
, &hrec
);
1047 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1050 MsiViewClose( hview
);
1051 MsiCloseHandle( hview
);
1055 static void test_system_tables( void )
1057 static const char patchsource
[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7";
1058 static const WCHAR streamsW
[] = {'_','S','t','r','e','a','m','s',0};
1059 static const WCHAR CAB_msitest_encodedW
[] = {0x3a8c,0x47cb,0x45b0,0x45ec,0x45a8,0x4837,0};
1063 MSIHANDLE hproduct
, hdb
, hview
, hrec
;
1065 if (!pMsiApplyPatchA
)
1067 win_skip("MsiApplyPatchA is not available\n");
1070 if (is_process_limited())
1072 skip("process is limited\n");
1076 CreateDirectoryA( "msitest", NULL
);
1077 create_file( "msitest\\patch.txt", 1000 );
1079 create_database( msifile
, tables
, sizeof(tables
) / sizeof(struct msi_table
) );
1080 create_patch( mspfile
);
1082 MsiSetInternalUI( INSTALLUILEVEL_NONE
, NULL
);
1084 r
= MsiInstallProductA( msifile
, NULL
);
1085 if (r
!= ERROR_SUCCESS
)
1087 skip("Product installation failed with error code %d\n", r
);
1091 r
= MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct
);
1092 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1094 hdb
= MsiGetActiveDatabase( hproduct
);
1095 ok( hdb
, "failed to get database handle\n" );
1097 r
= find_entry( hdb
, "_Streams", "\5SummaryInformation" );
1098 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1100 query
= "SELECT * FROM `_Storages`";
1101 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
1102 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1104 r
= MsiViewExecute( hview
, 0 );
1105 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1107 r
= MsiViewFetch( hview
, &hrec
);
1108 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1110 r
= find_entry( hdb
, "_Tables", "Directory" );
1111 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1113 r
= find_entry( hdb
, "_Tables", "File" );
1114 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1116 r
= find_entry( hdb
, "_Tables", "Component" );
1117 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1119 r
= find_entry( hdb
, "_Tables", "Feature" );
1120 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1122 r
= find_entry( hdb
, "_Tables", "FeatureComponents" );
1123 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1125 r
= find_entry( hdb
, "_Tables", "Property" );
1126 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1128 r
= find_entry( hdb
, "_Tables", "InstallExecuteSequence" );
1129 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1131 r
= find_entry( hdb
, "_Tables", "Media" );
1132 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1134 r
= get_integer( hdb
, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1135 ok( r
== 1, "Got %u\n", r
);
1137 r
= find_entry( hdb
, "_Tables", "_Property" );
1138 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1140 MsiCloseHandle( hrec
);
1141 MsiViewClose( hview
);
1142 MsiCloseHandle( hview
);
1143 MsiCloseHandle( hdb
);
1144 MsiCloseHandle( hproduct
);
1146 r
= MsiApplyPatchA( mspfile
, NULL
, INSTALLTYPE_DEFAULT
, NULL
);
1147 ok( r
== ERROR_SUCCESS
|| broken( r
== ERROR_PATCH_PACKAGE_INVALID
), /* version 2.0 */
1148 "expected ERROR_SUCCESS, got %u\n", r
);
1150 if (r
== ERROR_PATCH_PACKAGE_INVALID
)
1152 win_skip("Windows Installer < 3.0 detected\n");
1156 r
= MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct
);
1157 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1159 hdb
= MsiGetActiveDatabase( hproduct
);
1160 ok( hdb
, "failed to get database handle\n" );
1162 r
= find_entry( hdb
, "_Streams", "\5SummaryInformation" );
1163 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1165 r
= find_entryW( hdb
, streamsW
, CAB_msitest_encodedW
);
1166 ok( r
== ERROR_NO_MORE_ITEMS
, "failed to find entry %u\n", r
);
1168 query
= "SELECT * FROM `_Storages`";
1169 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
1170 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1172 r
= MsiViewExecute( hview
, 0 );
1173 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1175 r
= MsiViewFetch( hview
, &hrec
);
1176 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1178 r
= find_entry( hdb
, "_Tables", "Directory" );
1179 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1181 r
= find_entry( hdb
, "_Tables", "File" );
1182 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1184 r
= find_entry( hdb
, "_Tables", "Component" );
1185 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1187 r
= find_entry( hdb
, "_Tables", "Feature" );
1188 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1190 r
= find_entry( hdb
, "_Tables", "FeatureComponents" );
1191 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1193 r
= find_entry( hdb
, "_Tables", "Property" );
1194 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1196 r
= find_entry( hdb
, "_Tables", "InstallExecuteSequence" );
1197 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1199 r
= find_entry( hdb
, "_Tables", "Media" );
1200 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1202 r
= find_entry( hdb
, "_Tables", "_Property" );
1203 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1205 r
= find_entry( hdb
, "_Tables", "MsiPatchHeaders" );
1206 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1208 r
= find_entry( hdb
, "_Tables", "Patch" );
1209 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1211 r
= find_entry( hdb
, "_Tables", "PatchPackage" );
1212 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1214 cr
= get_string( hdb
, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1215 todo_wine
ok( !strcmp(cr
, patchsource
), "Expected \"%s\", got \"%s\"\n", patchsource
, cr
);
1217 r
= get_integer( hdb
, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1218 todo_wine
ok( r
== 100, "Got %u\n", r
);
1220 r
= get_integer( hdb
, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1221 todo_wine
ok( r
== 10000, "Got %u\n", r
);
1223 r
= get_integer( hdb
, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1224 ok( r
== 1, "Got %u\n", r
);
1226 cr
= get_string( hdb
, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1227 ok( !strcmp(cr
, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr
);
1229 r
= get_integer( hdb
, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
1230 ok( r
== 10000, "Got %u\n", r
);
1232 MsiCloseHandle( hrec
);
1233 MsiViewClose( hview
);
1234 MsiCloseHandle( hview
);
1235 MsiCloseHandle( hdb
);
1236 MsiCloseHandle( hproduct
);
1239 r
= MsiInstallProductA( msifile
, "REMOVE=ALL" );
1240 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1243 DeleteFileA( msifile
);
1244 DeleteFileA( mspfile
);
1245 DeleteFileA( "msitest\\patch.txt" );
1246 RemoveDirectoryA( "msitest" );
1249 static void test_patch_registration( void )
1252 char buffer
[MAX_PATH
], patch_code
[39];
1254 if (!pMsiApplyPatchA
|| !pMsiGetPatchInfoExA
|| !pMsiEnumPatchesExA
)
1256 win_skip("required functions not available\n");
1259 if (is_process_limited())
1261 skip("process is limited\n");
1265 CreateDirectoryA( "msitest", NULL
);
1266 create_file( "msitest\\patch.txt", 1000 );
1268 create_database( msifile
, tables
, sizeof(tables
) / sizeof(struct msi_table
) );
1269 create_patch( mspfile
);
1271 MsiSetInternalUI( INSTALLUILEVEL_NONE
, NULL
);
1273 r
= MsiInstallProductA( msifile
, NULL
);
1274 if (r
!= ERROR_SUCCESS
)
1276 skip("Product installation failed with error code %d\n", r
);
1280 r
= MsiApplyPatchA( mspfile
, NULL
, INSTALLTYPE_DEFAULT
, NULL
);
1281 ok( r
== ERROR_SUCCESS
|| broken( r
== ERROR_PATCH_PACKAGE_INVALID
), /* version 2.0 */
1282 "expected ERROR_SUCCESS, got %u\n", r
);
1284 if (r
== ERROR_PATCH_PACKAGE_INVALID
)
1286 win_skip("Windows Installer < 3.0 detected\n");
1291 size
= sizeof(buffer
);
1292 r
= pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1293 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1294 NULL
, MSIINSTALLCONTEXT_USERUNMANAGED
,
1295 INSTALLPROPERTY_LOCALPACKAGEA
, buffer
, &size
);
1296 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1297 ok( buffer
[0], "buffer empty\n" );
1300 size
= sizeof(buffer
);
1301 r
= pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1302 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1303 NULL
, MSIINSTALLCONTEXT_MACHINE
,
1304 INSTALLPROPERTY_LOCALPACKAGEA
, buffer
, &size
);
1305 ok( r
== ERROR_UNKNOWN_PRODUCT
, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r
);
1308 size
= sizeof(buffer
);
1309 r
= pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1310 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1311 NULL
, MSIINSTALLCONTEXT_USERMANAGED
,
1312 INSTALLPROPERTY_LOCALPACKAGEA
, buffer
, &size
);
1313 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1314 ok( !buffer
[0], "got %s\n", buffer
);
1316 r
= pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1317 NULL
, MSIINSTALLCONTEXT_USERUNMANAGED
, MSIPATCHSTATE_APPLIED
,
1318 0, patch_code
, NULL
, NULL
, NULL
, NULL
);
1319 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1320 ok( !strcmp( patch_code
, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1322 r
= pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1323 NULL
, MSIINSTALLCONTEXT_MACHINE
, MSIPATCHSTATE_APPLIED
,
1324 0, patch_code
, NULL
, NULL
, NULL
, NULL
);
1325 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1327 r
= pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1328 NULL
, MSIINSTALLCONTEXT_USERMANAGED
, MSIPATCHSTATE_APPLIED
,
1329 0, patch_code
, NULL
, NULL
, NULL
, NULL
);
1330 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1333 r
= MsiInstallProductA( msifile
, "REMOVE=ALL" );
1334 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1337 size
= sizeof(buffer
);
1338 r
= pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1339 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1340 NULL
, MSIINSTALLCONTEXT_USERUNMANAGED
,
1341 INSTALLPROPERTY_LOCALPACKAGEA
, buffer
, &size
);
1342 ok( r
== ERROR_UNKNOWN_PRODUCT
, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r
);
1345 DeleteFileA( msifile
);
1346 DeleteFileA( mspfile
);
1347 DeleteFileA( "msitest\\patch.txt" );
1348 RemoveDirectoryA( "msitest" );
1354 char temp_path
[MAX_PATH
], prev_path
[MAX_PATH
];
1356 init_function_pointers();
1358 GetCurrentDirectoryA( MAX_PATH
, prev_path
);
1359 GetTempPathA( MAX_PATH
, temp_path
);
1360 SetCurrentDirectoryA( temp_path
);
1362 strcpy( CURR_DIR
, temp_path
);
1363 len
= strlen( CURR_DIR
);
1365 if (len
&& (CURR_DIR
[len
- 1] == '\\'))
1366 CURR_DIR
[len
- 1] = 0;
1368 get_program_files_dir( PROG_FILES_DIR
, COMMON_FILES_DIR
);
1370 test_simple_patch();
1371 test_MsiOpenDatabase();
1372 test_system_tables();
1373 test_patch_registration();
1375 SetCurrentDirectoryA( prev_path
);