Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

959 lines
25 KiB

// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
#include <windows.h>
#include "dbglog.h"
#include "wininet.h"
#include "util.h"
//#include "lock.h"
#include "version.h"
extern HINSTANCE g_hInst;
extern WCHAR g_FusionDllPath[MAX_PATH+1];
#define XSP_APP_CACHE_DIR L"Temporary ASP.NET Files"
#define XSP_FUSION_LOG_DIR L"Bind Logs"
#define REG_KEY_FUSION_SETTINGS TEXT("Software\\Microsoft\\Fusion\\Installer\\1.0.0.0\\")
#define DLTYPE_DEFAULT L"DEFAULT"
#define DLTYPE_FOREGROUND L"Foreground"
#define DLTYPE_BACKGROUND L"Background"
WCHAR g_wzEXEPath[MAX_PATH+1];
DWORD g_dwDisableLog;
DWORD g_dwForceLog;
DWORD g_dwLogFailures;
DWORD g_dwLoggingLevel=1;
void GetExePath()
{
static BOOL bFirstTime=TRUE;
if(bFirstTime)
{
if (!GetModuleFileNameW(NULL, g_wzEXEPath, MAX_PATH)) {
lstrcpyW(g_wzEXEPath, L"Unknown");
}
bFirstTime=FALSE;
}
}
BOOL IsHosted()
{
return FALSE;
}
HRESULT GetRegValues()
{
DWORD dwSize;
DWORD dwType;
DWORD lResult;
HKEY hkey=0;
DWORD dwValue=0;
lResult = RegOpenKeyEx(HKEY_CURRENT_USER, REG_KEY_FUSION_SETTINGS, 0, KEY_READ, &hkey);
if(lResult == ERROR_SUCCESS) {
// Get Logging Level
dwSize = sizeof(DWORD);
lResult = RegQueryValueEx(hkey, REG_VAL_FUSION_LOG_LEVEL, NULL,
&dwType, (LPBYTE)&dwValue, &dwSize);
if (lResult != ERROR_SUCCESS) {
g_dwLoggingLevel = 0;
}
else
{
g_dwLoggingLevel = dwValue;
}
// Get Log Failures
dwSize = sizeof(DWORD);
lResult = RegQueryValueEx(hkey, REG_VAL_FUSION_LOG_FAILURES, NULL,
&dwType, (LPBYTE)&dwValue, &dwSize);
if (lResult != ERROR_SUCCESS) {
g_dwLogFailures = 0;
}
else
{
g_dwLogFailures = dwValue;
}
}
return S_OK;
}
HRESULT CreateLogObject(CDebugLog **ppdbglog, LPCWSTR szCodebase)
{
HRESULT hr = S_OK;
MAKE_ERROR_MACROS_STATIC(hr);
IF_FAILED_EXIT(CDebugLog::Create(NULL, NULL, ppdbglog));
// hr = GetRegValues();
exit:
return hr;
}
//
// CDebugLogElement Class
//
HRESULT CDebugLogElement::Create(DWORD dwDetailLvl, LPCWSTR pwzMsg,
CDebugLogElement **ppLogElem)
{
HRESULT hr = S_OK;
CDebugLogElement *pLogElem = NULL;
if (!ppLogElem || !pwzMsg) {
hr = E_INVALIDARG;
goto Exit;
}
*ppLogElem = NULL;
pLogElem = FUSION_NEW_SINGLETON(CDebugLogElement(dwDetailLvl));
if (!pLogElem) {
hr = E_OUTOFMEMORY;
goto Exit;
}
hr = pLogElem->Init(pwzMsg);
if (FAILED(hr)) {
SAFEDELETE(pLogElem);
goto Exit;
}
*ppLogElem = pLogElem;
Exit:
return hr;
}
CDebugLogElement::CDebugLogElement(DWORD dwDetailLvl)
: _pszMsg(NULL)
, _dwDetailLvl(dwDetailLvl)
{
}
CDebugLogElement::~CDebugLogElement()
{
SAFEDELETEARRAY(_pszMsg);
}
HRESULT CDebugLogElement::Init(LPCWSTR pwzMsg)
{
HRESULT hr = S_OK;
ASSERT(pwzMsg);
_pszMsg = WSTRDupDynamic(pwzMsg);
if (!_pszMsg) {
hr = E_OUTOFMEMORY;
goto Exit;
}
Exit:
return hr;
}
/*******************************************************************
NAME: Unicode2Ansi
SYNOPSIS: Converts a unicode widechar string to ansi (MBCS)
NOTES: Caller must free out parameter using delete
********************************************************************/
HRESULT Unicode2Ansi(const wchar_t *src, char ** dest)
{
if ((src == NULL) || (dest == NULL))
return E_INVALIDARG;
// find out required buffer size and allocate it.
int len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
*dest = NEW(char [len*sizeof(char)]);
if (!*dest)
return E_OUTOFMEMORY;
// Now do the actual conversion
if ((WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len*sizeof(char),
NULL, NULL)) != 0)
return S_OK;
else
return HRESULT_FROM_WIN32(GetLastError());
}
HRESULT CDebugLogElement::Dump(HANDLE hFile)
{
HRESULT hr = S_OK;
DWORD dwLen = 0;
DWORD dwWritten = 0;
DWORD dwSize = 0;
DWORD dwBufSize = 0;
LPSTR szBuf = NULL;
BOOL bRet;
if (!hFile) {
hr = E_INVALIDARG;
goto Exit;
}
dwSize = lstrlenW(_pszMsg) + 1;
hr = Unicode2Ansi(_pszMsg, &szBuf);
if(FAILED(hr))
goto Exit;
bRet = WriteFile(hFile, szBuf, strlen(szBuf), &dwWritten, NULL);
if (!bRet) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
Exit:
SAFEDELETEARRAY(szBuf);
return hr;
}
//
// CDebugLog Class
//
HRESULT CDebugLog::Create(IApplicationContext *pAppCtx, LPCWSTR pwzAsmName,
CDebugLog **ppdl)
{
HRESULT hr = S_OK;
CDebugLog *pdl = NULL;
*ppdl = NULL;
pdl = NEW(CDebugLog);
if (!pdl) {
hr = E_OUTOFMEMORY;
goto Exit;
}
hr = pdl->Init(pAppCtx, pwzAsmName);
if (FAILED(hr)) {
delete pdl;
pdl = NULL;
goto Exit;
}
*ppdl = pdl;
Exit:
return hr;
}
CDebugLog::CDebugLog()
: _pwzAsmName(NULL)
, _cRef(1)
, _bLogToWininet(TRUE)
, _dwNumEntries(0)
, _hr(S_OK)
, _wzEXEName(NULL)
, _bWroteDetails(FALSE)
{
_szLogPath[0] = L'\0';
InitializeCriticalSection(&_cs);
GetExePath();
}
CDebugLog::~CDebugLog()
{
LISTNODE pos = NULL;
CDebugLogElement *pLogElem = NULL;
pos = _listDbgMsg.GetHeadPosition();
while (pos) {
pLogElem = _listDbgMsg.GetNext(pos);
SAFEDELETE(pLogElem);
}
_listDbgMsg.RemoveAll();
SAFEDELETEARRAY(_pwzAsmName);
SAFEDELETEARRAY(_wzEXEName);
DeleteCriticalSection(&_cs);
}
HRESULT CDebugLog::Init(IApplicationContext *pAppCtx, LPCWSTR pwzAsmName)
{
HRESULT hr = S_OK;
BOOL bIsHosted = FALSE;
DWORD dwSize;
DWORD dwType;
DWORD lResult;
DWORD dwAttr;
HKEY hkey;
LPWSTR wzAppName = NULL;
LPWSTR wzEXEName = NULL;
hr = _sDLType.Assign(DLTYPE_DEFAULT);
if (wzAppName && lstrlenW(wzAppName)) {
_wzEXEName = WSTRDupDynamic(wzAppName);
if (!_wzEXEName) {
hr = E_OUTOFMEMORY;
goto Exit;
}
}
else {
LPWSTR wzFileName;
// Didn't find EXE name in appctx. Use the .EXE name.
wzFileName = PathFindFileName(g_wzEXEPath);
ASSERT(wzFileName);
hr = _sAppName.Assign(wzFileName);
_wzEXEName = WSTRDupDynamic(wzFileName);
if (!_wzEXEName) {
hr = E_OUTOFMEMORY;
goto Exit;
}
}
// Log path
lResult = RegOpenKeyEx(HKEY_CURRENT_USER, REG_KEY_FUSION_SETTINGS, 0, KEY_READ, &hkey);
if (lResult == ERROR_SUCCESS) {
dwSize = MAX_PATH;
lResult = RegQueryValueEx(hkey, REG_VAL_FUSION_LOG_PATH, NULL,
&dwType, (LPBYTE)_szLogPath, &dwSize);
if (lResult == ERROR_SUCCESS) {
PathRemoveBackslashW(_szLogPath);
}
else {
_szLogPath[0] = L'\0';
}
RegCloseKey(hkey);
dwAttr = GetFileAttributesW(_szLogPath);
if (dwAttr != -1 && (dwAttr & FILE_ATTRIBUTE_DIRECTORY)) {
_bLogToWininet = FALSE;
}
}
/*
bIsHosted = IsHosted();
if (bIsHosted && !lstrlenW(_szLogPath)) {
BOOL bRet;
WCHAR wzCorSystemDir[MAX_PATH];
WCHAR wzXSPAppCacheDir[MAX_PATH];
if (!GetCorSystemDirectory(wzCorSystemDir)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
PathRemoveBackslash(wzCorSystemDir);
wnsprintfW(wzXSPAppCacheDir, MAX_PATH, L"%ws\\%ws", wzCorSystemDir,
XSP_APP_CACHE_DIR);
dwAttr = GetFileAttributes(wzXSPAppCacheDir);
if (dwAttr == -1) {
bRet = CreateDirectory(wzXSPAppCacheDir, NULL);
if (!bRet) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
}
wnsprintfW(_szLogPath, MAX_PATH, L"%ws\\%ws", wzXSPAppCacheDir, XSP_FUSION_LOG_DIR);
dwAttr = GetFileAttributes(_szLogPath);
if (dwAttr == -1) {
bRet = CreateDirectory(_szLogPath, NULL);
if (!bRet) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
}
_bLogToWininet = FALSE;
}
*/
Exit:
SAFEDELETEARRAY(wzAppName);
return hr;
}
HRESULT CDebugLog::SetAsmName(LPCWSTR pwzAsmName)
{
HRESULT hr = S_OK;
int iLen;
if (_pwzAsmName) {
// You can only set the name once.
hr = S_FALSE;
goto Exit;
}
if (!pwzAsmName) {
hr = E_INVALIDARG;
goto Exit;
}
iLen = lstrlenW(pwzAsmName) + 1;
_pwzAsmName = NEW(WCHAR[iLen]);
if (!_pwzAsmName) {
hr = E_OUTOFMEMORY;
goto Exit;
}
lstrcpyW(_pwzAsmName, pwzAsmName);
Exit:
return hr;
}
HRESULT CDebugLog::SetDownloadType(DWORD dwFlags)
{
HRESULT hr = S_OK;
int iLen;
if(dwFlags & DOWNLOAD_FLAGS_PROGRESS_UI)
IF_FAILED_EXIT(_sDLType.Assign(DLTYPE_FOREGROUND));
else
IF_FAILED_EXIT(_sDLType.Assign(DLTYPE_BACKGROUND));
exit:
return hr;
}
HRESULT CDebugLog::SetAppName(LPCWSTR pwzAppName)
{
HRESULT hr = S_OK;
int iLen;
ASSERT(pwzAppName);
IF_FAILED_EXIT(_sAppName.Assign(pwzAppName));
exit:
return hr;
}
//
// IUnknown
//
STDMETHODIMP CDebugLog::QueryInterface(REFIID riid, void **ppv)
{
HRESULT hr = E_FAIL;
/*
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IFusionBindLog)) {
*ppv = static_cast<IFusionBindLog *>(this);
}
else {
*ppv = NULL;
hr = E_NOINTERFACE;
}
if (*ppv) {
AddRef();
}
*/
return hr;
}
STDMETHODIMP_(ULONG) CDebugLog::AddRef()
{
return InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) CDebugLog::Release()
{
ULONG ulRef;
ulRef = InterlockedDecrement(&_cRef);
if (ulRef == 0) {
delete this;
}
return ulRef;
}
//
// IFusionBindLog
//
STDMETHODIMP CDebugLog::GetResultCode()
{
return _hr;
}
HRESULT CDebugLog::GetLoggedMsgs(DWORD dwDetailLevel, CString& sLogMsgs )
{
HRESULT hr = S_OK;
MAKE_ERROR_MACROS_STATIC(hr);
BOOL bHaveMsgs = FALSE;
LISTNODE pos = NULL;
CDebugLogElement *pLogElem = NULL;
pos = _listDbgMsg.GetHeadPosition();
while (pos) {
pLogElem = _listDbgMsg.GetNext(pos);
ASSERT(pLogElem);
if (pLogElem->_dwDetailLvl <= dwDetailLevel) {
IF_FAILED_EXIT(sLogMsgs.Append(pLogElem->_pszMsg));
IF_FAILED_EXIT(sLogMsgs.Append( L"\r\n"));
bHaveMsgs = TRUE;
}
}
if(bHaveMsgs == FALSE)
hr = S_FALSE;
exit:
return hr;
}
STDMETHODIMP CDebugLog::GetBindLog(DWORD dwDetailLevel, LPWSTR pwzDebugLog,
DWORD *pcbDebugLog)
{
HRESULT hr = S_OK;
LISTNODE pos = NULL;
DWORD dwCharsReqd;
CDebugLogElement *pLogElem = NULL;
if (!pcbDebugLog) {
hr = E_INVALIDARG;
goto Exit;
}
pos = _listDbgMsg.GetHeadPosition();
if (!pos) {
// No entries in debug log!
hr = S_FALSE;
goto Exit;
}
// Calculate total size (entries + new line chars + NULL)
dwCharsReqd = 0;
while (pos) {
pLogElem = _listDbgMsg.GetNext(pos);
ASSERT(pLogElem);
if (pLogElem->_dwDetailLvl <= dwDetailLevel) {
dwCharsReqd += lstrlenW(pLogElem->_pszMsg) * sizeof(WCHAR);
dwCharsReqd += sizeof(L"\r\n");
}
}
dwCharsReqd += 1; // NULL char
if (!pwzDebugLog || *pcbDebugLog < dwCharsReqd) {
*pcbDebugLog = dwCharsReqd;
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
goto Exit;
}
*pwzDebugLog = L'\0';
pos = _listDbgMsg.GetHeadPosition();
while (pos) {
pLogElem = _listDbgMsg.GetNext(pos);
ASSERT(pLogElem);
if (pLogElem->_dwDetailLvl <= dwDetailLevel) {
StrCatW(pwzDebugLog, pLogElem->_pszMsg);
StrCatW(pwzDebugLog, L"\r\n");
}
}
ASSERT((DWORD)lstrlenW(pwzDebugLog) * sizeof(WCHAR) < dwCharsReqd);
Exit:
return hr;
}
//
// CDebugLog helpers
//
HRESULT CDebugLog::SetResultCode(HRESULT hr)
{
_hr = hr;
return S_OK;
}
HRESULT CDebugLog::DebugOut(DWORD dwDetailLvl, LPWSTR pwzFormatString, ...)
{
HRESULT hr = S_OK;
va_list args;
LPWSTR wzFormatString = NULL;
LPWSTR wzDebugStr = NULL;
/*
wzFormatString = NEW(WCHAR[MAX_DBG_STR_LEN]);
if (!wzFormatString) {
hr = E_OUTOFMEMORY;
goto Exit;
}
*/
wzDebugStr = NEW(WCHAR[MAX_DBG_STR_LEN]);
if (!wzDebugStr) {
hr = E_OUTOFMEMORY;
goto Exit;
}
/*
wzFormatString[0] = L'\0';
if (!WszLoadString(g_hInst, dwResId, wzFormatString, MAX_DBG_STR_LEN)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
*/
va_start(args, pwzFormatString);
wvnsprintfW(wzDebugStr, MAX_DBG_STR_LEN, pwzFormatString, args);
va_end(args);
hr = LogMessage(dwDetailLvl, wzDebugStr, FALSE);
if (FAILED(hr)) {
goto Exit;
}
Exit:
SAFEDELETEARRAY(wzDebugStr);
SAFEDELETEARRAY(wzFormatString);
return hr;
}
HRESULT CDebugLog::LogMessage(DWORD dwDetailLvl, LPCWSTR wzDebugStr, BOOL bPrepend)
{
HRESULT hr = S_OK;
CDebugLogElement *pLogElem = NULL;
hr = CDebugLogElement::Create(dwDetailLvl, wzDebugStr, &pLogElem);
if (FAILED(hr)) {
goto Exit;
}
_dwNumEntries += 1;
if (bPrepend) {
_listDbgMsg.AddHead(pLogElem);
}
else {
_listDbgMsg.AddTail(pLogElem);
}
Exit:
return hr;
}
HRESULT CDebugLog::DumpDebugLog(DWORD dwDetailLvl, HRESULT hrLog)
{
HRESULT hr = S_OK;
HANDLE hFile = INVALID_HANDLE_VALUE;
LISTNODE pos = NULL;
LPWSTR wzUrlName=NULL;
CDebugLogElement *pLogElem = NULL;
WCHAR *wzExtension = L"HTM";
WCHAR wzFileName[MAX_PATH];
WCHAR wzSiteName[MAX_PATH];
WCHAR wzAppLogDir[MAX_PATH];
LPWSTR wzEXEName = NULL;
LPWSTR wzResourceName = NULL;
FILETIME ftTime;
FILETIME ftExpireTime;
DWORD dwBytes;
DWORD dwSize;
BOOL bRet;
// CCriticalSection cs(&_cs);
/*
if (!g_dwLogFailures && !g_dwForceLog) {
return S_FALSE;
}
*/
/*
hr = cs.Lock();
if (FAILED(hr)) {
return hr;
}
*/
pos = _listDbgMsg.GetHeadPosition();
if (!pos) {
hr = S_FALSE;
goto Exit;
}
wzUrlName = NEW(WCHAR[MAX_URL_LENGTH+1]);
if (!wzUrlName)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
// Build the log entry URL and Wininet cache file
wnsprintfW(wzUrlName, MAX_URL_LENGTH, L"?ClickOnceErrorLog!exe=%ws!name=%ws", _sAppName._pwz, _sDLType._pwz);
if( dwDetailLvl == -1)
{
dwDetailLvl = g_dwLoggingLevel;
}
if (_bLogToWininet) {
// Replace all characters > 0x80 with '?'
dwSize = lstrlenW(wzUrlName);
for (unsigned i = 0; i < dwSize; i++) {
if (wzUrlName[i] > 0x80) {
wzUrlName[i] = L'?';
}
}
bRet = CreateUrlCacheEntryW(wzUrlName, 0, wzExtension, wzFileName, 0);
if (!bRet) {
goto Exit;
}
}
else {
wnsprintfW(wzAppLogDir, MAX_PATH, L"%ws\\%ws", _szLogPath, _wzEXEName);
if (GetFileAttributes(wzAppLogDir) == -1) {
BOOL bRet;
bRet = CreateDirectory(wzAppLogDir, NULL);
if (!bRet) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
}
if (PathIsURLW(_pwzAsmName)) {
// This was a where-ref bind. We can't spit out a filename w/
// the URL of the bind because the URL has invalid filename chars.
// The best we can do is show that it was a where-ref bind, and
// give the filename, and maybe the site.
dwSize = MAX_PATH;
hr = UrlGetPartW(_pwzAsmName, wzSiteName, &dwSize, URL_PART_HOSTNAME, 0);
if (FAILED(hr)) {
goto Exit;
}
wzResourceName = PathFindFileName(_pwzAsmName);
ASSERT(wzResourceName);
if (!lstrlenW(wzSiteName)) {
lstrcpyW(wzSiteName, L"LocalMachine");
}
wnsprintfW(wzFileName, MAX_PATH, L"%ws\\FusionBindError!exe=%ws!name=WhereRefBind!Host=(%ws)!FileName=(%ws).HTM",
wzAppLogDir, _wzEXEName, wzSiteName, wzResourceName);
}
else {
wnsprintfW(wzFileName, MAX_PATH, L"%ws\\FusionBindError!exe=%ws!name=%ws.HTM", wzAppLogDir, _wzEXEName, _pwzAsmName);
}
}
// Create the and write the log file
hr = CreateLogFile(&hFile, wzFileName, _wzEXEName, hrLog);
if (FAILED(hr)) {
goto Exit;
}
pos = _listDbgMsg.GetHeadPosition();
while (pos) {
pLogElem = _listDbgMsg.GetNext(pos);
ASSERT(pLogElem);
if (pLogElem->_dwDetailLvl <= dwDetailLvl) {
pLogElem->Dump(hFile);
WriteFile(hFile, DEBUG_LOG_NEW_LINE, lstrlenW(DEBUG_LOG_NEW_LINE) * sizeof(WCHAR),
&dwBytes, NULL);
}
}
// Close the log file and commit the wininet cache entry
hr = CloseLogFile(&hFile);
if (FAILED(hr)) {
goto Exit;
}
if (_bLogToWininet) {
GetSystemTimeAsFileTime(&ftTime);
ftExpireTime.dwLowDateTime = (DWORD)0;
ftExpireTime.dwHighDateTime = (DWORD)0;
bRet = CommitUrlCacheEntryW(wzUrlName, wzFileName, ftExpireTime, ftTime,
NORMAL_CACHE_ENTRY, NULL, 0, NULL, 0);
if (!bRet) {
hr = FusionpHresultFromLastError();
goto Exit;
}
}
Exit:
// cs.Unlock();
SAFEDELETEARRAY(wzUrlName);
return hr;
}
HRESULT CDebugLog::CloseLogFile(HANDLE *phFile)
{
HRESULT hr = S_OK;
DWORD dwBytes;
if (!phFile) {
hr = E_INVALIDARG;
goto Exit;
}
WriteFile(*phFile, DEBUG_LOG_HTML_END, lstrlenW(DEBUG_LOG_HTML_END) * sizeof(WCHAR),
&dwBytes, NULL);
CloseHandle(*phFile);
*phFile = INVALID_HANDLE_VALUE;
Exit:
return hr;
}
HRESULT CDebugLog::CreateLogFile(HANDLE *phFile, LPCWSTR wzFileName,
LPCWSTR wzEXEName, HRESULT hrLog)
{
HRESULT hr = S_OK;
SYSTEMTIME systime;
LPWSTR pwzFormatMessage = NULL;
DWORD dwFMResult = 0;
LPWSTR wzBuffer = NULL;
LPWSTR wzBuf = NULL;
LPWSTR wzResultText = NULL;
WCHAR wzDateBuffer[MAX_DATE_LEN];
WCHAR wzTimeBuffer[MAX_DATE_LEN];
if (!phFile || !wzFileName || !wzEXEName) {
hr = E_INVALIDARG;
goto Exit;
}
wzBuffer = NEW(WCHAR[MAX_DBG_STR_LEN]);
if (!wzBuffer) {
hr = E_OUTOFMEMORY;
goto Exit;
}
wzBuf = NEW(WCHAR[MAX_DBG_STR_LEN]);
if (!wzBuffer) {
hr = E_OUTOFMEMORY;
goto Exit;
}
wzResultText = NEW(WCHAR[MAX_DBG_STR_LEN]);
if (!wzResultText) {
hr = E_OUTOFMEMORY;
goto Exit;
}
*phFile = CreateFile(wzFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (*phFile == INVALID_HANDLE_VALUE) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
if (!_bWroteDetails) {
// Details
LogMessage(0, ID_COL_DETAILED_LOG, TRUE);
// Executable path
wnsprintfW(wzBuffer, MAX_DBG_STR_LEN, L"%ws %ws", ID_COL_EXECUTABLE, g_wzEXEPath);
LogMessage(0, wzBuffer, TRUE);
dwFMResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, 0, hrLog, 0,
(LPWSTR)&pwzFormatMessage, 0, NULL);
if (dwFMResult) {
wnsprintfW(wzBuffer, MAX_DBG_STR_LEN, ID_COL_FINAL_HR, hrLog, pwzFormatMessage);
}
else {
WCHAR wzNoDescription[MAX_DBG_STR_LEN] = L" ";
wnsprintfW(wzBuffer, MAX_DBG_STR_LEN, ID_COL_FINAL_HR, hrLog, wzNoDescription);
}
LogMessage(0, wzBuffer, TRUE);
// Header text
GetLocalTime(&systime);
if (!GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &systime, NULL, wzDateBuffer, MAX_DATE_LEN)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
if (!GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &systime, NULL, wzTimeBuffer, MAX_DATE_LEN)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
wnsprintfW(wzBuffer, MAX_DBG_STR_LEN, L"%ws (%ws @ %ws) *** (Version=%ws)\n", ID_COL_HEADER_TEXT, wzDateBuffer, wzTimeBuffer, VER_PRODUCTVERSION_STR_L);
LogMessage(0, wzBuffer, TRUE);
// HTML start/end
LogMessage(0, DEBUG_LOG_HTML_START, TRUE);
LogMessage(0, DEBUG_LOG_HTML_META_LANGUAGE, TRUE);
_bWroteDetails = TRUE;
}
Exit:
if (pwzFormatMessage) {
LocalFree(pwzFormatMessage);
}
SAFEDELETEARRAY(wzBuffer);
SAFEDELETEARRAY(wzBuf);
SAFEDELETEARRAY(wzResultText);
return hr;
}