Skip to content
Snippets Groups Projects
Commit 2d316dff authored by Nat Goodspeed's avatar Nat Goodspeed
Browse files

Remove old Windows updater executable from source tree and CMake.

parent ea96b9cc
No related branches found
No related tags found
No related merge requests found
...@@ -86,9 +86,8 @@ elseif (WINDOWS) ...@@ -86,9 +86,8 @@ elseif (WINDOWS)
if (EXISTS ${VIEWER_DIR}win_setup) if (EXISTS ${VIEWER_DIR}win_setup)
add_subdirectory(${VIEWER_DIR}win_setup) add_subdirectory(${VIEWER_DIR}win_setup)
endif (EXISTS ${VIEWER_DIR}win_setup) endif (EXISTS ${VIEWER_DIR}win_setup)
add_subdirectory(${VIEWER_PREFIX}win_updater) # add_dependencies(viewer windows-setup windows-crash-logger)
# add_dependencies(viewer windows-updater windows-setup windows-crash-logger) add_dependencies(viewer windows-crash-logger)
add_dependencies(viewer windows-updater windows-crash-logger)
elseif (SOLARIS) elseif (SOLARIS)
add_subdirectory(solaris_crash_logger) add_subdirectory(solaris_crash_logger)
add_dependencies(viewer solaris-crash-logger) add_dependencies(viewer solaris-crash-logger)
......
...@@ -1765,7 +1765,6 @@ if (WINDOWS) ...@@ -1765,7 +1765,6 @@ if (WINDOWS)
media_plugin_webkit media_plugin_webkit
winmm_shim winmm_shim
windows-crash-logger windows-crash-logger
windows-updater
) )
if (FMODEX) if (FMODEX)
...@@ -1811,7 +1810,6 @@ if (WINDOWS) ...@@ -1811,7 +1810,6 @@ if (WINDOWS)
add_dependencies(${VIEWER_BINARY_NAME} add_dependencies(${VIEWER_BINARY_NAME}
SLPlugin SLPlugin
windows-updater
windows-crash-logger windows-crash-logger
) )
......
# -*- cmake -*-
project(win_updater)
include(00-Common)
include(LLCommon)
include(Linking)
# *HACK - override msvcrt implementation (intialized on 00-Common) to be
# statically linked for the installer this relies on vc taking the last flag on
# the command line
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
include_directories(
${LLCOMMON_INCLUDE_DIRS}
)
set(win_updater_SOURCE_FILES updater.cpp)
set(win_updater_HEADER_FILES CMakeLists.txt)
set_source_files_properties(${win_updater_HEADER_FILES}
PROPERTIES HEADER_FILE_ONLY TRUE)
list(APPEND win_updater_SOURCE_FILES ${win_updater_HEADER_FILES})
add_executable(windows-updater WIN32 ${win_updater_SOURCE_FILES})
target_link_libraries(windows-updater
wininet
user32
gdi32
shell32
)
set_target_properties(windows-updater
PROPERTIES
LINK_FLAGS "/NODEFAULTLIB:MSVCRT"
LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;MSVCRT\""
)
# The windows-updater doesn't link against anything non-system, apparently
#ll_deploy_sharedlibs_command(windows-updater)
/**
* @file updater.cpp
* @brief Windows auto-updater
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
//
// Usage: updater -url <url>
//
// We use dangerous fopen, strtok, mbstowcs, sprintf
// which generates warnings on VC2005.
// *TODO: Switch to fopen_s, strtok_s, etc.
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <fstream>
#define BUFSIZE 8192
int gTotalBytesRead = 0;
DWORD gTotalBytes = -1;
HWND gWindow = NULL;
WCHAR gProgress[256];
char* gUpdateURL = NULL;
#if _DEBUG
std::ofstream logfile;
#define DEBUG(expr) logfile << expr << std::endl
#else
#define DEBUG(expr) /**/
#endif
char* wchars_to_utf8chars(const WCHAR* in_chars)
{
int tlen = 0;
const WCHAR* twc = in_chars;
while (*twc++ != 0)
{
tlen++;
}
char* outchars = new char[tlen];
char* res = outchars;
for (int i=0; i<tlen; i++)
{
int cur_char = (int)(*in_chars++);
if (cur_char < 0x80)
{
*outchars++ = (char)cur_char;
}
else
{
*outchars++ = '?';
}
}
*outchars = 0;
return res;
}
class Fetcher
{
public:
Fetcher(const std::wstring& uri)
{
// These actions are broken out as separate methods not because it
// makes the code clearer, but to avoid triggering AntiVir and
// McAfee-GW-Edition virus scanners (DEV-31680).
mInet = openInet();
mDownload = openUrl(uri);
}
~Fetcher()
{
DEBUG("Calling InternetCloseHandle");
InternetCloseHandle(mDownload);
InternetCloseHandle(mInet);
}
unsigned long read(char* buffer, size_t bufflen) const;
DWORD getTotalBytes() const
{
DWORD totalBytes;
DWORD sizeof_total_bytes = sizeof(totalBytes);
HttpQueryInfo(mDownload, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
&totalBytes, &sizeof_total_bytes, NULL);
return totalBytes;
}
struct InetError: public std::runtime_error
{
InetError(const std::string& what): std::runtime_error(what) {}
};
private:
// We test results from a number of different MS functions with different
// return types -- but the common characteristic is that 0 (i.e. (! result))
// means an error of some kind.
template <typename RESULT>
static RESULT check(const std::string& desc, RESULT result)
{
if (result)
{
// success, show caller
return result;
}
DWORD err = GetLastError();
std::ostringstream out;
out << desc << " Failed: " << err;
DEBUG(out.str());
throw InetError(out.str());
}
HINTERNET openUrl(const std::wstring& uri) const;
HINTERNET openInet() const;
HINTERNET mInet, mDownload;
};
HINTERNET Fetcher::openInet() const
{
DEBUG("Calling InternetOpen");
// Init wininet subsystem
return check("InternetOpen",
InternetOpen(L"LindenUpdater", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0));
}
HINTERNET Fetcher::openUrl(const std::wstring& uri) const
{
DEBUG("Calling InternetOpenUrl: " << wchars_to_utf8chars(uri.c_str()));
return check("InternetOpenUrl",
InternetOpenUrl(mInet, uri.c_str(), NULL, 0, INTERNET_FLAG_NEED_FILE, NULL));
}
unsigned long Fetcher::read(char* buffer, size_t bufflen) const
{
unsigned long bytes_read = 0;
DEBUG("Calling InternetReadFile");
check("InternetReadFile",
InternetReadFile(mDownload, buffer, bufflen, &bytes_read));
return bytes_read;
}
int WINAPI get_url_into_file(const std::wstring& uri, const std::string& path, int *cancelled)
{
int success = FALSE;
*cancelled = FALSE;
DEBUG("Opening '" << path << "'");
FILE* fp = fopen(path.c_str(), "wb"); /* Flawfinder: ignore */
if (!fp)
{
DEBUG("Failed to open '" << path << "'");
return success;
}
// Note, ctor can throw, since it uses check() function.
Fetcher fetcher(uri);
gTotalBytes = fetcher.getTotalBytes();
/*==========================================================================*|
// nobody uses total_bytes?!? What's this doing here?
DWORD total_bytes = 0;
success = check("InternetQueryDataAvailable",
InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0));
|*==========================================================================*/
success = FALSE;
while(!success && !(*cancelled))
{
char data[BUFSIZE]; /* Flawfinder: ignore */
unsigned long bytes_read = fetcher.read(data, sizeof(data));
if (!bytes_read)
{
DEBUG("InternetReadFile Read " << bytes_read << " bytes.");
}
DEBUG("Reading Data, bytes_read = " << bytes_read);
if (bytes_read == 0)
{
// If InternetFileRead returns TRUE AND bytes_read == 0
// we've successfully downloaded the entire file
wsprintf(gProgress, L"Download complete.");
success = TRUE;
}
else
{
// write what we've got, then continue
fwrite(data, sizeof(char), bytes_read, fp);
gTotalBytesRead += int(bytes_read);
if (gTotalBytes != -1)
wsprintf(gProgress, L"Downloaded: %d%%", 100 * gTotalBytesRead / gTotalBytes);
else
wsprintf(gProgress, L"Downloaded: %dK", gTotalBytesRead / 1024);
}
DEBUG("Calling InvalidateRect");
// Mark the window as needing redraw (of the whole thing)
InvalidateRect(gWindow, NULL, TRUE);
// Do the redraw
DEBUG("Calling UpdateWindow");
UpdateWindow(gWindow);
DEBUG("Calling PeekMessage");
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
{
// bail out, user cancelled
*cancelled = TRUE;
}
}
}
fclose(fp);
return success;
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
HDC hdc; // Drawing context
PAINTSTRUCT ps;
switch(message)
{
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
RECT rect;
GetClientRect(hwnd, &rect);
DrawText(hdc, gProgress, -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
}
case WM_CLOSE:
case WM_DESTROY:
// Get out of full screen
// full_screen_mode(false);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
#define win_class_name L"FullScreen"
int parse_args(int argc, char **argv)
{
int j;
for (j = 1; j < argc; j++)
{
if ((!strcmp(argv[j], "-url")) && (++j < argc))
{
gUpdateURL = argv[j];
}
}
// If nothing was set, let the caller know.
if (!gUpdateURL)
{
return 1;
}
return 0;
}
int WINAPI
WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
// Parse the command line.
LPSTR cmd_line_including_exe_name = GetCommandLineA();
const int MAX_ARGS = 100;
int argc = 0;
char* argv[MAX_ARGS]; /* Flawfinder: ignore */
#if _DEBUG
logfile.open("updater.log", std::ios_base::out);
DEBUG("Parsing command arguments");
#endif
char *token = NULL;
if( cmd_line_including_exe_name[0] == '\"' )
{
// Exe name is enclosed in quotes
token = strtok( cmd_line_including_exe_name, "\"" );
argv[argc++] = token;
token = strtok( NULL, " \t," );
}
else
{
// Exe name is not enclosed in quotes
token = strtok( cmd_line_including_exe_name, " \t," );
}
while( (token != NULL) && (argc < MAX_ARGS) )
{
argv[argc++] = token;
/* Get next token: */
if (*(token + strlen(token) + 1) == '\"') /* Flawfinder: ignore */
{
token = strtok( NULL, "\"");
}
else
{
token = strtok( NULL, " \t," );
}
}
gUpdateURL = NULL;
/////////////////////////////////////////
//
// Process command line arguments
//
DEBUG("Processing command arguments");
//
// Parse the command line arguments
//
int parse_args_result = parse_args(argc, argv);
WNDCLASSEX wndclassex = { 0 };
//DEVMODE dev_mode = { 0 };
const int WINDOW_WIDTH = 250;
const int WINDOW_HEIGHT = 100;
wsprintf(gProgress, L"Connecting...");
/* Init the WNDCLASSEX */
wndclassex.cbSize = sizeof(WNDCLASSEX);
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.hInstance = hInstance;
wndclassex.lpfnWndProc = WinProc;
wndclassex.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclassex.lpszClassName = win_class_name;
RegisterClassEx(&wndclassex);
// Get the size of the screen
//EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
gWindow = CreateWindowEx(NULL, win_class_name,
L"Second Life Updater",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
WINDOW_WIDTH,
WINDOW_HEIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(gWindow, nShowCmd);
UpdateWindow(gWindow);
if (parse_args_result)
{
MessageBox(gWindow,
L"Usage: updater -url <url> [-name <window_title>] [-program <program_name>] [-silent]",
L"Usage", MB_OK);
return parse_args_result;
}
// Did we get a userserver to work with?
if (!gUpdateURL)
{
MessageBox(gWindow, L"Please specify the download url from the command line",
L"Error", MB_OK);
return 1;
}
// Can't feed GetTempPath into GetTempFile directly
char temp_path[MAX_PATH]; /* Flawfinder: ignore */
if (0 == GetTempPathA(sizeof(temp_path), temp_path))
{
MessageBox(gWindow, L"Problem with GetTempPath()",
L"Error", MB_OK);
return 1;
}
std::string update_exec_path(temp_path);
update_exec_path.append("Second_Life_Updater.exe");
WCHAR update_uri[4096];
mbstowcs(update_uri, gUpdateURL, sizeof(update_uri));
int success = 0;
int cancelled = 0;
// Actually do the download
try
{
DEBUG("Calling get_url_into_file");
success = get_url_into_file(update_uri, update_exec_path, &cancelled);
}
catch (const Fetcher::InetError& e)
{
(void)e;
success = FALSE;
DEBUG("Caught: " << e.what());
}
// WinInet can't tell us if we got a 404 or not. Therefor, we check
// for the size of the downloaded file, and assume that our installer
// will always be greater than 1MB.
if (gTotalBytesRead < (1024 * 1024) && ! cancelled)
{
MessageBox(gWindow,
L"The Second Life auto-update has failed.\n"
L"The problem may be caused by other software installed \n"
L"on your computer, such as a firewall.\n"
L"Please visit http://secondlife.com/download/ \n"
L"to download the latest version of Second Life.\n",
NULL, MB_OK);
return 1;
}
if (cancelled)
{
// silently exit
return 0;
}
if (!success)
{
MessageBox(gWindow,
L"Second Life download failed.\n"
L"Please try again later.",
NULL, MB_OK);
return 1;
}
// TODO: Make updates silent (with /S to NSIS)
//char params[256]; /* Flawfinder: ignore */
//sprintf(params, "/S"); /* Flawfinder: ignore */
//MessageBox(gWindow,
// L"Updating Second Life.\n\nSecond Life will automatically start once the update is complete. This may take a minute...",
// L"Download Complete",
// MB_OK);
/*==========================================================================*|
// DEV-31680: ShellExecuteA() causes McAfee-GW-Edition and AntiVir
// scanners to flag this executable as a probable virus vector.
// Less than or equal to 32 means failure
if (32 >= (int) ShellExecuteA(gWindow, "open", update_exec_path.c_str(), NULL,
"C:\\", SW_SHOWDEFAULT))
|*==========================================================================*/
// from http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (! CreateProcessA(update_exec_path.c_str(), // executable file
NULL, // command line
NULL, // process cannot be inherited
NULL, // thread cannot be inherited
FALSE, // do not inherit existing handles
0, // process creation flags
NULL, // inherit parent's environment
NULL, // inherit parent's current dir
&si, // STARTUPINFO
&pi)) // PROCESS_INFORMATION
{
MessageBox(gWindow, L"Update failed. Please try again later.", NULL, MB_OK);
return 1;
}
// Give installer some time to open a window
Sleep(1000);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment