From 5aca7b099c46a87a859f40110efce708200a4bc8 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 3 Feb 2022 17:55:00 +0800 Subject: ... --- include/cru/common/io/MemoryStream.hpp | 3 ++ .../cru/common/platform/win/BrigdeComStream.hpp | 48 -------------------- include/cru/common/platform/win/ComAutoInit.hpp | 21 +++++++++ include/cru/common/platform/win/StreamConvert.hpp | 14 ++++++ .../cru/common/platform/win/Win32FileStream.hpp | 3 ++ include/cru/win/graphics/direct/Factory.hpp | 3 ++ src/common/CMakeLists.txt | 6 ++- src/common/platform/win/BridgeComStream.cpp | 2 +- src/common/platform/win/BrigdeComStream.hpp | 43 ++++++++++++++++++ src/common/platform/win/ComAutoInit.cpp | 15 ++++++ src/common/platform/win/StreamConvert.cpp | 53 ++++++++++++++++++++++ src/common/platform/win/Win32FileStream.cpp | 7 +-- src/win/graphics/direct/Factory.cpp | 21 +-------- test/common/CMakeLists.txt | 5 +- test/common/io/UnixFileStreamTest.cpp | 33 -------------- test/common/io/Win32FileStreamTest.cpp | 33 -------------- test/common/platform/unix/UnixFileStreamTest.cpp | 33 ++++++++++++++ test/common/platform/win/StreamConvertTest.cpp | 38 ++++++++++++++++ test/common/platform/win/Win32FileStreamTest.cpp | 33 ++++++++++++++ 19 files changed, 274 insertions(+), 140 deletions(-) delete mode 100644 include/cru/common/platform/win/BrigdeComStream.hpp create mode 100644 include/cru/common/platform/win/ComAutoInit.hpp create mode 100644 include/cru/common/platform/win/StreamConvert.hpp create mode 100644 src/common/platform/win/BrigdeComStream.hpp create mode 100644 src/common/platform/win/ComAutoInit.cpp create mode 100644 src/common/platform/win/StreamConvert.cpp delete mode 100644 test/common/io/UnixFileStreamTest.cpp delete mode 100644 test/common/io/Win32FileStreamTest.cpp create mode 100644 test/common/platform/unix/UnixFileStreamTest.cpp create mode 100644 test/common/platform/win/StreamConvertTest.cpp create mode 100644 test/common/platform/win/Win32FileStreamTest.cpp diff --git a/include/cru/common/io/MemoryStream.hpp b/include/cru/common/io/MemoryStream.hpp index e917814c..29da7b9f 100644 --- a/include/cru/common/io/MemoryStream.hpp +++ b/include/cru/common/io/MemoryStream.hpp @@ -31,6 +31,9 @@ class CRU_BASE_API MemoryStream : public Stream { bool CanWrite() override; Index Write(const std::byte* buffer, Index offset, Index size) override; + std::byte* GetBuffer() const { return buffer_; } + Index GetSize() override { return size_; } + private: std::byte* buffer_ = nullptr; Index size_ = 0; diff --git a/include/cru/common/platform/win/BrigdeComStream.hpp b/include/cru/common/platform/win/BrigdeComStream.hpp deleted file mode 100644 index 38b75dae..00000000 --- a/include/cru/common/platform/win/BrigdeComStream.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include "../../PreConfig.hpp" -#ifdef CRU_PLATFORM_WINDOWS - -#include "WinPreConfig.hpp" - -#include "../../io/Stream.hpp" - -#include - -namespace cru::platform::win { -class BridgeComStream : public IStream { - public: - explicit BridgeComStream(io::Stream* stream); - - CRU_DELETE_COPY(BridgeComStream) - CRU_DELETE_MOVE(BridgeComStream) - - ~BridgeComStream(); - - public: - ULONG AddRef() override; - ULONG Release() override; - HRESULT QueryInterface(REFIID riid, void** ppvObject) override; - - HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) override; - HRESULT Write(const void* pv, ULONG cb, ULONG* pcbWritten) override; - HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, - ULARGE_INTEGER* plibNewPosition) override; - HRESULT SetSize(ULARGE_INTEGER libNewSize) override; - HRESULT CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, - ULARGE_INTEGER* pcbWritten) override; - HRESULT Commit(DWORD grfCommitFlags) override; - HRESULT Revert() override; - HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, - DWORD dwLockType) override; - HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, - DWORD dwLockType) override; - HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) override; - HRESULT Clone(IStream** ppstm) override; - - private: - io::Stream* stream_; - ULONG ref_count_; -}; -} // namespace cru::platform::win - -#endif diff --git a/include/cru/common/platform/win/ComAutoInit.hpp b/include/cru/common/platform/win/ComAutoInit.hpp new file mode 100644 index 00000000..131f3f30 --- /dev/null +++ b/include/cru/common/platform/win/ComAutoInit.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "../../PreConfig.hpp" +#ifdef CRU_PLATFORM_WINDOWS + +#include "WinPreConfig.hpp" +#include "cru/common/Base.hpp" + +namespace cru::platform::win { +class CRU_BASE_API ComAutoInit { + public: + ComAutoInit(); + + CRU_DELETE_COPY(ComAutoInit) + CRU_DELETE_MOVE(ComAutoInit) + + ~ComAutoInit(); +}; +} // namespace cru::platform::win + +#endif diff --git a/include/cru/common/platform/win/StreamConvert.hpp b/include/cru/common/platform/win/StreamConvert.hpp new file mode 100644 index 00000000..80800115 --- /dev/null +++ b/include/cru/common/platform/win/StreamConvert.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "../../PreConfig.hpp" + +#ifdef CRU_PLATFORM_WINDOWS + +#include "../../io/Stream.hpp" + +#include + +namespace cru::platform::win { +CRU_BASE_API IStream* ConvertStreamToComStream(io::Stream* stream); +} + +#endif diff --git a/include/cru/common/platform/win/Win32FileStream.hpp b/include/cru/common/platform/win/Win32FileStream.hpp index ebb23357..b5511ba3 100644 --- a/include/cru/common/platform/win/Win32FileStream.hpp +++ b/include/cru/common/platform/win/Win32FileStream.hpp @@ -36,6 +36,9 @@ class CRU_BASE_API Win32FileStream : public io::Stream { void Close() override; + String GetPath() const { return path_; } + io::OpenFileFlag GetOpenFileFlags() const { return flags_; } + private: void CheckClosed(); diff --git a/include/cru/win/graphics/direct/Factory.hpp b/include/cru/win/graphics/direct/Factory.hpp index ba504f0d..4ceed7c5 100644 --- a/include/cru/win/graphics/direct/Factory.hpp +++ b/include/cru/win/graphics/direct/Factory.hpp @@ -3,6 +3,7 @@ #include "ImageFactory.hpp" +#include "cru/common/platform/win/ComAutoInit.hpp" #include "cru/platform/graphics/Base.hpp" #include "cru/platform/graphics/Factory.hpp" @@ -52,6 +53,8 @@ class CRU_WIN_GRAPHICS_DIRECT_API DirectGraphicsFactory IImageFactory* GetImageFactory() override; private: + platform::win::ComAutoInit com_auto_init_; + Microsoft::WRL::ComPtr d3d11_device_; Microsoft::WRL::ComPtr d2d1_factory_; Microsoft::WRL::ComPtr d2d1_device_; diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 3294b2f0..706f0ed0 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -35,9 +35,13 @@ endif() if (WIN32) target_sources(cru_base PRIVATE platform/win/BridgeComStream.cpp - platform/win/Win32FileStream.cpp + platform/win/ComAutoInit.cpp + platform/win/StreamConvert.cpp platform/win/Exception.cpp + platform/win/Win32FileStream.cpp ) + + target_link_libraries(cru_base PUBLIC Shlwapi.lib) endif() if (WIN32) diff --git a/src/common/platform/win/BridgeComStream.cpp b/src/common/platform/win/BridgeComStream.cpp index d324a4c2..48ba8154 100644 --- a/src/common/platform/win/BridgeComStream.cpp +++ b/src/common/platform/win/BridgeComStream.cpp @@ -1,5 +1,5 @@ +#include "BrigdeComStream.hpp" #include "cru/common/io/Stream.hpp" -#include "cru/common/platform/win/BrigdeComStream.hpp" namespace cru::platform::win { BridgeComStream::BridgeComStream(io::Stream *stream) diff --git a/src/common/platform/win/BrigdeComStream.hpp b/src/common/platform/win/BrigdeComStream.hpp new file mode 100644 index 00000000..228c16f6 --- /dev/null +++ b/src/common/platform/win/BrigdeComStream.hpp @@ -0,0 +1,43 @@ +#pragma once +#include "cru/common/platform/win/WinPreConfig.hpp" + +#include "cru/common/io/Stream.hpp" + +#include + +namespace cru::platform::win { +class BridgeComStream : public IStream { + public: + explicit BridgeComStream(io::Stream* stream); + + CRU_DELETE_COPY(BridgeComStream) + CRU_DELETE_MOVE(BridgeComStream) + + ~BridgeComStream(); + + public: + ULONG AddRef() override; + ULONG Release() override; + HRESULT QueryInterface(REFIID riid, void** ppvObject) override; + + HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) override; + HRESULT Write(const void* pv, ULONG cb, ULONG* pcbWritten) override; + HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, + ULARGE_INTEGER* plibNewPosition) override; + HRESULT SetSize(ULARGE_INTEGER libNewSize) override; + HRESULT CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, + ULARGE_INTEGER* pcbWritten) override; + HRESULT Commit(DWORD grfCommitFlags) override; + HRESULT Revert() override; + HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, + DWORD dwLockType) override; + HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, + DWORD dwLockType) override; + HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) override; + HRESULT Clone(IStream** ppstm) override; + + private: + io::Stream* stream_; + ULONG ref_count_; +}; +} // namespace cru::platform::win diff --git a/src/common/platform/win/ComAutoInit.cpp b/src/common/platform/win/ComAutoInit.cpp new file mode 100644 index 00000000..e336be59 --- /dev/null +++ b/src/common/platform/win/ComAutoInit.cpp @@ -0,0 +1,15 @@ +#include "cru/common/platform/win/ComAutoInit.hpp" +#include "cru/common/platform/win/Exception.hpp" + +#include + +namespace cru::platform::win { +ComAutoInit::ComAutoInit() { + const auto hresult = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + if (FAILED(hresult)) { + throw HResultError(hresult, "Failed to call CoInitializeEx."); + } +} + +ComAutoInit::~ComAutoInit() { ::CoUninitialize(); } +} // namespace cru::platform::win diff --git a/src/common/platform/win/StreamConvert.cpp b/src/common/platform/win/StreamConvert.cpp new file mode 100644 index 00000000..1d077573 --- /dev/null +++ b/src/common/platform/win/StreamConvert.cpp @@ -0,0 +1,53 @@ +#include "cru/common/platform/win/StreamConvert.hpp" +#include "BrigdeComStream.hpp" +#include "cru/common/Exception.hpp" +#include "cru/common/io/MemoryStream.hpp" +#include "cru/common/io/OpenFileFlag.hpp" +#include "cru/common/platform/win/ComAutoInit.hpp" +#include "cru/common/platform/win/Exception.hpp" +#include "cru/common/platform/win/Win32FileStream.hpp" + +#include +#include + +namespace cru::platform::win { +IStream* ConvertStreamToComStream(io::Stream* stream) { + static ComAutoInit com_auto_init; + + if (auto memory_stream = dynamic_cast(stream)) { + return SHCreateMemStream( + reinterpret_cast(memory_stream->GetBuffer()), + memory_stream->GetSize()); + } else if (auto file_stream = dynamic_cast(stream)) { + auto path = file_stream->GetPath(); + auto flags = file_stream->GetOpenFileFlags(); + DWORD grfMode = STGM_SHARE_DENY_NONE | STGM_FAILIFTHERE; + if (flags & io::OpenFileFlags::Read) { + if (flags & io::OpenFileFlags::Write) { + grfMode |= STGM_READWRITE; + } else { + grfMode |= STGM_READ; + } + } else { + if (flags & io::OpenFileFlags::Write) { + grfMode |= STGM_WRITE; + } else { + throw Exception(u"Stream must be readable or writable."); + } + } + + IStream* result; + + ThrowIfFailed(SHCreateStreamOnFileEx( + path.WinCStr(), grfMode, FILE_ATTRIBUTE_NORMAL, FALSE, NULL, &result)); + + LARGE_INTEGER position; + position.QuadPart = stream->Tell(); + result->Seek(position, STREAM_SEEK_SET, NULL); + + return result; + } else { + return new BridgeComStream(stream); + } +} +} // namespace cru::platform::win diff --git a/src/common/platform/win/Win32FileStream.cpp b/src/common/platform/win/Win32FileStream.cpp index ddf81c28..db3a1e01 100644 --- a/src/common/platform/win/Win32FileStream.cpp +++ b/src/common/platform/win/Win32FileStream.cpp @@ -4,6 +4,7 @@ #include "cru/common/platform/win/Exception.hpp" #include +#include namespace cru::platform::win { using namespace cru::io; @@ -37,9 +38,9 @@ Win32FileStream::Win32FileStream(String path, OpenFileFlag flags) dwCreationDisposition = OPEN_EXISTING; } - p_->handle = - ::CreateFileW(path_.WinCStr(), dwDesiredAccess, 0, nullptr, - dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr); + p_->handle = ::CreateFileW( + path_.WinCStr(), dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr); if (p_->handle == INVALID_HANDLE_VALUE) { throw Win32Error(u"Failed to call CreateFileW."); diff --git a/src/win/graphics/direct/Factory.cpp b/src/win/graphics/direct/Factory.cpp index cbdfe991..bc51cd1a 100644 --- a/src/win/graphics/direct/Factory.cpp +++ b/src/win/graphics/direct/Factory.cpp @@ -12,28 +12,11 @@ #include namespace cru::platform::graphics::win::direct { -namespace { -void InitializeCom() { - const auto hresult = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - if (FAILED(hresult)) { - throw HResultError(hresult, "Failed to call CoInitializeEx."); - } - if (hresult == S_FALSE) { - log::Debug( - u"Try to call CoInitializeEx, but it seems COM is already " - u"initialized."); - } -} - -void UninitializeCom() { ::CoUninitialize(); } -} // namespace DirectGraphicsFactory::DirectGraphicsFactory() { - // TODO! Detect repeated creation. Because I don't think we can create two d2d + // TODO: Detect repeated creation. Because I don't think we can create two d2d // and dwrite factory so we need to prevent the "probably dangerous" behavior. - InitializeCom(); - UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; #ifdef CRU_DEBUG @@ -79,7 +62,7 @@ DirectGraphicsFactory::DirectGraphicsFactory() { image_factory_ = std::make_unique(this); } -DirectGraphicsFactory::~DirectGraphicsFactory() { UninitializeCom(); } +DirectGraphicsFactory::~DirectGraphicsFactory() {} Microsoft::WRL::ComPtr DirectGraphicsFactory::CreateD2D1DeviceContext() { diff --git a/test/common/CMakeLists.txt b/test/common/CMakeLists.txt index 38c15000..600c18c3 100644 --- a/test/common/CMakeLists.txt +++ b/test/common/CMakeLists.txt @@ -8,13 +8,14 @@ target_link_libraries(cru_base_test PRIVATE cru_base cru_test_base) if (UNIX) target_sources(cru_base_test PRIVATE - io/UnixFileStreamTest.cpp + platform/unix/UnixFileStreamTest.cpp ) endif() if (WIN32) target_sources(cru_base_test PRIVATE - io/Win32FileStreamTest.cpp + platform/win/StreamConvertTest.cpp + platform/win/Win32FileStreamTest.cpp ) add_custom_command(TARGET cru_base_test POST_BUILD diff --git a/test/common/io/UnixFileStreamTest.cpp b/test/common/io/UnixFileStreamTest.cpp deleted file mode 100644 index cdc749ba..00000000 --- a/test/common/io/UnixFileStreamTest.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "cru/common/io/OpenFileFlag.hpp" -#include "cru/common/platform/unix/UnixFileStream.hpp" - -#include - -#include -#include - -TEST(UnixFileStream, Work) { - using namespace cru; - using namespace cru::io; - using namespace cru::platform::unix; - - auto temp_file_path = - (std::filesystem::temp_directory_path() / "cru_test_temp.XXXXXX") - .generic_string(); - mktemp(temp_file_path.data()); - - String path = String::FromUtf8(temp_file_path); - - UnixFileStream file(path, OpenFileFlags::Write | OpenFileFlags::Create); - file.Write("abc", 3); - file.Close(); - - UnixFileStream file2(path, OpenFileFlags::Read); - auto buffer = std::make_unique(3); - file2.Read(buffer.get(), 3); - ASSERT_EQ(std::string_view(reinterpret_cast(buffer.get()), 3), - "abc"); - file2.Close(); - - std::filesystem::remove(temp_file_path); -} diff --git a/test/common/io/Win32FileStreamTest.cpp b/test/common/io/Win32FileStreamTest.cpp deleted file mode 100644 index 0e35bb8d..00000000 --- a/test/common/io/Win32FileStreamTest.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "cru/common/io/OpenFileFlag.hpp" -#include "cru/common/platform/win/Win32FileStream.hpp" - -#include - -#include -#include - -TEST(UnixFileStream, Work) { - using namespace cru; - using namespace cru::io; - using namespace cru::platform::win; - - auto temp_file_path = - (std::filesystem::temp_directory_path() / "cru_test_temp.XXXXXX") - .native(); - _wmktemp(temp_file_path.data()); - - String path = temp_file_path; - - Win32FileStream file(path, OpenFileFlags::Write | OpenFileFlags::Create); - file.Write("abc", 3); - file.Close(); - - Win32FileStream file2(path, OpenFileFlags::Read); - auto buffer = std::make_unique(3); - file2.Read(buffer.get(), 3); - ASSERT_EQ(std::string_view(reinterpret_cast(buffer.get()), 3), - "abc"); - file2.Close(); - - std::filesystem::remove(temp_file_path); -} diff --git a/test/common/platform/unix/UnixFileStreamTest.cpp b/test/common/platform/unix/UnixFileStreamTest.cpp new file mode 100644 index 00000000..cdc749ba --- /dev/null +++ b/test/common/platform/unix/UnixFileStreamTest.cpp @@ -0,0 +1,33 @@ +#include "cru/common/io/OpenFileFlag.hpp" +#include "cru/common/platform/unix/UnixFileStream.hpp" + +#include + +#include +#include + +TEST(UnixFileStream, Work) { + using namespace cru; + using namespace cru::io; + using namespace cru::platform::unix; + + auto temp_file_path = + (std::filesystem::temp_directory_path() / "cru_test_temp.XXXXXX") + .generic_string(); + mktemp(temp_file_path.data()); + + String path = String::FromUtf8(temp_file_path); + + UnixFileStream file(path, OpenFileFlags::Write | OpenFileFlags::Create); + file.Write("abc", 3); + file.Close(); + + UnixFileStream file2(path, OpenFileFlags::Read); + auto buffer = std::make_unique(3); + file2.Read(buffer.get(), 3); + ASSERT_EQ(std::string_view(reinterpret_cast(buffer.get()), 3), + "abc"); + file2.Close(); + + std::filesystem::remove(temp_file_path); +} diff --git a/test/common/platform/win/StreamConvertTest.cpp b/test/common/platform/win/StreamConvertTest.cpp new file mode 100644 index 00000000..43c6f46c --- /dev/null +++ b/test/common/platform/win/StreamConvertTest.cpp @@ -0,0 +1,38 @@ +#include "cru/common/io/OpenFileFlag.hpp" +#include "cru/common/platform/win/Exception.hpp" +#include "cru/common/platform/win/StreamConvert.hpp" +#include "cru/common/platform/win/Win32FileStream.hpp" + +#include + +#include +#include + +TEST(StreamConvert, FileStreamWork) { + using namespace cru; + using namespace cru::io; + using namespace cru::platform::win; + + auto temp_file_path = + (std::filesystem::temp_directory_path() / "cru_test_temp.XXXXXX") + .native(); + _wmktemp(temp_file_path.data()); + + String path = temp_file_path; + + Win32FileStream file( + path, OpenFileFlags::Read | OpenFileFlags::Write | OpenFileFlags::Create); + file.Write("abc", 3); + + IStream* com_stream = ConvertStreamToComStream(&file); + LARGE_INTEGER position; + position.QuadPart = 0; + ThrowIfFailed(com_stream->Seek(position, SEEK_SET, nullptr)); + auto buffer = std::make_unique(3); + ThrowIfFailed(com_stream->Read(buffer.get(), 3, nullptr)); + ASSERT_EQ(std::string_view(buffer.get(), 3), "abc"); + com_stream->Release(); + file.Close(); + + std::filesystem::remove(temp_file_path); +} diff --git a/test/common/platform/win/Win32FileStreamTest.cpp b/test/common/platform/win/Win32FileStreamTest.cpp new file mode 100644 index 00000000..deb981f9 --- /dev/null +++ b/test/common/platform/win/Win32FileStreamTest.cpp @@ -0,0 +1,33 @@ +#include "cru/common/io/OpenFileFlag.hpp" +#include "cru/common/platform/win/Win32FileStream.hpp" + +#include + +#include +#include + +TEST(Win32FileStream, Work) { + using namespace cru; + using namespace cru::io; + using namespace cru::platform::win; + + auto temp_file_path = + (std::filesystem::temp_directory_path() / "cru_test_temp.XXXXXX") + .native(); + _wmktemp(temp_file_path.data()); + + String path = temp_file_path; + + Win32FileStream file(path, OpenFileFlags::Write | OpenFileFlags::Create); + file.Write("abc", 3); + file.Close(); + + Win32FileStream file2(path, OpenFileFlags::Read); + auto buffer = std::make_unique(3); + file2.Read(buffer.get(), 3); + ASSERT_EQ(std::string_view(reinterpret_cast(buffer.get()), 3), + "abc"); + file2.Close(); + + std::filesystem::remove(temp_file_path); +} -- cgit v1.2.3