1 /* 2 * PROJECT: ReactOS ATL 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: Providing ATLTRACE macro 5 * COPYRIGHT: Copyright 2022 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 8 #pragma once 9 10 #include "atldef.h" 11 12 #if DBG // FIXME: We should use _DEBUG instead of DBG. CORE-17505 13 14 #include <stdio.h> 15 #include <crtdbg.h> 16 17 extern "C" 18 { 19 // FIXME: Enabling _DEBUG at top level causes assertion failures... CORE-17505 20 int __cdecl _CrtDbgReport(int reportType, const char *filename, int linenumber, const char *moduleName, const char *format, ...); 21 int __cdecl _CrtDbgReportW(int reportType, const wchar_t *filename, int linenumber, const wchar_t *moduleName, const wchar_t *format, ...); 22 } 23 24 namespace ATL 25 { 26 27 template <UINT t_category = (1 << 19), UINT t_level = 0> 28 class CTraceCategoryEx 29 { 30 public: 31 enum 32 { 33 TraceGeneral = (1 << 0), 34 TraceCom = (1 << 1), 35 TraceQI = (1 << 2), 36 TraceRegistrar = (1 << 3), 37 TraceRefcount = (1 << 4), 38 TraceWindowing = (1 << 5), 39 TraceControls = (1 << 6), 40 TraceHosting = (1 << 7), 41 TraceDBClient = (1 << 8), 42 TraceDBProvider = (1 << 9), 43 TraceSnapin = (1 << 10), 44 TraceNotImpl = (1 << 11), 45 TraceAllocation = (1 << 12), 46 TraceException = (1 << 13), 47 TraceTime = (1 << 14), 48 TraceCache = (1 << 15), 49 TraceStencil = (1 << 16), 50 TraceString = (1 << 17), 51 TraceMap = (1 << 18), 52 TraceUtil = (1 << 19), 53 TraceSecurity = (1 << 20), 54 TraceSync = (1 << 21), 55 TraceISAPI = (1 << 22), 56 TraceUser = TraceUtil 57 }; 58 59 CTraceCategoryEx(LPCTSTR name = NULL) : m_name(name) 60 { 61 } 62 63 static UINT GetLevel() { return t_level; } 64 static UINT GetCategory() { return t_category; } 65 operator UINT() const { return GetCategory(); } 66 LPCTSTR GetCategoryName() const { return m_name; } 67 68 protected: 69 LPCTSTR m_name; 70 }; 71 72 class CTraceCategory : public CTraceCategoryEx<> 73 { 74 CTraceCategory(LPCTSTR name = NULL) : CTraceCategoryEx<>(name) 75 { 76 } 77 }; 78 79 #define DEFINE_TRACE_CATEGORY(name, cat) extern const DECLSPEC_SELECTANY CTraceCategoryEx<cat, 0> name(TEXT(#name)) 80 DEFINE_TRACE_CATEGORY(atlTraceGeneral, CTraceCategoryEx<>::TraceGeneral); 81 DEFINE_TRACE_CATEGORY(atlTraceCOM, CTraceCategoryEx<>::TraceCom); 82 DEFINE_TRACE_CATEGORY(atlTraceQI, CTraceCategoryEx<>::TraceQI); 83 DEFINE_TRACE_CATEGORY(atlTraceRegistrar, CTraceCategoryEx<>::TraceRegistrar); 84 DEFINE_TRACE_CATEGORY(atlTraceRefcount, CTraceCategoryEx<>::TraceRefcount); 85 DEFINE_TRACE_CATEGORY(atlTraceWindowing, CTraceCategoryEx<>::TraceWindowing); 86 DEFINE_TRACE_CATEGORY(atlTraceControls, CTraceCategoryEx<>::TraceControls); 87 DEFINE_TRACE_CATEGORY(atlTraceHosting, CTraceCategoryEx<>::TraceHosting); 88 DEFINE_TRACE_CATEGORY(atlTraceDBClient, CTraceCategoryEx<>::TraceDBClient); 89 DEFINE_TRACE_CATEGORY(atlTraceDBProvider, CTraceCategoryEx<>::TraceDBProvider); 90 DEFINE_TRACE_CATEGORY(atlTraceSnapin, CTraceCategoryEx<>::TraceSnapin); 91 DEFINE_TRACE_CATEGORY(atlTraceNotImpl, CTraceCategoryEx<>::TraceNotImpl); 92 DEFINE_TRACE_CATEGORY(atlTraceAllocation, CTraceCategoryEx<>::TraceAllocation); 93 DEFINE_TRACE_CATEGORY(atlTraceException, CTraceCategoryEx<>::TraceException); 94 DEFINE_TRACE_CATEGORY(atlTraceTime, CTraceCategoryEx<>::TraceTime); 95 DEFINE_TRACE_CATEGORY(atlTraceCache, CTraceCategoryEx<>::TraceCache); 96 DEFINE_TRACE_CATEGORY(atlTraceStencil, CTraceCategoryEx<>::TraceStencil); 97 DEFINE_TRACE_CATEGORY(atlTraceString, CTraceCategoryEx<>::TraceString); 98 DEFINE_TRACE_CATEGORY(atlTraceMap, CTraceCategoryEx<>::TraceMap); 99 DEFINE_TRACE_CATEGORY(atlTraceUtil, CTraceCategoryEx<>::TraceUtil); 100 DEFINE_TRACE_CATEGORY(atlTraceSecurity, CTraceCategoryEx<>::TraceSecurity); 101 DEFINE_TRACE_CATEGORY(atlTraceSync, CTraceCategoryEx<>::TraceSync); 102 DEFINE_TRACE_CATEGORY(atlTraceISAPI, CTraceCategoryEx<>::TraceISAPI); 103 #undef DEFINE_TRACE_CATEGORY 104 105 struct CTraceCategoryEasy 106 { 107 UINT m_category; 108 UINT m_level; 109 LPCTSTR m_name; 110 111 template <UINT t_category, UINT t_level> 112 CTraceCategoryEasy(const CTraceCategoryEx<t_category, t_level>& cat) 113 { 114 m_category = t_category; 115 m_level = t_level; 116 m_name = cat.GetCategoryName(); 117 } 118 119 operator UINT() const { return m_category; } 120 121 BOOL IsGeneral() const 122 { 123 return lstrcmp(m_name, TEXT("atlTraceGeneral")) == 0; 124 } 125 }; 126 127 struct CTrace 128 { 129 enum 130 { 131 DefaultTraceLevel = 0, 132 DisableTracing = 0xFFFFFFFF, 133 EnableAllCategories = 0xFFFFFFFF 134 }; 135 136 static UINT GetLevel() { return s_level; } 137 static UINT GetCategories() { return s_categories; } 138 static void SetLevel(UINT level) { s_level = level; } 139 static void SetCategories(UINT categories) { s_categories = categories; } 140 141 static bool IsTracingEnabled(UINT category, UINT level) 142 { 143 return (s_level != DisableTracing && s_level >= level && (s_categories & category)); 144 } 145 146 protected: 147 static UINT s_categories; 148 static UINT s_level; 149 }; 150 151 DECLSPEC_SELECTANY UINT CTrace::s_categories = CTrace::EnableAllCategories; 152 DECLSPEC_SELECTANY UINT CTrace::s_level = CTrace::DefaultTraceLevel; 153 154 template <typename X_CHAR> 155 inline VOID __stdcall 156 AtlTraceV(_In_opt_z_ const X_CHAR * file, 157 _In_ INT line, 158 _In_ const CTraceCategoryEasy& cat, 159 _In_ UINT level, 160 _In_z_ _Printf_format_string_ PCSTR format, 161 _In_ va_list va) 162 { 163 char szBuff[1024], szFile[MAX_PATH]; 164 size_t cch = 0; 165 const BOOL bUnicode = (sizeof(TCHAR) == 2); 166 167 if (!CTrace::IsTracingEnabled(cat, level)) 168 return; 169 170 #ifdef _STRSAFE_H_INCLUDED_ 171 StringCchPrintfA(szFile, _countof(szFile), ((sizeof(X_CHAR) == 2) ? "%ls" : "%hs"), file); 172 if (!cat.IsGeneral()) 173 { 174 StringCchPrintfA(szBuff, _countof(szBuff), (bUnicode ? "%ls - " : "%hs - "), cat.m_name); 175 StringCchLengthA(szBuff, _countof(szBuff), &cch); 176 } 177 StringCchVPrintfA(&szBuff[cch], _countof(szBuff) - cch, format, va); 178 #else 179 _snprintf(szFile, _countof(szFile), ((sizeof(X_CHAR) == 2) ? "%ls" : "%hs"), file); 180 if (!cat.IsGeneral()) 181 cch = _snprintf(szBuff, _countof(szBuff), (bUnicode ? "%ls - " : "%hs - "), cat.m_name); 182 _vsnprintf(&szBuff[cch], _countof(szBuff) - cch, format, va); 183 #endif 184 185 _CrtDbgReport(_CRT_WARN, szFile, line, NULL, "%hs", szBuff); 186 } 187 188 template <typename X_CHAR> 189 inline VOID __stdcall 190 AtlTraceV(_In_opt_z_ const X_CHAR * file, 191 _In_ INT line, 192 _In_ const CTraceCategoryEasy& cat, 193 _In_ UINT level, 194 _In_z_ _Printf_format_string_ PCWSTR format, 195 _In_ va_list va) 196 { 197 WCHAR szBuff[1024], szFile[MAX_PATH]; 198 size_t cch = 0; 199 const BOOL bUnicode = (sizeof(TCHAR) == 2); 200 201 if (!CTrace::IsTracingEnabled(cat, level)) 202 return; 203 204 #ifdef _STRSAFE_H_INCLUDED_ 205 StringCchPrintfW(szFile, _countof(szFile), ((sizeof(X_CHAR) == 2) ? L"%ls" : L"%hs"), file); 206 if (!cat.IsGeneral()) 207 { 208 StringCchPrintfW(szBuff, _countof(szBuff), (bUnicode ? L"%ls - " : L"%hs - "), cat.m_name); 209 StringCchLengthW(szBuff, _countof(szBuff), &cch); 210 } 211 StringCchVPrintfW(&szBuff[cch], _countof(szBuff) - cch, format, va); 212 #else 213 _snwprintf(szFile, _countof(szFile), ((sizeof(X_CHAR) == 2) ? L"%ls" : L"%hs"), file); 214 if (!cat.IsGeneral()) 215 cch = _snwprintf(szBuff, _countof(szBuff), (bUnicode ? L"%ls - " : L"%hs - "), cat.m_name); 216 _vsnwprintf(&szBuff[cch], _countof(szBuff) - cch, format, va); 217 #endif 218 219 _CrtDbgReportW(_CRT_WARN, szFile, line, NULL, L"%ls", szBuff); 220 } 221 222 template <typename X_CHAR, typename Y_CHAR> 223 inline VOID __cdecl 224 AtlTraceEx(_In_opt_z_ const X_CHAR * file, 225 _In_ INT line, 226 _In_ const CTraceCategoryEasy& cat, 227 _In_ UINT level, 228 _In_z_ _Printf_format_string_ const Y_CHAR * format, 229 ...) 230 { 231 va_list va; 232 va_start(va, format); 233 AtlTraceV(file, line, cat, level, format, va); 234 va_end(va); 235 } 236 237 template <typename X_CHAR, typename Y_CHAR> 238 inline VOID __cdecl 239 AtlTraceEx(_In_opt_z_ const X_CHAR *file, 240 _In_ INT line, 241 _In_z_ _Printf_format_string_ const Y_CHAR *format, 242 ...) 243 { 244 va_list va; 245 va_start(va, format); 246 AtlTraceV(file, line, atlTraceGeneral, 0, format, va); 247 va_end(va); 248 } 249 250 inline VOID __stdcall 251 AtlTraceEx(_In_opt_z_ PCTSTR file, 252 _In_ INT line, 253 _In_ DWORD value) 254 { 255 AtlTraceEx(file, line, TEXT("%ld (0x%lX)\n"), value, value); 256 } 257 258 template <typename X_CHAR> 259 inline VOID __cdecl 260 AtlTrace(_In_z_ _Printf_format_string_ const X_CHAR *format, ...) 261 { 262 va_list va; 263 va_start(va, format); 264 AtlTraceV(NULL, -1, atlTraceGeneral, 0, format, va); 265 va_end(va); 266 } 267 268 } // namespace ATL 269 270 #endif // DBG 271 272 #ifndef ATLTRACE 273 #if DBG // FIXME: We should use _DEBUG instead of DBG. CORE-17505 274 #define ATLTRACE(format, ...) ATL::AtlTraceEx(__FILE__, __LINE__, format, ##__VA_ARGS__) 275 #else 276 #define ATLTRACE(format, ...) ((void)0) 277 #endif 278 #endif 279 280 #define ATLTRACE2 ATLTRACE 281 282 #if DBG // FIXME: We should use _DEBUG instead of DBG. CORE-17505 283 #define ATLTRACENOTIMPL(funcname) do { \ 284 ATLTRACE(atlTraceNotImpl, 0, #funcname " is not implemented.\n"); \ 285 return E_NOTIMPL; \ 286 } while (0) 287 #else 288 #define ATLTRACENOTIMPL(funcname) return E_NOTIMPL 289 #endif 290 291 #ifndef _ATL_NO_AUTOMATIC_NAMESPACE 292 using namespace ATL; 293 #endif //!_ATL_NO_AUTOMATIC_NAMESPACE 294