From c0e0728ff439ddb364cee26f164e46705beac822 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 1 Sep 2021 02:41:52 +0300 Subject: [PATCH] Add drivers for the MSVC toolchain Shared libraries are not yet properly supported. Import libraries are not generated and all of my code lacks the necessary attributes anyway. --- Build | 8 ++ source/architecture.cpp | 22 +++-- source/builder.cpp | 3 + source/microsofttools.cpp | 79 +++++++++++++++++ source/microsofttools.h | 32 +++++++ source/msvcarchiver.cpp | 66 ++++++++++++++ source/msvcarchiver.h | 22 +++++ source/msvccompiler.cpp | 180 ++++++++++++++++++++++++++++++++++++++ source/msvccompiler.h | 28 ++++++ source/msvclinker.cpp | 134 ++++++++++++++++++++++++++++ source/msvclinker.h | 26 ++++++ source/sysutils.cpp | 78 +++++++++++++++++ source/sysutils.h | 5 ++ 13 files changed, 678 insertions(+), 5 deletions(-) create mode 100644 source/microsofttools.cpp create mode 100644 source/microsofttools.h create mode 100644 source/msvcarchiver.cpp create mode 100644 source/msvcarchiver.h create mode 100644 source/msvccompiler.cpp create mode 100644 source/msvccompiler.h create mode 100644 source/msvclinker.cpp create mode 100644 source/msvclinker.h diff --git a/Build b/Build index 1abaa6c..2363ad7 100644 --- a/Build +++ b/Build @@ -10,6 +10,14 @@ package "builder" program "builder" { source "source"; + if_arch "windows" + { + build_info + { + library "ole32"; + library "advapi32"; + }; + }; install true; }; diff --git a/source/architecture.cpp b/source/architecture.cpp index 75a6460..58f435d 100644 --- a/source/architecture.cpp +++ b/source/architecture.cpp @@ -68,6 +68,7 @@ const char *toolchains[] = { "gnu", "clang", + "msvc", 0 }; @@ -131,6 +132,8 @@ Architecture::Architecture(Builder &b, const string &spec): { if((system=="darwin" || system=="freebsd") && builder.get_vfs().find_binary("clang")) toolchain = "clang"; + else if(system=="windows" && native) + toolchain = "msvc"; else toolchain = "gnu"; } @@ -142,18 +145,27 @@ Architecture::Architecture(Builder &b, const string &spec): name += format("-%s", fpu); name += format("-%d-%s-%s", bits, system, toolchain); - add_pattern("%.o"); if(system=="windows") { add_pattern("%.dll"); - add_pattern("lib%.dll"); - add_pattern("lib%.dll.a"); - add_pattern("lib%.a"); - add_pattern("%.lib"); + if(toolchain=="msvc") + { + add_pattern("%.obj"); + add_pattern("%.lib"); + add_pattern("%_static.lib"); + } + else + { + add_pattern("%.o"); + add_pattern("lib%.dll"); + add_pattern("lib%.dll.a"); + add_pattern("lib%.a"); + } add_pattern("%.exe"); } else { + add_pattern("%.o"); if(system=="darwin") add_pattern("lib%.dylib"); else diff --git a/source/builder.cpp b/source/builder.cpp index 7ef1ea1..65d7da4 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -17,6 +17,7 @@ #include "datatool.h" #include "gnutools.h" #include "installedfile.h" +#include "microsofttools.h" #include "package.h" #include "sharedlibrary.h" #include "sourcepackage.h" @@ -89,6 +90,8 @@ void Builder::add_default_tools() const string &arch_tc = current_arch->get_toolchain(); if(current_arch->get_system()=="android") toolchain.add_toolchain(new AndroidTools(*this, *current_arch)); + else if(arch_tc=="msvc") + toolchain.add_toolchain(new MicrosoftTools(*this, *current_arch)); else if(arch_tc=="clang") toolchain.add_toolchain(new ClangTools(*this, *current_arch)); else if(arch_tc=="gnu") diff --git a/source/microsofttools.cpp b/source/microsofttools.cpp new file mode 100644 index 0000000..05edda5 --- /dev/null +++ b/source/microsofttools.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include "builder.h" +#include "externaltask.h" +#include "logger.h" +#include "microsofttools.h" +#include "msvcarchiver.h" +#include "msvccompiler.h" +#include "msvclinker.h" +#include "sysutils.h" + +using namespace std; +using namespace Msp; + +MicrosoftTools::MicrosoftTools(Builder &builder, const Architecture &arch) +{ + find_vc_bin_dir(builder, arch); + find_windows_sdk_dir(builder); + + add_tool(new MsvcCompiler(builder, arch, "CC", *this)); + add_tool(new MsvcCompiler(builder, arch, "CXX", *this)); + add_tool(new MsvcLinker(builder, arch, *this)); + add_tool(new MsvcArchiver(builder, arch, *this)); +} + +void MicrosoftTools::find_vc_bin_dir(Builder &builder, const Architecture &arch) +{ + FS::Path program_files_x86 = get_program_files_x86_dir(); + + ExternalTask::Arguments argv; + argv.push_back((program_files_x86/"Microsoft Visual Studio"/"Installer"/"vswhere.exe").str()); + argv.push_back("-latest"); + argv.push_back("-property"); + argv.push_back("installationPath"); + + builder.get_logger().log("auxcommands", format("Running %s", join(argv.begin(), argv.end()))); + + string output = ExternalTask::run_and_capture_output(argv, FS::Path(), true); + FS::Path vs_path = strip(output); + + builder.get_logger().log("tools", format("Visual Studio found in %s", vs_path)); + + FS::Path vc_version_fn = vs_path/"VC"/"Auxiliary"/"Build"/"Microsoft.VCToolsVersion.v142.default.txt"; + builder.get_logger().log("files", format("Reading %s", vc_version_fn)); + char buffer[256]; + unsigned len = IO::File(vc_version_fn.str()).read(buffer, sizeof(buffer)); + string vc_version = strip(string(buffer, len)); + + builder.get_logger().log("tools", format("Detected MSVC version %s", vc_version)); + + const Architecture &native_arch = builder.get_native_arch(); + string host = (native_arch.get_bits()==64 ? "Hostx64" : "Hostx86"); + string target = (arch.get_bits()==64 ? "x64" : "x86"); + + vc_base_dir = vs_path/"VC"/"Tools"/"MSVC"/vc_version; + vc_bin_dir = vc_base_dir/"bin"/host/target; +} + +void MicrosoftTools::find_windows_sdk_dir(Builder &builder) +{ + win_sdk_dir = get_registry_value("HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0\\InstallationFolder"); + if(win_sdk_dir.empty()) + win_sdk_dir = get_program_files_x86_dir()/"Windows Kits"/"10"; + + builder.get_logger().log("files", format("Traversing %s", win_sdk_dir/"include")); + vector sdk_versions = FS::list_filtered(win_sdk_dir/"include", "^10\\."); + if(sdk_versions.empty()) + { + builder.get_logger().log("problems", "No Windows SDK versions found"); + return; + } + + sort(sdk_versions); + win_sdk_version = sdk_versions.back(); + + builder.get_logger().log("tools", format("Windows SDK version %s found in %s", win_sdk_version, win_sdk_dir)); +} diff --git a/source/microsofttools.h b/source/microsofttools.h new file mode 100644 index 0000000..027499a --- /dev/null +++ b/source/microsofttools.h @@ -0,0 +1,32 @@ +#ifndef MICROSOFTTOOLS_H_ +#define MICROSOFTTOOLS_H_ + +#include +#include "toolchain.h" + +class Architecture; +class Builder; + +class MicrosoftTools: public Toolchain +{ +private: + Msp::FS::Path vc_base_dir; + Msp::FS::Path vc_bin_dir; + Msp::FS::Path win_sdk_dir; + std::string win_sdk_version; + +public: + MicrosoftTools(Builder &, const Architecture &); + +private: + void find_vc_bin_dir(Builder &, const Architecture &); + void find_windows_sdk_dir(Builder &); + +public: + const Msp::FS::Path &get_vc_base_dir() const { return vc_base_dir; } + const Msp::FS::Path &get_vc_bin_dir() const { return vc_bin_dir; } + const Msp::FS::Path &get_windows_sdk_dir() const { return win_sdk_dir; } + const std::string &get_windows_sdk_version() const { return win_sdk_version; } +}; + +#endif diff --git a/source/msvcarchiver.cpp b/source/msvcarchiver.cpp new file mode 100644 index 0000000..1481184 --- /dev/null +++ b/source/msvcarchiver.cpp @@ -0,0 +1,66 @@ +#include +#include "component.h" +#include "externaltask.h" +#include "microsofttools.h" +#include "msvcarchiver.h" +#include "objectfile.h" +#include "sourcepackage.h" +#include "staticlibrary.h" + +using namespace std; +using namespace Msp; + +MsvcArchiver::MsvcArchiver(Builder &b, const Architecture &a, const MicrosoftTools &m): + Tool(b, a, "AR"), + ms_tools(m) +{ + input_suffixes.push_back(".o"); + processing_unit = COMPONENT; + set_command((ms_tools.get_vc_bin_dir()/"lib.exe").str(), false); +} + +Target *MsvcArchiver::create_target(const list &sources, const string &) +{ + if(sources.empty()) + throw invalid_argument("MsvcArchiver::create_target"); + + list objs; + for(list::const_iterator i=sources.begin(); i!=sources.end(); ++i) + { + if(ObjectFile *obj = dynamic_cast(*i)) + objs.push_back(obj); + else + throw invalid_argument("MsvcArchiver::create_target"); + } + + const Component &comp = *objs.front()->get_component(); + StaticLibrary *lib = new StaticLibrary(builder, comp, objs); + lib->set_tool(*this); + return lib; +} + +string MsvcArchiver::create_build_signature(const BuildInfo &) const +{ + return FS::basename(executable->get_path()); +} + +Task *MsvcArchiver::run(const Target &target) const +{ + const StaticLibrary &lib = dynamic_cast(target); + const Component &comp = *lib.get_component(); + + vector argv; + argv.push_back(executable->get_path().str()); + argv.push_back("/NOLOGO"); + + FS::Path work_dir = comp.get_package().get_source_directory(); + + argv.push_back("/OUT:"+relative(lib.get_path(), work_dir).str()); + + const Target::Dependencies &deps = lib.get_dependencies(); + for(Target::Dependencies::const_iterator i=deps.begin(); i!=deps.end(); ++i) + if(ObjectFile *obj = dynamic_cast(*i)) + argv.push_back(relative(obj->get_path(), work_dir).str()); + + return new ExternalTask(argv, work_dir); +} diff --git a/source/msvcarchiver.h b/source/msvcarchiver.h new file mode 100644 index 0000000..0467ffb --- /dev/null +++ b/source/msvcarchiver.h @@ -0,0 +1,22 @@ +#ifndef MSVCARCHIVER_H_ +#define MSVCARCHIVER_H_ + +#include "tool.h" + +class MicrosoftTools; + +class MsvcArchiver: public Tool +{ +private: + const MicrosoftTools &ms_tools; + +public: + MsvcArchiver(Builder &, const Architecture &, const MicrosoftTools &); + + virtual Target *create_target(const std::list &, const std::string &); + virtual std::string create_build_signature(const BuildInfo &) const; + + virtual Task *run(const Target &) const; +}; + +#endif diff --git a/source/msvccompiler.cpp b/source/msvccompiler.cpp new file mode 100644 index 0000000..12668a6 --- /dev/null +++ b/source/msvccompiler.cpp @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include +#include "builder.h" +#include "component.h" +#include "csourcefile.h" +#include "externaltask.h" +#include "microsofttools.h" +#include "msvccompiler.h" +#include "objectfile.h" +#include "sourcepackage.h" + +using namespace std; +using namespace Msp; + +MsvcCompiler::MsvcCompiler(Builder &b, const Architecture &a, const string &t, const MicrosoftTools &m): + Tool(b, a, t), + ms_tools(m) +{ + if(tag=="CC") + { + input_suffixes.push_back(".c"); + aux_suffixes.push_back(".h"); + } + else if(tag=="CXX") + { + input_suffixes.push_back(".cpp"); + input_suffixes.push_back(".cc"); + aux_suffixes.push_back(".hpp"); + } + else + throw invalid_argument("MsvcCompiler::MsvcCompiler"); + + set_command((ms_tools.get_vc_bin_dir()/"cl.exe").str(), false); +} + +Target *MsvcCompiler::create_source(const Component &comp, const FS::Path &path) const +{ + return new CSourceFile(builder, comp, path); +} + +Target *MsvcCompiler::create_source(const FS::Path &path) const +{ + return new CSourceFile(builder, path); +} + +Target *MsvcCompiler::create_target(const list &sources, const string &) +{ + if(sources.size()!=1) + throw invalid_argument("MsvcCompiler::create_target"); + SourceFile &source = dynamic_cast(*sources.front()); + ObjectFile *obj = new ObjectFile(builder, *source.get_component(), source); + obj->set_tool(*this); + return obj; +} + +string MsvcCompiler::create_build_signature(const BuildInfo &binfo) const +{ + string result = FS::basename(executable->get_path()); + result += ','; + if(binfo.debug) + result += 'g'; + if(binfo.optimize) + { + result += 'O'; + result += (binfo.optimize<0 ? '1' : binfo.optimize==1 ? 'x' : '2'); + } + if(binfo.libmode<=BuildInfo::STATIC) + result += 't'; + return result; +} + +void MsvcCompiler::do_prepare() +{ + const FS::Path &vc_base_dir = ms_tools.get_vc_base_dir(); + system_path.push_back(vc_base_dir/"include"); + + const FS::Path &win_sdk_dir = ms_tools.get_windows_sdk_dir(); + const string &win_sdk_ver = ms_tools.get_windows_sdk_version(); + system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"ucrt"); + system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"shared"); + system_path.push_back(win_sdk_dir/"include"/win_sdk_ver/"um"); + + string path; + for(SearchPath::const_iterator i=system_path.begin(); i!=system_path.end(); ++i) + { + append(path, ";", i->str()); + builder.get_logger().log("tools", format("Got %s system path: %s", tag, *i)); + } + + setenv("INCLUDE", path); +} + +Task *MsvcCompiler::run(const Target &target) const +{ + const ObjectFile &object = dynamic_cast(target); + + ExternalTask::Arguments argv; + argv.push_back(executable->get_path().str()); + argv.push_back("/nologo"); + argv.push_back("/c"); + + BuildInfo binfo; + target.collect_build_info(binfo); + + if(binfo.standards.count(tag)) + { + string std = get_item(binfo.standards, tag); + if(std!="c++11" && std!="c99") + argv.push_back("/std:"+std); + } + + if(binfo.warning_level>=1) + { + argv.push_back(format("/W%d", binfo.warning_level)); + if(binfo.fatal_warnings) + argv.push_back("/WX"); + if(binfo.warning_level>=3) + argv.push_back("/permissive-"); + + argv.push_back("/wd4068"); // Unknown pragma + if(binfo.warning_level<4) + { + argv.push_back("/wd4244"); // Narrowing conversion on arg or return + argv.push_back("/wd4267"); // Narrowing conversion + } + } + else + argv.push_back("/w"); + + for(BuildInfo::PathList::const_iterator i=binfo.local_incpath.begin(); i!=binfo.local_incpath.end(); ++i) + { + argv.push_back("/I"); + argv.push_back(i->str()); + } + for(BuildInfo::PathList::const_iterator i=binfo.incpath.begin(); i!=binfo.incpath.end(); ++i) + { + argv.push_back("/I"); + argv.push_back(i->str()); + } + + for(BuildInfo::DefineMap::const_iterator i=binfo.defines.begin(); i!=binfo.defines.end(); ++i) + { + argv.push_back("/D"); + if(i->second.empty()) + argv.push_back(i->first); + else + argv.push_back(format("%s=%s", i->first, i->second)); + } + + if(binfo.debug) + argv.push_back("/Z7"); + if(binfo.optimize) + { + if(binfo.optimize<0) + argv.push_back("/O1"); + else if(binfo.optimize==1) + argv.push_back("/Ox"); + else + argv.push_back("/O2"); + } + + if(binfo.libmode<=BuildInfo::STATIC) + argv.push_back(binfo.debug ? "/MTd" : "/MT"); + else + argv.push_back(binfo.debug ? "/MDd" : "/MD"); + + argv.push_back("/EHsc"); + + FS::Path obj_path = object.get_path(); + FS::Path src_path = object.get_source().get_path(); + FS::Path work_dir = object.get_component()->get_package().get_source_directory(); + + argv.push_back("/Fo"+relative(obj_path, work_dir).str()); + argv.push_back(relative(src_path, work_dir).str()); + + return new ExternalTask(argv, work_dir); +} diff --git a/source/msvccompiler.h b/source/msvccompiler.h new file mode 100644 index 0000000..2a6f91f --- /dev/null +++ b/source/msvccompiler.h @@ -0,0 +1,28 @@ +#ifndef MSVCCOMPILER_H_ +#define MSVCCOMPILER_H_ + +#include "tool.h" + +class MicrosoftTools; + +class MsvcCompiler: public Tool +{ +private: + const MicrosoftTools &ms_tools; + +public: + MsvcCompiler(Builder &, const Architecture &, const std::string &, const MicrosoftTools &); + + virtual Target *create_source(const Component &, const Msp::FS::Path &) const; + virtual Target *create_source(const Msp::FS::Path &) const; + virtual Target *create_target(const std::list &, const std::string &); + virtual std::string create_build_signature(const BuildInfo &) const; + +protected: + virtual void do_prepare(); + +public: + virtual Task *run(const Target &) const; +}; + +#endif diff --git a/source/msvclinker.cpp b/source/msvclinker.cpp new file mode 100644 index 0000000..46d89f7 --- /dev/null +++ b/source/msvclinker.cpp @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include "builder.h" +#include "component.h" +#include "executable.h" +#include "externaltask.h" +#include "importlibrary.h" +#include "microsofttools.h" +#include "msvclinker.h" +#include "objectfile.h" +#include "sharedlibrary.h" +#include "sourcepackage.h" +#include "staticlibrary.h" + +using namespace std; +using namespace Msp; + +MsvcLinker::MsvcLinker(Builder &b, const Architecture &a, const MicrosoftTools &m): + Tool(b, a, "LINK"), + ms_tools(m) +{ + input_suffixes.push_back(".o"); + input_suffixes.push_back(".a"); + + processing_unit = COMPONENT; + + set_command((ms_tools.get_vc_bin_dir()/"link.exe").str(), false); +} + +Target *MsvcLinker::create_target(const list &sources, const string &arg) +{ + if(sources.empty()) + throw invalid_argument("MsvcLinker::create_target"); + + list objs; + for(list::const_iterator i=sources.begin(); i!=sources.end(); ++i) + { + if(ObjectFile *obj = dynamic_cast(*i)) + objs.push_back(obj); + else + throw invalid_argument("MsvcLinker::create_target"); + } + + const Component &comp = *objs.front()->get_component(); + Binary *bin = 0; + if(arg=="shared") + bin = new SharedLibrary(builder, comp, objs); + else + bin = new Executable(builder, comp, objs); + bin->set_tool(*this); + return bin; +} + +string MsvcLinker::create_build_signature(const BuildInfo &binfo) const +{ + string result = FS::basename(executable->get_path()); + result += ','; + if(binfo.strip) + result += 's'; + if(!binfo.libs.empty()) + { + result += ",l"; + result += join(binfo.libs.begin(), binfo.libs.end(), ",l"); + } + return result; +} + +void MsvcLinker::do_prepare() +{ + string arch_dir = (architecture->get_bits()==64 ? "x64" : "x86"); + + const FS::Path &vc_base_dir = ms_tools.get_vc_base_dir(); + system_path.push_back(vc_base_dir/"lib"/arch_dir); + + const FS::Path &win_sdk_dir = ms_tools.get_windows_sdk_dir(); + const string &win_sdk_ver = ms_tools.get_windows_sdk_version(); + system_path.push_back(win_sdk_dir/"lib"/win_sdk_ver/"ucrt"/arch_dir); + system_path.push_back(win_sdk_dir/"lib"/win_sdk_ver/"um"/arch_dir); + + string path; + for(SearchPath::const_iterator i=system_path.begin(); i!=system_path.end(); ++i) + { + append(path, ";", i->str()); + builder.get_logger().log("tools", format("Got %s system path: %s", tag, *i)); + } + + setenv("LIB", path); +} + +Task *MsvcLinker::run(const Target &target) const +{ + const Binary &bin = dynamic_cast(target); + + vector argv; + argv.push_back(executable->get_path().str()); + argv.push_back("/NOLOGO"); + + FS::Path work_dir = bin.get_component()->get_package().get_source_directory(); + + if(dynamic_cast(&bin)) + argv.push_back("/DLL"); + + BuildInfo binfo; + target.collect_build_info(binfo); + + /*for(BuildInfo::PathList::const_iterator i=binfo.libpath.begin(); i!=binfo.libpath.end(); ++i) + argv.push_back("/LIBPATH:"+i->str());*/ + if(binfo.strip) + argv.push_back("/INCREMENTAL:NO"); + else + argv.push_back("/DEBUG:FULL"); + + argv.push_back("/OUT:"+relative(bin.get_path(), work_dir).str()); + + const Target::Dependencies &depends = target.get_dependencies(); + for(Target::Dependencies::const_iterator i=depends.begin(); i!=depends.end(); ++i) + { + FileTarget *file = dynamic_cast(*i); + Target *tgt = (*i)->get_real_target(); + + if(ObjectFile *obj = dynamic_cast(tgt)) + argv.push_back(relative(obj->get_path(), work_dir).str()); + else if(StaticLibrary *stlib = dynamic_cast(tgt)) + argv.push_back((file?file:stlib)->get_path().str()); + else if(ImportLibrary *imp = dynamic_cast(tgt)) + argv.push_back((file?file:imp)->get_path().str()); + } + + argv.push_back("/SUBSYSTEM:CONSOLE"); + + return new ExternalTask(argv, work_dir); +} diff --git a/source/msvclinker.h b/source/msvclinker.h new file mode 100644 index 0000000..50f8a7b --- /dev/null +++ b/source/msvclinker.h @@ -0,0 +1,26 @@ +#ifndef MSVCLINKER_H_ +#define MSVCLINKER_H_ + +#include "tool.h" + +class MicrosoftTools; + +class MsvcLinker: public Tool +{ +private: + const MicrosoftTools &ms_tools; + +public: + MsvcLinker(Builder &, const Architecture &, const MicrosoftTools &); + + virtual Target *create_target(const std::list &, const std::string &); + virtual std::string create_build_signature(const BuildInfo &) const; + +protected: + virtual void do_prepare(); + +public: + virtual Task *run(const Target &) const; +}; + +#endif diff --git a/source/sysutils.cpp b/source/sysutils.cpp index 8fa3d48..95867b7 100644 --- a/source/sysutils.cpp +++ b/source/sysutils.cpp @@ -1,9 +1,16 @@ +#define _WIN32_WINNT _WIN32_WINNT_VISTA #define WIN32_LEAN_AND_MEAN +#define INITGUID #ifdef _WIN32 #include +#include +#include #else #include #endif +#include +#include +#include #include #include #include "sysutils.h" @@ -33,3 +40,74 @@ string get_system_type() return string(); } + +FS::Path get_program_files_x86_dir() +{ +#ifdef _WIN32 + wchar_t *program_files_x86_ptr = 0; + HRESULT err = SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, NULL, &program_files_x86_ptr); + if(err!=S_OK) + throw runtime_error("Can't get Program Files path"); + + unsigned len = wcslen(program_files_x86_ptr); + FS::Path program_files_x86 = StringCodec::transcode( + string(reinterpret_cast(program_files_x86_ptr), len*sizeof(wchar_t))); + + CoTaskMemFree(program_files_x86_ptr); + + return program_files_x86; +#else + return "/mnt/c/Program Files (x86)"; +#endif +} + +template<> +string get_registry_value(const string &path) +{ +#ifdef _WIN32 + string::size_type first_sep = path.find('\\'); + string::size_type last_sep = path.rfind('\\'); + string root = path.substr(0, first_sep); + string key_path = path.substr(first_sep+1, last_sep-first_sep-1); + string value_name = path.substr(last_sep+1); + + HKEY root_handle; + if(root=="HKCR") + root_handle = HKEY_CLASSES_ROOT; + else if(root=="HKCC") + root_handle = HKEY_CURRENT_CONFIG; + else if(root=="HKCU") + root_handle = HKEY_CURRENT_USER; + else if(root=="HKLM") + root_handle = HKEY_LOCAL_MACHINE; + else if(root=="HKU") + root_handle = HKEY_USERS; + else + throw invalid_argument("get_registry_value"); + + HKEY key; + LSTATUS err = RegOpenKeyEx(root_handle, key_path.c_str(), 0, KEY_READ, &key); + if(err!=ERROR_SUCCESS) + throw Msp::system_error("RegOpenKey", err); + + DWORD value_len; + err = RegGetValue(key, 0, value_name.c_str(), RRF_RT_REG_SZ, 0, 0, &value_len); + if(err!=ERROR_SUCCESS) + throw Msp::system_error("RegGetValue", err); + + char *buffer = new char[value_len]; + err = RegGetValue(key, 0, value_name.c_str(), RRF_RT_REG_SZ, 0, buffer, &value_len); + if(err!=ERROR_SUCCESS) + { + delete[] buffer; + throw Msp::system_error("RegGetValue", err); + } + + string result(buffer); + delete[] buffer; + return result; +#else + (void)path; + return string(); +#endif +} diff --git a/source/sysutils.h b/source/sysutils.h index c422b7f..7300869 100644 --- a/source/sysutils.h +++ b/source/sysutils.h @@ -2,7 +2,12 @@ #define SYSUTILS_H_ #include +#include std::string get_system_type(); +Msp::FS::Path get_program_files_x86_dir(); + +template +T get_registry_value(const std::string &); #endif -- 2.43.0