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
31 static void ok_(MSIHANDLE hinst
, int todo
, const char *file
, int line
, int condition
, const char *msg
, ...)
33 static char buffer
[2000];
37 va_start(valist
, msg
);
38 vsprintf(buffer
, msg
, valist
);
41 record
= MsiCreateRecord(5);
42 MsiRecordSetInteger(record
, 1, todo
);
43 MsiRecordSetStringA(record
, 2, file
);
44 MsiRecordSetInteger(record
, 3, line
);
45 MsiRecordSetInteger(record
, 4, condition
);
46 MsiRecordSetStringA(record
, 5, buffer
);
47 MsiProcessMessage(hinst
, INSTALLMESSAGE_USER
, record
);
48 MsiCloseHandle(record
);
50 #define ok(hinst, condition, ...) ok_(hinst, 0, __FILE__, __LINE__, condition, __VA_ARGS__)
51 #define todo_wine_ok(hinst, condition, ...) ok_(hinst, 1, __FILE__, __LINE__, condition, __VA_ARGS__)
53 static const char *dbgstr_w(WCHAR
*str
)
55 static char buffer
[300], *p
;
57 if (!str
) return "(null)";
62 while ((*p
++ = *str
++));
69 static void check_prop(MSIHANDLE hinst
, const char *prop
, const char *expect
)
71 char buffer
[10] = "x";
72 DWORD sz
= sizeof(buffer
);
73 UINT r
= MsiGetPropertyA(hinst
, prop
, buffer
, &sz
);
74 ok(hinst
, !r
, "'%s': got %u\n", prop
, r
);
75 ok(hinst
, sz
== strlen(buffer
), "'%s': expected %u, got %u\n", prop
, strlen(buffer
), sz
);
76 ok(hinst
, !strcmp(buffer
, expect
), "expected '%s', got '%s'\n", expect
, buffer
);
79 static void test_props(MSIHANDLE hinst
)
81 static const WCHAR booW
[] = {'b','o','o',0};
82 static const WCHAR xyzW
[] = {'x','y','z',0};
83 static const WCHAR xyW
[] = {'x','y',0};
89 /* test invalid values */
90 r
= MsiGetPropertyA(hinst
, NULL
, NULL
, NULL
);
91 ok(hinst
, r
== ERROR_INVALID_PARAMETER
, "got %u\n", r
);
93 r
= MsiGetPropertyA(hinst
, "boo", NULL
, NULL
);
94 ok(hinst
, !r
, "got %u\n", r
);
96 r
= MsiGetPropertyA(hinst
, "boo", buffer
, NULL
);
97 ok(hinst
, r
== ERROR_INVALID_PARAMETER
, "got %u\n", r
);
100 r
= MsiGetPropertyA(hinst
, "boo", NULL
, &sz
);
101 ok(hinst
, !r
, "got %u\n", r
);
102 ok(hinst
, sz
== 0, "got size %u\n", sz
);
106 r
= MsiGetPropertyA(hinst
, "boo", buffer
, &sz
);
107 ok(hinst
, r
== ERROR_MORE_DATA
, "got %u\n", r
);
108 ok(hinst
, !strcmp(buffer
, "x"), "got \"%s\"\n", buffer
);
109 ok(hinst
, sz
== 0, "got size %u\n", sz
);
113 r
= MsiGetPropertyA(hinst
, "boo", buffer
, &sz
);
114 ok(hinst
, !r
, "got %u\n", r
);
115 ok(hinst
, !buffer
[0], "got \"%s\"\n", buffer
);
116 ok(hinst
, sz
== 0, "got size %u\n", sz
);
118 /* set the property to something */
119 r
= MsiSetPropertyA(hinst
, NULL
, NULL
);
120 ok(hinst
, r
== ERROR_INVALID_PARAMETER
, "got %u\n", r
);
122 r
= MsiSetPropertyA(hinst
, "", NULL
);
123 ok(hinst
, !r
, "got %u\n", r
);
125 r
= MsiSetPropertyA(hinst
, "", "asdf");
126 ok(hinst
, r
== ERROR_FUNCTION_FAILED
, "got %u\n", r
);
128 r
= MsiSetPropertyA(hinst
, "=", "asdf");
129 ok(hinst
, !r
, "got %u\n", r
);
130 check_prop(hinst
, "=", "asdf");
132 r
= MsiSetPropertyA(hinst
, " ", "asdf");
133 ok(hinst
, !r
, "got %u\n", r
);
134 check_prop(hinst
, " ", "asdf");
136 r
= MsiSetPropertyA(hinst
, "'", "asdf");
137 ok(hinst
, !r
, "got %u\n", r
);
138 check_prop(hinst
, "'", "asdf");
140 r
= MsiSetPropertyA(hinst
, "boo", NULL
);
141 ok(hinst
, !r
, "got %u\n", r
);
142 check_prop(hinst
, "boo", "");
144 r
= MsiSetPropertyA(hinst
, "boo", "");
145 ok(hinst
, !r
, "got %u\n", r
);
146 check_prop(hinst
, "boo", "");
148 r
= MsiSetPropertyA(hinst
, "boo", "xyz");
149 ok(hinst
, !r
, "got %u\n", r
);
150 check_prop(hinst
, "boo", "xyz");
152 r
= MsiGetPropertyA(hinst
, "boo", NULL
, NULL
);
153 ok(hinst
, !r
, "got %u\n", r
);
155 r
= MsiGetPropertyA(hinst
, "boo", buffer
, NULL
);
156 ok(hinst
, r
== ERROR_INVALID_PARAMETER
, "got %u\n", r
);
158 /* Returned size is in bytes, not chars, but only for custom actions.
159 * Seems to be a casualty of RPC... */
162 r
= MsiGetPropertyA(hinst
, "boo", NULL
, &sz
);
163 ok(hinst
, !r
, "got %u\n", r
);
164 ok(hinst
, sz
== 6, "got size %u\n", sz
);
168 r
= MsiGetPropertyA(hinst
, "boo", buffer
, &sz
);
169 ok(hinst
, r
== ERROR_MORE_DATA
, "got %u\n", r
);
170 ok(hinst
, !strcmp(buffer
, "q"), "got \"%s\"\n", buffer
);
171 todo_wine_ok(hinst
, sz
== 6, "got size %u\n", sz
);
175 r
= MsiGetPropertyA(hinst
, "boo", buffer
, &sz
);
176 ok(hinst
, r
== ERROR_MORE_DATA
, "got %u\n", r
);
177 ok(hinst
, !buffer
[0], "got \"%s\"\n", buffer
);
178 todo_wine_ok(hinst
, sz
== 6, "got size %u\n", sz
);
182 r
= MsiGetPropertyA(hinst
, "boo", buffer
, &sz
);
183 ok(hinst
, r
== ERROR_MORE_DATA
, "got %u\n", r
);
184 ok(hinst
, !strcmp(buffer
, "xy"), "got \"%s\"\n", buffer
);
185 todo_wine_ok(hinst
, sz
== 6, "got size %u\n", sz
);
189 r
= MsiGetPropertyA(hinst
, "boo", buffer
, &sz
);
190 ok(hinst
, !r
, "got %u\n", r
);
191 ok(hinst
, !strcmp(buffer
, "xyz"), "got \"%s\"\n", buffer
);
192 ok(hinst
, sz
== 3, "got size %u\n", sz
);
195 r
= MsiGetPropertyW(hinst
, booW
, NULL
, &sz
);
196 ok(hinst
, !r
, "got %u\n", r
);
197 ok(hinst
, sz
== 3, "got size %u\n", sz
);
200 lstrcpyW(bufferW
, booW
);
201 r
= MsiGetPropertyW(hinst
, booW
, bufferW
, &sz
);
202 ok(hinst
, r
== ERROR_MORE_DATA
, "got %u\n", r
);
203 ok(hinst
, !lstrcmpW(bufferW
, booW
), "got %s\n", dbgstr_w(bufferW
));
204 ok(hinst
, sz
== 3, "got size %u\n", sz
);
207 lstrcpyW(bufferW
, booW
);
208 r
= MsiGetPropertyW(hinst
, booW
, bufferW
, &sz
);
209 ok(hinst
, r
== ERROR_MORE_DATA
, "got %u\n", r
);
210 ok(hinst
, !bufferW
[0], "got %s\n", dbgstr_w(bufferW
));
211 ok(hinst
, sz
== 3, "got size %u\n", sz
);
214 lstrcpyW(bufferW
, booW
);
215 r
= MsiGetPropertyW(hinst
, booW
, bufferW
, &sz
);
216 ok(hinst
, r
== ERROR_MORE_DATA
, "got %u\n", r
);
217 ok(hinst
, !lstrcmpW(bufferW
, xyW
), "got %s\n", dbgstr_w(bufferW
));
218 ok(hinst
, sz
== 3, "got size %u\n", sz
);
221 lstrcpyW(bufferW
, booW
);
222 r
= MsiGetPropertyW(hinst
, booW
, bufferW
, &sz
);
223 ok(hinst
, !r
, "got %u\n", r
);
224 ok(hinst
, !lstrcmpW(bufferW
, xyzW
), "got %s\n", dbgstr_w(bufferW
));
225 ok(hinst
, sz
== 3, "got size %u\n", sz
);
227 r
= MsiSetPropertyA(hinst
, "boo", NULL
);
228 ok(hinst
, !r
, "got %u\n", r
);
229 check_prop(hinst
, "boo", "");
232 r
= MsiGetPropertyA(hinst
, "embednullprop", NULL
, &sz
);
233 ok(hinst
, !r
, "got %u\n", r
);
234 ok(hinst
, sz
== 6, "got size %u\n", sz
);
237 memset(buffer
, 0xcc, sizeof(buffer
));
238 r
= MsiGetPropertyA(hinst
, "embednullprop", buffer
, &sz
);
239 ok(hinst
, !r
, "got %u\n", r
);
240 ok(hinst
, sz
== 3, "got size %u\n", sz
);
241 ok(hinst
, !memcmp(buffer
, "a\0\0\0\xcc", 5), "wrong data\n");
244 static void test_db(MSIHANDLE hinst
)
249 hdb
= MsiGetActiveDatabase(hinst
);
250 ok(hinst
, hdb
, "MsiGetActiveDatabase failed\n");
252 r
= MsiDatabaseIsTablePersistentA(hdb
, "Test");
253 ok(hinst
, r
== MSICONDITION_TRUE
, "got %u\n", r
);
255 r
= MsiDatabaseOpenViewA(hdb
, NULL
, &view
);
256 ok(hinst
, r
== ERROR_BAD_QUERY_SYNTAX
, "got %u\n", r
);
258 r
= MsiDatabaseOpenViewA(hdb
, "SELECT * FROM `Test`", NULL
);
259 ok(hinst
, r
== ERROR_INVALID_PARAMETER
, "got %u\n", r
);
261 r
= MsiDatabaseOpenViewA(hdb
, "SELECT * FROM `Test`", &view
);
262 ok(hinst
, !r
, "got %u\n", r
);
264 r
= MsiCloseHandle(view
);
265 ok(hinst
, !r
, "got %u\n", r
);
267 r
= MsiCloseHandle(hdb
);
268 ok(hinst
, !r
, "got %u\n", r
);
271 /* Main test. Anything that doesn't depend on a specific install configuration
272 * or have undesired side effects should go here. */
273 UINT WINAPI
main_test(MSIHANDLE hinst
)
276 IUnknown
*unk
= NULL
;
279 /* Test for an MTA apartment */
280 hr
= CoCreateInstance(&CLSID_XMLDocument
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void **)&unk
);
281 todo_wine_ok(hinst
, hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
283 if (unk
) IUnknown_Release(unk
);
285 /* but ours is uninitialized */
286 hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
287 ok(hinst
, hr
== S_OK
, "got %#x\n", hr
);
290 /* Test MsiGetDatabaseState() */
291 res
= MsiGetDatabaseState(hinst
);
292 todo_wine_ok(hinst
, res
== MSIDBSTATE_ERROR
, "expected MSIDBSTATE_ERROR, got %u\n", res
);
297 return ERROR_SUCCESS
;
300 UINT WINAPI
test_retval(MSIHANDLE hinst
)
303 DWORD len
= sizeof(prop
);
306 MsiGetPropertyA(hinst
, "TEST_RETVAL", prop
, &len
);
307 sscanf(prop
, "%u", &retval
);
311 static void append_file(MSIHANDLE hinst
, const char *filename
, const char *text
)
314 HANDLE file
= CreateFileA(filename
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
315 ok(hinst
, file
!= INVALID_HANDLE_VALUE
, "CreateFile failed, error %u\n", GetLastError());
317 SetFilePointer(file
, 0, NULL
, FILE_END
);
318 WriteFile(file
, text
, strlen(text
), &size
, NULL
);
322 UINT WINAPI
da_immediate(MSIHANDLE hinst
)
325 DWORD len
= sizeof(prop
);
327 MsiGetPropertyA(hinst
, "TESTPATH", prop
, &len
);
329 append_file(hinst
, prop
, "one");
331 ok(hinst
, !MsiGetMode(hinst
, MSIRUNMODE_SCHEDULED
), "shouldn't be scheduled\n");
332 ok(hinst
, !MsiGetMode(hinst
, MSIRUNMODE_ROLLBACK
), "shouldn't be rollback\n");
333 ok(hinst
, !MsiGetMode(hinst
, MSIRUNMODE_COMMIT
), "shouldn't be commit\n");
335 return ERROR_SUCCESS
;
338 UINT WINAPI
da_deferred(MSIHANDLE hinst
)
341 DWORD len
= sizeof(prop
);
345 /* Test that we were in fact deferred */
346 r
= MsiGetPropertyA(hinst
, "CustomActionData", prop
, &len
);
347 ok(hinst
, r
== ERROR_SUCCESS
, "got %u\n", r
);
348 ok(hinst
, prop
[0], "CustomActionData was empty\n");
350 append_file(hinst
, prop
, "two");
352 /* Test available properties */
354 r
= MsiGetPropertyA(hinst
, "ProductCode", prop
, &len
);
355 ok(hinst
, r
== ERROR_SUCCESS
, "got %u\n", r
);
356 ok(hinst
, prop
[0], "got %s\n", prop
);
359 r
= MsiGetPropertyA(hinst
, "UserSID", prop
, &len
);
360 ok(hinst
, r
== ERROR_SUCCESS
, "got %u\n", r
);
361 ok(hinst
, prop
[0], "got %s\n", prop
);
364 r
= MsiGetPropertyA(hinst
, "TESTPATH", prop
, &len
);
365 ok(hinst
, r
== ERROR_SUCCESS
, "got %u\n", r
);
366 todo_wine_ok(hinst
, !prop
[0], "got %s\n", prop
);
369 ok(hinst
, MsiGetMode(hinst
, MSIRUNMODE_SCHEDULED
), "should be scheduled\n");
370 ok(hinst
, !MsiGetMode(hinst
, MSIRUNMODE_ROLLBACK
), "shouldn't be rollback\n");
371 ok(hinst
, !MsiGetMode(hinst
, MSIRUNMODE_COMMIT
), "shouldn't be commit\n");
373 lang
= MsiGetLanguage(hinst
);
374 ok(hinst
, lang
!= ERROR_INVALID_HANDLE
, "MsiGetLanguage failed\n");
376 return ERROR_SUCCESS
;