msi/tests: Test deferral of CreateShorcuts and RemoveShortcuts.
[wine.git] / dlls / msi / tests / custom.c
blobdb6d61239ec0218f8c3527258176afa61e6e6f01
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 #include <stdarg.h>
22 #include <stdio.h>
24 #include <windef.h>
25 #include <winbase.h>
26 #define COBJMACROS
27 #include <shlobj.h>
28 #include <msxml.h>
29 #include <msi.h>
30 #include <msiquery.h>
32 static int todo_level, todo_do_loop;
34 static void ok_(MSIHANDLE hinst, int todo, const char *file, int line, int condition, const char *msg, ...)
36 static char buffer[2000];
37 MSIHANDLE record;
38 va_list valist;
40 va_start(valist, msg);
41 vsprintf(buffer, msg, valist);
42 va_end(valist);
44 record = MsiCreateRecord(5);
45 MsiRecordSetInteger(record, 1, todo);
46 MsiRecordSetStringA(record, 2, file);
47 MsiRecordSetInteger(record, 3, line);
48 MsiRecordSetInteger(record, 4, condition);
49 MsiRecordSetStringA(record, 5, buffer);
50 MsiProcessMessage(hinst, INSTALLMESSAGE_USER, record);
51 MsiCloseHandle(record);
54 static void winetest_start_todo( int is_todo )
56 todo_level = (todo_level << 1) | (is_todo != 0);
57 todo_do_loop=1;
60 static int winetest_loop_todo(void)
62 int do_loop=todo_do_loop;
63 todo_do_loop=0;
64 return do_loop;
67 static void winetest_end_todo(void)
69 todo_level >>= 1;
72 #define ok(hinst, condition, ...) ok_(hinst, todo_level, __FILE__, __LINE__, condition, __VA_ARGS__)
73 #define todo_wine_if(is_todo) for (winetest_start_todo(is_todo); \
74 winetest_loop_todo(); \
75 winetest_end_todo())
76 #define todo_wine todo_wine_if(1)
78 static const char *dbgstr_w(WCHAR *str)
80 static char buffer[300], *p;
82 if (!str) return "(null)";
84 p = buffer;
85 *p++ = 'L';
86 *p++ = '"';
87 while ((*p++ = *str++));
88 *p++ = '"';
89 *p++ = 0;
91 return buffer;
94 static void check_prop(MSIHANDLE hinst, const char *prop, const char *expect)
96 char buffer[10] = "x";
97 DWORD sz = sizeof(buffer);
98 UINT r = MsiGetPropertyA(hinst, prop, buffer, &sz);
99 ok(hinst, !r, "'%s': got %u\n", prop, r);
100 ok(hinst, sz == strlen(buffer), "'%s': expected %u, got %u\n", prop, strlen(buffer), sz);
101 ok(hinst, !strcmp(buffer, expect), "expected '%s', got '%s'\n", expect, buffer);
104 static void test_props(MSIHANDLE hinst)
106 static const WCHAR booW[] = {'b','o','o',0};
107 static const WCHAR xyzW[] = {'x','y','z',0};
108 static const WCHAR xyW[] = {'x','y',0};
109 char buffer[10];
110 WCHAR bufferW[10];
111 DWORD sz;
112 UINT r;
114 /* test invalid values */
115 r = MsiGetPropertyA(hinst, NULL, NULL, NULL);
116 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
118 r = MsiGetPropertyA(hinst, "boo", NULL, NULL);
119 ok(hinst, !r, "got %u\n", r);
121 r = MsiGetPropertyA(hinst, "boo", buffer, NULL );
122 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
124 sz = 0;
125 r = MsiGetPropertyA(hinst, "boo", NULL, &sz);
126 ok(hinst, !r, "got %u\n", r);
127 ok(hinst, sz == 0, "got size %u\n", sz);
129 sz = 0;
130 strcpy(buffer,"x");
131 r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
132 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
133 ok(hinst, !strcmp(buffer, "x"), "got \"%s\"\n", buffer);
134 ok(hinst, sz == 0, "got size %u\n", sz);
136 sz = 1;
137 strcpy(buffer,"x");
138 r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
139 ok(hinst, !r, "got %u\n", r);
140 ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
141 ok(hinst, sz == 0, "got size %u\n", sz);
143 /* set the property to something */
144 r = MsiSetPropertyA(hinst, NULL, NULL);
145 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
147 r = MsiSetPropertyA(hinst, "", NULL);
148 ok(hinst, !r, "got %u\n", r);
150 r = MsiSetPropertyA(hinst, "", "asdf");
151 ok(hinst, r == ERROR_FUNCTION_FAILED, "got %u\n", r);
153 r = MsiSetPropertyA(hinst, "=", "asdf");
154 ok(hinst, !r, "got %u\n", r);
155 check_prop(hinst, "=", "asdf");
157 r = MsiSetPropertyA(hinst, " ", "asdf");
158 ok(hinst, !r, "got %u\n", r);
159 check_prop(hinst, " ", "asdf");
161 r = MsiSetPropertyA(hinst, "'", "asdf");
162 ok(hinst, !r, "got %u\n", r);
163 check_prop(hinst, "'", "asdf");
165 r = MsiSetPropertyA(hinst, "boo", NULL);
166 ok(hinst, !r, "got %u\n", r);
167 check_prop(hinst, "boo", "");
169 r = MsiSetPropertyA(hinst, "boo", "");
170 ok(hinst, !r, "got %u\n", r);
171 check_prop(hinst, "boo", "");
173 r = MsiSetPropertyA(hinst, "boo", "xyz");
174 ok(hinst, !r, "got %u\n", r);
175 check_prop(hinst, "boo", "xyz");
177 r = MsiGetPropertyA(hinst, "boo", NULL, NULL);
178 ok(hinst, !r, "got %u\n", r);
180 r = MsiGetPropertyA(hinst, "boo", buffer, NULL );
181 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
183 /* Returned size is in bytes, not chars, but only for custom actions.
184 * Seems to be a casualty of RPC... */
186 sz = 0;
187 r = MsiGetPropertyA(hinst, "boo", NULL, &sz);
188 ok(hinst, !r, "got %u\n", r);
189 ok(hinst, sz == 6, "got size %u\n", sz);
191 sz = 0;
192 strcpy(buffer,"q");
193 r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
194 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
195 ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
196 ok(hinst, sz == 6, "got size %u\n", sz);
198 sz = 1;
199 strcpy(buffer,"x");
200 r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
201 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
202 ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
203 ok(hinst, sz == 6, "got size %u\n", sz);
205 sz = 3;
206 strcpy(buffer,"x");
207 r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
208 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
209 ok(hinst, !strcmp(buffer, "xy"), "got \"%s\"\n", buffer);
210 ok(hinst, sz == 6, "got size %u\n", sz);
212 sz = 4;
213 strcpy(buffer,"x");
214 r = MsiGetPropertyA(hinst, "boo", buffer, &sz);
215 ok(hinst, !r, "got %u\n", r);
216 ok(hinst, !strcmp(buffer, "xyz"), "got \"%s\"\n", buffer);
217 ok(hinst, sz == 3, "got size %u\n", sz);
219 r = MsiGetPropertyW(hinst, booW, NULL, NULL);
220 ok(hinst, !r, "got %u\n", r);
222 r = MsiGetPropertyW(hinst, booW, bufferW, NULL );
223 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
225 sz = 0;
226 r = MsiGetPropertyW(hinst, booW, NULL, &sz);
227 ok(hinst, !r, "got %u\n", r);
228 ok(hinst, sz == 3, "got size %u\n", sz);
230 sz = 0;
231 lstrcpyW(bufferW, booW);
232 r = MsiGetPropertyW(hinst, booW, bufferW, &sz);
233 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
234 ok(hinst, !lstrcmpW(bufferW, booW), "got %s\n", dbgstr_w(bufferW));
235 ok(hinst, sz == 3, "got size %u\n", sz);
237 sz = 1;
238 lstrcpyW(bufferW, booW);
239 r = MsiGetPropertyW(hinst, booW, bufferW, &sz);
240 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
241 ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
242 ok(hinst, sz == 3, "got size %u\n", sz);
244 sz = 3;
245 lstrcpyW(bufferW, booW);
246 r = MsiGetPropertyW(hinst, booW, bufferW, &sz);
247 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
248 ok(hinst, !lstrcmpW(bufferW, xyW), "got %s\n", dbgstr_w(bufferW));
249 ok(hinst, sz == 3, "got size %u\n", sz);
251 sz = 4;
252 lstrcpyW(bufferW, booW);
253 r = MsiGetPropertyW(hinst, booW, bufferW, &sz);
254 ok(hinst, !r, "got %u\n", r);
255 ok(hinst, !lstrcmpW(bufferW, xyzW), "got %s\n", dbgstr_w(bufferW));
256 ok(hinst, sz == 3, "got size %u\n", sz);
258 r = MsiSetPropertyA(hinst, "boo", NULL);
259 ok(hinst, !r, "got %u\n", r);
260 check_prop(hinst, "boo", "");
262 sz = 0;
263 r = MsiGetPropertyA(hinst, "embednullprop", NULL, &sz);
264 ok(hinst, !r, "got %u\n", r);
265 ok(hinst, sz == 6, "got size %u\n", sz);
267 sz = 4;
268 memset(buffer, 0xcc, sizeof(buffer));
269 r = MsiGetPropertyA(hinst, "embednullprop", buffer, &sz);
270 ok(hinst, !r, "got %u\n", r);
271 ok(hinst, sz == 3, "got size %u\n", sz);
272 ok(hinst, !memcmp(buffer, "a\0\0\0\xcc", 5), "wrong data\n");
275 static void test_db(MSIHANDLE hinst)
277 MSIHANDLE hdb, view, rec, rec2, suminfo;
278 char buffer[10];
279 DWORD sz;
280 UINT r;
282 hdb = MsiGetActiveDatabase(hinst);
283 ok(hinst, hdb, "MsiGetActiveDatabase failed\n");
285 r = MsiDatabaseIsTablePersistentA(hdb, "Test");
286 ok(hinst, r == MSICONDITION_TRUE, "got %u\n", r);
288 r = MsiDatabaseOpenViewA(hdb, NULL, &view);
289 ok(hinst, r == ERROR_BAD_QUERY_SYNTAX, "got %u\n", r);
291 r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `Test`", NULL);
292 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
294 r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `Test`", &view);
295 ok(hinst, !r, "got %u\n", r);
297 r = MsiViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec2);
298 ok(hinst, !r, "got %u\n", r);
300 sz = sizeof(buffer);
301 r = MsiRecordGetStringA(rec2, 1, buffer, &sz);
302 ok(hinst, !r, "got %u\n", r);
303 ok(hinst, sz == strlen(buffer), "got size %u\n", sz);
304 ok(hinst, !strcmp(buffer, "Name"), "got '%s'\n", buffer);
306 r = MsiCloseHandle(rec2);
307 ok(hinst, !r, "got %u\n", r);
309 r = MsiViewExecute(view, 0);
310 ok(hinst, !r, "got %u\n", r);
312 r = MsiViewFetch(view, &rec2);
313 ok(hinst, !r, "got %u\n", r);
315 r = MsiRecordGetFieldCount(rec2);
316 ok(hinst, r == 3, "got %u\n", r);
318 sz = sizeof(buffer);
319 r = MsiRecordGetStringA(rec2, 1, buffer, &sz);
320 ok(hinst, !r, "got %u\n", r);
321 ok(hinst, sz == strlen(buffer), "got size %u\n", sz);
322 ok(hinst, !strcmp(buffer, "one"), "got '%s'\n", buffer);
324 r = MsiRecordGetInteger(rec2, 2);
325 ok(hinst, r == 1, "got %d\n", r);
327 sz = sizeof(buffer);
328 r = MsiRecordReadStream(rec2, 3, buffer, &sz);
329 ok(hinst, !r, "got %u\n", r);
330 ok(hinst, !memcmp(buffer, "unus", 4), "wrong data\n");
332 r = MsiCloseHandle(rec2);
333 ok(hinst, !r, "got %u\n", r);
335 r = MsiViewFetch(view, &rec2);
336 ok(hinst, !r, "got %u\n", r);
338 r = MsiRecordGetFieldCount(rec2);
339 ok(hinst, r == 3, "got %u\n", r);
341 sz = sizeof(buffer);
342 r = MsiRecordGetStringA(rec2, 1, buffer, &sz);
343 ok(hinst, !r, "got %u\n", r);
344 ok(hinst, sz == strlen(buffer), "got size %u\n", sz);
345 ok(hinst, !strcmp(buffer, "two"), "got '%s'\n", buffer);
347 r = MsiRecordGetInteger(rec2, 2);
348 ok(hinst, r == 2, "got %d\n", r);
350 sz = sizeof(buffer);
351 r = MsiRecordReadStream(rec2, 3, buffer, &sz);
352 ok(hinst, !r, "got %u\n", r);
353 ok(hinst, !memcmp(buffer, "duo", 3), "wrong data\n");
355 r = MsiViewModify(view, MSIMODIFY_REFRESH, 0);
356 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
358 r = MsiRecordSetStringA(rec2, 1, "three");
359 ok(hinst, !r, "got %u\n", r);
361 r = MsiRecordSetInteger(rec2, 2, 3);
362 ok(hinst, !r, "got %u\n", r);
364 r = MsiRecordSetInteger(rec2, 3, 3);
365 ok(hinst, !r, "got %u\n", r);
367 r = MsiViewModify(view, MSIMODIFY_REFRESH, rec2);
368 ok(hinst, !r, "got %d\n", r);
370 sz = sizeof(buffer);
371 r = MsiRecordGetStringA(rec2, 1, buffer, &sz);
372 ok(hinst, !r, "got %u\n", r);
373 ok(hinst, sz == strlen(buffer), "got size %u\n", sz);
374 ok(hinst, !strcmp(buffer, "two"), "got '%s'\n", buffer);
376 r = MsiRecordGetInteger(rec2, 2);
377 ok(hinst, r == 2, "got %d\n", r);
379 sz = sizeof(buffer);
380 r = MsiRecordReadStream(rec2, 3, buffer, &sz);
381 ok(hinst, !r, "got %u\n", r);
382 ok(hinst, !memcmp(buffer, "duo", 3), "wrong data\n");
384 r = MsiCloseHandle(rec2);
385 ok(hinst, !r, "got %u\n", r);
387 r = MsiViewFetch(view, &rec2);
388 ok(hinst, r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
389 ok(hinst, !rec2, "got %u\n", rec2);
391 r = MsiViewClose(view);
392 ok(hinst, !r, "got %u\n", r);
394 r = MsiCloseHandle(view);
395 ok(hinst, !r, "got %u\n", r);
397 r = MsiDatabaseOpenViewA(hdb, "SELECT * FROM `Test` WHERE `Name` = ?", &view);
398 ok(hinst, !r, "got %u\n", r);
400 rec = MsiCreateRecord(1);
401 MsiRecordSetStringA(rec, 1, "one");
403 r = MsiViewExecute(view, rec);
404 ok(hinst, !r, "got %u\n", r);
406 r = MsiViewFetch(view, &rec2);
407 ok(hinst, !r, "got %u\n", r);
409 r = MsiRecordGetInteger(rec2, 2);
410 ok(hinst, r == 1, "got %d\n", r);
412 r = MsiCloseHandle(rec2);
413 ok(hinst, !r, "got %u\n", r);
415 r = MsiViewFetch(view, &rec2);
416 ok(hinst, r == ERROR_NO_MORE_ITEMS, "got %u\n", r);
417 ok(hinst, !rec2, "got %u\n", rec2);
419 r = MsiCloseHandle(rec);
420 ok(hinst, !r, "got %u\n", r);
422 r = MsiCloseHandle(view);
423 ok(hinst, !r, "got %u\n", r);
425 /* test MsiDatabaseGetPrimaryKeys() */
426 r = MsiDatabaseGetPrimaryKeysA(hdb, "Test", &rec);
427 ok(hinst, !r, "got %u\n", r);
429 r = MsiRecordGetFieldCount(rec);
430 ok(hinst, r == 1, "got %d\n", r);
432 sz = sizeof(buffer);
433 r = MsiRecordGetStringA(rec, 0, buffer, &sz);
434 ok(hinst, !r, "got %u\n", r);
435 ok(hinst, sz == strlen(buffer), "got size %u\n", sz);
436 ok(hinst, !strcmp(buffer, "Test"), "got '%s'\n", buffer);
438 sz = sizeof(buffer);
439 r = MsiRecordGetStringA(rec, 1, buffer, &sz);
440 ok(hinst, !r, "got %u\n", r);
441 ok(hinst, sz == strlen(buffer), "got size %u\n", sz);
442 ok(hinst, !strcmp(buffer, "Name"), "got '%s'\n", buffer);
444 r = MsiCloseHandle(rec);
445 ok(hinst, !r, "got %u\n", r);
447 r = MsiGetSummaryInformationA(hdb, NULL, 1, NULL);
448 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
450 r = MsiGetSummaryInformationA(hdb, NULL, 1, &suminfo);
451 ok(hinst, !r, "got %u\n", r);
453 r = MsiCloseHandle(suminfo);
454 ok(hinst, !r, "got %u\n", r);
456 r = MsiCloseHandle(hdb);
457 ok(hinst, !r, "got %u\n", r);
460 static void test_doaction(MSIHANDLE hinst)
462 UINT r;
464 r = MsiDoActionA(hinst, "nested51");
465 ok(hinst, !r, "got %u\n", r);
466 check_prop(hinst, "nested", "1");
468 r = MsiDoActionA(hinst, "nested1");
469 ok(hinst, !r, "got %u\n", r);
470 check_prop(hinst, "nested", "2");
472 r = MsiSequenceA(hinst, NULL, 0);
473 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
475 r = MsiSequenceA(hinst, "TestSequence", 0);
476 ok(hinst, !r, "got %u\n", r);
477 check_prop(hinst, "nested", "1");
480 UINT WINAPI nested(MSIHANDLE hinst)
482 MsiSetPropertyA(hinst, "nested", "2");
484 return ERROR_SUCCESS;
487 static void test_targetpath(MSIHANDLE hinst)
489 static const WCHAR targetdirW[] = {'T','A','R','G','E','T','D','I','R',0};
490 static const WCHAR xyzW[] = {'C',':','\\',0};
491 static const WCHAR xyW[] = {'C',':',0};
492 WCHAR bufferW[100];
493 char buffer[100];
494 DWORD sz, srcsz;
495 UINT r;
497 /* test invalid values */
498 r = MsiGetTargetPathA(hinst, NULL, NULL, NULL);
499 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
501 r = MsiGetTargetPathA(hinst, "TARGETDIR", NULL, NULL );
502 ok(hinst, !r, "got %u\n", r);
504 r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, NULL );
505 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
507 /* Returned size is in bytes, not chars, but only for custom actions.
508 * Seems to be a casualty of RPC... */
510 sz = 0;
511 r = MsiGetTargetPathA(hinst, "TARGETDIR", NULL, &sz);
512 ok(hinst, !r, "got %u\n", r);
513 ok(hinst, sz == 6, "got size %u\n", sz);
515 sz = 0;
516 strcpy(buffer,"q");
517 r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, &sz);
518 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
519 ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
520 ok(hinst, sz == 6, "got size %u\n", sz);
522 sz = 1;
523 strcpy(buffer,"x");
524 r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, &sz);
525 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
526 ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
527 ok(hinst, sz == 6, "got size %u\n", sz);
529 sz = 3;
530 strcpy(buffer,"x");
531 r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, &sz);
532 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
533 ok(hinst, !strcmp(buffer, "C:"), "got \"%s\"\n", buffer);
534 ok(hinst, sz == 6, "got size %u\n", sz);
536 sz = 4;
537 strcpy(buffer,"x");
538 r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, &sz);
539 ok(hinst, !r, "got %u\n", r);
540 ok(hinst, !strcmp(buffer, "C:\\"), "got \"%s\"\n", buffer);
541 ok(hinst, sz == 3, "got size %u\n", sz);
543 sz = 0;
544 r = MsiGetTargetPathW(hinst, targetdirW, NULL, &sz);
545 ok(hinst, !r, "got %u\n", r);
546 ok(hinst, sz == 3, "got size %u\n", sz);
548 sz = 0;
549 bufferW[0] = 'q';
550 r = MsiGetTargetPathW(hinst, targetdirW, bufferW, &sz);
551 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
552 ok(hinst, bufferW[0] == 'q', "got %s\n", dbgstr_w(bufferW));
553 ok(hinst, sz == 3, "got size %u\n", sz);
555 sz = 1;
556 bufferW[0] = 'q';
557 r = MsiGetTargetPathW(hinst, targetdirW, bufferW, &sz);
558 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
559 ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
560 ok(hinst, sz == 3, "got size %u\n", sz);
562 sz = 3;
563 bufferW[0] = 'q';
564 r = MsiGetTargetPathW(hinst, targetdirW, bufferW, &sz);
565 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
566 ok(hinst, !lstrcmpW(bufferW, xyW), "got %s\n", dbgstr_w(bufferW));
567 ok(hinst, sz == 3, "got size %u\n", sz);
569 sz = 4;
570 bufferW[0] = 'q';
571 r = MsiGetTargetPathW(hinst, targetdirW, bufferW, &sz);
572 ok(hinst, !r, "got %u\n", r);
573 ok(hinst, !lstrcmpW(bufferW, xyzW), "got %s\n", dbgstr_w(bufferW));
574 ok(hinst, sz == 3, "got size %u\n", sz);
576 r = MsiSetTargetPathA(hinst, NULL, "C:\\subdir");
577 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
579 r = MsiSetTargetPathA(hinst, "TARGETDIR", NULL);
580 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
582 r = MsiSetTargetPathA(hinst, "TARGETDIR", "C:\\subdir");
583 ok(hinst, !r, "got %u\n", r);
585 sz = sizeof(buffer);
586 r = MsiGetTargetPathA(hinst, "TARGETDIR", buffer, &sz);
587 ok(hinst, !r, "got %u\n", r);
588 ok(hinst, !strcmp(buffer, "C:\\subdir\\"), "got \"%s\"\n", buffer);
590 r = MsiSetTargetPathA(hinst, "TARGETDIR", "C:\\");
592 /* test GetSourcePath() */
594 r = MsiGetSourcePathA(hinst, NULL, NULL, NULL);
595 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
597 r = MsiGetSourcePathA(hinst, "TARGETDIR", NULL, NULL );
598 ok(hinst, !r, "got %u\n", r);
600 r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, NULL );
601 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
603 /* Returned size is in bytes, not chars, but only for custom actions.
604 * Seems to be a casualty of RPC... */
606 srcsz = 0;
607 MsiGetSourcePathW(hinst, targetdirW, NULL, &srcsz);
609 sz = 0;
610 r = MsiGetSourcePathA(hinst, "TARGETDIR", NULL, &sz);
611 ok(hinst, !r, "got %u\n", r);
612 ok(hinst, sz == srcsz * 2, "got size %u\n", sz);
614 sz = 0;
615 strcpy(buffer,"q");
616 r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, &sz);
617 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
618 ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
619 ok(hinst, sz == srcsz * 2, "got size %u\n", sz);
621 sz = 1;
622 strcpy(buffer,"x");
623 r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, &sz);
624 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
625 ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
626 ok(hinst, sz == srcsz * 2, "got size %u\n", sz);
628 sz = srcsz;
629 strcpy(buffer,"x");
630 r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, &sz);
631 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
632 ok(hinst, strlen(buffer) == srcsz - 1, "wrong buffer length %d\n", strlen(buffer));
633 ok(hinst, sz == srcsz * 2, "got size %u\n", sz);
635 sz = srcsz + 1;
636 strcpy(buffer,"x");
637 r = MsiGetSourcePathA(hinst, "TARGETDIR", buffer, &sz);
638 ok(hinst, !r, "got %u\n", r);
639 ok(hinst, strlen(buffer) == srcsz, "wrong buffer length %d\n", strlen(buffer));
640 ok(hinst, sz == srcsz, "got size %u\n", sz);
642 sz = 0;
643 r = MsiGetSourcePathW(hinst, targetdirW, NULL, &sz);
644 ok(hinst, !r, "got %u\n", r);
645 ok(hinst, sz == srcsz, "got size %u\n", sz);
647 sz = 0;
648 bufferW[0] = 'q';
649 r = MsiGetSourcePathW(hinst, targetdirW, bufferW, &sz);
650 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
651 ok(hinst, bufferW[0] == 'q', "got %s\n", dbgstr_w(bufferW));
652 ok(hinst, sz == srcsz, "got size %u\n", sz);
654 sz = 1;
655 bufferW[0] = 'q';
656 r = MsiGetSourcePathW(hinst, targetdirW, bufferW, &sz);
657 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
658 ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
659 ok(hinst, sz == srcsz, "got size %u\n", sz);
661 sz = srcsz;
662 bufferW[0] = 'q';
663 r = MsiGetSourcePathW(hinst, targetdirW, bufferW, &sz);
664 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
665 ok(hinst, lstrlenW(bufferW) == srcsz - 1, "wrong buffer length %d\n", lstrlenW(bufferW));
666 ok(hinst, sz == srcsz, "got size %u\n", sz);
668 sz = srcsz + 1;
669 bufferW[0] = 'q';
670 r = MsiGetSourcePathW(hinst, targetdirW, bufferW, &sz);
671 ok(hinst, !r, "got %u\n", r);
672 ok(hinst, lstrlenW(bufferW) == srcsz, "wrong buffer length %d\n", lstrlenW(bufferW));
673 ok(hinst, sz == srcsz, "got size %u\n", sz);
676 static void test_misc(MSIHANDLE hinst)
678 MSICONDITION cond;
679 LANGID lang;
680 UINT r;
682 r = MsiSetMode(hinst, MSIRUNMODE_REBOOTATEND, FALSE);
683 ok(hinst, !r, "got %u\n", r);
685 lang = MsiGetLanguage(hinst);
686 ok(hinst, lang == 1033, "got %u\n", lang);
688 check_prop(hinst, "INSTALLLEVEL", "3");
689 r = MsiSetInstallLevel(hinst, 123);
690 ok(hinst, !r, "got %u\n", r);
691 check_prop(hinst, "INSTALLLEVEL", "123");
692 MsiSetInstallLevel(hinst, 3);
694 cond = MsiEvaluateConditionA(hinst, NULL);
695 ok(hinst, cond == MSICONDITION_NONE, "got %u\n", cond);
696 MsiSetPropertyA(hinst, "condprop", "1");
697 cond = MsiEvaluateConditionA(hinst, "condprop = 1");
698 ok(hinst, cond == MSICONDITION_TRUE, "got %u\n", cond);
701 static void test_feature_states(MSIHANDLE hinst)
703 INSTALLSTATE state, action;
704 UINT r;
706 /* test feature states */
708 r = MsiGetFeatureStateA(hinst, NULL, &state, &action);
709 ok(hinst, r == ERROR_UNKNOWN_FEATURE, "got %u\n", r);
711 r = MsiGetFeatureStateA(hinst, "fake", &state, &action);
712 ok(hinst, r == ERROR_UNKNOWN_FEATURE, "got %u\n", r);
714 r = MsiGetFeatureStateA(hinst, "One", NULL, &action);
715 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
717 r = MsiGetFeatureStateA(hinst, "One", &state, NULL);
718 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
720 r = MsiGetFeatureStateA(hinst, "One", &state, &action);
721 ok(hinst, !r, "got %u\n", r);
722 ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
723 ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
725 r = MsiSetFeatureStateA(hinst, NULL, INSTALLSTATE_ABSENT);
726 ok(hinst, r == ERROR_UNKNOWN_FEATURE, "got %u\n", r);
728 r = MsiSetFeatureStateA(hinst, "One", INSTALLSTATE_ADVERTISED);
729 ok(hinst, !r, "got %u\n", r);
731 r = MsiGetFeatureStateA(hinst, "One", &state, &action);
732 ok(hinst, !r, "got %u\n", r);
733 ok(hinst, action == INSTALLSTATE_ADVERTISED, "got action %d\n", action);
735 r = MsiSetFeatureStateA(hinst, "One", INSTALLSTATE_LOCAL);
736 ok(hinst, !r, "got %u\n", r);
738 r = MsiGetFeatureStateA(hinst, "One", &state, &action);
739 ok(hinst, !r, "got %u\n", r);
740 ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
742 /* test component states */
744 r = MsiGetComponentStateA(hinst, NULL, &state, &action);
745 ok(hinst, r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r);
747 r = MsiGetComponentStateA(hinst, "fake", &state, &action);
748 ok(hinst, r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r);
750 r = MsiGetComponentStateA(hinst, "One", NULL, &action);
751 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
753 r = MsiGetComponentStateA(hinst, "One", &state, NULL);
754 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
756 r = MsiGetComponentStateA(hinst, "One", &state, &action);
757 ok(hinst, !r, "got %u\n", r);
758 ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
759 ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
761 r = MsiGetComponentStateA(hinst, "dangler", &state, &action);
762 ok(hinst, !r, "got %u\n", r);
763 ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
764 ok(hinst, action == INSTALLSTATE_UNKNOWN, "got action %d\n", action);
766 r = MsiGetComponentStateA(hinst, "component", &state, &action);
767 ok(hinst, !r, "got %u\n", r);
768 ok(hinst, state == INSTALLSTATE_UNKNOWN, "got state %d\n", state);
769 ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
771 r = MsiSetComponentStateA(hinst, NULL, INSTALLSTATE_ABSENT);
772 ok(hinst, r == ERROR_UNKNOWN_COMPONENT, "got %u\n", r);
774 r = MsiSetComponentStateA(hinst, "One", INSTALLSTATE_SOURCE);
775 ok(hinst, !r, "got %u\n", r);
777 r = MsiGetComponentStateA(hinst, "One", &state, &action);
778 ok(hinst, !r, "got %u\n", r);
779 ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
780 ok(hinst, action == INSTALLSTATE_SOURCE, "got action %d\n", action);
782 r = MsiSetComponentStateA(hinst, "One", INSTALLSTATE_LOCAL);
783 ok(hinst, !r, "got %u\n", r);
785 r = MsiGetComponentStateA(hinst, "One", &state, &action);
786 ok(hinst, !r, "got %u\n", r);
787 ok(hinst, state == INSTALLSTATE_ABSENT, "got state %d\n", state);
788 ok(hinst, action == INSTALLSTATE_LOCAL, "got action %d\n", action);
791 static void test_format_record(MSIHANDLE hinst)
793 static const WCHAR xyzW[] = {'f','o','o',' ','1','2','3',0};
794 static const WCHAR xyW[] = {'f','o','o',' ','1','2',0};
795 WCHAR bufferW[10];
796 char buffer[10];
797 MSIHANDLE rec;
798 DWORD sz;
799 UINT r;
801 r = MsiFormatRecordA(hinst, 0, NULL, NULL);
802 ok(hinst, r == ERROR_INVALID_HANDLE, "got %u\n", r);
804 rec = MsiCreateRecord(1);
805 MsiRecordSetStringA(rec, 0, "foo [1]");
806 MsiRecordSetInteger(rec, 1, 123);
808 r = MsiFormatRecordA(hinst, rec, NULL, NULL);
809 ok(hinst, !r, "got %u\n", r);
811 r = MsiFormatRecordA(hinst, rec, buffer, NULL);
812 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
814 /* Returned size is in bytes, not chars, but only for custom actions. */
816 sz = 0;
817 r = MsiFormatRecordA(hinst, rec, NULL, &sz);
818 ok(hinst, !r, "got %u\n", r);
819 ok(hinst, sz == 14, "got size %u\n", sz);
821 sz = 0;
822 strcpy(buffer,"q");
823 r = MsiFormatRecordA(hinst, rec, buffer, &sz);
824 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
825 ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
826 ok(hinst, sz == 14, "got size %u\n", sz);
828 sz = 1;
829 strcpy(buffer,"x");
830 r = MsiFormatRecordA(hinst, rec, buffer, &sz);
831 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
832 ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
833 ok(hinst, sz == 14, "got size %u\n", sz);
835 sz = 7;
836 strcpy(buffer,"x");
837 r = MsiFormatRecordA(hinst, rec, buffer, &sz);
838 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
839 ok(hinst, !strcmp(buffer, "foo 12"), "got \"%s\"\n", buffer);
840 ok(hinst, sz == 14, "got size %u\n", sz);
842 sz = 8;
843 strcpy(buffer,"x");
844 r = MsiFormatRecordA(hinst, rec, buffer, &sz);
845 ok(hinst, !r, "got %u\n", r);
846 ok(hinst, !strcmp(buffer, "foo 123"), "got \"%s\"\n", buffer);
847 ok(hinst, sz == 7, "got size %u\n", sz);
849 r = MsiFormatRecordW(hinst, rec, NULL, NULL);
850 ok(hinst, !r, "got %u\n", r);
852 r = MsiFormatRecordW(hinst, rec, bufferW, NULL);
853 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
855 sz = 0;
856 r = MsiFormatRecordW(hinst, rec, NULL, &sz);
857 ok(hinst, !r, "got %u\n", r);
858 ok(hinst, sz == 7, "got size %u\n", sz);
860 sz = 0;
861 bufferW[0] = 'q';
862 r = MsiFormatRecordW(hinst, rec, bufferW, &sz);
863 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
864 ok(hinst, bufferW[0] == 'q', "got %s\n", dbgstr_w(bufferW));
865 ok(hinst, sz == 7, "got size %u\n", sz);
867 sz = 1;
868 bufferW[0] = 'q';
869 r = MsiFormatRecordW(hinst, rec, bufferW, &sz);
870 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
871 ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
872 ok(hinst, sz == 7, "got size %u\n", sz);
874 sz = 7;
875 bufferW[0] = 'q';
876 r = MsiFormatRecordW(hinst, rec, bufferW, &sz);
877 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
878 ok(hinst, !lstrcmpW(bufferW, xyW), "got %s\n", dbgstr_w(bufferW));
879 ok(hinst, sz == 7, "got size %u\n", sz);
881 sz = 8;
882 bufferW[0] = 'q';
883 r = MsiFormatRecordW(hinst, rec, bufferW, &sz);
884 ok(hinst, !r, "got %u\n", r);
885 ok(hinst, !lstrcmpW(bufferW, xyzW), "got %s\n", dbgstr_w(bufferW));
886 ok(hinst, sz == 7, "got size %u\n", sz);
888 /* check that properties work */
889 MsiSetPropertyA(hinst, "fmtprop", "foobar");
890 MsiRecordSetStringA(rec, 0, "[fmtprop]");
891 sz = sizeof(buffer);
892 r = MsiFormatRecordA(hinst, rec, buffer, &sz);
893 ok(hinst, !r, "got %u\n", r);
894 ok(hinst, !strcmp(buffer, "foobar"), "got \"%s\"\n", buffer);
895 ok(hinst, sz == 6, "got size %u\n", sz);
897 MsiCloseHandle(rec);
900 static void test_costs(MSIHANDLE hinst)
902 static const WCHAR oneW[] = {'O','n','e',0};
903 static const WCHAR xyzW[] = {'C',':',0};
904 static const WCHAR xyW[] = {'C',0};
905 WCHAR bufferW[10];
906 char buffer[10];
907 int cost, temp;
908 DWORD sz;
909 UINT r;
911 cost = 0xdead;
912 r = MsiGetFeatureCostA(hinst, NULL, MSICOSTTREE_CHILDREN, INSTALLSTATE_LOCAL, &cost);
913 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
914 todo_wine
915 ok(hinst, !cost, "got %d\n", cost);
917 r = MsiGetFeatureCostA(hinst, "One", MSICOSTTREE_CHILDREN, INSTALLSTATE_LOCAL, NULL);
918 ok(hinst, r == RPC_X_NULL_REF_POINTER, "got %u\n", r);
920 cost = 0xdead;
921 r = MsiGetFeatureCostA(hinst, "One", MSICOSTTREE_CHILDREN, INSTALLSTATE_LOCAL, &cost);
922 ok(hinst, !r, "got %u\n", r);
923 todo_wine
924 ok(hinst, cost == 8, "got %d\n", cost);
926 sz = cost = temp = 0xdead;
927 r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, NULL, &sz, &cost, &temp);
928 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
929 ok(hinst, sz == 0xdead, "got size %d\n", sz);
930 ok(hinst, cost == 0xdead, "got cost %d\n", cost);
931 ok(hinst, temp == 0xdead, "got temp %d\n", temp);
933 cost = temp = 0xdead;
934 r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, NULL, &cost, &temp);
935 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
936 ok(hinst, cost == 0xdead, "got cost %d\n", cost);
937 ok(hinst, temp == 0xdead, "got temp %d\n", temp);
939 sz = temp = 0xdead;
940 r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, NULL, &temp);
941 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
942 ok(hinst, sz == 0xdead, "got size %d\n", sz);
943 ok(hinst, temp == 0xdead, "got temp %d\n", temp);
945 sz = cost = 0xdead;
946 r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, NULL);
947 ok(hinst, r == ERROR_INVALID_PARAMETER, "got %u\n", r);
948 ok(hinst, sz == 0xdead, "got size %d\n", sz);
949 ok(hinst, cost == 0xdead, "got cost %d\n", cost);
951 cost = temp = 0xdead;
952 sz = sizeof(buffer);
953 r = MsiEnumComponentCostsA(hinst, NULL, 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
954 ok(hinst, !r, "got %u\n", r);
955 ok(hinst, sz == 2, "got size %u\n", sz);
956 ok(hinst, !strcmp(buffer, "C:"), "got '%s'\n", buffer);
957 ok(hinst, !cost, "got cost %d\n", cost);
958 ok(hinst, temp && temp != 0xdead, "got temp %d\n", temp);
960 cost = temp = 0xdead;
961 sz = sizeof(buffer);
962 r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
963 ok(hinst, !r, "got %u\n", r);
964 ok(hinst, sz == 2, "got size %u\n", sz);
965 ok(hinst, !strcmp(buffer, "C:"), "got '%s'\n", buffer);
966 ok(hinst, cost == 8, "got cost %d\n", cost);
967 ok(hinst, !temp, "got temp %d\n", temp);
969 /* same string behaviour */
970 cost = temp = 0xdead;
971 sz = 0;
972 strcpy(buffer,"q");
973 r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
974 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
975 ok(hinst, !strcmp(buffer, "q"), "got \"%s\"\n", buffer);
976 todo_wine
977 ok(hinst, sz == 4, "got size %u\n", sz);
978 ok(hinst, cost == 8, "got cost %d\n", cost);
979 ok(hinst, !temp, "got temp %d\n", temp);
981 sz = 1;
982 strcpy(buffer,"x");
983 r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
984 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
985 todo_wine {
986 ok(hinst, !buffer[0], "got \"%s\"\n", buffer);
987 ok(hinst, sz == 4, "got size %u\n", sz);
990 sz = 2;
991 strcpy(buffer,"x");
992 r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
993 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
994 todo_wine {
995 ok(hinst, !strcmp(buffer, "C"), "got \"%s\"\n", buffer);
996 ok(hinst, sz == 4, "got size %u\n", sz);
999 sz = 3;
1000 strcpy(buffer,"x");
1001 r = MsiEnumComponentCostsA(hinst, "One", 0, INSTALLSTATE_LOCAL, buffer, &sz, &cost, &temp);
1002 ok(hinst, !r, "got %u\n", r);
1003 ok(hinst, !strcmp(buffer, "C:"), "got \"%s\"\n", buffer);
1004 ok(hinst, sz == 2, "got size %u\n", sz);
1006 sz = 0;
1007 bufferW[0] = 'q';
1008 r = MsiEnumComponentCostsW(hinst, oneW, 0, INSTALLSTATE_LOCAL, bufferW, &sz, &cost, &temp);
1009 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
1010 ok(hinst, bufferW[0] == 'q', "got %s\n", dbgstr_w(bufferW));
1011 ok(hinst, sz == 2, "got size %u\n", sz);
1013 sz = 1;
1014 bufferW[0] = 'q';
1015 r = MsiEnumComponentCostsW(hinst, oneW, 0, INSTALLSTATE_LOCAL, bufferW, &sz, &cost, &temp);
1016 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
1017 ok(hinst, !bufferW[0], "got %s\n", dbgstr_w(bufferW));
1018 ok(hinst, sz == 2, "got size %u\n", sz);
1020 sz = 2;
1021 bufferW[0] = 'q';
1022 r = MsiEnumComponentCostsW(hinst, oneW, 0, INSTALLSTATE_LOCAL, bufferW, &sz, &cost, &temp);
1023 ok(hinst, r == ERROR_MORE_DATA, "got %u\n", r);
1024 ok(hinst, !lstrcmpW(bufferW, xyW), "got %s\n", dbgstr_w(bufferW));
1025 ok(hinst, sz == 2, "got size %u\n", sz);
1027 sz = 3;
1028 bufferW[0] = 'q';
1029 r = MsiEnumComponentCostsW(hinst, oneW, 0, INSTALLSTATE_LOCAL, bufferW, &sz, &cost, &temp);
1030 ok(hinst, !r, "got %u\n", r);
1031 ok(hinst, !lstrcmpW(bufferW, xyzW), "got %s\n", dbgstr_w(bufferW));
1032 ok(hinst, sz == 2, "got size %u\n", sz);
1035 /* Main test. Anything that doesn't depend on a specific install configuration
1036 * or have undesired side effects should go here. */
1037 UINT WINAPI main_test(MSIHANDLE hinst)
1039 UINT res;
1040 IUnknown *unk = NULL;
1041 HRESULT hr;
1043 /* Test for an MTA apartment */
1044 hr = CoCreateInstance(&CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk);
1045 ok(hinst, hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1047 if (unk) IUnknown_Release(unk);
1049 /* but ours is uninitialized */
1050 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1051 ok(hinst, hr == S_OK, "got %#x\n", hr);
1052 CoUninitialize();
1054 /* Test MsiGetDatabaseState() */
1055 res = MsiGetDatabaseState(hinst);
1056 todo_wine
1057 ok(hinst, res == MSIDBSTATE_ERROR, "expected MSIDBSTATE_ERROR, got %u\n", res);
1059 test_props(hinst);
1060 test_db(hinst);
1061 test_doaction(hinst);
1062 test_targetpath(hinst);
1063 test_misc(hinst);
1064 test_feature_states(hinst);
1065 test_format_record(hinst);
1066 test_costs(hinst);
1068 return ERROR_SUCCESS;
1071 UINT WINAPI test_retval(MSIHANDLE hinst)
1073 char prop[10];
1074 DWORD len = sizeof(prop);
1075 UINT retval;
1077 MsiGetPropertyA(hinst, "TEST_RETVAL", prop, &len);
1078 sscanf(prop, "%u", &retval);
1079 return retval;
1082 static void append_file(MSIHANDLE hinst, const char *filename, const char *text)
1084 DWORD size;
1085 HANDLE file = CreateFileA(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
1086 ok(hinst, file != INVALID_HANDLE_VALUE, "CreateFile failed, error %u\n", GetLastError());
1088 SetFilePointer(file, 0, NULL, FILE_END);
1089 WriteFile(file, text, strlen(text), &size, NULL);
1090 CloseHandle(file);
1093 UINT WINAPI da_immediate(MSIHANDLE hinst)
1095 char prop[300];
1096 DWORD len = sizeof(prop);
1098 MsiGetPropertyA(hinst, "TESTPATH", prop, &len);
1100 append_file(hinst, prop, "one");
1102 ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_SCHEDULED), "shouldn't be scheduled\n");
1103 ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_ROLLBACK), "shouldn't be rollback\n");
1104 ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_COMMIT), "shouldn't be commit\n");
1106 return ERROR_SUCCESS;
1109 UINT WINAPI da_deferred(MSIHANDLE hinst)
1111 char prop[300];
1112 DWORD len = sizeof(prop);
1113 LANGID lang;
1114 UINT r;
1116 /* Test that we were in fact deferred */
1117 r = MsiGetPropertyA(hinst, "CustomActionData", prop, &len);
1118 ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1119 ok(hinst, prop[0], "CustomActionData was empty\n");
1121 append_file(hinst, prop, "two");
1123 /* Test available properties */
1124 len = sizeof(prop);
1125 r = MsiGetPropertyA(hinst, "ProductCode", prop, &len);
1126 ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1127 ok(hinst, prop[0], "got %s\n", prop);
1129 len = sizeof(prop);
1130 r = MsiGetPropertyA(hinst, "UserSID", prop, &len);
1131 ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1132 ok(hinst, prop[0], "got %s\n", prop);
1134 len = sizeof(prop);
1135 r = MsiGetPropertyA(hinst, "TESTPATH", prop, &len);
1136 ok(hinst, r == ERROR_SUCCESS, "got %u\n", r);
1137 todo_wine
1138 ok(hinst, !prop[0], "got %s\n", prop);
1140 /* Test modes */
1141 ok(hinst, MsiGetMode(hinst, MSIRUNMODE_SCHEDULED), "should be scheduled\n");
1142 ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_ROLLBACK), "shouldn't be rollback\n");
1143 ok(hinst, !MsiGetMode(hinst, MSIRUNMODE_COMMIT), "shouldn't be commit\n");
1145 lang = MsiGetLanguage(hinst);
1146 ok(hinst, lang != ERROR_INVALID_HANDLE, "MsiGetLanguage failed\n");
1148 return ERROR_SUCCESS;
1151 static BOOL pf_exists(const char *file)
1153 char path[MAX_PATH];
1155 if (FAILED(SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, path)))
1156 SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES, NULL, 0, path);
1157 strcat(path, "\\");
1158 strcat(path, file);
1159 return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
1162 UINT WINAPI cf_present(MSIHANDLE hinst)
1164 todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
1165 ok(hinst, pf_exists("msitest\\first"), "folder absent\n");
1166 ok(hinst, pf_exists("msitest\\second"), "folder absent\n");
1167 ok(hinst, pf_exists("msitest\\third"), "folder absent\n");
1169 return ERROR_SUCCESS;
1172 UINT WINAPI cf_absent(MSIHANDLE hinst)
1174 todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED)) {
1175 ok(hinst, !pf_exists("msitest\\first"), "folder present\n");
1176 ok(hinst, !pf_exists("msitest\\second"), "folder present\n");
1177 ok(hinst, !pf_exists("msitest\\third"), "folder present\n");
1179 return ERROR_SUCCESS;
1182 UINT WINAPI crs_present(MSIHANDLE hinst)
1184 todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
1185 ok(hinst, pf_exists("msitest\\shortcut.lnk"), "shortcut absent\n");
1186 return ERROR_SUCCESS;
1189 UINT WINAPI crs_absent(MSIHANDLE hinst)
1191 todo_wine_if(!MsiGetMode(hinst, MSIRUNMODE_SCHEDULED))
1192 ok(hinst, !pf_exists("msitest\\shortcut.lnk"), "shortcut present\n");
1193 return ERROR_SUCCESS;