/* Copyright © 1991-2021 Amebis This file is part of MSICA. MSICA is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. MSICA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with MSICA. If not, see . */ #include "pch.h" //////////////////////////////////////////////////////////////////////////// // Local constants //////////////////////////////////////////////////////////////////////////// #define MSICA_CERT_TICK_SIZE ( 4*1024) #define MSICA_SVC_SET_START_TICK_SIZE ( 1*1024) #define MSICA_SVC_START_TICK_SIZE ( 1*1024) #define MSICA_SVC_STOP_TICK_SIZE ( 1*1024) #define MSICA_TASK_TICK_SIZE (16*1024) #define MSICA_WLAN_PROFILE_TICK_SIZE ( 2*1024) //////////////////////////////////////////////////////////////////////////// // WLAN API //////////////////////////////////////////////////////////////////////////// static HMODULE hWlanapi = NULL; VOID (WINAPI *pfnWlanFreeMemory)(__in PVOID pMemory) = NULL; DWORD (WINAPI *pfnWlanOpenHandle)(__in DWORD dwClientVersion, __reserved PVOID pReserved, __out PDWORD pdwNegotiatedVersion, __out PHANDLE phClientHandle) = NULL; DWORD (WINAPI *pfnWlanCloseHandle)(__in HANDLE hClientHandle, __reserved PVOID pReserved) = NULL; DWORD (WINAPI *pfnWlanEnumInterfaces)(__in HANDLE hClientHandle, __reserved PVOID pReserved, __deref_out PWLAN_INTERFACE_INFO_LIST *ppInterfaceList) = NULL; DWORD (WINAPI *pfnWlanGetProfile)(__in HANDLE hClientHandle, __in CONST GUID *pInterfaceGuid, __in LPCWSTR strProfileName, __reserved PVOID pReserved, __deref_out LPWSTR *pstrProfileXml, __inout_opt DWORD *pdwFlags, __out_opt DWORD *pdwGrantedAccess) = NULL; DWORD (WINAPI *pfnWlanDeleteProfile)(__in HANDLE hClientHandle, __in CONST GUID *pInterfaceGuid, __in LPCWSTR strProfileName, __reserved PVOID pReserved) = NULL; DWORD (WINAPI *pfnWlanSetProfile)(__in HANDLE hClientHandle, __in CONST GUID *pInterfaceGuid, __in DWORD dwFlags, __in LPCWSTR strProfileXml, __in_opt LPCWSTR strAllUserProfileSecurity, __in BOOL bOverwrite, __reserved PVOID pReserved, __out DWORD *pdwReasonCode) = NULL; DWORD (WINAPI *pfnWlanReasonCodeToString)(__in DWORD dwReasonCode, __in DWORD dwBufferSize, __in_ecount(dwBufferSize) PWCHAR pStringBuffer, __reserved PVOID pReserved) = NULL; //////////////////////////////////////////////////////////////////////////// // Global functions //////////////////////////////////////////////////////////////////////////// extern "C" BOOL WINAPI DllMain(_In_ HINSTANCE hInstance, _In_ DWORD dwReason, _In_ LPVOID pReserved) { UNREFERENCED_PARAMETER(hInstance); UNREFERENCED_PARAMETER(pReserved); if (dwReason == DLL_PROCESS_ATTACH) { // Load Wlanapi.dll hWlanapi = ::LoadLibrary(_T("Wlanapi.dll")); if (hWlanapi) { pfnWlanFreeMemory = (VOID (WINAPI*)(PVOID)) ::GetProcAddress(hWlanapi, "pfnWlanFreeMemory" ); pfnWlanOpenHandle = (DWORD(WINAPI*)(DWORD, PVOID, PDWORD, PHANDLE)) ::GetProcAddress(hWlanapi, "pfnWlanOpenHandle" ); pfnWlanCloseHandle = (DWORD(WINAPI*)(HANDLE, PVOID)) ::GetProcAddress(hWlanapi, "pfnWlanCloseHandle" ); pfnWlanEnumInterfaces = (DWORD(WINAPI*)(HANDLE, PVOID, PWLAN_INTERFACE_INFO_LIST*)) ::GetProcAddress(hWlanapi, "pfnWlanEnumInterfaces" ); pfnWlanGetProfile = (DWORD(WINAPI*)(HANDLE, CONST GUID*, LPCWSTR, PVOID, LPWSTR*, DWORD*, DWORD*)) ::GetProcAddress(hWlanapi, "pfnWlanGetProfile" ); pfnWlanDeleteProfile = (DWORD(WINAPI*)(HANDLE, CONST GUID*, LPCWSTR, PVOID)) ::GetProcAddress(hWlanapi, "pfnWlanDeleteProfile" ); pfnWlanSetProfile = (DWORD(WINAPI*)(HANDLE, CONST GUID*, DWORD, LPCWSTR, LPCWSTR, BOOL, PVOID, DWORD*))::GetProcAddress(hWlanapi, "pfnWlanSetProfile" ); pfnWlanReasonCodeToString = (DWORD(WINAPI*)(DWORD, DWORD, PWCHAR, PVOID)) ::GetProcAddress(hWlanapi, "pfnWlanReasonCodeToString"); } } else if (dwReason == DLL_PROCESS_DETACH) { if (hWlanapi) ::FreeLibrary(hWlanapi); } return TRUE; } //////////////////////////////////////////////////////////////////// // Exported functions //////////////////////////////////////////////////////////////////// UINT __declspec(dllexport) MSICAInitialize(MSIHANDLE hInstall) { //::MessageBox(NULL, _T(__FUNCTION__), _T("MSICA"), MB_OK); UINT uiResult; winstd::com_initializer com_init(NULL); MSICA::COpList olInstallCertificates, olRemoveCertificates, olInstallWLANProfiles, olRemoveWLANProfiles, olInstallScheduledTask, olRemoveScheduledTask, olStopServices, olSetServiceStarts, olStartServices; BOOL bRollbackEnabled; PMSIHANDLE hDatabase, hRecordProg = ::MsiCreateRecord(3); winstd::tstring sValue; // Check and add the rollback enabled state. uiResult = ::MsiGetProperty(hInstall, _T("RollbackDisabled"), sValue); bRollbackEnabled = uiResult == NO_ERROR ? _ttoi(sValue.c_str()) || !sValue.empty() && _totlower(sValue[0]) == _T('y') ? FALSE : TRUE : TRUE; olRemoveScheduledTask.push_back(new MSICA::COpRollbackEnable(bRollbackEnabled)); olStopServices.push_back(new MSICA::COpRollbackEnable(bRollbackEnabled)); olRemoveWLANProfiles.push_back(new MSICA::COpRollbackEnable(bRollbackEnabled)); olRemoveCertificates.push_back(new MSICA::COpRollbackEnable(bRollbackEnabled)); olInstallCertificates.push_back(new MSICA::COpRollbackEnable(bRollbackEnabled)); olInstallWLANProfiles.push_back(new MSICA::COpRollbackEnable(bRollbackEnabled)); olSetServiceStarts.push_back(new MSICA::COpRollbackEnable(bRollbackEnabled)); olStartServices.push_back(new MSICA::COpRollbackEnable(bRollbackEnabled)); olInstallScheduledTask.push_back(new MSICA::COpRollbackEnable(bRollbackEnabled)); // Open MSI database. hDatabase = ::MsiGetActiveDatabase(hInstall); if (hDatabase) { MSICONDITION condition; // Check if Certificate table exists. If it doesn't exist, there's nothing to do. condition = ::MsiDatabaseIsTablePersistent(hDatabase, _T("Certificate")); if (condition == MSICONDITION_FALSE || condition == MSICONDITION_TRUE) { PMSIHANDLE hViewCert; // Prepare a query to get a list/view of certificates. uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT `Binary_`,`Store`,`Flags`,`Encoding`,`Condition`,`Component_` FROM `Certificate`"), &hViewCert); if (uiResult == NO_ERROR) { // Execute query! uiResult = ::MsiViewExecute(hViewCert, NULL); if (uiResult == NO_ERROR) { std::wstring sStore; int iFlags, iEncoding; std::vector binCert; for (;;) { PMSIHANDLE hRecord; INSTALLSTATE iInstalled, iAction; PMSIHANDLE hViewBinary; // Fetch one record from the view. uiResult = ::MsiViewFetch(hViewCert, &hRecord); if (uiResult == ERROR_NO_MORE_ITEMS) { uiResult = NO_ERROR; break; } else if (uiResult != NO_ERROR) break; // Read and evaluate certificate's condition. uiResult = ::MsiRecordGetString(hRecord, 5, sValue); if (uiResult != NO_ERROR) break; condition = ::MsiEvaluateCondition(hInstall, sValue.c_str()); if (condition == MSICONDITION_FALSE) continue; else if (condition == MSICONDITION_ERROR) { uiResult = ERROR_INVALID_FIELD; break; } // Perform another query to get certificate's binary data. uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT `Data` FROM `Binary` WHERE `Name`=?"), &hViewBinary); if (uiResult != NO_ERROR) break; // Execute query! uiResult = ::MsiViewExecute(hViewBinary, hRecord); if (uiResult == NO_ERROR) { PMSIHANDLE hRecordCert; // Fetch one record from the view. uiResult = ::MsiViewFetch(hViewBinary, &hRecordCert); if (uiResult == NO_ERROR) uiResult = ::MsiRecordReadStream(hRecordCert, 1, binCert); ::MsiViewClose(hViewBinary); if (uiResult != NO_ERROR) break; } else break; // Read certificate's store. uiResult = ::MsiRecordGetString(hRecord, 2, sStore); if (uiResult != NO_ERROR) break; // Read certificate's flags. iFlags = ::MsiRecordGetInteger(hRecord, 3); if (iFlags == MSI_NULL_INTEGER) { uiResult = ERROR_INVALID_FIELD; break; } // Read certificate's encoding. iEncoding = ::MsiRecordGetInteger(hRecord, 4); if (iEncoding == MSI_NULL_INTEGER) { uiResult = ERROR_INVALID_FIELD; break; } // Read certificate's Component ID. uiResult = ::MsiRecordGetString(hRecord, 6, sValue); if (uiResult != NO_ERROR) break; // Get the component state. uiResult = ::MsiGetComponentState(hInstall, sValue.c_str(), &iInstalled, &iAction); if (uiResult != NO_ERROR) break; if (iAction >= INSTALLSTATE_LOCAL) { // Component is or should be installed. Install the certificate. olInstallCertificates.push_back(new MSICA::COpCertInstall(binCert.data(), binCert.size(), sStore.c_str(), iEncoding, iFlags, MSICA_CERT_TICK_SIZE)); } else if (iAction >= INSTALLSTATE_REMOVED) { // Component is installed, but should be degraded to advertised/removed. Delete the certificate. olRemoveCertificates.push_back(new MSICA::COpCertRemove(binCert.data(), binCert.size(), sStore.c_str(), iEncoding, iFlags, MSICA_CERT_TICK_SIZE)); } // The amount of tick space to add for each certificate to progress indicator. ::MsiRecordSetInteger(hRecordProg, 1, 3 ); ::MsiRecordSetInteger(hRecordProg, 2, MSICA_CERT_TICK_SIZE); if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } } ::MsiViewClose(hViewCert); } else { ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } else { ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } // Check if ServiceConfigure table exists. If it doesn't exist, there's nothing to do. condition = ::MsiDatabaseIsTablePersistent(hDatabase, _T("ServiceConfigure")); if (condition == MSICONDITION_FALSE || condition == MSICONDITION_TRUE) { PMSIHANDLE hViewSC; // Prepare a query to get a list/view of service configurations. uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT `Name`,`StartType`,`Control`,`Condition` FROM `ServiceConfigure` ORDER BY `Sequence`"), &hViewSC); if (uiResult == NO_ERROR) { // Execute query! uiResult = ::MsiViewExecute(hViewSC, NULL); if (uiResult == NO_ERROR) { int iValue; for (;;) { PMSIHANDLE hRecord; // Fetch one record from the view. uiResult = ::MsiViewFetch(hViewSC, &hRecord); if (uiResult == ERROR_NO_MORE_ITEMS) { uiResult = NO_ERROR; break; } else if (uiResult != NO_ERROR) break; // Read and evaluate service configuration condition. uiResult = ::MsiRecordGetString(hRecord, 4, sValue); if (uiResult != NO_ERROR) break; condition = ::MsiEvaluateCondition(hInstall, sValue.c_str()); if (condition == MSICONDITION_FALSE) continue; else if (condition == MSICONDITION_ERROR) { uiResult = ERROR_INVALID_FIELD; break; } // Read service name. uiResult = ::MsiRecordGetString(hRecord, 1, sValue); if (uiResult != NO_ERROR) break; // Read service start type. iValue = ::MsiRecordGetInteger(hRecord, 2); if (iValue == MSI_NULL_INTEGER) { uiResult = ERROR_INVALID_FIELD; break; } if (iValue >= 0) { // Set service start type. olSetServiceStarts.push_back(new MSICA::COpSvcSetStart(sValue.c_str(), iValue, MSICA_SVC_SET_START_TICK_SIZE)); // The amount of tick space to add to progress indicator. ::MsiRecordSetInteger(hRecordProg, 1, 3 ); ::MsiRecordSetInteger(hRecordProg, 2, MSICA_SVC_SET_START_TICK_SIZE); if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } } // Read service control. iValue = ::MsiRecordGetInteger(hRecord, 3); if (iValue == MSI_NULL_INTEGER) { uiResult = ERROR_INVALID_FIELD; break; } if ((iValue & 4) != 0) { // Stop service. olStopServices.push_back(new MSICA::COpSvcStop(sValue.c_str(), (iValue & 1) ? TRUE : FALSE, MSICA_SVC_STOP_TICK_SIZE)); // The amount of tick space to add to progress indicator. ::MsiRecordSetInteger(hRecordProg, 1, 3 ); ::MsiRecordSetInteger(hRecordProg, 2, MSICA_SVC_STOP_TICK_SIZE); if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } } else if ((iValue & 2) != 0) { // Start service. olStartServices.push_back(new MSICA::COpSvcStart(sValue.c_str(), (iValue & 1) ? TRUE : FALSE, MSICA_SVC_START_TICK_SIZE)); // The amount of tick space to add to progress indicator. ::MsiRecordSetInteger(hRecordProg, 1, 3 ); ::MsiRecordSetInteger(hRecordProg, 2, MSICA_SVC_START_TICK_SIZE); if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } } } ::MsiViewClose(hViewSC); } else { ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } else { ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } // Check if ScheduledTask table exists. If it doesn't exist, there's nothing to do. condition = ::MsiDatabaseIsTablePersistent(hDatabase, _T("ScheduledTask")); if (condition == MSICONDITION_FALSE || condition == MSICONDITION_TRUE) { PMSIHANDLE hViewST; // Prepare a query to get a list/view of tasks. uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT `Task`,`DisplayName`,`Application`,`Parameters`,`Directory_`,`Flags`,`Priority`,`User`,`Password`,`Author`,`Description`,`IdleMin`,`IdleDeadline`,`MaxRuntime`,`Condition`,`Component_` FROM `ScheduledTask`"), &hViewST); if (uiResult == NO_ERROR) { // Execute query! uiResult = ::MsiViewExecute(hViewST, NULL); if (uiResult == NO_ERROR) { //winstd::tstring sComponent; std::wstring sDisplayName; for (;;) { PMSIHANDLE hRecord; INSTALLSTATE iInstalled, iAction; // Fetch one record from the view. uiResult = ::MsiViewFetch(hViewST, &hRecord); if (uiResult == ERROR_NO_MORE_ITEMS) { uiResult = NO_ERROR; break; } else if (uiResult != NO_ERROR) break; // Read and evaluate task's condition. uiResult = ::MsiRecordGetString(hRecord, 15, sValue); if (uiResult != NO_ERROR) break; condition = ::MsiEvaluateCondition(hInstall, sValue.c_str()); if (condition == MSICONDITION_FALSE) continue; else if (condition == MSICONDITION_ERROR) { uiResult = ERROR_INVALID_FIELD; break; } // Read task's Component ID. uiResult = ::MsiRecordGetString(hRecord, 16, sValue); if (uiResult != NO_ERROR) break; // Get the component state. uiResult = ::MsiGetComponentState(hInstall, sValue.c_str(), &iInstalled, &iAction); if (uiResult != NO_ERROR) break; // Get task's DisplayName. uiResult = ::MsiRecordFormatStringW(hInstall, hRecord, 2, sDisplayName); if (iAction >= INSTALLSTATE_LOCAL) { // Component is or should be installed. Create the task. PMSIHANDLE hViewTT; MSICA::COpTaskCreate *opCreateTask = new MSICA::COpTaskCreate(sDisplayName.c_str(), MSICA_TASK_TICK_SIZE); // Populate the operation with task's data. uiResult = opCreateTask->SetFromRecord(hInstall, hRecord); if (uiResult != NO_ERROR) break; // Perform another query to get task's triggers. uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT `Trigger`,`BeginDate`,`EndDate`,`StartTime`,`StartTimeRand`,`MinutesDuration`,`MinutesInterval`,`Flags`,`Type`,`DaysInterval`,`WeeksInterval`,`DaysOfTheWeek`,`DaysOfMonth`,`WeekOfMonth`,`MonthsOfYear` FROM `TaskTrigger` WHERE `Task_`=?"), &hViewTT); if (uiResult != NO_ERROR) break; // Execute query! uiResult = ::MsiViewExecute(hViewTT, hRecord); if (uiResult == NO_ERROR) { // Populate trigger list. uiResult = opCreateTask->SetTriggersFromView(hViewTT); ::MsiViewClose(hViewTT); if (uiResult != NO_ERROR) break; } else break; olInstallScheduledTask.push_back(opCreateTask); } else if (iAction >= INSTALLSTATE_REMOVED) { // Component is installed, but should be degraded to advertised/removed. Delete the task. olRemoveScheduledTask.push_back(new MSICA::COpTaskDelete(sDisplayName.c_str(), MSICA_TASK_TICK_SIZE)); } // The amount of tick space to add for each task to progress indicator. ::MsiRecordSetInteger(hRecordProg, 1, 3 ); ::MsiRecordSetInteger(hRecordProg, 2, MSICA_TASK_TICK_SIZE); if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } } ::MsiViewClose(hViewST); } else { ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } else { ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } // Check if WLANProfile table exists. If it doesn't exist, there's nothing to do. condition = ::MsiDatabaseIsTablePersistent(hDatabase, _T("WLANProfile")); if (condition == MSICONDITION_FALSE || condition == MSICONDITION_TRUE) { PMSIHANDLE hViewProfile; // Prepare a query to get a list/view of profiles. uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT `Binary_`,`Name`,`Condition`,`Component_` FROM `WLANProfile`"), &hViewProfile); if (uiResult == NO_ERROR) { // Execute query! uiResult = ::MsiViewExecute(hViewProfile, NULL); if (uiResult == NO_ERROR) { if (::pfnWlanOpenHandle && ::pfnWlanCloseHandle && ::pfnWlanEnumInterfaces && ::pfnWlanFreeMemory) { DWORD dwError, dwNegotiatedVersion; HANDLE hClientHandle; // Open WLAN handle. dwError = ::pfnWlanOpenHandle(2, NULL, &dwNegotiatedVersion, &hClientHandle); if (dwError == NO_ERROR) { WLAN_INTERFACE_INFO_LIST *pInterfaceList; // Get a list of WLAN interfaces. dwError = ::pfnWlanEnumInterfaces(hClientHandle, NULL, &pInterfaceList); if (dwError == NO_ERROR) { std::wstring sName, sProfileXML; std::vector binProfile; for (;;) { PMSIHANDLE hRecord; INSTALLSTATE iInstalled, iAction; int iTick = 0; DWORD i; // Fetch one record from the view. uiResult = ::MsiViewFetch(hViewProfile, &hRecord); if (uiResult == ERROR_NO_MORE_ITEMS) { uiResult = NO_ERROR; break; } else if (uiResult != NO_ERROR) break; // Read and evaluate profile's condition. uiResult = ::MsiRecordGetString(hRecord, 3, sValue); if (uiResult != NO_ERROR) break; condition = ::MsiEvaluateCondition(hInstall, sValue.c_str()); if (condition == MSICONDITION_FALSE) continue; else if (condition == MSICONDITION_ERROR) { uiResult = ERROR_INVALID_FIELD; break; } // Read profile's name. uiResult = ::MsiRecordGetString(hRecord, 2, sName); if (uiResult != NO_ERROR) break; // Read profile's component ID. uiResult = ::MsiRecordGetString(hRecord, 4, sValue); if (uiResult != NO_ERROR) break; // Get the component state. uiResult = ::MsiGetComponentState(hInstall, sValue.c_str(), &iInstalled, &iAction); if (uiResult != NO_ERROR) break; if (iAction >= INSTALLSTATE_LOCAL) { PMSIHANDLE hViewBinary, hRecordBin; LPCWSTR pProfileStr; SIZE_T nCount; // Perform another query to get profile's binary data. uiResult = ::MsiDatabaseOpenView(hDatabase, _T("SELECT `Data` FROM `Binary` WHERE `Name`=?"), &hViewBinary); if (uiResult != NO_ERROR) break; // Execute query! uiResult = ::MsiViewExecute(hViewBinary, hRecord); if (uiResult != NO_ERROR) break; // Fetch one record from the view. uiResult = ::MsiViewFetch(hViewBinary, &hRecordBin); if (uiResult == NO_ERROR) uiResult = ::MsiRecordReadStream(hRecordBin, 1, binProfile); ::MsiViewClose(hViewBinary); if (uiResult != NO_ERROR) break; // Convert std::vector to std::wstring. pProfileStr = (LPCWSTR)binProfile.data(); nCount = binProfile.size()/sizeof(WCHAR); if (nCount < 1 || pProfileStr[0] != 0xfeff) { // The profile XML is not UTF-16 encoded. ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_PROFILE_NOT_UTF16); ::MsiRecordSetStringW(hRecordProg, 2, sName.c_str() ); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); uiResult = ERROR_INSTALL_USEREXIT; } sProfileXML.assign(pProfileStr + 1, (int)nCount - 1); for (i = 0; i < pInterfaceList->dwNumberOfItems; i++) { // Check for not ready state in interface. if (pInterfaceList->InterfaceInfo[i].isState != wlan_interface_state_not_ready) { olInstallWLANProfiles.push_back(new MSICA::COpWLANProfileSet(pInterfaceList->InterfaceInfo[i].InterfaceGuid, 0, sName.c_str(), sProfileXML.c_str(), MSICA_WLAN_PROFILE_TICK_SIZE)); iTick += MSICA_WLAN_PROFILE_TICK_SIZE; } } // The amount of tick space to add for each profile to progress indicator. ::MsiRecordSetInteger(hRecordProg, 1, 3 ); ::MsiRecordSetInteger(hRecordProg, 2, iTick); if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } } else if (iAction >= INSTALLSTATE_REMOVED) { // Component is installed, but should be degraded to advertised/removed. Delete the profile from all interfaces. for (i = 0; i < pInterfaceList->dwNumberOfItems; i++) { // Check for not ready state in interface. if (pInterfaceList->InterfaceInfo[i].isState != wlan_interface_state_not_ready) { olRemoveWLANProfiles.push_back(new MSICA::COpWLANProfileDelete(pInterfaceList->InterfaceInfo[i].InterfaceGuid, sName.c_str(), MSICA_WLAN_PROFILE_TICK_SIZE)); iTick += MSICA_WLAN_PROFILE_TICK_SIZE; } } // The amount of tick space to add for each profile to progress indicator. ::MsiRecordSetInteger(hRecordProg, 1, 3 ); ::MsiRecordSetInteger(hRecordProg, 2, iTick); if (::MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hRecordProg) == IDCANCEL) { uiResult = ERROR_INSTALL_USEREXIT; break; } } } ::pfnWlanFreeMemory(pInterfaceList); } ::pfnWlanCloseHandle(hClientHandle, NULL); } else if (dwError == ERROR_SERVICE_NOT_ACTIVE) { uiResult = ERROR_INSTALL_WLAN_SVC_NOT_STARTED; ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } else { uiResult = ERROR_INSTALL_WLAN_HANDLE_OPEN; ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiRecordSetInteger(hRecordProg, 2, dwError); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } else { uiResult = ERROR_INSTALL_WLAN_NOT_INSTALLED; ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } ::MsiViewClose(hViewProfile); } else { ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } else { ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } // Save the sequences. if (uiResult == NO_ERROR) uiResult = MSICA::SaveSequence(hInstall, _T("RemoveScheduledTasksExec"), _T("RemoveScheduledTasksCommit"), _T("RemoveScheduledTasksRollback"), olRemoveScheduledTask); if (uiResult == NO_ERROR) uiResult = MSICA::SaveSequence(hInstall, _T("StopServicesExec"), _T("StopServicesCommit"), _T("StopServicesRollback"), olStopServices); if (uiResult == NO_ERROR) uiResult = MSICA::SaveSequence(hInstall, _T("RemoveWLANProfilesExec"), _T("RemoveWLANProfilesCommit"), _T("RemoveWLANProfilesRollback"), olRemoveWLANProfiles); if (uiResult == NO_ERROR) uiResult = MSICA::SaveSequence(hInstall, _T("RemoveCertificatesExec"), _T("RemoveCertificatesCommit"), _T("RemoveCertificatesRollback"), olRemoveCertificates); if (uiResult == NO_ERROR) uiResult = MSICA::SaveSequence(hInstall, _T("InstallCertificatesExec"), _T("InstallCertificatesCommit"), _T("InstallCertificatesRollback"), olInstallCertificates); if (uiResult == NO_ERROR) uiResult = MSICA::SaveSequence(hInstall, _T("InstallWLANProfilesExec"), _T("InstallWLANProfilesCommit"), _T("InstallWLANProfilesRollback"), olInstallWLANProfiles); if (uiResult == NO_ERROR) uiResult = MSICA::SaveSequence(hInstall, _T("SetServiceStartExec"), _T("SetServiceStartCommit"), _T("SetServiceStartRollback"), olSetServiceStarts); if (uiResult == NO_ERROR) uiResult = MSICA::SaveSequence(hInstall, _T("StartServicesExec"), _T("StartServicesCommit"), _T("StartServicesRollback"), olStartServices); if (uiResult == NO_ERROR) uiResult = MSICA::SaveSequence(hInstall, _T("InstallScheduledTasksExec"), _T("InstallScheduledTasksCommit"), _T("InstallScheduledTasksRollback"), olInstallScheduledTask); if (uiResult != NO_ERROR && uiResult != ERROR_INSTALL_USEREXIT) { ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_OPLIST_CREATE); ::MsiRecordSetInteger(hRecordProg, 2, uiResult ); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } } else { uiResult = ERROR_INSTALL_DATABASE_OPEN; ::MsiRecordSetInteger(hRecordProg, 1, uiResult); ::MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecordProg); } return uiResult; } UINT __declspec(dllexport) ExecuteSequence(MSIHANDLE hInstall) { //::MessageBox(NULL, _T(__FUNCTION__), _T("MSICA"), MB_OK); return MSICA::ExecuteSequence(hInstall); }