Changeset 86782 in vbox for trunk/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.cpp
- Timestamp:
- Nov 2, 2020 4:31:41 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Installer/win/InstallHelper/VBoxInstallHelper.cpp
r86777 r86782 144 144 145 145 /** 146 * Tries to retrieve the Python installation path on the system. 146 * Waits for a started process to terminate. 147 * 148 * @returns VBox status code. 149 * @param Process Handle of process to wait for. 150 * @param msTimeout Timeout (in ms) to wait for process to terminate. 151 * @param pProcSts Pointer to process status on return. 152 */ 153 static int procWait(RTPROCESS Process, RTMSINTERVAL msTimeout, PRTPROCSTATUS pProcSts) 154 { 155 uint64_t tsStartMs = RTTimeMilliTS(); 156 157 while (RTTimeMilliTS() - tsStartMs <= msTimeout) 158 { 159 int rc = RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, pProcSts); 160 if (rc == VERR_PROCESS_RUNNING) 161 continue; 162 else if (RT_FAILURE(rc)) 163 return rc; 164 165 if ( pProcSts->iStatus != 0 166 || pProcSts->enmReason != RTPROCEXITREASON_NORMAL) 167 { 168 rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */ 169 } 170 171 return VINF_SUCCESS; 172 } 173 174 return VERR_TIMEOUT; 175 } 176 177 /** 178 * Runs an executable on the OS. 179 * 180 * @returns VBox status code. 181 * @param hModule Windows installer module handle. 182 * @param pcsExe Absolute path of executable to run. 183 * @param papcszArgs Pointer to command line arguments to use for calling the executable. 184 * @param cArgs Number of command line arguments in \a papcszArgs. 185 */ 186 static int procRun(MSIHANDLE hModule, const char *pcszImage, const char **papcszArgs, size_t cArgs) 187 { 188 RT_NOREF(cArgs); 189 190 RTPROCESS Process; 191 RT_ZERO(Process); 192 193 uint32_t fProcess = 0; 194 #ifndef DEBUG 195 fProcess |= RTPROC_FLAGS_HIDDEN; 196 #endif 197 198 int rc = RTProcCreate(pcszImage, papcszArgs, RTENV_DEFAULT, fProcess, &Process); 199 if (RT_SUCCESS(rc)) 200 { 201 RTPROCSTATUS ProcSts; 202 RT_ZERO(ProcSts); 203 204 rc = procWait(Process, RT_MS_30SEC, &ProcSts); 205 206 if (RT_FAILURE(rc)) 207 logStringF(hModule, "procRun: Waiting for process \"%s\" failed with %Rrc (process status: %d, reason: %d)\n", 208 pcszImage, rc, ProcSts.iStatus, ProcSts.enmReason); 209 } 210 else 211 logStringF(hModule, "procRun: Creating process for \"%s\" failed with %Rrc\n", pcszImage, rc); 212 213 return rc; 214 } 215 216 /** 217 * Tries to retrieve the Python installation path on the system, extended version. 147 218 * 148 219 * @returns VBox status code. … … 152 223 * Must be free'd by the caller using RTStrFree(). 153 224 */ 154 static int getPythonPath (MSIHANDLE hModule, HKEY hKeyRoot, char **ppszPath)225 static int getPythonPathEx(MSIHANDLE hModule, HKEY hKeyRoot, char **ppszPath) 155 226 { 156 227 HKEY hkPythonCore = NULL; … … 194 265 dwErr = RegQueryValueExW(hkPythonInstPath, L"", NULL, &dwKeyType, (LPBYTE)wszVal, &dwKey); 195 266 if (dwErr == ERROR_SUCCESS) 196 logStringF(hModule, " InstallPythonAPI: Path \"%ls\" found.", wszVal);267 logStringF(hModule, "getPythonPath: Path \"%ls\" found.", wszVal); 197 268 198 269 if (pszPythonPath) /* Free former path, if any. */ … … 207 278 if (!RTPathExists(pszPythonPath)) 208 279 { 209 logStringF(hModule, " InstallPythonAPI: Warning: Path \"%s\" does not exist, skipping.", wszVal);280 logStringF(hModule, "getPythonPath: Warning: Defined path \"%s\" does not exist, skipping.", wszVal); 210 281 rc = VERR_PATH_NOT_FOUND; 211 282 } … … 227 298 228 299 /** 229 * Waits for a started process to terminate.300 * Retrieves the absolute path of the Python installation. 230 301 * 231 302 * @returns VBox status code. 232 * @param Process Handle of process to wait for.233 * @param msTimeout Timeout (in ms) to wait for process to terminate.234 * @param pProcSts Pointer to process status on return.303 * @param hModule Windows installer module handle. 304 * @param ppszPath Where to store the absolute path of the Python installation. 305 * Must be free'd by the caller. 235 306 */ 236 int procWait(RTPROCESS Process, RTMSINTERVAL msTimeout, PRTPROCSTATUS pProcSts) 237 { 238 uint64_t tsStartMs = RTTimeMilliTS(); 239 240 while (RTTimeMilliTS() - tsStartMs <= msTimeout) 241 { 242 int rc = RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, pProcSts); 243 if (rc == VERR_PROCESS_RUNNING) 244 continue; 245 else if (RT_FAILURE(rc)) 246 return rc; 247 248 if ( pProcSts->iStatus != 0 249 || pProcSts->enmReason != RTPROCEXITREASON_NORMAL) 250 { 251 rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */ 252 } 253 254 return VINF_SUCCESS; 255 } 256 257 return VERR_TIMEOUT; 307 static int getPythonPath(MSIHANDLE hModule, char **ppszPath) 308 { 309 int rc = getPythonPathEx(hModule, HKEY_LOCAL_MACHINE, ppszPath); 310 if (RT_FAILURE(rc)) 311 rc = getPythonPathEx(hModule, HKEY_CURRENT_USER, ppszPath); 312 313 return rc; 314 } 315 316 /** 317 * Retrieves the absolute path of the Python executable. 318 * 319 * @returns VBox status code. 320 * @param hModule Windows installer module handle. 321 * @param ppszPythonExe Where to store the absolute path of the Python executable. 322 * Must be free'd by the caller. 323 */ 324 static int getPythonExe(MSIHANDLE hModule, char **ppszPythonExe) 325 { 326 int rc = getPythonPath(hModule, ppszPythonExe); 327 if (RT_SUCCESS(rc)) 328 rc = RTStrAAppend(ppszPythonExe, "python.exe"); /** @todo Can this change? */ 329 330 return rc; 331 } 332 333 /** 334 * Checks if all dependencies for running the VBox Python API bindings are met. 335 * 336 * @returns VBox status code, or error if depedencies are not met. 337 * @param hModule Windows installer module handle. 338 * @param pcszPythonExe Path to Python interpreter image (.exe). 339 */ 340 static int checkPythonDependencies(MSIHANDLE hModule, const char *pcszPythonExe) 341 { 342 /* 343 * Check if importing the win32api module works. 344 * This is a prerequisite for setting up the VBox API. 345 */ 346 logStringF(hModule, "checkPythonDependencies: Checking for win32api extensions ..."); 347 348 const char *papszArgs[4] = { pcszPythonExe, "-c", "import win32api", NULL}; 349 350 int rc = procRun(hModule, pcszPythonExe, papszArgs, RT_ELEMENTS(papszArgs)); 351 if (RT_SUCCESS(rc)) 352 { 353 logStringF(hModule, "checkPythonDependencies: win32api found\n"); 354 } 355 else 356 logStringF(hModule, "checkPythonDependencies: Importing win32api failed with %Rrc\n", rc); 357 358 return rc; 258 359 } 259 360 … … 272 373 { 273 374 char *pszPythonPath; 274 int rc = getPythonPath(hModule, HKEY_LOCAL_MACHINE, &pszPythonPath); 275 if (RT_FAILURE(rc)) 276 rc = getPythonPath(hModule, HKEY_CURRENT_USER, &pszPythonPath); 277 375 int rc = getPythonPath(hModule, &pszPythonPath); 278 376 if (RT_SUCCESS(rc)) 279 377 { … … 296 394 logStringF(hModule, "IsPythonInstalled: Error: No suitable Python installation found (%Rrc), skipping installation.", rc); 297 395 396 if (RT_FAILURE(rc)) 397 logStringF(hModule, "IsPythonInstalled: Python seems not to be installed (%Rrc); please download + install the Python Core package.", rc); 398 298 399 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_INSTALLED", RT_SUCCESS(rc) ? L"1" : L"0"); 400 401 return ERROR_SUCCESS; /* Never return failure. */ 402 } 403 404 /** 405 * Checks if all dependencies for running the VBox Python API bindings are met. 406 * 407 * Called from the MSI installer as custom action. 408 * 409 * @returns Always ERROR_SUCCESS. 410 * Sets public property VBOX_PYTHON_DEPS_INSTALLED to "0" (false) or "1" (success). 411 * 412 * @param hModule Windows installer module handle. 413 */ 414 UINT __stdcall ArePythonAPIDepsInstalled(MSIHANDLE hModule) 415 { 416 char *pszPythonExe; 417 int rc = getPythonExe(hModule, &pszPythonExe); 418 if (RT_SUCCESS(rc)) 419 { 420 rc = checkPythonDependencies(hModule, pszPythonExe); 421 if (RT_SUCCESS(rc)) 422 logStringF(hModule, "ArePythonAPIDepsInstalled: Dependencies look good.\n"); 423 424 RTStrFree(pszPythonExe); 425 } 426 427 if (RT_FAILURE(rc)) 428 logStringF(hModule, "ArePythonAPIDepsInstalled: Failed with %Rrc\n", rc); 429 430 VBoxSetMsiProp(hModule, L"VBOX_PYTHON_DEPS_INSTALLED", RT_SUCCESS(rc) ? L"1" : L"0"); 299 431 300 432 return ERROR_SUCCESS; /* Never return failure. */ … … 315 447 logStringF(hModule, "InstallPythonAPI: Checking for installed Python environment(s) ..."); 316 448 317 char *pszPython Path;318 int rc = getPython Path(hModule, HKEY_LOCAL_MACHINE, &pszPythonPath);449 char *pszPythonExe; 450 int rc = getPythonExe(hModule, &pszPythonExe); 319 451 if (RT_FAILURE(rc)) 320 rc = getPythonPath(hModule, HKEY_CURRENT_USER, &pszPythonPath);321 322 if (RT_FAILURE(rc))323 452 { 324 453 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", L"0"); 325 326 logStringF(hModule, "InstallPythonAPI: Python seems not to be installed (%Rrc); please download + install the Python Core package.", rc);327 454 return ERROR_SUCCESS; 328 }329 330 logStringF(hModule, "InstallPythonAPI: Python installation found at \"%s\".", pszPythonPath);331 logStringF(hModule, "InstallPythonAPI: Checking for win32api extensions ...");332 333 uint32_t fProcess = 0;334 #ifndef DEBUG335 fProcess |= RTPROC_FLAGS_HIDDEN;336 #endif337 338 char szPythonPath[RTPATH_MAX] = { 0 };339 rc = RTPathAppend(szPythonPath, sizeof(szPythonPath), pszPythonPath);340 if (RT_SUCCESS(rc))341 {342 rc = RTPathAppend(szPythonPath, sizeof(szPythonPath), "python.exe");343 if (RT_SUCCESS(rc))344 {345 /*346 * Check if importing the win32api module works.347 * This is a prerequisite for setting up the VBox API.348 */349 RTPROCESS Process;350 RT_ZERO(Process);351 const char *papszArgs[4] = { szPythonPath, "-c", "import win32api", NULL};352 rc = RTProcCreate(szPythonPath, papszArgs, RTENV_DEFAULT, fProcess, &Process);353 if (RT_SUCCESS(rc))354 {355 RTPROCSTATUS ProcSts;356 rc = procWait(Process, RT_MS_30SEC, &ProcSts);357 if (RT_FAILURE(rc))358 logStringF(hModule, "InstallPythonAPI: Importing the win32api failed with %d (exit reason: %d)\n",359 ProcSts.iStatus, ProcSts.enmReason);360 }361 }362 455 } 363 456 … … 365 458 * Set up the VBox API. 366 459 */ 460 /* Get the VBox API setup string. */ 461 char *pszVBoxSDKPath; 462 rc = VBoxGetMsiPropUtf8(hModule, "CustomActionData", &pszVBoxSDKPath); 367 463 if (RT_SUCCESS(rc)) 368 464 { 369 /* Get the VBox API setup string. */ 370 char *pszVBoxSDKPath; 371 rc = VBoxGetMsiPropUtf8(hModule, "CustomActionData", &pszVBoxSDKPath); 465 /* Make sure our current working directory is the VBox installation path. */ 466 rc = RTPathSetCurrent(pszVBoxSDKPath); 372 467 if (RT_SUCCESS(rc)) 373 468 { 374 /* Make sure our current working directory is the VBox installation path. */375 rc = RT PathSetCurrent(pszVBoxSDKPath);469 /* Set required environment variables. */ 470 rc = RTEnvSet("VBOX_INSTALL_PATH", pszVBoxSDKPath); 376 471 if (RT_SUCCESS(rc)) 377 472 { 378 /* Set required environment variables. */ 379 rc = RTEnvSet("VBOX_INSTALL_PATH", pszVBoxSDKPath); 473 logStringF(hModule, "InstallPythonAPI: Invoking vboxapisetup.py in \"%s\" ...\n", pszVBoxSDKPath); 474 475 const char *papszArgs[4] = { pszPythonExe, "vboxapisetup.py", "install", NULL}; 476 477 rc = procRun(hModule, pszPythonExe, papszArgs, RT_ELEMENTS(papszArgs)); 380 478 if (RT_SUCCESS(rc)) 381 { 382 RTPROCSTATUS ProcSts; 383 RT_ZERO(ProcSts); 384 385 logStringF(hModule, "InstallPythonAPI: Invoking vboxapisetup.py in \"%s\" ...\n", pszVBoxSDKPath); 386 387 RTPROCESS Process; 388 RT_ZERO(Process); 389 const char *papszArgs[4] = { szPythonPath, "vboxapisetup.py", "install", NULL}; 390 rc = RTProcCreate(szPythonPath, papszArgs, RTENV_DEFAULT, fProcess, &Process); 391 if (RT_SUCCESS(rc)) 392 { 393 rc = procWait(Process, RT_MS_30SEC, &ProcSts); 394 if (RT_SUCCESS(rc)) 395 logStringF(hModule, "InstallPythonAPI: Installation of vboxapisetup.py successful\n"); 396 } 397 398 if (RT_FAILURE(rc)) 399 logStringF(hModule, "InstallPythonAPI: Calling vboxapisetup.py failed with %Rrc (process status: %d, exit reason: %d)\n", 400 rc, ProcSts.iStatus, ProcSts.enmReason); 401 } 402 else 403 logStringF(hModule, "InstallPythonAPI: Could set environment variable VBOX_INSTALL_PATH, rc=%Rrc\n", rc); 479 logStringF(hModule, "InstallPythonAPI: Installation of vboxapisetup.py successful\n"); 480 481 if (RT_FAILURE(rc)) 482 logStringF(hModule, "InstallPythonAPI: Calling vboxapisetup.py failed with %Rrc\n", rc); 404 483 } 405 484 else 406 logStringF(hModule, "InstallPythonAPI: Could set working directory to \"%s\", rc=%Rrc\n", pszVBoxSDKPath, rc); 407 408 RTStrFree(pszVBoxSDKPath); 485 logStringF(hModule, "InstallPythonAPI: Could set environment variable VBOX_INSTALL_PATH, rc=%Rrc\n", rc); 409 486 } 410 487 else 411 logStringF(hModule, "InstallPythonAPI: Unable to retrieve VBox installation directory, rc=%Rrc\n", rc); 412 } 488 logStringF(hModule, "InstallPythonAPI: Could set working directory to \"%s\", rc=%Rrc\n", pszVBoxSDKPath, rc); 489 490 RTStrFree(pszVBoxSDKPath); 491 } 492 else 493 logStringF(hModule, "InstallPythonAPI: Unable to retrieve VBox installation directory, rc=%Rrc\n", rc); 413 494 414 495 /* … … 419 500 logStringF(hModule, "InstallPythonAPI: Validating VBox API ...\n"); 420 501 421 RTPROCSTATUS ProcSts; 422 RT_ZERO(ProcSts); 423 424 RTPROCESS Process; 425 RT_ZERO(Process); 426 const char *papszArgs[4] = { szPythonPath, "-c", "from vboxapi import VirtualBoxManager", NULL}; 427 rc = RTProcCreate(szPythonPath, papszArgs, RTENV_DEFAULT, fProcess, &Process); 502 const char *papszArgs[4] = { pszPythonExe, "-c", "from vboxapi import VirtualBoxManager", NULL}; 503 504 rc = procRun(hModule, pszPythonExe, papszArgs, RT_ELEMENTS(papszArgs)); 428 505 if (RT_SUCCESS(rc)) 429 { 430 rc = procWait(Process, RT_MS_30SEC, &ProcSts); 431 if (RT_SUCCESS(rc)) 432 logStringF(hModule, "InstallPythonAPI: VBox API looks good.\n"); 433 } 506 logStringF(hModule, "InstallPythonAPI: VBox API looks good.\n"); 434 507 435 508 if (RT_FAILURE(rc)) 436 logStringF(hModule, "InstallPythonAPI: Validating VBox API failed with %Rrc (process status: %d, exit reason: %d)\n", 437 rc, ProcSts.iStatus, ProcSts.enmReason); 438 } 439 440 RTStrFree(pszPythonPath); 509 logStringF(hModule, "InstallPythonAPI: Validating VBox API failed with %Rrc\n", rc); 510 } 511 512 RTStrFree(pszPythonExe); 441 513 442 514 VBoxSetMsiProp(hModule, L"VBOX_API_INSTALLED", RT_SUCCESS(rc) ? L"1" : L"0");
Note:
See TracChangeset
for help on using the changeset viewer.