diff options
author | Egor Tensin <Egor.Tensin@gmail.com> | 2020-10-18 00:11:25 +0300 |
---|---|---|
committer | Egor Tensin <Egor.Tensin@gmail.com> | 2020-10-18 00:24:13 +0300 |
commit | 3eec1310829f6ec7f3c40a35d5991b0ebbf273b5 (patch) | |
tree | ce8257ca7e35f0471bbc1fd67acd8a1c75969ec9 | |
parent | process_tests: add stdin redirection test (diff) | |
download | winapi-common-3eec1310829f6ec7f3c40a35d5991b0ebbf273b5.tar.gz winapi-common-3eec1310829f6ec7f3c40a35d5991b0ebbf273b5.zip |
Process: add methods to load resource strings
-rw-r--r-- | include/winapi/buffer.hpp | 5 | ||||
-rw-r--r-- | include/winapi/process.hpp | 9 | ||||
-rw-r--r-- | include/winapi/resource.hpp | 27 | ||||
-rw-r--r-- | src/process.cpp | 52 | ||||
-rw-r--r-- | test/unit_tests/CMakeLists.txt | 5 | ||||
-rw-r--r-- | test/unit_tests/resource.cpp | 57 | ||||
-rw-r--r-- | test/unit_tests/resource.rc | 15 | ||||
-rw-r--r-- | test/unit_tests/resource_ids.h | 3 |
8 files changed, 169 insertions, 4 deletions
diff --git a/include/winapi/buffer.hpp b/include/winapi/buffer.hpp index 246822e..7c8f928 100644 --- a/include/winapi/buffer.hpp +++ b/include/winapi/buffer.hpp @@ -7,6 +7,7 @@ #include <cstddef> #include <cstring> +#include <initializer_list> #include <sstream> #include <stdexcept> #include <string> @@ -21,6 +22,8 @@ public: Buffer() = default; + Buffer(std::initializer_list<unsigned char> lst) : Parent(lst) {} + explicit Buffer(Parent&& src) : Parent(std::move(src)) {} template <typename CharT> @@ -28,7 +31,7 @@ public: set(src); } - explicit Buffer(const void* src, std::size_t nb) { set(src, nb); } + Buffer(const void* src, std::size_t nb) { set(src, nb); } template <typename CharT> void set(const std::basic_string<CharT>& src) { diff --git a/include/winapi/process.hpp b/include/winapi/process.hpp index f404b33..469653c 100644 --- a/include/winapi/process.hpp +++ b/include/winapi/process.hpp @@ -7,10 +7,14 @@ #include "cmd_line.hpp" #include "handle.hpp" +#include "resource.hpp" #include "stream.hpp" #include <boost/config.hpp> +#include <windows.h> + +#include <string> #include <utility> namespace winapi { @@ -52,9 +56,14 @@ public: int get_exit_code() const; + static Resource get_resource(unsigned int id); + static std::string get_resource_string(unsigned int id); + private: explicit Process(Handle&& handle) : m_handle{std::move(handle)} {} + static HMODULE get_exe_module(); + Handle m_handle; }; diff --git a/include/winapi/resource.hpp b/include/winapi/resource.hpp new file mode 100644 index 0000000..2f77d3e --- /dev/null +++ b/include/winapi/resource.hpp @@ -0,0 +1,27 @@ +// Copyright (c) 2020 Egor Tensin <Egor.Tensin@gmail.com> +// This file is part of the "winapi-common" project. +// For details, see https://github.com/egor-tensin/winapi-common. +// Distributed under the MIT License. + +#pragma once + +#include "buffer.hpp" + +#include <cstddef> + +namespace winapi { + +struct Resource { + // This is just a pointer to static data. + + Resource() = default; + + Resource(const void* data, std::size_t nb) : data{data}, nb{nb} {} + + Buffer copy() const { return {data, nb}; } + + const void* data = nullptr; + std::size_t nb = 0; +}; + +} // namespace winapi diff --git a/src/process.cpp b/src/process.cpp index f95bc56..d3ce3a4 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -6,14 +6,18 @@ #include <winapi/cmd_line.hpp> #include <winapi/error.hpp> #include <winapi/process.hpp> +#include <winapi/resource.hpp> #include <winapi/utf8.hpp> #include <boost/config.hpp> #include <windows.h> +#include <cstddef> #include <cstring> +#include <sstream> #include <stdexcept> +#include <string> #include <utility> #include <vector> @@ -110,4 +114,52 @@ int Process::get_exit_code() const { return static_cast<int>(ec); } +HMODULE Process::get_exe_module() { + const auto module = ::GetModuleHandleW(NULL); + if (module == NULL) { + throw error::windows(GetLastError(), "GetModuleHandleW"); + } + return module; +} + +std::string Process::get_resource_string(unsigned int id) { + wchar_t* s = nullptr; + + const auto nch = ::LoadStringW(get_exe_module(), id, reinterpret_cast<wchar_t*>(&s), 0); + + if (nch <= 0) { + throw error::windows(GetLastError(), "LoadStringW"); + } + + return narrow(s, nch * sizeof(wchar_t)); +} + +Resource Process::get_resource(unsigned int id) { + const auto module = get_exe_module(); + + const auto src = ::FindResourceA(module, MAKEINTRESOURCEA(id), RT_RCDATA); + + if (src == NULL) { + throw error::windows(GetLastError(), "FindResourceA"); + } + + const auto resource = ::LoadResource(module, src); + + if (resource == NULL) { + throw error::windows(GetLastError(), "LoadResource"); + } + + const auto data = ::LockResource(resource); + + if (data == NULL) { + std::ostringstream oss; + oss << "Couldn't get data pointer for resource with ID " << id; + throw std::runtime_error{oss.str()}; + } + + const auto nb = ::SizeofResource(module, src); + + return {data, nb}; +} + } // namespace winapi diff --git a/test/unit_tests/CMakeLists.txt b/test/unit_tests/CMakeLists.txt index 19ce0c0..8aaa6d3 100644 --- a/test/unit_tests/CMakeLists.txt +++ b/test/unit_tests/CMakeLists.txt @@ -1,6 +1,5 @@ -file(GLOB unit_tests_cpp "*.cpp") -file(GLOB unit_tests_hpp "*.hpp") -add_executable(unit_tests ${unit_tests_cpp} ${unit_tests_hpp}) +file(GLOB unit_tests_files "*.cpp" "*.h" "*.hpp" "*.rc") +add_executable(unit_tests ${unit_tests_files}) set_target_properties(unit_tests PROPERTIES OUTPUT_NAME winapi-common-unit-tests) target_link_libraries(unit_tests PRIVATE winapi_common winapi_utf8) diff --git a/test/unit_tests/resource.cpp b/test/unit_tests/resource.cpp new file mode 100644 index 0000000..894edca --- /dev/null +++ b/test/unit_tests/resource.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2020 Egor Tensin <Egor.Tensin@gmail.com> +// This file is part of the "winapi-common" project. +// For details, see https://github.com/egor-tensin/winapi-common. +// Distributed under the MIT License. + +#include "resource_ids.h" + +#include <winapi/process.hpp> +#include <winapi/utf8.hpp> + +#include <boost/config.hpp> +#include <boost/format.hpp> +#include <boost/test/unit_test.hpp> + +using namespace winapi; + +#include <ostream> +#include <vector> + +namespace std { + +ostream& operator<<(ostream& os, unsigned char c) { + return os << boost::format("%|1$02x|") % static_cast<unsigned int>(c); +} + +ostream& operator<<(ostream& os, const vector<unsigned char>& cs) { + for (auto c : cs) { + os << c; + } + return os; +} + +} // namespace std + +BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Buffer); + +BOOST_AUTO_TEST_SUITE(resource_tests) + +BOOST_AUTO_TEST_CASE(get_string) { + BOOST_STATIC_CONSTEXPR auto expected = "This is a test resource string!"; + const auto actual = Process::get_resource_string(IDS_TEST_STRING); + BOOST_TEST(actual == expected); +} + +BOOST_AUTO_TEST_CASE(get_string_wide) { + BOOST_STATIC_CONSTEXPR auto expected = "This is another test string, wide this time."; + const auto actual = Process::get_resource_string(IDS_TEST_STRING_WIDE); + BOOST_TEST(actual == expected); +} + +BOOST_AUTO_TEST_CASE(get_data) { + static const Buffer expected{0xde, 0xad, 0xbe, 0xef}; + const auto actual = Process::get_resource(ID_TEST_DATA).copy(); + BOOST_TEST(actual == expected); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_tests/resource.rc b/test/unit_tests/resource.rc new file mode 100644 index 0000000..4ff6e5c --- /dev/null +++ b/test/unit_tests/resource.rc @@ -0,0 +1,15 @@ +#include "resource_ids.h" + +#include <windows.h> + +STRINGTABLE +{ + IDS_TEST_STRING, "This is a test resource string!" + IDS_TEST_STRING_WIDE, L"This is another test string, wide this time." +} + +// 0xdeadbeef, byte by byte +ID_TEST_DATA RCDATA +{ + 0xadde, 0xefbe +} diff --git a/test/unit_tests/resource_ids.h b/test/unit_tests/resource_ids.h new file mode 100644 index 0000000..46046bf --- /dev/null +++ b/test/unit_tests/resource_ids.h @@ -0,0 +1,3 @@ +#define IDS_TEST_STRING 69 +#define IDS_TEST_STRING_WIDE 70 +#define ID_TEST_DATA 420 |