1 /*
2  * SetupAPI device class-related functions tests
3  *
4  * Copyright 2015 V�ctor Mart�nez (victor.martinez@reactos.org)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this library; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <apitest.h>
22 #include <stdio.h>
23 #include <assert.h>
24 #include <winuser.h>
25 #include <winreg.h>
26 #include <winsvc.h>
27 #include <setupapi.h>
28 #include <strsafe.h>
29 
30 static const char inffile[] = "test.inf";
31 static char CURR_DIR[MAX_PATH];
32 
33 /* Helpers */
34 
35 static void create_inf_file(LPCSTR filename, const char *data)
36 {
37     DWORD res;
38     BOOL ret;
39     HANDLE handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
40                                 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
41     assert(handle != INVALID_HANDLE_VALUE);
42     ret = WriteFile(handle, data, strlen(data), &res, NULL);
43     assert(ret != 0);
44     CloseHandle(handle);
45 }
46 
47 static void test_SetupDiInstallClassExA(void)
48 {
49     char inf[2048];
50     char path[MAX_PATH];
51     BOOL ret;
52     ULONG del;
53     HKEY RegHandle;
54     HINF infhandle;
55     SC_HANDLE scm_handle, svc_handle;
56 
57     /* [Version]:Signature */
58     strcpy(inf, "[Version]\nSignature=\"$Chicago$\"\n");
59     create_inf_file(inffile, inf);
60     StringCbPrintfA(path, sizeof(path), "%s\\%s", CURR_DIR, inffile);
61 
62     SetLastError(0xdeadbeef);
63     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
64     ok(!ret, "Expected failure\n");
65     ok(GetLastError() == ERROR_INVALID_CLASS,
66        "Expected ERROR_INVALID_CLASS, got %08x\n", (int)GetLastError());
67     DeleteFileA(inffile);
68 
69     /* [Version]:Signature+Class */
70     strcat(inf, "Class=MySampleClass\n");
71     create_inf_file(inffile, inf);
72     StringCbPrintfA(path, sizeof(path), "%s\\%s", CURR_DIR, inffile);
73 
74     SetLastError(0xdeadbeef);
75     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
76     ok(!ret, "Expected failure\n");
77     ok(GetLastError() == ERROR_INVALID_CLASS,
78        "Expected ERROR_INVALID_CLASS, got %08x\n", (int)GetLastError());
79     DeleteFileA(inffile);
80 
81     /* [Version]:Signature+Class+ClassGUID */
82     strcat(inf, "ClassGuid={3b409830-5f9d-432a-abf5-7d2e4e102467}\n");
83     create_inf_file(inffile, inf);
84     StringCbPrintfA(path, sizeof(path), "%s\\%s", CURR_DIR, inffile);
85 
86     SetLastError(0xdeadbeef);
87     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
88     ok(!ret, "Expected failure\n");
89     ok(GetLastError() == ERROR_SECTION_NOT_FOUND,
90        "Expected ERROR_SECTION_NOT_FOUND, got %08x\n", (int)GetLastError());
91     DeleteFileA(inffile);
92 
93     /* [Version]Signature+Class+ClassGUID;[ClassInstall32.NT]Empty */
94     strcat(inf, "[ClassInstall32.NT]\n");
95     create_inf_file(inffile, inf);
96     StringCbPrintfA(path, sizeof(path), "%s\\%s", CURR_DIR, inffile);
97 
98     SetLastError(0xdeadbeef);
99     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
100     ok(ret, "Expected success\n");
101     ok(!GetLastError(),
102        "Expected no error, got %08x\n", (int)GetLastError());
103     DeleteFileA(inffile);
104     if (ret == TRUE)
105     {
106         RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM", 0, KEY_ALL_ACCESS, &RegHandle);
107         del = RegDeleteKeyW(RegHandle, L"CurrentControlSet\\Control\\Class\\{3B409830-5F9D-432A-ABF5-7D2E4E102467}");
108         ok(del == ERROR_SUCCESS, "Expected success \n");
109     }
110 
111     /* [Version]Signature+Class+ClassGUID;[ClassInstall32.NT]AddReg */
112     strcat(inf, "AddReg=SampleClassAddReg\n");
113     create_inf_file(inffile, inf);
114     StringCbPrintfA(path, sizeof(path), "%s\\%s", CURR_DIR, inffile);
115 
116     SetLastError(0xdeadbeef);
117     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
118     ok(ret, "Expected success\n");
119     ok(!GetLastError(),
120        "Expected no error, got %08x\n", (int)GetLastError());
121     DeleteFileA(inffile);
122     if (ret == TRUE)
123     {
124         RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM", 0, KEY_ALL_ACCESS, &RegHandle);
125         del = RegDeleteKeyW(RegHandle, L"CurrentControlSet\\Control\\Class\\{3B409830-5F9D-432A-ABF5-7D2E4E102467}");
126         ok(del == ERROR_SUCCESS, "Expected success \n");
127     }
128 
129     /* [Version]Signature+Class+ClassGUID;[ClassInstall32.NT]AddReg; [SampleClassAddReg];*/
130     strcat(inf, "[SampleClassAddReg]\n");
131     create_inf_file(inffile, inf);
132     StringCbPrintfA(path, sizeof(path), "%s\\%s", CURR_DIR, inffile);
133 
134     SetLastError(0xdeadbeef);
135     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
136     ok(ret, "Expected success\n");
137     ok(!GetLastError(),
138         "Expected no error, got %08x\n", (int)GetLastError());
139     DeleteFileA(inffile);
140     if (ret == TRUE)
141     {
142         RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM", 0, KEY_ALL_ACCESS, &RegHandle);
143         del = RegDeleteKeyW(RegHandle, L"CurrentControlSet\\Control\\Class\\{3B409830-5F9D-432A-ABF5-7D2E4E102467}");
144         ok(del == ERROR_SUCCESS, "Expected success \n");
145     }
146 
147     /* [Version]Signature+Class+ClassGUID;[ClassInstall32.NT]AddReg; [SampleClassAddReg]HKR;*/
148     strcat(inf, "HKR,,,,\"ReactOS Test SetupDiInstallClassExA\"\n");
149     create_inf_file(inffile, inf);
150     StringCbPrintfA(path, sizeof(path), "%s\\%s", CURR_DIR, inffile);
151 
152     SetLastError(0xdeadbeef);
153     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
154     ok(ret, "Expected success\n");
155     ok(!GetLastError(),
156        "Expected no error, got %08x\n", (int)GetLastError());
157     DeleteFileA(inffile);
158     if (ret == TRUE)
159     {
160         RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM", 0, KEY_ALL_ACCESS, &RegHandle);
161         del = RegDeleteKeyW(RegHandle, L"CurrentControlSet\\Control\\Class\\{3B409830-5F9D-432A-ABF5-7D2E4E102467}");
162         ok(del == ERROR_SUCCESS, "Expected success \n");
163     }
164 
165     /*[Version]Signature+Class+ClassGUID;[ClassInstall32.NT]AddReg;[SampleClassAddReg]HKR;[ClassInstall32.NT.Services]*/
166     strcat(inf, "[ClassInstall32.NT.Services]\n");
167     create_inf_file(inffile, inf);
168     StringCbPrintfA(path, sizeof(path), "%s\\%s", CURR_DIR, inffile);
169 
170     SetLastError(0xdeadbeef);
171     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
172     ok(ret, "Expected success\n");
173     ok(!GetLastError(),
174         "Expected no error, got %08x\n", (int)GetLastError());
175     DeleteFileA(inffile);
176     if (ret == TRUE)
177     {
178         RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM", 0, KEY_ALL_ACCESS, &RegHandle);
179         del = RegDeleteKeyW(RegHandle, L"CurrentControlSet\\Control\\Class\\{3B409830-5F9D-432A-ABF5-7D2E4E102467}");
180         ok(del == ERROR_SUCCESS, "Expected success\n");
181     }
182 
183     /* Add a reference */
184     strcat(inf, "AddService=Reactostest,,Reactostest.Service\n");
185     create_inf_file(inffile, inf);
186     infhandle =  SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
187     SetLastError(0xdeadbeef);
188     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
189     ok(!ret, "Expected failure\n");
190     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
191        "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", (int)GetLastError());
192     SetupCloseInfFile(infhandle);
193     DeleteFileA(inffile);
194 
195     /* Add the section */
196     strcat(inf, "[Reactostest.Service]\n");
197     create_inf_file(inffile, inf);
198     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
199     SetLastError(0xdeadbeef);
200     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
201     ok(!ret, "Expected failure\n");
202     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
203        "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", (int)GetLastError());
204     SetupCloseInfFile(infhandle);
205     DeleteFileA(inffile);
206 
207     /* Just the ServiceBinary */
208     strcat(inf, "ServiceBinary=%12%\\reactostest.sys\n");
209     create_inf_file(inffile, inf);
210     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
211     SetLastError(0xdeadbeef);
212     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
213     ok(!ret, "Expected failure\n");
214     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
215        "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", (int)GetLastError());
216     SetupCloseInfFile(infhandle);
217     DeleteFileA(inffile);
218 
219     /* Add the ServiceType */
220     strcat(inf, "ServiceType=1\n");
221     create_inf_file(inffile, inf);
222     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
223     SetLastError(0xdeadbeef);
224     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
225     ok(!ret, "Expected failure\n");
226     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
227        "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", (int)GetLastError());
228     SetupCloseInfFile(infhandle);
229     DeleteFileA(inffile);
230 
231     /* Add the StartType */
232     strcat(inf, "StartType=4\n");
233     create_inf_file(inffile, inf);
234     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
235     SetLastError(0xdeadbeef);
236     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
237     ok(!ret, "Expected failure\n");
238     ok(GetLastError() == ERROR_BAD_SERVICE_INSTALLSECT,
239        "Expected ERROR_BAD_SERVICE_INSTALLSECT, got %08x\n", (int)GetLastError());
240     SetupCloseInfFile(infhandle);
241     DeleteFileA(inffile);
242 
243     /* This should be it, the minimal entries to install a service */
244     strcat(inf, "ErrorControl=1");
245     create_inf_file(inffile, inf);
246     infhandle = SetupOpenInfFileA(path, NULL, INF_STYLE_WIN4, NULL);
247     SetLastError(0xdeadbeef);
248     ret = SetupDiInstallClassExA(NULL, path, DI_QUIETINSTALL, NULL, NULL, NULL,NULL);
249     if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
250     {
251         skip("Not enough rights to install the service\n");
252         SetupCloseInfFile(infhandle);
253         DeleteFileA(inffile);
254         return;
255     }
256     ok(ret, "Expected success\n");
257     ok(GetLastError() == ERROR_SUCCESS,
258         "Expected ERROR_SUCCESS, got %08x\n", (int)GetLastError());
259     SetupCloseInfFile(infhandle);
260     DeleteFileA(inffile);
261 
262     scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
263 
264     /* Open the service to see if it's really there */
265     svc_handle = OpenServiceA(scm_handle, "Reactostest", DELETE);
266     ok(svc_handle != NULL, "Service was not created\n");
267 
268     SetLastError(0xdeadbeef);
269     ret = DeleteService(svc_handle);
270     ok(ret, "Service could not be deleted : %d\n", (int)GetLastError());
271 
272     CloseServiceHandle(svc_handle);
273     CloseServiceHandle(scm_handle);
274 }
275 
276 
277 START_TEST(SetupDiInstallClassExA)
278 {
279     char temp_path[MAX_PATH], prev_path[MAX_PATH];
280     DWORD len;
281 
282     GetCurrentDirectoryA(MAX_PATH, prev_path);
283     GetTempPathA(MAX_PATH, temp_path);
284     SetCurrentDirectoryA(temp_path);
285 
286     strcpy(CURR_DIR, temp_path);
287     len = strlen(CURR_DIR);
288     if (len && (CURR_DIR[len - 1] == '\\'))
289         CURR_DIR[len - 1] = 0;
290 
291     test_SetupDiInstallClassExA();
292     SetCurrentDirectoryA(prev_path);
293 
294 }
295