aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2020-10-18 00:11:25 +0300
committerEgor Tensin <Egor.Tensin@gmail.com>2020-10-18 00:24:13 +0300
commit3eec1310829f6ec7f3c40a35d5991b0ebbf273b5 (patch)
treece8257ca7e35f0471bbc1fd67acd8a1c75969ec9
parentprocess_tests: add stdin redirection test (diff)
downloadwinapi-common-3eec1310829f6ec7f3c40a35d5991b0ebbf273b5.tar.gz
winapi-common-3eec1310829f6ec7f3c40a35d5991b0ebbf273b5.zip
Process: add methods to load resource strings
-rw-r--r--include/winapi/buffer.hpp5
-rw-r--r--include/winapi/process.hpp9
-rw-r--r--include/winapi/resource.hpp27
-rw-r--r--src/process.cpp52
-rw-r--r--test/unit_tests/CMakeLists.txt5
-rw-r--r--test/unit_tests/resource.cpp57
-rw-r--r--test/unit_tests/resource.rc15
-rw-r--r--test/unit_tests/resource_ids.h3
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