1330 lines
41 KiB
C++
1330 lines
41 KiB
C++
|
#include "pch.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#define MAINWINDOW_CURSOR IDC_ARROW
|
||
|
#define RESOURCE_STRING_MAX_LENGTH 100
|
||
|
|
||
|
TCHAR AU_WINDOW_CLASS_NAME[] = _T("Auto Update Client Window");
|
||
|
const TCHAR gtszAUW2KPrivacyUrl[]= _T("..\\help\\wuauhelp.chm::/w2k_autoupdate_privacy.htm");
|
||
|
const TCHAR gtszAUXPPrivacyUrl[]= _T("..\\help\\wuauhelp.chm::/autoupdate_privacy.htm");
|
||
|
|
||
|
const ReminderItem ReminderTimes[TIMEOUT_INX_COUNT] =
|
||
|
{
|
||
|
{ 1800, IDS_THIRTY_MINUTES },
|
||
|
{ 3600, IDS_ONE_HOUR },
|
||
|
{ 7200, IDS_TWO_HOURS },
|
||
|
{ 14400, IDS_FOUR_HOURS },
|
||
|
{ 86400, IDS_TOMORROW },
|
||
|
{ 259200, IDS_THREE_DAYS }
|
||
|
};
|
||
|
|
||
|
const UINT RESOURCESTRINGINDEX[] = {
|
||
|
IDS_NOTE,
|
||
|
IDS_WELCOME_CONTINUE,
|
||
|
IDS_EULA,
|
||
|
IDS_PRIVACY,
|
||
|
IDS_LEARNMORE,
|
||
|
IDS_LEARNMOREAUTO
|
||
|
};
|
||
|
|
||
|
|
||
|
// Global Data Items
|
||
|
CAUInternals* gInternals;
|
||
|
AUClientCatalog *gpClientCatalog ; //= NULL
|
||
|
TCHAR gResStrings[ARRAYSIZE(RESOURCESTRINGINDEX)][RESOURCE_STRING_MAX_LENGTH];
|
||
|
// Global UI Items
|
||
|
CRITICAL_SECTION gcsClient; // guard guard user's tray interaction (showing, not showing) and guard customlb data
|
||
|
HINSTANCE ghInstance;
|
||
|
HFONT ghHeaderFont;
|
||
|
HCURSOR ghCursorHand;
|
||
|
HCURSOR ghCursorNormal; // cursor of main window
|
||
|
|
||
|
HMODULE ghRichEd20;
|
||
|
HANDLE ghEngineState;
|
||
|
HWND ghMainWindow;
|
||
|
HWND ghCurrentDialog;
|
||
|
HWND ghCurrentMainDlg;
|
||
|
AUCLTTopWindows gTopWins;
|
||
|
UINT gNextDialogMsg;
|
||
|
BOOL gbOnlySession; // = FALSE;
|
||
|
BOOL gfShowingInstallWarning; // = FALSE;
|
||
|
|
||
|
HMENU ghPauseMenu;
|
||
|
HMENU ghResumeMenu;
|
||
|
HMENU ghCurrentMenu;
|
||
|
HICON ghAppIcon;
|
||
|
HICON ghAppSmIcon;
|
||
|
HICON ghTrayIcon;
|
||
|
UINT guExitProcess=CDWWUAUCLT_UNSPECIFY;
|
||
|
|
||
|
LPCTSTR gtszAUSchedInstallUrl;
|
||
|
LPCTSTR gtszAUPrivacyUrl;
|
||
|
|
||
|
AU_ENV_VARS gAUEnvVars;
|
||
|
|
||
|
HANDLE g_hClientNotifyEvt = NULL; //the event Engine use to notify client
|
||
|
HANDLE g_hRegisterWait = NULL;
|
||
|
BOOL g_fCoInit = FALSE;
|
||
|
BOOL g_fcsInit = FALSE;
|
||
|
|
||
|
/****
|
||
|
Helper function to simplify window class registration.
|
||
|
*****/
|
||
|
ATOM AURegisterWindowClass(WNDPROC lpWndProc, LPTSTR lpClassName)
|
||
|
{
|
||
|
WNDCLASSEX wcex;
|
||
|
|
||
|
ZeroMemory(&wcex, sizeof(wcex));
|
||
|
|
||
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
||
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||
|
wcex.lpfnWndProc = (WNDPROC)lpWndProc;
|
||
|
// wcex.cbClsExtra = 0;
|
||
|
// wcex.cbWndExtra = 0;
|
||
|
// wcex.lpszMenuName = NULL;
|
||
|
// wcex.hIcon = NULL;
|
||
|
// wcex.hIconSm = NULL;
|
||
|
wcex.hInstance = ghInstance;
|
||
|
wcex.hCursor = LoadCursor(NULL, MAINWINDOW_CURSOR);
|
||
|
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
||
|
wcex.lpszClassName = lpClassName;
|
||
|
|
||
|
return RegisterClassEx(&wcex);
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
// map string id to its storage in the gResStrings
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
LPTSTR ResStrFromId(UINT uStrId)
|
||
|
{
|
||
|
for (int i = 0; i < ARRAYSIZE(RESOURCESTRINGINDEX); i++)
|
||
|
{
|
||
|
if (RESOURCESTRINGINDEX[i] == uStrId)
|
||
|
{
|
||
|
return gResStrings[i];
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////
|
||
|
// Set reminder timeout and state and quit
|
||
|
////////////////////////////////////////////////////////
|
||
|
void QuitNRemind(TIMEOUTINDEX enTimeoutIndex)
|
||
|
{
|
||
|
AUSTATE auState;
|
||
|
if (FAILED(gInternals->m_getServiceState(&auState)))
|
||
|
{
|
||
|
goto done;
|
||
|
}
|
||
|
if (FAILED(gInternals->m_setReminderTimeout(enTimeoutIndex)))
|
||
|
{
|
||
|
goto done;
|
||
|
}
|
||
|
gInternals->m_setReminderState(auState.dwState);
|
||
|
done:
|
||
|
QUITAUClient();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Helper Function HrQuerySessionConnectState(int iAdminSession, int *piConState)
|
||
|
// helper function to get the Session Connection State
|
||
|
//
|
||
|
// Input: int iAdminSession Session Admin ID
|
||
|
// Output: int *piConState Conection state
|
||
|
// Return: HRESULT value. If Failed, *piConState is unspecified
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
HRESULT HrQuerySessionConnectState(int iAdminSession, int *piConState)
|
||
|
{
|
||
|
LPTSTR pBuffer = NULL;
|
||
|
HRESULT hr = NO_ERROR;
|
||
|
DWORD dwBytes;
|
||
|
|
||
|
if (AUIsTSRunning())
|
||
|
{
|
||
|
|
||
|
if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, iAdminSession, WTSConnectState,
|
||
|
&pBuffer, &dwBytes))
|
||
|
{
|
||
|
*piConState = (int) *pBuffer; //Because we are asking for WTSConnectState, pBuffer points to an int
|
||
|
WTSFreeMemory(pBuffer);
|
||
|
hr = NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT: WTSQuerySessionInformation failed: %lu", GetLastError());
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DWORD dwSession = iAdminSession;
|
||
|
|
||
|
if (dwSession == WTS_CURRENT_SESSION)
|
||
|
ProcessIdToSessionId(GetCurrentProcessId(), &dwSession);
|
||
|
|
||
|
// if we're launched & TS is not up, we've gotta be an active session.
|
||
|
if (dwSession == 0)
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT: TS is not running or not installed. Assuming session 0 is active.");
|
||
|
gbOnlySession = TRUE;
|
||
|
*piConState = WTSActive;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT: TS is not running or not installed, but a non 0 session was asked for (session %d). Failing call.", iAdminSession);
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
BOOL FCurrentSessionInActive()
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
HRESULT hr;
|
||
|
int iConState;
|
||
|
|
||
|
if (gbOnlySession)
|
||
|
{
|
||
|
DEBUGMSG("FCurrentSessionInActive() Only one session");
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
//Check if the Current Session is Inactive
|
||
|
hr = HrQuerySessionConnectState(WTS_CURRENT_SESSION, &iConState);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
fRet = (WTSDisconnected == iConState);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (RPC_S_INVALID_BINDING == GetLastError()) //Terminal Services are disabled, this is session 0
|
||
|
{
|
||
|
DEBUGMSG("FCurrentSessionInActive() TS disabled");
|
||
|
gbOnlySession = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUGMSG("FCurrentSessionInActive() HrQuerySessionConnectState failed %#lx =",hr);
|
||
|
}
|
||
|
}
|
||
|
Done:
|
||
|
// DEBUGMSG("FCurrentSessionInActive() return %s", fRet ? "TRUE" : "FALSE");
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// BuildClientCatalog
|
||
|
//
|
||
|
// Do online detection of the catalog and build up the wuv3is.dll detection state
|
||
|
// inside this process. Validation is done during this process with the catalog file
|
||
|
// previously written by the engine.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
HRESULT BuildClientCatalog(void)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
DEBUGMSG("BuildClientCatalog() starts");
|
||
|
if ( NULL == gpClientCatalog )
|
||
|
{
|
||
|
gpClientCatalog = new AUClientCatalog();
|
||
|
if ( NULL != gpClientCatalog )
|
||
|
{
|
||
|
if ( FAILED(hr = gpClientCatalog->Init()) )
|
||
|
{
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto done;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// change to: hr = gpClientCatalog->LoadInstallXML();
|
||
|
|
||
|
done:
|
||
|
DEBUGMSG("BuildClientCatalog() ends");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
void DismissUIIfAny()
|
||
|
{
|
||
|
gTopWins.Add(ghCurrentMainDlg);
|
||
|
gTopWins.Dismiss();
|
||
|
|
||
|
// Don't leave any popup menu around when dismissing dialogs.
|
||
|
if (SendMessage(ghMainWindow, WM_CANCELMODE, 0, 0))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT WM_CANCELMODE was not handled");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void ResetAUClient(void)
|
||
|
{
|
||
|
DismissUIIfAny();
|
||
|
RemoveTrayIcon();
|
||
|
gfShowingInstallWarning = FALSE;
|
||
|
gNextDialogMsg = NULL;
|
||
|
ghCurrentMenu = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ShowInstallWarning()
|
||
|
{ //dismiss current dialog if any
|
||
|
DEBUGMSG("ShowInstallWarning() starts");
|
||
|
gfShowingInstallWarning = TRUE;
|
||
|
gNextDialogMsg = NULL;
|
||
|
ghCurrentMenu = NULL;
|
||
|
CPromptUserDlg PromptUserDlg(IDD_START_INSTALL);
|
||
|
PromptUserDlg.SetInstanceHandle(ghInstance);
|
||
|
INT iRet = PromptUserDlg.DoModal(NULL);
|
||
|
DEBUGMSG("WUAUCLT ShowInstallWarning dlg return code is %d", iRet);
|
||
|
if (IDYES == iRet || AU_IDTIMEOUT == iRet)
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_INSTALLNOW);
|
||
|
QUITAUClient();
|
||
|
}
|
||
|
else //if (retVal == IDNO)
|
||
|
{
|
||
|
gNextDialogMsg = AUMSG_SHOW_INSTALL;
|
||
|
}
|
||
|
gfShowingInstallWarning = FALSE;
|
||
|
DEBUGMSG("ShowInstallWarning() ends");
|
||
|
}
|
||
|
|
||
|
void ShowRebootWarning(BOOL fEnableYes, BOOL fEnableNo)
|
||
|
{
|
||
|
DEBUGMSG("ShowRebootWarning() starts");
|
||
|
INT iRet;
|
||
|
CPromptUserDlg PromptUserDlg(IDD_PROMPT_RESTART, fEnableYes, fEnableNo);
|
||
|
|
||
|
PromptUserDlg.SetInstanceHandle(ghInstance);
|
||
|
iRet = PromptUserDlg.DoModal(NULL);
|
||
|
if (IDYES == iRet)
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_REBOOTNOW);
|
||
|
}
|
||
|
else if (IDNO == iRet)
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_REBOOTLATER);
|
||
|
}
|
||
|
else //if (IDTIMEOUT == iRet)
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_REBOOTTIMEOUT);
|
||
|
}
|
||
|
|
||
|
QUITAUClient();
|
||
|
DEBUGMSG("ShowRebootWarning() ends with return code %d", iRet);
|
||
|
DEBUGMSG("ShowRebootWarning() set client exit code to be %d", GetClientExitCode());
|
||
|
}
|
||
|
|
||
|
VOID CALLBACK WaitCallback(PVOID lpParameter, BOOLEAN /*fTimerOrWaitFired*/ )
|
||
|
{
|
||
|
// fTimerOrWaitFired is always false - We can't time out with INFINATE wait
|
||
|
|
||
|
BOOL fRebootWarningMode = (BOOL) PtrToInt(lpParameter);
|
||
|
if (fRebootWarningMode)
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT got exit signal from engine");
|
||
|
QUITAUClient();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
// ClientNotify event was fired
|
||
|
CLIENT_NOTIFY_DATA notifyData;
|
||
|
BOOL fCoInit = SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
|
||
|
|
||
|
if ( !fCoInit )
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT WaitCallback CoInitialize failed");
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
IUpdates * pUpdates = NULL;
|
||
|
HRESULT hr = CoCreateInstance(__uuidof(Updates),
|
||
|
NULL,
|
||
|
CLSCTX_LOCAL_SERVER,
|
||
|
IID_IUpdates,
|
||
|
(LPVOID*)&pUpdates);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DEBUGMSG("WaitCallback failed to get Updates object");
|
||
|
goto Done;
|
||
|
}
|
||
|
if (FAILED(hr = pUpdates->GetNotifyData(¬ifyData)))
|
||
|
{
|
||
|
DEBUGMSG("WaitCallback fail to get NotifyData %#lx", hr);
|
||
|
goto Done;
|
||
|
}
|
||
|
switch (notifyData.actionCode)
|
||
|
{
|
||
|
case NOTIFY_STOP_CLIENT:
|
||
|
case NOTIFY_RELAUNCH_CLIENT:
|
||
|
if (NOTIFY_RELAUNCH_CLIENT == notifyData.actionCode)
|
||
|
{
|
||
|
DEBUGMSG("WaitCallback() notify client to relaunch");
|
||
|
SetClientExitCode(CDWWUAUCLT_RELAUNCHNOW);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUGMSG("WaitCallback() notify client to stop");
|
||
|
SetClientExitCode(CDWWUAUCLT_OK);
|
||
|
}
|
||
|
if (NULL != ghMutex)
|
||
|
{
|
||
|
WaitForSingleObject(ghMutex, INFINITE);
|
||
|
if (NULL != gpClientCatalog)
|
||
|
{
|
||
|
gpClientCatalog->CancelNQuit();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUGMSG("No need to cancel catalag");
|
||
|
}
|
||
|
ReleaseMutex(ghMutex);
|
||
|
}
|
||
|
QUITAUClient();
|
||
|
break;
|
||
|
case NOTIFY_RESET: //reprocess state and option and show UI accordingly
|
||
|
ResetAUClient();
|
||
|
SetEvent(ghEngineState);
|
||
|
break;
|
||
|
case NOTIFY_ADD_TRAYICON:
|
||
|
DEBUGMSG("WaitCallback() notify client to show tray icon");
|
||
|
ShowTrayIcon();
|
||
|
ghCurrentMenu = ghPauseMenu; //the job is now downloading
|
||
|
break;
|
||
|
case NOTIFY_REMOVE_TRAYICON:
|
||
|
DEBUGMSG("WaitCallback() notify client to remove tray icon");
|
||
|
RemoveTrayIcon();
|
||
|
break;
|
||
|
case NOTIFY_STATE_CHANGE:
|
||
|
DEBUGMSG("WaitCallback() notify client of state change");
|
||
|
SetEvent(ghEngineState);
|
||
|
break;
|
||
|
case NOTIFY_SHOW_INSTALLWARNING:
|
||
|
DEBUGMSG("WaitCallback() notify client to show install warning");
|
||
|
if (!gfShowingInstallWarning)
|
||
|
{ //install warning dialog is not up, prevent install warning dialog torn down before it expires when secsinaday low
|
||
|
DismissUIIfAny();
|
||
|
PostMessage(ghMainWindow, AUMSG_SHOW_INSTALLWARNING, 0, 0);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
Done:
|
||
|
SafeRelease(pUpdates);
|
||
|
if (fCoInit)
|
||
|
{
|
||
|
CoUninitialize();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL ProcessEngineState()
|
||
|
{
|
||
|
AUSTATE AuState;
|
||
|
BOOL fResult = TRUE;
|
||
|
|
||
|
DEBUGMSG("WUAUCLT starts ProcessEngineState()");
|
||
|
ghCurrentMenu = NULL;
|
||
|
|
||
|
if (FAILED(gInternals->m_getServiceState(&AuState)))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT : quit because m_getServiceState failed");
|
||
|
SetClientExitCode(CDWWUAUCLT_FATAL_ERROR);
|
||
|
fResult = FALSE;
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
DEBUGMSG("WUAUCLT process Engine state %lu",AuState.dwState);
|
||
|
switch(AuState.dwState)
|
||
|
{
|
||
|
case AUSTATE_NOT_CONFIGURED:
|
||
|
if(gNextDialogMsg != AUMSG_SHOW_WELCOME && ghCurrentMainDlg == NULL )
|
||
|
{
|
||
|
if (ShowTrayIcon())
|
||
|
{
|
||
|
ShowTrayBalloon(IDS_WELCOMETITLE, IDS_WELCOMECAPTION, IDS_WELCOMETITLE);
|
||
|
gNextDialogMsg = AUMSG_SHOW_WELCOME;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case AUSTATE_DETECT_COMPLETE:
|
||
|
if ( FAILED(gInternals->m_getServiceUpdatesList()) )
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT : quit because m_getServiceUpdatesList failed");
|
||
|
SetClientExitCode(CDWWUAUCLT_FATAL_ERROR);
|
||
|
fResult = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
AUOPTION auopt;
|
||
|
|
||
|
if (SUCCEEDED(gInternals->m_getServiceOption(&auopt)) &&
|
||
|
(AUOPTION_INSTALLONLY_NOTIFY == auopt.dwOption || AUOPTION_SCHEDULED == auopt.dwOption))
|
||
|
{
|
||
|
// user option is auto download, start download
|
||
|
//ShowTrayIcon();
|
||
|
|
||
|
// do download right away without dialogs if user options set to notify for just install
|
||
|
if (FAILED(gInternals->m_startDownload()))
|
||
|
{
|
||
|
QUITAUClient();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// ghCurrentMenu = ghPauseMenu;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(gNextDialogMsg != AUMSG_SHOW_DOWNLOAD && ghCurrentMainDlg == NULL)
|
||
|
{
|
||
|
if (ShowTrayIcon())
|
||
|
{
|
||
|
ShowTrayBalloon(IDS_DOWNLOADTITLE, IDS_DOWNLOADCAPTION, IDS_DOWNLOADTITLE);
|
||
|
gNextDialogMsg = AUMSG_SHOW_DOWNLOAD;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AUSTATE_DOWNLOAD_COMPLETE:
|
||
|
if (AUCLT_ACTION_AUTOINSTALL == AuState.dwCltAction)
|
||
|
{ // engine initiated install: auto install
|
||
|
HRESULT hr;
|
||
|
DEBUGMSG("Auto install ...");
|
||
|
if ( S_OK !=(hr = BuildClientCatalog()))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fail to build client catalog with error %#lx, exiting, hr");
|
||
|
SetClientExitCode(CDWWUAUCLT_FATAL_ERROR);
|
||
|
fResult = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
if (FAILED(hr = gInternals->m_startInstall(TRUE)))
|
||
|
{
|
||
|
DEBUGMSG("Fail to post install message with error %#lx", hr);
|
||
|
fResult = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
gpClientCatalog->m_WrkThread.WaitUntilDone();
|
||
|
if (gpClientCatalog->m_fReboot)
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_REBOOTNEEDED);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_OK);
|
||
|
}
|
||
|
QUITAUClient();
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{ //show preinstall dialog and let user initiate install
|
||
|
HRESULT hr;
|
||
|
DEBUGMSG("Prompt for manual install");
|
||
|
if ( FAILED(gInternals->m_getServiceUpdatesList()))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT : quit because m_getServiceUpdatesList failed");
|
||
|
SetClientExitCode(CDWWUAUCLT_FATAL_ERROR);
|
||
|
fResult = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( S_OK !=(hr = BuildClientCatalog()) )
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fail to build client catalog with error %#lx, exiting", hr);
|
||
|
SetClientExitCode(CDWWUAUCLT_FATAL_ERROR);
|
||
|
fResult = FALSE;
|
||
|
}
|
||
|
else if(gNextDialogMsg != AUMSG_SHOW_INSTALL && ghCurrentMainDlg == NULL)
|
||
|
{
|
||
|
if (ShowTrayIcon())
|
||
|
{
|
||
|
ShowTrayBalloon(IDS_INSTALLTITLE, IDS_INSTALLCAPTION, IDS_INSTALLTITLE);
|
||
|
gNextDialogMsg = AUMSG_SHOW_INSTALL;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AUSTATE_DOWNLOAD_PENDING:
|
||
|
{
|
||
|
UINT nPercentComplete = 0;
|
||
|
DWORD dwStatus;
|
||
|
|
||
|
//if drizzle got transient error, quit client
|
||
|
//fixcode: why quit if transient error?
|
||
|
if (AuState.fDisconnected)
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT : quit because of lost of connection, fDisconnected = %d",AuState.fDisconnected);
|
||
|
fResult = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
if (FAILED(gInternals->m_getDownloadStatus(&nPercentComplete, &dwStatus)))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT : quit because m_getDownloadStatus failed");
|
||
|
fResult = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (DWNLDSTATUS_CHECKING_CONNECTION == dwStatus)
|
||
|
{
|
||
|
//hide tray icon
|
||
|
DEBUGMSG("WUAUCLT Waiting for engine to find connection first");
|
||
|
// RemoveTrayIcon();
|
||
|
// ghCurrentMenu = NULL;
|
||
|
}
|
||
|
else if(dwStatus == DWNLDSTATUS_DOWNLOADING)
|
||
|
{
|
||
|
ghCurrentMenu = ghPauseMenu;
|
||
|
DEBUGMSG("WUAUCLT in active downloading state");
|
||
|
ShowTrayIcon();
|
||
|
}
|
||
|
else if(dwStatus == DWNLDSTATUS_PAUSED)
|
||
|
{
|
||
|
ghCurrentMenu = ghResumeMenu;
|
||
|
DEBUGMSG("WUAUCLT in download paused state");
|
||
|
if (fDisableSelection() &&
|
||
|
FAILED(gInternals->m_setDownloadPaused(FALSE)))
|
||
|
{
|
||
|
// QUITAUClient(); //let wuaueng to figure out problem and recover
|
||
|
}
|
||
|
ShowTrayIcon();
|
||
|
}
|
||
|
else //not downloading
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT WARNING: not downloading while in download pending state");
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case AUSTATE_DETECT_PENDING:
|
||
|
//Quit only if the Install UI has been accepted or there is no InstallUI
|
||
|
if (NULL == ghCurrentMainDlg)
|
||
|
{
|
||
|
QUITAUClient();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case AUSTATE_DISABLED:
|
||
|
QUITAUClient();
|
||
|
break;
|
||
|
|
||
|
case AUSTATE_INSTALL_PENDING:
|
||
|
default:
|
||
|
// outofbox and waiting_for_reboot are here. WUAUCLT should not be launched in these states
|
||
|
DEBUGMSG("WUAUCLT AUSTATE = %lu", AuState.dwState);
|
||
|
break;
|
||
|
}
|
||
|
Done:
|
||
|
DEBUGMSG("WUAUCLT exits ProcessEngineState()");
|
||
|
return fResult;
|
||
|
}
|
||
|
|
||
|
BOOL InitUIComponents(HINSTANCE hInstance)
|
||
|
{
|
||
|
INITCOMMONCONTROLSEX icex;
|
||
|
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
||
|
icex.dwICC = 0; //We dont need to register any control classes
|
||
|
if (!InitCommonControlsEx(&icex)) //needed for theming
|
||
|
{
|
||
|
DEBUGMSG("InitUIComponents :InitCommonControlsEx failed");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//we need to load riched20.dll to register the class
|
||
|
ghRichEd20 = LoadLibraryFromSystemDir(_T("RICHED20.dll"));
|
||
|
if (NULL == ghRichEd20)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
ghCursorHand = LoadCursor(NULL, IDC_HAND);
|
||
|
ghCursorNormal = LoadCursor(NULL, MAINWINDOW_CURSOR); //change if main window's cursor does
|
||
|
if (NULL == ghCursorHand)
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fail to load hand cursor");
|
||
|
ghCursorHand = ghCursorNormal;
|
||
|
}
|
||
|
|
||
|
ghAppIcon = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_AUICON), IMAGE_ICON, NULL, NULL, LR_DEFAULTSIZE | LR_CREATEDIBSECTION);
|
||
|
ghAppSmIcon = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_AUICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_CREATEDIBSECTION);
|
||
|
|
||
|
if (IsWin2K())
|
||
|
{
|
||
|
//Win2k
|
||
|
ghTrayIcon = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_AUSYSTRAYICON), IMAGE_ICON, 16, 16, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//WindowsXP
|
||
|
ghTrayIcon = (HICON) LoadImage(hInstance, MAKEINTRESOURCE(IDI_AUICON), IMAGE_ICON, 16, 16, LR_CREATEDIBSECTION);
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < ARRAYSIZE(RESOURCESTRINGINDEX); i++)
|
||
|
{
|
||
|
LoadString(hInstance, RESOURCESTRINGINDEX[i], ResStrFromId(RESOURCESTRINGINDEX[i]), RESOURCE_STRING_MAX_LENGTH);
|
||
|
}
|
||
|
|
||
|
ghCurrentAccel = LoadAccelerators(ghInstance, MAKEINTRESOURCE(IDA_BASE));
|
||
|
gtszAUSchedInstallUrl = IsWin2K() ? gtszAUW2kSchedInstallUrl : gtszAUXPSchedInstallUrl;
|
||
|
gtszAUPrivacyUrl = IsWin2K() ? gtszAUW2KPrivacyUrl : gtszAUXPPrivacyUrl;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL InitializeAUClientForRebootWarning(HINSTANCE hInstance,
|
||
|
OUT HANDLE *phRegisterWait,
|
||
|
OUT HANDLE *phClientNotifyEvt,
|
||
|
OUT BOOL *pfCoInit)
|
||
|
{
|
||
|
TCHAR buf[100];
|
||
|
|
||
|
SetClientExitCode(CDWWUAUCLT_UNSPECIFY);
|
||
|
*phRegisterWait = NULL;
|
||
|
*pfCoInit = FALSE;
|
||
|
*phClientNotifyEvt = OpenEvent(SYNCHRONIZE, FALSE, gAUEnvVars.m_szClientExitEvtName);
|
||
|
if (NULL == *phClientNotifyEvt)
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fail to open client exit event");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
INITCOMMONCONTROLSEX icex;
|
||
|
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
||
|
icex.dwICC = 0; //We dont need to register any control classes
|
||
|
if (!InitCommonControlsEx(&icex)) //needed for theming
|
||
|
{
|
||
|
DEBUGMSG("InitCommonControlsEx failed");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!RegisterWaitForSingleObject(phRegisterWait, // wait handle
|
||
|
*phClientNotifyEvt, // handle to object
|
||
|
WaitCallback, // timer callback function
|
||
|
(PVOID)1, // callback function parameter
|
||
|
INFINITE, // time-out interval
|
||
|
WT_EXECUTEONLYONCE // options
|
||
|
))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT RegisterWaitForSingleObject failed %lu",GetLastError());
|
||
|
*phRegisterWait = NULL;
|
||
|
return FALSE;
|
||
|
}
|
||
|
ghInstance = hInstance;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL InitializeAUClient(HINSTANCE hInstance,
|
||
|
OUT HANDLE * phRegisterWait,
|
||
|
OUT HANDLE * phClientNotifyEvt,
|
||
|
OUT BOOL *pfCoInit,
|
||
|
OUT BOOL *pfcsInit)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
*pfcsInit = FALSE;
|
||
|
*phClientNotifyEvt = NULL;
|
||
|
*phRegisterWait = NULL;
|
||
|
SetClientExitCode(CDWWUAUCLT_UNSPECIFY);
|
||
|
*pfCoInit = SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
|
||
|
|
||
|
if ( !*pfCoInit )
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT WinMain CoInitialize failed");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!InitUIComponents(hInstance))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fail to initialize UI components");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (NULL == (ghMutex = CreateMutex(NULL, FALSE, NULL)))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fail to create global mutex");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
gInternals = NULL;
|
||
|
|
||
|
if ( (NULL == (ghEngineState = CreateEvent(NULL, FALSE, FALSE, NULL))) )
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fails to create event");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
ghInstance = hInstance;
|
||
|
|
||
|
if (!(*pfcsInit = SafeInitializeCriticalSection(&gcsClient)))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fails to initialize critical section");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
#ifndef TESTUI
|
||
|
|
||
|
if (! (gInternals = new CAUInternals()))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fails to create auinternals object");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr = gInternals->m_Init()))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT failed in CoCreateInstance of service with error %#lx, exiting", hr);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
AUEVTHANDLES AuEvtHandles;
|
||
|
ZeroMemory(&AuEvtHandles, sizeof(AuEvtHandles));
|
||
|
if (FAILED(hr = gInternals->m_getEvtHandles(GetCurrentProcessId(), &AuEvtHandles)))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT failed in m_getEvtHandles with error %#lx, exiting", hr);
|
||
|
return FALSE;
|
||
|
}
|
||
|
*phClientNotifyEvt = (HANDLE)AuEvtHandles.ulNotifyClient;
|
||
|
|
||
|
if (!RegisterWaitForSingleObject( phRegisterWait, // wait handle
|
||
|
*phClientNotifyEvt, // handle to object
|
||
|
WaitCallback, // timer callback function
|
||
|
0, // callback function parameter
|
||
|
INFINITE, // time-out interval
|
||
|
WT_EXECUTEDEFAULT // options
|
||
|
))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT RegisterWaitForSingleObject failed %lu",GetLastError());
|
||
|
*phRegisterWait = NULL;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
void UninitializeAUClient(HANDLE hRegisterWait, HANDLE hClientNotifyEvt, BOOL fCoInit, BOOL fcsInit)
|
||
|
{
|
||
|
static BOOL fAlreadyUninit = FALSE;
|
||
|
|
||
|
if (fAlreadyUninit)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
fAlreadyUninit = TRUE;
|
||
|
|
||
|
RemoveTrayIcon();
|
||
|
if (NULL != hRegisterWait)
|
||
|
{
|
||
|
if ( !UnregisterWaitEx(hRegisterWait, INVALID_HANDLE_VALUE) )
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT: UnregisterWaitEx() failed, dw = %lu", GetLastError());
|
||
|
}
|
||
|
}
|
||
|
if (NULL != ghRichEd20)
|
||
|
{
|
||
|
FreeLibrary(ghRichEd20);
|
||
|
ghRichEd20 = NULL;
|
||
|
}
|
||
|
SafeCloseHandleNULL(hClientNotifyEvt);
|
||
|
|
||
|
if (!gAUEnvVars.m_fRebootWarningMode)
|
||
|
{
|
||
|
//fixcode: is ghMainWindow a valid window here?
|
||
|
KillTimer(ghMainWindow, 1);
|
||
|
if (fcsInit)
|
||
|
{
|
||
|
DeleteCriticalSection(&gcsClient);
|
||
|
}
|
||
|
SafeDeleteNULL(gInternals);
|
||
|
SafeDeleteNULL(gpClientCatalog);
|
||
|
SafeCloseHandleNULL(ghEngineState);
|
||
|
SafeCloseHandleNULL(ghMutex);
|
||
|
}
|
||
|
|
||
|
if ( fCoInit)
|
||
|
{
|
||
|
CoUninitialize();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int APIENTRY WinMain(HINSTANCE hInstance,
|
||
|
HINSTANCE /*hPrevInstance*/,
|
||
|
LPSTR /*lpCmdLine*/,
|
||
|
int /*nCmdShow*/)
|
||
|
{
|
||
|
HANDLE rhEvents[CNUM_EVENTS];
|
||
|
|
||
|
//Initialize the global pointing to WU Directory. (the directory should already exist)
|
||
|
if(!CreateWUDirectory(TRUE))
|
||
|
{
|
||
|
//If we can not create WU directory, no point in continuing
|
||
|
DEBUGMSG("WUAUCLT Fail to create WU directory");
|
||
|
SetClientExitCode(CDWWUAUCLT_FATAL_ERROR);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
if (!gAUEnvVars.ReadIn())
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT fails to read in environment variables");
|
||
|
SetClientExitCode(CDWWUAUCLT_FATAL_ERROR);
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
if (gAUEnvVars.m_fRebootWarningMode)
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT starts in reboot warning mode");
|
||
|
if (!InitializeAUClientForRebootWarning(hInstance, &g_hRegisterWait, &g_hClientNotifyEvt, &g_fCoInit))
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_FATAL_ERROR);
|
||
|
goto exit;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT starts in regular mode");
|
||
|
if (!InitializeAUClient(hInstance, &g_hRegisterWait, &g_hClientNotifyEvt, &g_fCoInit, &g_fcsInit))
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_FATAL_ERROR);
|
||
|
goto exit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DEBUGMSG("WUAUCLT initialization done");
|
||
|
// Create the main window hidden
|
||
|
if (!AURegisterWindowClass(MainWndProc, AU_WINDOW_CLASS_NAME))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
if (!AURegisterWindowClass(CustomLBWndProc, _T("MYLB")))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
if (!CreateWindow(AU_WINDOW_CLASS_NAME, AU_WINDOW_CLASS_NAME, WS_CAPTION,
|
||
|
0, 0, 0, 0, NULL, NULL, hInstance, NULL))
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
ShowWindow(ghMainWindow, SW_HIDE);
|
||
|
|
||
|
#ifdef TESTUI
|
||
|
{
|
||
|
MSG msg;
|
||
|
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||
|
{
|
||
|
if (WM_QUIT == msg.message )
|
||
|
{
|
||
|
// Set this event so the service does what every appropriate
|
||
|
// If we don't do this, we might leave the service waiting for this event for
|
||
|
// some cases - for example, when the session in which the client leaves is deactivated or
|
||
|
// when there is a log off
|
||
|
//SetEvent(ghEngineState);
|
||
|
goto exit;
|
||
|
}
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
{
|
||
|
// Run the main message loop
|
||
|
MSG msg;
|
||
|
|
||
|
if (gAUEnvVars.m_fRebootWarningMode)
|
||
|
{
|
||
|
ShowRebootWarning(gAUEnvVars.m_fEnableYes, gAUEnvVars.m_fEnableNo);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetTimer(ghMainWindow, 1, dwTimeToWait(ReminderTimes[TIMEOUT_INX_FOUR_HOURS].timeout), NULL); //every 4 hours
|
||
|
|
||
|
DEBUGMSG("WUAUCLT Processing messages and being alert for Engine state change event");
|
||
|
|
||
|
rhEvents[ISTATE_CHANGE] = ghEngineState;
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
DWORD dwRet = MsgWaitForMultipleObjectsEx(CNUM_EVENTS, rhEvents, INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
|
||
|
|
||
|
if (WAIT_OBJECT_0 + ISTATE_CHANGE == dwRet) //ghEngineState (ISTATE_CHANGE)
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT Engine changed state");
|
||
|
if (!ProcessEngineState())
|
||
|
{
|
||
|
QUITAUClient();
|
||
|
}
|
||
|
}
|
||
|
else if (WAIT_OBJECT_0 + IMESSAGE == dwRet) // There is a message to process
|
||
|
{
|
||
|
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||
|
{
|
||
|
if (WM_QUIT == msg.message )
|
||
|
{
|
||
|
goto exit;
|
||
|
}
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (WAIT_ABANDONED_0 == dwRet) //ghEngineState abandoned
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT quitting because engine state event was abandoned");
|
||
|
}
|
||
|
else if (WAIT_FAILED == dwRet) //MsgWaitForMultipleObjectsEx failed
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT quitting because MsgWaitForMultipleObjectsEx() failed with last error = %lu", GetLastError());
|
||
|
}
|
||
|
QUITAUClient();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
exit:
|
||
|
DEBUGMSG("WUAUCLT Exiting");
|
||
|
|
||
|
//if installation thread is live, wait until it finishes
|
||
|
if (NULL != gpClientCatalog)
|
||
|
{
|
||
|
gpClientCatalog->m_WrkThread.m_Terminate();
|
||
|
}
|
||
|
UninitializeAUClient(g_hRegisterWait, g_hClientNotifyEvt, g_fCoInit, g_fcsInit);
|
||
|
|
||
|
if (CDWWUAUCLT_UNSPECIFY == GetClientExitCode())
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_OK);
|
||
|
}
|
||
|
DEBUGMSG("WUAUCLT exit code %d", GetClientExitCode());
|
||
|
ExitProcess(GetClientExitCode());
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
AUSTATE AuState;
|
||
|
|
||
|
switch(message)
|
||
|
{
|
||
|
case WM_CREATE:
|
||
|
{
|
||
|
LOGFONT lFont;
|
||
|
|
||
|
// initialize global ui variables
|
||
|
ghMainWindow = hWnd;
|
||
|
ghCurrentMainDlg = NULL;
|
||
|
gNextDialogMsg = NULL;
|
||
|
ghHeaderFont = NULL;
|
||
|
|
||
|
InitTrayIcon();
|
||
|
|
||
|
HFONT hDefUIFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
|
||
|
//create header font
|
||
|
ZeroMemory(&lFont, sizeof(lFont));
|
||
|
lFont.lfWeight = FW_BOLD;
|
||
|
lFont.lfCharSet = DEFAULT_CHARSET;
|
||
|
lFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
||
|
lFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||
|
lFont.lfQuality = DEFAULT_QUALITY;
|
||
|
lFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
|
||
|
LoadString(ghInstance, IDS_HEADERFONT, lFont.lfFaceName, ARRAYSIZE(lFont.lfFaceName));
|
||
|
ghHeaderFont = CreateFontIndirect(&lFont);
|
||
|
if(ghHeaderFont == NULL) {
|
||
|
DEBUGMSG("WUAUCLT fail to create Header Font, use default GUI font instead");
|
||
|
ghHeaderFont = hDefUIFont;
|
||
|
}
|
||
|
//create underline font
|
||
|
ZeroMemory(&lFont, sizeof(lFont));
|
||
|
GetObject(hDefUIFont, sizeof(lFont), &lFont);
|
||
|
lFont.lfUnderline = TRUE;
|
||
|
|
||
|
ghHook = SetWindowsHookEx(WH_MSGFILTER, AUTranslatorProc, ghInstance, GetCurrentThreadId());
|
||
|
#ifdef TESTUI
|
||
|
PostMessage(ghMainWindow, AUMSG_SHOW_WELCOME, 0, 0);
|
||
|
#else
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
case AUMSG_SHOW_WELCOME:
|
||
|
DEBUGMSG("WUAUCLT Displaying Welcome");
|
||
|
DialogBox(ghInstance, MAKEINTRESOURCE(IDD_UPDATEFRAME),
|
||
|
NULL, (DLGPROC)WizardFrameProc);
|
||
|
return 0;
|
||
|
|
||
|
case AUMSG_SHOW_DOWNLOAD:
|
||
|
#ifdef TESTUI
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT Displaying Predownload");
|
||
|
DialogBox(ghInstance, MAKEINTRESOURCE(IDD_DOWNLOAD),
|
||
|
NULL, (DLGPROC)DownloadDlgProc);
|
||
|
return 0;
|
||
|
}
|
||
|
#else
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT Displaying Predownload");
|
||
|
DialogBox(ghInstance, MAKEINTRESOURCE(IDD_DOWNLOAD),
|
||
|
NULL, (DLGPROC)DownloadDlgProc);
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
case AUMSG_SHOW_INSTALL:
|
||
|
DEBUGMSG("WUAUCLT Displaying Install");
|
||
|
DismissUIIfAny();
|
||
|
DialogBox(ghInstance, MAKEINTRESOURCE(IDD_INSTALLFRAME),
|
||
|
NULL, (DLGPROC)InstallDlgProc);
|
||
|
return 0;
|
||
|
|
||
|
case AUMSG_SHOW_INSTALLWARNING:
|
||
|
DEBUGMSG("WUAUCLT Displaying install warning dialog");
|
||
|
ShowInstallWarning();
|
||
|
return 0;
|
||
|
|
||
|
case WM_CLOSE:
|
||
|
DestroyWindow(ghMainWindow);
|
||
|
return 0;
|
||
|
|
||
|
case WM_ENDSESSION:
|
||
|
DEBUGMSG("WUAUCLT received WM_ENDSESSION (wParam = %#x)", wParam);
|
||
|
if (wParam)
|
||
|
{
|
||
|
//if installation thread is live, wait until it finishes
|
||
|
if (NULL != gpClientCatalog)
|
||
|
{
|
||
|
gpClientCatalog->m_WrkThread.m_Terminate();
|
||
|
}
|
||
|
DismissUIIfAny();
|
||
|
UninitPopupMenus();
|
||
|
if (NULL != ghHeaderFont)
|
||
|
{
|
||
|
DeleteObject(ghHeaderFont);
|
||
|
}
|
||
|
UninitializeAUClient(g_hRegisterWait, g_hClientNotifyEvt, g_fCoInit, g_fcsInit);
|
||
|
|
||
|
// Even we try to set the client exit code here, but there are cases
|
||
|
// based on observation (e.g. logging off during reboot warning) that
|
||
|
// we don't get back to WinMain for clean up after so the exit code gets
|
||
|
// ignored.
|
||
|
if (CDWWUAUCLT_UNSPECIFY == GetClientExitCode())
|
||
|
{
|
||
|
SetClientExitCode(CDWWUAUCLT_ENDSESSION);
|
||
|
}
|
||
|
DEBUGMSG("WUAUCLT exit code %d", GetClientExitCode());
|
||
|
}
|
||
|
return 0;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
if (NULL != ghHeaderFont)
|
||
|
{
|
||
|
DeleteObject(ghHeaderFont);
|
||
|
}
|
||
|
if(ghCurrentMainDlg != NULL)
|
||
|
{
|
||
|
DestroyWindow(ghCurrentMainDlg);
|
||
|
}
|
||
|
UninitPopupMenus();
|
||
|
PostQuitMessage(0);
|
||
|
return 0;
|
||
|
|
||
|
case WM_TIMER:
|
||
|
#ifdef TESTUI
|
||
|
return 0;
|
||
|
#else
|
||
|
{
|
||
|
UINT nPercentComplete = 0;
|
||
|
DWORD dwStatus;
|
||
|
|
||
|
if (FAILED(gInternals->m_getServiceState(&AuState)))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT m_getServiceState failed when WM_TIMER or AuState.fDisconnected, quitting");
|
||
|
QUITAUClient();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (AUSTATE_DETECT_COMPLETE != AuState.dwState
|
||
|
&& AUSTATE_DOWNLOAD_PENDING != AuState.dwState
|
||
|
&& AUSTATE_DOWNLOAD_COMPLETE != AuState.dwState
|
||
|
&& AUSTATE_NOT_CONFIGURED != AuState.dwState)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
if (AUSTATE_DOWNLOAD_PENDING != AuState.dwState ||
|
||
|
SUCCEEDED(gInternals->m_getDownloadStatus(&nPercentComplete, &dwStatus)) && (DWNLDSTATUS_PAUSED == dwStatus))
|
||
|
{
|
||
|
UINT cSess;
|
||
|
|
||
|
if ((SUCCEEDED(gInternals->m_AvailableSessions(&cSess)) && cSess > 1) || FCurrentSessionInActive())
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT : After 4 hours, exit client and relaunch it in next available admin session");
|
||
|
SetClientExitCode(CDWWUAUCLT_RELAUNCHNOW);
|
||
|
QUITAUClient();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
case AUMSG_TRAYCALLBACK:
|
||
|
#ifdef TESTUI
|
||
|
return 0;
|
||
|
#else
|
||
|
switch(lParam)
|
||
|
{
|
||
|
case WM_LBUTTONDOWN:
|
||
|
case WM_RBUTTONDOWN:
|
||
|
case WM_LBUTTONDBLCLK:
|
||
|
case WM_CONTEXTMENU:
|
||
|
case NIN_BALLOONUSERCLICK:
|
||
|
DEBUGMSG("TrayIcon Message got %d", lParam);
|
||
|
if (ghCurrentMenu != NULL)
|
||
|
{
|
||
|
// bug 499697
|
||
|
// Don't show Pause/Resume menu for download if domain policy specifies schedule install
|
||
|
if (//SUCCEEDED(gInternals->m_getServiceState(&AuState)) &&
|
||
|
//AUSTATE_DOWNLOAD_PENDING == AuState.dwState &&
|
||
|
fDisableSelection())
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
POINT mousePos;
|
||
|
GetCursorPos(&mousePos);
|
||
|
SetForegroundWindow(ghMainWindow);
|
||
|
/*BOOL result =*/ TrackPopupMenu(ghCurrentMenu, 0, mousePos.x, mousePos.y, 0, ghMainWindow, NULL);
|
||
|
PostMessage(ghMainWindow, WM_NULL, 0, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EnterCriticalSection(&gcsClient);
|
||
|
|
||
|
if(gNextDialogMsg != 0)
|
||
|
{
|
||
|
PostMessage(hWnd, gNextDialogMsg, 0, 0);
|
||
|
gNextDialogMsg = 0;
|
||
|
// we need to make use of the permission to set foregroundwindow ASAP because
|
||
|
// SetForegroundWindow() will fail if called later
|
||
|
if (!SetForegroundWindow(ghMainWindow))
|
||
|
{
|
||
|
DEBUGMSG("WUAUCLT: Set main window to foreground FAILED");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetActiveWindow(ghCurrentMainDlg);
|
||
|
SetForegroundWindow(ghCurrentMainDlg);
|
||
|
if(ghCurrentDialog != NULL) SetFocus(ghCurrentDialog);
|
||
|
}
|
||
|
LeaveCriticalSection(&gcsClient);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_MOUSEMOVE:
|
||
|
if (FAILED(gInternals->m_getServiceState(&AuState)))
|
||
|
{
|
||
|
//fixcode: shall we quit AU here?
|
||
|
RemoveTrayIcon();
|
||
|
break;
|
||
|
}
|
||
|
if (AUSTATE_DOWNLOAD_PENDING == AuState.dwState)
|
||
|
{
|
||
|
ShowProgress();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return 0;
|
||
|
#endif
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
|
||
|
#ifdef TESTUI
|
||
|
return 0;
|
||
|
#else
|
||
|
// bug 499697
|
||
|
// Don't process Pause/Resume menu commands
|
||
|
// if domain policy specifies scheduled install
|
||
|
// in case the message was generated before
|
||
|
// current domain policy kicked in.
|
||
|
if (fDisableSelection())
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
switch(LOWORD(wParam))
|
||
|
{
|
||
|
case IDC_PAUSE:
|
||
|
DEBUGMSG("WUAUCLT User pausing download");
|
||
|
if (FAILED(gInternals->m_setDownloadPaused(TRUE)))
|
||
|
{
|
||
|
// QUITAUClient(); //let wuaueng to figure out problem and recover
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ghCurrentMenu = ghResumeMenu;
|
||
|
DEBUGMSG("current menu = resume");
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case IDC_RESUME:
|
||
|
DEBUGMSG("WUAUCLT User resuming download");
|
||
|
if (FAILED(gInternals->m_setDownloadPaused(FALSE)))
|
||
|
{
|
||
|
// QUITAUClient();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ghCurrentMenu = ghPauseMenu;
|
||
|
DEBUGMSG("current menu = pause");
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return 0;
|
||
|
#endif
|
||
|
default:
|
||
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||
|
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//client exit code should only be set once with a meaningful value
|
||
|
void SetClientExitCode(UINT uExitCode)
|
||
|
{
|
||
|
if (guExitProcess != CDWWUAUCLT_UNSPECIFY)
|
||
|
{
|
||
|
DEBUGMSG("ERROR: WUAUCLT Client exit code should only be set once");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
guExitProcess = uExitCode;
|
||
|
}
|
||
|
}
|