Skip to content

Commit

Permalink
Merge pull request #337 from Squirrel/machine-installs
Browse files Browse the repository at this point in the history
Per-Machine installs
  • Loading branch information
anaisbetts committed May 11, 2015
2 parents 281bf59 + 72bbf04 commit 55f09fe
Show file tree
Hide file tree
Showing 7 changed files with 1,123 additions and 4 deletions.
151 changes: 151 additions & 0 deletions src/Setup/MachineInstaller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#include "stdafx.h"
#include "unzip.h"
#include "MachineInstaller.h"
#include "resource.h"
#include <sddl.h>

bool findPackageFromEmbeddedZip(wchar_t* buf, DWORD cbSize)
{
bool ret = false;

CResource zipResource;
if (!zipResource.Load(L"DATA", IDR_UPDATE_ZIP)) {
return false;
}

DWORD dwSize = zipResource.GetSize();
if (dwSize < 0x100) {
return false;
}

BYTE* pData = (BYTE*)zipResource.Lock();
HZIP zipFile = OpenZip(pData, dwSize, NULL);

ZRESULT zr;
int index = 0;
do {
ZIPENTRY zentry;

zr = GetZipItem(zipFile, index, &zentry);
if (zr != ZR_OK && zr != ZR_MORE) {
break;
}

if (wcsstr(zentry.name, L"nupkg")) {
ZeroMemory(buf, cbSize);

int idx = wcscspn(zentry.name, L"-");
memcpy(buf, zentry.name, sizeof(wchar_t) * idx);
ret = true;
break;
}

index++;
} while (zr == ZR_MORE || zr == ZR_OK);

CloseZip(zipFile);
zipResource.Release();

return ret;
}

int MachineInstaller::PerformMachineInstallSetup()
{
wchar_t packageName[512];

if (!findPackageFromEmbeddedZip(packageName, sizeof(packageName))) {
MessageBox(NULL, L"Corrupt installer", L"Cannot find package name for installer, is it created correctly?", MB_OK);
return ERROR_INVALID_PARAMETER;
}

wchar_t machineInstallFolder[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, machineInstallFolder);
wcscat(machineInstallFolder, L"\\SquirrelMachineInstalls");

// NB: This is the DACL for Program Files
PSECURITY_DESCRIPTOR descriptor;
ConvertStringSecurityDescriptorToSecurityDescriptor(
L"D:PAI(A;;FA;;;S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464)(A;CIIO;GA;;;S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464)(A;;0x1301bf;;;SY)(A;OICIIO;GA;;;SY)(A;;0x1301bf;;;BA)(A;OICIIO;GA;;;BA)(A;;0x1200a9;;;BU)(A;OICIIO;GXGR;;;BU)(A;OICIIO;GA;;;CO)(A;;0x1200a9;;;AC)(A;OICIIO;GXGR;;;AC)",
SDDL_REVISION_1,
&descriptor, NULL);

SECURITY_ATTRIBUTES attrs;
attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
attrs.bInheritHandle = false;
attrs.lpSecurityDescriptor = descriptor;

if (!CreateDirectory(machineInstallFolder, &attrs) && GetLastError() != ERROR_ALREADY_EXISTS) {
LocalFree(descriptor);
return GetLastError();
}

LocalFree(descriptor);

wcscat(machineInstallFolder, L"\\");
wcscat(machineInstallFolder, packageName);
wcscat(machineInstallFolder, L".exe");

wchar_t ourFile[MAX_PATH];
HMODULE hMod = GetModuleHandle(NULL);
GetModuleFileName(hMod, ourFile, _countof(ourFile));

if (!CopyFile(ourFile, machineInstallFolder, false)) {
return GetLastError();
}

HKEY runKey;
DWORD dontcare;
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &runKey, &dontcare) != ERROR_SUCCESS) {
return GetLastError();
}

wcscat_s(machineInstallFolder, L" --checkInstall");

if (RegSetValueEx(runKey, packageName, 0, REG_SZ, (BYTE*)machineInstallFolder, (wcsnlen(machineInstallFolder, sizeof(machineInstallFolder)) + 1) * sizeof(wchar_t)) != ERROR_SUCCESS) {
return GetLastError();
}

RegCloseKey(runKey);
return 0;
}


