diff --git a/MSIBuild/Makefile b/MSIBuild/Makefile index d883704..cc73454 100644 --- a/MSIBuild/Makefile +++ b/MSIBuild/Makefile @@ -59,6 +59,7 @@ i2 L0 2571 Error [3] changing service "[2]" start type. Please, contact your support personnel. 2572 Error [3] starting service "[2]". Please, contact your support personnel. 2573 Error [3] stopping service "[2]". Please, contact your support personnel. +2580 Error installing WLAN profiles, because WLAN is not installed. Please, install Wireless LAN Service Windows feature, or contact your support personnel. 2579 Error opening WLAN handle, because WLAN AutoConfig service is not started. Please, enable and start WLAN AutoConfig service, or contact your support personnel. 2577 Error [2] opening WLAN handle. Please, contact your support personnel. 2578 WLAN profile "[2]" XML data is not UTF-16 encoded. Please, contact your support personnel. diff --git a/include/MSICALib.h b/include/MSICALib.h index 858fea8..1f461fb 100644 --- a/include/MSICALib.h +++ b/include/MSICALib.h @@ -30,7 +30,7 @@ //////////////////////////////////////////////////////////////////// -// Error codes (next unused 2580L) +// Error codes (next unused 2581L) //////////////////////////////////////////////////////////////////// #define ERROR_INSTALL_DATABASE_OPEN 2550L @@ -57,6 +57,7 @@ #define ERROR_INSTALL_SVC_SET_START 2571L #define ERROR_INSTALL_SVC_START 2572L #define ERROR_INSTALL_SVC_STOP 2573L +#define ERROR_INSTALL_WLAN_NOT_INSTALLED 2580L #define ERROR_INSTALL_WLAN_SVC_NOT_STARTED 2579L #define ERROR_INSTALL_WLAN_HANDLE_OPEN 2577L #define ERROR_INSTALL_WLAN_PROFILE_NOT_UTF16 2578L diff --git a/src/OpWLAN.cpp b/src/OpWLAN.cpp index 7af99d9..11c7d0a 100644 --- a/src/OpWLAN.cpp +++ b/src/OpWLAN.cpp @@ -19,8 +19,6 @@ #include "stdafx.h" -#pragma comment(lib, "wlanapi.lib") - namespace MSICA { @@ -46,45 +44,52 @@ COpWLANProfileDelete::COpWLANProfileDelete(const GUID &guidInterface, LPCWSTR ps HRESULT COpWLANProfileDelete::Execute(CSession *pSession) { - DWORD dwError, dwNegotiatedVersion; - HANDLE hClientHandle; + if (::pfnWlanOpenHandle && ::pfnWlanCloseHandle && ::pfnWlanGetProfile && ::pfnWlanDeleteProfile && ::pfnWlanFreeMemory) { + DWORD dwError, dwNegotiatedVersion; + HANDLE hClientHandle; - dwError = ::WlanOpenHandle(2, NULL, &dwNegotiatedVersion, &hClientHandle); - if (dwError == NO_ERROR) { - if (pSession->m_bRollbackEnabled) { - LPWSTR pszProfileXML = NULL; - DWORD dwFlags = 0, dwGrantedAccess = 0; + dwError = ::pfnWlanOpenHandle(2, NULL, &dwNegotiatedVersion, &hClientHandle); + if (dwError == NO_ERROR) { + if (pSession->m_bRollbackEnabled) { + LPWSTR pszProfileXML = NULL; + DWORD dwFlags = 0, dwGrantedAccess = 0; - // Get profile settings as XML first. - dwError = ::WlanGetProfile(hClientHandle, &m_guidInterface, m_sValue, NULL, &pszProfileXML, &dwFlags, &dwGrantedAccess); - if (dwError == NO_ERROR) { - // Delete the profile. - dwError = ::WlanDeleteProfile(hClientHandle, &m_guidInterface, m_sValue, NULL); + // Get profile settings as XML first. + dwError = ::pfnWlanGetProfile(hClientHandle, &m_guidInterface, m_sValue, NULL, &pszProfileXML, &dwFlags, &dwGrantedAccess); if (dwError == NO_ERROR) { - // Order rollback action to recreate it. - pSession->m_olRollback.AddHead(new COpWLANProfileSet(m_guidInterface, dwFlags, m_sValue, pszProfileXML)); + // Delete the profile. + dwError = ::pfnWlanDeleteProfile(hClientHandle, &m_guidInterface, m_sValue, NULL); + if (dwError == NO_ERROR) { + // Order rollback action to recreate it. + pSession->m_olRollback.AddHead(new COpWLANProfileSet(m_guidInterface, dwFlags, m_sValue, pszProfileXML)); + } + ::pfnWlanFreeMemory(pszProfileXML); } - ::WlanFreeMemory(pszProfileXML); + } else { + // Delete the profile. + dwError = ::pfnWlanDeleteProfile(hClientHandle, &m_guidInterface, m_sValue, NULL); } - } else { - // Delete the profile. - dwError = ::WlanDeleteProfile(hClientHandle, &m_guidInterface, m_sValue, NULL); + ::pfnWlanCloseHandle(hClientHandle, NULL); } - ::WlanCloseHandle(hClientHandle, NULL); - } - if (dwError == NO_ERROR || dwError == ERROR_NOT_FOUND) - return S_OK; - else { - PMSIHANDLE hRecordProg = ::MsiCreateRecord(4); - ATL::CAtlStringW sGUID; - GuidToString(&m_guidInterface, sGUID); - ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_PROFILE_DELETE); - ::MsiRecordSetStringW(hRecordProg, 2, sGUID ); - ::MsiRecordSetStringW(hRecordProg, 3, m_sValue ); - ::MsiRecordSetInteger(hRecordProg, 4, dwError ); + if (dwError == NO_ERROR || dwError == ERROR_NOT_FOUND) + return S_OK; + else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(4); + ATL::CAtlStringW sGUID; + GuidToString(&m_guidInterface, sGUID); + ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_PROFILE_DELETE); + ::MsiRecordSetStringW(hRecordProg, 2, sGUID ); + ::MsiRecordSetStringW(hRecordProg, 3, m_sValue ); + ::MsiRecordSetInteger(hRecordProg, 4, dwError ); + ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + return AtlHresultFromWin32(dwError); + } + } else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(1); + ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_NOT_INSTALLED); ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - return AtlHresultFromWin32(dwError); + return E_NOTIMPL; } } @@ -103,50 +108,57 @@ COpWLANProfileSet::COpWLANProfileSet(const GUID &guidInterface, DWORD dwFlags, L HRESULT COpWLANProfileSet::Execute(CSession *pSession) { - DWORD dwError, dwNegotiatedVersion; - HANDLE hClientHandle; - WLAN_REASON_CODE wlrc = 0; + if (::pfnWlanOpenHandle && ::pfnWlanCloseHandle && ::pfnWlanSetProfile && ::pfnWlanReasonCodeToString) { + DWORD dwError, dwNegotiatedVersion; + HANDLE hClientHandle; + WLAN_REASON_CODE wlrc = 0; - { - // Delete existing profile first. - // Since deleting a profile is a complicated job (when rollback/commit support is required), and we do have an operation just for that, we use it. - // Don't worry, COpWLANProfileDelete::Execute() returns S_OK if profile doesn't exist. - COpWLANProfileDelete opDelete(m_guidInterface, m_sValue); - HRESULT hr = opDelete.Execute(pSession); - if (FAILED(hr)) return hr; - } - - dwError = ::WlanOpenHandle(2, NULL, &dwNegotiatedVersion, &hClientHandle); - if (dwError == NO_ERROR) { - // Set the profile. - dwError = ::WlanSetProfile(hClientHandle, &m_guidInterface, m_dwFlags, m_sProfileXML, NULL, TRUE, NULL, &wlrc); - if (dwError == NO_ERROR && pSession->m_bRollbackEnabled) { - // Order rollback action to delete it. - pSession->m_olRollback.AddHead(new COpWLANProfileDelete(m_guidInterface, m_sValue)); + { + // Delete existing profile first. + // Since deleting a profile is a complicated job (when rollback/commit support is required), and we do have an operation just for that, we use it. + // Don't worry, COpWLANProfileDelete::Execute() returns S_OK if profile doesn't exist. + COpWLANProfileDelete opDelete(m_guidInterface, m_sValue); + HRESULT hr = opDelete.Execute(pSession); + if (FAILED(hr)) return hr; } - ::WlanCloseHandle(hClientHandle, NULL); - } - if (dwError == NO_ERROR) - return S_OK; - else { - PMSIHANDLE hRecordProg = ::MsiCreateRecord(5); - ATL::CAtlStringW sGUID, sReason; - DWORD dwSize = 1024, dwResult; - LPWSTR szBuffer = sReason.GetBuffer(dwSize); + dwError = ::pfnWlanOpenHandle(2, NULL, &dwNegotiatedVersion, &hClientHandle); + if (dwError == NO_ERROR) { + // Set the profile. + dwError = ::pfnWlanSetProfile(hClientHandle, &m_guidInterface, m_dwFlags, m_sProfileXML, NULL, TRUE, NULL, &wlrc); + if (dwError == NO_ERROR && pSession->m_bRollbackEnabled) { + // Order rollback action to delete it. + pSession->m_olRollback.AddHead(new COpWLANProfileDelete(m_guidInterface, m_sValue)); + } + ::pfnWlanCloseHandle(hClientHandle, NULL); + } - GuidToString(&m_guidInterface, sGUID); - dwResult = ::WlanReasonCodeToString(wlrc, dwSize, szBuffer, NULL); - sReason.ReleaseBuffer(dwSize); - if (dwResult != NO_ERROR) sReason.Format(L"0x%x", wlrc); + if (dwError == NO_ERROR) + return S_OK; + else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(5); + ATL::CAtlStringW sGUID, sReason; + DWORD dwSize = 1024, dwResult; + LPWSTR szBuffer = sReason.GetBuffer(dwSize); - ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_PROFILE_SET); - ::MsiRecordSetStringW(hRecordProg, 2, sGUID ); - ::MsiRecordSetStringW(hRecordProg, 3, m_sValue ); - ::MsiRecordSetStringW(hRecordProg, 4, sReason ); - ::MsiRecordSetInteger(hRecordProg, 5, dwError ); + GuidToString(&m_guidInterface, sGUID); + dwResult = ::pfnWlanReasonCodeToString(wlrc, dwSize, szBuffer, NULL); + sReason.ReleaseBuffer(dwSize); + if (dwResult != NO_ERROR) sReason.Format(L"0x%x", wlrc); + + ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_PROFILE_SET); + ::MsiRecordSetStringW(hRecordProg, 2, sGUID ); + ::MsiRecordSetStringW(hRecordProg, 3, m_sValue ); + ::MsiRecordSetStringW(hRecordProg, 4, sReason ); + ::MsiRecordSetInteger(hRecordProg, 5, dwError ); + ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); + return AtlHresultFromWin32(dwError); + } + } else { + PMSIHANDLE hRecordProg = ::MsiCreateRecord(1); + ::MsiRecordSetInteger(hRecordProg, 1, ERROR_INSTALL_WLAN_NOT_INSTALLED); ::MsiProcessMessage(pSession->m_hInstall, INSTALLMESSAGE_ERROR, hRecordProg); - return AtlHresultFromWin32(dwError); + return E_NOTIMPL; } } diff --git a/src/stdafx.h b/src/stdafx.h index 87766bf..73788a6 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -33,3 +33,13 @@ #include #include #include + +// Must not statically link to Wlanapi.dll as it is not available on Windows +// without a WLAN interface. +extern VOID (WINAPI *pfnWlanFreeMemory)(__in PVOID pMemory); +extern DWORD (WINAPI *pfnWlanOpenHandle)(__in DWORD dwClientVersion, __reserved PVOID pReserved, __out PDWORD pdwNegotiatedVersion, __out PHANDLE phClientHandle); +extern DWORD (WINAPI *pfnWlanCloseHandle)(__in HANDLE hClientHandle, __reserved PVOID pReserved); +extern 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); +extern 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); +extern DWORD (WINAPI *pfnWlanDeleteProfile)(__in HANDLE hClientHandle, __in CONST GUID *pInterfaceGuid, __in LPCWSTR strProfileName, __reserved PVOID pReserved); +extern DWORD (WINAPI *pfnWlanReasonCodeToString)(__in DWORD dwReasonCode, __in DWORD dwBufferSize, __in_ecount(dwBufferSize) PWCHAR pStringBuffer, __reserved PVOID pReserved);