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
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;
|
|
}
|
|
|