diff --git a/DDrawCompat/Common/Hook.cpp b/DDrawCompat/Common/Hook.cpp index 48e0a82..3700e28 100644 --- a/DDrawCompat/Common/Hook.cpp +++ b/DDrawCompat/Common/Hook.cpp @@ -171,7 +171,8 @@ namespace break; } #ifdef DEBUGLOGS - oss << Compat::hexDump(prevTargetFunc, instructionSize) << " -> " << Compat::funcPtrToStr(targetFunc) << ' '; + Compat::LogStream(oss) << Compat::hexDump(prevTargetFunc, instructionSize) << " -> " + << Compat::funcPtrToStr(targetFunc) << ' '; #endif prevTargetFunc = targetFunc; } diff --git a/DDrawCompat/Common/Log.cpp b/DDrawCompat/Common/Log.cpp index 4f72eb1..a1db4c3 100644 --- a/DDrawCompat/Common/Log.cpp +++ b/DDrawCompat/Common/Log.cpp @@ -1,3 +1,5 @@ +#include + #include #include @@ -6,54 +8,21 @@ namespace Compat::CriticalSection g_logCs; } -std::ostream& operator<<(std::ostream& os, std::nullptr_t) -{ - return os << "null"; -} - -std::ostream& operator<<(std::ostream& os, const char* str) -{ - if (!str) - { - return os << "null"; - } - - if (!Compat::Log::isPointerDereferencingAllowed() || reinterpret_cast(str) <= 0xFFFF) - { - return os << static_cast(str); - } - - return os.write(str, strlen(str)); -} - -std::ostream& operator<<(std::ostream& os, const unsigned char* data) -{ - return os << static_cast(data); -} - -std::ostream& operator<<(std::ostream& os, const WCHAR* wstr) -{ - if (!wstr) - { - return os << "null"; - } - - if (!Compat::Log::isPointerDereferencingAllowed() || reinterpret_cast(wstr) <= 0xFFFF) - { - return os << static_cast(wstr); - } - - while (*wstr) - { - os.put(static_cast(*wstr)); - ++wstr; - } - - return os; -} - namespace Compat { + LogStream operator<<(LogStream os, const void* ptr) + { + if (ptr) + { + os.getStream() << '&' << static_cast(ptr); + } + else + { + os.getStream() << "null"; + } + return os; + } + Log::Log() : m_lock(g_logCs) { SYSTEMTIME st = {}; @@ -105,8 +74,7 @@ namespace Compat } thread_local DWORD Log::s_indent = 0; - thread_local DWORD Log::s_outParamDepth = 0; - thread_local bool Log::s_isLeaveLog = false; + bool Log::s_isLeaveLog = false; std::ofstream Log::s_logFile; } diff --git a/DDrawCompat/Common/Log.h b/DDrawCompat/Common/Log.h index 25915be..afbd1f8 100644 --- a/DDrawCompat/Common/Log.h +++ b/DDrawCompat/Common/Log.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -17,10 +17,12 @@ #ifdef DEBUGLOGS #define LOG_DEBUG Compat::Log() #define LOG_FUNC(...) Compat::LogFunc logFunc(__VA_ARGS__) +#define LOG_FUNC_CUSTOM(funcPtr, ...) Compat::LogFunc logFunc(__VA_ARGS__) #define LOG_RESULT(...) logFunc.setResult(__VA_ARGS__) #else #define LOG_DEBUG if constexpr (false) Compat::Log() #define LOG_FUNC(...) +#define LOG_FUNC_CUSTOM(funcPtr, ...) #define LOG_RESULT(...) __VA_ARGS__ #endif @@ -36,139 +38,208 @@ #define LOG_CONST_CASE(constant) case constant: return os << #constant; -std::ostream& operator<<(std::ostream& os, std::nullptr_t); -std::ostream& operator<<(std::ostream& os, const char* str); -std::ostream& operator<<(std::ostream& os, const unsigned char* data); -std::ostream& operator<<(std::ostream& os, const WCHAR* wstr); - -template -std::ostream& operator<<(std::ostream & os, const std::pair & pair) -{ - return Compat::LogStruct(os) - << pair.first - << pair.second; -} - namespace Compat { - using ::operator<<; - - namespace detail + template + struct IsPrintable : std::false_type { - using ::operator<<; + }; - template - struct Array + template + struct IsPrintable() << std::declval(), void())> : std::true_type + { + }; + + template + struct IsString : std::disjunction< + std::is_same>, + std::is_same>, + std::is_same>, + std::is_same>, + std::is_same>, + std::is_same>> + { + }; + + class LogStream + { + public: + explicit LogStream(std::ostream& os) : m_os(os) {} + + std::ostream& getStream() const { return m_os; } + operator std::ostream& () const { return m_os; } + + private: + std::ostream& m_os; + }; + + LogStream operator<<(LogStream os, const void* ptr); + + template + std::enable_if_t::value || std::is_class_v, LogStream> operator<<(LogStream os, const T& val) + { + if constexpr (IsPrintable::value) { - Array(const Elem* elem, const unsigned long size) : elem(elem), size(size) {} - const Elem* elem; - const unsigned long size; - }; - - template - struct Hex + os.getStream() << val; + } + else { - explicit Hex(T val) : val(val) {} - T val; - }; + os << static_cast(&val); + } + return os; + } - struct HexByte + template + LogStream operator<<(LogStream os, const T* ptr) + { + if constexpr (std::is_function_v) { - explicit HexByte(BYTE val) : val(val) {} - BYTE val; - }; - - template - struct Out + os.getStream() << ptr; + } + else if (!ptr) { - explicit Out(T val) : val(val) {} - T val; - }; - - class LogParams; - - class LogFirstParam + os.getStream() << "null"; + } + else if (reinterpret_cast(ptr) <= 0xFFFF) { - public: - LogFirstParam(std::ostream& os) : m_os(os) {} - template LogParams operator<<(const T& val) { m_os << val; return LogParams(m_os); } - - protected: - std::ostream& m_os; - }; - - class LogParams + os << static_cast(ptr); + } + else if constexpr (std::is_same_v || std::is_same_v) { - public: - LogParams(std::ostream& os) : m_os(os) {} - template LogParams& operator<<(const T& val) { m_os << ',' << val; return *this; } - - operator std::ostream&() { return m_os; } - - private: - std::ostream& m_os; - }; - - template - std::ostream& operator<<(std::ostream& os, Array array) - { - os << '['; - if (Log::isPointerDereferencingAllowed()) + while (*ptr) { - if (0 != array.size) - { - os << array.elem[0]; - } - for (unsigned long i = 1; i < array.size; ++i) - { - os << ',' << array.elem[i]; - } + os.getStream().put(static_cast(*ptr)); + ++ptr; } - return os << ']'; + } + else if constexpr (std::is_pointer_v || IsPrintable::value) + { + os << '*' << *ptr; + } + else + { + os << *ptr; } - template - std::ostream& operator<<(std::ostream& os, Hex hex) - { - return os << "0x" << std::hex << hex.val << std::dec; - } + return os; + } - inline std::ostream& operator<<(std::ostream& os, HexByte hexByte) - { - os.fill('0'); - os.width(2); - return os << std::hex << static_cast(hexByte.val) << std::dec; - } + template + LogStream operator<<(LogStream os, T* ptr) + { + return os << static_cast(ptr); + } - template - std::ostream& operator<<(std::ostream& os, Out out) - { - ++Log::s_outParamDepth; - os << out.val; - --Log::s_outParamDepth; - return os; - } + template + LogStream operator<<(LogStream os, const std::pair& pair) + { + return Compat::LogStruct(os) + << pair.first + << pair.second; } template - detail::Array array(const Elem* elem, const unsigned long size) + struct Array { - return detail::Array(elem, size); + Array(const Elem* elem, const unsigned long size) : elem(elem), size(size) {} + const Elem* elem; + const unsigned long size; + }; + + template + struct Hex + { + explicit Hex(T val) : val(val) {} + T val; + }; + + struct HexByte + { + explicit HexByte(BYTE val) : val(val) {} + BYTE val; + }; + + template + struct Out + { + explicit Out(const T& val) : val(val) {} + const T& val; + }; + + template + Array array(const Elem* elem, const unsigned long size) + { + return Array(elem, size); } - template detail::Hex hex(T val) + template + const void* getOutPtr(const T* val) { - return detail::Hex(val); + return val; } - inline detail::Array hexDump(const void* buf, const unsigned long size) + template + const void* getOutPtr(const Array& val) { - return detail::Array(static_cast(buf), size); + return val.elem; } - template detail::Out out(const T& val) + template + Hex hex(T val) { - return detail::Out(val); + return Hex(val); + } + + inline Array hexDump(const void* buf, const unsigned long size) + { + return Array(static_cast(buf), size); + } + + template + Out out(const T& val) + { + return Out(val); + } + + template + LogStream operator<<(LogStream os, Array array) + { + os << '['; + if (0 != array.size) + { + os << array.elem[0]; + } + for (unsigned long i = 1; i < array.size; ++i) + { + os << ',' << array.elem[i]; + } + return os << ']'; + } + + template + LogStream operator<<(LogStream os, Hex hex) + { + return os << "0x" << std::hex << hex.val << std::dec; + } + + inline LogStream operator<<(LogStream os, HexByte hexByte) + { + auto fill = os.getStream().fill('0'); + return os << std::setw(2) << std::hex << static_cast(hexByte.val) << std::dec << std::setfill(fill); + } + + template + LogStream operator<<(LogStream os, Out out) + { + if (Log::isLeaveLog()) + { + os << out.val; + } + else + { + os.getStream() << '<' << getOutPtr(out.val) << '>'; + } + return os; } class Log @@ -180,139 +251,199 @@ namespace Compat template Log& operator<<(const T& t) { - s_logFile << t; + LogStream(s_logFile) << t; return *this; } static void initLogging(std::filesystem::path processPath); - static bool isPointerDereferencingAllowed() { return s_isLeaveLog || 0 == s_outParamDepth; } - - protected: - template - Log(const char* prefix, const char* funcName, Params... params) : Log() - { - s_logFile << prefix << ' ' << funcName << '('; - toList(params...); - s_logFile << ')'; - } + static bool isLeaveLog() { return s_isLeaveLog; } private: - friend class LogFunc; - template friend std::ostream& detail::operator<<(std::ostream& os, detail::Out out); - - void toList() - { - } - - template - void toList(Param param) - { - s_logFile << param; - } - - template - void toList(Param firstParam, Params... remainingParams) - { - s_logFile << firstParam << ", "; - toList(remainingParams...); - } + friend class LogFuncBase; ScopedCriticalSection m_lock; static thread_local DWORD s_indent; - static thread_local DWORD s_outParamDepth; - static thread_local bool s_isLeaveLog; + static bool s_isLeaveLog; static std::ofstream s_logFile; }; - class LogFunc + template + class LogParam; + + template + class LogParam { public: template - LogFunc(const char* funcName, Params... params) - : m_printCall([=](Log& log) { log << funcName << '('; log.toList(params...); log << ')'; }) + static void log(Log& log, Params&... params) + { + auto& param = std::get(std::tie(params...)); + if constexpr (IsString::value) + { + if constexpr (!std::is_class_v) + { + if (reinterpret_cast(param) <= 0xFFFF) + { + log << param; + return; + } + } + log << '"' << param << '"'; + } + else + { + log << param; + } + } + }; + + template + class LogParam + { + public: + static void log(Log& log, Params... params) + { + LogParam::log(log, params...); + } + }; + + class LogFuncBase + { + public: + template + T setResult(T result) + { + m_logResult = [=](Log& log) { log << std::hex << result << std::dec; }; + return result; + } + + protected: + template + LogFuncBase(const char* funcName, std::function logParams) + : m_funcName(funcName) + , m_logParams(logParams) { Log log; log << "> "; - m_printCall(log); + logCall(log); Log::s_indent += 2; } - ~LogFunc() + ~LogFuncBase() { Log::s_isLeaveLog = true; Log::s_indent -= 2; Log log; log << "< "; - m_printCall(log); + logCall(log); - if (m_printResult) + if (m_logResult) { log << " = "; - m_printResult(log); + m_logResult(log); } Log::s_isLeaveLog = false; } - template - T setResult(T result) + template + auto packParam(Param&& param) { - m_printResult = [=](Log& log) { log << std::hex << result << std::dec; }; - return result; + if constexpr (std::is_lvalue_reference_v) + { + return std::cref(param); + } + else + { + return param; + } + } + + template + auto packParams(Params&&... params) + { + return std::make_tuple(packParam(std::forward(params))...); } private: - std::function m_printCall; - std::function m_printResult; + void logCall(Log& log) + { + log << m_funcName << '('; + m_logParams(log); + log << ')'; + } + + const char* m_funcName; + std::function m_logParams; + std::function m_logResult; }; - class LogStruct : public detail::LogFirstParam + template + class LogFunc : public LogFuncBase { public: - LogStruct(std::ostream& os) : detail::LogFirstParam(os) { m_os << '{'; } + template + LogFunc(const char* funcName, Params&&... params) + : LogFuncBase(funcName, [&, p = packParams(std::forward(params)...)](Log& log) { logParams(log, p); }) + { + } + + private: + template + void logParams(Log&) + { + } + + template + void logParams(Log& log, Params&... params) + { + if constexpr (paramIndex > 0) + { + log << ", "; + } + + LogParam::log(log, params...); + + if constexpr (paramIndex + 1 < sizeof...(Params)) + { + logParams(log, params...); + } + } + + template + void logParams(Log& log, const Pack& pack) + { + std::apply([&](auto&... params) { logParams<0>(log, params...); }, pack); + } + }; + + class LogStruct + { + public: + LogStruct(std::ostream& os) : m_os(os), m_isFirst(true) { m_os << '{'; } ~LogStruct() { m_os << '}'; } + + template + LogStruct& operator<<(const T& val) + { + if (m_isFirst) + { + m_isFirst = false; + } + else + { + m_os << ','; + } + m_os << val; + return *this; + } + + operator LogStream() const { return m_os; } + operator std::ostream& () const { return m_os.getStream(); } + + private: + LogStream m_os; + bool m_isFirst; }; } - -template -typename std::enable_if::value && !std::is_same::value, std::ostream&>::type -operator<<(std::ostream& os, const T& t) -{ - return os << static_cast(&t); -} - -template -typename std::enable_if::value, std::ostream&>::type -operator<<(std::ostream& os, T* t) -{ - if (!t) - { - return os << "null"; - } - - if (!Compat::Log::isPointerDereferencingAllowed() || reinterpret_cast(t) <= 0xFFFF) - { - return os << static_cast(t); - } - - return os << *t; -} - -template -std::ostream& operator<<(std::ostream& os, T** t) -{ - if (!t) - { - return os << "null"; - } - - os << static_cast(t); - - if (!Compat::Log::isPointerDereferencingAllowed() || reinterpret_cast(t) <= 0xFFFF) - { - return os; - } - - return os << '=' << *t; -} diff --git a/DDrawCompat/D3dDdi/AdapterCallbacks.h b/DDrawCompat/D3dDdi/AdapterCallbacks.h index 7a4b8de..c80a4aa 100644 --- a/DDrawCompat/D3dDdi/AdapterCallbacks.h +++ b/DDrawCompat/D3dDdi/AdapterCallbacks.h @@ -3,6 +3,8 @@ #include #include +#include + namespace D3dDdi { namespace AdapterCallbacks diff --git a/DDrawCompat/D3dDdi/Log/AdapterCallbacksLog.cpp b/DDrawCompat/D3dDdi/Log/AdapterCallbacksLog.cpp new file mode 100644 index 0000000..ab36b69 --- /dev/null +++ b/DDrawCompat/D3dDdi/Log/AdapterCallbacksLog.cpp @@ -0,0 +1,17 @@ +#include +#include + +std::ostream& operator<<(std::ostream& os, const D3DDDICB_QUERYADAPTERINFO& data) +{ + return Compat::LogStruct(os) + << data.pPrivateDriverData + << data.PrivateDriverDataSize; +} + +std::ostream& operator<<(std::ostream& os, const D3DDDICB_QUERYADAPTERINFO2& data) +{ + return Compat::LogStruct(os) + << data.QueryType + << data.pPrivateDriverData + << data.PrivateDriverDataSize; +} diff --git a/DDrawCompat/D3dDdi/Log/AdapterCallbacksLog.h b/DDrawCompat/D3dDdi/Log/AdapterCallbacksLog.h new file mode 100644 index 0000000..d862cab --- /dev/null +++ b/DDrawCompat/D3dDdi/Log/AdapterCallbacksLog.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include +#include + +#include + +std::ostream& operator<<(std::ostream& os, const D3DDDICB_QUERYADAPTERINFO& data); +std::ostream& operator<<(std::ostream& os, const D3DDDICB_QUERYADAPTERINFO2& data); diff --git a/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.cpp b/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.cpp index 72071b1..07431a8 100644 --- a/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.cpp +++ b/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.cpp @@ -1,24 +1,6 @@ #include #include -std::ostream& operator<<(std::ostream& os, const D3DDDI_ALLOCATIONLIST& data) -{ - return Compat::LogStruct(os) - << Compat::hex(data.hAllocation) - << Compat::hex(data.Value); -} - -std::ostream& operator<<(std::ostream& os, const D3DDDI_PATCHLOCATIONLIST& data) -{ - return Compat::LogStruct(os) - << data.AllocationIndex - << Compat::hex(data.Value) - << Compat::hex(data.DriverId) - << Compat::hex(data.AllocationOffset) - << Compat::hex(data.PatchOffset) - << Compat::hex(data.SplitOffset); -} - std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATEDEVICE& data) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.h b/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.h index c7893f3..3f39003 100644 --- a/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.h +++ b/DDrawCompat/D3dDdi/Log/AdapterFuncsLog.h @@ -7,8 +7,6 @@ #include -std::ostream& operator<<(std::ostream& os, const D3DDDI_ALLOCATIONLIST& data); -std::ostream& operator<<(std::ostream& os, const D3DDDI_PATCHLOCATIONLIST& data); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CREATEDEVICE& data); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_GETCAPS& data); std::ostream& operator<<(std::ostream& os, D3DDDICAPS_TYPE data); diff --git a/DDrawCompat/D3dDdi/Log/CommonLog.cpp b/DDrawCompat/D3dDdi/Log/CommonLog.cpp index 9ac4cb9..1273606 100644 --- a/DDrawCompat/D3dDdi/Log/CommonLog.cpp +++ b/DDrawCompat/D3dDdi/Log/CommonLog.cpp @@ -3,6 +3,24 @@ #include #include +std::ostream& operator<<(std::ostream& os, const D3DDDI_ALLOCATIONLIST& data) +{ + return Compat::LogStruct(os) + << Compat::hex(data.hAllocation) + << Compat::hex(data.Value); +} + +std::ostream& operator<<(std::ostream& os, const D3DDDI_PATCHLOCATIONLIST& data) +{ + return Compat::LogStruct(os) + << data.AllocationIndex + << Compat::hex(data.Value) + << Compat::hex(data.DriverId) + << Compat::hex(data.AllocationOffset) + << Compat::hex(data.PatchOffset) + << Compat::hex(data.SplitOffset); +} + std::ostream& operator<<(std::ostream& os, const D3DDDI_RATIONAL& val) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/CommonLog.h b/DDrawCompat/D3dDdi/Log/CommonLog.h index 02bf02c..6a92c60 100644 --- a/DDrawCompat/D3dDdi/Log/CommonLog.h +++ b/DDrawCompat/D3dDdi/Log/CommonLog.h @@ -5,5 +5,7 @@ #include #include +std::ostream& operator<<(std::ostream& os, const D3DDDI_ALLOCATIONLIST& data); +std::ostream& operator<<(std::ostream& os, const D3DDDI_PATCHLOCATIONLIST& data); std::ostream& operator<<(std::ostream& os, const D3DDDI_RATIONAL& val); std::ostream& operator<<(std::ostream& os, D3DDDIFORMAT val); diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp index 843cce6..792eba0 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.cpp @@ -15,6 +15,14 @@ std::ostream& operator<<(std::ostream& os, D3DDDI_POOL val) return os << "D3DDDIPOOL_" << static_cast(val); } +std::ostream& operator<<(std::ostream& os, const D3DDDI_OPENALLOCATIONINFO& val) +{ + return Compat::LogStruct(os) + << Compat::hex(val.hAllocation) + << val.pPrivateDriverData + << val.PrivateDriverDataSize; +} + std::ostream& operator<<(std::ostream& os, const D3DDDI_SURFACEINFO& val) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h index f8e9782..3ff698c 100644 --- a/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h +++ b/DDrawCompat/D3dDdi/Log/DeviceFuncsLog.h @@ -8,6 +8,7 @@ #include std::ostream& operator<<(std::ostream& os, D3DDDI_POOL val); +std::ostream& operator<<(std::ostream& os, const D3DDDI_OPENALLOCATIONINFO& val); std::ostream& operator<<(std::ostream& os, const D3DDDI_SURFACEINFO& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_BLT& val); std::ostream& operator<<(std::ostream& os, const D3DDDIARG_CLEAR& val); diff --git a/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp b/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp index a604def..34d9bbb 100644 --- a/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp +++ b/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp @@ -129,6 +129,16 @@ std::ostream& operator<<(std::ostream& os, const D3DKMT_QUERYADAPTERINFO& data) << data.PrivateDriverDataSize; } +std::ostream& operator<<(std::ostream& os, const D3DKMT_SETGAMMARAMP& data) +{ + return Compat::LogStruct(os) + << Compat::hex(data.hDevice) + << data.VidPnSourceId + << data.Type + << static_cast(data.pGammaRampRgb256x3x16) + << data.Size; +} + std::ostream& operator<<(std::ostream& os, const D3DKMT_SETQUEUEDLIMIT& data) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.h b/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.h index 56b6e9a..54eaf3b 100644 --- a/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.h +++ b/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.h @@ -19,6 +19,7 @@ std::ostream& operator<<(std::ostream& os, const D3DKMT_DESTROYDEVICE& data); std::ostream& operator<<(std::ostream& os, const D3DKMT_OPENADAPTERFROMHDC& data); std::ostream& operator<<(std::ostream& os, const D3DKMT_PRESENT& data); std::ostream& operator<<(std::ostream& os, const D3DKMT_QUERYADAPTERINFO& data); +std::ostream& operator<<(std::ostream& os, const D3DKMT_SETGAMMARAMP& data); std::ostream& operator<<(std::ostream& os, const D3DKMT_SETQUEUEDLIMIT& data); std::ostream& operator<<(std::ostream& os, const D3DKMT_SETVIDPNSOURCEOWNER& data); std::ostream& operator<<(std::ostream& os, const D3DKMT_SETVIDPNSOURCEOWNER1& data); diff --git a/DDrawCompat/DDraw/DirectDraw.cpp b/DDrawCompat/DDraw/DirectDraw.cpp index 385841a..d78d8a7 100644 --- a/DDrawCompat/DDraw/DirectDraw.cpp +++ b/DDrawCompat/DDraw/DirectDraw.cpp @@ -105,15 +105,13 @@ namespace void logSrcColorKeySupportFailure(const char* reason, UINT32 resultCode) { - std::ostringstream oss; - oss << "Source color key support: no (" << reason; + Compat::Log log; + log << "Source color key support: no (" << reason; if (resultCode) { - oss << ": " << Compat::hex(resultCode); + log << ": " << Compat::hex(resultCode); } - oss << ')'; - - Compat::Log() << oss.str(); + log << ')'; } template diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 0b4dd65..28c49da 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -234,6 +234,7 @@ + @@ -349,6 +350,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index 6a4095c..7ae97bb 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -492,6 +492,9 @@ Header Files\Overlay + + Header Files\D3dDdi\Log + @@ -779,6 +782,9 @@ Source Files\Overlay + + Source Files\D3dDdi\Log + diff --git a/DDrawCompat/Gdi/DcFunctions.cpp b/DDrawCompat/Gdi/DcFunctions.cpp index 40f7fa6..39f22df 100644 --- a/DDrawCompat/Gdi/DcFunctions.cpp +++ b/DDrawCompat/Gdi/DcFunctions.cpp @@ -9,6 +9,109 @@ #include #include +namespace +{ + template + void logString(Compat::Log& log, const Char* str, int length) + { + log << '"'; + if (length < 0) + { + log << str; + } + else + { + for (int i = 0; i < length; ++i) + { + log << static_cast(str[i]); + } + } + log << '"'; + } + + template + void logExtTextOutString(Compat::Log& log, UINT options, const Char* lpString, UINT c) + { + if (options & ETO_GLYPH_INDEX) + { + log << static_cast(lpString); + } + else + { + logString(log, lpString, c); + } + } +} + +namespace Compat +{ + template <> + void LogParam<&DrawEscape, 3>::log(Log& log, HDC, int, int, LPCSTR lpIn) + { + log << static_cast(lpIn); + } + + template <> + void LogParam<&DrawTextA, 1>::log(Log& log, HDC, LPCSTR lpchText, int cchText, LPRECT, UINT) + { + logString(log, lpchText, cchText); + } + + template <> + void LogParam<&DrawTextW, 1>::log(Log& log, HDC, LPCWSTR lpchText, int cchText, LPRECT, UINT) + { + logString(log, lpchText, cchText); + } + + template <> + void LogParam<&DrawTextExA, 1>::log(Log& log, HDC, LPSTR lpchText, int cchText, LPRECT, UINT, LPDRAWTEXTPARAMS) + { + logString(log, lpchText, cchText); + } + + template <> + void LogParam<&DrawTextExW, 1>::log(Log& log, HDC, LPWSTR lpchText, int cchText, LPRECT, UINT, LPDRAWTEXTPARAMS) + { + logString(log, lpchText, cchText); + } + + template <> + void LogParam<&ExtTextOutA, 5>::log(Log& log, HDC, int, int, UINT options, const RECT*, LPCSTR lpString, UINT c, const INT*) + { + logExtTextOutString(log, options, lpString, c); + } + + template <> + void LogParam<&ExtTextOutW, 5>::log(Log& log, HDC, int, int, UINT options, const RECT*, LPCWSTR lpString, UINT c, const INT*) + { + logExtTextOutString(log, options, lpString, c); + } + + template <> + void LogParam<&TabbedTextOutA, 3>::log(Log& log, HDC, int, int, LPCSTR lpString, int chCount, int, const INT*, int) + { + logString(log, lpString, chCount); + } + + template <> + void LogParam<&TabbedTextOutW, 3>::log(Log& log, HDC, int, int, LPCWSTR lpString, int chCount, int, const INT*, int) + { + logString(log, lpString, chCount); + } + + template <> + void LogParam<&TextOutA, 3>::log(Log& log, HDC, int, int, LPCSTR lpString, int c) + { + logString(log, lpString, c); + } + + template <> + void LogParam<&TextOutW, 3>::log(Log& log, HDC, int, int, LPCWSTR lpString, int c) + { + logString(log, lpString, c); + } +} + namespace { template @@ -94,7 +197,7 @@ namespace template Result WINAPI compatGdiDcFunc(HDC hdc, Params... params) { - LOG_FUNC(g_funcName, hdc, params...); + LOG_FUNC_CUSTOM(origFunc, g_funcName, hdc, params...); if (hasDisplayDcArg(hdc, params...)) { @@ -116,7 +219,7 @@ namespace BOOL WINAPI compatGdiDcFunc<&ExtTextOutW>( HDC hdc, int x, int y, UINT options, const RECT* lprect, LPCWSTR lpString, UINT c, const INT* lpDx) { - LOG_FUNC("ExtTextOutW", hdc, x, y, options, lprect, lpString, c, lpDx); + LOG_FUNC_CUSTOM(&ExtTextOutW, "ExtTextOutW", hdc, x, y, options, lprect, lpString, c, lpDx); if (hasDisplayDcArg(hdc)) { diff --git a/DDrawCompat/Win32/Log.cpp b/DDrawCompat/Win32/Log.cpp index dce084c..2b27a50 100644 --- a/DDrawCompat/Win32/Log.cpp +++ b/DDrawCompat/Win32/Log.cpp @@ -6,6 +6,28 @@ namespace { + template + class ParamConverter + { + public: + template + static T& convert(Param& param) + { + return *reinterpret_cast(¶m); + } + }; + + template + class ParamConverter> + { + public: + template + static Compat::Out convert(Param& param) + { + return Compat::out(ParamConverter::convert(param)); + } + }; + template std::ostream& logCreateStruct(std::ostream& os, const CreateStruct& cs) { @@ -139,16 +161,13 @@ std::ostream& operator<<(std::ostream& os, const GESTURENOTIFYSTRUCT& gns) << gns.dwInstanceID; } -std::ostream& operator<<(std::ostream& os, HDC dc) +std::ostream& operator<<(std::ostream& os, const HDC__& dc) { os << "DC"; - if (!dc) - { - return os << "(null)"; - } + HDC hdc = const_cast(&dc); return Compat::LogStruct(os) - << static_cast(dc) - << CALL_ORIG_FUNC(WindowFromDC)(dc); + << static_cast(hdc) + << CALL_ORIG_FUNC(WindowFromDC)(hdc); } std::ostream& operator<<(std::ostream& os, const HELPINFO& hi) @@ -172,27 +191,21 @@ std::ostream& operator<<(std::ostream& os, const HELPINFO& hi) << hi.MousePos; } -std::ostream& operator<<(std::ostream& os, HFONT font) +std::ostream& operator<<(std::ostream& os, const HFONT__& font) { + HFONT hfont = const_cast(&font); LOGFONT lf = {}; - if (font) - { - GetObject(font, sizeof(lf), &lf); - } + GetObject(hfont, sizeof(lf), &lf); return Compat::LogStruct(os) - << static_cast(font) - << (font ? &lf : nullptr); + << static_cast(hfont) + << lf; } -std::ostream& operator<<(std::ostream& os, HRGN rgn) +std::ostream& operator<<(std::ostream& os, const HRGN__& rgn) { os << "RGN"; - if (!rgn) - { - return os << "(null)"; - } - - DWORD size = GetRegionData(rgn, 0, nullptr); + HRGN hrgn = const_cast(&rgn); + DWORD size = GetRegionData(hrgn, 0, nullptr); if (0 == size) { return os << "[]"; @@ -200,19 +213,16 @@ std::ostream& operator<<(std::ostream& os, HRGN rgn) std::vector rgnDataBuf(size); auto& rgnData = *reinterpret_cast(rgnDataBuf.data()); - GetRegionData(rgn, size, &rgnData); + GetRegionData(hrgn, size, &rgnData); - return os << Compat::array(reinterpret_cast(rgnData.Buffer), rgnData.rdh.nCount); + Compat::LogStream(os) << Compat::array(reinterpret_cast(rgnData.Buffer), rgnData.rdh.nCount); + return os; } -std::ostream& operator<<(std::ostream& os, HWND hwnd) +std::ostream& operator<<(std::ostream& os, const HWND__& wnd) { os << "WND"; - if (!hwnd) - { - return os << "(null)"; - } - + HWND hwnd = const_cast(&wnd); if (!IsWindow(hwnd)) { return Compat::LogStruct(os) @@ -409,7 +419,7 @@ std::ostream& operator<<(std::ostream& os, const WINDOWPOS& wp) namespace Compat { - std::ostream& operator<<(std::ostream& os, WindowMessage msg) + LogStream operator<<(LogStream os, WindowMessage msg) { #define LOG_WM_CASE(msg) case msg: return os << #msg; switch (msg.msg) @@ -659,33 +669,31 @@ namespace Compat }; #undef LOG_WM_CASE - os.width(4); - os.fill('0'); - os << "WM_" << std::hex << msg.msg << std::dec; - return os; + return os << "WM_" << std::hex << msg.msg << std::dec; } - std::ostream& operator<<(std::ostream& os, WindowMessage16 msg) + LogStream operator<<(LogStream os, WindowMessage16 msg) { return os << WindowMessage(msg.msg); } - std::ostream& operator<<(std::ostream& os, WindowMessageStruct wm) + LogStream operator<<(LogStream os, WindowMessageStruct wm) { - os << '{' << wm.hwnd << ',' << wm.msg << ','; + Compat::LogStruct log(os); + log << wm.hwnd << wm.msg; #define LOG_PARAM_CASE_1(param, msg, ...) \ case msg: \ static_assert(sizeof(__VA_ARGS__) == sizeof(param)); \ - os << *reinterpret_cast(¶m); \ + log << ParamConverter<__VA_ARGS__>::convert(param); \ break #define LOG_PARAM_CASE_2(param, msg, TypeA, TypeW) \ case msg: \ if (IsWindowUnicode(wm.hwnd)) \ - os << *reinterpret_cast(¶m); \ + log << ParamConverter::convert(param); \ else \ - os << *reinterpret_cast(¶m); \ + log << ParamConverter::convert(param); \ break; #define LOG_WPARAM_CASE_1(msg, ...) LOG_PARAM_CASE_1(wm.wParam, msg, __VA_ARGS__) @@ -697,7 +705,7 @@ namespace Compat LOG_WPARAM_CASE_1(WM_APPCOMMAND, HWND); LOG_WPARAM_CASE_1(WM_ASKCBFORMATNAME, DWORD); LOG_WPARAM_CASE_1(WM_CHANGECBCHAIN, HWND); - LOG_WPARAM_CASE_1(WM_CHANGEUISTATE, std::pair>); + LOG_WPARAM_CASE_1(WM_CHANGEUISTATE, std::pair>); LOG_WPARAM_CASE_1(WM_CHARTOITEM, std::pair); LOG_WPARAM_CASE_1(WM_CTLCOLORMSGBOX, HDC); LOG_WPARAM_CASE_1(WM_CTLCOLOREDIT, HDC); @@ -706,7 +714,7 @@ namespace Compat LOG_WPARAM_CASE_1(WM_CTLCOLORDLG, HDC); LOG_WPARAM_CASE_1(WM_CTLCOLORSCROLLBAR, HDC); LOG_WPARAM_CASE_1(WM_CTLCOLORSTATIC, HDC); - LOG_WPARAM_CASE_1(WM_COMMAND, std::pair, WORD>); + LOG_WPARAM_CASE_1(WM_COMMAND, std::pair, WORD>); LOG_WPARAM_CASE_1(WM_CONTEXTMENU, HWND); LOG_WPARAM_CASE_1(WM_COPYDATA, HWND); LOG_WPARAM_CASE_1(WM_DISPLAYCHANGE, INT); @@ -726,14 +734,14 @@ namespace Compat LOG_WPARAM_CASE_1(WM_MDIMAXIMIZE, HWND); LOG_WPARAM_CASE_1(WM_MDINEXT, HWND); LOG_WPARAM_CASE_1(WM_MDIRESTORE, HWND); - LOG_WPARAM_CASE_1(WM_MENUCHAR, std::pair, Compat::detail::Hex>); + LOG_WPARAM_CASE_1(WM_MENUCHAR, std::pair, Hex>); LOG_WPARAM_CASE_1(WM_MENUCOMMAND, DWORD); LOG_WPARAM_CASE_1(WM_MENUDRAG, DWORD); LOG_WPARAM_CASE_1(WM_MENURBUTTONUP, DWORD); - LOG_WPARAM_CASE_1(WM_MENUSELECT, std::pair>); + LOG_WPARAM_CASE_1(WM_MENUSELECT, std::pair>); LOG_WPARAM_CASE_1(WM_MOUSEACTIVATE, HWND); - LOG_WPARAM_CASE_1(WM_MOUSEHWHEEL, std::pair, SHORT>); - LOG_WPARAM_CASE_1(WM_MOUSEWHEEL, std::pair, SHORT>); + LOG_WPARAM_CASE_1(WM_MOUSEHWHEEL, std::pair, SHORT>); + LOG_WPARAM_CASE_1(WM_MOUSEWHEEL, std::pair, SHORT>); LOG_WPARAM_CASE_1(WM_NCLBUTTONDBLCLK, INT); LOG_WPARAM_CASE_1(WM_NCLBUTTONDOWN, INT); LOG_WPARAM_CASE_1(WM_NCLBUTTONUP, INT); @@ -746,51 +754,51 @@ namespace Compat LOG_WPARAM_CASE_1(WM_NCPOINTERDOWN, std::pair); LOG_WPARAM_CASE_1(WM_NCPOINTERUP, std::pair); LOG_WPARAM_CASE_1(WM_NCPOINTERUPDATE, std::pair); - LOG_WPARAM_CASE_1(WM_NCXBUTTONDBLCLK, std::pair, WORD>); - LOG_WPARAM_CASE_1(WM_NCXBUTTONDOWN, std::pair, WORD>); - LOG_WPARAM_CASE_1(WM_NCXBUTTONUP, std::pair, WORD>); + LOG_WPARAM_CASE_1(WM_NCXBUTTONDBLCLK, std::pair, WORD>); + LOG_WPARAM_CASE_1(WM_NCXBUTTONDOWN, std::pair, WORD>); + LOG_WPARAM_CASE_1(WM_NCXBUTTONUP, std::pair, WORD>); LOG_WPARAM_CASE_1(WM_NOTIFYFORMAT, HWND); LOG_WPARAM_CASE_1(WM_PALETTECHANGED, HWND); LOG_WPARAM_CASE_1(WM_PALETTEISCHANGING, HWND); - LOG_WPARAM_CASE_1(WM_PARENTNOTIFY, std::pair>); + LOG_WPARAM_CASE_1(WM_PARENTNOTIFY, std::pair>); LOG_WPARAM_CASE_1(WM_POINTERACTIVATE, std::pair); - LOG_WPARAM_CASE_1(WM_POINTERDOWN, std::pair>); - LOG_WPARAM_CASE_1(WM_POINTERENTER, std::pair>); + LOG_WPARAM_CASE_1(WM_POINTERDOWN, std::pair>); + LOG_WPARAM_CASE_1(WM_POINTERENTER, std::pair>); LOG_WPARAM_CASE_1(WM_POINTERHWHEEL, std::pair); - LOG_WPARAM_CASE_1(WM_POINTERLEAVE, std::pair>); - LOG_WPARAM_CASE_1(WM_POINTERUP, std::pair>); - LOG_WPARAM_CASE_1(WM_POINTERUPDATE, std::pair>); + LOG_WPARAM_CASE_1(WM_POINTERLEAVE, std::pair>); + LOG_WPARAM_CASE_1(WM_POINTERUP, std::pair>); + LOG_WPARAM_CASE_1(WM_POINTERUPDATE, std::pair>); LOG_WPARAM_CASE_1(WM_POINTERWHEEL, std::pair); LOG_WPARAM_CASE_1(WM_PRINT, HDC); LOG_WPARAM_CASE_1(WM_PRINTCLIENT, HDC); LOG_WPARAM_CASE_1(WM_SETFOCUS, HWND); LOG_WPARAM_CASE_1(WM_SETFONT, HFONT); - LOG_WPARAM_CASE_1(WM_SETHOTKEY, std::pair, Compat::detail::Hex>); + LOG_WPARAM_CASE_1(WM_SETHOTKEY, std::pair, Hex>); LOG_WPARAM_CASE_1(WM_SETTEXT, DWORD); LOG_WPARAM_CASE_1(WM_SIZECLIPBOARD, HWND); LOG_WPARAM_CASE_1(WM_STYLECHANGED, INT); LOG_WPARAM_CASE_1(WM_STYLECHANGING, INT); - LOG_WPARAM_CASE_1(WM_UPDATEUISTATE, std::pair>); - LOG_WPARAM_CASE_1(WM_VKEYTOITEM, std::pair, WORD>); + LOG_WPARAM_CASE_1(WM_UPDATEUISTATE, std::pair>); + LOG_WPARAM_CASE_1(WM_VKEYTOITEM, std::pair, WORD>); LOG_WPARAM_CASE_1(WM_VSCROLL, std::pair); LOG_WPARAM_CASE_1(WM_VSCROLLCLIPBOARD, HWND); - LOG_WPARAM_CASE_1(WM_XBUTTONDBLCLK, std::pair, WORD>); - LOG_WPARAM_CASE_1(WM_XBUTTONDOWN, std::pair, WORD>); - LOG_WPARAM_CASE_1(WM_XBUTTONUP, std::pair, WORD>); + LOG_WPARAM_CASE_1(WM_XBUTTONDBLCLK, std::pair, WORD>); + LOG_WPARAM_CASE_1(WM_XBUTTONDOWN, std::pair, WORD>); + LOG_WPARAM_CASE_1(WM_XBUTTONUP, std::pair, WORD>); case WM_NEXTDLGCTL: if (wm.lParam) { - os << reinterpret_cast(wm.wParam); + log << reinterpret_cast(wm.wParam); } else { - os << wm.wParam; + log << wm.wParam; } break; default: - os << Compat::hex(wm.wParam); + log << hex(wm.wParam); break; } @@ -800,12 +808,10 @@ namespace Compat #define LOG_LPARAM_CASE_1(msg, ...) LOG_PARAM_CASE_1(wm.lParam, msg, __VA_ARGS__) #define LOG_LPARAM_CASE_2(msg, TypeA, TypeW) LOG_PARAM_CASE_2(wm.lParam, msg, TypeA, TypeW) - os << ','; - switch (wm.msg.msg) { LOG_LPARAM_CASE_1(WM_ACTIVATE, HWND); - LOG_LPARAM_CASE_2(WM_ASKCBFORMATNAME, Compat::detail::Out, Compat::detail::Out); + LOG_LPARAM_CASE_2(WM_ASKCBFORMATNAME, Out, Out); LOG_LPARAM_CASE_1(WM_CAPTURECHANGED, HWND); LOG_LPARAM_CASE_1(WM_CHANGECBCHAIN, HWND); LOG_LPARAM_CASE_1(WM_CHARTOITEM, HWND); @@ -833,9 +839,9 @@ namespace Compat LOG_LPARAM_CASE_1(WM_GETDPISCALEDSIZE, SIZE*); LOG_LPARAM_CASE_1(WM_GETICON, DWORD); LOG_LPARAM_CASE_1(WM_GETMINMAXINFO, MINMAXINFO*); - LOG_LPARAM_CASE_2(WM_GETTEXT, Compat::detail::Out, Compat::detail::Out); + LOG_LPARAM_CASE_2(WM_GETTEXT, Out, Out); LOG_LPARAM_CASE_1(WM_HELP, HELPINFO*); - LOG_LPARAM_CASE_1(WM_HOTKEY, std::pair, Compat::detail::Hex>); + LOG_LPARAM_CASE_1(WM_HOTKEY, std::pair, Hex>); LOG_LPARAM_CASE_1(WM_HSCROLL, HWND); LOG_LPARAM_CASE_1(WM_HSCROLLCLIPBOARD, std::pair); LOG_LPARAM_CASE_1(WM_INITMENUPOPUP, std::pair); @@ -849,7 +855,7 @@ namespace Compat LOG_LPARAM_CASE_1(WM_MDIGETACTIVE, BOOL*); LOG_LPARAM_CASE_1(WM_MEASUREITEM, MEASUREITEMSTRUCT*); LOG_LPARAM_CASE_1(WM_MENUGETOBJECT, MENUGETOBJECTINFO*); - LOG_LPARAM_CASE_1(WM_MOUSEACTIVATE, std::pair>); + LOG_LPARAM_CASE_1(WM_MOUSEACTIVATE, std::pair>); LOG_LPARAM_CASE_1(WM_MOUSEHOVER, POINTS); LOG_LPARAM_CASE_1(WM_MOUSEHWHEEL, POINTS); LOG_LPARAM_CASE_1(WM_MOUSEMOVE, POINTS); @@ -890,7 +896,7 @@ namespace Compat LOG_LPARAM_CASE_1(WM_RBUTTONDBLCLK, POINTS); LOG_LPARAM_CASE_1(WM_RBUTTONDOWN, POINTS); LOG_LPARAM_CASE_1(WM_RBUTTONUP, POINTS); - LOG_LPARAM_CASE_1(WM_SETCURSOR, std::pair>); + LOG_LPARAM_CASE_1(WM_SETCURSOR, std::pair>); LOG_LPARAM_CASE_2(WM_SETTEXT, LPCSTR, LPCWSTR); LOG_LPARAM_CASE_2(WM_SETTINGCHANGE, LPCSTR, LPCWSTR); LOG_LPARAM_CASE_1(WM_SIZE, POINTS); @@ -912,27 +918,27 @@ namespace Compat case WM_NCACTIVATE: if (-1 == wm.lParam) { - os << "-1"; + log << "-1"; } else { - os << reinterpret_cast(wm.lParam); + log << reinterpret_cast(wm.lParam); } break; case WM_NCCALCSIZE: if (wm.wParam) { - os << reinterpret_cast(wm.lParam); + log << reinterpret_cast(wm.lParam); } else { - os << reinterpret_cast(wm.lParam); + log << reinterpret_cast(wm.lParam); } break; default: - os << Compat::hex(wm.lParam); + log << hex(wm.lParam); break; } @@ -941,7 +947,6 @@ namespace Compat #undef LOG_PARAM_CASE_1 #undef LOG_PARAM_CASE_2 - os << '}'; return os; } } diff --git a/DDrawCompat/Win32/Log.h b/DDrawCompat/Win32/Log.h index 772c381..0f2b9ec 100644 --- a/DDrawCompat/Win32/Log.h +++ b/DDrawCompat/Win32/Log.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include @@ -16,11 +15,11 @@ std::ostream& operator<<(std::ostream& os, const DEVMODEA& dm); std::ostream& operator<<(std::ostream& os, const DEVMODEW& dm); std::ostream& operator<<(std::ostream& os, const DRAWITEMSTRUCT& dis); std::ostream& operator<<(std::ostream& os, const GESTURENOTIFYSTRUCT& gns); -std::ostream& operator<<(std::ostream& os, HDC dc); +std::ostream& operator<<(std::ostream& os, const HDC__& dc); std::ostream& operator<<(std::ostream& os, const HELPINFO& hi); -std::ostream& operator<<(std::ostream& os, HFONT font); -std::ostream& operator<<(std::ostream& os, HRGN rgn); -std::ostream& operator<<(std::ostream& os, HWND hwnd); +std::ostream& operator<<(std::ostream& os, const HFONT__& font); +std::ostream& operator<<(std::ostream& os, const HRGN__& rgn); +std::ostream& operator<<(std::ostream& os, const HWND__& wnd); std::ostream& operator<<(std::ostream& os, const LOGFONT& lf); std::ostream& operator<<(std::ostream& os, const MDICREATESTRUCTA& mcs); std::ostream& operator<<(std::ostream& os, const MDICREATESTRUCTW& mcs); @@ -43,6 +42,8 @@ std::ostream& operator<<(std::ostream& os, const WINDOWPOS& wp); namespace Compat { + class LogStream; + struct WindowMessage { UINT msg; @@ -70,7 +71,7 @@ namespace Compat } }; - std::ostream& operator<<(std::ostream& os, WindowMessage msg); - std::ostream& operator<<(std::ostream& os, WindowMessage16 msg); - std::ostream& operator<<(std::ostream& os, WindowMessageStruct wm); + LogStream operator<<(LogStream os, WindowMessage msg); + LogStream operator<<(LogStream os, WindowMessage16 msg); + LogStream operator<<(LogStream os, WindowMessageStruct wm); }