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