/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Debug output operators for Windows-specific types. For use in SAL_INFO(), SAL_WARN(), and * friends. The exact format of the generated output is not guaranteed to be stable or contain * complete information. */ #ifndef INCLUDED_COMPHELPER_WINDOWSDEBUGOUTPUT_HXX #define INCLUDED_COMPHELPER_WINDOWSDEBUGOUTPUT_HXX // If you get a warning about being deprecated from VS2017, you need to add a "#define // _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1" to your source file before any #include // statements. It would not be enough to have that here. See // https://blogs.msdn.microsoft.com/vcblog/2017/12/08/c17-feature-removals-and-deprecations/ #include #include #include #include #include #ifdef LIBO_INTERNAL_ONLY #include #include #else #include #endif #include namespace { DEFINE_GUID(IID_IdentityUnmarshal, 0x0000001B, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); } template inline std::basic_ostream& operator<<(std::basic_ostream& stream, const IID& rIid) { LPOLESTR pRiid; if (StringFromIID(rIid, &pRiid) != S_OK) return stream << "?"; stream << std::wstring_convert, wchar_t>().to_bytes( std::wstring(pRiid)); DWORD nSize; if (RegGetValueW(HKEY_CLASSES_ROOT, std::wstring(L"CLSID\\").append(pRiid).data(), NULL, RRF_RT_REG_SZ, NULL, NULL, &nSize) == ERROR_SUCCESS) { std::vector sValue(nSize / 2); if (RegGetValueW(HKEY_CLASSES_ROOT, std::wstring(L"CLSID\\").append(pRiid).data(), NULL, RRF_RT_REG_SZ, NULL, sValue.data(), &nSize) == ERROR_SUCCESS) { stream << "=\"" << std::wstring_convert, wchar_t>().to_bytes( std::wstring(sValue.data())) << "\""; } } else if (RegGetValueW(HKEY_CLASSES_ROOT, std::wstring(L"Interface\\").append(pRiid).data(), NULL, RRF_RT_REG_SZ, NULL, NULL, &nSize) == ERROR_SUCCESS) { std::vector sValue(nSize / 2); if (RegGetValueW(HKEY_CLASSES_ROOT, std::wstring(L"Interface\\").append(pRiid).data(), NULL, RRF_RT_REG_SZ, NULL, sValue.data(), &nSize) == ERROR_SUCCESS) { stream << "=\"" << std::wstring_convert, wchar_t>().to_bytes( std::wstring(sValue.data())) << "\""; } } else { // Special case well-known interfaces that pop up a lot, but which don't have their name in // the Registry. if (IsEqualIID(rIid, IID_IMarshal)) stream << "=\"IMarshal\""; else if (IsEqualIID(rIid, IID_INoMarshal)) stream << "=\"INoMarshal\""; else if (IsEqualIID(rIid, IID_IdentityUnmarshal)) stream << "=\"IdentityUnmarshal\""; else if (IsEqualIID(rIid, IID_IFastRundown)) stream << "=\"IFastRundown\""; else if (IsEqualIID(rIid, IID_IStdMarshalInfo)) stream << "=\"IStdMarshalInfo\""; else if (IsEqualIID(rIid, IID_IAgileObject)) stream << "=\"IAgileObject\""; else if (IsEqualIID(rIid, IID_IExternalConnection)) stream << "=\"IExternalConnection\""; else if (IsEqualIID(rIid, IID_ICallFactory)) stream << "=\"ICallFactory\""; } CoTaskMemFree(pRiid); return stream; } template inline std::basic_ostream& operator<<(std::basic_ostream& stream, const VARIANT& rVariant) { if (rVariant.vt & VT_VECTOR) stream << "VECTOR:"; if (rVariant.vt & VT_ARRAY) stream << "ARRAY:"; if (rVariant.vt & VT_BYREF) stream << "BYREF:"; switch (rVariant.vt & ~(VT_VECTOR | VT_ARRAY | VT_BYREF)) { case VT_EMPTY: stream << "EMPTY"; break; case VT_NULL: stream << "NULL"; break; case VT_I2: stream << "I2"; break; case VT_I4: stream << "I4"; break; case VT_R4: stream << "R4"; break; case VT_R8: stream << "R8"; break; case VT_CY: stream << "CY"; break; case VT_DATE: stream << "DATE"; break; case VT_BSTR: stream << "BSTR"; break; case VT_DISPATCH: stream << "DISPATCH"; break; case VT_ERROR: stream << "ERROR"; break; case VT_BOOL: stream << "BOOL"; break; case VT_VARIANT: stream << "VARIANT"; break; case VT_UNKNOWN: stream << "UNKNOWN"; break; case VT_DECIMAL: stream << "DECIMAL"; break; case VT_I1: stream << "I1"; break; case VT_UI1: stream << "UI1"; break; case VT_UI2: stream << "UI2"; break; case VT_UI4: stream << "UI4"; break; case VT_I8: stream << "I8"; break; case VT_UI8: stream << "UI8"; break; case VT_INT: stream << "INT"; break; case VT_UINT: stream << "UINT"; break; case VT_VOID: stream << "VOID"; break; case VT_HRESULT: stream << "HRESULT"; break; case VT_PTR: stream << "PTR"; break; case VT_SAFEARRAY: stream << "SAFEARRAY"; break; case VT_CARRAY: stream << "CARRAY"; break; case VT_USERDEFINED: stream << "USERDEFINED"; break; case VT_LPSTR: stream << "LPSTR"; break; case VT_LPWSTR: stream << "LPWSTR"; break; case VT_RECORD: stream << "RECORD"; break; case VT_INT_PTR: stream << "INT_PTR"; break; case VT_UINT_PTR: stream << "UINT_PTR"; break; case VT_FILETIME: stream << "FILETIME"; break; case VT_BLOB: stream << "BLOB"; break; case VT_STREAM: stream << "STREAM"; break; case VT_STORAGE: stream << "STORAGE"; break; case VT_STREAMED_OBJECT: stream << "STREAMED_OBJECT"; break; case VT_STORED_OBJECT: stream << "STORED_OBJECT"; break; case VT_BLOB_OBJECT: stream << "BLOB_OBJECT"; break; case VT_CF: stream << "CF"; break; case VT_CLSID: stream << "CLSID"; break; case VT_VERSIONED_STREAM: stream << "VERSIONED_STREAM"; break; case VT_BSTR_BLOB: stream << "BSTR_BLOB"; break; default: stream << rVariant.vt; break; } if (rVariant.vt == VT_EMPTY || rVariant.vt == VT_NULL || rVariant.vt == VT_VOID) return stream; stream << ":"; std::ios_base::fmtflags flags; std::streamsize width; charT fill; if (rVariant.vt & VT_BYREF) { stream << rVariant.byref << ":"; if (rVariant.byref == nullptr) return stream; if ((rVariant.vt & VT_TYPEMASK) == VT_VOID || (rVariant.vt & VT_TYPEMASK) == VT_USERDEFINED) return stream; stream << ":"; switch (rVariant.vt & VT_TYPEMASK) { case VT_I2: stream << *(short*)rVariant.byref; break; case VT_I4: stream << *(int*)rVariant.byref; break; case VT_R4: stream << *(float*)rVariant.byref; break; case VT_R8: stream << *(double*)rVariant.byref; break; case VT_CY: stream << ((CY*)rVariant.byref)->int64; break; case VT_DATE: stream << *(double*)rVariant.byref; break; // FIXME case VT_BSTR: stream << std::wstring_convert, wchar_t>().to_bytes( *(OLECHAR**)rVariant.byref); break; case VT_DISPATCH: stream << rVariant.byref; break; case VT_ERROR: case VT_HRESULT: flags = stream.flags(); stream << std::hex << *(int*)rVariant.byref; stream.setf(flags); break; case VT_BOOL: stream << (*(VARIANT_BOOL*)rVariant.byref ? "YES" : "NO"); break; case VT_VARIANT: stream << *(VARIANT*)rVariant.byref; break; case VT_UNKNOWN: stream << *(IUnknown**)rVariant.byref; break; case VT_DECIMAL: flags = stream.flags(); width = stream.width(); fill = stream.fill(); stream << std::hex << std::setw(8) << std::setfill('0') << ((DECIMAL*)rVariant.byref)->Hi32; stream << std::setw(16) << ((DECIMAL*)rVariant.byref)->Lo64; stream.setf(flags); stream << std::setw(width) << std::setfill(fill); break; case VT_I1: stream << (int)*(char*)rVariant.byref; break; case VT_UI1: stream << (unsigned int)*(unsigned char*)rVariant.byref; break; case VT_UI2: stream << *(unsigned short*)rVariant.byref; break; case VT_UI4: stream << *(unsigned int*)rVariant.byref; break; case VT_I8: stream << *(long long*)rVariant.byref; break; case VT_UI8: stream << *(unsigned long long*)rVariant.byref; break; case VT_INT: stream << *(int*)rVariant.byref; break; case VT_UINT: stream << *(unsigned int*)rVariant.byref; break; case VT_INT_PTR: stream << *(intptr_t*)rVariant.byref; break; case VT_UINT_PTR: stream << *(uintptr_t*)rVariant.byref; break; case VT_PTR: case VT_CARRAY: stream << *(void**)rVariant.byref; break; case VT_SAFEARRAY: break; // FIXME case VT_LPSTR: stream << *(char**)rVariant.byref; break; case VT_LPWSTR: stream << std::wstring_convert, wchar_t>().to_bytes( std::wstring(*(wchar_t**)rVariant.byref)); break; case VT_FILETIME: break; // FIXME case VT_BLOB: break; // FIXME case VT_STREAM: break; // FIXME case VT_STORAGE: break; // FIXME case VT_STREAMED_OBJECT: break; // FIXME case VT_STORED_OBJECT: break; // FIXME case VT_BLOB_OBJECT: break; // FIXME case VT_CF: break; // FIXME case VT_CLSID: stream << *(IID*)rVariant.byref; break; case VT_VERSIONED_STREAM: break; // FIXME case VT_BSTR_BLOB: break; // FIXME default: stream << "?(" << (rVariant.vt & VT_TYPEMASK) << ")"; break; } return stream; } switch (rVariant.vt & VT_TYPEMASK) { case VT_I2: stream << rVariant.iVal; break; case VT_I4: stream << rVariant.lVal; break; case VT_R4: stream << rVariant.fltVal; break; case VT_R8: stream << rVariant.dblVal; break; case VT_CY: stream << rVariant.cyVal.int64; break; case VT_DATE: stream << (double)rVariant.date; break; // FIXME case VT_BSTR: stream << std::wstring_convert, wchar_t>().to_bytes( rVariant.bstrVal); break; case VT_DISPATCH: stream << rVariant.pdispVal; break; case VT_ERROR: case VT_HRESULT: flags = stream.flags(); stream << std::hex << rVariant.lVal; stream.setf(flags); break; case VT_BOOL: stream << (rVariant.boolVal ? "YES" : "NO"); break; case VT_UNKNOWN: stream << rVariant.punkVal; break; case VT_DECIMAL: flags = stream.flags(); width = stream.width(); fill = stream.fill(); stream << std::hex << std::setw(8) << std::setfill('0') << rVariant.decVal.Hi32; stream << std::setw(16) << rVariant.decVal.Lo64; stream.setf(flags); stream << std::setw(width) << std::setfill(fill); break; case VT_I1: stream << (int)rVariant.bVal; break; case VT_UI1: stream << (unsigned int)rVariant.bVal; break; case VT_UI2: stream << (unsigned short)rVariant.iVal; break; case VT_UI4: stream << (unsigned int)rVariant.lVal; break; case VT_I8: stream << rVariant.llVal; break; case VT_UI8: stream << (unsigned long long)rVariant.llVal; break; case VT_INT: stream << rVariant.lVal; break; case VT_UINT: stream << (unsigned int)rVariant.lVal; break; case VT_INT_PTR: stream << (intptr_t)rVariant.plVal; break; case VT_UINT_PTR: stream << (uintptr_t)rVariant.plVal; break; case VT_PTR: case VT_CARRAY: stream << rVariant.byref; break; case VT_SAFEARRAY: break; // FIXME case VT_LPSTR: stream << rVariant.bstrVal; break; case VT_LPWSTR: stream << std::wstring_convert, wchar_t>().to_bytes( std::wstring((wchar_t*)rVariant.byref)); break; case VT_FILETIME: break; // FIXME case VT_BLOB: break; // FIXME case VT_STREAM: break; // FIXME case VT_STORAGE: break; // FIXME case VT_STREAMED_OBJECT: break; // FIXME case VT_STORED_OBJECT: break; // FIXME case VT_BLOB_OBJECT: break; // FIXME case VT_CF: break; // FIXME case VT_VERSIONED_STREAM: break; // FIXME case VT_BSTR_BLOB: break; // FIXME default: stream << "?(" << (rVariant.vt & VT_TYPEMASK) << ")"; break; } return stream; } #endif // INCLUDED_COMPHELPER_WINDOWSDEBUGOUTPUT_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */