1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ============================================================
11 // Implements the fusion-derived CDebugLog class
13 // ============================================================
15 #ifdef FEATURE_VERSIONING_LOG
17 #include "cdebuglog.hpp"
18 #include "applicationcontext.hpp"
19 #include "assemblyname.hpp"
20 #include "variables.hpp"
26 #include "../dlls/mscorrc/fusres.h"
28 #define MAX_DBG_STR_LEN 1024
29 #define MAX_DATE_LEN 128
31 #define DEBUG_LOG_HTML_START L"<html><pre>\r\n"
32 #define DEBUG_LOG_HTML_META_LANGUAGE L"<meta http-equiv=\"Content-Type\" content=\"charset=unicode-1-1-utf-8\">"
33 #define DEBUG_LOG_MARK_OF_THE_WEB L"<!-- saved from url=(0015)assemblybinder: -->"
34 #define DEBUG_LOG_HTML_END L"\r\n</pre></html>"
35 #define DEBUG_LOG_NEW_LINE L"\r\n"
37 namespace BINDER_SPACE
41 inline LPCWSTR LogCategoryToString(DWORD dwLogCategory)
43 switch (dwLogCategory)
45 case FUSION_BIND_LOG_CATEGORY_DEFAULT:
47 case FUSION_BIND_LOG_CATEGORY_NGEN:
54 HRESULT CreateFilePathHierarchy(LPCOLESTR pszName)
58 PathString szPathString;
61 size_t pszNameLen = wcslen(pszName);
62 WCHAR * szPath = szPathString.OpenUnicodeBuffer(static_cast<COUNT_T>(pszNameLen));
63 size_t cbSzPath = (sizeof(WCHAR)) * (pszNameLen + 1); // SString allocates extra byte for null
64 IF_FAIL_GO(StringCbCopy(szPath, cbSzPath, pszName));
65 szPathString.CloseBuffer(static_cast<COUNT_T>(pszNameLen));
67 pszFileName = PathFindFileName(szPath);
69 if (pszFileName <= szPath)
71 IF_FAIL_GO(E_INVALIDARG);
76 dw = WszGetFileAttributes(szPath);
77 if (dw != INVALID_FILE_ATTRIBUTES)
82 hr = HRESULT_FROM_GetLastError();
86 case __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND):
88 hr = CreateFilePathHierarchy(szPath);
93 case __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
95 if (WszCreateDirectory(szPath, NULL))
99 hr = HRESULT_FROM_WIN32(GetLastError());
100 if(hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
115 HRESULT WriteLog(HANDLE hLogFile,
121 CHAR szBuf[MAX_DBG_STR_LEN];
123 dwLen = WszWideCharToMultiByte(CP_UTF8,
134 IF_FAIL_GO(HRESULT_FROM_GetLastError());
137 // dwLen includes NULL terminator. We don't want to write this out.
141 if (!WriteFile(hLogFile, szBuf, dwLen, &dwWritten, NULL)) {
142 IF_FAIL_GO(HRESULT_FROM_GetLastError());
150 HRESULT GetBindTimeInfo(PathString &info)
156 WCHAR wzDateBuffer[MAX_DATE_LEN];
157 WCHAR wzTimeBuffer[MAX_DATE_LEN];
159 GetLocalTime(&systime);
161 if (!WszGetDateFormat(LOCALE_USER_DEFAULT,
168 return HRESULT_FROM_GetLastError();
171 if (!WszGetTimeFormat(LOCALE_USER_DEFAULT,
178 return HRESULT_FROM_GetLastError();
181 info.Printf(L"(%s @ %s)", wzDateBuffer, wzTimeBuffer);
186 HRESULT GetHrResultInfo(PathString &info, HRESULT hrResult)
190 // TODO: Get the result information in here.
191 info.Printf(L"%p.", hrResult);
196 inline BOOL IsInvalidCharacter(WCHAR wcChar)
215 inline void ReplaceInvalidFileCharacters(SString &assemblyName)
217 SString::Iterator pos = assemblyName.Begin();
218 SString::Iterator end = assemblyName.End();
222 if (IsInvalidCharacter(pos[0]))
224 assemblyName.Replace(pos, L'_');
232 CDebugLog::CDebugLog()
237 CDebugLog::~CDebugLog()
239 // Nothing to do here
243 HRESULT CDebugLog::Create(ApplicationContext *pApplicationContext,
244 AssemblyName *pAssemblyName,
246 CDebugLog **ppCDebugLog)
249 BINDER_LOG_ENTER(L"CDebugLog::Create");
250 ReleaseHolder<CDebugLog> pDebugLog;
252 // Validate input arguments
253 IF_FALSE_GO(pApplicationContext != NULL);
254 IF_FALSE_GO(ppCDebugLog != NULL);
256 SAFE_NEW(pDebugLog, CDebugLog);
257 IF_FAIL_GO(pDebugLog->Init(pApplicationContext, pAssemblyName, sCodeBase));
259 *ppCDebugLog = pDebugLog.Extract();
262 BINDER_LOG_LEAVE_HR(L"CDebugLog::Create", hr);
266 ULONG CDebugLog::AddRef()
268 return InterlockedIncrement(&m_cRef);
271 ULONG CDebugLog::Release()
275 ulRef = InterlockedDecrement(&m_cRef);
285 HRESULT CDebugLog::SetResultCode(DWORD dwLogCategory,
289 BINDER_LOG_ENTER(L"CDebugLog::SetResultCode");
291 IF_FALSE_GO(dwLogCategory < FUSION_BIND_LOG_CATEGORY_MAX);
293 m_HrResult[dwLogCategory] = hrResult;
296 BINDER_LOG_LEAVE_HR(L"CDebugLog::SetResultCode", hr);
300 HRESULT CDebugLog::LogMessage(DWORD,
302 SString &sDebugString)
305 BINDER_LOG_ENTER(L"CDebugLog::LogMessage");
307 IF_FALSE_GO(dwLogCategory < FUSION_BIND_LOG_CATEGORY_MAX);
309 m_content[dwLogCategory].AddTail(const_cast<const SString &>(sDebugString));
312 BINDER_LOG_LEAVE_HR(L"CDebugLog::LogMessage", hr);
316 HRESULT CDebugLog::Flush(DWORD,
320 BINDER_LOG_ENTER(L"CDebugLog::Flush");
321 SmallStackSString sCategory(LogCategoryToString(dwLogCategory));
322 PathString logFilePath;
323 ListNode<SString> *pListNode = NULL;
325 IF_FALSE_GO(dwLogCategory < FUSION_BIND_LOG_CATEGORY_MAX);
327 CombinePath(g_BinderVariables->logPath, sCategory, logFilePath);
328 CombinePath(logFilePath, m_applicationName, logFilePath);
329 CombinePath(logFilePath, m_logFileName, logFilePath);
331 BINDER_LOG_STRING(L"logFilePath", logFilePath);
333 IF_FAIL_GO(CreateFilePathHierarchy(logFilePath.GetUnicode()));
335 m_hLogFile = WszCreateFile(logFilePath.GetUnicode(),
336 GENERIC_READ | GENERIC_WRITE,
340 FILE_ATTRIBUTE_NORMAL,
343 if (m_hLogFile == INVALID_HANDLE_VALUE)
345 // Silently ignore unability to log.
346 BINDER_LOG(L"Unable to open binding log");
347 GO_WITH_HRESULT(S_OK);
350 LogHeader(dwLogCategory);
352 pListNode = static_cast<ListNode<SString> *>(m_content[dwLogCategory].GetHeadPosition());
353 while (pListNode != NULL)
355 SString item = pListNode->GetItem();
357 IF_FAIL_GO(WriteLog(m_hLogFile, item.GetUnicode()));
358 IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE));
360 pListNode = pListNode->GetNext();
363 LogFooter(dwLogCategory);
366 CloseHandle(m_hLogFile.Extract());
369 BINDER_LOG_LEAVE_HR(L"CDebugLog::Flush", hr);
373 HRESULT CDebugLog::Init(ApplicationContext *pApplicationContext,
374 AssemblyName *pAssemblyName,
378 BINDER_LOG_ENTER(L"CDebugLog::Init");
380 m_applicationName.Set(pApplicationContext->GetApplicationName());
381 ReplaceInvalidFileCharacters(m_applicationName);
383 if (m_applicationName.IsEmpty())
385 BINDER_LOG(L"empty application name");
386 m_applicationName.Set(L"unknown");
389 if (pAssemblyName == NULL)
391 m_logFileName.Set(L"WhereRefBind!Host=(LocalMachine)!FileName=(");
393 LPCWSTR pwzFileName = PathFindFileNameW(sCodeBase.GetUnicode());
394 if (pwzFileName != NULL)
396 m_logFileName.Append(pwzFileName);
398 m_logFileName.Append(L").HTM");
402 PathString assemblyDisplayName;
404 pAssemblyName->GetDisplayName(assemblyDisplayName,
405 AssemblyName::INCLUDE_VERSION |
406 AssemblyName::INCLUDE_ARCHITECTURE |
407 AssemblyName::INCLUDE_RETARGETABLE);
409 ReplaceInvalidFileCharacters(assemblyDisplayName);
411 m_logFileName.Set(assemblyDisplayName);
412 m_logFileName.Append(L".HTM");
415 BINDER_LOG_LEAVE_HR(L"CDebugLog::Init", hr);
419 HRESULT CDebugLog::LogHeader(DWORD dwLogCategory)
422 BINDER_LOG_ENTER(L"CDebugLog::LogHeader");
427 IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_HTML_META_LANGUAGE));
428 IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_MARK_OF_THE_WEB));
429 IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_HTML_START));
431 IF_FAIL_GO(GetBindTimeInfo(temp));
432 IF_FAIL_GO(format.LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_BEGIN));
433 info.Printf(format.GetUnicode(), temp.GetUnicode());
434 IF_FAIL_GO(WriteLog(m_hLogFile, info.GetUnicode()));
435 IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE DEBUG_LOG_NEW_LINE));
437 if (SUCCEEDED(m_HrResult[dwLogCategory]))
440 LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_BIND_RESULT_SUCCESS));
441 IF_FAIL_GO(WriteLog(m_hLogFile, temp.GetUnicode()));
446 LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_BIND_RESULT_ERROR));
447 IF_FAIL_GO(WriteLog(m_hLogFile, temp.GetUnicode()));
449 IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE));
451 GetHrResultInfo(temp, m_HrResult[dwLogCategory]);
453 IF_FAIL_GO(format.LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_BIND_RESULT));
454 info.Printf(format.GetUnicode(), temp.GetUnicode());
455 IF_FAIL_GO(WriteLog(m_hLogFile, info.GetUnicode()));
456 IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE DEBUG_LOG_NEW_LINE));
458 // TODO: Assembly Manager info + Executable info.
460 IF_FAIL_GO(info.LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_END));
461 IF_FAIL_GO(WriteLog(m_hLogFile, info.GetUnicode()));
462 IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE DEBUG_LOG_NEW_LINE));
465 BINDER_LOG_LEAVE_HR(L"CDebugLog::LogHeader", hr);
469 HRESULT CDebugLog::LogFooter(DWORD)
472 BINDER_LOG_ENTER(L"CDebugLog::LogFooter");
474 IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_HTML_END));
477 BINDER_LOG_LEAVE_HR(L"CDebugLog::LogFooter", hr);
482 #endif // FEATURE_VERSIONING_LOG