mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 17:52:08 -10:00
458 lines
10 KiB
C++
458 lines
10 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <windows.h>
|
|
|
|
#include <Shlobj.h>
|
|
#include <Sddl.h>
|
|
|
|
#include "globalincs/pstypes.h"
|
|
#include "osapi/osregistry.h"
|
|
#include "cmdline/cmdline.h"
|
|
|
|
// ------------------------------------------------------------------------------------------------------------
|
|
// REGISTRY DEFINES/VARS
|
|
//
|
|
|
|
static char szCompanyName[128];
|
|
static char szAppName[128];
|
|
static char szAppVersion[128];
|
|
|
|
const char *Osreg_company_name = "Volition";
|
|
const char *Osreg_class_name = "FreeSpace2Class";
|
|
|
|
// RT Lets make all versions use the same registry location
|
|
// If we don't the launcher either needs to handle somehow telling what release type a
|
|
// FS2 exe is or it won't work. Its far similar to just use one default location.
|
|
// The Launcher will set up everything needed
|
|
const char *Osreg_app_name = "FreeSpace2";
|
|
const char *Osreg_title = "FreeSpace 2";
|
|
|
|
const char *Osreg_pref_dir = NULL;
|
|
|
|
int Os_reg_inited = 0;
|
|
|
|
// For string config functions
|
|
static char tmp_string_data[1024];
|
|
|
|
// This code is needed for compatibility with the old windows registry
|
|
|
|
static bool userSIDValid = false;
|
|
static SCP_string userSID;
|
|
|
|
bool get_user_sid(SCP_string& outStr)
|
|
{
|
|
HANDLE hToken = NULL;
|
|
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == FALSE)
|
|
{
|
|
mprintf(("Failed to get process token! Error Code: %d", GetLastError()));
|
|
|
|
return false;
|
|
}
|
|
|
|
DWORD dwBufferSize;
|
|
GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize);
|
|
|
|
PTOKEN_USER ptkUser = (PTOKEN_USER) new byte[dwBufferSize];
|
|
|
|
if (GetTokenInformation(hToken, TokenUser, ptkUser, dwBufferSize, &dwBufferSize))
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
if (IsValidSid(ptkUser->User.Sid) == FALSE)
|
|
{
|
|
mprintf(("Invalid SID structure detected!"));
|
|
|
|
delete[] ptkUser;
|
|
return false;
|
|
}
|
|
|
|
LPTSTR sidName = NULL;
|
|
if (ConvertSidToStringSid(ptkUser->User.Sid, &sidName) == 0)
|
|
{
|
|
mprintf(("Failed to convert SID structure to string! Error Code: %d", GetLastError()));
|
|
|
|
delete[] ptkUser;
|
|
return false;
|
|
}
|
|
|
|
outStr.assign(sidName);
|
|
|
|
LocalFree(sidName);
|
|
delete[](byte*) ptkUser;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool needsWOW64()
|
|
{
|
|
#ifdef _WIN64
|
|
// 64-bit application always use the Wow6432Node
|
|
return true;
|
|
#else
|
|
BOOL bIsWow64 = FALSE;
|
|
if (!IsWow64Process(GetCurrentProcess(), &bIsWow64))
|
|
{
|
|
mprintf(("Failed to determine if we run under Wow64, registry configuration may fail!"));
|
|
return false;
|
|
}
|
|
|
|
return bIsWow64 == TRUE;
|
|
#endif
|
|
}
|
|
|
|
HKEY get_registry_keyname(char* out_keyname, const char* section)
|
|
{
|
|
if (!Cmdline_alternate_registry_path) {
|
|
// Use the original registry path, sometimes breaks for no reason which can be fixed by the code below
|
|
if (section) {
|
|
sprintf(out_keyname, "Software\\%s\\%s\\%s", szCompanyName, szAppName, section);
|
|
}
|
|
else {
|
|
sprintf(out_keyname, "Software\\%s\\%s", szCompanyName, szAppName);
|
|
}
|
|
return HKEY_LOCAL_MACHINE;
|
|
}
|
|
|
|
// Every compiler from Visual Studio 2008 onward should have support for UAC
|
|
#if _MSC_VER >= 1400
|
|
if (userSIDValid)
|
|
{
|
|
if (needsWOW64())
|
|
{
|
|
if (section) {
|
|
sprintf(out_keyname, "%s_Classes\\VirtualStore\\Machine\\Software\\Wow6432Node\\%s\\%s\\%s", userSID.c_str(), szCompanyName, szAppName, section);
|
|
}
|
|
else {
|
|
sprintf(out_keyname, "%s_Classes\\VirtualStore\\Machine\\Software\\Wow6432Node\\%s\\%s", userSID.c_str(), szCompanyName, szAppName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (section) {
|
|
sprintf(out_keyname, "%s_Classes\\VirtualStore\\Machine\\Software\\%s\\%s\\%s", userSID.c_str(), szCompanyName, szAppName, section);
|
|
}
|
|
else {
|
|
sprintf(out_keyname, "%s_Classes\\VirtualStore\\Machine\\Software\\%s\\%s", userSID.c_str(), szCompanyName, szAppName);
|
|
}
|
|
}
|
|
|
|
return HKEY_USERS;
|
|
}
|
|
else
|
|
{
|
|
// This will probably fail
|
|
if (section) {
|
|
sprintf(out_keyname, "Software\\%s\\%s\\%s", szCompanyName, szAppName, section);
|
|
}
|
|
else {
|
|
sprintf(out_keyname, "Software\\%s\\%s", szCompanyName, szAppName);
|
|
}
|
|
|
|
return HKEY_LOCAL_MACHINE;
|
|
}
|
|
#else
|
|
if (section) {
|
|
sprintf(out_keyname, "Software\\%s\\%s\\%s", szCompanyName, szAppName, section);
|
|
}
|
|
else {
|
|
sprintf(out_keyname, "Software\\%s\\%s", szCompanyName, szAppName);
|
|
}
|
|
|
|
return HKEY_LOCAL_MACHINE;
|
|
#endif
|
|
}
|
|
|
|
bool registry_has_value(const char *section, const char *name)
|
|
{
|
|
HKEY hKey = NULL;
|
|
char keyname[1024];
|
|
LONG lResult;
|
|
bool retVal = false;
|
|
|
|
if (!Os_reg_inited) {
|
|
return NULL;
|
|
}
|
|
|
|
HKEY useHKey = get_registry_keyname(keyname, section);
|
|
|
|
lResult = RegOpenKeyEx(useHKey, // Where it is
|
|
keyname, // name of key
|
|
NULL, // DWORD reserved
|
|
KEY_QUERY_VALUE, // Allows all changes
|
|
&hKey); // Location to store key
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!name) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
lResult = RegQueryValueEx(hKey, // Handle to key
|
|
name, // The values name
|
|
NULL, // DWORD reserved
|
|
NULL, // What kind it is
|
|
NULL, // value to set
|
|
NULL); // How many bytes to set
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
retVal = true;
|
|
|
|
Cleanup:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
void os_config_write_string(const char *section, const char *name, const char *value)
|
|
{
|
|
HKEY hKey = NULL;
|
|
DWORD dwDisposition;
|
|
char keyname[1024];
|
|
LONG lResult;
|
|
|
|
if (!Os_reg_inited) {
|
|
return;
|
|
}
|
|
|
|
HKEY useHKey = get_registry_keyname(keyname, section);
|
|
|
|
lResult = RegCreateKeyEx(useHKey, // Where to add it
|
|
keyname, // name of key
|
|
NULL, // DWORD reserved
|
|
"", // Object class
|
|
REG_OPTION_NON_VOLATILE, // Save to disk
|
|
KEY_ALL_ACCESS, // Allows all changes
|
|
NULL, // Default security attributes
|
|
&hKey, // Location to store key
|
|
&dwDisposition); // Location to store status of key
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!name) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
lResult = RegSetValueEx(hKey, // Handle to key
|
|
name, // The values name
|
|
NULL, // DWORD reserved
|
|
REG_SZ, // null terminated string
|
|
(CONST BYTE *)value, // value to set
|
|
strlen(value) + 1); // How many bytes to set
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
void os_config_write_uint(const char *section, const char *name, uint value)
|
|
{
|
|
HKEY hKey = NULL;
|
|
DWORD dwDisposition;
|
|
char keyname[1024];
|
|
LONG lResult;
|
|
|
|
if (!Os_reg_inited) {
|
|
return;
|
|
}
|
|
|
|
HKEY useHKey = get_registry_keyname(keyname, section);
|
|
|
|
lResult = RegCreateKeyEx(useHKey, // Where to add it
|
|
keyname, // name of key
|
|
NULL, // DWORD reserved
|
|
"", // Object class
|
|
REG_OPTION_NON_VOLATILE, // Save to disk
|
|
KEY_ALL_ACCESS, // Allows all changes
|
|
NULL, // Default security attributes
|
|
&hKey, // Location to store key
|
|
&dwDisposition); // Location to store status of key
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!name) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
lResult = RegSetValueEx(hKey, // Handle to key
|
|
name, // The values name
|
|
NULL, // DWORD reserved
|
|
REG_DWORD, // null terminated string
|
|
(CONST BYTE *)&value, // value to set
|
|
4); // How many bytes to set
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
// Reads a string from the INI file. If default is passed,
|
|
// and the string isn't found, returns ptr to default otherwise
|
|
// returns NULL; Copy the return value somewhere before
|
|
// calling os_read_string again, because it might reuse the
|
|
// same buffer.
|
|
const char * os_config_read_string(const char *section, const char *name, const char *default_value)
|
|
{
|
|
HKEY hKey = NULL;
|
|
DWORD dwType, dwLen;
|
|
char keyname[1024];
|
|
LONG lResult;
|
|
|
|
if (!Os_reg_inited) {
|
|
return NULL;
|
|
}
|
|
|
|
HKEY useHKey = get_registry_keyname(keyname, section);
|
|
|
|
lResult = RegOpenKeyEx(useHKey, // Where it is
|
|
keyname, // name of key
|
|
NULL, // DWORD reserved
|
|
KEY_QUERY_VALUE, // Allows all changes
|
|
&hKey); // Location to store key
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!name) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
dwLen = 1024;
|
|
lResult = RegQueryValueEx(hKey, // Handle to key
|
|
name, // The values name
|
|
NULL, // DWORD reserved
|
|
&dwType, // What kind it is
|
|
(ubyte *)&tmp_string_data, // value to set
|
|
&dwLen); // How many bytes to set
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
default_value = tmp_string_data;
|
|
|
|
Cleanup:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return default_value;
|
|
}
|
|
|
|
// Reads a string from the INI file. Default_value must
|
|
// be passed, and if 'name' isn't found, then returns default_value
|
|
uint os_config_read_uint(const char *section, const char *name, uint default_value)
|
|
{
|
|
HKEY hKey = NULL;
|
|
DWORD dwType, dwLen;
|
|
char keyname[1024];
|
|
LONG lResult;
|
|
uint tmp_val;
|
|
|
|
if (!Os_reg_inited) {
|
|
return default_value;
|
|
}
|
|
|
|
HKEY useHKey = get_registry_keyname(keyname, section);
|
|
|
|
lResult = RegOpenKeyEx(useHKey, // Where it is
|
|
keyname, // name of key
|
|
NULL, // DWORD reserved
|
|
KEY_QUERY_VALUE, // Allows all changes
|
|
&hKey); // Location to store key
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!name) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
dwLen = 4;
|
|
lResult = RegQueryValueEx(hKey, // Handle to key
|
|
name, // The values name
|
|
NULL, // DWORD reserved
|
|
&dwType, // What kind it is
|
|
(ubyte *)&tmp_val, // value to set
|
|
&dwLen); // How many bytes to set
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
default_value = tmp_val;
|
|
|
|
Cleanup:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return default_value;
|
|
}
|
|
|
|
|
|
// initialize the registry. setup default keys to use
|
|
void os_init_registry_stuff(const char *company, const char *app, const char *version)
|
|
{
|
|
if (company) {
|
|
strcpy_s(szCompanyName, company);
|
|
}
|
|
else {
|
|
strcpy_s(szCompanyName, Osreg_company_name);
|
|
}
|
|
|
|
if (app) {
|
|
strcpy_s(szAppName, app);
|
|
}
|
|
else {
|
|
strcpy_s(szAppName, Osreg_app_name);
|
|
}
|
|
|
|
if (version) {
|
|
strcpy_s(szAppVersion, version);
|
|
}
|
|
else {
|
|
strcpy_s(szAppVersion, "1.0");
|
|
}
|
|
|
|
OSVERSIONINFO versionInfo;
|
|
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&versionInfo);
|
|
|
|
// Windows Vista is 6.0 which is the first version requiring this
|
|
if (versionInfo.dwMajorVersion >= 6)
|
|
{
|
|
userSIDValid = get_user_sid(userSID);
|
|
}
|
|
|
|
Os_reg_inited = 1;
|
|
}
|