JetBrains products updater: invoke UAC elevation if needed (IDEA-52571)

This commit is contained in:
Kirill.Safonov
2011-09-01 11:39:42 +04:00
parent 804c5321bc
commit f7f7b9deb6
3 changed files with 171 additions and 56 deletions

Binary file not shown.

View File

@@ -1,18 +1,18 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "stdafx.h"
#include <windows.h>
@@ -23,53 +23,168 @@
#include <string.h>
#include <stdlib.h>
static const wchar_t* INSTALL_PARAM = L"install";
static const wchar_t* SKIP_ELEVATION_PARAM = L"--skip-uac-elevation--";
bool isWritable(wchar_t* path)
{
wprintf(L"Trying to create temporary file in\"%s\"\n", path);
wchar_t fileName[32768] = L"";
wcscat_s(fileName, path);
wcscat_s(fileName, L"\\.jetbrains-uac-check");
HANDLE file = CreateFile(fileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
if (file == INVALID_HANDLE_VALUE)
{
DWORD error = GetLastError();
if (error == ERROR_ACCESS_DENIED)
{
// looks like we need to request elevation
return false;
}
else
{
// there's no need to request elevaion since patcher will most likely fail anyway
wprintf(L"Unexpected error when creating temp file: %d\n", error);
fflush(stdout);
return true;
}
}
CloseHandle(file);
DeleteFile(fileName);
return true;
}
void appendArgument(wchar_t result[], wchar_t argument[])
{
bool needsQuoting = wcschr(argument, L' ') != NULL;
if (needsQuoting)
{
wcscat_s(result, 32768, L"\"");
}
wcscat_s(result, 32768, argument);
if (needsQuoting)
{
wcscat_s(result, 32768, L"\"");
}
wcscat_s(result, 32768, L" ");
}
bool getElevationPath(int argc, _TCHAR* argv[], wchar_t result[])
{
int start = -1;
for (int i = 1; i < argc; i++) {
if (wcscmp(argv[i], SKIP_ELEVATION_PARAM) == 0)
{
wprintf(L"Elevation suppressed\n");
fflush(stdout);
return false;
}
if (wcscmp(argv[i], INSTALL_PARAM) == 0)
{
start = i;
}
else if (start >= 0)
{
if (i > start + 1)
{
wcscat_s(result, 32768, L" ");
}
wcscat_s(result, 32768, argv[i]);
}
}
return start >= 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
STARTUPINFO startupInfo = {0};
startupInfo.cb = sizeof(startupInfo);
PROCESS_INFORMATION processInformation = {0};
startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
wchar_t commandLine[32768] = L"";
for (int i = 1; i < argc; i++) {
wcscat_s(commandLine, L"\"");
wcscat_s(commandLine, argv[i]);
wcscat_s(commandLine, L"\" ");
}
wprintf(L"Creating new process: %s\n", commandLine);
fflush(stdout);
if (!CreateProcess(
NULL, /*LPCTSTR lpApplicationName*/
commandLine,/* LPTSTR lpCommandLine*/
NULL, /*LPSECURITY_ATTRIBUTES lpProcessAttributes*/
NULL, /*LPSECURITY_ATTRIBUTES lpThreadAttributes*/
TRUE, /*BOOL bInheritHandles,*/
0, /*DWORD dwCreationFlags*/
NULL, /*LPVOID lpEnvironment*/
NULL, /*LPCTSTR lpCurrentDirectory*/
&startupInfo, /*LPSTARTUPINFO lpStartupInfo*/
&processInformation /*LPPROCESS_INFORMATION lpProcessInformation*/))
wchar_t elevationPath[32768] = L"";
HANDLE processHandle = NULL;
if (getElevationPath(argc, argv, elevationPath) && !isWritable(elevationPath))
{
wchar_t paramsLine[32768] = L"";
wcscat_s(paramsLine, SKIP_ELEVATION_PARAM);
for (int i = 1; i < argc; i++)
{
wcscat_s(paramsLine, L" ");
appendArgument(paramsLine, argv[i]);
}
wprintf(L"Creating elevated process: %s %s\n", argv[0], paramsLine);
fflush(stdout);
SHELLEXECUTEINFO shExecInfo;
shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExecInfo.hwnd = NULL;
shExecInfo.lpVerb = L"runas";
shExecInfo.lpFile = argv[0];
shExecInfo.lpParameters = paramsLine;
shExecInfo.lpDirectory = NULL;
shExecInfo.nShow = SW_HIDE;
shExecInfo.hInstApp = NULL;
if (ShellExecuteEx(&shExecInfo) == FALSE)
{
wprintf(L"ShellExecuteEx() failed with error code %d\n", GetLastError());
fflush(stdout);
return -1;
}
processHandle = shExecInfo.hProcess;
}
else
{
STARTUPINFO startupInfo = {0};
startupInfo.cb = sizeof(startupInfo);
PROCESS_INFORMATION processInformation = {0};
startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
wchar_t commandLine[32768] = L"";
for (int i = 1; i < argc; i++) {
if (wcscmp(argv[i], SKIP_ELEVATION_PARAM) != 0)
{
// add only original parameters
appendArgument(commandLine, argv[i]);
}
}
wprintf(L"Creating new process: %s\n", commandLine);
fflush(stdout);
if (!CreateProcess(
NULL, /*LPCTSTR lpApplicationName*/
commandLine,/* LPTSTR lpCommandLine*/
NULL, /*LPSECURITY_ATTRIBUTES lpProcessAttributes*/
NULL, /*LPSECURITY_ATTRIBUTES lpThreadAttributes*/
TRUE, /*BOOL bInheritHandles,*/
0, /*DWORD dwCreationFlags*/
NULL, /*LPVOID lpEnvironment*/
NULL, /*LPCTSTR lpCurrentDirectory*/
&startupInfo, /*LPSTARTUPINFO lpStartupInfo*/
&processInformation /*LPPROCESS_INFORMATION lpProcessInformation*/))
{
wprintf(L"Cannot create process: %d\n", GetLastError());
return -1;
}
processHandle = processInformation.hProcess;
}
WaitForSingleObject(processInformation.hProcess, INFINITE);
WaitForSingleObject(processHandle, INFINITE);
DWORD exitCode = 0;
if (!GetExitCodeProcess(processInformation.hProcess, &exitCode))
if (!GetExitCodeProcess(processHandle, &exitCode))
{
wprintf(L"Cannot retrieve process exit code: %d\n", GetLastError());
exitCode = -1;
}
CloseHandle(processInformation.hProcess);
CloseHandle(processHandle);
return exitCode;
}

View File

@@ -7,7 +7,7 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
#include "windows.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@@ -27,18 +27,18 @@ LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
// TEXTINCLUDE
//
1 TEXTINCLUDE
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"#include ""windows.h""\r\n"
"\0"
END
3 TEXTINCLUDE
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
@@ -70,12 +70,12 @@ BEGIN
BLOCK "041904b0"
BEGIN
VALUE "CompanyName", "JetBrains, Inc."
VALUE "FileDescription", "IntelliJ IDEA Automatic Update"
VALUE "FileDescription", "JetBrains Updater Launcher"
VALUE "FileVersion", "1, 0, 0, 1"
VALUE "InternalName", "fsnotifier"
VALUE "LegalCopyright", "Copyright (C) 2009 JetBrains, Inc."
VALUE "InternalName", "vistalauncher"
VALUE "LegalCopyright", "Copyright (C) 2009-2011 JetBrains, Inc."
VALUE "OriginalFilename", "vistalauncher.exe"
VALUE "ProductName", "IntelliJ IDEA"
VALUE "ProductName", "JetBrains Updater Launcher"
VALUE "ProductVersion", "1, 0, 0, 1"
END
END