/*
- * 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>
#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--";
-int _tmain(int argc, _TCHAR* argv[])
+
+bool isWritable(wchar_t* path)
{
- STARTUPINFO startupInfo = {0};
- startupInfo.cb = sizeof(startupInfo);
- PROCESS_INFORMATION processInformation = {0};
+ 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;
+ }
+ }
- startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
- startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
- startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+ CloseHandle(file);
+ DeleteFile(fileName);
+ return true;
+}
- wchar_t commandLine[32768] = L"";
+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++) {
- wcscat_s(commandLine, L"\"");
- wcscat_s(commandLine, argv[i]);
- wcscat_s(commandLine, L"\" ");
+ 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;
+}
- 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*/))
+int _tmain(int argc, _TCHAR* argv[])
+{
+ 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;
}