1 /* 2 * Unit tests for advpack.dll install functions 3 * 4 * Copyright (C) 2006 James Hawkins 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #define WIN32_NO_STATUS 22 #define _INC_WINDOWS 23 #define COM_NO_WINDOWS_H 24 25 #include <stdio.h> 26 #include <windef.h> 27 #include <winbase.h> 28 #include <winreg.h> 29 #include <objbase.h> 30 #include <advpub.h> 31 #include <wine/test.h> 32 33 static HMODULE hAdvPack; 34 /* function pointers */ 35 static HRESULT (WINAPI *pRunSetupCommand)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, HANDLE*, DWORD, LPVOID); 36 static HRESULT (WINAPI *pLaunchINFSection)(HWND, HINSTANCE, LPSTR, INT); 37 static HRESULT (WINAPI *pLaunchINFSectionEx)(HWND, HINSTANCE, LPSTR, INT); 38 39 static char CURR_DIR[MAX_PATH]; 40 41 static BOOL init_function_pointers(void) 42 { 43 hAdvPack = LoadLibraryA("advpack.dll"); 44 if (!hAdvPack) 45 return FALSE; 46 47 pRunSetupCommand = (void *)GetProcAddress(hAdvPack, "RunSetupCommand"); 48 pLaunchINFSection = (void *)GetProcAddress(hAdvPack, "LaunchINFSection"); 49 pLaunchINFSectionEx = (void *)GetProcAddress(hAdvPack, "LaunchINFSectionEx"); 50 51 if (!pRunSetupCommand || !pLaunchINFSection || !pLaunchINFSectionEx) 52 return FALSE; 53 54 return TRUE; 55 } 56 57 static BOOL is_spapi_err(DWORD err) 58 { 59 const DWORD SPAPI_PREFIX = 0x800F0000L; 60 const DWORD SPAPI_MASK = 0xFFFF0000L; 61 62 return (((err & SPAPI_MASK) ^ SPAPI_PREFIX) == 0); 63 } 64 65 static void create_inf_file(LPCSTR filename) 66 { 67 DWORD dwNumberOfBytesWritten; 68 HANDLE hf = CreateFileA(filename, GENERIC_WRITE, 0, NULL, 69 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 70 71 static const char data[] = 72 "[Version]\n" 73 "Signature=\"$Chicago$\"\n" 74 "AdvancedINF=2.5\n" 75 "[DefaultInstall]\n" 76 "CheckAdminRights=1\n"; 77 78 WriteFile(hf, data, sizeof(data) - 1, &dwNumberOfBytesWritten, NULL); 79 CloseHandle(hf); 80 } 81 82 static void test_RunSetupCommand(void) 83 { 84 HRESULT hr; 85 HANDLE hexe; 86 char path[MAX_PATH]; 87 char dir[MAX_PATH]; 88 char systemdir[MAX_PATH]; 89 90 GetSystemDirectoryA(systemdir, sizeof(systemdir)); 91 92 /* try an invalid cmd name */ 93 hr = pRunSetupCommand(NULL, NULL, "Install", "Dir", "Title", NULL, 0, NULL); 94 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %d\n", hr); 95 96 /* try an invalid directory */ 97 hr = pRunSetupCommand(NULL, "winver.exe", "Install", NULL, "Title", NULL, 0, NULL); 98 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %d\n", hr); 99 100 /* try to run a nonexistent exe */ 101 hexe = (HANDLE)0xdeadbeef; 102 hr = pRunSetupCommand(NULL, "idontexist.exe", "Install", systemdir, "Title", &hexe, 0, NULL); 103 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), 104 "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %d\n", hr); 105 ok(hexe == NULL, "Expected hexe to be NULL\n"); 106 ok(!TerminateProcess(hexe, 0), "Expected TerminateProcess to fail\n"); 107 108 /* try a bad directory */ 109 hexe = (HANDLE)0xdeadbeef; 110 hr = pRunSetupCommand(NULL, "winver.exe", "Install", "non\\existent\\directory", "Title", &hexe, 0, NULL); 111 ok(hr == HRESULT_FROM_WIN32(ERROR_DIRECTORY), 112 "Expected HRESULT_FROM_WIN32(ERROR_DIRECTORY), got %d\n", hr); 113 ok(hexe == NULL, "Expected hexe to be NULL\n"); 114 ok(!TerminateProcess(hexe, 0), "Expected TerminateProcess to fail\n"); 115 116 /* try to run an exe with the RSC_FLAG_INF flag */ 117 hexe = (HANDLE)0xdeadbeef; 118 hr = pRunSetupCommand(NULL, "winver.exe", "Install", systemdir, "Title", &hexe, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 119 ok(is_spapi_err(hr), "Expected a setupapi error, got %d\n", hr); 120 ok(hexe == (HANDLE)0xdeadbeef, "Expected hexe to be 0xdeadbeef\n"); 121 ok(!TerminateProcess(hexe, 0), "Expected TerminateProcess to fail\n"); 122 123 /* run winver.exe */ 124 hexe = (HANDLE)0xdeadbeef; 125 hr = pRunSetupCommand(NULL, "winver.exe", "Install", systemdir, "Title", &hexe, 0, NULL); 126 ok(hr == S_ASYNCHRONOUS, "Expected S_ASYNCHRONOUS, got %d\n", hr); 127 ok(hexe != NULL, "Expected hexe to be non-NULL\n"); 128 ok(TerminateProcess(hexe, 0), "Expected TerminateProcess to succeed\n"); 129 130 CreateDirectoryA("one", NULL); 131 create_inf_file("one\\test.inf"); 132 133 /* try a full path to the INF, with working dir provided */ 134 lstrcpyA(path, CURR_DIR); 135 lstrcatA(path, "\\one\\test.inf"); 136 lstrcpyA(dir, CURR_DIR); 137 lstrcatA(dir, "\\one"); 138 hr = pRunSetupCommand(NULL, path, "DefaultInstall", dir, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 139 ok(hr == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", hr); 140 141 /* try a full path to the INF, NULL working dir */ 142 hr = pRunSetupCommand(NULL, path, "DefaultInstall", NULL, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 143 ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), 144 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %d\n", hr); 145 146 /* try a full path to the INF, empty working dir */ 147 hr = pRunSetupCommand(NULL, path, "DefaultInstall", "", "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 148 ok(hr == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", hr); 149 150 /* try a relative path to the INF, with working dir provided */ 151 hr = pRunSetupCommand(NULL, "one\\test.inf", "DefaultInstall", dir, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 152 ok(hr == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", hr); 153 154 /* try a relative path to the INF, NULL working dir */ 155 hr = pRunSetupCommand(NULL, "one\\test.inf", "DefaultInstall", NULL, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 156 ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), 157 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %d\n", hr); 158 159 /* try a relative path to the INF, empty working dir */ 160 hr = pRunSetupCommand(NULL, "one\\test.inf", "DefaultInstall", "", "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 161 ok(hr == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", hr); 162 163 /* try only the INF filename, with working dir provided */ 164 hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", dir, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 165 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %d\n", hr); 166 167 /* try only the INF filename, NULL working dir */ 168 hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", NULL, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 169 ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), 170 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %d\n", hr); 171 172 /* try only the INF filename, empty working dir */ 173 hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", "", "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 174 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %d\n", hr); 175 176 DeleteFileA("one\\test.inf"); 177 RemoveDirectoryA("one"); 178 179 create_inf_file("test.inf"); 180 181 /* try INF file in the current directory, working directory provided */ 182 hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", CURR_DIR, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 183 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %d\n", hr); 184 185 /* try INF file in the current directory, NULL working directory */ 186 hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", NULL, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 187 ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), 188 "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %d\n", hr); 189 190 /* try INF file in the current directory, empty working directory */ 191 hr = pRunSetupCommand(NULL, "test.inf", "DefaultInstall", CURR_DIR, "Title", NULL, RSC_FLAG_INF | RSC_FLAG_QUIET, NULL); 192 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Expected HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), got %d\n", hr); 193 } 194 195 static void test_LaunchINFSection(void) 196 { 197 HRESULT hr; 198 char cmdline[MAX_PATH]; 199 static char file[] = "test.inf,DefaultInstall,4,0"; 200 static char file2[] = "test.inf,,1,0"; 201 202 /* The 'No UI' flag seems to have no effect whatsoever on Windows. 203 * So only do this test in interactive mode. 204 */ 205 if (winetest_interactive) 206 { 207 /* try an invalid cmdline */ 208 hr = pLaunchINFSection(NULL, NULL, NULL, 0); 209 ok(hr == 1, "Expected 1, got %d\n", hr); 210 } 211 212 CreateDirectoryA("one", NULL); 213 create_inf_file("one\\test.inf"); 214 215 /* try a full path to the INF */ 216 lstrcpyA(cmdline, CURR_DIR); 217 lstrcatA(cmdline, "\\"); 218 lstrcatA(cmdline, "one\\test.inf,DefaultInstall,,4"); 219 hr = pLaunchINFSection(NULL, NULL, cmdline, 0); 220 ok(hr == 0, "Expected 0, got %d\n", hr); 221 222 DeleteFileA("one\\test.inf"); 223 RemoveDirectoryA("one"); 224 225 create_inf_file("test.inf"); 226 227 /* try just the INF filename */ 228 hr = pLaunchINFSection(NULL, NULL, file, 0); 229 ok(hr == 0, "Expected 0, got %d\n", hr); 230 231 hr = pLaunchINFSection(NULL, NULL, file2, 0); 232 ok(hr == 0, "Expected 0, got %d\n", hr); 233 234 DeleteFileA("test.inf"); 235 } 236 237 static void test_LaunchINFSectionEx(void) 238 { 239 HRESULT hr; 240 char cmdline[MAX_PATH]; 241 242 create_inf_file("test.inf"); 243 244 /* try an invalid CAB filename with an absolute INF name */ 245 lstrcpyA(cmdline, CURR_DIR); 246 lstrcatA(cmdline, "\\"); 247 lstrcatA(cmdline, "test.inf,DefaultInstall,c:imacab.cab,4"); 248 hr = pLaunchINFSectionEx(NULL, NULL, cmdline, 0); 249 ok(hr == 0, "Expected 0, got %d\n", hr); 250 251 /* try quoting the parameters */ 252 lstrcpyA(cmdline, "\""); 253 lstrcatA(cmdline, CURR_DIR); 254 lstrcatA(cmdline, "\\test.inf\",\"DefaultInstall\",\"c:,imacab.cab\",\"4\""); 255 hr = pLaunchINFSectionEx(NULL, NULL, cmdline, 0); 256 ok(hr == 0, "Expected 0, got %d\n", hr); 257 258 /* The 'No UI' flag seems to have no effect whatsoever on Windows. 259 * So only do this test in interactive mode. 260 */ 261 if (winetest_interactive) 262 { 263 /* try an invalid CAB filename with a relative INF name */ 264 lstrcpyA(cmdline, "test.inf,DefaultInstall,c:imacab.cab,4"); 265 hr = pLaunchINFSectionEx(NULL, NULL, cmdline, 0); 266 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %d\n", hr); 267 } 268 269 DeleteFileA("test.inf"); 270 } 271 272 START_TEST(install) 273 { 274 DWORD len; 275 char temp_path[MAX_PATH], prev_path[MAX_PATH]; 276 277 if (!init_function_pointers()) 278 return; 279 280 if (!IsNTAdmin(0, NULL)) 281 { 282 skip("Most tests need admin rights\n"); 283 return; 284 } 285 286 GetCurrentDirectoryA(MAX_PATH, prev_path); 287 GetTempPathA(MAX_PATH, temp_path); 288 SetCurrentDirectoryA(temp_path); 289 290 lstrcpyA(CURR_DIR, temp_path); 291 len = lstrlenA(CURR_DIR); 292 293 if(len && (CURR_DIR[len - 1] == '\\')) 294 CURR_DIR[len - 1] = 0; 295 296 test_RunSetupCommand(); 297 test_LaunchINFSection(); 298 test_LaunchINFSectionEx(); 299 300 FreeLibrary(hAdvPack); 301 SetCurrentDirectoryA(prev_path); 302 } 303