Run Code
|
API
|
Code Wall
|
Misc
|
Feedback
|
Login
|
Theme
|
Privacy
|
Patreon
Time Zone Registry
#define WIN32_LEAN_AND_MEAN #include <Windows.h> #include <algorithm> #include <cassert> #include <codecvt> #include <iostream> #include <locale> #include <memory> #include <stdexcept> #include <string> class reg_key { private: // Note there is no value documented to be an invalid handle value. // Not NULL nor INVALID_HANDLE_VALUE. We must rely on is_open. HKEY m_key = nullptr; bool m_is_open = false; public: ~reg_key() { close(); } reg_key() = default; reg_key(const reg_key&) = delete; reg_key& operator=(const reg_key&) = delete; HKEY handle() { return m_key; } bool is_open() const { return m_is_open; } LONG open(const wchar_t* key_name) { LONG result; result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &m_key); if (result == ERROR_SUCCESS) m_is_open = true; return result; } LONG close() { if (m_is_open) { auto result = RegCloseKey(m_key); assert(result == ERROR_SUCCESS); if (result == ERROR_SUCCESS) { m_is_open = false; m_key = nullptr; } return result; } return ERROR_SUCCESS; } // WARNING: this function is not a general-purpose function. // It has a hard-coded value size limit that should be sufficient for our use cases. bool get_string(const wchar_t* key_name, std::string& value, std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>& converter) { value.clear(); wchar_t value_buffer[256]; // in/out parameter. Documentation say that size is a count of bytes not chars. DWORD size = sizeof(value_buffer) - sizeof(value_buffer[0]); DWORD tzi_type = REG_SZ; if (RegQueryValueExW(handle(), key_name, nullptr, &tzi_type, reinterpret_cast<LPBYTE>(value_buffer), &size) == ERROR_SUCCESS) { // Function does not guarantee to null terminate. value.resize(size/sizeof(value_buffer[0])-1); value_buffer[value.size()] = L'\0'; wcstombs(&value.front(), value_buffer, value.size()); // value = converter.to_bytes(value_buffer); return true; } return false; } bool get_binary(const wchar_t* key_name, void* value, int value_size) { DWORD size = value_size; DWORD type = REG_BINARY; if (RegQueryValueExW(handle(), key_name, nullptr, &type, reinterpret_cast<LPBYTE>(value), &size) == ERROR_SUCCESS && (int) size == value_size) return true; return false; } }; struct timezone_info { std::string timezone_id; std::string standard_name; }; static std::string get_win32_message(DWORD error_code) { struct free_message { void operator()(char buf[]) { if (buf != nullptr) { auto result = HeapFree(GetProcessHeap(), 0, buf); assert(result != 0); } } }; char* msg = nullptr; auto result = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<char*>(&msg), 0, nullptr ); std::unique_ptr<char[], free_message> message_buffer(msg); if (result == 0) // If there is no error message, still give the code. { std::string err = "Error getting message for error number "; err += std::to_string(error_code); return err; } assert(message_buffer.get() != nullptr); return std::string(message_buffer.get()); } void get_windows_timezone_info() { LONG result; // Open the parent time zone key that has the list of timezones in. reg_key zones_key; static const wchar_t zones_key_name[] = { L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones" }; result = zones_key.open(zones_key_name); // TODO! Review if this should happen here or be signalled later. // We don't want the process to fail on startup because of this. if (result != ERROR_SUCCESS) throw std::runtime_error("Time Zone registry key could not be opened: " + get_win32_message(result)); DWORD size; wchar_t zone_key_name[256]; std::wstring value; std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; // Iterate through the list of keys of the parent time zones key to get // each key that identifies each individual timezone. std::wstring full_zone_key_name; for (DWORD zone_index = 0; ; ++zone_index) { timezone_info tz; size = (DWORD) sizeof(zone_key_name)/sizeof(zone_key_name[0]); auto status = RegEnumKeyExW(zones_key.handle(), zone_index, zone_key_name, &size, nullptr, nullptr, nullptr, nullptr); if (status != ERROR_SUCCESS && status != ERROR_NO_MORE_ITEMS) throw std::runtime_error("Can't enumerate time zone registry key" + get_win32_message(status)); if (status == ERROR_NO_MORE_ITEMS) break; tz.timezone_id.resize(size); wcstombs(&tz.timezone_id.front(), zone_key_name, tz.timezone_id.size()); // tz.timezone_id = converter.to_bytes(zone_key_name); full_zone_key_name = zones_key_name; full_zone_key_name += L'\\'; full_zone_key_name += zone_key_name; // If any field fails to be found, consider the whole time zone // entry corrupt and move onto the next. See comments // at the top of function. reg_key zone_key; if (zone_key.open(full_zone_key_name.c_str()) != ERROR_SUCCESS) continue; if (!zone_key.get_string(L"Std", tz.standard_name, converter)) continue; zone_key.close(); if (tz.timezone_id == tz.standard_name) std::cerr << '{' << tz.timezone_id << " : " << tz.timezone_id.size() << "}\n"; else { std::cerr << '{' << tz.timezone_id << " : " << tz.timezone_id.size() << ", " << tz.standard_name << " : " << tz.standard_name.size() << "}\n"; if (tz.timezone_id.size() == tz.standard_name.size()) { auto p = std::mismatch(tz.timezone_id.begin(), tz.timezone_id.end(), tz.standard_name.begin()); if (p.first != tz.timezone_id.end()) std::cerr << *p.first << " vs " << *p.second << '\n'; } } } result = zones_key.close(); } int main() { get_windows_timezone_info(); }
run
|
edit
|
history
|
help
0
a parameter pack
MSVC_example_GetAllocLength
dynamic_cast in assert Causing Error
LinkedList
print adapted struct
list multiply
codecvt wide string conversion with multibyte chars and locale + concatenation
wall
VC++ error LNK2001 with combined use of non-type template parameters
Template