// // Deferred Custom Action // // // CustomActionData: // <ierrordialog>|<hardware_id>|<inf_path>|<regpath>|<regvalue> // // NC_DLLSPEC UINT NC_CALLSPEC NcaMsiUpdateOrInstallPnpDevice(MSIHANDLE hInstall) { RUN_MODE_TRACE(hInstall); pMsiIncrementProgressBar(hInstall, 10); UINT uiReturn = 0; INT iErrorDlg = 0; LPCTSTR pszHardwareID = NULL; LPCTSTR pszInfPath = NULL; LPCTSTR pszRegPath = NULL; LPCTSTR pszRegValue = NULL; CADParser parser; parser.AddToken<INT>(iErrorDlg); parser.AddToken<LPCTSTR>(pszHardwareID); parser.AddToken<LPCTSTR>(pszInfPath); parser.AddToken<LPCTSTR>(pszRegPath); parser.AddToken<LPCTSTR>(pszRegValue); DWORD nTokens = parser.Parse(hInstall); if (parser.GetTokenCount() != nTokens) { MSILOGERR(_T("Cannot parse tokens")); return ERROR_INSTALL_FAILURE; } TCHAR szInstalledInf[MAX_PATH] = {0}; BOOL bRebootRequired = FALSE; BOOL fSuccess = FALSE; BOOL fUpdateExisting = FALSE; while (TRUE) { bRebootRequired = FALSE; // // Specifying INSTALLFLAG_FORCE will overwrite the // existing device driver with the current one // irrespective of existence of higher version // fUpdateExisting = NdasDiFindExistingDevice( NULL, pszHardwareID, FALSE); if (fUpdateExisting) { fSuccess = NdasDiUpdateDeviceDriver( NULL, pszInfPath, pszHardwareID, INSTALLFLAG_FORCE, &bRebootRequired); if (!fSuccess) { MSILOGERR_PROC(_T("NdasDiUpdateDeviceDriver")); } } else { MSILOGERR_PROC(_T("NdasDiFindExistingDevice")); fSuccess = NdasDiInstallRootEnumeratedDevice( NULL, pszInfPath, pszHardwareID, INSTALLFLAG_FORCE, &bRebootRequired); if (!fSuccess) { MSILOGERR_PROC(_T("NdasDiInstallRootEnumeratedDevice")); } } if (!fSuccess) { UINT uiResponse = pMsiErrorMessageBox(hInstall, iErrorDlg); // 0, IDABORT, IDRETRY, IDIGNORE if (IDABORT == uiResponse) { return ERROR_INSTALL_FAILURE; } else if (IDRETRY == uiResponse) { continue; } else if (IDIGNORE == uiResponse) { } } break; } if (bRebootRequired) { (void) pMsiScheduleRebootForDeferredCA(hInstall); } // // The following actions are non-critical ones // if (fSuccess) { // // set the registry value // if (!fUpdateExisting && _T('\0') != szInstalledInf[0]) { fSuccess = pSetInstalledPath( hInstall, HKEY_LOCAL_MACHINE, pszRegPath, pszRegValue, szInstalledInf); if (!fSuccess) { MSILOGERR_PROC(_T("pSetInstalledPath")); } } } return ERROR_SUCCESS; }
int pnpdevinst(int argc, LPTSTR *argv) { typedef enum { DEV_INSTALL, DEV_UPDATE, DEV_REMOVE, DEV_COPYINF, DEV_FIND, DEV_UNINSTALLINF } DEV_COMMAND_TYPE; struct { DEV_COMMAND_TYPE type; LPCTSTR cmd; int argc; BOOL op; } opts[] = { { DEV_INSTALL, L"install", 2, FALSE}, { DEV_UPDATE, L"update", 2, FALSE}, { DEV_REMOVE, L"remove", 1, TRUE}, { DEV_COPYINF, L"copyinf", 1, FALSE}, { DEV_FIND, L"find", 1, TRUE}, { DEV_UNINSTALLINF, L"uninstallinf", 1, FALSE} }; DEV_COMMAND_TYPE CmdType; const DWORD nopts = RTL_NUMBER_OF(opts); DWORD i = 0; for (; i < nopts; ++i) { if (lstrcmpi(opts[i].cmd, argv[0]) == 0) { if ((argc - 1) == opts[i].argc || (opts[i].op && (argc - 1) >= opts[i].argc)) { CmdType = opts[i].type; } else { _ftprintf(stderr, _T("Invalid command arguments.\n")); return 254; } break; } } if (i == nopts) { _ftprintf(stderr, _T("Invalid command.\n")); return 254; } BOOL bRebootRequired; BOOL bPresentOnly = TRUE; if (DEV_INSTALL == CmdType) { BOOL fSuccess = NdasDiInstallRootEnumeratedDevice( NULL, argv[1], argv[2], INSTALLFLAG_FORCE, &bRebootRequired); if (!fSuccess) { printErrorText(); return 255; } else { _ftprintf(stdout, _T("Installation is done.%s"), (bRebootRequired) ? _T(" Reboot required.") : _T("")); return (bRebootRequired) ? 1 : 0; } } else if (DEV_UPDATE == CmdType) { BOOL fSuccess = NdasDiUpdateDeviceDriver( NULL, argv[1], argv[2], INSTALLFLAG_FORCE, &bRebootRequired); if (!fSuccess) { printErrorText(); return 255; } else { _ftprintf(stdout, _T("Update is done.%s"), (bRebootRequired) ? _T(" Reboot required.") : _T("")); return (bRebootRequired) ? 1 : 0; } } else if (DEV_REMOVE == CmdType) { if (argc > 2 && 0 == lstrcmpi(argv[2], _T("all"))) { bPresentOnly = FALSE; } DWORD dwRemoved = 0; BOOL fSuccess = NdasDiRemoveDevice( NULL, argv[1], bPresentOnly, &dwRemoved, &bRebootRequired, RemoveErrorCallback, NULL); if (!fSuccess) { printErrorText(); return 255; } else { printErrorText(); _ftprintf(stdout, _T("Removal is done for %d devices.%s"), dwRemoved, (bRebootRequired) ? _T(" Reboot required.") : _T("")); return 0; } } else if (DEV_COPYINF == CmdType) { TCHAR szOemInf[MAX_PATH + 1]; BOOL fSuccess = NdasDiCopyOEMInf( argv[1], 0, szOemInf, MAX_PATH, NULL, NULL); if (!fSuccess) { printErrorText(); return 255; } else { _ftprintf(stdout, _T("Copied to %s\n"), szOemInf); return 0; } } else if (DEV_FIND == CmdType) { LPCTSTR szHardwareID = argv[1]; if (argc > 2 && 0 == lstrcmpi(argv[2], _T("all"))) { bPresentOnly = FALSE; } BOOL fSuccess = NdasDiFindExistingDevice( NULL, szHardwareID, bPresentOnly); if (!fSuccess) { if (ERROR_NO_MORE_ITEMS == GetLastError()) { _ftprintf(stdout, _T("Device not found.\n")); return 1; } else { printErrorText(); return 255; } } else { _ftprintf(stdout, _T("Device found.\n")); return 0; } } else if (DEV_UNINSTALLINF == CmdType) { size_t cchHardwareIDs = ::lstrlen(argv[1]) + 2; // plus additional null LPTSTR mszHardwareIDs = (LPTSTR) ::HeapAlloc( ::GetProcessHeap(), HEAP_ZERO_MEMORY, cchHardwareIDs * sizeof(TCHAR)); _ASSERTE(NULL != mszHardwareIDs); HRESULT hr = ::StringCchCopy(mszHardwareIDs, cchHardwareIDs, argv[1]); _ASSERTE(SUCCEEDED(hr)); // replaces , to _T('\0') PTCHAR pch = mszHardwareIDs; for (size_t i = 0; i < cchHardwareIDs; ++i, ++pch) { if (_T(',') == *pch) { *pch = _T('\0'); } } _tprintf(_T("%s\n"), mszHardwareIDs); BOOL fSuccess = NdasDiDeleteOEMInf( _T("oem*.inf"), mszHardwareIDs, 0x0001, DeleteOEMInfCallback, NULL); ::HeapFree(::GetProcessHeap(), 0, mszHardwareIDs); return 0; } else { _ftprintf(stderr, _T("Unknown command.\n")); return 254; } }