bool MachineInstaller::ShouldSilentInstall()
{
// Figure out the package name from our own EXE name
wchar_t ourFile[MAX_PATH];
HMODULE hMod = GetModuleHandle(NULL);
GetModuleFileName(hMod, ourFile, _countof(ourFile));

CString fullPath = CString(ourFile);
CString pkgName = CString(ourFile + fullPath.ReverseFind(L'\\'));
pkgName.Replace(L".exe", L"");

wchar_t installFolder[MAX_PATH];

// C:\Users\Username\AppData\Local\$pkgName\packages
SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, installFolder);
wcscat(installFolder, L"\\");
wcscat(installFolder, pkgName);
wcscat(installFolder, L"\\");
wcscat(installFolder, L"packages");

if (GetFileAttributes(installFolder) != INVALID_FILE_ATTRIBUTES) return false;

// C:\ProgramData\$pkgName\$username\packages
wchar_t username[512];
DWORD unamesize = _countof(username);
SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, installFolder);
GetUserName(username, &unamesize);
wcscat(installFolder, L"\\");
wcscat(installFolder, pkgName);
wcscat(installFolder, L"\\");
wcscat(installFolder, username);
wcscat(installFolder, L"\\");
wcscat(installFolder, L"packages");

if (GetFileAttributes(installFolder) != INVALID_FILE_ATTRIBUTES) return false;

// Neither exist, create them
return true;
}
8 changes: 8 additions & 0 deletions src/Setup/MachineInstaller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once
class MachineInstaller
{
public:
static int PerformMachineInstallSetup();
static bool ShouldSilentInstall();
};

2 changes: 2 additions & 0 deletions src/Setup/Setup.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="FxHelper.h" />
<ClInclude Include="MachineInstaller.h" />
<ClInclude Include="Resource.h" />
<ClInclude Include="Setup.h" />
<ClInclude Include="stdafx.h" />
Expand All @@ -154,6 +155,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="FxHelper.cpp" />
<ClCompile Include="MachineInstaller.cpp" />
<ClCompile Include="unzip.cpp" />
<ClCompile Include="UpdateRunner.cpp" />
<ClCompile Include="winmain.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions src/Setup/Setup.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
<ClInclude Include="UpdateRunner.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MachineInstaller.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
Expand All @@ -53,6 +56,9 @@
<ClCompile Include="UpdateRunner.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MachineInstaller.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Setup.rc">
Expand Down
2 changes: 2 additions & 0 deletions src/Setup/stdafx.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// are changed infrequently
//

#define _CRT_SECURE_NO_WARNINGS 1

#pragma once

#include "targetver.h"
Expand Down
32 changes: 28 additions & 4 deletions src/Setup/winmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Setup.h"
#include "FxHelper.h"
#include "UpdateRunner.h"
#include "MachineInstaller.h"

CAppModule _Module;

Expand All @@ -14,14 +15,39 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_ int nCmdShow)
{
int exitCode = -1;
CString cmdLine(lpCmdLine);

if (cmdLine.Find(L"--checkInstall") >= 0) {
// If we're already installed, exit as fast as possible
if (!MachineInstaller::ShouldSilentInstall()) {
exitCode = 0;
goto out;
}

// Make sure update.exe gets silent
wcscat(lpCmdLine, L" --silent");
}

HRESULT hr = ::CoInitialize(NULL);
ATLASSERT(SUCCEEDED(hr));

AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);
hr = _Module.Init(NULL, hInstance);

CString cmdLine(lpCmdLine);
bool isQuiet = (cmdLine.Find(L"-s") >= 0);
bool weAreUACElevated = CUpdateRunner::AreWeUACElevated() == S_OK;
bool explicitMachineInstall = (cmdLine.Find(L"--machine") >= 0);

if (explicitMachineInstall || weAreUACElevated) {
exitCode = MachineInstaller::PerformMachineInstallSetup();
if (exitCode != 0) goto out;
isQuiet = true;

// Make sure update.exe gets silent
if (explicitMachineInstall) {
wcscat(lpCmdLine, L" --silent");
}
}

if (!CFxHelper::CanInstallDotNet4_5()) {
// Explain this as nicely as possible and give up.
Expand All @@ -44,11 +70,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
}
}

hr = CUpdateRunner::AreWeUACElevated();

// If we're UAC-elevated, we shouldn't be because it will give us permissions
// problems later. Just silently rerun ourselves.
if (hr == S_OK) {
if (weAreUACElevated) {
wchar_t buf[4096];
HMODULE hMod = GetModuleHandle(NULL);
GetModuleFileNameW(hMod, buf, 4096);
Expand Down
Loading

0 comments on commit 55f09fe

Please sign in to comment.