Release 9.12.
[wine.git] / dlls / msi / tests / custom.c
blob8c5e7e4bbd072b8009e50d589bb3141712be4192
1 /*
2 * DLL for testing type 1 custom actions
4 * Copyright 2017 Zebediah Figura
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 #if 0
22 #pragma makedep testdll
23 #endif
25 #include <stdarg.h>
26 #include <stdio.h>
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>
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
45 static int todo_level, todo_do_loop;
47 static void WINAPIV __WINE_PRINTF_ATTR(6,7) ok_(MSIHANDLE hinst, int todo, const char *file, int line, int condition, const char *msg, ...)
49 static char buffer[2000];
50 MSIHANDLE record;
51 va_list valist;
53 va_start(valist, msg);
54 vsprintf(buffer, msg, valist);
55 va_end(valist);
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);
67 static void winetest_start_todo( int is_todo )
69 todo_level = (todo_level << 1) | (is_todo != 0);
70 todo_do_loop=1;
73 static int winetest_loop_todo(void)
75 int do_loop=todo_do_loop;
76 todo_do_loop=0;
77 return do_loop;
80 static void winetest_end_todo(void)
82 todo_level >>= 1;
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)
91 static const char *dbgstr_w(WCHAR *str)
93 static char buffer[300], *p;
95 if (!str) return "(null)";
97 p = buffer;
98 *p++ = 'L';
99 *p++ = '"';
100 while ((*p++ = *str++));
101 *p++ = '"';
102 *p++ = 0;
104 return buffer;
107 static void check_prop(MSIHANDLE hinst, const char *prop, const char *expect)
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);
117 static void test_props(MSIHANDLE hinst)
119 char buffer[10];
120 WCHAR bufferW[10];
121 DWORD sz;
122 UINT r;
124 /* test invalid values */
125 r = MsiGetPropertyA(hinst, NULL, NULL, NULL);
126 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
128 r = MsiGetPropertyA(hinst, "boo", NULL, NULL);
129 ok(hinst, !r, "got %u\n", r);
131 r = MsiGetPropertyA(hinst, "boo", buffer, NULL );
132 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
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);
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);
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);
153 /* set the property to something */
154 r = MsiSetPropertyA(hinst, NULL, NULL);
155 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
157 r = MsiSetPropertyA(hinst, "", NULL);
158 ok(hinst, !r, "got %u\n", r);
160 r = MsiSetPropertyA(hinst, "", "asdf");
161 ok(hinst, r == ERROR_FUNCTION_FAILED, "got %u\n", r);
163 r = MsiSetPropertyA(hinst, "=", "asdf");
164 ok(hinst, !r, "got %u\n", r);
165 check_prop(hinst, "=", "asdf");
167 r = MsiSetPropertyA(hinst, " ", "asdf");
168 ok(hinst, !r, "got %u\n", r);
169 check_prop(hinst, " ", "asdf");
171 r = MsiSetPropertyA(hinst, "'", "asdf");
172 ok(hinst, !r, "got %u\n", r);
173 check_prop(hinst, "'", "asdf");
175 r = MsiSetPropertyA(hinst, "boo", NULL);
176 ok(hinst, !r, "got %u\n", r);
177 check_prop(hinst, "boo", "");
179 r = MsiSetPropertyA(hinst, "boo", "");
180 ok(hinst, !r, "got %u\n", r);
181 check_prop(hinst, "boo", "");
183 r = MsiSetPropertyA(hinst, "boo", "xyz");
184 ok(hinst, !r, "got %u\n", r);
185 check_prop(hinst, "boo", "xyz");
187 r = MsiGetPropertyA(hinst, "boo", NULL, NULL);
188 ok(hinst, !r, "got %u\n", r);
190 r = MsiGetPropertyA(hinst, "boo", buffer, NULL );
191 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
193 /* Returned size is in bytes, not chars, but only for custom actions.
194 * Seems to be a casualty of RPC... */
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);
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);
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);
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);
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);
229 r = MsiGetPropertyW(hinst, L"boo", NULL, NULL);
230 ok(hinst, !r, "got %u\n", r);
232 r = MsiGetPropertyW(hinst, L"boo", bufferW, NULL );
233 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
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);
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);
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);
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);
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);
268 r = MsiSetPropertyA(hinst, "boo", NULL);
269 ok(hinst, !r, "got %u\n", r);
270 check_prop(hinst, "boo", "");
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);
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");
285 static void test_db(MSIHANDLE hinst)
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;
298 hdb = MsiGetActiveDatabase(hinst);
299 ok(hinst, hdb, "MsiGetActiveDatabase failed\n");
301 r = MsiDatabaseIsTablePersistentA(hdb, "Test");
302 ok(hinst, r == MSICONDITION_TRUE, "got %u\n", r);
304 r = MsiDatabaseOpenViewA(hdb, NULL, &view);
305 ok(hinst, r == ERROR_BAD_QUERY_SYNTAX, "got %u\n", r);
307 r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `Test`", NULL);
308 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
310 r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `Test`", &view);
311 ok(hinst, !r, "got %u\n", r);
313 r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec2);
314 ok(hinst, !r, "got %u\n", r);
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);
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");
327 r = MsiDatabaseIsTablePersistentA(hdb2, "Test");
328 ok(hinst, r == MSICONDITION_TRUE, "got %u\n", r);
330 r = MsiCloseHandle(hdb2);
331 ok(hinst, !r, "got %u\n", r);
333 r = MsiCloseHandle(rec2);
334 ok(hinst, !r, "got %u\n", r);
336 r = MsiViewExecute(view, 0);
337 ok(hinst, !r, "got %u\n", r);
339 r = MsiViewFetch(view, &rec2);
340 ok(hinst, !r, "got %u\n", r);
342 r = MsiRecordGetFieldCount(rec2);
343 ok(hinst, r == 3, "got %u\n", r);
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);
351 r = MsiRecordGetInteger(rec2, 2);
352 ok(hinst, r == 1, "got %u\n", r);
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");
359 r = MsiCloseHandle(rec2);
360 ok(hinst, !r, "got %u\n", r);
362 r = MsiViewFetch(view, &rec2);
363 ok(hinst, !r, "got %u\n", r);
365 r = MsiRecordGetFieldCount(rec2);
366 ok(hinst, r == 3, "got %u\n", r);
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);
374 r = MsiRecordGetInteger(rec2, 2);
375 ok(hinst, r == 2, "got %u\n", r);
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");
382 r = MsiViewModify(view, MSIMODIFY_REFRESH, 0);
383 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
385 r = MsiRecordSetStringA(rec2, 1, "three");
386 ok(hinst, !r, "got %u\n", r);
388 r = MsiRecordSetInteger(rec2, 2, 3);
389 ok(hinst, !r, "got %u\n", r);
391 r = MsiRecordSetInteger(rec2, 3, 3);
392 ok(hinst, !r, "got %u\n", r);
394 r = MsiViewModify(view, MSIMODIFY_REFRESH, rec2);
395 ok(hinst, !r, "got %u\n", r);
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);
403 r = MsiRecordGetInteger(rec2, 2);
404 ok(hinst, r == 2, "got %u\n", r);
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");
411 r = MsiCloseHandle(rec2);
412 ok(hinst, !r, "got %u\n", r);
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);
418 r = MsiViewClose(view);
419 ok(hinst, !r, "got %u\n", r);
421 r = MsiCloseHandle(view);
422 ok(hinst, !r, "got %u\n", r);
424 r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `Test` WHERE `Name` = ?", &view);
425 ok(hinst, !r, "got %u\n", r);
427 rec = MsiCreateRecord(1);
428 MsiRecordSetStringA(rec, 1, "one");
430 r = MsiViewExecute(view, rec);
431 ok(hinst, !r, "got %u\n", r);
433 r = MsiViewFetch(view, &rec2);
434 ok(hinst, !r, "got %u\n", r);
436 r = MsiRecordGetInteger(rec2, 2);
437 ok(hinst, r == 1, "got %u\n", r);
439 r = MsiCloseHandle(rec2);
440 ok(hinst, !r, "got %u\n", r);
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);
446 r = MsiCloseHandle(rec);
447 ok(hinst, !r, "got %u\n", r);
449 r = MsiCloseHandle(view);
450 ok(hinst, !r, "got %u\n", r);
452 /* test MsiDatabaseGetPrimaryKeys() */
453 r = MsiDatabaseGetPrimaryKeysA(hdb, "Test", &rec);
454 ok(hinst, !r, "got %u\n", r);
456 r = MsiRecordGetFieldCount(rec);
457 ok(hinst, r == 1, "got %u\n", r);
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);
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);
471 r = MsiCloseHandle(rec);
472 ok(hinst, !r, "got %u\n", r);
474 r = MsiGetSummaryInformationA(hdb, NULL, 1, NULL);
475 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
477 r = MsiGetSummaryInformationA(hdb, NULL, 1, &suminfo);
478 ok(hinst, !r, "got %u\n", r);
480 r = MsiSummaryInfoGetPropertyCount(suminfo, NULL);
481 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
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);
488 r = MsiSummaryInfoGetPropertyA(suminfo, 0, NULL, NULL, NULL, NULL, NULL);
489 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
491 for (i = 0; i < 20; i++)
493 /* for some reason query for PID_TITLE leads to install failure under Windows */
494 if (i == PID_TITLE) continue;
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)
512 ok(hinst, sz == 5, "%u: got %lu\n", i, sz);
513 ok(hinst, !lstrcmpA(buffer, ";1033"), "%u: got %s\n", i, buffer);
515 else if (i == PID_REVNUMBER)
517 ok(hinst, sz == 76, "%u: got %lu\n", i, sz);
518 ok(hinst, !lstrcmpA(buffer, "{004757CA"), "%u: got %s\n", i, buffer);
520 else
522 ok(hinst, sz == sizeof(buffer), "%u: got %lu\n", i, sz);
523 ok(hinst, !*buffer, "%u: got %s\n", i, buffer);
527 GetSystemTimeAsFileTime(&ft);
529 for (i = 0; i < 20; i++)
531 r = MsiSummaryInfoSetPropertyA(suminfo, i, prop_type[i], 1252, &ft, "");
532 ok(hinst, r == ERROR_FUNCTION_FAILED, "%u: got %u\n", i, r);
534 r = MsiSummaryInfoSetPropertyW(suminfo, i, prop_type[i], 1252, &ft, L"");
535 ok(hinst, r == ERROR_FUNCTION_FAILED, "%u: got %u\n", i, r);
538 r = MsiCloseHandle(suminfo);
539 ok(hinst, !r, "got %u\n", r);
541 r = MsiCloseHandle(hdb);
542 ok(hinst, !r, "got %u\n", r);
545 static void test_doaction(MSIHANDLE hinst)
547 UINT r;
549 r = MsiDoActionA(hinst, "nested51");
550 ok(hinst, !r, "got %u\n", r);
551 check_prop(hinst, "nested", "1");
553 r = MsiDoActionA(hinst, "nested1");
554 ok(hinst, !r, "got %u\n", r);
555 check_prop(hinst, "nested", "2");
557 r = MsiSequenceA(hinst, NULL, 0);
558 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
560 r = MsiSequenceA(hinst, "TestSequence", 0);
561 ok(hinst, !r, "got %u\n", r);
562 check_prop(hinst, "nested", "1");
565 UINT WINAPI nested(MSIHANDLE hinst)
567 MsiSetPropertyA(hinst, "nested", "2");
569 return ERROR_SUCCESS;
572 static void test_targetpath(MSIHANDLE hinst)
574 WCHAR bufferW[100];
575 char buffer[100];
576 DWORD sz, srcsz;
577 UINT r;
579 /* test invalid values */
580 r = MsiGetTargetPathA(hinst, NULL, NULL, NULL);
581 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
583 r = MsiGetTargetPathA(hinst, "TARGETDIR", NULL, NULL );
584 ok(hinst, !r, "got %u\n", r);
586 r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, NULL );
587 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
589 /* Returned size is in bytes, not chars, but only for custom actions.
590 * Seems to be a casualty of RPC... */
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
658 r = MsiSetTargetPathA(hinst, NULL, "C:\\subdir");
659 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
661 r = MsiSetTargetPathA(hinst, "MSITESTDIR", NULL);
662 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
664 r = MsiSetTargetPathA(hinst, "MSITESTDIR", "C:\\subdir");
665 ok(hinst, !r, "got %u\n", r);
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);
672 r = MsiSetTargetPathA(hinst, "MSITESTDIR", "C:\\");
674 /* test GetSourcePath() */
676 r = MsiGetSourcePathA(hinst, NULL, NULL, NULL);
677 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
679 r = MsiGetSourcePathA(hinst, "TARGETDIR", NULL, NULL );
680 ok(hinst, !r, "got %u\n", r);
682 r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, NULL );
683 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
685 /* Returned size is in bytes, not chars, but only for custom actions.
686 * Seems to be a casualty of RPC... */
688 srcsz = 0;
689 MsiGetSourcePathW(hinst, L"TARGETDIR", NULL, &srcsz);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
758 static void test_misc(MSIHANDLE hinst)
760 MSICONDITION cond;
761 LANGID lang;
762 UINT r;
764 r = MsiSetMode(hinst, MSIRUNMODE_REBOOTATEND, FALSE);
765 ok(hinst, !r, "got %u\n", r);
767 lang = MsiGetLanguage(hinst);
768 ok(hinst, lang == 1033, "got %u\n", lang);
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);
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);
783 static void test_feature_states(MSIHANDLE hinst)
785 INSTALLSTATE state, action;
786 UINT r;
788 /* test feature states */
790 r = MsiGetFeatureStateA(hinst, NULL, &state, &action);
791 ok(hinst, r == ERROR_UNKNOWN_FEATURE, "got %u\n", r);
793 r = MsiGetFeatureStateA(hinst, "fake", &state, &action);
794 ok(hinst, r == ERROR_UNKNOWN_FEATURE, "got %u\n", r);
796 r = MsiGetFeatureStateA(hinst, "One", NULL, &action);
797 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
799 r = MsiGetFeatureStateA(hinst, "One", &state, NULL);
800 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
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);
807 r = MsiSetFeatureStateA(hinst, NULL, INSTALLSTATE_ABSENT);
808 ok(hinst, r == ERROR_UNKNOWN_FEATURE, "got %u\n", r);
810 r = MsiSetFeatureStateA(hinst, "One", INSTALLSTATE_ADVERTISED);
811 ok(hinst, !r, "got %u\n", r);
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);
817 r = MsiSetFeatureStateA(hinst, "One", INSTALLSTATE_LOCAL);
818 ok(hinst, !r, "got %u\n", r);
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);
824 /* test component states */
826 r = MsiGetComponentStateA(hinst, NULL, &state, &action);
827 ok(hinst, r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r);
829 r = MsiGetComponentStateA(hinst, "fake", &state, &action);
830 ok(hinst, r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r);
832 r = MsiGetComponentStateA(hinst, "One", NULL, &action);
833 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
835 r = MsiGetComponentStateA(hinst, "One", &state, NULL);
836 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
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);
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);
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);
853 r = MsiSetComponentStateA(hinst, NULL, INSTALLSTATE_ABSENT);
854 ok(hinst, r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r);
856 r = MsiSetComponentStateA(hinst, "One", INSTALLSTATE_SOURCE);
857 ok(hinst, !r, "got %u\n", r);
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);
864 r = MsiSetComponentStateA(hinst, "One", INSTALLSTATE_LOCAL);
865 ok(hinst, !r, "got %u\n", r);
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);
873 static void test_format_record(MSIHANDLE hinst)
875 WCHAR bufferW[10];
876 char buffer[10];
877 MSIHANDLE rec;
878 DWORD sz;
879 UINT r;
881 r = MsiFormatRecordA(hinst, 0, NULL, NULL);
882 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
884 rec = MsiCreateRecord(1);
885 MsiRecordSetStringA(rec, 0, "foo [1]");
886 MsiRecordSetInteger(rec, 1, 123);
888 r = MsiFormatRecordA(hinst, rec, NULL, NULL);
889 ok(hinst, !r, "got %u\n", r);
891 r = MsiFormatRecordA(hinst, rec, buffer, NULL);
892 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
894 /* Returned size is in bytes, not chars, but only for custom actions. */
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);
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);
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);
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);
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);
929 r = MsiFormatRecordW(hinst, rec, NULL, NULL);
930 ok(hinst, !r, "got %u\n", r);
932 r = MsiFormatRecordW(hinst, rec, bufferW, NULL);
933 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
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);
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);
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);
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);
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);
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);
977 MsiCloseHandle(rec);
980 static void test_costs(MSIHANDLE hinst)
982 WCHAR bufferW[10];
983 char buffer[10];
984 int cost, temp;
985 DWORD sz;
986 UINT r;
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);
994 r = MsiGetFeatureCostA(hinst, "One", MSICOSTTREE_CHILDREN, INSTALLSTATE_LOCAL, NULL);
995 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1112 static void test_invalid_functions(MSIHANDLE hinst)
1114 char path[MAX_PATH], package_name[20];
1115 MSIHANDLE db, preview, package;
1116 UINT r;
1118 r = MsiGetDatabaseState(hinst);
1119 ok(hinst, r == MSIDBSTATE_ERROR, "got %u\n", r);
1121 db = MsiGetActiveDatabase(hinst);
1122 ok(hinst, db, "MsiGetActiveDatabase failed\n");
1124 r = MsiDatabaseGenerateTransformA(db, db, "bogus.mst", 0, 0);
1125 todo_wine ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1127 r = MsiDatabaseApplyTransformA(db, "bogus.mst", 0);
1128 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1130 r = MsiCreateTransformSummaryInfoA(db, db, "bogus.mst", 0, 0);
1131 todo_wine ok(hinst, r == ERROR_INSTALL_PACKAGE_OPEN_FAILED, "got %u\n", r);
1133 GetCurrentDirectoryA(sizeof(path), path);
1134 r = MsiDatabaseExportA(db, "Test", path, "bogus.idt");
1135 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1137 r = MsiDatabaseImportA(db, path, "bogus.idt");
1138 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1140 r = MsiDatabaseCommit(db);
1141 ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1143 r = MsiDatabaseMergeA(db, db, "MergeErrors");
1144 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1146 r = MsiGetDatabaseState(db);
1147 ok(hinst, r == MSIDBSTATE_ERROR, "got %u\n", r);
1149 r = MsiEnableUIPreview(db, &preview);
1150 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1152 sprintf(package_name, "#%lu", db);
1153 r = MsiOpenPackageA(package_name, &package);
1154 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
1156 MsiCloseHandle(db);
1159 static void test_view_get_error(MSIHANDLE hinst)
1161 MSIHANDLE db, view, rec;
1162 char buffer[5];
1163 MSIDBERROR err;
1164 DWORD sz;
1165 UINT r;
1167 db = MsiGetActiveDatabase(hinst);
1168 ok(hinst, db, "MsiGetActiveDatabase failed\n");
1170 r = MsiDatabaseOpenViewA(db, "SELECT * FROM `test2`", &view);
1171 ok(hinst, !r, "got %u\n", r);
1173 r = MsiViewExecute(view, 0);
1174 ok(hinst, !r, "got %u\n", r);
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);
1181 err = MsiViewGetErrorA(view, NULL, NULL);
1182 ok(hinst, err == MSIDBERROR_INVALIDARG, "got %d\n", err);
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);
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);
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);
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);
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);
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);
1223 r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
1224 ok(hinst, r == ERROR_INVALID_DATA, "got %u\n", r);
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);
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);
1240 r = MsiViewModify(view, MSIMODIFY_VALIDATE_NEW, rec);
1241 ok(hinst, r == ERROR_INVALID_DATA, "got %u\n", r);
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);
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);
1257 MsiCloseHandle(rec);
1258 MsiCloseHandle(view);
1259 MsiCloseHandle(db);
1262 /* Main test. Anything that doesn't depend on a specific install configuration
1263 * or have undesired side effects should go here. */
1264 UINT WINAPI main_test(MSIHANDLE hinst)
1266 IUnknown *unk = NULL;
1267 HRESULT hr;
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);
1273 if (unk) IUnknown_Release(unk);
1275 /* but ours is uninitialized */
1276 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1277 ok(hinst, hr == S_OK, "got %#lx\n", hr);
1278 CoUninitialize();
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);
1291 return ERROR_SUCCESS;
1294 UINT WINAPI test_retval(MSIHANDLE hinst)
1296 char prop[10];
1297 DWORD len = sizeof(prop);
1298 UINT retval;
1300 MsiGetPropertyA(hinst, "TEST_RETVAL", prop, &len);
1301 sscanf(prop, "%u", &retval);
1302 return retval;
1305 static void append_file(MSIHANDLE hinst, const char *filename, const char *text)
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());
1311 SetFilePointer(file, 0, NULL, FILE_END);
1312 WriteFile(file, text, strlen(text), &size, NULL);
1313 CloseHandle(file);
1316 UINT WINAPI da_immediate(MSIHANDLE hinst)
1318 char prop[300];
1319 DWORD len = sizeof(prop);
1321 MsiGetPropertyA(hinst, "TESTPATH", prop, &len);
1323 append_file(hinst, prop, "one");
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");
1329 return ERROR_SUCCESS;
1332 UINT WINAPI da_deferred(MSIHANDLE hinst)
1334 char prop[300];
1335 DWORD len = sizeof(prop);
1336 LANGID lang;
1337 UINT r;
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");
1344 append_file(hinst, prop, "two");
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);
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);
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);
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");
1368 lang = MsiGetLanguage(hinst);
1369 ok(hinst, lang != ERROR_INVALID_HANDLE, "MsiGetLanguage failed\n");
1371 return ERROR_SUCCESS;
1374 static int global_state;
1376 UINT WINAPI process1(MSIHANDLE hinst)
1378 SetEnvironmentVariableA("MSI_PROCESS_TEST","1");
1379 global_state++;
1380 return ERROR_SUCCESS;
1383 UINT WINAPI process2(MSIHANDLE hinst)
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;
1393 UINT WINAPI async1(MSIHANDLE hinst)
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;
1403 UINT WINAPI async2(MSIHANDLE hinst)
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;
1414 static BOOL pf_exists(const char *file)
1416 char path[MAX_PATH];
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;
1425 UINT WINAPI cf_present(MSIHANDLE hinst)
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;
1433 UINT WINAPI cf_absent(MSIHANDLE hinst)
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;
1441 UINT WINAPI file_present(MSIHANDLE hinst)
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;
1448 UINT WINAPI file_absent(MSIHANDLE hinst)
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;
1455 UINT WINAPI crs_present(MSIHANDLE hinst)
1457 ok(hinst, pf_exists("msitest\\shortcut.lnk"), "shortcut absent\n");
1458 return ERROR_SUCCESS;
1461 UINT WINAPI crs_absent(MSIHANDLE hinst)
1463 ok(hinst, !pf_exists("msitest\\shortcut.lnk"), "shortcut present\n");
1464 return ERROR_SUCCESS;
1467 UINT WINAPI sds_present(MSIHANDLE hinst)
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;
1478 UINT WINAPI sds_absent(MSIHANDLE hinst)
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;
1489 UINT WINAPI sis_present(MSIHANDLE hinst)
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;
1500 UINT WINAPI sis_absent(MSIHANDLE hinst)
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;
1511 UINT WINAPI sss_started(MSIHANDLE hinst)
1513 SC_HANDLE manager, service;
1514 SERVICE_STATUS status;
1515 BOOL ret;
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);
1523 CloseServiceHandle(service);
1524 CloseServiceHandle(manager);
1525 return ERROR_SUCCESS;
1528 UINT WINAPI sss_stopped(MSIHANDLE hinst)
1530 SC_HANDLE manager, service;
1531 SERVICE_STATUS status;
1532 BOOL ret;
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);
1540 CloseServiceHandle(service);
1541 CloseServiceHandle(manager);
1542 return ERROR_SUCCESS;
1545 UINT WINAPI rd_present(MSIHANDLE hinst)
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;
1554 UINT WINAPI rd_absent(MSIHANDLE hinst)
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;
1563 UINT WINAPI odbc_present(MSIHANDLE hinst)
1565 int gotdriver = 0, gotdriver2 = 0;
1566 char buffer[1000], *p;
1567 WORD len;
1568 BOOL r;
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)
1576 if (!strcmp(p, "ODBC test driver"))
1577 gotdriver = 1;
1578 if (!strcmp(p, "ODBC test driver2"))
1579 gotdriver2 = 1;
1581 ok(hinst, gotdriver, "driver absent\n");
1582 ok(hinst, gotdriver2, "driver 2 absent\n");
1583 return ERROR_SUCCESS;
1586 UINT WINAPI odbc_absent(MSIHANDLE hinst)
1588 int gotdriver = 0, gotdriver2 = 0;
1589 char buffer[1000], *p;
1590 WORD len;
1591 BOOL r;
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)
1599 if (!strcmp(p, "ODBC test driver"))
1600 gotdriver = 1;
1601 if (!strcmp(p, "ODBC test driver2"))
1602 gotdriver2 = 1;
1604 ok(hinst, !gotdriver, "driver present\n");
1605 ok(hinst, !gotdriver2, "driver 2 present\n");
1606 return ERROR_SUCCESS;
1609 UINT WINAPI mov_present(MSIHANDLE hinst)
1611 ok(hinst, pf_exists("msitest\\canada"), "file absent\n");
1612 ok(hinst, pf_exists("msitest\\dominica"), "file absent\n");
1613 return ERROR_SUCCESS;
1616 UINT WINAPI mov_absent(MSIHANDLE hinst)
1618 ok(hinst, !pf_exists("msitest\\canada"), "file present\n");
1619 ok(hinst, !pf_exists("msitest\\dominica"), "file present\n");
1620 return ERROR_SUCCESS;
1623 static void check_reg_str(MSIHANDLE hinst, HKEY key, const char *name, const char *expect)
1625 char value[300];
1626 DWORD sz;
1627 LONG res;
1629 sz = sizeof(value);
1630 res = RegQueryValueExA(key, name, NULL, NULL, (BYTE *)value, &sz);
1631 if (expect)
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);
1637 else
1638 ok(hinst, res == ERROR_FILE_NOT_FOUND, "\"%s\": expected missing, got %ld\n",
1639 name, res);
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\"";
1646 UINT WINAPI pa_present(MSIHANDLE hinst)
1648 HKEY key;
1649 LONG res;
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);
1656 return ERROR_SUCCESS;
1659 UINT WINAPI pa_absent(MSIHANDLE hinst)
1661 HKEY key;
1662 LONG res;
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)
1668 check_reg_str(hinst, key, name_dotnet, NULL);
1669 RegCloseKey(key);
1671 return ERROR_SUCCESS;
1674 static const char ppc_key[] = "Software\\Microsoft\\Windows\\CurrentVersion\\"
1675 "Installer\\UserData\\S-1-5-18\\Components\\CBABC2FDCCB35E749A8944D8C1C098B5";
1677 UINT WINAPI ppc_present(MSIHANDLE hinst)
1679 char expect[MAX_PATH];
1680 HKEY key;
1681 UINT r;
1683 r = RegOpenKeyExA(HKEY_LOCAL_MACHINE, ppc_key, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &key);
1684 ok(hinst, !r, "got %u\n", r);
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);
1691 RegCloseKey(key);
1692 return ERROR_SUCCESS;
1695 UINT WINAPI ppc_absent(MSIHANDLE hinst)
1697 HKEY key;
1698 UINT r;
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;
1705 static const char pub_key[] = "Software\\Microsoft\\Installer\\Components\\0CBCFA296AC907244845745CEEB2F8AA";
1707 UINT WINAPI pub_present(MSIHANDLE hinst)
1709 HKEY key;
1710 LONG res;
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;
1720 UINT WINAPI pub_absent(MSIHANDLE hinst)
1722 HKEY key;
1723 LONG res;
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;
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";
1734 UINT WINAPI pf_present(MSIHANDLE hinst)
1736 HKEY key;
1737 LONG res;
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);
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);
1751 return ERROR_SUCCESS;
1754 UINT WINAPI pf_absent(MSIHANDLE hinst)
1756 HKEY key;
1757 LONG res;
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);
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);
1765 return ERROR_SUCCESS;
1768 static const char pp_prodkey[] = "Installer\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB";
1770 UINT WINAPI pp_present(MSIHANDLE hinst)
1772 HKEY key;
1773 LONG res;
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", ":");
1781 RegCloseKey(key);
1782 return ERROR_SUCCESS;
1785 UINT WINAPI pp_absent(MSIHANDLE hinst)
1787 HKEY key;
1788 LONG res;
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);
1793 return ERROR_SUCCESS;
1796 UINT WINAPI rci_present(MSIHANDLE hinst)
1798 HKEY key;
1799 LONG res;
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);
1806 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "FileType\\{110913E7-86D1-4BF3-9922-BA103FCDDDFA}", &key);
1807 ok(hinst, !res, "got %ld\n", res);
1808 RegCloseKey(key);
1810 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "AppID\\{CFCC3B38-E683-497D-9AB4-CB40AAFE307F}", &key);
1811 ok(hinst, !res, "got %ld\n", res);
1812 RegCloseKey(key);
1814 return ERROR_SUCCESS;
1817 UINT WINAPI rci_absent(MSIHANDLE hinst)
1819 HKEY key;
1820 LONG res;
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);
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);
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);
1832 return ERROR_SUCCESS;
1835 UINT WINAPI rei_present(MSIHANDLE hinst)
1837 HKEY key;
1838 LONG res;
1840 res = RegOpenKeyA(HKEY_CLASSES_ROOT, ".extension", &key);
1841 ok(hinst, !res, "got %ld\n", res);
1842 RegCloseKey(key);
1844 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Prog.Id.1\\shell\\Open\\command", &key);
1845 ok(hinst, !res, "got %ld\n", res);
1846 RegCloseKey(key);
1848 return ERROR_SUCCESS;
1851 UINT WINAPI rei_absent(MSIHANDLE hinst)
1853 HKEY key;
1854 LONG res;
1856 res = RegOpenKeyA(HKEY_CLASSES_ROOT, ".extension", &key);
1857 ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
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);
1862 return ERROR_SUCCESS;
1865 static const char font_key[] = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
1867 UINT WINAPI font_present(MSIHANDLE hinst)
1869 HKEY key;
1870 LONG res;
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);
1878 return ERROR_SUCCESS;
1881 UINT WINAPI font_absent(MSIHANDLE hinst)
1883 HKEY key;
1884 LONG res;
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);
1891 return ERROR_SUCCESS;
1894 UINT WINAPI rmi_present(MSIHANDLE hinst)
1896 HKEY key;
1897 LONG res;
1899 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "MIME\\Database\\Content Type\\mime/type", &key);
1900 ok(hinst, !res, "got %ld\n", res);
1902 return ERROR_SUCCESS;
1905 UINT WINAPI rmi_absent(MSIHANDLE hinst)
1907 HKEY key;
1908 LONG res;
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);
1913 return ERROR_SUCCESS;
1916 static const char rp_key[] = "Software\\Microsoft\\Windows\\CurrentVersion\\"
1917 "Uninstall\\{7DF88A48-996F-4EC8-A022-BF956F9B2CBB}";
1919 UINT WINAPI rp_present(MSIHANDLE hinst)
1921 HKEY key;
1922 LONG res;
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);
1929 return ERROR_SUCCESS;
1932 UINT WINAPI rp_absent(MSIHANDLE hinst)
1934 HKEY key;
1935 LONG res;
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);
1940 return ERROR_SUCCESS;
1943 UINT WINAPI rpi_present(MSIHANDLE hinst)
1945 HKEY key;
1946 LONG res;
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);
1953 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.1", &key);
1954 ok(hinst, !res, "got %ld\n", res);
1955 RegCloseKey(key);
1957 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class", &key);
1958 ok(hinst, !res, "got %ld\n", res);
1959 RegCloseKey(key);
1961 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.2", &key);
1962 ok(hinst, !res, "got %ld\n", res);
1963 RegCloseKey(key);
1965 return ERROR_SUCCESS;
1968 UINT WINAPI rpi_absent(MSIHANDLE hinst)
1970 HKEY key;
1971 LONG res;
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);
1977 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.1", &key);
1978 ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1980 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class", &key);
1981 ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1983 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "Winetest.Class.2", &key);
1984 ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
1986 return ERROR_SUCCESS;
1989 static const CHAR ru_key[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Installer"
1990 "\\UserData\\S-1-5-18\\Products\\84A88FD7F6998CE40A22FB59F6B9C2BB\\InstallProperties";
1992 UINT WINAPI ru_present(MSIHANDLE hinst)
1994 HKEY key;
1995 LONG res;
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);
2002 return ERROR_SUCCESS;
2005 UINT WINAPI ru_absent(MSIHANDLE hinst)
2007 HKEY key;
2008 LONG res;
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);
2013 return ERROR_SUCCESS;
2016 static const GUID LIBID_register_test =
2017 {0xeac5166a, 0x9734, 0x4d91, {0x87,0x8f, 0x1d,0xd0,0x23,0x04,0xc6,0x6c}};
2019 UINT WINAPI tl_present(MSIHANDLE hinst)
2021 ITypeLib *tlb;
2022 HRESULT hr;
2024 hr = LoadRegTypeLib(&LIBID_register_test, 7, 1, 0, &tlb);
2025 ok(hinst, hr == S_OK, "got %#lx\n", hr);
2026 ITypeLib_Release(tlb);
2028 return ERROR_SUCCESS;
2031 UINT WINAPI tl_absent(MSIHANDLE hinst)
2033 ITypeLib *tlb;
2034 HRESULT hr;
2036 hr = LoadRegTypeLib(&LIBID_register_test, 7, 1, 0, &tlb);
2037 ok(hinst, hr == TYPE_E_LIBNOTREGISTERED, "got %#lx\n", hr);
2039 return ERROR_SUCCESS;
2042 UINT WINAPI sr_present(MSIHANDLE hinst)
2044 HKEY key;
2045 LONG res;
2047 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "selfreg_test", &key);
2048 ok(hinst, !res, "got %ld\n", res);
2049 RegCloseKey(key);
2051 return ERROR_SUCCESS;
2054 UINT WINAPI sr_absent(MSIHANDLE hinst)
2056 HKEY key;
2057 LONG res;
2059 res = RegOpenKeyA(HKEY_CLASSES_ROOT, "selfreg_test", &key);
2060 ok(hinst, res == ERROR_FILE_NOT_FOUND, "got %ld\n", res);
2062 return ERROR_SUCCESS;
2065 UINT WINAPI env_present(MSIHANDLE hinst)
2067 HKEY key;
2068 LONG res;
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);
2076 return ERROR_SUCCESS;
2079 UINT WINAPI env_absent(MSIHANDLE hinst)
2081 HKEY key;
2082 LONG res;
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);
2090 return ERROR_SUCCESS;
2093 UINT WINAPI ini_present(MSIHANDLE hinst)
2095 char path[MAX_PATH], buf[10];
2096 DWORD len;
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");
2102 len = GetPrivateProfileStringA("section1", "key1", NULL, buf, sizeof(buf), path);
2103 ok(hinst, len == 6, "got %lu\n", len);
2105 return ERROR_SUCCESS;
2108 UINT WINAPI ini_absent(MSIHANDLE hinst)
2110 char path[MAX_PATH], buf[10];
2111 DWORD len;
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");
2117 len = GetPrivateProfileStringA("section1", "key1", NULL, buf, sizeof(buf), path);
2118 ok(hinst, !len, "got %lu\n", len);
2120 return ERROR_SUCCESS;
2123 UINT WINAPI wrv_present(MSIHANDLE hinst)
2125 HKEY key;
2126 LONG res;
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);
2133 return ERROR_SUCCESS;
2136 UINT WINAPI wrv_absent(MSIHANDLE hinst)
2138 HKEY key;
2139 LONG res;
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);
2146 return ERROR_SUCCESS;