2401 lines
63 KiB
C++
2401 lines
63 KiB
C++
//=======================================================================
|
|
//
|
|
// Copyright (c) 2000 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// File: Update.cpp
|
|
//
|
|
// Owner: JHou
|
|
//
|
|
// Description:
|
|
//
|
|
// Industry Update v1.0 client control stub - Implementation of CUpdate
|
|
//
|
|
//
|
|
// Revision History:
|
|
//
|
|
// Date Author Desc
|
|
// ~~~~ ~~~~~~ ~~~~
|
|
// 9/15/2000 JHou created.
|
|
//
|
|
//=======================================================================
|
|
#include "stdafx.h"
|
|
#include "iu.h"
|
|
#include "iucommon.h"
|
|
#include "IUCtl.h"
|
|
#include "Update.h"
|
|
#include "iudl.h"
|
|
#include "selfupd.h"
|
|
#include "loadengine.h"
|
|
#include <logging.h>
|
|
#include <fileutil.h>
|
|
#include <trust.h>
|
|
#include <osdet.h>
|
|
#include <exdisp.h>
|
|
#include <UrlAgent.h>
|
|
#include <wusafefn.h>
|
|
|
|
typedef BOOL (WINAPI* pfn_InternetCrackUrl)(LPCTSTR, DWORD, DWORD, LPURL_COMPONENTS);
|
|
|
|
extern HANDLE g_hEngineLoadQuit;
|
|
extern CIUUrlAgent *g_pIUUrlAgent;
|
|
|
|
#define Initialized (2 == m_lInitState)
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// declaration of function template for CoFreeUnusedLibrariesEx(), which is
|
|
// available on Win98+ and Win2000+ only, in ole32.dll
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
typedef void (WINAPI * PFN_CoFreeUnusedLibrariesEx) (IN DWORD dwUnloadDelay,
|
|
IN DWORD dwReserved);
|
|
extern "C" const CLSID CLSID_Update2;
|
|
typedef HRESULT (STDMETHODCALLTYPE* PROC_RegServer)(void);
|
|
|
|
DWORD MyGetModuleFileName(HMODULE hModule, LPTSTR pszBuf, DWORD cchBuf);
|
|
BOOL IsThisUpdate2();
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CUpdate
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Constructor
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CUpdate::CUpdate()
|
|
: m_EvtWindow(this),
|
|
m_dwSafety(0),
|
|
m_dwMode(0x0),
|
|
m_hValidated(E_FAIL), // container not validated yet
|
|
m_fUseCompression(TRUE),
|
|
m_fOfflineMode(FALSE),
|
|
m_hEngineModule(NULL),
|
|
m_pClientSite(NULL),
|
|
m_lInitState(0L),
|
|
m_dwUpdateInfo(0x0),
|
|
m_hIUEngine(NULL)
|
|
{
|
|
m_szReqControlVer[0] = _T('\0');
|
|
m_gfInit_csLock = SafeInitializeCriticalSection(&m_lock);
|
|
m_evtControlQuit = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
m_EvtWindow.Create();
|
|
|
|
/*
|
|
we decided to use the new Win32 API GetControlUpdateInfo() to expose these
|
|
data and let a wrapper control to call it so we won't have reboot issue on
|
|
OS prior to WinXP
|
|
|
|
|
|
//
|
|
// try to free unused libraries
|
|
//
|
|
HMODULE hOle32Dll = LoadLibrary(_T("ole32.dll"));
|
|
if (NULL != hOle32Dll)
|
|
{
|
|
//
|
|
// The min platforms support CoFreeUnusedLibrariesEx() are W2K and W98
|
|
// so we can't call it directly
|
|
//
|
|
PFN_CoFreeUnusedLibrariesEx pFreeLib = (PFN_CoFreeUnusedLibrariesEx)
|
|
GetProcAddress(hOle32Dll,
|
|
"CoFreeUnusedLibrariesEx");
|
|
if (NULL != pFreeLib)
|
|
{
|
|
//
|
|
// ask to release the unused library immediately, this will cause the COM objects
|
|
// that being released (e.g., set obj to nothing) unloaded from memory immediately,
|
|
// so in control update case we can safely jump to a to use <OBJECT> with codebase
|
|
// to update the control and it won't cause reboot even though on this page we already
|
|
// loaded the control
|
|
//
|
|
pFreeLib(0, 0);
|
|
}
|
|
FreeLibrary(hOle32Dll);
|
|
}
|
|
|
|
//
|
|
// figure out if we are upate 2, we are if this module name ends with "2.dll"
|
|
//
|
|
m_fIsThisUpdate2 = ::IsThisUpdate2();
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Destructor
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CUpdate::~CUpdate()
|
|
{
|
|
m_EvtWindow.Destroy();
|
|
|
|
if(m_gfInit_csLock)
|
|
{
|
|
DeleteCriticalSection(&m_lock);
|
|
}
|
|
if (NULL != m_evtControlQuit)
|
|
{
|
|
CloseHandle(m_evtControlQuit);
|
|
}
|
|
SafeReleaseNULL(m_pClientSite);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetInterfaceSafetyOptions()
|
|
//
|
|
// Retrieves the safety options supported by the object.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
|
|
{
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL)
|
|
return E_POINTER;
|
|
HRESULT hr = S_OK;
|
|
if (riid == IID_IDispatch)
|
|
{
|
|
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
|
|
*pdwEnabledOptions = m_dwSafety & INTERFACESAFE_FOR_UNTRUSTED_CALLER;
|
|
}
|
|
else
|
|
{
|
|
*pdwSupportedOptions = 0;
|
|
*pdwEnabledOptions = 0;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetInterfaceSafetyOptions()
|
|
//
|
|
// Makes the object safe for initialization or scripting.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
|
|
{
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// If we're being asked to set our safe for scripting option then oblige
|
|
if (riid == IID_IDispatch)
|
|
{
|
|
// Store our current safety level to return in GetInterfaceSafetyOptions
|
|
m_dwSafety = dwEnabledOptions & dwOptionSetMask;
|
|
return S_OK;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// InterfaceSupportsErrorInfo()
|
|
//
|
|
// Indicates whether the interface identified by riid supports the
|
|
// IErrorInfo interface
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::InterfaceSupportsErrorInfo(REFIID riid)
|
|
{
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
static const IID* arr[] =
|
|
{
|
|
&IID_IUpdate
|
|
};
|
|
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
|
|
{
|
|
if (InlineIsEqualGUID(*arr[i],riid))
|
|
return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetSystemSpec()
|
|
//
|
|
// Gets the basic system specs.
|
|
// Input:
|
|
// bstrXmlClasses - a list of requested classes in xml format, NULL if any.
|
|
// For example:
|
|
// <devices>
|
|
// <class name="video"/>
|
|
// <class name="sound" id="2560AD4D-3ED3-49C6-A937-4368C0B0E06A"/>
|
|
// </devices>
|
|
// Return:
|
|
// pbstrXmlDetectionResult - the detection result in xml format.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::GetSystemSpec(BSTR bstrXmlClasses,
|
|
BSTR* pbstrXmlDetectionResult)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
LOG_Block("CUpdate::GetSystemSpec");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_GetSystemSpec pfnGetSystemSpec = (PFN_GetSystemSpec)GetProcAddress(m_hEngineModule, "EngGetSystemSpec");
|
|
DWORD dwFlags = 0x0;
|
|
|
|
if (m_fOfflineMode)
|
|
{
|
|
dwFlags |= FLAG_OFFLINE_MODE;
|
|
}
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnGetSystemSpec)
|
|
{
|
|
hr = pfnGetSystemSpec(m_hIUEngine, bstrXmlClasses, dwFlags, pbstrXmlDetectionResult);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetManifest()
|
|
//
|
|
// Gets a catalog base on the specified information.
|
|
// Input:
|
|
// bstrXmlClientInfo - the credentials of the client in xml format
|
|
// bstrXmlSystemSpec - the detected system specifications in xml
|
|
// bstrXmlQuery - the user query infomation in xml
|
|
// Return:
|
|
// pbstrXmlCatalog - the xml catalog retrieved
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::GetManifest(BSTR bstrXmlClientInfo,
|
|
BSTR bstrXmlSystemSpec,
|
|
BSTR bstrXmlQuery,
|
|
BSTR* pbstrXmlCatalog)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LOG_Block("CUpdate::GetManifest");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
if (m_fOfflineMode)
|
|
{
|
|
// if we are in offline mode we can't download from the internet.
|
|
LOG_ErrorMsg(ERROR_INVALID_PARAMETER);
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_GetManifest pfnGetManifest = (PFN_GetManifest)GetProcAddress(m_hEngineModule, "EngGetManifest");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnGetManifest)
|
|
{
|
|
DWORD dwFlags = 0x0;
|
|
|
|
if (m_fUseCompression)
|
|
{
|
|
dwFlags |= FLAG_USE_COMPRESSION;
|
|
}
|
|
|
|
hr = pfnGetManifest(m_hIUEngine, bstrXmlClientInfo, bstrXmlSystemSpec, bstrXmlQuery, dwFlags, pbstrXmlCatalog);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Detect()
|
|
//
|
|
// Do detection.
|
|
// Input:
|
|
// bstrXmlCatalog - the xml catalog portion containing items to be detected
|
|
// Output:
|
|
// pbstrXmlItems - the detected items in xml format
|
|
// e.g.
|
|
// <id guid="2560AD4D-3ED3-49C6-A937-4368C0B0E06D" installed="1" force="1"/>
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::Detect(BSTR bstrXmlCatalog,
|
|
BSTR* pbstrXmlItems)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LOG_Block("CUpdate::Detect");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_Detect pfnDetect = (PFN_Detect)GetProcAddress(m_hEngineModule, "EngDetect");
|
|
DWORD dwFlags = 0x0;
|
|
|
|
if (m_fOfflineMode)
|
|
{
|
|
dwFlags |= FLAG_OFFLINE_MODE;
|
|
}
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnDetect)
|
|
{
|
|
hr = pfnDetect(m_hIUEngine, bstrXmlCatalog, dwFlags, pbstrXmlItems);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Download()
|
|
//
|
|
// Do synchronized downloading.
|
|
// Input:
|
|
// bstrXmlClientInfo - the credentials of the client in xml format
|
|
// bstrXmlCatalog - the xml catalog portion containing items to be downloaded
|
|
// bstrDestinationFolder - the destination folder. Null will use the default IU folder
|
|
// lMode - indicates throttled or fore-ground downloading mode
|
|
// punkProgressListener - the callback function pointer for reporting download progress
|
|
// Output:
|
|
// pbstrXmlItems - the items with download status in xml format
|
|
// e.g.
|
|
// <id guid="2560AD4D-3ED3-49C6-A937-4368C0B0E06D" downloaded="1"/>
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::Download(BSTR bstrXmlClientInfo,
|
|
BSTR bstrXmlCatalog,
|
|
BSTR bstrDestinationFolder,
|
|
LONG lMode,
|
|
IUnknown* punkProgressListener,
|
|
BSTR* pbstrXmlItems)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LOG_Block("CUpdate::Download");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
if (m_fOfflineMode)
|
|
{
|
|
// if we are in offline mode we can't download from the internet.
|
|
LOG_ErrorMsg(ERROR_INVALID_PARAMETER);
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_Download pfnDownload = (PFN_Download)GetProcAddress(m_hEngineModule, "EngDownload");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnDownload)
|
|
{
|
|
hr = pfnDownload(m_hIUEngine,
|
|
bstrXmlClientInfo,
|
|
bstrXmlCatalog,
|
|
bstrDestinationFolder,
|
|
lMode,
|
|
punkProgressListener,
|
|
m_EvtWindow.GetEvtHWnd(), // should we send event msg for sync download?
|
|
pbstrXmlItems);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// DownloadAsync()
|
|
//
|
|
// Download asynchronously - the method will return before completion.
|
|
// Input:
|
|
// bstrXmlClientInfo - the credentials of the client in xml format
|
|
// bstrXmlCatalog - the xml catalog portion containing items to be downloaded
|
|
// bstrDestinationFolder - the destination folder. Null will use the default IU folder
|
|
// lMode - indicates throttled or fore-ground downloading mode
|
|
// punkProgressListener - the callback function pointer for reporting download progress
|
|
// bstrUuidOperation - an id provided by the client to provide further
|
|
// identification to the operation as indexes may be reused.
|
|
// Output:
|
|
// pbstrUuidOperation - the operation ID. If it is not provided by the in bstrUuidOperation
|
|
// parameter (an empty string is passed), it will generate a new UUID,
|
|
// in which case, the caller will be responsible to free the memory of
|
|
// the string buffer that holds the generated UUID using SysFreeString().
|
|
// Otherwise, it returns the value passed by bstrUuidOperation.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::DownloadAsync(BSTR bstrXmlClientInfo,
|
|
BSTR bstrXmlCatalog,
|
|
BSTR bstrDestinationFolder,
|
|
LONG lMode,
|
|
IUnknown* punkProgressListener,
|
|
BSTR bstrUuidOperation,
|
|
BSTR* pbstrUuidOperation)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LOG_Block("CUpdate::DownloadAsync");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
if (m_fOfflineMode)
|
|
{
|
|
// if we are in offline mode we can't download from the internet.
|
|
LOG_ErrorMsg(ERROR_INVALID_PARAMETER);
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_DownloadAsync pfnDownloadAsync = (PFN_DownloadAsync)GetProcAddress(m_hEngineModule, "EngDownloadAsync");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnDownloadAsync)
|
|
{
|
|
hr = pfnDownloadAsync(m_hIUEngine,
|
|
bstrXmlClientInfo,
|
|
bstrXmlCatalog,
|
|
bstrDestinationFolder,
|
|
lMode,
|
|
punkProgressListener,
|
|
m_EvtWindow.GetEvtHWnd(),
|
|
bstrUuidOperation,
|
|
pbstrUuidOperation);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Install()
|
|
//
|
|
// Do synchronized installation.
|
|
// Input:
|
|
// bstrXmlCatalog - the xml catalog portion containing items to be installed
|
|
// bstrXmlDownloadedItems - the xml of downloaded items and their respective download
|
|
// result as described in the result schema. Install uses this
|
|
// to know whether the items were downloaded and if so where they
|
|
// were downloaded to so that it can install the items
|
|
// lMode - indicates different installation mode
|
|
// punkProgressListener - the callback function pointer for reporting install progress
|
|
// Output:
|
|
// pbstrXmlItems - the items with installation status in xml format
|
|
// e.g.
|
|
// <id guid="2560AD4D-3ED3-49C6-A937-4368C0B0E06D" installed="1"/>
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::Install(BSTR bstrXmlClientInfo,
|
|
BSTR bstrXmlCatalog,
|
|
BSTR bstrXmlDownloadedItems,
|
|
LONG lMode,
|
|
IUnknown* punkProgressListener,
|
|
BSTR* pbstrXmlItems)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LOG_Block("CUpdate::Install");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
if (m_fOfflineMode)
|
|
{
|
|
// make sure offline mode parameter is set if SetProperty() Offline Mode was Set
|
|
lMode |= UPDATE_OFFLINE_MODE;
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_Install pfnInstall = (PFN_Install)GetProcAddress(m_hEngineModule, "EngInstall");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnInstall)
|
|
{
|
|
hr = pfnInstall(m_hIUEngine,
|
|
bstrXmlClientInfo,
|
|
bstrXmlCatalog,
|
|
bstrXmlDownloadedItems,
|
|
lMode,
|
|
punkProgressListener,
|
|
m_EvtWindow.GetEvtHWnd(),
|
|
pbstrXmlItems);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// InstallAsync()
|
|
//
|
|
// Install Asynchronously.
|
|
// Input:
|
|
// bstrXmlCatalog - the xml catalog portion containing items to be installed
|
|
// bstrXmlDownloadedItems - the xml of downloaded items and their respective download
|
|
// result as described in the result schema. Install uses this
|
|
// to know whether the items were downloaded and if so where they
|
|
// were downloaded to so that it can install the items
|
|
// lMode - indicates different installation mode
|
|
// punkProgressListener - the callback function pointer for reporting install progress
|
|
// bstrUuidOperation - an id provided by the client to provide further
|
|
// identification to the operation as indexes may be reused.
|
|
// Output:
|
|
// pbstrUuidOperation - the operation ID. If it is not provided by the in bstrUuidOperation
|
|
// parameter (an empty string is passed), it will generate a new UUID,
|
|
// in which case, the caller will be responsible to free the memory of
|
|
// the string buffer that holds the generated UUID using SysFreeString().
|
|
// Otherwise, it returns the value passed by bstrUuidOperation.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::InstallAsync(BSTR bstrXmlClientInfo,
|
|
BSTR bstrXmlCatalog,
|
|
BSTR bstrXmlDownloadedItems,
|
|
LONG lMode,
|
|
IUnknown* punkProgressListener,
|
|
BSTR bstrUuidOperation,
|
|
BSTR* pbstrUuidOperation)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LOG_Block("CUpdate::InstallAsync");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
if (m_fOfflineMode)
|
|
{
|
|
// make sure offline mode parameter is set if SetProperty() Offline Mode was Set
|
|
lMode |= UPDATE_OFFLINE_MODE;
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_InstallAsync pfnInstallAsync = (PFN_InstallAsync)GetProcAddress(m_hEngineModule, "EngInstallAsync");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnInstallAsync)
|
|
{
|
|
hr = pfnInstallAsync(m_hIUEngine,
|
|
bstrXmlClientInfo,
|
|
bstrXmlCatalog,
|
|
bstrXmlDownloadedItems,
|
|
lMode,
|
|
punkProgressListener,
|
|
m_EvtWindow.GetEvtHWnd(),
|
|
bstrUuidOperation,
|
|
pbstrUuidOperation);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetOperationMode()
|
|
// Set the operation status.
|
|
//
|
|
// Input:
|
|
// bstrUuidOperation - an id provided by the client to provide further
|
|
// identification to the operation as indexes may be reused.
|
|
// lMode - the mode affecting the operation:
|
|
//
|
|
// UPDATE_COMMAND_PAUSE
|
|
// UPDATE_COMMAND_RESUME
|
|
// UPDATE_COMMAND_CANCEL
|
|
// UPDATE_NOTIFICATION_COMPLETEONLY
|
|
// UPDATE_NOTIFICATION_ANYPROGRESS
|
|
// UPDATE_NOTIFICATION_1PCT
|
|
// UPDATE_NOTIFICATION_5PCT
|
|
// UPDATE_NOTIFICATION_10PCT
|
|
// UPDATE_SHOWUI
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::SetOperationMode(
|
|
BSTR bstrUuidOperation,
|
|
LONG lMode)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LOG_Block("CUpdate::SetOperationMode");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_SetOperationMode pfnSetOperationMode = (PFN_SetOperationMode)GetProcAddress(m_hEngineModule, "EngSetOperationMode");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnSetOperationMode)
|
|
{
|
|
hr = pfnSetOperationMode(m_hIUEngine, bstrUuidOperation, lMode);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetHistory()
|
|
//
|
|
// Get the history log.
|
|
// Input:
|
|
// bstrDateTimeFrom - the start date and time for which a log is required.
|
|
// This is a string in ANSI format (YYYY-MM-DDTHH-MM).
|
|
// If the string is empty, there will be no date restriction
|
|
// of the returned history log.
|
|
// bstrDateTimeTo - the end date and time for which a log is required.
|
|
// This is a string in ANSI format (YYYY-MM-DDTHH-MM).
|
|
// If the string is empty, there will be no date restriction
|
|
// of the returned history log.
|
|
// bstrClient - the name of the client that initiated the action. If this parameter
|
|
// is null or an empty string, then there will be no filtering based
|
|
// on the client.
|
|
// bstrPath - the path used for download or install. Used in the corporate version
|
|
// by IT managers. If this parameter is null or an empty string, then
|
|
// there will be no filtering based on the path.
|
|
// Output:
|
|
// pbstrLog - the history log in xml format
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::GetHistory(BSTR bstrDateTimeFrom,
|
|
BSTR bstrDateTimeTo,
|
|
BSTR bstrClient,
|
|
BSTR bstrPath,
|
|
BSTR* pbstrLog)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LOG_Block("CUpdate::GetHistory");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_GetHistory pfnGetHistory = (PFN_GetHistory)GetProcAddress(m_hEngineModule, "EngGetHistory");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnGetHistory)
|
|
{
|
|
hr = pfnGetHistory(m_hIUEngine,
|
|
bstrDateTimeFrom,
|
|
bstrDateTimeTo,
|
|
bstrClient,
|
|
bstrPath,
|
|
pbstrLog);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// private overriding function InternalRelease(), to unlock the engine
|
|
// if the reference (before the release) is 1, i.e., the last ref
|
|
// count about to be released
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
ULONG CUpdate::InternalRelease()
|
|
{
|
|
if (1 == m_dwRef)
|
|
{
|
|
//
|
|
// the control is going to really gone, we need to make sure that
|
|
// if the engine is loaded, we unload it here.
|
|
//
|
|
UnlockEngine();
|
|
CleanupDownloadLib();
|
|
}
|
|
|
|
return CComObjectRootEx<CComMultiThreadModel>::InternalRelease();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// UnlockEngine()
|
|
//
|
|
// release the engine dll if ref cnt of engine is down to zero
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CUpdate::UnlockEngine()
|
|
{
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
TCHAR szSystemDir[MAX_PATH];
|
|
TCHAR szEngineDllPath[MAX_PATH];
|
|
TCHAR szEngineNewDllPath[MAX_PATH];
|
|
int iVerCheck = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
SetEvent(m_evtControlQuit);
|
|
|
|
EnterCriticalSection(&m_lock);
|
|
|
|
if (NULL != m_hEngineModule)
|
|
{
|
|
//
|
|
// We have to delete the engine instance we are using. This will clean up
|
|
// all resources, stop threads, etc. for the instance we own.
|
|
//
|
|
PFN_DeleteEngUpdateInstance pfnDeleteEngUpdateInstance = (PFN_DeleteEngUpdateInstance) GetProcAddress(m_hEngineModule, "DeleteEngUpdateInstance");
|
|
|
|
if (NULL != pfnDeleteEngUpdateInstance)
|
|
{
|
|
pfnDeleteEngUpdateInstance(m_hIUEngine);
|
|
}
|
|
|
|
//
|
|
// Cleanup any global threads (it checks to see if we are last instance)
|
|
//
|
|
PFN_ShutdownGlobalThreads pfnShutdownGlobalThreads = (PFN_ShutdownGlobalThreads) GetProcAddress(m_hEngineModule, "ShutdownGlobalThreads");
|
|
|
|
if (NULL != pfnShutdownGlobalThreads)
|
|
{
|
|
pfnShutdownGlobalThreads();
|
|
}
|
|
|
|
//
|
|
// unload engine
|
|
//
|
|
FreeLibrary(m_hEngineModule);
|
|
m_hEngineModule = NULL;
|
|
m_lInitState = 0; // mark as uninitialized
|
|
|
|
//
|
|
// get path of enginenew.dll
|
|
//
|
|
GetSystemDirectory(szSystemDir, ARRAYSIZE(szSystemDir));
|
|
hr = PathCchCombine(szEngineNewDllPath, ARRAYSIZE(szEngineNewDllPath), szSystemDir,ENGINENEWDLL);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// see if we should try to update the engine (locally)
|
|
//
|
|
HKEY hkey = NULL;
|
|
DWORD dwStatus = 0;
|
|
DWORD dwSize = sizeof(dwStatus);
|
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, &hkey))
|
|
{
|
|
RegQueryValueEx(hkey, REGVAL_SELFUPDATESTATUS, NULL, NULL, (LPBYTE)&dwStatus, &dwSize);
|
|
}
|
|
if (FileExists(szEngineNewDllPath) &&
|
|
S_OK == VerifyFileTrust(szEngineNewDllPath, NULL, ReadWUPolicyShowTrustUI()) &&
|
|
SELFUPDATE_COMPLETE_UPDATE_BINARY_REQUIRED == dwStatus)
|
|
{
|
|
// an iuenginenew.dll exists, try replacing the engine.dll This will fail if this is
|
|
// not the last process using the engine. This is not a problem, when that process
|
|
// finishes it will rename the DLL.
|
|
hr = PathCchCombine(szEngineDllPath, ARRAYSIZE(szEngineDllPath), szSystemDir,ENGINEDLL);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
if (SUCCEEDED(CompareFileVersion(szEngineDllPath, szEngineNewDllPath, &iVerCheck)) &&
|
|
iVerCheck < 0 &&
|
|
TRUE == MoveFileEx(szEngineNewDllPath, szEngineDllPath, MOVEFILE_REPLACE_EXISTING))
|
|
{
|
|
// Rename was Successful.. reset RegKey Information about SelfUpdate Status
|
|
// Because the rename was successful we know no other processes are interacting
|
|
// It should be safe to set the reg key.
|
|
dwStatus = 0; // PreFast
|
|
RegSetValueEx(hkey, REGVAL_SELFUPDATESTATUS, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(dwStatus));
|
|
}
|
|
}
|
|
else if (SELFUPDATE_COMPLETE_UPDATE_BINARY_REQUIRED == dwStatus)
|
|
{
|
|
// registry indicates rename required, but enginenew DLL does not exist. Reset registry
|
|
dwStatus = 0;
|
|
RegSetValueEx(hkey, REGVAL_SELFUPDATESTATUS, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(dwStatus));
|
|
}
|
|
if (NULL != hkey)
|
|
{
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&m_lock);
|
|
ResetEvent(m_evtControlQuit);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
*
|
|
* Get the mode of a specified operation.
|
|
*
|
|
* @param bstrUuidOperation: same as in SetOperationMode()
|
|
* @param plMode - the retval for the mode found in a bitmask for:
|
|
* (value in brackets [] means default)
|
|
* UPDATE_COMMAND_PAUSE (TRUE/[FALSE])
|
|
* UPDATE_COMMAND_RESUME (TRUE/[FALSE])
|
|
* UPDATE_NOTIFICATION_COMPLETEONLY (TRUE/[FALSE])
|
|
* UPDATE_NOTIFICATION_ANYPROGRESS ([TRUE]/FALSE)
|
|
* UPDATE_NOTIFICATION_1PCT (TRUE/[FALSE])
|
|
* UPDATE_NOTIFICATION_5PCT (TRUE/[FALSE])
|
|
* UPDATE_NOTIFICATION_10PCT (TRUE/[FALSE])
|
|
* UPDATE_SHOWUI (TRUE/[FALSE])
|
|
*
|
|
*/
|
|
STDMETHODIMP CUpdate::GetOperationMode(BSTR bstrUuidOperation, LONG *plMode)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LOG_Block("CUpdate::GetOperationMode");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_GetOperationMode pfnGetOperationMode = (PFN_GetOperationMode)GetProcAddress(m_hEngineModule, "EngGetOperationMode");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnGetOperationMode)
|
|
{
|
|
hr = pfnGetOperationMode(m_hIUEngine, bstrUuidOperation, plMode);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
*
|
|
* Set a property of this control
|
|
* Calling this method will not cause the engine loaded
|
|
*
|
|
* @param lProperty - the identifier to flag which property need changed
|
|
* UPDATE_PROP_OFFLINEMODE (TRUE/[FALSE])
|
|
* UPDATE_PROP_USECOMPRESSION ([TRUE]/FALSE)
|
|
*
|
|
* @param varValue - the value to change
|
|
*
|
|
*/
|
|
STDMETHODIMP CUpdate::SetProperty(LONG lProperty, VARIANT varValue)
|
|
{
|
|
LOG_Block("CUpdate::SetProperty");
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
switch(lProperty)
|
|
{
|
|
case UPDATE_PROP_USECOMPRESSION:
|
|
if (VT_BOOL != varValue.vt)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
LOG_ErrorMsg(hr);
|
|
}
|
|
else
|
|
{
|
|
m_fUseCompression = (VARIANT_TRUE == varValue.boolVal) ? TRUE : FALSE;
|
|
}
|
|
break;
|
|
case UPDATE_PROP_OFFLINEMODE:
|
|
if (VT_BOOL != varValue.vt)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
LOG_ErrorMsg(hr);
|
|
}
|
|
else
|
|
{
|
|
m_fOfflineMode = (VARIANT_TRUE == varValue.boolVal) ? TRUE : FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
*
|
|
* Retrieve a property of this control
|
|
* Calling this method will not cause the engine loaded
|
|
*
|
|
* @param lProperty - the identifier to flag which property need retrieved
|
|
* UPDATE_PROP_OFFLINEMODE (TRUE/[FALSE])
|
|
* UPDATE_PROP_USECOMPRESSION ([TRUE]/FALSE)
|
|
*
|
|
* @param varValue - the value to retrieve
|
|
*
|
|
*/
|
|
STDMETHODIMP CUpdate::GetProperty(LONG lProperty, VARIANT *pvarValue)
|
|
{
|
|
LOG_Block("CUpdate::GetProperty");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
if (NULL == pvarValue)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
VariantInit(pvarValue);
|
|
|
|
switch(lProperty)
|
|
{
|
|
case UPDATE_PROP_USECOMPRESSION:
|
|
pvarValue->vt = VT_BOOL;
|
|
pvarValue->boolVal = (m_fUseCompression) ? VARIANT_TRUE : VARIANT_FALSE;
|
|
break;
|
|
case UPDATE_PROP_OFFLINEMODE:
|
|
pvarValue->vt = VT_BOOL;
|
|
pvarValue->boolVal = (m_fOfflineMode) ? VARIANT_TRUE : VARIANT_FALSE;
|
|
break;
|
|
default:
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Primarily expose shlwapi BrowseForFolder API, can also do checking
|
|
// on R/W access if flagged so.
|
|
//
|
|
// @param bstrStartFolder - the folder from which to start. If NULL or empty str
|
|
// is being passed in, then start from desktop
|
|
//
|
|
// @param flag - validating check
|
|
// UI_WRITABLE for checking write access, OK button may disabled.
|
|
// UI_READABLE for checking read access, OK button may disabled.
|
|
// NO_UI_WRITABLE for checking write access, return error if no access
|
|
// NO_UI_READABLE for checking read access, return error if no access
|
|
// 0 (default) for no checking.
|
|
//
|
|
// @param pbstrFolder - returned folder if a valid folder selected
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::BrowseForFolder(BSTR bstrStartFolder, LONG flag, BSTR* pbstrFolder)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
LOG_Block("CUpdate::BrowseForFolder");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
//
|
|
// engine is current, delegate the call to engine
|
|
//
|
|
PFN_BrowseForFolder pfnBrowseForFolder = (PFN_BrowseForFolder)GetProcAddress(m_hEngineModule, "EngBrowseForFolder");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnBrowseForFolder)
|
|
{
|
|
hr = pfnBrowseForFolder(m_hIUEngine, bstrStartFolder, flag, pbstrFolder);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Allows the Caller to Request the Control to do a Reboot
|
|
*
|
|
*/
|
|
STDMETHODIMP CUpdate::RebootMachine()
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
LOG_Block("CUpdate::RebootMachine");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
|
|
//
|
|
// load the engine if it's not up-to-date
|
|
//
|
|
if (Initialized && SUCCEEDED(hr = ValidateControlContainer()))
|
|
{
|
|
PFN_RebootMachine pfnRebootMachine = (PFN_RebootMachine)GetProcAddress(m_hEngineModule, "EngRebootMachine");
|
|
|
|
if (NULL != m_hIUEngine && NULL != pfnRebootMachine)
|
|
{
|
|
hr = pfnRebootMachine(m_hIUEngine);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(ERROR_INVALID_DLL);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DLL);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Override of IObjectWithSite::SetSite()
|
|
// Internet Explorer QIs for IObjectWithSite, and calls this method
|
|
// with a pointer to its IOleClientSite
|
|
//
|
|
STDMETHODIMP CUpdate::SetSite(IUnknown* pSite)
|
|
{
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
SafeReleaseNULL(m_pClientSite);
|
|
m_pClientSite = pSite;
|
|
if (NULL != m_pClientSite)
|
|
m_pClientSite->AddRef();
|
|
return IObjectWithSiteImpl<CUpdate>::SetSite(pSite);
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
*
|
|
* Security feature: make sure if the user of this control is
|
|
* a web page then the URL can be found in iuident.txt
|
|
*
|
|
* This function should be called after iuident refreshed.
|
|
*
|
|
* Return: TRUE/FALSE, to tell if we can continue
|
|
*
|
|
*/
|
|
|
|
|
|
const TCHAR IDENT_IUSERVERCACHE[] = _T("IUServerURLs");
|
|
const TCHAR IDENT_IUSERVERCOUNT[] = _T("ServerCount");
|
|
const TCHAR IDENT_IUSERVER[] = _T("Server");
|
|
|
|
|
|
|
|
HRESULT CUpdate::ValidateControlContainer(void)
|
|
{
|
|
LOG_Block("ValidateControlContainer");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
IServiceProvider* pISP = NULL;
|
|
IWebBrowserApp* pWeb = NULL;
|
|
BSTR bstrUrl = NULL;
|
|
LPTSTR lpszUrl = NULL;
|
|
#if !(defined(_UNICODE) || defined(UNICODE))
|
|
// ANSI build
|
|
LPSTR lpszAnsiUrl = NULL;
|
|
#endif
|
|
TCHAR szIUDir[MAX_PATH];
|
|
TCHAR szIdentFile[MAX_PATH];
|
|
TCHAR szServer[32];
|
|
LPTSTR szValidURL = NULL;
|
|
|
|
if (E_FAIL != m_hValidated)
|
|
{
|
|
//
|
|
// has been invalidated already
|
|
//
|
|
LOG_Internet(_T("Validate result: %s"), SUCCEEDED(m_hValidated) ? _T("S_OK") : _T("INET_E_INVALID_URL"));
|
|
return m_hValidated;
|
|
}
|
|
//
|
|
// check to see if the container is a web page/site, if
|
|
// not done so yet.
|
|
//
|
|
if (NULL != m_pClientSite)
|
|
{
|
|
//
|
|
// this is a web site!
|
|
//
|
|
m_hValidated = INET_E_INVALID_URL;
|
|
LOG_Internet(_T("Found control called by a web page"));
|
|
|
|
if (SUCCEEDED(m_pClientSite->QueryInterface(IID_IServiceProvider, (void**)&pISP)) &&
|
|
NULL != pISP &&
|
|
SUCCEEDED(pISP->QueryService(IID_IWebBrowserApp, IID_IWebBrowserApp, (void**)&pWeb)) &&
|
|
NULL != pWeb &&
|
|
SUCCEEDED(pWeb->get_LocationURL(&bstrUrl)) &&
|
|
NULL != bstrUrl)
|
|
{
|
|
#if defined(_UNICODE) || defined(UNICODE)
|
|
lpszUrl = bstrUrl;
|
|
#else // ANSI build
|
|
int nBufferLength = WideCharToMultiByte(CP_ACP, 0, bstrUrl, -1, NULL, 0, NULL, NULL);
|
|
|
|
lpszAnsiUrl = (LPSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nBufferLength);
|
|
if (NULL == lpszAnsiUrl || 0 == nBufferLength)
|
|
{
|
|
//
|
|
// Unfortunately, we return this error in place of E_OUTOFMEMORY, but the most
|
|
// likely scenario that would cause this would be a security attack (bad URL)
|
|
//
|
|
goto CleanUp; // Will return INET_E_INVALID_URL
|
|
}
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, bstrUrl, -1, lpszAnsiUrl, nBufferLength, NULL, NULL);
|
|
lpszUrl = lpszAnsiUrl;
|
|
#endif
|
|
|
|
LOG_Internet(_T("Web address = %s"), lpszUrl);
|
|
|
|
//
|
|
// no matter what protocol specified in this URL
|
|
// (can be anything: http, ftp, UNC, path...)
|
|
// we just need to verify it against iuident.txt
|
|
//
|
|
|
|
szValidURL = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
|
|
if (NULL == szValidURL)
|
|
{
|
|
SafeReleaseNULL(pISP);
|
|
SafeReleaseNULL(pWeb);
|
|
SysFreeString(bstrUrl);
|
|
LOG_ErrorMsg(E_OUTOFMEMORY);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
GetIndustryUpdateDirectory(szIUDir);
|
|
m_hValidated = PathCchCombine(szIdentFile, ARRAYSIZE(szIdentFile), szIUDir,IDENTTXT);
|
|
if (FAILED(m_hValidated))
|
|
{
|
|
SafeReleaseNULL(pISP);
|
|
SafeReleaseNULL(pWeb);
|
|
SysFreeString(bstrUrl);
|
|
SafeHeapFree(szValidURL);
|
|
LOG_ErrorMsg(m_hValidated);
|
|
return m_hValidated;
|
|
}
|
|
|
|
// Fix of bug 557430: IU: Security: Use InternetCrackUrl to verify server url used by control.
|
|
URL_COMPONENTS urlComp;
|
|
ZeroMemory(&urlComp, sizeof(urlComp));
|
|
urlComp.dwStructSize = sizeof(urlComp);
|
|
|
|
// Only interested in the hostname
|
|
LPTSTR pszHostName = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
|
|
urlComp.lpszHostName = pszHostName;
|
|
urlComp.dwHostNameLength = INTERNET_MAX_URL_LENGTH;
|
|
|
|
#if defined(UNICODE)
|
|
pfn_InternetCrackUrl pfnInternetCrackUrl = (pfn_InternetCrackUrl)GetProcAddress(
|
|
GetModuleHandle(_T("wininet.dll")), "InternetCrackUrlW");
|
|
#else
|
|
pfn_InternetCrackUrl pfnInternetCrackUrl = (pfn_InternetCrackUrl)GetProcAddress(
|
|
GetModuleHandle(_T("wininet.dll")), "InternetCrackUrlA");
|
|
#endif
|
|
|
|
if (pfnInternetCrackUrl != NULL)
|
|
{
|
|
BOOL fRet = (*pfnInternetCrackUrl)(lpszUrl, 0, 0, &urlComp);
|
|
if (fRet==FALSE) {
|
|
SafeHeapFree(pszHostName);
|
|
m_hValidated = INET_E_INVALID_URL;
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SafeHeapFree(pszHostName);
|
|
SafeReleaseNULL(pISP);
|
|
SafeReleaseNULL(pWeb);
|
|
SysFreeString(bstrUrl);
|
|
SafeHeapFree(szValidURL);
|
|
m_hValidated = ERROR_PROC_NOT_FOUND;
|
|
LOG_ErrorMsg(m_hValidated);
|
|
return m_hValidated;
|
|
}
|
|
|
|
//
|
|
// get number to servers to compare
|
|
//
|
|
int iServerCnt = GetPrivateProfileInt(IDENT_IUSERVERCACHE,
|
|
IDENT_IUSERVERCOUNT,
|
|
-1,
|
|
szIdentFile);
|
|
|
|
//
|
|
// loop through
|
|
//
|
|
URL_COMPONENTS urlCompi;
|
|
m_hValidated = INET_E_INVALID_URL;
|
|
for (INT i=1; i<=iServerCnt; i++)
|
|
{
|
|
StringCchPrintfEx(szServer,ARRAYSIZE(szServer),NULL,NULL,MISTSAFE_STRING_FLAGS,_T("%s%d"), IDENT_IUSERVER, i);
|
|
|
|
//
|
|
// get valid server from iuident
|
|
//
|
|
GetPrivateProfileString(IDENT_IUSERVERCACHE,
|
|
szServer,
|
|
_T(""),
|
|
szValidURL,
|
|
INTERNET_MAX_URL_LENGTH,
|
|
szIdentFile);
|
|
|
|
ZeroMemory(&urlCompi, sizeof(urlCompi));
|
|
urlCompi.dwStructSize = sizeof(urlCompi);
|
|
|
|
LPTSTR pszHostNamei = (LPTSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
|
|
urlCompi.lpszHostName = pszHostNamei;
|
|
urlCompi.dwHostNameLength = INTERNET_MAX_URL_LENGTH;
|
|
|
|
if (TRUE == (*pfnInternetCrackUrl)(szValidURL, 0, 0, &urlCompi))
|
|
{
|
|
if (0 == lstrcmpi(urlComp.lpszHostName, urlCompi.lpszHostName))
|
|
{
|
|
//
|
|
// Found the current site URL is in this valid URL domain!
|
|
//
|
|
LogMessage("Windows Update Web Site has a valid address: %ls", bstrUrl);
|
|
m_hValidated = S_OK;
|
|
SafeHeapFree(pszHostNamei);
|
|
break;
|
|
}
|
|
}
|
|
SafeHeapFree(pszHostNamei);
|
|
}
|
|
SafeHeapFree(pszHostName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// NTRAID#NTBUG9-436604-2001/07/17-waltw Security fix: block possible user system information
|
|
// leak to non WU callers
|
|
//
|
|
// If the COM user doesn't call SetSite on our IObjectWithSiteImpl to set m_pClientSite or doesn't
|
|
// support IID_IWebBrowserApp functionality on the client site then we won't support them since
|
|
// we can't validate the URL that invoked us
|
|
//
|
|
m_hValidated = INET_E_INVALID_URL;
|
|
}
|
|
|
|
CleanUp:
|
|
SafeReleaseNULL(pISP);
|
|
SafeReleaseNULL(pWeb);
|
|
SysFreeString(bstrUrl);
|
|
SafeHeapFree(szValidURL);
|
|
|
|
LOG_Internet(_T("Validate result: %s"), SUCCEEDED(m_hValidated) ? _T("S_OK") : _T("INET_E_INVALID_URL"));
|
|
|
|
if (FAILED(m_hValidated) && NULL != lpszUrl)
|
|
{
|
|
#if defined(UNICODE) || defined(_UNICODE)
|
|
LogError(m_hValidated, "Site URL %ls is not valid", lpszUrl);
|
|
#else
|
|
LogError(m_hValidated, "Site URL %s is not valid", lpszUrl);
|
|
#endif
|
|
}
|
|
|
|
|
|
#if !(defined(UNICODE) || defined(_UNICODE))
|
|
if (NULL != lpszAnsiUrl)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID) lpszAnsiUrl);
|
|
}
|
|
#endif
|
|
|
|
return m_hValidated;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PRIVATE DetectEngine()
|
|
//
|
|
// download the ident and find out if need to update engine
|
|
//
|
|
// Note that this function itself is not thread safe. Need to call it
|
|
// inside critical section
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CUpdate::DetectEngine(BOOL *pfUpdateAvail)
|
|
{
|
|
LOG_Block("GetPropUpdateInfo()");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (NULL == pfUpdateAvail)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pfUpdateAvail = FALSE;
|
|
|
|
//
|
|
// get the latest ident
|
|
//
|
|
if (NULL == m_hEngineModule)
|
|
{
|
|
//
|
|
// This is the first load of the engine for this instance, check for selfupdate first.
|
|
// First step is to check for an updated iuident.cab and download it.
|
|
//
|
|
|
|
//
|
|
// Only Download the Ident if we are NOT in Offline Mode
|
|
//
|
|
if (!m_fOfflineMode)
|
|
{
|
|
//
|
|
// download iuident and populate g_pIUUrlAgent
|
|
//
|
|
if (FAILED(hr = DownloadIUIdent_PopulateData()))
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// check engine update info. Note that since 2nd pram is FALSE
|
|
// means don't do any actual update, therefore its 1st argument
|
|
// is also ignored.
|
|
//
|
|
hr = SelfUpdateCheck(
|
|
FALSE, // async update? ignored now
|
|
FALSE, // don't do actual update
|
|
m_evtControlQuit, // quit event.
|
|
NULL, // no event firing
|
|
NULL // no callback needed
|
|
);
|
|
|
|
if (IU_SELFUPDATE_FAILED == hr)
|
|
{
|
|
LOG_Error(_T("SelfUpdate Failed, using current Engine DLL"));
|
|
hr = S_FALSE; // not fatal, let the existing engine work
|
|
}
|
|
|
|
*pfUpdateAvail = (S_FALSE == hr);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Initialize() API must be called before any other API will function
|
|
//
|
|
// If any other API is called before the control is initialized,
|
|
// that API will return OLE_E_BLANK, signalling this OLE control is an
|
|
// uninitialized object (although in this case it's a bit different from
|
|
// its original meaning)
|
|
//
|
|
// Parameters:
|
|
//
|
|
// lInitFlag - IU_INIT_CHECK, cause Initialize() download ident and check if any
|
|
// of the components need updated. currently we support control version
|
|
// check and engine version check. Return value is a bit mask
|
|
//
|
|
// - IU_INIT_UPDATE_SYNC, cause Initialize() kicks off update engine
|
|
// process if already called by IU_INIT_CHECK and a new engine is available.
|
|
// When API returns, the update process is finished.
|
|
//
|
|
// - IU_INIT_UPDATE_ASYNC, cause Initialize() kicks off update engine
|
|
// process in Asynchronized mode if already called by IU_INIT_CHECK and
|
|
// a new engine is available. This API will return right after the
|
|
// update process starts.
|
|
//
|
|
// punkUpdateCompleteListener - this is a pointer to a user-implemented
|
|
// COM callback feature. It contains only one function OnComplete() that
|
|
// will be called when the engine update is done.
|
|
// This value can be NULL.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::Initialize(LONG lInitFlag, IUnknown *punkUpdateCompleteListener, LONG *plRetVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
LOG_Block("Initialize()");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
TCHAR szFilePath[MAX_PATH + 1] = {0};
|
|
FILE_VERSION verControl;
|
|
int iCompareResult = 0;
|
|
DWORD dwErr = 0;
|
|
char szAnsiRequiredControlVersion[64];
|
|
|
|
LOG_Out(_T("Parameters: (0x%08x, 0x%08x, 0x%08x)"), lInitFlag, punkUpdateCompleteListener, plRetVal);
|
|
|
|
//
|
|
// we should to previlidge check first.
|
|
//
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED);
|
|
}
|
|
if (0x0 == GetLogonGroupInfo())
|
|
{
|
|
//
|
|
// if the current logon is neither member of admins nor power users
|
|
// or windows update is disabled, there is no need to continue
|
|
//
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
|
|
USES_CONVERSION;
|
|
|
|
EnterCriticalSection(&m_lock);
|
|
|
|
LPTSTR ptszLivePingServerUrl = NULL;
|
|
LPTSTR ptszCorpPingServerUrl = NULL;
|
|
|
|
if (NULL != (ptszCorpPingServerUrl = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR))))
|
|
{
|
|
if (FAILED(g_pIUUrlAgent->GetCorpPingServer(ptszCorpPingServerUrl, INTERNET_MAX_URL_LENGTH)))
|
|
{
|
|
LOG_Out(_T("failed to get corp WU ping server URL"));
|
|
SafeHeapFree(ptszCorpPingServerUrl);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_Out(_T("failed to allocate memory for ptszCorpPingServerUrl"));
|
|
}
|
|
|
|
if (IU_INIT_CHECK == lInitFlag)
|
|
{
|
|
// RAID: 453770 IU - IUCTL - Initialize check returns Engine update required
|
|
// after downloading new engine using Initialize Sync/Async
|
|
// Fix: initialize dwFlag to 0 rather than m_dwUpdateInfo (carried forward
|
|
// previous IU_UPDATE_ENGINE_BIT even when new engine had been brought down).
|
|
DWORD dwFlag = 0;
|
|
BOOL fEngineUpdate = FALSE;
|
|
|
|
FILE_VERSION verCurrent;
|
|
|
|
|
|
CleanUpIfFalseAndSetHrMsg((NULL == plRetVal), E_INVALIDARG);
|
|
|
|
hr = DetectEngine(&fEngineUpdate);
|
|
if (IU_SELFUPDATE_USENEWDLL == hr)
|
|
{
|
|
//
|
|
// found engine already been updated by someone,
|
|
// but not renamed to iuengine.dll yet
|
|
//
|
|
// doesn't matter to us,since we always try
|
|
// to load enginenew before we try to load eng.
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
|
|
if (g_pIUUrlAgent->HasBeenPopulated())
|
|
{
|
|
ptszLivePingServerUrl = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INTERNET_MAX_URL_LENGTH * sizeof(TCHAR));
|
|
CleanUpFailedAllocSetHrMsg(ptszLivePingServerUrl);
|
|
|
|
if (FAILED(g_pIUUrlAgent->GetLivePingServer(ptszLivePingServerUrl, INTERNET_MAX_URL_LENGTH)))
|
|
{
|
|
LOG_Out(_T("failed to get live ping server URL"));
|
|
SafeHeapFree(ptszLivePingServerUrl);
|
|
}
|
|
}
|
|
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
if (fEngineUpdate)
|
|
{
|
|
dwFlag = IU_UPDATE_ENGINE_BIT;
|
|
}
|
|
|
|
//
|
|
// get required version number of iuctl from iuident
|
|
//
|
|
|
|
GetIndustryUpdateDirectory(szFilePath);
|
|
CleanUpIfFailedAndSetHrMsg(PathCchAppend(szFilePath, ARRAYSIZE(szFilePath), IDENTTXT));
|
|
|
|
(void) GetPrivateProfileString(
|
|
_T("IUControl"),
|
|
_T("ControlVer"),
|
|
_T("0.0.0.0"),
|
|
m_szReqControlVer,
|
|
ARRAYSIZE(m_szReqControlVer),
|
|
szFilePath);
|
|
|
|
#ifdef UNICODE
|
|
WideCharToMultiByte(CP_ACP, 0, m_szReqControlVer, -1, szAnsiRequiredControlVersion,
|
|
sizeof(szAnsiRequiredControlVersion), NULL, NULL);
|
|
ConvertStringVerToFileVer(szAnsiRequiredControlVersion, &verControl);
|
|
#else
|
|
ConvertStringVerToFileVer(m_szReqControlVer, &verControl);
|
|
#endif
|
|
|
|
//
|
|
// get current iuctl.dll version number
|
|
//
|
|
szFilePath[0] = _T('\0');
|
|
if (0 == GetSystemDirectory(szFilePath, ARRAYSIZE(szFilePath)))
|
|
{
|
|
Win32MsgSetHrGotoCleanup(GetLastError());
|
|
}
|
|
|
|
CleanUpIfFailedAndSetHrMsg(PathCchAppend(szFilePath, ARRAYSIZE(szFilePath), _T("iuctl.dll")));
|
|
|
|
//
|
|
// change for bug fix 488487 by charlma 11/30/2001
|
|
// in order to output file ver to freelog, we dig out verionn here:
|
|
//
|
|
|
|
//
|
|
// if we failed to get the version, GetFileVersion() alraedy produced debug log.
|
|
// we just use 0.0.0.0 to do compare, since in that case we need to update it!
|
|
//
|
|
ZeroMemory((void*)(&verCurrent), sizeof(verCurrent));
|
|
if (GetFileVersion(szFilePath, &verCurrent))
|
|
{
|
|
LogMessage("Current iuctl.dll version: %d.%d.%d.%d",
|
|
verCurrent.Major,
|
|
verCurrent.Minor,
|
|
verCurrent.Build,
|
|
verCurrent.Ext);
|
|
}
|
|
iCompareResult = CompareFileVersion(verCurrent, verControl);
|
|
|
|
//CleanUpIfFailedAndSetHrMsg(CompareFileVersion(szFilePath, verControl, &iCompareResult));
|
|
|
|
if (iCompareResult < 0)
|
|
{
|
|
//
|
|
// if current control dll (szFilePath) has lower version
|
|
// then the one specified in ident
|
|
//
|
|
dwFlag |= IU_UPDATE_CONTROL_BIT;
|
|
|
|
#if defined(UNICODE) || defined(_UNICODE)
|
|
LogMessage("IUCtl needs update to %ls", m_szReqControlVer);
|
|
#else
|
|
LogMessage("IUCtl needs update to %s", m_szReqControlVer);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// also output engine version
|
|
//
|
|
if ((0 != GetSystemDirectory(szFilePath, ARRAYSIZE(szFilePath)) &&
|
|
SUCCEEDED(hr = PathCchAppend(szFilePath, ARRAYSIZE(szFilePath), _T("iuenginenew.dll"))) &&
|
|
GetFileVersion(szFilePath, &verCurrent)) ||
|
|
(0 != GetSystemDirectory(szFilePath, ARRAYSIZE(szFilePath)) &&
|
|
SUCCEEDED(hr = PathCchAppend(szFilePath, ARRAYSIZE(szFilePath), _T("iuengine.dll"))) &&
|
|
GetFileVersion(szFilePath, &verCurrent))
|
|
)
|
|
{
|
|
LogMessage("Current iuengine.dll version: %d.%d.%d.%d",
|
|
verCurrent.Major,
|
|
verCurrent.Minor,
|
|
verCurrent.Build,
|
|
verCurrent.Ext);
|
|
}
|
|
|
|
|
|
*plRetVal = (LONG) dwFlag;
|
|
m_dwUpdateInfo = dwFlag;
|
|
|
|
if (0x0 == dwFlag)
|
|
{
|
|
//
|
|
// no update needed. move to READY stage
|
|
//
|
|
m_lInitState = 2;
|
|
}
|
|
else
|
|
{
|
|
m_lInitState = 1; // we have update work to do!
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BOOL fSync = (IU_INIT_UPDATE_SYNC == lInitFlag);
|
|
|
|
if (!fSync && (IU_INIT_UPDATE_ASYNC != lInitFlag))
|
|
{
|
|
//
|
|
// unknown flag
|
|
//
|
|
SetHrMsgAndGotoCleanUp(E_INVALIDARG);
|
|
}
|
|
|
|
if (1 != m_lInitState || (m_dwUpdateInfo & IU_UPDATE_CONTROL_BIT))
|
|
{
|
|
//
|
|
// if we are not indicated that update needed. this
|
|
// call shouldn't happen at all!
|
|
//
|
|
SetHrMsgAndGotoCleanUp(E_UNEXPECTED);
|
|
}
|
|
|
|
//
|
|
// we need to check update again before we kick off the
|
|
// actual update process since we don't know when last
|
|
// time you get the info saying we need to update. Probably
|
|
// it's already been updated, or is being updated.
|
|
//
|
|
// so we call the check function again but this time tell
|
|
// the check function that if update needed then do it.
|
|
//
|
|
hr = SelfUpdateCheck(fSync, TRUE, m_evtControlQuit, this, punkUpdateCompleteListener);
|
|
if (IU_SELFUPDATE_USENEWDLL == hr)
|
|
{
|
|
//
|
|
// found engine already been updated by someone,
|
|
// but not renamed to iuengine.dll yet
|
|
//
|
|
// doesn't matter to us,since we always try
|
|
// to load enginenew before we try to load eng.
|
|
//
|
|
m_lInitState = 2;
|
|
hr = S_OK;
|
|
}
|
|
|
|
|
|
if (fSync && SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// synchronized update done and successful
|
|
//
|
|
m_lInitState = 2;
|
|
}
|
|
|
|
|
|
if (NULL != plRetVal)
|
|
{
|
|
*plRetVal = (LONG)hr; // result pass out: 0 or error code
|
|
|
|
}
|
|
}
|
|
|
|
if (2 == m_lInitState)
|
|
{
|
|
if (NULL == m_hEngineModule)
|
|
{
|
|
//
|
|
// check if iuengine new exist and validate the file
|
|
//
|
|
TCHAR szEnginePath[MAX_PATH + 1];
|
|
TCHAR szEngineNewPath[MAX_PATH + 1];
|
|
int cch = 0;
|
|
int iVerCheck = 0;
|
|
|
|
cch = GetSystemDirectory(szEnginePath, ARRAYSIZE(szEnginePath));
|
|
CleanUpIfFalseAndSetHrMsg(cch == 0 || cch >= ARRAYSIZE(szEnginePath), HRESULT_FROM_WIN32(GetLastError()));
|
|
|
|
(void) StringCchCopy(szEngineNewPath, ARRAYSIZE(szEngineNewPath), szEnginePath);
|
|
|
|
hr = PathCchAppend(szEnginePath, ARRAYSIZE(szEnginePath), ENGINEDLL);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
hr = PathCchAppend(szEngineNewPath, ARRAYSIZE(szEngineNewPath), ENGINENEWDLL);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
//
|
|
// try to verify trust of engine new
|
|
//
|
|
if (FileExists(szEngineNewPath) &&
|
|
S_OK == VerifyFileTrust(szEngineNewPath, NULL, ReadWUPolicyShowTrustUI()) &&
|
|
SUCCEEDED(CompareFileVersion(szEnginePath, szEngineNewPath, &iVerCheck)) &&
|
|
iVerCheck < 0)
|
|
{
|
|
//
|
|
// load the engine
|
|
//
|
|
m_hEngineModule = LoadLibraryFromSystemDir(_T("iuenginenew.dll"));
|
|
}
|
|
if (NULL != m_hEngineModule)
|
|
{
|
|
LOG_Internet(_T("IUCtl Using IUENGINENEW.DLL"));
|
|
}
|
|
else
|
|
{
|
|
LOG_Internet(_T("IUCtl Using IUENGINE.DLL"));
|
|
m_hEngineModule = LoadLibraryFromSystemDir(_T("iuengine.dll"));
|
|
|
|
if (NULL == m_hEngineModule)
|
|
{
|
|
dwErr = GetLastError();
|
|
LOG_ErrorMsg(dwErr);
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If load engine succeeded, get a CEngUpdate instance and start aynsc misc worker threads
|
|
//
|
|
if (NULL != m_hEngineModule)
|
|
{
|
|
#if defined(DBG)
|
|
// Log error if m_hIUEngine isn't NULL
|
|
if (NULL != m_hIUEngine)
|
|
{
|
|
LOG_Error(_T("m_hIUEngine should be NULL here!"));
|
|
}
|
|
#endif
|
|
|
|
PFN_CreateEngUpdateInstance pfnCreateEngUpdateInstance =
|
|
(PFN_CreateEngUpdateInstance) GetProcAddress(m_hEngineModule, "CreateEngUpdateInstance");
|
|
|
|
if (NULL != pfnCreateEngUpdateInstance)
|
|
{
|
|
m_hIUEngine = pfnCreateEngUpdateInstance();
|
|
}
|
|
|
|
if (NULL == m_hIUEngine)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
LOG_ErrorMsg(hr);
|
|
FreeLibrary(m_hEngineModule);
|
|
m_hEngineModule = NULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If load engine and create instance succeeded, start aynsc misc worker threads
|
|
//
|
|
PFN_AsyncExtraWorkUponEngineLoad pfnAsyncExtraWorkUponEngineLoad =
|
|
(PFN_AsyncExtraWorkUponEngineLoad) GetProcAddress(m_hEngineModule, "AsyncExtraWorkUponEngineLoad");
|
|
|
|
if (NULL != pfnAsyncExtraWorkUponEngineLoad)
|
|
{
|
|
pfnAsyncExtraWorkUponEngineLoad();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (IU_INIT_UPDATE_ASYNC == lInitFlag && SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// this is a rare case: the previous Iniitalize() call tells
|
|
// that engine update needed, but now, when we try to update it
|
|
// in async mode, we found it's no longer true.
|
|
// Must be some other process already complete the engine update
|
|
// task since then. But it may or may not completed the change
|
|
// file name process yet.
|
|
//
|
|
// For us, we just need to signal that we are done to update.
|
|
//
|
|
|
|
//
|
|
// signal callback
|
|
//
|
|
IUpdateCompleteListener* pCallback = NULL;
|
|
if (NULL != punkUpdateCompleteListener && (SUCCEEDED(hr = punkUpdateCompleteListener->QueryInterface(IID_IUpdateCompleteListener, (void**) &pCallback))))
|
|
{
|
|
pCallback->OnComplete(dwErr);
|
|
pCallback->Release();
|
|
LOG_Out(_T("Returned from callback API OnComplete()"));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// signal event if user has not passed in a progress listner IUnknown ptr
|
|
//
|
|
HWND hWnd = m_EvtWindow.GetEvtHWnd();
|
|
|
|
if (NULL != hWnd)
|
|
{
|
|
PostMessage(hWnd, UM_EVENT_SELFUPDATE_COMPLETE, 0, (LPARAM)dwErr);
|
|
LOG_Out(_T("Fired event OnComplete()"));
|
|
}
|
|
}
|
|
|
|
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
PingEngineUpdate(
|
|
m_hEngineModule,
|
|
&g_hEngineLoadQuit,
|
|
1,
|
|
ptszLivePingServerUrl,
|
|
ptszCorpPingServerUrl,
|
|
hr,
|
|
_T("IU_SITE")); // Only the site (other than test) calls this function
|
|
|
|
LeaveCriticalSection(&m_lock);
|
|
|
|
SafeHeapFree(ptszLivePingServerUrl);
|
|
SafeHeapFree(ptszCorpPingServerUrl);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT CUpdate::ChangeControlInitState(LONG lNewState)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LOG_Block("ChangeControlInitState()");
|
|
|
|
if (!m_gfInit_csLock)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
EnterCriticalSection(&m_lock);
|
|
m_lInitState = lNewState;
|
|
if (2 == m_lInitState && NULL == m_hEngineModule)
|
|
{
|
|
//
|
|
// load the engine
|
|
//
|
|
m_hEngineModule = LoadLibraryFromSystemDir(_T("iuenginenew.dll"));
|
|
if (NULL != m_hEngineModule)
|
|
{
|
|
LOG_Internet(_T("IUCtl Using IUENGINENEW.DLL"));
|
|
}
|
|
else
|
|
{
|
|
LOG_Internet(_T("IUCtl Using IUENGINE.DLL"));
|
|
m_hEngineModule = LoadLibraryFromSystemDir(_T("iuengine.dll"));
|
|
|
|
if (NULL == m_hEngineModule)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
LOG_ErrorMsg(dwErr);
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
}
|
|
}
|
|
//
|
|
// Create the CEngUpdate instance
|
|
//
|
|
if (NULL != m_hEngineModule)
|
|
{
|
|
#if defined(DBG)
|
|
// Log error if m_hIUEngine isn't NULL
|
|
if (NULL != m_hIUEngine)
|
|
{
|
|
LOG_Error(_T("m_hIUEngine should be NULL here!"));
|
|
}
|
|
#endif
|
|
PFN_CreateEngUpdateInstance pfnCreateEngUpdateInstance =
|
|
(PFN_CreateEngUpdateInstance) GetProcAddress(m_hEngineModule, "CreateEngUpdateInstance");
|
|
|
|
if (NULL != pfnCreateEngUpdateInstance)
|
|
{
|
|
m_hIUEngine = pfnCreateEngUpdateInstance();
|
|
}
|
|
|
|
if (NULL == m_hIUEngine)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
LOG_ErrorMsg(hr);
|
|
FreeLibrary(m_hEngineModule);
|
|
m_hEngineModule = NULL;
|
|
}
|
|
}
|
|
}
|
|
LeaveCriticalSection(&m_lock);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
STDMETHODIMP CUpdate::PrepareSelfUpdate(LONG lStep)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Helper API to let the caller (script) knows the necessary information
|
|
// when Initialize() returns control need updated.
|
|
//
|
|
// For the current implementation, bstrClientName is ignored, and
|
|
// the returned bstr has format:
|
|
// "<version>|<url>"
|
|
// where:
|
|
// <version> is the expacted version number of the control
|
|
// <url> is the base url to get the control if this is a CorpWU policy controlled machine,
|
|
// or empty if this is a consumer machine (in that case caller, i.e., script, knows
|
|
// the default base url, which is the v4 live site)
|
|
//
|
|
// Script will need these two pieces of information in order to make a right <OBJECT> tag
|
|
// for control update.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP CUpdate::GetControlExtraInfo(BSTR bstrClientName, BSTR *pbstrExtraInfo)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// new Win32 API called by wrapper control to retrieve update info
|
|
//
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
int GetControlUpdateInfo(LPTSTR lpszUpdateInfo, int cchBufferSize)
|
|
{
|
|
LOG_Block("GetControlUpdateInfo()");
|
|
|
|
HRESULT hr = S_OK;
|
|
int nSize = 0;
|
|
BOOL fCorpUser = FALSE, fBetaSelfUpdate = FALSE;
|
|
FILE_VERSION fvCurrentCtl, fvCurrentEngine;
|
|
|
|
TCHAR szDir[MAX_PATH];
|
|
TCHAR szFile[MAX_PATH];
|
|
TCHAR szExpectedEngVer[64]; // 64 should be more then enough
|
|
TCHAR szExpectedCtlVer[64]; // if not enough, then it's bad data anyway
|
|
|
|
HKEY hKey;
|
|
|
|
DWORD dwErr = ERROR_SUCCESS; // error code for this API
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
dwErr = ERROR_SERVICE_DISABLED;
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
goto CleanUp;
|
|
}
|
|
if (0x0 == GetLogonGroupInfo())
|
|
{
|
|
dwErr = ERROR_ACCESS_DENIED;
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
if (FAILED(hr = DownloadIUIdent_PopulateData()))
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
dwErr = hr;
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// get current control ver
|
|
//
|
|
GetSystemDirectory(szDir, ARRAYSIZE(szDir));
|
|
hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,IUCTL);
|
|
if (FAILED(hr))
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
dwErr = hr;
|
|
goto CleanUp;
|
|
}
|
|
if (!GetFileVersion(szFile, &fvCurrentCtl))
|
|
{
|
|
ZeroMemory(&fvCurrentCtl, sizeof(fvCurrentCtl));
|
|
}
|
|
|
|
|
|
//
|
|
// get current engine ver
|
|
//
|
|
hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,ENGINENEWDLL);
|
|
if (FAILED(hr))
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
dwErr = hr;
|
|
goto CleanUp;
|
|
}
|
|
if (!GetFileVersion(szFile, &fvCurrentEngine))
|
|
{
|
|
//
|
|
// if no engine new there, check engine ver
|
|
//
|
|
hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,ENGINEDLL);
|
|
if (FAILED(hr))
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
dwErr = hr;
|
|
goto CleanUp;
|
|
}
|
|
if (!GetFileVersion(szFile, &fvCurrentEngine))
|
|
{
|
|
ZeroMemory(&fvCurrentCtl, sizeof(fvCurrentEngine));
|
|
}
|
|
}
|
|
|
|
//
|
|
// check if this is beta code
|
|
//
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_IUCTL,0, KEY_READ, &hKey))
|
|
{
|
|
// Check for Beta IU SelfUpdate Handling Requested
|
|
DWORD dwStatus = 0;
|
|
DWORD dwSize = sizeof(dwStatus);
|
|
DWORD dwRet = RegQueryValueEx(hKey, REGVAL_BETASELFUPDATE, NULL, NULL, (LPBYTE)&dwStatus, &dwSize);
|
|
if (1 == dwStatus)
|
|
{
|
|
fBetaSelfUpdate = TRUE;
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// get expected control ver
|
|
//
|
|
GetIndustryUpdateDirectory(szDir);
|
|
hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,IDENTTXT);
|
|
if (FAILED(hr))
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
dwErr = hr;
|
|
goto CleanUp;
|
|
}
|
|
GetPrivateProfileString(_T("IUControl"),
|
|
_T("ControlVer"),
|
|
_T(""),
|
|
szExpectedCtlVer,
|
|
ARRAYSIZE(szExpectedCtlVer),
|
|
szFile);
|
|
if ('\0' == szExpectedCtlVer[0])
|
|
{
|
|
//
|
|
// no selfupdate available, no server version information. bad ident?
|
|
//
|
|
dwErr = ERROR_FILE_CORRUPT;
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
//
|
|
// get expected engine ver
|
|
//
|
|
GetIndustryUpdateDirectory(szDir);
|
|
hr = PathCchCombine(szFile, ARRAYSIZE(szFile), szDir,IDENTTXT);
|
|
if (FAILED(hr))
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
dwErr = hr;
|
|
goto CleanUp;
|
|
}
|
|
GetPrivateProfileString(fBetaSelfUpdate ? IDENT_IUBETASELFUPDATE : IDENT_IUSELFUPDATE,
|
|
IDENT_VERSION,
|
|
_T(""),
|
|
szExpectedEngVer,
|
|
ARRAYSIZE(szExpectedEngVer),
|
|
szFile);
|
|
if ('\0' == szExpectedEngVer[0])
|
|
{
|
|
//
|
|
// no selfupdate available, no server version information. bad ident?
|
|
//
|
|
dwErr = ERROR_FILE_CORRUPT;
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
hr = g_pIUUrlAgent->IsIdentFromPolicy();
|
|
if (FAILED(hr))
|
|
{
|
|
dwErr = (DWORD)hr;
|
|
goto CleanUp;
|
|
}
|
|
|
|
fCorpUser = (S_OK == hr) ? TRUE : FALSE;
|
|
hr = S_OK;
|
|
|
|
//
|
|
// contscut data
|
|
// the constructed buffer will be in format
|
|
// <CurrentCtlVer>|<ExpCtlVer>|CurrentEngVer>|<ExpEngVer>|<baseUrl>
|
|
//
|
|
nSize = wnsprintf(lpszUpdateInfo, cchBufferSize, _T("%d.%d.%d.%d|%s|%d.%d.%d.%d|%s|%d"),
|
|
fvCurrentCtl.Major, fvCurrentCtl.Minor, fvCurrentCtl.Build, fvCurrentCtl.Ext,
|
|
szExpectedCtlVer,
|
|
fvCurrentEngine.Major, fvCurrentEngine.Minor, fvCurrentEngine.Build, fvCurrentEngine.Ext,
|
|
szExpectedEngVer,
|
|
fCorpUser ? 1 : 0);
|
|
|
|
if (nSize < 0)
|
|
{
|
|
nSize = 0;
|
|
dwErr = ERROR_INSUFFICIENT_BUFFER;
|
|
goto CleanUp;
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
SetLastError(dwErr);
|
|
|
|
return nSize;
|
|
} |