1 /*
2  * DLL for testing type 1 custom actions
3  *
4  * Copyright 2017 Zebediah Figura
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 #if 0
22 #pragma makedep testdll
23 #endif
24 
25 #include <stdarg.h>
26 #include <stdio.h>
27 
28 #include <windef.h>
29 #include <winbase.h>
30 #include <winsvc.h>
31 #include <odbcinst.h>
32 #define COBJMACROS
33 #include <shlobj.h>
34 #include <msxml.h>
35 #include <msi.h>
36 #include <msiquery.h>
37 #include <msidefs.h>
38 
39 #ifdef __MINGW32__
40 #define __WINE_PRINTF_ATTR(fmt,args) __attribute__((format (printf,fmt,args)))
41 #else
42 #define __WINE_PRINTF_ATTR(fmt,args)
43 #endif
44 
45 static int todo_level, todo_do_loop;
46 
ok_(MSIHANDLE hinst,int todo,const char * file,int line,int condition,const char * msg,...)47 static void WINAPIV  __WINE_PRINTF_ATTR(6,7) ok_(MSIHANDLE hinst, int todo, const char *file, int line, int condition, const char *msg, ...)
48 {
49     static char buffer[2000];
50     MSIHANDLE record;
51     va_list valist;
52 
53     va_start(valist, msg);
54     vsprintf(buffer, msg, valist);
55     va_end(valist);
56 
57     record = MsiCreateRecord(5);
58     MsiRecordSetInteger(record, 1, todo);
59     MsiRecordSetStringA(record, 2, file);
60     MsiRecordSetInteger(record, 3, line);
61     MsiRecordSetInteger(record, 4, condition);
62     MsiRecordSetStringA(record, 5, buffer);
63     MsiProcessMessage(hinst, INSTALLMESSAGE_USER, record);
64     MsiCloseHandle(record);
65 }
66 
winetest_start_todo(int is_todo)67 static void winetest_start_todo( int is_todo )
68 {
69     todo_level = (todo_level << 1) | (is_todo != 0);
70     todo_do_loop=1;
71 }
72 
winetest_loop_todo(void)73 static int winetest_loop_todo(void)
74 {
75     int do_loop=todo_do_loop;
76     todo_do_loop=0;
77     return do_loop;
78 }
79 
winetest_end_todo(void)80 static void winetest_end_todo(void)
81 {
82     todo_level >>= 1;
83 }
84 
85 #define ok(hinst, condition, ...)   ok_(hinst, todo_level, __FILE__, __LINE__, condition, __VA_ARGS__)
86 #define todo_wine_if(is_todo) for (winetest_start_todo(is_todo); \
87                                    winetest_loop_todo(); \
88                                    winetest_end_todo())
89 #define todo_wine   todo_wine_if(1)
90 
dbgstr_w(WCHAR * str)91 static const char *dbgstr_w(WCHAR *str)
92 {
93     static char buffer[300], *p;
94 
95     if (!str) return "(null)";
96 
97     p = buffer;
98     *p++ = 'L';
99     *p++ = '"';
100     while ((*p++ = *str++));
101     *p++ = '"';
102     *p++ = 0;
103 
104     return buffer;
105 }
106 
check_prop(MSIHANDLE hinst,const char * prop,const char * expect)107 static void check_prop(MSIHANDLE hinst, const char *prop, const char *expect)
108 {
109     char buffer[10] = "x";
110     DWORD sz = sizeof(buffer);
111     UINT r = MsiGetPropertyA(hinst, prop, buffer, &sz);
112     ok(hinst, !r, "'%s': got %u\n", prop, r);
113     ok(hinst, sz == strlen(buffer), "'%s': expected %Iu, got %lu\n", prop, strlen(buffer), sz);
114     ok(hinst, !strcmp(buffer, expect), "expected '%s', got '%s'\n", expect, buffer);
115 }
116 
test_props(MSIHANDLE hinst)117 static void test_props(MSIHANDLE hinst)
118 {
119     char buffer[10];
120     WCHAR bufferW[10];
121     DWORD sz;
122     UINT r;
123 
124     /* test invalid values */
125     r = MsiGetPropertyA(hinst, NULL, NULL, NULL);
126     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
127 
128     r = MsiGetPropertyA(hinst, "boo", NULL, NULL);
129     ok(hinst, !r, "got %u\n", r);
130 
131     r = MsiGetPropertyA(hinst, "boo", buffer, NULL );
132     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
133 
134     sz = 0;
135     r = MsiGetPropertyA(hinst, "boo", NULL, &sz);
136     ok(hinst, !r, "got %u\n", r);
137     ok(hinst, sz == 0, "got size %lu\n", sz);
138 
139     sz = 0;
140     strcpy(buffer,"x");
141     r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
142     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
143     ok(hinst, !strcmp(buffer, "x"), "got \"%s\"\n", buffer);
144     ok(hinst, sz == 0, "got size %lu\n", sz);
145 
146     sz = 1;
147     strcpy(buffer,"x");
148     r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
149     ok(hinst, !r, "got %u\n", r);
150     ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
151     ok(hinst, sz == 0, "got size %lu\n", sz);
152 
153     /* set the property to something */
154     r = MsiSetPropertyA(hinst, NULL, NULL);
155     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
156 
157     r = MsiSetPropertyA(hinst, "", NULL);
158     ok(hinst, !r, "got %u\n", r);
159 
160     r = MsiSetPropertyA(hinst, "", "asdf");
161     ok(hinst, r == ERROR_FUNCTION_FAILED, "got %u\n", r);
162 
163     r = MsiSetPropertyA(hinst, "=", "asdf");
164     ok(hinst, !r, "got %u\n", r);
165     check_prop(hinst, "=", "asdf");
166 
167     r = MsiSetPropertyA(hinst, " ", "asdf");
168     ok(hinst, !r, "got %u\n", r);
169     check_prop(hinst, " ", "asdf");
170 
171     r = MsiSetPropertyA(hinst, "'", "asdf");
172     ok(hinst, !r, "got %u\n", r);
173     check_prop(hinst, "'", "asdf");
174 
175     r = MsiSetPropertyA(hinst, "boo", NULL);
176     ok(hinst, !r, "got %u\n", r);
177     check_prop(hinst, "boo", "");
178 
179     r = MsiSetPropertyA(hinst, "boo", "");
180     ok(hinst, !r, "got %u\n", r);
181     check_prop(hinst, "boo", "");
182 
183     r = MsiSetPropertyA(hinst, "boo", "xyz");
184     ok(hinst, !r, "got %u\n", r);
185     check_prop(hinst, "boo", "xyz");
186 
187     r = MsiGetPropertyA(hinst, "boo", NULL, NULL);
188     ok(hinst, !r, "got %u\n", r);
189 
190     r = MsiGetPropertyA(hinst, "boo", buffer, NULL );
191     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
192 
193     /* Returned size is in bytes, not chars, but only for custom actions.
194      * Seems to be a casualty of RPC... */
195 
196     sz = 0;
197     r = MsiGetPropertyA(hinst, "boo", NULL, &sz);
198     ok(hinst, !r, "got %u\n", r);
199     ok(hinst, sz == 6, "got size %lu\n", sz);
200 
201     sz = 0;
202     strcpy(buffer,"q");
203     r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
204     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
205     ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
206     ok(hinst, sz == 6, "got size %lu\n", sz);
207 
208     sz = 1;
209     strcpy(buffer,"x");
210     r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
211     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
212     ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
213     ok(hinst, sz == 6, "got size %lu\n", sz);
214 
215     sz = 3;
216     strcpy(buffer,"x");
217     r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
218     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
219     ok(hinst, !strcmp(buffer, "xy"), "got \"%s\"\n", buffer);
220     ok(hinst, sz == 6, "got size %lu\n", sz);
221 
222     sz = 4;
223     strcpy(buffer,"x");
224     r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
225     ok(hinst, !r, "got %u\n", r);
226     ok(hinst, !strcmp(buffer, "xyz"), "got \"%s\"\n", buffer);
227     ok(hinst, sz == 3, "got size %lu\n", sz);
228 
229     r = MsiGetPropertyW(hinst, L"boo", NULL, NULL);
230     ok(hinst, !r, "got %u\n", r);
231 
232     r = MsiGetPropertyW(hinst, L"boo", bufferW, NULL );
233     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
234 
235     sz = 0;
236     r = MsiGetPropertyW(hinst, L"boo", NULL, &sz);
237     ok(hinst, !r, "got %u\n", r);
238     ok(hinst, sz == 3, "got size %lu\n", sz);
239 
240     sz = 0;
241     lstrcpyW(bufferW, L"boo");
242     r = MsiGetPropertyW(hinst, L"boo", bufferW, &sz);
243     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
244     ok(hinst, !lstrcmpW(bufferW, L"boo"), "got %s\n", dbgstr_w(bufferW));
245     ok(hinst, sz == 3, "got size %lu\n", sz);
246 
247     sz = 1;
248     lstrcpyW(bufferW, L"boo");
249     r = MsiGetPropertyW(hinst, L"boo", bufferW, &sz);
250     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
251     ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
252     ok(hinst, sz == 3, "got size %lu\n", sz);
253 
254     sz = 3;
255     lstrcpyW(bufferW, L"boo");
256     r = MsiGetPropertyW(hinst, L"boo", bufferW, &sz);
257     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
258     ok(hinst, !lstrcmpW(bufferW, L"xy"), "got %s\n", dbgstr_w(bufferW));
259     ok(hinst, sz == 3, "got size %lu\n", sz);
260 
261     sz = 4;
262     lstrcpyW(bufferW, L"boo");
263     r = MsiGetPropertyW(hinst, L"boo", bufferW, &sz);
264     ok(hinst, !r, "got %u\n", r);
265     ok(hinst, !lstrcmpW(bufferW, L"xyz"), "got %s\n", dbgstr_w(bufferW));
266     ok(hinst, sz == 3, "got size %lu\n", sz);
267 
268     r = MsiSetPropertyA(hinst, "boo", NULL);
269     ok(hinst, !r, "got %u\n", r);
270     check_prop(hinst, "boo", "");
271 
272     sz = 0;
273     r = MsiGetPropertyA(hinst, "embednullprop", NULL, &sz);
274     ok(hinst, !r, "got %u\n", r);
275     ok(hinst, sz == 6, "got size %lu\n", sz);
276 
277     sz = 4;
278     memset(buffer, 0xcc, sizeof(buffer));
279     r = MsiGetPropertyA(hinst, "embednullprop", buffer, &sz);
280     ok(hinst, !r, "got %u\n", r);
281     ok(hinst, sz == 3, "got size %lu\n", sz);
282     ok(hinst, !memcmp(buffer, "a\0\0\0\xcc", 5), "wrong data\n");
283 }
284 
test_db(MSIHANDLE hinst)285 static void test_db(MSIHANDLE hinst)
286 {
287     static const UINT prop_type[20] = { VT_EMPTY, VT_EMPTY, VT_LPSTR, VT_EMPTY, VT_EMPTY,
288                                         VT_EMPTY, VT_EMPTY, VT_LPSTR, VT_EMPTY, VT_LPSTR,
289                                         VT_EMPTY, VT_EMPTY, VT_EMPTY, VT_EMPTY, VT_I4,
290                                         VT_I4, VT_EMPTY, VT_EMPTY, VT_EMPTY, VT_EMPTY };
291     MSIHANDLE hdb, hdb2, view, rec, rec2, suminfo;
292     char buffer[10];
293     DWORD sz;
294     UINT r, count, type, i;
295     INT int_value;
296     FILETIME ft;
297 
298     hdb = MsiGetActiveDatabase(hinst);
299     ok(hinst, hdb, "MsiGetActiveDatabase failed\n");
300 
301     r = MsiDatabaseIsTablePersistentA(hdb, "Test");
302     ok(hinst, r == MSICONDITION_TRUE, "got %u\n", r);
303 
304     r = MsiDatabaseOpenViewA(hdb, NULL, &view);
305     ok(hinst, r == ERROR_BAD_QUERY_SYNTAX, "got %u\n", r);
306 
307     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `Test`", NULL);
308     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
309 
310     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `Test`", &view);
311     ok(hinst, !r, "got %u\n", r);
312 
313     r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec2);
314     ok(hinst, !r, "got %u\n", r);
315 
316     sz = sizeof(buffer);
317     r = MsiRecordGetStringA(rec2, 1, buffer, &sz);
318     ok(hinst, !r, "got %u\n", r);
319     ok(hinst, sz == strlen(buffer), "got size %lu\n", sz);
320     ok(hinst, !strcmp(buffer, "Name"), "got '%s'\n", buffer);
321 
322     /* Test MsiGetActiveDatabase + MsiDatabaseIsTablePersistent once again */
323     hdb2 = MsiGetActiveDatabase(hinst);
324     ok(hinst, hdb2, "MsiGetActiveDatabase failed\n");
325     ok(hinst, hdb2 != hdb, "db handles should be different\n");
326 
327     r = MsiDatabaseIsTablePersistentA(hdb2, "Test");
328     ok(hinst, r == MSICONDITION_TRUE, "got %u\n", r);
329 
330     r = MsiCloseHandle(hdb2);
331     ok(hinst, !r, "got %u\n", r);
332 
333     r = MsiCloseHandle(rec2);
334     ok(hinst, !r, "got %u\n", r);
335 
336     r = MsiViewExecute(view, 0);
337     ok(hinst, !r, "got %u\n", r);
338 
339     r = MsiViewFetch(view, &rec2);
340     ok(hinst, !r, "got %u\n", r);
341 
342     r = MsiRecordGetFieldCount(rec2);
343     ok(hinst, r == 3, "got %u\n", r);
344 
345     sz = sizeof(buffer);
346     r = MsiRecordGetStringA(rec2, 1, buffer, &sz);
347     ok(hinst, !r, "got %u\n", r);
348     ok(hinst, sz == strlen(buffer), "got size %lu\n", sz);
349     ok(hinst, !strcmp(buffer, "one"), "got '%s'\n", buffer);
350 
351     r = MsiRecordGetInteger(rec2, 2);
352     ok(hinst, r == 1, "got %u\n", r);
353 
354     sz = sizeof(buffer);
355     r = MsiRecordReadStream(rec2, 3, buffer, &sz);
356     ok(hinst, !r, "got %u\n", r);
357     ok(hinst, !memcmp(buffer, "unus", 4), "wrong data\n");
358 
359     r = MsiCloseHandle(rec2);
360     ok(hinst, !r, "got %u\n", r);
361 
362     r = MsiViewFetch(view, &rec2);
363     ok(hinst, !r, "got %u\n", r);
364 
365     r = MsiRecordGetFieldCount(rec2);
366     ok(hinst, r == 3, "got %u\n", r);
367 
368     sz = sizeof(buffer);
369     r = MsiRecordGetStringA(rec2, 1, buffer, &sz);
370     ok(hinst, !r, "got %u\n", r);
371     ok(hinst, sz == strlen(buffer), "got size %lu\n", sz);
372     ok(hinst, !strcmp(buffer, "two"), "got '%s'\n", buffer);
373 
374     r = MsiRecordGetInteger(rec2, 2);
375     ok(hinst, r == 2, "got %u\n", r);
376 
377     sz = sizeof(buffer);
378     r = MsiRecordReadStream(rec2, 3, buffer, &sz);
379     ok(hinst, !r, "got %u\n", r);
380     ok(hinst, !memcmp(buffer, "duo", 3), "wrong data\n");
381 
382     r = MsiViewModify(view, MSIMODIFY_REFRESH, 0);
383     ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
384 
385     r = MsiRecordSetStringA(rec2, 1, "three");
386     ok(hinst, !r, "got %u\n", r);
387 
388     r = MsiRecordSetInteger(rec2, 2, 3);
389     ok(hinst, !r, "got %u\n", r);
390 
391     r = MsiRecordSetInteger(rec2, 3, 3);
392     ok(hinst, !r, "got %u\n", r);
393 
394     r = MsiViewModify(view, MSIMODIFY_REFRESH, rec2);
395     ok(hinst, !r, "got %u\n", r);
396 
397     sz = sizeof(buffer);
398     r = MsiRecordGetStringA(rec2, 1, buffer, &sz);
399     ok(hinst, !r, "got %u\n", r);
400     ok(hinst, sz == strlen(buffer), "got size %lu\n", sz);
401     ok(hinst, !strcmp(buffer, "two"), "got '%s'\n", buffer);
402 
403     r = MsiRecordGetInteger(rec2, 2);
404     ok(hinst, r == 2, "got %u\n", r);
405 
406     sz = sizeof(buffer);
407     r = MsiRecordReadStream(rec2, 3, buffer, &sz);
408     ok(hinst, !r, "got %u\n", r);
409     ok(hinst, !memcmp(buffer, "duo", 3), "wrong data\n");
410 
411     r = MsiCloseHandle(rec2);
412     ok(hinst, !r, "got %u\n", r);
413 
414     r = MsiViewFetch(view, &rec2);
415     ok(hinst, r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
416     ok(hinst, !rec2, "got %lu\n", rec2);
417 
418     r = MsiViewClose(view);
419     ok(hinst, !r, "got %u\n", r);
420 
421     r = MsiCloseHandle(view);
422     ok(hinst, !r, "got %u\n", r);
423 
424     r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `Test` WHERE `Name` = ?", &view);
425     ok(hinst, !r, "got %u\n", r);
426 
427     rec = MsiCreateRecord(1);
428     MsiRecordSetStringA(rec, 1, "one");
429 
430     r = MsiViewExecute(view, rec);
431     ok(hinst, !r, "got %u\n", r);
432 
433     r = MsiViewFetch(view, &rec2);
434     ok(hinst, !r, "got %u\n", r);
435 
436     r = MsiRecordGetInteger(rec2, 2);
437     ok(hinst, r == 1, "got %u\n", r);
438 
439     r = MsiCloseHandle(rec2);
440     ok(hinst, !r, "got %u\n", r);
441 
442     r = MsiViewFetch(view, &rec2);
443     ok(hinst, r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
444     ok(hinst, !rec2, "got %lu\n", rec2);
445 
446     r = MsiCloseHandle(rec);
447     ok(hinst, !r, "got %u\n", r);
448 
449     r = MsiCloseHandle(view);
450     ok(hinst, !r, "got %u\n", r);
451 
452     /* test MsiDatabaseGetPrimaryKeys() */
453     r = MsiDatabaseGetPrimaryKeysA(hdb, "Test", &rec);
454     ok(hinst, !r, "got %u\n", r);
455 
456     r = MsiRecordGetFieldCount(rec);
457     ok(hinst, r == 1, "got %u\n", r);
458 
459     sz = sizeof(buffer);
460     r = MsiRecordGetStringA(rec, 0, buffer, &sz);
461     ok(hinst, !r, "got %u\n", r);
462     ok(hinst, sz == strlen(buffer), "got size %lu\n", sz);
463     ok(hinst, !strcmp(buffer, "Test"), "got '%s'\n", buffer);
464 
465     sz = sizeof(buffer);
466     r = MsiRecordGetStringA(rec, 1, buffer, &sz);
467     ok(hinst, !r, "got %u\n", r);
468     ok(hinst, sz == strlen(buffer), "got size %lu\n", sz);
469     ok(hinst, !strcmp(buffer, "Name"), "got '%s'\n", buffer);
470 
471     r = MsiCloseHandle(rec);
472     ok(hinst, !r, "got %u\n", r);
473 
474     r = MsiGetSummaryInformationA(hdb, NULL, 1, NULL);
475     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
476 
477     r = MsiGetSummaryInformationA(hdb, NULL, 1, &suminfo);
478     ok(hinst, !r, "got %u\n", r);
479 
480     r = MsiSummaryInfoGetPropertyCount(suminfo, NULL);
481     ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
482 
483     count = 0xdeadbeef;
484     r = MsiSummaryInfoGetPropertyCount(suminfo, &count);
485     ok(hinst, !r, "got %u\n", r);
486     ok(hinst, count == 5, "got %u\n", count);
487 
488     r = MsiSummaryInfoGetPropertyA(suminfo, 0, NULL, NULL, NULL, NULL, NULL);
489     ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
490 
491     for (i = 0; i < 20; i++)
492     {
493         /* for some reason query for PID_TITLE leads to install failure under Windows */
494         if (i == PID_TITLE) continue;
495 
496         type = 0xdeadbeef;
497         int_value = 0xdeadbeef;
498         *buffer = 0;
499         sz = sizeof(buffer);
500         r = MsiSummaryInfoGetPropertyA(suminfo, i, &type, &int_value, &ft, buffer, &sz);
501         if (sz == sizeof(buffer) || i == PID_TEMPLATE)
502             ok(hinst, !r, "%u: got %u\n", i, r);
503         else
504             ok(hinst, r == ERROR_MORE_DATA, "%u: got %u\n", i, r);
505         ok(hinst, type == prop_type[i], "%u: expected %u, got %u\n", i, prop_type[i], type);
506         if (i == PID_PAGECOUNT)
507             ok(hinst, int_value == 100, "%u: got %u\n", i, int_value);
508         else
509             ok(hinst, int_value == 0, "%u: got %u\n", i, int_value);
510         if (i == PID_TEMPLATE)
511         {
512             ok(hinst, sz == 5, "%u: got %lu\n", i, sz);
513             ok(hinst, !lstrcmpA(buffer, ";1033"), "%u: got %s\n", i, buffer);
514         }
515         else if (i == PID_REVNUMBER)
516         {
517             ok(hinst, sz == 76, "%u: got %lu\n", i, sz);
518             ok(hinst, !lstrcmpA(buffer, "{004757CA"), "%u: got %s\n", i, buffer);
519         }
520         else
521         {
522             ok(hinst, sz == sizeof(buffer), "%u: got %lu\n", i, sz);
523             ok(hinst, !*buffer, "%u: got %s\n", i, buffer);
524         }
525     }
526 
527     GetSystemTimeAsFileTime(&ft);
528 
529     for (i = 0; i < 20; i++)
530     {
531         r = MsiSummaryInfoSetPropertyA(suminfo, i, prop_type[i], 1252, &ft, "");
532         ok(hinst, r == ERROR_FUNCTION_FAILED, "%u: got %u\n", i, r);
533 
534         r = MsiSummaryInfoSetPropertyW(suminfo, i, prop_type[i], 1252, &ft, L"");
535         ok(hinst, r == ERROR_FUNCTION_FAILED, "%u: got %u\n", i, r);
536     }
537 
538     r = MsiCloseHandle(suminfo);
539     ok(hinst, !r, "got %u\n", r);
540 
541     r = MsiCloseHandle(hdb);
542     ok(hinst, !r, "got %u\n", r);
543 }
544 
test_doaction(MSIHANDLE hinst)545 static void test_doaction(MSIHANDLE hinst)
546 {
547     UINT r;
548 
549     r = MsiDoActionA(hinst, "nested51");
550     ok(hinst, !r, "got %u\n", r);
551     check_prop(hinst, "nested", "1");
552 
553     r = MsiDoActionA(hinst, "nested1");
554     ok(hinst, !r, "got %u\n", r);
555     check_prop(hinst, "nested", "2");
556 
557     r = MsiSequenceA(hinst, NULL, 0);
558     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
559 
560     r = MsiSequenceA(hinst, "TestSequence", 0);
561     ok(hinst, !r, "got %u\n", r);
562     check_prop(hinst, "nested", "1");
563 }
564 
nested(MSIHANDLE hinst)565 UINT WINAPI nested(MSIHANDLE hinst)
566 {
567     MsiSetPropertyA(hinst, "nested", "2");
568 
569     return ERROR_SUCCESS;
570 }
571 
test_targetpath(MSIHANDLE hinst)572 static void test_targetpath(MSIHANDLE hinst)
573 {
574     WCHAR bufferW[100];
575     char buffer[100];
576     DWORD sz, srcsz;
577     UINT r;
578 
579     /* test invalid values */
580     r = MsiGetTargetPathA(hinst, NULL, NULL, NULL);
581     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
582 
583     r = MsiGetTargetPathA(hinst, "TARGETDIR", NULL, NULL );
584     ok(hinst, !r, "got %u\n", r);
585 
586     r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, NULL );
587     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
588 
589     /* Returned size is in bytes, not chars, but only for custom actions.
590      * Seems to be a casualty of RPC... */
591 
592     sz = 0;
593     r = MsiGetTargetPathA(hinst, "TARGETDIR", NULL, &sz);
594     ok(hinst, !r, "got %u\n", r);
595     ok(hinst, sz == 6, "got size %lu\n", sz);
596 
597     sz = 0;
598     strcpy(buffer,"q");
599     r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, &sz);
600     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
601     ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
602     ok(hinst, sz == 6, "got size %lu\n", sz);
603 
604     sz = 1;
605     strcpy(buffer,"x");
606     r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, &sz);
607     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
608     ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
609     ok(hinst, sz == 6, "got size %lu\n", sz);
610 
611     sz = 3;
612     strcpy(buffer,"x");
613     r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, &sz);
614     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
615     ok(hinst, !strcmp(buffer, "C:"), "got \"%s\"\n", buffer);
616     ok(hinst, sz == 6, "got size %lu\n", sz);
617 
618     sz = 4;
619     strcpy(buffer,"x");
620     r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, &sz);
621     ok(hinst, !r, "got %u\n", r);
622     ok(hinst, !strcmp(buffer, "C:\\"), "got \"%s\"\n", buffer);
623     ok(hinst, sz == 3, "got size %lu\n", sz);
624 
625     sz = 0;
626     r = MsiGetTargetPathW(hinst, L"TARGETDIR", NULL, &sz);
627     ok(hinst, !r, "got %u\n", r);
628     ok(hinst, sz == 3, "got size %lu\n", sz);
629 
630     sz = 0;
631     bufferW[0] = 'q';
632     r = MsiGetTargetPathW(hinst, L"TARGETDIR", bufferW, &sz);
633     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
634     ok(hinst, bufferW[0] == 'q', "got %s\n", dbgstr_w(bufferW));
635     ok(hinst, sz == 3, "got size %lu\n", sz);
636 
637     sz = 1;
638     bufferW[0] = 'q';
639     r = MsiGetTargetPathW(hinst, L"TARGETDIR", bufferW, &sz);
640     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
641     ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
642     ok(hinst, sz == 3, "got size %lu\n", sz);
643 
644     sz = 3;
645     bufferW[0] = 'q';
646     r = MsiGetTargetPathW(hinst, L"TARGETDIR", bufferW, &sz);
647     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
648     ok(hinst, !lstrcmpW(bufferW, L"C:"), "got %s\n", dbgstr_w(bufferW));
649     ok(hinst, sz == 3, "got size %lu\n", sz);
650 
651     sz = 4;
652     bufferW[0] = 'q';
653     r = MsiGetTargetPathW(hinst, L"TARGETDIR", bufferW, &sz);
654     ok(hinst, !r, "got %u\n", r);
655     ok(hinst, !lstrcmpW(bufferW, L"C:\\"), "got %s\n", dbgstr_w(bufferW));
656     ok(hinst, sz == 3, "got size %lu\n", sz);
657 
658     r = MsiSetTargetPathA(hinst, NULL, "C:\\subdir");
659     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
660 
661     r = MsiSetTargetPathA(hinst, "MSITESTDIR", NULL);
662     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
663 
664     r = MsiSetTargetPathA(hinst, "MSITESTDIR", "C:\\subdir");
665     ok(hinst, !r, "got %u\n", r);
666 
667     sz = sizeof(buffer);
668     r = MsiGetTargetPathA(hinst, "MSITESTDIR", buffer, &sz);
669     ok(hinst, !r, "got %u\n", r);
670     ok(hinst, !strcmp(buffer, "C:\\subdir\\"), "got \"%s\"\n", buffer);
671 
672     r = MsiSetTargetPathA(hinst, "MSITESTDIR", "C:\\");
673 
674     /* test GetSourcePath() */
675 
676     r = MsiGetSourcePathA(hinst, NULL, NULL, NULL);
677     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
678 
679     r = MsiGetSourcePathA(hinst, "TARGETDIR", NULL, NULL );
680     ok(hinst, !r, "got %u\n", r);
681 
682     r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, NULL );
683     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
684 
685     /* Returned size is in bytes, not chars, but only for custom actions.
686      * Seems to be a casualty of RPC... */
687 
688     srcsz = 0;
689     MsiGetSourcePathW(hinst, L"TARGETDIR", NULL, &srcsz);
690 
691     sz = 0;
692     r = MsiGetSourcePathA(hinst, "TARGETDIR", NULL, &sz);
693     ok(hinst, !r, "got %u\n", r);
694     ok(hinst, sz == srcsz * 2, "got size %lu\n", sz);
695 
696     sz = 0;
697     strcpy(buffer,"q");
698     r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, &sz);
699     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
700     ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
701     ok(hinst, sz == srcsz * 2, "got size %lu\n", sz);
702 
703     sz = 1;
704     strcpy(buffer,"x");
705     r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, &sz);
706     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
707     ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
708     ok(hinst, sz == srcsz * 2, "got size %lu\n", sz);
709 
710     sz = srcsz;
711     strcpy(buffer,"x");
712     r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, &sz);
713     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
714     ok(hinst, strlen(buffer) == srcsz - 1, "wrong buffer length %Iu\n", strlen(buffer));
715     ok(hinst, sz == srcsz * 2, "got size %lu\n", sz);
716 
717     sz = srcsz + 1;
718     strcpy(buffer,"x");
719     r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, &sz);
720     ok(hinst, !r, "got %u\n", r);
721     ok(hinst, strlen(buffer) == srcsz, "wrong buffer length %Iu\n", strlen(buffer));
722     ok(hinst, sz == srcsz, "got size %lu\n", sz);
723 
724     sz = 0;
725     r = MsiGetSourcePathW(hinst, L"TARGETDIR", NULL, &sz);
726     ok(hinst, !r, "got %u\n", r);
727     ok(hinst, sz == srcsz, "got size %lu\n", sz);
728 
729     sz = 0;
730     bufferW[0] = 'q';
731     r = MsiGetSourcePathW(hinst, L"TARGETDIR", bufferW, &sz);
732     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
733     ok(hinst, bufferW[0] == 'q', "got %s\n", dbgstr_w(bufferW));
734     ok(hinst, sz == srcsz, "got size %lu\n", sz);
735 
736     sz = 1;
737     bufferW[0] = 'q';
738     r = MsiGetSourcePathW(hinst, L"TARGETDIR", bufferW, &sz);
739     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
740     ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
741     ok(hinst, sz == srcsz, "got size %lu\n", sz);
742 
743     sz = srcsz;
744     bufferW[0] = 'q';
745     r = MsiGetSourcePathW(hinst, L"TARGETDIR", bufferW, &sz);
746     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
747     ok(hinst, lstrlenW(bufferW) == srcsz - 1, "wrong buffer length %d\n", lstrlenW(bufferW));
748     ok(hinst, sz == srcsz, "got size %lu\n", sz);
749 
750     sz = srcsz + 1;
751     bufferW[0] = 'q';
752     r = MsiGetSourcePathW(hinst, L"TARGETDIR", bufferW, &sz);
753     ok(hinst, !r, "got %u\n", r);
754     ok(hinst, lstrlenW(bufferW) == srcsz, "wrong buffer length %d\n", lstrlenW(bufferW));
755     ok(hinst, sz == srcsz, "got size %lu\n", sz);
756 }
757 
test_misc(MSIHANDLE hinst)758 static void test_misc(MSIHANDLE hinst)
759 {
760     MSICONDITION cond;
761     LANGID lang;
762     UINT r;
763 
764     r = MsiSetMode(hinst, MSIRUNMODE_REBOOTATEND, FALSE);
765     ok(hinst, !r, "got %u\n", r);
766 
767     lang = MsiGetLanguage(hinst);
768     ok(hinst, lang == 1033, "got %u\n", lang);
769 
770     check_prop(hinst, "INSTALLLEVEL", "3");
771     r = MsiSetInstallLevel(hinst, 123);
772     ok(hinst, !r, "got %u\n", r);
773     check_prop(hinst, "INSTALLLEVEL", "123");
774     MsiSetInstallLevel(hinst, 3);
775 
776     cond = MsiEvaluateConditionA(hinst, NULL);
777     ok(hinst, cond == MSICONDITION_NONE, "got %u\n", cond);
778     MsiSetPropertyA(hinst, "condprop", "1");
779     cond = MsiEvaluateConditionA(hinst, "condprop = 1");
780     ok(hinst, cond == MSICONDITION_TRUE, "got %u\n", cond);
781 }
782 
test_feature_states(MSIHANDLE hinst)783 static void test_feature_states(MSIHANDLE hinst)
784 {
785     INSTALLSTATE state, action;
786     UINT r;
787 
788     /* test feature states */
789 
790     r = MsiGetFeatureStateA(hinst, NULL, &state, &action);
791     ok(hinst, r == ERROR_UNKNOWN_FEATURE, "got %u\n", r);
792 
793     r = MsiGetFeatureStateA(hinst, "fake", &state, &action);
794     ok(hinst, r == ERROR_UNKNOWN_FEATURE, "got %u\n", r);
795 
796     r = MsiGetFeatureStateA(hinst, "One", NULL, &action);
797     ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
798 
799     r = MsiGetFeatureStateA(hinst, "One", &state, NULL);
800     ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
801 
802     r = MsiGetFeatureStateA(hinst, "One", &state, &action);
803     ok(hinst, !r, "got %u\n", r);
804     ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
805     ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
806 
807     r = MsiSetFeatureStateA(hinst, NULL, INSTALLSTATE_ABSENT);
808     ok(hinst, r == ERROR_UNKNOWN_FEATURE, "got %u\n", r);
809 
810     r = MsiSetFeatureStateA(hinst, "One", INSTALLSTATE_ADVERTISED);
811     ok(hinst, !r, "got %u\n", r);
812 
813     r = MsiGetFeatureStateA(hinst, "One", &state, &action);
814     ok(hinst, !r, "got %u\n", r);
815     ok(hinst, action == INSTALLSTATE_ADVERTISED, "got action %d\n", action);
816 
817     r = MsiSetFeatureStateA(hinst, "One", INSTALLSTATE_LOCAL);
818     ok(hinst, !r, "got %u\n", r);
819 
820     r = MsiGetFeatureStateA(hinst, "One", &state, &action);
821     ok(hinst, !r, "got %u\n", r);
822     ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
823 
824     /* test component states */
825 
826     r = MsiGetComponentStateA(hinst, NULL, &state, &action);
827     ok(hinst, r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r);
828 
829     r = MsiGetComponentStateA(hinst, "fake", &state, &action);
830     ok(hinst, r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r);
831 
832     r = MsiGetComponentStateA(hinst, "One", NULL, &action);
833     ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
834 
835     r = MsiGetComponentStateA(hinst, "One", &state, NULL);
836     ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
837 
838     r = MsiGetComponentStateA(hinst, "One", &state, &action);
839     ok(hinst, !r, "got %u\n", r);
840     ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
841     ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
842 
843     r = MsiGetComponentStateA(hinst, "dangler", &state, &action);
844     ok(hinst, !r, "got %u\n", r);
845     ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
846     ok(hinst, action == INSTALLSTATE_UNKNOWN, "got action %d\n", action);
847 
848     r = MsiGetComponentStateA(hinst, "component", &state, &action);
849     ok(hinst, !r, "got %u\n", r);
850     ok(hinst, state == INSTALLSTATE_UNKNOWN, "got state %d\n", state);
851     ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
852 
853     r = MsiSetComponentStateA(hinst, NULL, INSTALLSTATE_ABSENT);
854     ok(hinst, r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r);
855 
856     r = MsiSetComponentStateA(hinst, "One", INSTALLSTATE_SOURCE);
857     ok(hinst, !r, "got %u\n", r);
858 
859     r = MsiGetComponentStateA(hinst, "One", &state, &action);
860     ok(hinst, !r, "got %u\n", r);
861     ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
862     ok(hinst, action == INSTALLSTATE_SOURCE, "got action %d\n", action);
863 
864     r = MsiSetComponentStateA(hinst, "One", INSTALLSTATE_LOCAL);
865     ok(hinst, !r, "got %u\n", r);
866 
867     r = MsiGetComponentStateA(hinst, "One", &state, &action);
868     ok(hinst, !r, "got %u\n", r);
869     ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
870     ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
871 }
872 
test_format_record(MSIHANDLE hinst)873 static void test_format_record(MSIHANDLE hinst)
874 {
875     WCHAR bufferW[10];
876     char buffer[10];
877     MSIHANDLE rec;
878     DWORD sz;
879     UINT r;
880 
881     r = MsiFormatRecordA(hinst, 0, NULL, NULL);
882     ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
883 
884     rec = MsiCreateRecord(1);
885     MsiRecordSetStringA(rec, 0, "foo [1]");
886     MsiRecordSetInteger(rec, 1, 123);
887 
888     r = MsiFormatRecordA(hinst, rec, NULL, NULL);
889     ok(hinst, !r, "got %u\n", r);
890 
891     r = MsiFormatRecordA(hinst, rec, buffer, NULL);
892     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
893 
894     /* Returned size is in bytes, not chars, but only for custom actions. */
895 
896     sz = 0;
897     r = MsiFormatRecordA(hinst, rec, NULL, &sz);
898     ok(hinst, !r, "got %u\n", r);
899     ok(hinst, sz == 14, "got size %lu\n", sz);
900 
901     sz = 0;
902     strcpy(buffer,"q");
903     r = MsiFormatRecordA(hinst, rec, buffer, &sz);
904     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
905     ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
906     ok(hinst, sz == 14, "got size %lu\n", sz);
907 
908     sz = 1;
909     strcpy(buffer,"x");
910     r = MsiFormatRecordA(hinst, rec, buffer, &sz);
911     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
912     ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
913     ok(hinst, sz == 14, "got size %lu\n", sz);
914 
915     sz = 7;
916     strcpy(buffer,"x");
917     r = MsiFormatRecordA(hinst, rec, buffer, &sz);
918     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
919     ok(hinst, !strcmp(buffer, "foo 12"), "got \"%s\"\n", buffer);
920     ok(hinst, sz == 14, "got size %lu\n", sz);
921 
922     sz = 8;
923     strcpy(buffer,"x");
924     r = MsiFormatRecordA(hinst, rec, buffer, &sz);
925     ok(hinst, !r, "got %u\n", r);
926     ok(hinst, !strcmp(buffer, "foo 123"), "got \"%s\"\n", buffer);
927     ok(hinst, sz == 7, "got size %lu\n", sz);
928 
929     r = MsiFormatRecordW(hinst, rec, NULL, NULL);
930     ok(hinst, !r, "got %u\n", r);
931 
932     r = MsiFormatRecordW(hinst, rec, bufferW, NULL);
933     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
934 
935     sz = 0;
936     r = MsiFormatRecordW(hinst, rec, NULL, &sz);
937     ok(hinst, !r, "got %u\n", r);
938     ok(hinst, sz == 7, "got size %lu\n", sz);
939 
940     sz = 0;
941     bufferW[0] = 'q';
942     r = MsiFormatRecordW(hinst, rec, bufferW, &sz);
943     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
944     ok(hinst, bufferW[0] == 'q', "got %s\n", dbgstr_w(bufferW));
945     ok(hinst, sz == 7, "got size %lu\n", sz);
946 
947     sz = 1;
948     bufferW[0] = 'q';
949     r = MsiFormatRecordW(hinst, rec, bufferW, &sz);
950     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
951     ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
952     ok(hinst, sz == 7, "got size %lu\n", sz);
953 
954     sz = 7;
955     bufferW[0] = 'q';
956     r = MsiFormatRecordW(hinst, rec, bufferW, &sz);
957     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
958     ok(hinst, !lstrcmpW(bufferW, L"foo 12"), "got %s\n", dbgstr_w(bufferW));
959     ok(hinst, sz == 7, "got size %lu\n", sz);
960 
961     sz = 8;
962     bufferW[0] = 'q';
963     r = MsiFormatRecordW(hinst, rec, bufferW, &sz);
964     ok(hinst, !r, "got %u\n", r);
965     ok(hinst, !lstrcmpW(bufferW, L"foo 123"), "got %s\n", dbgstr_w(bufferW));
966     ok(hinst, sz == 7, "got size %lu\n", sz);
967 
968     /* check that properties work */
969     MsiSetPropertyA(hinst, "fmtprop", "foobar");
970     MsiRecordSetStringA(rec, 0, "[fmtprop]");
971     sz = sizeof(buffer);
972     r = MsiFormatRecordA(hinst, rec, buffer, &sz);
973     ok(hinst, !r, "got %u\n", r);
974     ok(hinst, !strcmp(buffer, "foobar"), "got \"%s\"\n", buffer);
975     ok(hinst, sz == 6, "got size %lu\n", sz);
976 
977     MsiCloseHandle(rec);
978 }
979 
test_costs(MSIHANDLE hinst)980 static void test_costs(MSIHANDLE hinst)
981 {
982     WCHAR bufferW[10];
983     char buffer[10];
984     int cost, temp;
985     DWORD sz;
986     UINT r;
987 
988     cost = 0xdead;
989     r = MsiGetFeatureCostA(hinst, NULL, MSICOSTTREE_CHILDREN, INSTALLSTATE_LOCAL, &cost);
990     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
991     todo_wine
992     ok(hinst, !cost, "got %d\n", cost);
993 
994     r = MsiGetFeatureCostA(hinst, "One", MSICOSTTREE_CHILDREN, INSTALLSTATE_LOCAL, NULL);
995     ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
996 
997     cost = 0xdead;
998     r = MsiGetFeatureCostA(hinst, "One", MSICOSTTREE_CHILDREN, INSTALLSTATE_LOCAL, &cost);
999     ok(hinst, !r, "got %u\n", r);
1000     todo_wine
1001     ok(hinst, cost == 8, "got %d\n", cost);
1002 
1003     sz = cost = temp = 0xdead;
1004     r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, NULL, &sz, &cost, &temp);
1005     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
1006     ok(hinst, sz == 0xdead, "got size %lu\n", sz);
1007     ok(hinst, cost == 0xdead, "got cost %d\n", cost);
1008     ok(hinst, temp == 0xdead, "got temp %d\n", temp);
1009 
1010     cost = temp = 0xdead;
1011     r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, NULL, &cost, &temp);
1012     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
1013     ok(hinst, cost == 0xdead, "got cost %d\n", cost);
1014     ok(hinst, temp == 0xdead, "got temp %d\n", temp);
1015 
1016     sz = temp = 0xdead;
1017     r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, NULL, &temp);
1018     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
1019     ok(hinst, sz == 0xdead, "got size %lu\n", sz);
1020     ok(hinst, temp == 0xdead, "got temp %d\n", temp);
1021 
1022     sz = cost = 0xdead;
1023     r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, NULL);
1024     ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
1025     ok(hinst, sz == 0xdead, "got size %lu\n", sz);
1026     ok(hinst, cost == 0xdead, "got cost %d\n", cost);
1027 
1028     cost = temp = 0xdead;
1029     sz = sizeof(buffer);
1030     r = MsiEnumComponentCostsA(hinst, NULL, 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
1031     ok(hinst, !r, "got %u\n", r);
1032     ok(hinst, sz == 2, "got size %lu\n", sz);
1033     ok(hinst, !strcmp(buffer, "C:"), "got '%s'\n", buffer);
1034     ok(hinst, !cost, "got cost %d\n", cost);
1035     ok(hinst, temp && temp != 0xdead, "got temp %d\n", temp);
1036 
1037     cost = temp = 0xdead;
1038     sz = sizeof(buffer);
1039     r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
1040     ok(hinst, !r, "got %u\n", r);
1041     ok(hinst, sz == 2, "got size %lu\n", sz);
1042     ok(hinst, !strcmp(buffer, "C:"), "got '%s'\n", buffer);
1043     ok(hinst, cost == 8, "got cost %d\n", cost);
1044     ok(hinst, !temp, "got temp %d\n", temp);
1045 
1046     /* same string behaviour */
1047     cost = temp = 0xdead;
1048     sz = 0;
1049     strcpy(buffer,"q");
1050     r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
1051     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
1052     ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
1053     todo_wine
1054     ok(hinst, sz == 4, "got size %lu\n", sz);
1055     ok(hinst, cost == 8, "got cost %d\n", cost);
1056     ok(hinst, !temp, "got temp %d\n", temp);
1057 
1058     sz = 1;
1059     strcpy(buffer,"x");
1060     r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
1061     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
1062     todo_wine {
1063     ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
1064     ok(hinst, sz == 4, "got size %lu\n", sz);
1065     }
1066 
1067     sz = 2;
1068     strcpy(buffer,"x");
1069     r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
1070     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
1071     todo_wine {
1072     ok(hinst, !strcmp(buffer, "C"), "got \"%s\"\n", buffer);
1073     ok(hinst, sz == 4, "got size %lu\n", sz);
1074     }
1075 
1076     sz = 3;
1077     strcpy(buffer,"x");
1078     r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
1079     ok(hinst, !r, "got %u\n", r);
1080     ok(hinst, !strcmp(buffer, "C:"), "got \"%s\"\n", buffer);
1081     ok(hinst, sz == 2, "got size %lu\n", sz);
1082 
1083     sz = 0;
1084     bufferW[0] = 'q';
1085     r = MsiEnumComponentCostsW(hinst, L"One", 0, INSTALLSTATE_LOCAL, bufferW, &sz, &cost, &temp);
1086     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
1087     ok(hinst, bufferW[0] == 'q', "got %s\n", dbgstr_w(bufferW));
1088     ok(hinst, sz == 2, "got size %lu\n", sz);
1089 
1090     sz = 1;
1091     bufferW[0] = 'q';
1092     r = MsiEnumComponentCostsW(hinst, L"One", 0, INSTALLSTATE_LOCAL, bufferW, &sz, &cost, &temp);
1093     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
1094     ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
1095     ok(hinst, sz == 2, "got size %lu\n", sz);
1096 
1097     sz = 2;
1098     bufferW[0] = 'q';
1099     r = MsiEnumComponentCostsW(hinst, L"One", 0, INSTALLSTATE_LOCAL, bufferW, &sz, &cost, &temp);
1100     ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
1101     ok(hinst, !lstrcmpW(bufferW, L"C"), "got %s\n", dbgstr_w(bufferW));
1102     ok(hinst, sz == 2, "got size %lu\n", sz);
1103 
1104     sz = 3;
1105     bufferW[0] = 'q';
1106     r = MsiEnumComponentCostsW(hinst, L"One", 0, INSTALLSTATE_LOCAL, bufferW, &sz, &cost, &temp);
1107     ok(hinst, !r, "got %u\n", r);
1108     ok(hinst, !lstrcmpW(bufferW, L"C:"), "got %s\n", dbgstr_w(bufferW));
1109     ok(hinst, sz == 2, "got size %lu\n", sz);
1110 }
1111 
test_invalid_functions(MSIHANDLE hinst)1112 static void test_invalid_functions(MSIHANDLE hinst)
1113 {
1114     char path[MAX_PATH], package_name[20];
1115     MSIHANDLE db, preview, package;
1116     UINT r;
1117 
1118     r = MsiGetDatabaseState(hinst);
1119     ok(hinst, r == MSIDBSTATE_ERROR, "got %u\n", r);
1120 
1121     db = MsiGetActiveDatabase(hinst);
1122     ok(hinst, db, "MsiGetActiveDatabase failed\n");
1123 
1124     r = MsiDatabaseGenerateTransformA(db, db, "bogus.mst", 0, 0);
1125     todo_wine ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1126 
1127     r = MsiDatabaseApplyTransformA(db, "bogus.mst", 0);
1128     ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1129 
1130     r = MsiCreateTransformSummaryInfoA(db, db, "bogus.mst", 0, 0);
1131     todo_wine ok(hinst, r == ERROR_INSTALL_PACKAGE_OPEN_FAILED, "got %u\n", r);
1132 
1133     GetCurrentDirectoryA(sizeof(path), path);
1134     r = MsiDatabaseExportA(db, "Test", path, "bogus.idt");
1135     ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1136 
1137     r = MsiDatabaseImportA(db, path, "bogus.idt");
1138     ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1139 
1140     r = MsiDatabaseCommit(db);
1141     ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1142 
1143     r = MsiDatabaseMergeA(db, db, "MergeErrors");
1144     ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1145 
1146     r = MsiGetDatabaseState(db);
1147     ok(hinst, r == MSIDBSTATE_ERROR, "got %u\n", r);
1148 
1149     r = MsiEnableUIPreview(db, &preview);
1150     ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1151 
1152     sprintf(package_name, "#%lu", db);
1153     r = MsiOpenPackageA(package_name, &package);
1154     ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1155 
1156     MsiCloseHandle(db);
1157 }
1158 
test_view_get_error(MSIHANDLE hinst)1159 static void test_view_get_error(MSIHANDLE hinst)
1160 {
1161     MSIHANDLE db, view, rec;
1162     char buffer[5];
1163     MSIDBERROR err;
1164     DWORD sz;
1165     UINT r;
1166 
1167     db = MsiGetActiveDatabase(hinst);
1168     ok(hinst, db, "MsiGetActiveDatabase failed\n");
1169 
1170     r = MsiDatabaseOpenViewA(db, "SELECT * FROM `test2`", &view);
1171     ok(hinst, !r, "got %u\n", r);
1172 
1173     r = MsiViewExecute(view, 0);
1174     ok(hinst, !r, "got %u\n", r);
1175 
1176     sz = 0;
1177     err = MsiViewGetErrorA(0, NULL, &sz);
1178     todo_wine ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err);
1179     ok(hinst, sz == 0, "got size %lu\n", sz);
1180 
1181     err = MsiViewGetErrorA(view, NULL, NULL);
1182     ok(hinst, err == MSIDBERROR_INVALIDARG, "got %d\n", err);
1183 
1184     sz = 0;
1185     err = MsiViewGetErrorA(view, NULL, &sz);
1186     ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err);
1187     ok(hinst, sz == 0, "got size %lu\n", sz);
1188 
1189     sz = 0;
1190     strcpy(buffer, "x");
1191     err = MsiViewGetErrorA(view, buffer, &sz);
1192     ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err);
1193     ok(hinst, !strcmp(buffer, "x"), "got \"%s\"\n", buffer);
1194     ok(hinst, sz == 0, "got size %lu\n", sz);
1195 
1196     sz = 1;
1197     strcpy(buffer, "x");
1198     err = MsiViewGetErrorA(view, buffer, &sz);
1199     ok(hinst, err == MSIDBERROR_NOERROR, "got %d\n", err);
1200     ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
1201     ok(hinst, sz == 0, "got size %lu\n", sz);
1202 
1203     rec = MsiCreateRecord(2);
1204     MsiRecordSetInteger(rec, 1, 1);
1205     MsiRecordSetInteger(rec, 2, 2);
1206     r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
1207     ok(hinst, r == ERROR_INVALID_DATA, "got %u\n", r);
1208 
1209     sz = 2;
1210     strcpy(buffer, "x");
1211     err = MsiViewGetErrorA(view, buffer, &sz);
1212     ok(hinst, err == MSIDBERROR_DUPLICATEKEY, "got %d\n", err);
1213     ok(hinst, !strcmp(buffer, "A"), "got \"%s\"\n", buffer);
1214     ok(hinst, sz == 1, "got size %lu\n", sz);
1215 
1216     sz = 2;
1217     strcpy(buffer, "x");
1218     err = MsiViewGetErrorA(view, buffer, &sz);
1219     todo_wine ok(hinst, err == MSIDBERROR_NOERROR, "got %d\n", err);
1220     todo_wine ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
1221     todo_wine ok(hinst, sz == 0, "got size %lu\n", sz);
1222 
1223     r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
1224     ok(hinst, r == ERROR_INVALID_DATA, "got %u\n", r);
1225 
1226     sz = 1;
1227     strcpy(buffer, "x");
1228     err = MsiViewGetErrorA(view, buffer, &sz);
1229     ok(hinst, err == MSIDBERROR_MOREDATA, "got %d\n", err);
1230     ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
1231     ok(hinst, sz == 1, "got size %lu\n", sz);
1232 
1233     sz = 1;
1234     strcpy(buffer, "x");
1235     err = MsiViewGetErrorA(view, buffer, &sz);
1236     todo_wine ok(hinst, err == MSIDBERROR_NOERROR, "got %d\n", err);
1237     ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
1238     todo_wine ok(hinst, sz == 0, "got size %lu\n", sz);
1239 
1240     r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
1241     ok(hinst, r == ERROR_INVALID_DATA, "got %u\n", r);
1242 
1243     sz = 0;
1244     strcpy(buffer, "x");
1245     err = MsiViewGetErrorA(view, buffer, &sz);
1246     ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err);
1247     ok(hinst, !strcmp(buffer, "x"), "got \"%s\"\n", buffer);
1248     ok(hinst, sz == 0, "got size %lu\n", sz);
1249 
1250     sz = 0;
1251     strcpy(buffer, "x");
1252     err = MsiViewGetErrorA(view, buffer, &sz);
1253     ok(hinst, err == MSIDBERROR_FUNCTIONERROR, "got %d\n", err);
1254     ok(hinst, !strcmp(buffer, "x"), "got \"%s\"\n", buffer);
1255     ok(hinst, sz == 0, "got size %lu\n", sz);
1256 
1257     MsiCloseHandle(rec);
1258     MsiCloseHandle(view);
1259     MsiCloseHandle(db);
1260 }
1261 
1262 /* Main test. Anything that doesn't depend on a specific install configuration
1263  * or have undesired side effects should go here. */
main_test(MSIHANDLE hinst)1264 UINT WINAPI main_test(MSIHANDLE hinst)
1265 {
1266     IUnknown *unk = NULL;
1267     HRESULT hr;
1268 
1269     /* Test for an MTA apartment */
1270     hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk);
1271     ok(hinst, hr == S_OK, "CoCreateInstance failed with %08lx\n", hr);
1272 
1273     if (unk) IUnknown_Release(unk);
1274 
1275     /* but ours is uninitialized */
1276     hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1277     ok(hinst, hr == S_OK, "got %#lx\n", hr);
1278     CoUninitialize();
1279 
1280     test_props(hinst);
1281     test_db(hinst);
1282     test_doaction(hinst);
1283     test_targetpath(hinst);
1284     test_misc(hinst);
1285     test_feature_states(hinst);
1286     test_format_record(hinst);
1287     test_costs(hinst);
1288     test_invalid_functions(hinst);
1289     test_view_get_error(hinst);
1290 
1291     return ERROR_SUCCESS;
1292 }
1293 
test_retval(MSIHANDLE hinst)1294 UINT WINAPI test_retval(MSIHANDLE hinst)
1295 {
1296     char prop[10];
1297     DWORD len = sizeof(prop);
1298     UINT retval;
1299 
1300     MsiGetPropertyA(hinst, "TEST_RETVAL", prop, &len);
1301     sscanf(prop, "%u", &retval);
1302     return retval;
1303 }
1304 
append_file(MSIHANDLE hinst,const char * filename,const char * text)1305 static void append_file(MSIHANDLE hinst, const char *filename, const char *text)
1306 {
1307     DWORD size;
1308     HANDLE file = CreateFileA(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
1309     ok(hinst, file != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError());
1310 
1311     SetFilePointer(file, 0, NULL, FILE_END);
1312     WriteFile(file, text, strlen(text), &size, NULL);
1313     CloseHandle(file);
1314 }
1315 
da_immediate(MSIHANDLE hinst)1316 UINT WINAPI da_immediate(MSIHANDLE hinst)
1317 {
1318     char prop[300];
1319     DWORD len = sizeof(prop);
1320 
1321     MsiGetPropertyA(hinst, "TESTPATH", prop, &len);
1322 
1323     append_file(hinst, prop, "one");
1324 
1325     ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_SCHEDULED), "shouldn't be scheduled\n");
1326     ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_ROLLBACK), "shouldn't be rollback\n");
1327     ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_COMMIT), "shouldn't be commit\n");
1328 
1329     return ERROR_SUCCESS;
1330 }
1331 
da_deferred(MSIHANDLE hinst)1332 UINT WINAPI da_deferred(MSIHANDLE hinst)
1333 {
1334     char prop[300];
1335     DWORD len = sizeof(prop);
1336     LANGID lang;
1337     UINT r;
1338 
1339     /* Test that we were in fact deferred */
1340     r = MsiGetPropertyA(hinst, "CustomActionData", prop, &len);
1341     ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1342     ok(hinst, prop[0], "CustomActionData was empty\n");
1343 
1344     append_file(hinst, prop, "two");
1345 
1346     /* Test available properties */
1347     len = sizeof(prop);
1348     r = MsiGetPropertyA(hinst, "ProductCode", prop, &len);
1349     ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1350     ok(hinst, prop[0], "got %s\n", prop);
1351 
1352     len = sizeof(prop);
1353     r = MsiGetPropertyA(hinst, "UserSID", prop, &len);
1354     ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1355     ok(hinst, prop[0], "got %s\n", prop);
1356 
1357     len = sizeof(prop);
1358     r = MsiGetPropertyA(hinst, "TESTPATH", prop, &len);
1359     ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1360     todo_wine
1361     ok(hinst, !prop[0], "got %s\n", prop);
1362 
1363     /* Test modes */
1364     ok(hinst, MsiGetMode(hinst, MSIRUNMODE_SCHEDULED), "should be scheduled\n");
1365     ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_ROLLBACK), "shouldn't be rollback\n");
1366     ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_COMMIT), "shouldn't be commit\n");
1367 
1368     lang = MsiGetLanguage(hinst);
1369     ok(hinst, lang != ERROR_INVALID_HANDLE, "MsiGetLanguage failed\n");
1370 
1371     return ERROR_SUCCESS;
1372 }
1373 
1374 static int global_state;
1375 
process1(MSIHANDLE hinst)1376 UINT WINAPI process1(MSIHANDLE hinst)
1377 {
1378     SetEnvironmentVariableA("MSI_PROCESS_TEST","1");
1379     global_state++;
1380     return ERROR_SUCCESS;
1381 }
1382 
process2(MSIHANDLE hinst)1383 UINT WINAPI process2(MSIHANDLE hinst)
1384 {
1385     char env[2] = {0};
1386     DWORD r = GetEnvironmentVariableA("MSI_PROCESS_TEST", env, sizeof(env));
1387     ok(hinst, r == 1, "got %lu, error %lu\n", r, GetLastError());
1388     ok(hinst, !strcmp(env, "1"), "got %s\n", env);
1389     ok(hinst, !global_state, "got global_state %d\n", global_state);
1390     return ERROR_SUCCESS;
1391 }
1392 
async1(MSIHANDLE hinst)1393 UINT WINAPI async1(MSIHANDLE hinst)
1394 {
1395     HANDLE event = CreateEventA(NULL, TRUE, FALSE, "wine_msi_async_test");
1396     HANDLE event2 = CreateEventA(NULL, TRUE, FALSE, "wine_msi_async_test2");
1397     DWORD r = WaitForSingleObject(event, 10000);
1398     ok(hinst, !r, "wait timed out\n");
1399     SetEvent(event2);
1400     return ERROR_SUCCESS;
1401 }
1402 
async2(MSIHANDLE hinst)1403 UINT WINAPI async2(MSIHANDLE hinst)
1404 {
1405     HANDLE event = CreateEventA(NULL, TRUE, FALSE, "wine_msi_async_test");
1406     HANDLE event2 = CreateEventA(NULL, TRUE, FALSE, "wine_msi_async_test2");
1407     DWORD r;
1408     SetEvent(event);
1409     r = WaitForSingleObject(event2, 10000);
1410     ok(hinst, !r, "wait timed out\n");
1411     return ERROR_SUCCESS;
1412 }
1413 
pf_exists(const char * file)1414 static BOOL pf_exists(const char *file)
1415 {
1416     char path[MAX_PATH];
1417 
1418     if (FAILED(SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, path)))
1419         SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES, NULL, 0, path);
1420     strcat(path, "\\");
1421     strcat(path, file);
1422     return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
1423 }
1424 
cf_present(MSIHANDLE hinst)1425 UINT WINAPI cf_present(MSIHANDLE hinst)
1426 {
1427     ok(hinst, pf_exists("msitest\\first"), "folder absent\n");
1428     ok(hinst, pf_exists("msitest\\second"), "folder absent\n");
1429     ok(hinst, pf_exists("msitest\\third"), "folder absent\n");
1430     return ERROR_SUCCESS;
1431 }
1432 
cf_absent(MSIHANDLE hinst)1433 UINT WINAPI cf_absent(MSIHANDLE hinst)
1434 {
1435     ok(hinst, !pf_exists("msitest\\first"), "folder present\n");
1436     ok(hinst, !pf_exists("msitest\\second"), "folder present\n");
1437     ok(hinst, !pf_exists("msitest\\third"), "folder present\n");
1438     return ERROR_SUCCESS;
1439 }
1440 
file_present(MSIHANDLE hinst)1441 UINT WINAPI file_present(MSIHANDLE hinst)
1442 {
1443     ok(hinst, pf_exists("msitest\\first\\one.txt"), "file absent\n");
1444     ok(hinst, pf_exists("msitest\\second\\two.txt"), "file absent\n");
1445     return ERROR_SUCCESS;
1446 }
1447 
file_absent(MSIHANDLE hinst)1448 UINT WINAPI file_absent(MSIHANDLE hinst)
1449 {
1450     ok(hinst, !pf_exists("msitest\\first\\one.txt"), "file present\n");
1451     ok(hinst, !pf_exists("msitest\\second\\two.txt"), "file present\n");
1452     return ERROR_SUCCESS;
1453 }
1454 
crs_present(MSIHANDLE hinst)1455 UINT WINAPI crs_present(MSIHANDLE hinst)
1456 {
1457     ok(hinst, pf_exists("msitest\\shortcut.lnk"), "shortcut absent\n");
1458     return ERROR_SUCCESS;
1459 }
1460 
crs_absent(MSIHANDLE hinst)1461 UINT WINAPI crs_absent(MSIHANDLE hinst)
1462 {
1463     ok(hinst, !pf_exists("msitest\\shortcut.lnk"), "shortcut present\n");
1464     return ERROR_SUCCESS;
1465 }
1466 
sds_present(MSIHANDLE hinst)1467 UINT WINAPI sds_present(MSIHANDLE hinst)
1468 {
1469     SC_HANDLE manager, service;
1470     manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1471     service = OpenServiceA(manager, "TestService3", GENERIC_ALL);
1472     ok(hinst, !!service, "service absent: %lu\n", GetLastError());
1473     CloseServiceHandle(service);
1474     CloseServiceHandle(manager);
1475     return ERROR_SUCCESS;
1476 }
1477 
sds_absent(MSIHANDLE hinst)1478 UINT WINAPI sds_absent(MSIHANDLE hinst)
1479 {
1480     SC_HANDLE manager, service;
1481     manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1482     service = OpenServiceA(manager, "TestService3", GENERIC_ALL);
1483     ok(hinst, !service, "service present\n");
1484     if (service) CloseServiceHandle(service);
1485     CloseServiceHandle(manager);
1486     return ERROR_SUCCESS;
1487 }
1488 
sis_present(MSIHANDLE hinst)1489 UINT WINAPI sis_present(MSIHANDLE hinst)
1490 {
1491     SC_HANDLE manager, service;
1492     manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1493     service = OpenServiceA(manager, "TestService", GENERIC_ALL);
1494     ok(hinst, !!service, "service absent: %lu\n", GetLastError());
1495     CloseServiceHandle(service);
1496     CloseServiceHandle(manager);
1497     return ERROR_SUCCESS;
1498 }
1499 
sis_absent(MSIHANDLE hinst)1500 UINT WINAPI sis_absent(MSIHANDLE hinst)
1501 {
1502     SC_HANDLE manager, service;
1503     manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1504     service = OpenServiceA(manager, "TestService", GENERIC_ALL);
1505     ok(hinst, !service, "service present\n");
1506     if (service) CloseServiceHandle(service);
1507     CloseServiceHandle(manager);
1508     return ERROR_SUCCESS;
1509 }
1510 
sss_started(MSIHANDLE hinst)1511 UINT WINAPI sss_started(MSIHANDLE hinst)
1512 {
1513     SC_HANDLE manager, service;
1514     SERVICE_STATUS status;
1515     BOOL ret;
1516 
1517     manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1518     service = OpenServiceA(manager, "Spooler", SC_MANAGER_ALL_ACCESS);
1519     ret = QueryServiceStatus(service, &status);
1520     ok(hinst, ret, "QueryServiceStatus failed: %lu\n", GetLastError());
1521     ok(hinst, status.dwCurrentState == SERVICE_RUNNING, "got %lu\n", status.dwCurrentState);
1522 
1523     CloseServiceHandle(service);
1524     CloseServiceHandle(manager);
1525     return ERROR_SUCCESS;
1526 }
1527 
sss_stopped(MSIHANDLE hinst)1528 UINT WINAPI sss_stopped(MSIHANDLE hinst)
1529 {
1530     SC_HANDLE manager, service;
1531     SERVICE_STATUS status;
1532     BOOL ret;
1533 
1534     manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1535     service = OpenServiceA(manager, "Spooler", SC_MANAGER_ALL_ACCESS);
1536     ret = QueryServiceStatus(service, &status);
1537     ok(hinst, ret, "QueryServiceStatus failed: %lu\n", GetLastError());
1538     ok(hinst, status.dwCurrentState == SERVICE_STOPPED, "got %lu\n", status.dwCurrentState);
1539 
1540     CloseServiceHandle(service);
1541     CloseServiceHandle(manager);
1542     return ERROR_SUCCESS;
1543 }
1544 
rd_present(MSIHANDLE hinst)1545 UINT WINAPI rd_present(MSIHANDLE hinst)
1546 {
1547     ok(hinst, pf_exists("msitest\\original2.txt"), "file absent\n");
1548     ok(hinst, pf_exists("msitest\\duplicate.txt"), "file absent\n");
1549     ok(hinst, !pf_exists("msitest\\original3.txt"), "file present\n");
1550     ok(hinst, !pf_exists("msitest\\duplicate2.txt"), "file present\n");
1551     return ERROR_SUCCESS;
1552 }
1553 
rd_absent(MSIHANDLE hinst)1554 UINT WINAPI rd_absent(MSIHANDLE hinst)
1555 {
1556     ok(hinst, !pf_exists("msitest\\original2.txt"), "file present\n");
1557     ok(hinst, !pf_exists("msitest\\duplicate.txt"), "file present\n");
1558     ok(hinst, !pf_exists("msitest\\original3.txt"), "file present\n");
1559     ok(hinst, !pf_exists("msitest\\duplicate2.txt"), "file present\n");
1560     return ERROR_SUCCESS;
1561 }
1562 
odbc_present(MSIHANDLE hinst)1563 UINT WINAPI odbc_present(MSIHANDLE hinst)
1564 {
1565     int gotdriver = 0, gotdriver2 = 0;
1566     char buffer[1000], *p;
1567     WORD len;
1568     BOOL r;
1569 
1570     buffer[0] = 0;
1571     len = sizeof(buffer);
1572     r = SQLGetInstalledDrivers(buffer, sizeof(buffer), &len);
1573     if (r) ok(hinst, len < sizeof(buffer), "buffer too small\n");
1574     for (p = buffer; *p; p += strlen(p) + 1)
1575     {
1576         if (!strcmp(p, "ODBC test driver"))
1577             gotdriver = 1;
1578         if (!strcmp(p, "ODBC test driver2"))
1579             gotdriver2 = 1;
1580     }
1581     ok(hinst, gotdriver, "driver absent\n");
1582     ok(hinst, gotdriver2, "driver 2 absent\n");
1583     return ERROR_SUCCESS;
1584 }
1585 
odbc_absent(MSIHANDLE hinst)1586 UINT WINAPI odbc_absent(MSIHANDLE hinst)
1587 {
1588     int gotdriver = 0, gotdriver2 = 0;
1589     char buffer[1000], *p;
1590     WORD len;
1591     BOOL r;
1592 
1593     buffer[0] = 0;
1594     len = sizeof(buffer);
1595     r = SQLGetInstalledDrivers(buffer, sizeof(buffer), &len);
1596     if (r) ok(hinst, len < sizeof(buffer), "buffer too small\n");
1597     for (p = buffer; *p; p += strlen(p) + 1)
1598     {
1599         if (!strcmp(p, "ODBC test driver"))
1600             gotdriver = 1;
1601         if (!strcmp(p, "ODBC test driver2"))
1602             gotdriver2 = 1;
1603     }
1604     ok(hinst, !gotdriver, "driver present\n");
1605     ok(hinst, !gotdriver2, "driver 2 present\n");
1606     return ERROR_SUCCESS;
1607 }
1608 
mov_present(MSIHANDLE hinst)1609 UINT WINAPI mov_present(MSIHANDLE hinst)
1610 {
1611     ok(hinst, pf_exists("msitest\\canada"), "file absent\n");
1612     ok(hinst, pf_exists("msitest\\dominica"), "file absent\n");
1613     return ERROR_SUCCESS;
1614 }
1615 
mov_absent(MSIHANDLE hinst)1616 UINT WINAPI mov_absent(MSIHANDLE hinst)
1617 {
1618     ok(hinst, !pf_exists("msitest\\canada"), "file present\n");
1619     ok(hinst, !pf_exists("msitest\\dominica"), "file present\n");
1620     return ERROR_SUCCESS;
1621 }
1622 
check_reg_str(MSIHANDLE hinst,HKEY key,const char * name,const char * expect)1623 static void check_reg_str(MSIHANDLE hinst, HKEY key, const char *name, const char *expect)
1624 {
1625     char value[300];
1626     DWORD sz;
1627     LONG res;
1628 
1629     sz = sizeof(value);
1630     res = RegQueryValueExA(key, name, NULL, NULL, (BYTE *)value, &sz);
1631     if (expect)
1632     {
1633         ok(hinst, !res, "failed to get value \"%s\": %ld\n", name, res);
1634         ok(hinst, !strcmp(value, expect), "\"%s\": expected \"%s\", got \"%s\"\n",
1635             name, expect, value);
1636     }
1637     else
1638         ok(hinst, res == ERROR_FILE_NOT_FOUND, "\"%s\": expected missing, got %ld\n",
1639             name, res);
1640 }
1641 
1642 static const char path_dotnet[] = "Software\\Microsoft\\Installer\\Assemblies\\Global";
1643 static const char name_dotnet[] = "Wine.Dotnet.Assembly,processorArchitecture=\"MSIL\","
1644     "publicKeyToken=\"abcdef0123456789\",version=\"1.0.0.0\",culture=\"neutral\"";
1645 
pa_present(MSIHANDLE hinst)1646 UINT WINAPI pa_present(MSIHANDLE hinst)
1647 {
1648     HKEY key;
1649     LONG res;
1650 
1651     res = RegOpenKeyA(HKEY_CURRENT_USER, path_dotnet, &key);
1652     ok(hinst, !res, "got %ld\n", res);
1653     check_reg_str(hinst, key, name_dotnet, "rcHQPHq?CA@Uv-XqMI1e>Z'q,T*76M@=YEg6My?~]");
1654     RegCloseKey(key);
1655 
1656     return ERROR_SUCCESS;
1657 }
1658 
pa_absent(MSIHANDLE hinst)1659 UINT WINAPI pa_absent(MSIHANDLE hinst)
1660 {
1661     HKEY key;
1662     LONG res;
1663 
1664     res = RegOpenKeyA(HKEY_CURRENT_USER, path_dotnet, &key);
1665     ok(hinst, !res || res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1666     if (!res)
1667     {
1668         check_reg_str(hinst, key, name_dotnet, NULL);
1669         RegCloseKey(key);
1670     }
1671     return ERROR_SUCCESS;
1672 }
1673 
1674 static const char ppc_key[] = "Software\\Microsoft\\Windows\\CurrentVersion\\"
1675     "Installer\\UserData\\S-1-5-18\\Components\\CBABC2FDCCB35E749A8944D8C1C098B5";
1676 
ppc_present(MSIHANDLE hinst)1677 UINT WINAPI ppc_present(MSIHANDLE hinst)
1678 {
1679     char expect[MAX_PATH];
1680     HKEY key;
1681     UINT r;
1682 
1683     r = RegOpenKeyExA(HKEY_LOCAL_MACHINE, ppc_key, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &key);
1684     ok(hinst, !r, "got %u\n", r);
1685 
1686     if (FAILED(SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, expect)))
1687         SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES, NULL, 0, expect);
1688     strcat(expect, "\\msitest\\maximus");
1689     check_reg_str(hinst, key, "84A88FD7F6998CE40A22FB59F6B9C2BB", expect);
1690 
1691     RegCloseKey(key);
1692     return ERROR_SUCCESS;
1693 }
1694 
ppc_absent(MSIHANDLE hinst)1695 UINT WINAPI ppc_absent(MSIHANDLE hinst)
1696 {
1697     HKEY key;
1698     UINT r;
1699 
1700     r = RegOpenKeyExA(HKEY_LOCAL_MACHINE, ppc_key, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &key);
1701     ok(hinst, r == ERROR_FILE_NOT_FOUND, "got %u\n", r);
1702     return ERROR_SUCCESS;
1703 }
1704 
1705 static const char pub_key[] = "Software\\Microsoft\\Installer\\Components\\0CBCFA296AC907244845745CEEB2F8AA";
1706 
pub_present(MSIHANDLE hinst)1707 UINT WINAPI pub_present(MSIHANDLE hinst)
1708 {
1709     HKEY key;
1710     LONG res;
1711 
1712     res = RegOpenKeyA(HKEY_CURRENT_USER, pub_key, &key);
1713     ok(hinst, !res, "got %ld\n", res);
1714     res = RegQueryValueExA(key, "english.txt", NULL, NULL, NULL, NULL);
1715     ok(hinst, !res, "got %ld\n", res);
1716     RegCloseKey(key);
1717     return ERROR_SUCCESS;
1718 }
1719 
pub_absent(MSIHANDLE hinst)1720 UINT WINAPI pub_absent(MSIHANDLE hinst)
1721 {
1722     HKEY key;
1723     LONG res;
1724 
1725     res = RegOpenKeyA(HKEY_CURRENT_USER, pub_key, &key);
1726     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1727     return ERROR_SUCCESS;
1728 }
1729 
1730 static const char pf_classkey[] = "Installer\\Features\\84A88FD7F6998CE40A22FB59F6B9C2BB";
1731 static const char pf_userkey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\"
1732     "Installer\\UserData\\S-1-5-18\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB\\Features";
1733 
pf_present(MSIHANDLE hinst)1734 UINT WINAPI pf_present(MSIHANDLE hinst)
1735 {
1736     HKEY key;
1737     LONG res;
1738 
1739     res = RegOpenKeyExA(HKEY_CLASSES_ROOT, pf_classkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
1740     ok(hinst, !res, "got %ld\n", res);
1741     check_reg_str(hinst, key, "feature", "");
1742     check_reg_str(hinst, key, "montecristo", "");
1743     RegCloseKey(key);
1744 
1745     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, pf_userkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
1746     ok(hinst, !res, "got %ld\n", res);
1747     check_reg_str(hinst, key, "feature", "VGtfp^p+,?82@JU1j_KE");
1748     check_reg_str(hinst, key, "montecristo", "VGtfp^p+,?82@JU1j_KE");
1749     RegCloseKey(key);
1750 
1751     return ERROR_SUCCESS;
1752 }
1753 
pf_absent(MSIHANDLE hinst)1754 UINT WINAPI pf_absent(MSIHANDLE hinst)
1755 {
1756     HKEY key;
1757     LONG res;
1758 
1759     res = RegOpenKeyExA(HKEY_CLASSES_ROOT, pf_classkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
1760     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1761 
1762     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, pf_userkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
1763     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1764 
1765     return ERROR_SUCCESS;
1766 }
1767 
1768 static const char pp_prodkey[] = "Installer\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB";
1769 
pp_present(MSIHANDLE hinst)1770 UINT WINAPI pp_present(MSIHANDLE hinst)
1771 {
1772     HKEY key;
1773     LONG res;
1774 
1775     res = RegOpenKeyExA(HKEY_CLASSES_ROOT, pp_prodkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
1776     ok(hinst, !res, "got %ld\n", res);
1777     check_reg_str(hinst, key, "ProductName", "MSITEST");
1778     check_reg_str(hinst, key, "PackageCode", "AC75740029052C94DA02821EECD05F2F");
1779     check_reg_str(hinst, key, "Clients", ":");
1780 
1781     RegCloseKey(key);
1782     return ERROR_SUCCESS;
1783 }
1784 
pp_absent(MSIHANDLE hinst)1785 UINT WINAPI pp_absent(MSIHANDLE hinst)
1786 {
1787     HKEY key;
1788     LONG res;
1789 
1790     res = RegOpenKeyExA(HKEY_CLASSES_ROOT, pp_prodkey, 0, KEY_READ | KEY_WOW64_64KEY, &key);
1791     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1792 
1793     return ERROR_SUCCESS;
1794 }
1795 
rci_present(MSIHANDLE hinst)1796 UINT WINAPI rci_present(MSIHANDLE hinst)
1797 {
1798     HKEY key;
1799     LONG res;
1800 
1801     res = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}",
1802         0, KEY_READ | KEY_WOW64_32KEY, &key);
1803     ok(hinst, !res, "got %ld\n", res);
1804     RegCloseKey(key);
1805 
1806     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "FileType\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}", &key);
1807     ok(hinst, !res, "got %ld\n", res);
1808     RegCloseKey(key);
1809 
1810     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "AppID\\{CFCC3B38-E683-497D-9AB4-CB40AAFE307F}", &key);
1811     ok(hinst, !res, "got %ld\n", res);
1812     RegCloseKey(key);
1813 
1814     return ERROR_SUCCESS;
1815 }
1816 
rci_absent(MSIHANDLE hinst)1817 UINT WINAPI rci_absent(MSIHANDLE hinst)
1818 {
1819     HKEY key;
1820     LONG res;
1821 
1822     res = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}",
1823         0, KEY_READ | KEY_WOW64_32KEY, &key);
1824     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1825 
1826     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "FileType\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}", &key);
1827     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1828 
1829     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "AppID\\{CFCC3B38-E683-497D-9AB4-CB40AAFE307F}", &key);
1830     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1831 
1832     return ERROR_SUCCESS;
1833 }
1834 
rei_present(MSIHANDLE hinst)1835 UINT WINAPI rei_present(MSIHANDLE hinst)
1836 {
1837     HKEY key;
1838     LONG res;
1839 
1840     res = RegOpenKeyA(HKEY_CLASSES_ROOT, ".extension", &key);
1841     ok(hinst, !res, "got %ld\n", res);
1842     RegCloseKey(key);
1843 
1844     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Prog.Id.1\\shell\\Open\\command", &key);
1845     ok(hinst, !res, "got %ld\n", res);
1846     RegCloseKey(key);
1847 
1848     return ERROR_SUCCESS;
1849 }
1850 
rei_absent(MSIHANDLE hinst)1851 UINT WINAPI rei_absent(MSIHANDLE hinst)
1852 {
1853     HKEY key;
1854     LONG res;
1855 
1856     res = RegOpenKeyA(HKEY_CLASSES_ROOT, ".extension", &key);
1857     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1858 
1859     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Prog.Id.1\\shell\\Open\\command", &key);
1860     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1861 
1862     return ERROR_SUCCESS;
1863 }
1864 
1865 static const char font_key[] = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
1866 
font_present(MSIHANDLE hinst)1867 UINT WINAPI font_present(MSIHANDLE hinst)
1868 {
1869     HKEY key;
1870     LONG res;
1871 
1872     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, font_key, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &key);
1873     ok(hinst, !res, "got %ld\n", res);
1874     res = RegQueryValueExA(key, "msi test font", NULL, NULL, NULL, NULL);
1875     ok(hinst, !res, "got %ld\n", res);
1876     RegCloseKey(key);
1877 
1878     return ERROR_SUCCESS;
1879 }
1880 
font_absent(MSIHANDLE hinst)1881 UINT WINAPI font_absent(MSIHANDLE hinst)
1882 {
1883     HKEY key;
1884     LONG res;
1885 
1886     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, font_key, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &key);
1887     ok(hinst, !res, "got %ld\n", res);
1888     check_reg_str(hinst, key, "msi test font", NULL);
1889     RegCloseKey(key);
1890 
1891     return ERROR_SUCCESS;
1892 }
1893 
rmi_present(MSIHANDLE hinst)1894 UINT WINAPI rmi_present(MSIHANDLE hinst)
1895 {
1896     HKEY key;
1897     LONG res;
1898 
1899     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "MIME\\Database\\Content Type\\mime/type", &key);
1900     ok(hinst, !res, "got %ld\n", res);
1901 
1902     return ERROR_SUCCESS;
1903 }
1904 
rmi_absent(MSIHANDLE hinst)1905 UINT WINAPI rmi_absent(MSIHANDLE hinst)
1906 {
1907     HKEY key;
1908     LONG res;
1909 
1910     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "MIME\\Database\\Content Type\\mime/type", &key);
1911     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1912 
1913     return ERROR_SUCCESS;
1914 }
1915 
1916 static const char rp_key[] = "Software\\Microsoft\\Windows\\CurrentVersion\\"
1917     "Uninstall\\{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}";
1918 
rp_present(MSIHANDLE hinst)1919 UINT WINAPI rp_present(MSIHANDLE hinst)
1920 {
1921     HKEY key;
1922     LONG res;
1923 
1924     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, rp_key, 0, KEY_READ | KEY_WOW64_32KEY, &key);
1925     ok(hinst, !res, "got %ld\n", res);
1926     check_reg_str(hinst, key, "DisplayName", "MSITEST");
1927     RegCloseKey(key);
1928 
1929     return ERROR_SUCCESS;
1930 }
1931 
rp_absent(MSIHANDLE hinst)1932 UINT WINAPI rp_absent(MSIHANDLE hinst)
1933 {
1934     HKEY key;
1935     LONG res;
1936 
1937     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, rp_key, 0, KEY_READ | KEY_WOW64_32KEY, &key);
1938     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1939 
1940     return ERROR_SUCCESS;
1941 }
1942 
rpi_present(MSIHANDLE hinst)1943 UINT WINAPI rpi_present(MSIHANDLE hinst)
1944 {
1945     HKEY key;
1946     LONG res;
1947 
1948     res = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}",
1949         0, KEY_READ | KEY_WOW64_32KEY, &key);
1950     ok(hinst, !res, "got %ld\n", res);
1951     RegCloseKey(key);
1952 
1953     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.1", &key);
1954     ok(hinst, !res, "got %ld\n", res);
1955     RegCloseKey(key);
1956 
1957     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class", &key);
1958     ok(hinst, !res, "got %ld\n", res);
1959     RegCloseKey(key);
1960 
1961     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.2", &key);
1962     ok(hinst, !res, "got %ld\n", res);
1963     RegCloseKey(key);
1964 
1965     return ERROR_SUCCESS;
1966 }
1967 
rpi_absent(MSIHANDLE hinst)1968 UINT WINAPI rpi_absent(MSIHANDLE hinst)
1969 {
1970     HKEY key;
1971     LONG res;
1972 
1973     res = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}",
1974         0, KEY_READ | KEY_WOW64_32KEY, &key);
1975     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1976 
1977     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.1", &key);
1978     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1979 
1980     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class", &key);
1981     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1982 
1983     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.2", &key);
1984     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1985 
1986     return ERROR_SUCCESS;
1987 }
1988 
1989 static const CHAR ru_key[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Installer"
1990     "\\UserData\\S-1-5-18\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB\\InstallProperties";
1991 
ru_present(MSIHANDLE hinst)1992 UINT WINAPI ru_present(MSIHANDLE hinst)
1993 {
1994     HKEY key;
1995     LONG res;
1996 
1997     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, ru_key, 0, KEY_READ | KEY_WOW64_64KEY, &key);
1998     ok(hinst, !res, "got %ld\n", res);
1999     check_reg_str(hinst, key, "ProductID", "none");
2000     RegCloseKey(key);
2001 
2002     return ERROR_SUCCESS;
2003 }
2004 
ru_absent(MSIHANDLE hinst)2005 UINT WINAPI ru_absent(MSIHANDLE hinst)
2006 {
2007     HKEY key;
2008     LONG res;
2009 
2010     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, ru_key, 0, KEY_READ | KEY_WOW64_64KEY, &key);
2011     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
2012 
2013     return ERROR_SUCCESS;
2014 }
2015 
2016 static const GUID LIBID_register_test =
2017     {0xeac5166a, 0x9734, 0x4d91, {0x87,0x8f, 0x1d,0xd0,0x23,0x04,0xc6,0x6c}};
2018 
tl_present(MSIHANDLE hinst)2019 UINT WINAPI tl_present(MSIHANDLE hinst)
2020 {
2021     ITypeLib *tlb;
2022     HRESULT hr;
2023 
2024     hr = LoadRegTypeLib(&LIBID_register_test, 7, 1, 0, &tlb);
2025     ok(hinst, hr == S_OK, "got %#lx\n", hr);
2026     ITypeLib_Release(tlb);
2027 
2028     return ERROR_SUCCESS;
2029 }
2030 
tl_absent(MSIHANDLE hinst)2031 UINT WINAPI tl_absent(MSIHANDLE hinst)
2032 {
2033     ITypeLib *tlb;
2034     HRESULT hr;
2035 
2036     hr = LoadRegTypeLib(&LIBID_register_test, 7, 1, 0, &tlb);
2037     ok(hinst, hr == TYPE_E_LIBNOTREGISTERED, "got %#lx\n", hr);
2038 
2039     return ERROR_SUCCESS;
2040 }
2041 
sr_present(MSIHANDLE hinst)2042 UINT WINAPI sr_present(MSIHANDLE hinst)
2043 {
2044     HKEY key;
2045     LONG res;
2046 
2047     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "selfreg_test", &key);
2048     ok(hinst, !res, "got %ld\n", res);
2049     RegCloseKey(key);
2050 
2051     return ERROR_SUCCESS;
2052 }
2053 
sr_absent(MSIHANDLE hinst)2054 UINT WINAPI sr_absent(MSIHANDLE hinst)
2055 {
2056     HKEY key;
2057     LONG res;
2058 
2059     res = RegOpenKeyA(HKEY_CLASSES_ROOT, "selfreg_test", &key);
2060     ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
2061 
2062     return ERROR_SUCCESS;
2063 }
2064 
env_present(MSIHANDLE hinst)2065 UINT WINAPI env_present(MSIHANDLE hinst)
2066 {
2067     HKEY key;
2068     LONG res;
2069 
2070     res = RegOpenKeyA(HKEY_CURRENT_USER, "Environment", &key);
2071     ok(hinst, !res, "got %ld\n", res);
2072     check_reg_str(hinst, key, "MSITESTVAR3", "1");
2073     check_reg_str(hinst, key, "MSITESTVAR4", "1");
2074     RegCloseKey(key);
2075 
2076     return ERROR_SUCCESS;
2077 }
2078 
env_absent(MSIHANDLE hinst)2079 UINT WINAPI env_absent(MSIHANDLE hinst)
2080 {
2081     HKEY key;
2082     LONG res;
2083 
2084     res = RegOpenKeyA(HKEY_CURRENT_USER, "Environment", &key);
2085     ok(hinst, !res, "got %ld\n", res);
2086     check_reg_str(hinst, key, "MSITESTVAR3", NULL);
2087     check_reg_str(hinst, key, "MSITESTVAR4", NULL);
2088     RegCloseKey(key);
2089 
2090     return ERROR_SUCCESS;
2091 }
2092 
ini_present(MSIHANDLE hinst)2093 UINT WINAPI ini_present(MSIHANDLE hinst)
2094 {
2095     char path[MAX_PATH], buf[10];
2096     DWORD len;
2097 
2098     if (FAILED(SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, path)))
2099         SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES, NULL, 0, path);
2100     strcat(path, "\\msitest\\test.ini");
2101 
2102     len = GetPrivateProfileStringA("section1", "key1", NULL, buf, sizeof(buf), path);
2103     ok(hinst, len == 6, "got %lu\n", len);
2104 
2105     return ERROR_SUCCESS;
2106 }
2107 
ini_absent(MSIHANDLE hinst)2108 UINT WINAPI ini_absent(MSIHANDLE hinst)
2109 {
2110     char path[MAX_PATH], buf[10];
2111     DWORD len;
2112 
2113     if (FAILED(SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, path)))
2114         SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES, NULL, 0, path);
2115     strcat(path, "\\msitest\\test.ini");
2116 
2117     len = GetPrivateProfileStringA("section1", "key1", NULL, buf, sizeof(buf), path);
2118     ok(hinst, !len, "got %lu\n", len);
2119 
2120     return ERROR_SUCCESS;
2121 }
2122 
wrv_present(MSIHANDLE hinst)2123 UINT WINAPI wrv_present(MSIHANDLE hinst)
2124 {
2125     HKEY key;
2126     LONG res;
2127 
2128     res = RegOpenKeyA(HKEY_CURRENT_USER, "msitest", &key);
2129     ok(hinst, !res, "got %ld\n", res);
2130     check_reg_str(hinst, key, "sz", "string");
2131     RegCloseKey(key);
2132 
2133     return ERROR_SUCCESS;
2134 }
2135 
wrv_absent(MSIHANDLE hinst)2136 UINT WINAPI wrv_absent(MSIHANDLE hinst)
2137 {
2138     HKEY key;
2139     LONG res;
2140 
2141     res = RegOpenKeyA(HKEY_CURRENT_USER, "msitest", &key);
2142     ok(hinst, !res, "got %ld\n", res);
2143     check_reg_str(hinst, key, "sz", NULL);
2144     RegCloseKey(key);
2145 
2146     return ERROR_SUCCESS;
2147 }
2148