diff --git a/jlib/base/config.h b/jlib/base/config.h index 98f4398c9913b0a36c22577350b32b69c0568aa5..341e10fe3514f1153f57277567130e1a25445c9a 100644 --- a/jlib/base/config.h +++ b/jlib/base/config.h @@ -7,3 +7,7 @@ #else #error "jlib only support linux and windows" #endif + +#ifdef JLIB_WINDOWS +#define _CRT_SECURE_NO_WARNINGS +#endif diff --git a/jlib/base/logging.h b/jlib/base/logging.h index 9af1146fe2b37202af21b91035d159eed5d623e3..d3d6d5b3d5b354ea6df583ecf4eb76b803a112ab 100644 --- a/jlib/base/logging.h +++ b/jlib/base/logging.h @@ -1,7 +1,10 @@ #pragma once +#include "config.h" #include "logstream.h" #include "timestamp.h" +#include "currentthread.h" +#include <stdlib.h> // getenv namespace jlib { @@ -11,59 +14,169 @@ class TimeZone; class Logger { public: - enum class LogLevel { - LOGLEVEL_TRACE, - LOGLEVEL_DEBUG, - LOGLEVEL_INFO, - LOGLEVEL_WARN, - LOGLEVEL_ERROR, - LOGLEVEL_FATAL, - LOGLEVEL_COUNT, - }; - - // compile time calculation of basename of source file - struct SourceFile - { - template <int N> - SourceFile(const char (&arr)[N]) : data_(arr) , size_(N - 1) { - const char* slash = strrchr(data_, '/'); - if (slash) { data_ = slash + 1; } - size_ -= static_cast<int>(data_ - arr); - } - - explicit SourceFile(const char* filename) : data_(filename) { - const char* slash = strrchr(filename, '/'); - if (slash) { data_ = slash + 1; } - size_ = static_cast<int>(strlen(data_)); - } - - const char* data_; - int size_; - }; - - Logger(SourceFile file, int line); + enum LogLevel { + LOGLEVEL_TRACE, + LOGLEVEL_DEBUG, + LOGLEVEL_INFO, + LOGLEVEL_WARN, + LOGLEVEL_ERROR, + LOGLEVEL_FATAL, + LOGLEVEL_COUNT, + }; + + // compile time calculation of basename of source file + struct SourceFile + { + template <int N> + SourceFile(const char(&arr)[N]) : data_(arr), size_(N - 1) { + const char* slash = strrchr(data_, '/'); + if (slash) { data_ = slash + 1; } + size_ -= static_cast<int>(data_ - arr); + } + + explicit SourceFile(const char* filename) : data_(filename) { + const char* slash = strrchr(filename, '/'); + if (slash) { data_ = slash + 1; } + size_ = static_cast<int>(strlen(data_)); + } + + const char* data_; + int size_; + }; + + Logger(SourceFile file, int line); Logger(SourceFile file, int line, LogLevel level); - Logger(SourceFile file, int line, LogLevel level, const char *func); + Logger(SourceFile file, int line, LogLevel level, const char* func); Logger(SourceFile file, int line, bool toAbort); ~Logger(); - LogStream &stream() { return impl_.stream_; } + LogStream& stream() { return impl_.stream_; } - static LogLevel logLevel(); + static LogLevel logLevel() { return logLevel_; } static void setLogLevel(LogLevel level); - typedef void (*OutputFunc)(const char *msg, int len); + typedef void (*OutputFunc)(const char* msg, int len); typedef void (*FlushFunc)(); static void setOutput(OutputFunc); static void setFlush(FlushFunc); - static void setTimeZone(const TimeZone &tz); + static void setTimeZone(const TimeZone& tz); private: - class Impl - { - public: - }; + class Impl + { + public: + typedef Logger::LogLevel LogLevel; + + Impl(LogLevel level, int old_errno, const SourceFile& file, int line); + void formatTime(); + void finish(); + + Timestamp time_; + LogStream stream_; + LogLevel level_; + int line_; + SourceFile basename_; + }; + + static LogLevel logLevel_; + + Impl impl_; +}; + + +static void defaultOutput(const char* msg, int len) { fwrite(msg, 1, len, stdout); } +static void defaultFlush() { fflush(stdout); } + +static Logger::OutputFunc g_output = defaultOutput; +static Logger::FlushFunc g_flush = defaultFlush; + + +namespace detail +{ + +static const char* LogLevelName[Logger::LogLevel::LOGLEVEL_COUNT] = +{ + "TRACE ", + "DEBUG ", + "INFO ", + "WARN ", + "ERROR ", + "FATAL ", +}; + +static Logger::LogLevel initLogLevel() { + if (::getenv("JLIB_LOGLEVEL_TRACE")) { + return Logger::LogLevel::LOGLEVEL_TRACE; + } else if (::getenv("JLIB_LOGLEVEL_DEBUG")) { + return Logger::LogLevel::LOGLEVEL_DEBUG; + } else { + return Logger::LogLevel::LOGLEVEL_INFO; + } } +struct T +{ + explicit T(const char* str, unsigned int len) + : str_(str) + , len_(len) + { + assert(strlen(str) == len); + } + + const char* str_; + const unsigned int len_; +}; + +thread_local char t_errnobuf[512] = { 0 }; +thread_local char t_time[64] = { 0 }; +thread_local time_t t_lastSecond = 0; + +} // detail + + +Logger::LogLevel Logger::logLevel_ = detail::initLogLevel(); + +inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& f) { + s.append(f.data_, f.size_); return s; +} + +inline LogStream& operator<<(LogStream& s, detail::T t) { + s.append(t.str_, t.len_); return s; +} + +static const char* strerror_t(int savedErrno) { + strerror_s(detail::t_errnobuf, savedErrno); + return detail::t_errnobuf; +} + + +Logger::Impl::Impl(LogLevel level, int old_errno, const SourceFile& file, int line) + : time_(Timestamp::now()) + , stream_() + , level_(level) + , line_(line) + , basename_(file) +{ + formatTime(); + CurrentThread::tid(); + stream_ << detail::T(CurrentThread::tidString(), CurrentThread::tidStringLength()); + stream_ << detail::T(detail::LogLevelName[level], 6); + if (old_errno != 0) { + stream_ << strerror_t(old_errno) << " (errorno=" << old_errno << ") "; + } +} + +void Logger::Impl::formatTime() +{ + int64_t microSecsSinceEpoch = time_.microSecondsSinceEpoch(); + time_t seconds = static_cast<time_t>(microSecsSinceEpoch / Timestamp::MICRO_SECONDS_PER_SECOND); + int microsecs = static_cast<int>(microSecsSinceEpoch % Timestamp::MICRO_SECONDS_PER_SECOND); + if (seconds != detail::t_lastSecond) { + detail::t_lastSecond = seconds; + + } +} + + } // namespace jlib diff --git a/jlib/base/timezone.h b/jlib/base/timezone.h new file mode 100644 index 0000000000000000000000000000000000000000..610d659266b0bcf1b60d81455a1aa39e023a929b --- /dev/null +++ b/jlib/base/timezone.h @@ -0,0 +1,120 @@ +#pragma once + +#include "config.h" +#include "copyable.h" +#include <time.h> +#include <memory> +#include <vector> +#include <string> + + +namespace jlib +{ + +namespace detail +{ + +struct Transition +{ + time_t gmtime_; + time_t localtime_; + int localTimeIdx_; + + Transition(time_t gmt, time_t localt, int localIdx) + : gmtime_(gmt) + , localtime_(localt) + , localTimeIdx_(localIdx) + {} +}; + +struct Compare +{ + bool compareGmt_ = true; + + Compare(bool gmt) + : compareGmt_(gmt) + {} + + bool operator()(const Transition& lhs, const Transition& rhs) const { + if (compareGmt_) { + return lhs.gmtime_ < rhs.gmtime_; + } else { + return lhs.localtime_ < rhs.localtime_; + } + } + + bool equal(const Transition& lhs, const Transition& rhs) const { + if (compareGmt_) { + return lhs.gmtime_ == rhs.gmtime_; + } else { + return lhs.localtime_ == rhs.localtime_; + } + } +}; + +struct LocalTime +{ + time_t gmtOffset; + bool isDst; + int abbrIdx; + + LocalTime(time_t offset, bool dst, int abbr) + : gmtOffset(offset) + , isDst(dst) + , abbrIdx(abbr) + {} +}; + +} // namespace detail + + +static constexpr int SECONDS_PER_DAY = 24 * 60 * 60; + + +class Timezone : public copyable +{ +public: + explicit Timezone(const char* zonename); + Timezone(int bias, const char* tzname); + Timezone() = default; // invalid timezone + + bool valid() const{ + return static_cast<bool>(data_); + } + + struct tm toLocalTime(time_t secondsSinceEpoch) const { + + } + + time_t fromLocalTime(const struct tm& tm_time) const { + + } + + static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); + static time_t fromUtcTime(const struct tm& tm_time); + + /** + * @param year [1900, 2500] + * @param month [1, 12] + * @param day [1, 31] + * @param hour [0, 23] + * @param minute [0, 59] + * @param seconds [0, 59] + */ + static time_t fromUtcTime(int year, int month, int day, + int hour, int minute, int seconds) { + + } + + struct Data { + std::vector<detail::Transition> transitions; + std::vector<detail::LocalTime> localtimes; + std::vector<std::string> names; + std::string abbreviation; + }; + +private: + std::shared_ptr<Data> data_ = {}; +}; + +} // namespace jlib diff --git a/jlib/win32/registry.h b/jlib/win32/registry.h new file mode 100644 index 0000000000000000000000000000000000000000..6f16a69373eaaff9e51f41adbdd8220bd87594f3 --- /dev/null +++ b/jlib/win32/registry.h @@ -0,0 +1,933 @@ +#pragma once + + +// mainly inspired by Giovanni Dicanio +// with some simplifications and changes +// see his original license below: + + +//////////////////////////////////////////////////////////////////////////////// +// +// *** Modern C++ Wrappers Around Windows Registry C API *** +// +// Copyright (C) by Giovanni Dicanio +// +// First version: 2017, January 22nd +// Last update: 2019, March 26th +// +// E-mail: <giovanni.dicanio AT gmail.com> +// +// Registry key handles are safely and conveniently wrapped +// in the RegKey resource manager C++ class. +// +// Errors are signaled throwing exceptions of class RegException. +// +// Unicode UTF-16 strings are represented using the std::wstring class; +// ATL's CString is not used, to avoid dependencies from ATL or MFC. +// +// This is a header-only self-contained reusable module. +// +// Compiler: Visual Studio 2015 +// Code compiles clean at /W4 on both 32-bit and 64-bit builds. +// +// =========================================================================== +// +// The MIT License(MIT) +// +// Copyright(c) 2017 Giovanni Dicanio +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +//////////////////////////////////////////////////////////////////////////////// + + + +#include <Windows.h> +#include <strsafe.h> +#include <string> +#include <memory> +#include <vector> +#include <stdexcept> +#include <utility> +#include <assert.h> +#include "../base/noncopyable.h" + + +namespace jlib +{ + +namespace win32 +{ + +namespace reg +{ + +class RegException : public std::runtime_error +{ +public: + explicit RegException(const std::string& msg, DWORD errorCode, const std::string& desc) + : std::runtime_error(msg) + , lastError_(errorCode) + , description_(desc) + {} + + DWORD errorCode() const { return lastError_; } + std::string description() const { return description_; } + +private: + DWORD lastError_ = ERROR_SUCCESS; + std::string description_ = {}; +}; + + +inline void throwRegException(const std::string& msg, DWORD errorCode) +{ + LPVOID lpMsgBuf; + + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)& lpMsgBuf, + 0, NULL); + + std::string desc(reinterpret_cast<const char*>(lpMsgBuf)); + LocalFree(lpMsgBuf); + + throw RegException(msg, errorCode, desc); +} + + +#define THROW_REG_EXCEPTION(msg, err) \ +do { \ + std::string errMsg = msg; errMsg += " SourceFile: "; errMsg += __FILE__; \ + errMsg += " Line: "; errMsg += std::to_string(__LINE__); \ + throwRegException(errMsg, err); \ +} while(0); + + +class RegKey : public noncopyable +{ +public: + RegKey() = default; + explicit RegKey(HKEY hKey) noexcept : hKey_(hKey) {} + ~RegKey() noexcept { close(); } + + RegKey& operator=(RegKey&& rhs) noexcept { + // prevent self-move-assign + if ((this != &rhs) && (hKey_ != rhs.hKey_)) { + close(); hKey_ = rhs.hKey_; rhs.hKey_ = nullptr; + } + return *this; + } + + // properties + + HKEY hKey() const noexcept { return hKey_; } + bool valid() const noexcept { return hKey_ != nullptr; } + explicit operator bool() const noexcept { return valid(); } + bool isPredefined() const noexcept; + + + // operations + + void close() noexcept; + void open(HKEY hKeyParent, const std::wstring& subKey, REGSAM desiredAccess = KEY_READ | KEY_WRITE); + void create(HKEY hKeyParent, const std::wstring& subKey, REGSAM desiredAccess = KEY_READ | KEY_WRITE); + void create(HKEY hKeyParent, const std::wstring& subKey, REGSAM desiredAccess, DWORD options, SECURITY_ATTRIBUTES* sa, DWORD* disposition); + + + // value getters + + DWORD getDwordValue(const std::wstring& valueName); + ULONGLONG getQwordValue(const std::wstring& valueName); + std::wstring getStringValue(const std::wstring& valueName); + + enum class ExpandStringOption { + DonotExpand, + Expand, + }; + + std::wstring getExpandStringValue(const std::wstring& valueName, ExpandStringOption option = ExpandStringOption::DonotExpand); + std::vector<std::wstring> getMultiStringValue(const std::wstring& valueName); + std::vector<BYTE> getBinaryValue(const std::wstring& valueName); + + + // value setters + + void setDwordValue(const std::wstring& valueName, DWORD data); + void setQwordValue(const std::wstring& valueName, const ULONGLONG& data); + void setStringValue(const std::wstring& valueName, const std::wstring& data); + void setExpandStringValue(const std::wstring& valueName, const std::wstring& data); + void setMultiStringValue(const std::wstring& valueName, const std::vector<std::wstring>& data); + void setBinaryValue(const std::wstring& valueName, const std::vector<BYTE>& data); + void setBinaryValue(const std::wstring& valueName, const void* data, DWORD dataSize); + + + // query + + DWORD queryValueType(const std::wstring& valueName); + std::vector<std::wstring> querySubKeys(); + // value-name value-type + std::vector<std::pair<std::wstring, DWORD>> queryValues(); + + + // delete + + void deleteValue(const std::wstring& valueName); + void deleteKey(const std::wstring& subKey, REGSAM desiredAccess); + void deleteTree(const std::wstring& subKey); + + + static std::wstring regTypeToString(DWORD regType); + +private: + HKEY hKey_ = nullptr; +}; + + +// implementation + +inline bool RegKey::isPredefined() const noexcept +{ + // Predefined keys + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724836(v=vs.85).aspx + + return ((hKey_ == HKEY_CURRENT_USER) + || (hKey_ == HKEY_LOCAL_MACHINE) + || (hKey_ == HKEY_CLASSES_ROOT) + || (hKey_ == HKEY_CURRENT_CONFIG) + || (hKey_ == HKEY_CURRENT_USER_LOCAL_SETTINGS) + || (hKey_ == HKEY_PERFORMANCE_DATA) + || (hKey_ == HKEY_PERFORMANCE_NLSTEXT) + || (hKey_ == HKEY_PERFORMANCE_TEXT) + || (hKey_ == HKEY_USERS)); +} + +inline void RegKey::close() noexcept +{ + if (valid()) { + if (!isPredefined()) { + ::RegCloseKey(hKey_); + } + + hKey_ = nullptr; + } +} + +inline void RegKey::open(HKEY hKeyParent, const std::wstring& subKey, REGSAM desiredAccess) +{ + HKEY hKey{ nullptr }; + DWORD retCode = ::RegOpenKeyExW( + hKeyParent, + subKey.c_str(), + REG_NONE, // default options + desiredAccess, + &hKey + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("RegOpenKeyEx failed.", retCode); + } + + close(); + hKey_ = hKey; +} + +inline void RegKey::create(const HKEY hKeyParent, const std::wstring& subKey, const REGSAM desiredAccess) +{ + constexpr DWORD kDefaultOptions = REG_OPTION_NON_VOLATILE; + + create(hKeyParent, subKey, desiredAccess, kDefaultOptions, + nullptr, // no security attributes, + nullptr // no disposition + ); +} + +inline void RegKey::create(HKEY hKeyParent, const std::wstring& subKey, REGSAM desiredAccess, DWORD options, + SECURITY_ATTRIBUTES* securityAttributes, DWORD* disposition) +{ + HKEY hKey{ nullptr }; + DWORD retCode = ::RegCreateKeyExW( + hKeyParent, + subKey.c_str(), + 0, // reserved + REG_NONE, // user-defined class type parameter not supported + options, + desiredAccess, + securityAttributes, + &hKey, + disposition + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("RegCreateKeyEx failed.", retCode); + } + + close(); + hKey_ = hKey; +} + +inline DWORD RegKey::getDwordValue(const std::wstring& valueName) +{ + assert(valid()); + + DWORD data{}; // to be read from the registry + DWORD dataSize = sizeof(data); // size of data, in bytes + + const DWORD flags = RRF_RT_REG_DWORD; + DWORD retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // type not required + &data, + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get DWORD value: RegGetValue failed.", retCode); + } + + return data; +} + +inline ULONGLONG RegKey::getQwordValue(const std::wstring& valueName) +{ + assert(valid()); + + ULONGLONG data{}; // to be read from the registry + DWORD dataSize = sizeof(data); // size of data, in bytes + + const DWORD flags = RRF_RT_REG_QWORD; + DWORD retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // type not required + &data, + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get QWORD value: RegGetValue failed.", retCode); + } + + return data; +} + +inline std::wstring RegKey::getStringValue(const std::wstring& valueName) +{ + assert(valid()); + + // Get the size of the result string + DWORD dataSize = 0; // size of data, in bytes + const DWORD flags = RRF_RT_REG_SZ; + DWORD retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // type not required + nullptr, // output buffer not needed now + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get size of string value: RegGetValue failed.", retCode); + } + + // Allocate a string of proper size. + // Note that dataSize is in bytes and includes the terminating NUL; + // we have to convert the size from bytes to wchar_ts for wstring::resize. + std::wstring result; + result.resize(dataSize / sizeof(wchar_t)); + + // Call RegGetValue for the second time to read the string's content + retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // type not required + &result[0], // output buffer + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get string value: RegGetValue failed.", retCode); + } + + // Remove the NUL terminator scribbled by RegGetValue from the wstring + result.resize((dataSize / sizeof(wchar_t)) - 1); + + return result; +} + +inline std::wstring RegKey::getExpandStringValue(const std::wstring& valueName, ExpandStringOption expandOption) +{ + assert(valid()); + + DWORD flags = RRF_RT_REG_EXPAND_SZ; + + // Adjust the flag for RegGetValue considering the expand string option specified by the caller + if (expandOption == ExpandStringOption::DonotExpand) { + flags |= RRF_NOEXPAND; + } + + // Get the size of the result string + DWORD dataSize = 0; // size of data, in bytes + DWORD retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // type not required + nullptr, // output buffer not needed now + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get size of expand string value: RegGetValue failed.", retCode); + } + + // Allocate a string of proper size. + // Note that dataSize is in bytes and includes the terminating NUL. + // We must convert from bytes to wchar_ts for wstring::resize. + std::wstring result; + result.resize(dataSize / sizeof(wchar_t)); + + // Call RegGetValue for the second time to read the string's content + retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // type not required + &result[0], // output buffer + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get expand string value: RegGetValue failed.", retCode); + } + + // Remove the NUL terminator scribbled by RegGetValue from the wstring + result.resize((dataSize / sizeof(wchar_t)) - 1); + + return result; +} + +inline std::vector<std::wstring> RegKey::getMultiStringValue(const std::wstring& valueName) +{ + assert(valid()); + + // Request the size of the multi-string, in bytes + DWORD dataSize = 0; + const DWORD flags = RRF_RT_REG_MULTI_SZ; + DWORD retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // type not required + nullptr, // output buffer not needed now + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get size of multi-string value: RegGetValue failed.", retCode); + } + + // Allocate room for the result multi-string. + // Note that dataSize is in bytes, but our vector<wchar_t>::resize method requires size + // to be expressed in wchar_ts. + std::vector<wchar_t> data; + data.resize(dataSize / sizeof(wchar_t)); + + // Read the multi-string from the registry into the vector object + retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // no type required + &data[0], // output buffer + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get multi-string value: RegGetValue failed.", retCode); + } + + // Resize vector to the actual size returned by GetRegValue. + // Note that the vector is a vector of wchar_ts, instead the size returned by GetRegValue + // is in bytes, so we have to scale from bytes to wchar_t count. + data.resize(dataSize / sizeof(wchar_t)); + + // Parse the double-NUL-terminated string into a vector<wstring>, + // which will be returned to the caller + std::vector<std::wstring> result; + const wchar_t* currStringPtr = &data[0]; + while (*currStringPtr != L'\0') { + // Current string is NUL-terminated, so get its length calling wcslen + const size_t currStringLength = wcslen(currStringPtr); + + // Add current string to the result vector + result.push_back(std::wstring{ currStringPtr, currStringLength }); + + // Move to the next string + currStringPtr += currStringLength + 1; + } + + return result; +} + +inline std::vector<BYTE> RegKey::getBinaryValue(const std::wstring& valueName) +{ + assert(valid()); + + // Get the size of the binary data + DWORD dataSize = 0; // size of data, in bytes + const DWORD flags = RRF_RT_REG_BINARY; + DWORD retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // type not required + nullptr, // output buffer not needed now + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get size of binary data: RegGetValue failed.", retCode); + } + + // Allocate a buffer of proper size to store the binary data + std::vector<BYTE> data(dataSize); + + // Call RegGetValue for the second time to read the data content + retCode = ::RegGetValueW( + hKey_, + nullptr, // no subkey + valueName.c_str(), + flags, + nullptr, // type not required + &data[0], // output buffer + &dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get binary data: RegGetValue failed.", retCode); + } + + return data; +} + +inline void RegKey::setDwordValue(const std::wstring& valueName, DWORD data) +{ + assert(valid()); + + DWORD retCode = ::RegSetValueExW( + hKey_, + valueName.c_str(), + 0, // reserved + REG_DWORD, + reinterpret_cast<const BYTE*>(&data), + sizeof(data) + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot write DWORD value: RegSetValueEx failed.", retCode); + } +} + +inline void RegKey::setQwordValue(const std::wstring& valueName, const ULONGLONG& data) +{ + assert(valid()); + + DWORD retCode = ::RegSetValueExW( + hKey_, + valueName.c_str(), + 0, // reserved + REG_QWORD, + reinterpret_cast<const BYTE*>(&data), + sizeof(data) + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot write QWORD value: RegSetValueEx failed.", retCode); + } +} + +inline void RegKey::setStringValue(const std::wstring& valueName, const std::wstring& data) +{ + assert(valid()); + + // String size including the terminating NUL, in bytes + const DWORD dataSize = static_cast<DWORD>((data.length() + 1) * sizeof(wchar_t)); + + DWORD retCode = ::RegSetValueExW( + hKey_, + valueName.c_str(), + 0, // reserved + REG_SZ, + reinterpret_cast<const BYTE*>(data.c_str()), + dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot write string value: RegSetValueEx failed.", retCode); + } +} + +inline void RegKey::setExpandStringValue(const std::wstring& valueName, const std::wstring& data) +{ + assert(valid()); + + // String size including the terminating NUL, in bytes + const DWORD dataSize = static_cast<DWORD>((data.length() + 1) * sizeof(wchar_t)); + + DWORD retCode = ::RegSetValueExW( + hKey_, + valueName.c_str(), + 0, // reserved + REG_EXPAND_SZ, + reinterpret_cast<const BYTE*>(data.c_str()), + dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot write expand string value: RegSetValueEx failed.", retCode); + } +} + +inline void RegKey::setMultiStringValue(const std::wstring& valueName, const std::vector<std::wstring>& data) +{ + assert(valid()); + + static auto buildMultiString = [](const std::vector<std::wstring>& data) -> std::vector<wchar_t> { + // Special case of the empty multi-string + if (data.empty()) { + // Build a vector containing just two NULs + return std::vector<wchar_t>(2, L'\0'); + } + + // Get the total length in wchar_ts of the multi-string + size_t totalLen = 0; + for (const auto& s : data) { + // Add one to current string's length for the terminating NUL + totalLen += (s.length() + 1); + } + + // Add one for the last NUL terminator (making the whole structure double-NUL terminated) + totalLen++; + + // Allocate a buffer to store the multi-string + std::vector<wchar_t> multiString; + multiString.reserve(totalLen); + + // Copy the single strings into the multi-string + for (const auto& s : data) { + multiString.insert(multiString.end(), s.begin(), s.end()); + + // Don't forget to NUL-terminate the current string + multiString.push_back(L'\0'); + } + + // Add the last NUL-terminator + multiString.push_back(L'\0'); + + return multiString; + }; + + // First, we have to build a double-NUL-terminated multi-string from the input data + const std::vector<wchar_t> multiString = buildMultiString(data); + + // Total size, in bytes, of the whole multi-string structure + const DWORD dataSize = static_cast<DWORD>(multiString.size() * sizeof(wchar_t)); + + DWORD retCode = ::RegSetValueExW( + hKey_, + valueName.c_str(), + 0, // reserved + REG_MULTI_SZ, + reinterpret_cast<const BYTE*>(&multiString[0]), + dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot write multi-string value: RegSetValueEx failed.", retCode); + } +} + +inline void RegKey::setBinaryValue(const std::wstring& valueName, const std::vector<BYTE>& data) +{ + assert(valid()); + + // Total data size, in bytes + const DWORD dataSize = static_cast<DWORD>(data.size()); + + DWORD retCode = ::RegSetValueExW( + hKey_, + valueName.c_str(), + 0, // reserved + REG_BINARY, + &data[0], + dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot write binary data value: RegSetValueEx failed.", retCode); + } +} + +inline void RegKey::setBinaryValue(const std::wstring& valueName, const void* data, DWORD dataSize) +{ + assert(valid()); + + DWORD retCode = ::RegSetValueExW( + hKey_, + valueName.c_str(), + 0, // reserved + REG_BINARY, + static_cast<const BYTE*>(data), + dataSize + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot write binary data value: RegSetValueEx failed.", retCode); + } +} + +inline DWORD RegKey::queryValueType(const std::wstring& valueName) +{ + assert(valid()); + + DWORD typeId{}; // will be returned by RegQueryValueEx + + DWORD retCode = ::RegQueryValueExW( + hKey_, + valueName.c_str(), + nullptr, // reserved + &typeId, + nullptr, // not interested + nullptr // not interested + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot get the value type: RegQueryValueEx failed.", retCode); + } + + return typeId; +} + +inline std::vector<std::wstring> RegKey::querySubKeys() +{ + assert(valid()); + + // Get some useful enumeration info, like the total number of subkeys + // and the maximum length of the subkey names + DWORD subKeyCount{}; + DWORD maxSubKeyNameLen{}; + DWORD retCode = ::RegQueryInfoKeyW( + hKey_, + nullptr, // no user-defined class + nullptr, // no user-defined class size + nullptr, // reserved + &subKeyCount, + &maxSubKeyNameLen, + nullptr, // no subkey class length + nullptr, // no value count + nullptr, // no value name max length + nullptr, // no max value length + nullptr, // no security descriptor + nullptr // no last write time + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("RegQueryInfoKey failed while preparing for subkey enumeration.", retCode); + } + + // NOTE: According to the MSDN documentation, the size returned for subkey name max length + // does *not* include the terminating NUL, so let's add +1 to take it into account + // when I allocate the buffer for reading subkey names. + maxSubKeyNameLen++; + + // Preallocate a buffer for the subkey names + auto nameBuffer = std::make_unique<wchar_t[]>(maxSubKeyNameLen); + + // The result subkey names will be stored here + std::vector<std::wstring> subkeyNames; + + // Enumerate all the subkeys + for (DWORD index = 0; index < subKeyCount; index++) { + // Get the name of the current subkey + DWORD subKeyNameLen = maxSubKeyNameLen; + retCode = ::RegEnumKeyExW( + hKey_, + index, + nameBuffer.get(), + &subKeyNameLen, + nullptr, // reserved + nullptr, // no class + nullptr, // no class + nullptr // no last write time + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot enumerate subkeys: RegEnumKeyEx failed.", retCode); + } + + // On success, the ::RegEnumKeyEx API writes the length of the + // subkey name in the subKeyNameLen output parameter + // (not including the terminating NUL). + // So I can build a wstring based on that length. + subkeyNames.push_back(std::wstring{ nameBuffer.get(), subKeyNameLen }); + } + + return subkeyNames; +} + +std::vector<std::pair<std::wstring, DWORD>> RegKey::queryValues() +{ + assert(valid()); + + // Get useful enumeration info, like the total number of values + // and the maximum length of the value names + DWORD valueCount{}; + DWORD maxValueNameLen{}; + DWORD retCode = ::RegQueryInfoKeyW( + hKey_, + nullptr, // no user-defined class + nullptr, // no user-defined class size + nullptr, // reserved + nullptr, // no subkey count + nullptr, // no subkey max length + nullptr, // no subkey class length + &valueCount, + &maxValueNameLen, + nullptr, // no max value length + nullptr, // no security descriptor + nullptr // no last write time + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("RegQueryInfoKey failed while preparing for value enumeration.", retCode); + } + + // NOTE: According to the MSDN documentation, the size returned for value name max length + // does *not* include the terminating NUL, so let's add +1 to take it into account + // when I allocate the buffer for reading value names. + maxValueNameLen++; + + // Preallocate a buffer for the value names + auto nameBuffer = std::make_unique<wchar_t[]>(maxValueNameLen); + + // The value names and types will be stored here + std::vector<std::pair<std::wstring, DWORD>> valueInfo; + + // Enumerate all the values + for (DWORD index = 0; index < valueCount; index++) { + // Get the name and the type of the current value + DWORD valueNameLen = maxValueNameLen; + DWORD valueType{}; + retCode = ::RegEnumValueW( + hKey_, + index, + nameBuffer.get(), + &valueNameLen, + nullptr, // reserved + &valueType, + nullptr, // no data + nullptr // no data size + ); + + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("Cannot enumerate values: RegEnumValue failed.", retCode); + } + + // On success, the RegEnumValue API writes the length of the + // value name in the valueNameLen output parameter + // (not including the terminating NUL). + // So we can build a wstring based on that. + valueInfo.push_back( + std::make_pair(std::wstring{ nameBuffer.get(), valueNameLen }, valueType) + ); + } + + return valueInfo; +} + +inline void RegKey::deleteValue(const std::wstring& valueName) +{ + assert(valid()); + + DWORD retCode = ::RegDeleteValueW(hKey_, valueName.c_str()); + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("RegDeleteValue failed.", retCode); + } +} + +inline void RegKey::deleteKey(const std::wstring& subKey, const REGSAM desiredAccess) +{ + assert(valid()); + + DWORD retCode = ::RegDeleteKeyExW(hKey_, subKey.c_str(), desiredAccess, 0); + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("RegDeleteKeyEx failed.", retCode); + } +} + +inline void RegKey::deleteTree(const std::wstring& subKey) +{ + assert(valid()); + + DWORD retCode = ::RegDeleteTreeW(hKey_, subKey.c_str()); + if (retCode != ERROR_SUCCESS) { + THROW_REG_EXCEPTION("RegDeleteTree failed.", retCode); + } +} + +inline std::wstring RegKey::regTypeToString(const DWORD regType) +{ + switch (regType) + { + case REG_SZ: return L"REG_SZ"; + case REG_EXPAND_SZ: return L"REG_EXPAND_SZ"; + case REG_MULTI_SZ: return L"REG_MULTI_SZ"; + case REG_DWORD: return L"REG_DWORD"; + case REG_QWORD: return L"REG_QWORD"; + case REG_BINARY: return L"REG_BINARY"; + + default: return L"Unknown/unsupported registry type"; + } +} + +} // namespace reg + +} // namespace win32 + +} // namespace jlib diff --git a/test/test.sln b/test/test.sln index 190d8c6891c1eaacec659f6c1f897e0ec3398695..f98224eaf590ed2ded82ac2c1a2172841b3ff4b7 100644 --- a/test/test.sln +++ b/test/test.sln @@ -48,10 +48,44 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "base", "base", "{608A105E-4 ..\jlib\base\singleton.h = ..\jlib\base\singleton.h ..\jlib\base\stringpiece.h = ..\jlib\base\stringpiece.h ..\jlib\base\timestamp.h = ..\jlib\base\timestamp.h + ..\jlib\base\timezone.h = ..\jlib\base\timezone.h EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_singleton", "test_singleton\test_singleton.vcxproj", "{B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_logging", "test_logging\test_logging.vcxproj", "{3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_timezone", "test_timezone\test_timezone.vcxproj", "{8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "win32", "win32", "{B5D9E71E-2BFE-4D04-A66A-4CB0A103CD77}" + ProjectSection(SolutionItems) = preProject + ..\jlib\win32\clipboard.h = ..\jlib\win32\clipboard.h + ..\jlib\win32\DeviceUniqueIdentifier.cpp = ..\jlib\win32\DeviceUniqueIdentifier.cpp + ..\jlib\win32\DeviceUniqueIdentifier.h = ..\jlib\win32\DeviceUniqueIdentifier.h + ..\jlib\win32\deviceuniqueidentifierheaderonly.h = ..\jlib\win32\deviceuniqueidentifierheaderonly.h + ..\jlib\win32\file_op = ..\jlib\win32\file_op + ..\jlib\win32\file_op.h = ..\jlib\win32\file_op.h + ..\jlib\win32\memory_micros.h = ..\jlib\win32\memory_micros.h + ..\jlib\win32\MtVerify.h = ..\jlib\win32\MtVerify.h + ..\jlib\win32\MtVerify.h.bak = ..\jlib\win32\MtVerify.h.bak + ..\jlib\win32\MyWSAError.h = ..\jlib\win32\MyWSAError.h + ..\jlib\win32\odbccp32.lib = ..\jlib\win32\odbccp32.lib + ..\jlib\win32\path_op.h = ..\jlib\win32\path_op.h + ..\jlib\win32\registry.h = ..\jlib\win32\registry.h + ..\jlib\win32\UnicodeTool.h = ..\jlib\win32\UnicodeTool.h + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mfc", "mfc", "{9A3F45EB-C57C-4789-8177-0DEFCC5AFD0E}" + ProjectSection(SolutionItems) = preProject + ..\jlib\win32\mfc\FileOper.h = ..\jlib\win32\mfc\FileOper.h + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{21DC893D-AB0B-48E1-9E23-069A025218D9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "win32_tests", "win32_tests", "{0E6598D3-602D-4552-97F7-DC5AB458D553}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_registry", "test_registry\test_registry.vcxproj", "{519E5179-6E95-44EF-A63B-65C9C9C47A3B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -122,13 +156,51 @@ Global {B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Release|x64.Build.0 = Release|x64 {B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Release|x86.ActiveCfg = Release|Win32 {B4B8F20B-1B3E-42CD-8B37-A734EF3CA279}.Release|x86.Build.0 = Release|Win32 + {3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}.Debug|x64.ActiveCfg = Debug|x64 + {3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}.Debug|x64.Build.0 = Debug|x64 + {3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}.Debug|x86.ActiveCfg = Debug|Win32 + {3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}.Debug|x86.Build.0 = Debug|Win32 + {3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}.Release|x64.ActiveCfg = Release|x64 + {3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}.Release|x64.Build.0 = Release|x64 + {3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}.Release|x86.ActiveCfg = Release|Win32 + {3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}.Release|x86.Build.0 = Release|Win32 + {8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}.Debug|x64.ActiveCfg = Debug|x64 + {8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}.Debug|x64.Build.0 = Debug|x64 + {8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}.Debug|x86.ActiveCfg = Debug|Win32 + {8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}.Debug|x86.Build.0 = Debug|Win32 + {8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}.Release|x64.ActiveCfg = Release|x64 + {8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}.Release|x64.Build.0 = Release|x64 + {8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}.Release|x86.ActiveCfg = Release|Win32 + {8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}.Release|x86.Build.0 = Release|Win32 + {519E5179-6E95-44EF-A63B-65C9C9C47A3B}.Debug|x64.ActiveCfg = Debug|x64 + {519E5179-6E95-44EF-A63B-65C9C9C47A3B}.Debug|x64.Build.0 = Debug|x64 + {519E5179-6E95-44EF-A63B-65C9C9C47A3B}.Debug|x86.ActiveCfg = Debug|Win32 + {519E5179-6E95-44EF-A63B-65C9C9C47A3B}.Debug|x86.Build.0 = Debug|Win32 + {519E5179-6E95-44EF-A63B-65C9C9C47A3B}.Release|x64.ActiveCfg = Release|x64 + {519E5179-6E95-44EF-A63B-65C9C9C47A3B}.Release|x64.Build.0 = Release|x64 + {519E5179-6E95-44EF-A63B-65C9C9C47A3B}.Release|x86.ActiveCfg = Release|Win32 + {519E5179-6E95-44EF-A63B-65C9C9C47A3B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {155F525A-FA2F-471F-A2DF-9B77E7CCCFA5} = {21DC893D-AB0B-48E1-9E23-069A025218D9} + {1E6D1113-2EDE-4E7E-BF17-A3663101C3AE} = {0E6598D3-602D-4552-97F7-DC5AB458D553} + {CA7812A3-9E48-4A94-B39A-32EED587E38A} = {0E6598D3-602D-4552-97F7-DC5AB458D553} + {A4B1CDB2-7325-4E22-AD0A-1D2907924CDB} = {0E6598D3-602D-4552-97F7-DC5AB458D553} + {B12702AD-ABFB-343A-A199-8E24837244A3} = {21DC893D-AB0B-48E1-9E23-069A025218D9} + {8A39D7AF-50AF-43BD-8CC6-DA20B6349F03} = {21DC893D-AB0B-48E1-9E23-069A025218D9} + {372670F2-83A5-4058-B93C-BB0DCC1521ED} = {21DC893D-AB0B-48E1-9E23-069A025218D9} {5A2CA1BE-5A4B-41B0-B74A-F86AB433F4A5} = {42703978-A988-403D-9723-E35527FA8A07} {608A105E-40DB-44FD-8FC2-A66AB921688D} = {42703978-A988-403D-9723-E35527FA8A07} + {B4B8F20B-1B3E-42CD-8B37-A734EF3CA279} = {21DC893D-AB0B-48E1-9E23-069A025218D9} + {3E322E9F-E560-4300-AFF8-1DCE44E7DDA2} = {21DC893D-AB0B-48E1-9E23-069A025218D9} + {8A9333D5-2981-4E92-87BF-AFFC5F99B1A4} = {21DC893D-AB0B-48E1-9E23-069A025218D9} + {B5D9E71E-2BFE-4D04-A66A-4CB0A103CD77} = {42703978-A988-403D-9723-E35527FA8A07} + {9A3F45EB-C57C-4789-8177-0DEFCC5AFD0E} = {B5D9E71E-2BFE-4D04-A66A-4CB0A103CD77} + {0E6598D3-602D-4552-97F7-DC5AB458D553} = {21DC893D-AB0B-48E1-9E23-069A025218D9} + {519E5179-6E95-44EF-A63B-65C9C9C47A3B} = {0E6598D3-602D-4552-97F7-DC5AB458D553} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A8EBEA58-739C-4DED-99C0-239779F57D5D} diff --git a/test/test_logging/test_logging.cpp b/test/test_logging/test_logging.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78a3a91ca7b6cc0fe0479c5a7526953ff14fbfeb --- /dev/null +++ b/test/test_logging/test_logging.cpp @@ -0,0 +1,6 @@ +#include "../../jlib/base/logging.h" + +int main() +{ + +} \ No newline at end of file diff --git a/test/test_logging/test_logging.vcxproj b/test/test_logging/test_logging.vcxproj new file mode 100644 index 0000000000000000000000000000000000000000..512b765541ea6cae7e1f315e5d77441133a933c3 --- /dev/null +++ b/test/test_logging/test_logging.vcxproj @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>16.0</VCProjectVersion> + <ProjectGuid>{3E322E9F-E560-4300-AFF8-1DCE44E7DDA2}</ProjectGuid> + <RootNamespace>testlogging</RootNamespace> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(BOOST);$(DEVLIBS)\jlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="test_logging.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/test/test_logging/test_logging.vcxproj.filters b/test/test_logging/test_logging.vcxproj.filters new file mode 100644 index 0000000000000000000000000000000000000000..12ec501e1240a1c60889768d87ebc50bd5be3039 --- /dev/null +++ b/test/test_logging/test_logging.vcxproj.filters @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="test_logging.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/test/test_logging/test_logging.vcxproj.user b/test/test_logging/test_logging.vcxproj.user new file mode 100644 index 0000000000000000000000000000000000000000..88a550947edbc3c5003a41726f0749201fdb6822 --- /dev/null +++ b/test/test_logging/test_logging.vcxproj.user @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup /> +</Project> \ No newline at end of file diff --git a/test/test_registry/test_registry.cpp b/test/test_registry/test_registry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d7f251c263c5702bc964074fe5a4359486c41ea6 --- /dev/null +++ b/test/test_registry/test_registry.cpp @@ -0,0 +1,162 @@ +#include "../../jlib/win32/registry.h" +#include <exception> +#include <iostream> + +using namespace std; +using namespace jlib::win32::reg; + +int main() +{ + constexpr int kExitError = 1; + + try + { + wcout << L"=========================================\n"; + wcout << L"*** Testing Giovanni Dicanio's WinReg ***\n"; + wcout << L"=========================================\n\n"; + + // + // Test subkey and value enumeration + // + + const wstring testSubKey = L"SOFTWARE\\GioTest"; + RegKey key; + + key.open(HKEY_CURRENT_USER, testSubKey); + + vector<wstring> subKeyNames = key.querySubKeys(); + wcout << L"Subkeys:\n"; + for (const auto& s : subKeyNames) + { + wcout << L" [" << s << L"]\n"; + } + wcout << L'\n'; + + vector<pair<wstring, DWORD>> values = key.queryValues(); + wcout << L"Values:\n"; + for (const auto& v : values) + { + wcout << L" [" << v.first << L"](" << RegKey::regTypeToString(v.second) << L")\n"; + } + wcout << L'\n'; + + key.close(); + + + // + // Test SetXxxValue and GetXxxValue methods + // + + key.open(HKEY_CURRENT_USER, testSubKey); + + const DWORD testDw = 0x1234ABCD; + const ULONGLONG testQw = 0xAABBCCDD11223344; + const wstring testSz = L"CiaoTestSz"; + const wstring testExpandSz = L"%PATH%"; + const vector<BYTE> testBinary{ 0xAA, 0xBB, 0xCC, 0x11, 0x22, 0x33 }; + const vector<wstring> testMultiSz{ L"Hi", L"Hello", L"Ciao" }; + + key.setDwordValue(L"TestValueDword", testDw); + key.setQwordValue(L"TestValueQword", testQw); + key.setStringValue(L"TestValueString", testSz); + key.setExpandStringValue(L"TestValueExpandString", testExpandSz); + key.setMultiStringValue(L"TestValueMultiString", testMultiSz); + key.setBinaryValue(L"TestValueBinary", testBinary); + + DWORD testDw1 = key.getDwordValue(L"TestValueDword"); + if (testDw1 != testDw) + { + wcout << L"RegKey::GetDwordValue failed.\n"; + } + + DWORD typeId = key.queryValueType(L"TestValueDword"); + if (typeId != REG_DWORD) + { + wcout << L"RegKey::QueryValueType failed for REG_DWORD.\n"; + } + + ULONGLONG testQw1 = key.getQwordValue(L"TestValueQword"); + if (testQw1 != testQw) + { + wcout << L"RegKey::GetQwordValue failed.\n"; + } + + typeId = key.queryValueType(L"TestValueQword"); + if (typeId != REG_QWORD) + { + wcout << L"RegKey::QueryValueType failed for REG_QWORD.\n"; + } + + wstring testSz1 = key.getStringValue(L"TestValueString"); + if (testSz1 != testSz) + { + wcout << L"RegKey::GetStringValue failed.\n"; + } + + typeId = key.queryValueType(L"TestValueString"); + if (typeId != REG_SZ) + { + wcout << L"RegKey::QueryValueType failed for REG_SZ.\n"; + } + + wstring testExpandSz1 = key.getExpandStringValue(L"TestValueExpandString"); + if (testExpandSz1 != testExpandSz) + { + wcout << L"RegKey::GetExpandStringValue failed.\n"; + } + + typeId = key.queryValueType(L"TestValueExpandString"); + if (typeId != REG_EXPAND_SZ) + { + wcout << L"RegKey::QueryValueType failed for REG_EXPAND_SZ.\n"; + } + + vector<wstring> testMultiSz1 = key.getMultiStringValue(L"TestValueMultiString"); + if (testMultiSz1 != testMultiSz) + { + wcout << L"RegKey::GetMultiStringValue failed.\n"; + } + + typeId = key.queryValueType(L"TestValueMultiString"); + if (typeId != REG_MULTI_SZ) + { + wcout << L"RegKey::QueryValueType failed for REG_MULTI_SZ.\n"; + } + + vector<BYTE> testBinary1 = key.getBinaryValue(L"TestValueBinary"); + if (testBinary1 != testBinary) + { + wcout << L"RegKey::GetBinaryValue failed.\n"; + } + + typeId = key.queryValueType(L"TestValueBinary"); + if (typeId != REG_BINARY) + { + wcout << L"RegKey::QueryValueType failed for REG_BINARY.\n"; + } + + + // + // Remove some test values + // + + key.deleteValue(L"TestValueDword"); + key.deleteValue(L"TestValueQword"); + key.deleteValue(L"TestValueString"); + key.deleteValue(L"TestValueExpandString"); + key.deleteValue(L"TestValueMultiString"); + key.deleteValue(L"TestValueBinary"); + + + + wcout << L"All right!! :)\n\n"; + } catch (const RegException& e) { + cout << "\n*** Registry Exception: " << e.what(); + cout << "\n*** [Windows API error code = " << e.errorCode(); + cout << "\n*** Description: " << e.description() << "\n\n"; + return kExitError; + } catch (const exception& e) { + cout << "\n*** ERROR: " << e.what() << '\n'; + return kExitError; + } +} diff --git a/test/test_registry/test_registry.vcxproj b/test/test_registry/test_registry.vcxproj new file mode 100644 index 0000000000000000000000000000000000000000..522d5d934495e4f0a8cc090274a5d8f207c972fa --- /dev/null +++ b/test/test_registry/test_registry.vcxproj @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>16.0</VCProjectVersion> + <ProjectGuid>{519E5179-6E95-44EF-A63B-65C9C9C47A3B}</ProjectGuid> + <RootNamespace>testregistry</RootNamespace> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="test_registry.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/test/test_registry/test_registry.vcxproj.filters b/test/test_registry/test_registry.vcxproj.filters new file mode 100644 index 0000000000000000000000000000000000000000..fae7ca8e03e57b31c829ee8cab6dd835bf256570 --- /dev/null +++ b/test/test_registry/test_registry.vcxproj.filters @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="test_registry.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/test/test_registry/test_registry.vcxproj.user b/test/test_registry/test_registry.vcxproj.user new file mode 100644 index 0000000000000000000000000000000000000000..88a550947edbc3c5003a41726f0749201fdb6822 --- /dev/null +++ b/test/test_registry/test_registry.vcxproj.user @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup /> +</Project> \ No newline at end of file diff --git a/test/test_timezone/test_timezone.cpp b/test/test_timezone/test_timezone.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dfce3e7adb25582f3f3681ce748e0c97ebab7d2b --- /dev/null +++ b/test/test_timezone/test_timezone.cpp @@ -0,0 +1,11 @@ +#include <Windows.h> +#include <stdio.h> +#include "../../jlib/base/timezone.h" + +int main() +{ + TIME_ZONE_INFORMATION info = { 0 }; + auto ret = GetTimeZoneInformation(&info); + + printf("info.bias=%ld\n", info.Bias); +} \ No newline at end of file diff --git a/test/test_timezone/test_timezone.vcxproj b/test/test_timezone/test_timezone.vcxproj new file mode 100644 index 0000000000000000000000000000000000000000..30634b3b706972b66877bb3a8356c134e2efc442 --- /dev/null +++ b/test/test_timezone/test_timezone.vcxproj @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>16.0</VCProjectVersion> + <ProjectGuid>{8A9333D5-2981-4E92-87BF-AFFC5F99B1A4}</ProjectGuid> + <RootNamespace>testtimezone</RootNamespace> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v142</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="test_timezone.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/test/test_timezone/test_timezone.vcxproj.filters b/test/test_timezone/test_timezone.vcxproj.filters new file mode 100644 index 0000000000000000000000000000000000000000..6d84a357a1b47eaf32fef3ea1a980f121a3a38a1 --- /dev/null +++ b/test/test_timezone/test_timezone.vcxproj.filters @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="test_timezone.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/test/test_timezone/test_timezone.vcxproj.user b/test/test_timezone/test_timezone.vcxproj.user new file mode 100644 index 0000000000000000000000000000000000000000..88a550947edbc3c5003a41726f0749201fdb6822 --- /dev/null +++ b/test/test_timezone/test_timezone.vcxproj.user @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup /> +</Project> \ No newline at end of file