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.
1612 lines
52 KiB
1612 lines
52 KiB
// DBGLauncher.cpp : Implementation of WinMain
|
|
|
|
|
|
// Note: Proxy/Stub Information
|
|
// To build a separate proxy/stub DLL,
|
|
// run nmake -f DBGLauncherps.mk in the project directory.
|
|
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "Messages.h"
|
|
#include <time.h>
|
|
#include <sys/timeb.h>
|
|
#include <strsafe.h>
|
|
#include "DBGLauncher_i.c"
|
|
#include "ocamon.h"
|
|
#define MAX_QUEUE_OPEN_RETRY 5
|
|
|
|
|
|
|
|
static WCHAR strGuidMQTestType[] =
|
|
L"{c30e0960-a2c0-11cf-9785-00608cb3e80c}";
|
|
|
|
|
|
|
|
// Some useful macros
|
|
#define RELEASE(punk) if (punk) { (punk)->Release(); (punk) = NULL; }
|
|
#define ADDREF(punk) ((punk) ? (punk)->AddRef() : 0)
|
|
|
|
CServiceModule _Module;
|
|
HANDLE g_hStopEvent = NULL;
|
|
BOOL g_ReadQueueFlag = TRUE;
|
|
BEGIN_OBJECT_MAP(ObjectMap)
|
|
END_OBJECT_MAP()
|
|
|
|
|
|
LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
|
|
{
|
|
while (p1 != NULL && *p1 != NULL)
|
|
{
|
|
LPCTSTR p = p2;
|
|
while (p != NULL && *p != NULL)
|
|
{
|
|
if (*p1 == *p)
|
|
return CharNext(p1);
|
|
p = CharNext(p);
|
|
}
|
|
p1 = CharNext(p1);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Although some of these functions are big they are declared inline since they are only used once
|
|
|
|
inline HRESULT CServiceModule::RegisterServer(BOOL bRegTypeLib, BOOL bService)
|
|
{
|
|
HRESULT hr = CoInitialize(NULL);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Remove any previous service since it may point to
|
|
// the incorrect file
|
|
Uninstall();
|
|
SetupEventLog(FALSE);
|
|
// Add service entries
|
|
UpdateRegistryFromResource(IDR_DBGLauncher, TRUE);
|
|
|
|
// Adjust the AppID for Local Server or Service
|
|
CRegKey keyAppID;
|
|
LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE);
|
|
if (lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
|
|
CRegKey key;
|
|
lRes = key.Open(keyAppID, _T("{5D3C7CA6-DF04-4864-897D-83BF996692B3}"), KEY_WRITE);
|
|
if (lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
key.DeleteValue(_T("LocalService"));
|
|
|
|
if (bService)
|
|
{
|
|
key.SetValue(_T("DBGLauncher"), _T("LocalService") );
|
|
key.SetValue(_T("-Service"), _T("ServiceParameters"));
|
|
// Create service
|
|
Install();
|
|
}
|
|
|
|
// Add object entries
|
|
hr = CComModule::RegisterServer(bRegTypeLib);
|
|
|
|
CoUninitialize();
|
|
return hr;
|
|
}
|
|
|
|
inline HRESULT CServiceModule::UnregisterServer()
|
|
{
|
|
HRESULT hr = CoInitialize(NULL);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Remove service entries
|
|
UpdateRegistryFromResource(IDR_DBGLauncher, FALSE);
|
|
// Remove service
|
|
Uninstall();
|
|
// Remove object entries
|
|
CComModule::UnregisterServer(TRUE);
|
|
CoUninitialize();
|
|
return S_OK;
|
|
}
|
|
|
|
inline void CServiceModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, UINT nServiceNameID, const GUID* plibid)
|
|
{
|
|
CComModule::Init(p, h, plibid);
|
|
|
|
m_bService = TRUE;
|
|
|
|
LoadString(h, nServiceNameID, m_szServiceName, sizeof(m_szServiceName) / sizeof(TCHAR));
|
|
|
|
// set up the initial service status
|
|
m_hServiceStatus = NULL;
|
|
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
m_status.dwCurrentState = SERVICE_STOPPED;
|
|
m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
|
m_status.dwWin32ExitCode = 0;
|
|
m_status.dwServiceSpecificExitCode = 0;
|
|
m_status.dwCheckPoint = 0;
|
|
m_status.dwWaitHint = 0;
|
|
//
|
|
// Create Named Events
|
|
//
|
|
g_hStopEvent = CreateEvent(
|
|
NULL,
|
|
FALSE,
|
|
FALSE,
|
|
s_cszStopEvent
|
|
);
|
|
if(NULL == g_hStopEvent)
|
|
{
|
|
LogEvent( _T("Failed to create stop event: %s; hr=%ld"),
|
|
s_cszStopEvent,
|
|
GetLastError());
|
|
}
|
|
m_hMonNotifyPipe = NULL;
|
|
}
|
|
|
|
LONG CServiceModule::Unlock()
|
|
{
|
|
LONG l = CComModule::Unlock();
|
|
if (l == 0 && !m_bService)
|
|
PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
|
|
return l;
|
|
}
|
|
|
|
BOOL CServiceModule::IsInstalled()
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (hSCM != NULL)
|
|
{
|
|
SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_QUERY_CONFIG);
|
|
if (hService != NULL)
|
|
{
|
|
bResult = TRUE;
|
|
::CloseServiceHandle(hService);
|
|
}
|
|
::CloseServiceHandle(hSCM);
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
inline BOOL CServiceModule::Install()
|
|
{
|
|
if (IsInstalled())
|
|
return TRUE;
|
|
|
|
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (hSCM == NULL)
|
|
{
|
|
MessageBox(NULL, _T("Couldn't open service manager"), m_szServiceName, MB_OK);
|
|
return FALSE;
|
|
}
|
|
SetupEventLog(TRUE);
|
|
// Get the executable file path
|
|
TCHAR szFilePath[_MAX_PATH];
|
|
::GetModuleFileName(NULL, szFilePath, _MAX_PATH);
|
|
|
|
SC_HANDLE hService = ::CreateService(
|
|
hSCM, m_szServiceName, m_szServiceName,
|
|
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
|
|
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
|
|
szFilePath, NULL, NULL, _T("RPCSS\0"), NULL, NULL);
|
|
|
|
if (hService == NULL)
|
|
{
|
|
::CloseServiceHandle(hSCM);
|
|
MessageBox(NULL, _T("Couldn't create service"), m_szServiceName, MB_OK);
|
|
return FALSE;
|
|
}
|
|
SERVICE_FAILURE_ACTIONS Failure;
|
|
SC_ACTION Actions[3];
|
|
|
|
Failure.cActions = 3;
|
|
Failure.dwResetPeriod = 1200;
|
|
Failure.lpCommand = _T("");
|
|
Failure.lpRebootMsg = _T("");
|
|
Failure.lpsaActions = Actions;
|
|
|
|
Actions[0].Delay = 2000;
|
|
Actions[0].Type = SC_ACTION_RESTART;
|
|
|
|
Actions[1].Delay = 2000;
|
|
Actions[1].Type = SC_ACTION_RESTART;
|
|
|
|
Actions[2].Delay = 2000;
|
|
Actions[2].Type = SC_ACTION_RESTART;
|
|
|
|
::CloseServiceHandle(hService);
|
|
::CloseServiceHandle(hSCM);
|
|
return TRUE;
|
|
}
|
|
|
|
inline BOOL CServiceModule::Uninstall()
|
|
{
|
|
if (!IsInstalled())
|
|
return TRUE;
|
|
|
|
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (hSCM == NULL)
|
|
{
|
|
MessageBox(NULL, _T("Couldn't open service manager"), m_szServiceName, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_STOP | DELETE);
|
|
|
|
if (hService == NULL)
|
|
{
|
|
::CloseServiceHandle(hSCM);
|
|
MessageBox(NULL, _T("Couldn't open service"), m_szServiceName, MB_OK);
|
|
return FALSE;
|
|
}
|
|
SERVICE_STATUS status;
|
|
::ControlService(hService, SERVICE_CONTROL_STOP, &status);
|
|
|
|
BOOL bDelete = ::DeleteService(hService);
|
|
::CloseServiceHandle(hService);
|
|
::CloseServiceHandle(hSCM);
|
|
|
|
if (bDelete)
|
|
return TRUE;
|
|
|
|
MessageBox(NULL, _T("Service could not be deleted"), m_szServiceName, MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Logging functions
|
|
void CServiceModule::LogEvent(LPCTSTR pFormat, ...)
|
|
{
|
|
TCHAR chMsg[256];
|
|
HANDLE hEventSource;
|
|
LPTSTR lpszStrings[1];
|
|
va_list pArg;
|
|
|
|
va_start(pArg, pFormat);
|
|
// _vstprintf(chMsg, pFormat, pArg);
|
|
if (StringCbVPrintf(chMsg,sizeof chMsg, pFormat, pArg) != S_OK)
|
|
{
|
|
return;
|
|
}
|
|
va_end(pArg);
|
|
|
|
lpszStrings[0] = chMsg;
|
|
|
|
if (m_bService)
|
|
{
|
|
/* Get a handle to use with ReportEvent(). */
|
|
hEventSource = RegisterEventSource(NULL, m_szServiceName);
|
|
if (hEventSource != NULL)
|
|
{
|
|
/* Write to event log. */
|
|
|
|
ReportEvent(hEventSource, EVENTLOG_INFORMATION_TYPE, 0, EVENT_MESSAGE, NULL, 1, 0, (LPCTSTR*) &lpszStrings[0], NULL);
|
|
DeregisterEventSource(hEventSource);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// As we are not running as a service, just write the error to the console.
|
|
_putts(chMsg);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Service startup and registration
|
|
inline void CServiceModule::Start()
|
|
{
|
|
SERVICE_TABLE_ENTRY st[] =
|
|
{
|
|
{ m_szServiceName, _ServiceMain },
|
|
{ NULL, NULL }
|
|
};
|
|
if (m_bService && !::StartServiceCtrlDispatcher(st))
|
|
{
|
|
m_bService = FALSE;
|
|
}
|
|
if (m_bService == FALSE)
|
|
Run();
|
|
}
|
|
|
|
inline void CServiceModule::ServiceMain(DWORD /* dwArgc */, LPTSTR* /* lpszArgv */)
|
|
{
|
|
// Register the control request handler
|
|
m_status.dwCurrentState = SERVICE_START_PENDING;
|
|
m_hServiceStatus = RegisterServiceCtrlHandler(m_szServiceName, _Handler);
|
|
if (m_hServiceStatus == NULL)
|
|
{
|
|
LogEvent(_T("Handler not installed"));
|
|
return;
|
|
}
|
|
SetServiceStatus(SERVICE_START_PENDING);
|
|
|
|
m_status.dwWin32ExitCode = S_OK;
|
|
m_status.dwCheckPoint = 0;
|
|
m_status.dwWaitHint = 0;
|
|
|
|
// When the Run function returns, the service has stopped.
|
|
Run();
|
|
|
|
SetupEventLog(TRUE);
|
|
SetServiceStatus(SERVICE_STOPPED);
|
|
|
|
LogEvent(_T("Service stopped"));
|
|
}
|
|
|
|
inline void CServiceModule::Handler(DWORD dwOpcode)
|
|
{
|
|
switch (dwOpcode)
|
|
{
|
|
case SERVICE_CONTROL_STOP:
|
|
SetServiceStatus(SERVICE_STOP_PENDING);
|
|
// SetServiceStatus(SERVICE_STOP_PENDING);
|
|
|
|
if(NULL != g_hStopEvent)
|
|
{
|
|
if(FALSE == SetEvent( g_hStopEvent ))
|
|
{
|
|
LogFatalEvent( _T("Unable to signal Stop Event; Error: %ld"), GetLastError());
|
|
}
|
|
|
|
CloseHandle( g_hStopEvent );
|
|
}
|
|
/// PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
|
|
// break;
|
|
PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
|
|
break;
|
|
case SERVICE_CONTROL_PAUSE:
|
|
break;
|
|
case SERVICE_CONTROL_CONTINUE:
|
|
break;
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
break;
|
|
case SERVICE_CONTROL_SHUTDOWN:
|
|
break;
|
|
default:
|
|
LogEvent(_T("Bad service request"));
|
|
}
|
|
}
|
|
|
|
void WINAPI CServiceModule::_ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
|
|
{
|
|
_Module.ServiceMain(dwArgc, lpszArgv);
|
|
}
|
|
void WINAPI CServiceModule::_Handler(DWORD dwOpcode)
|
|
{
|
|
_Module.Handler(dwOpcode);
|
|
}
|
|
|
|
void CServiceModule::SetServiceStatus(DWORD dwState)
|
|
{
|
|
m_status.dwCurrentState = dwState;
|
|
::SetServiceStatus(m_hServiceStatus, &m_status);
|
|
}
|
|
|
|
void CServiceModule::Run()
|
|
{
|
|
BYTE *byteVersionBuff = NULL;
|
|
VS_FIXEDFILEINFO *pVersionInfo = NULL;
|
|
UINT uLength = 0;
|
|
_Module.dwThreadID = GetCurrentThreadId();
|
|
TCHAR szFilePath[_MAX_PATH];
|
|
DWORD dwPlaceHolder = 0;
|
|
|
|
// HRESULT hr = CoInitialize(NULL);
|
|
// If you are running on NT 4.0 or higher you can use the following call
|
|
// instead to make the EXE free threaded.
|
|
// This means that calls come in on a random RPC thread
|
|
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
|
|
_ASSERTE(SUCCEEDED(hr));
|
|
|
|
// This provides a NULL DACL which will allow access to everyone.
|
|
CSecurityDescriptor sd;
|
|
sd.InitializeFromThreadToken();
|
|
hr = CoInitializeSecurity(sd, -1, NULL, NULL,
|
|
RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
|
|
_ASSERTE(SUCCEEDED(hr));
|
|
|
|
hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE);
|
|
_ASSERTE(SUCCEEDED(hr));
|
|
|
|
|
|
ZeroMemory(szFilePath, sizeof szFilePath);
|
|
::GetModuleFileName(NULL, szFilePath, _MAX_PATH);
|
|
if (szFilePath[0] != _T('\0'))
|
|
{
|
|
DWORD dwBufferSize = GetFileVersionInfoSize(szFilePath,&dwPlaceHolder);
|
|
if (dwBufferSize > 0)
|
|
byteVersionBuff = (BYTE*) malloc (dwBufferSize);
|
|
if (byteVersionBuff)
|
|
{
|
|
GetFileVersionInfo(szFilePath,NULL,dwBufferSize,byteVersionBuff);
|
|
VerQueryValue(byteVersionBuff,_T("\\"),(VOID **) &pVersionInfo, &uLength);
|
|
|
|
LogEvent(_T("DbgLauncher service version: %d.%d.%d.%d Started."), HIWORD (pVersionInfo->dwFileVersionMS),LOWORD(pVersionInfo->dwFileVersionMS)
|
|
,HIWORD(pVersionInfo->dwFileVersionLS),LOWORD(pVersionInfo->dwFileVersionLS)) ;
|
|
}
|
|
}
|
|
|
|
// DWORD NameLength = sizeof(TCHAR) * (MAX_COMPUTERNAME_LENGTH + 1);
|
|
|
|
if (m_bService)
|
|
SetServiceStatus(SERVICE_RUNNING);
|
|
|
|
|
|
//
|
|
// Execute Archive Service
|
|
//
|
|
try
|
|
{
|
|
PrepareForDebuggerLaunch();
|
|
}
|
|
catch(...)
|
|
{
|
|
LogEvent( _T("dbgLauncher Service CRASHED !!! "));
|
|
}
|
|
if (m_hMonNotifyPipe != NULL &&
|
|
m_hMonNotifyPipe != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(m_hMonNotifyPipe);
|
|
m_hMonNotifyPipe = NULL;
|
|
}
|
|
MSG msg;
|
|
while (GetMessage(&msg, 0, 0, 0))
|
|
DispatchMessage(&msg);
|
|
|
|
_Module.RevokeClassObjects();
|
|
|
|
CoUninitialize();
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
|
|
HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
|
|
{
|
|
lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
|
|
_Module.Init(ObjectMap, hInstance, IDS_SERVICENAME, &LIBID_DBGLAUNCHERLib);
|
|
_Module.m_bService = TRUE;
|
|
|
|
TCHAR szTokens[] = _T("-/");
|
|
|
|
LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
|
|
while (lpszToken != NULL)
|
|
{
|
|
if (CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),
|
|
NORM_IGNORECASE,
|
|
lpszToken,
|
|
-1,
|
|
_T("UnregServer"),
|
|
-1 ) == CSTR_EQUAL)
|
|
|
|
// if (lstrcmpi(lpszToken, _T("UnregServer"))==0)
|
|
return _Module.UnregisterServer();
|
|
|
|
// Register as Local Server
|
|
if (CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),
|
|
NORM_IGNORECASE,
|
|
lpszToken,
|
|
-1,
|
|
_T("RegServer"),
|
|
-1 ) == CSTR_EQUAL)
|
|
|
|
//if (lstrcmpi(lpszToken, _T("RegServer"))==0)
|
|
return _Module.RegisterServer(TRUE, FALSE);
|
|
|
|
// Register as Service
|
|
if (CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT),
|
|
NORM_IGNORECASE,
|
|
lpszToken,
|
|
-1,
|
|
_T("Service"),
|
|
-1 ) == CSTR_EQUAL)
|
|
|
|
// if (lstrcmpi(lpszToken, _T("Service"))==0)
|
|
return _Module.RegisterServer(TRUE, TRUE);
|
|
|
|
lpszToken = FindOneOf(lpszToken, szTokens);
|
|
}
|
|
|
|
// Are we Service or Local Server
|
|
CRegKey keyAppID;
|
|
LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_READ);
|
|
if (lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
|
|
CRegKey key;
|
|
lRes = key.Open(keyAppID, _T("{5D3C7CA6-DF04-4864-897D-83BF996692B3}"), KEY_READ);
|
|
if (lRes != ERROR_SUCCESS)
|
|
return lRes;
|
|
|
|
TCHAR szValue[_MAX_PATH];
|
|
DWORD dwLen = _MAX_PATH;
|
|
lRes = key.QueryValue(szValue,_T("LocalService"), &dwLen);
|
|
|
|
_Module.m_bService = FALSE;
|
|
if (lRes == ERROR_SUCCESS)
|
|
_Module.m_bService = TRUE;
|
|
|
|
_Module.Start();
|
|
|
|
// When we get here, the service has been stopped
|
|
return _Module.m_status.dwWin32ExitCode;
|
|
}
|
|
|
|
BOOL
|
|
CServiceModule::GetServiceParams(SVCPARAMS *ServiceParams)
|
|
{
|
|
HKEY hHKLM;
|
|
HKEY hDbgLauncherKey;
|
|
BYTE Buffer[MAX_PATH + 1];
|
|
DWORD Type;
|
|
DWORD BufferSize = MAX_PATH +1; // Set for largest value
|
|
BOOL Status = TRUE;
|
|
|
|
if(!RegConnectRegistry(NULL, HKEY_LOCAL_MACHINE, &hHKLM))
|
|
{
|
|
|
|
if(!RegOpenKeyEx(hHKLM,_T("Software\\Microsoft\\DbgLauncherSvc"), 0, KEY_ALL_ACCESS, &hDbgLauncherKey))
|
|
{
|
|
// Get the input queue directory path
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("DebuggerName"), 0, &Type, Buffer, &BufferSize) != ERROR_SUCCESS)
|
|
{
|
|
LogEvent(_T("Failed to get InputQueue value from registry."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (StringCbCopy (ServiceParams->DebuggerName, sizeof ServiceParams->DebuggerName,(TCHAR *) Buffer)!= S_OK)
|
|
{
|
|
LogEvent (_T("Failed to copy debuggername reg value to ServiceParams->DebuggerName"));
|
|
Status = FALSE;
|
|
}
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
// Now get the Primary Queue connection string
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("PrimaryQueue"), 0, &Type, Buffer, &BufferSize) != ERROR_SUCCESS)
|
|
{
|
|
LogEvent(_T("Failed to get PrimaryQueue value from registry."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (StringCbCopy(ServiceParams->PrimaryQueue,sizeof ServiceParams->PrimaryQueue, (TCHAR *) Buffer)!= S_OK)
|
|
{
|
|
LogEvent (_T("Failed to copy PrimaryQueue reg value to ServiceParams->PrimaryQueue"));
|
|
Status = FALSE;
|
|
}
|
|
|
|
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
|
|
// Now get the Primary Queue connection string
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("SecondaryQueue"), 0, &Type, Buffer, &BufferSize) != ERROR_SUCCESS)
|
|
{
|
|
LogEvent(_T("Failed to get SecondaryQueue value from registry."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (StringCbCopy(ServiceParams->SecondaryQueue,sizeof ServiceParams->SecondaryQueue, (TCHAR *) Buffer)!= S_OK)
|
|
{
|
|
LogEvent (_T("Failed to copy SecondaryQueue reg value to ServiceParams->SecondaryQueue"));
|
|
Status = FALSE;
|
|
}
|
|
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
|
|
|
|
// now get the primary response queue
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("PrimaryResponseQueue"), 0, &Type, Buffer, &BufferSize) != ERROR_SUCCESS)
|
|
{
|
|
LogEvent(_T("Failed to get Primary ResponseQueue value from registry."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (StringCbCopy(ServiceParams->PrimaryResponseQueue,sizeof ServiceParams->PrimaryResponseQueue, (TCHAR *) Buffer) != S_OK)
|
|
{
|
|
LogEvent (_T("Failed to copy PrimaryResponseQueue reg value to ServiceParams->PrimaryResponseQueue"));
|
|
Status = FALSE;
|
|
}
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
|
|
// now get the secondary response queue
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("SecondaryResponseQueue"), 0, &Type, Buffer, &BufferSize) != ERROR_SUCCESS)
|
|
{
|
|
LogEvent(_T("Failed to get Secondary ResponseQueue value from registry."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (StringCbCopy(ServiceParams->SecondaryResponseQueue,sizeof ServiceParams->SecondaryResponseQueue, (TCHAR *) Buffer)!= S_OK)
|
|
{
|
|
LogEvent (_T("Failed to copy SecondaryResponseQueue reg value to ServiceParams->SecondaryResponseQueue"));
|
|
Status = FALSE;
|
|
}
|
|
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
// Now get the ini release point
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("IniInstallLocation"), 0, &Type, Buffer, &BufferSize) != ERROR_SUCCESS)
|
|
{
|
|
LogEvent(_T("Failed to get IniInstallLocation Queue value from registry."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (StringCbCopy(ServiceParams->IniInstallLocation,sizeof ServiceParams->IniInstallLocation, (TCHAR *) Buffer)!= S_OK)
|
|
{
|
|
LogEvent (_T("Failed to copy IniInstallLocation reg value to ServiceParams->IniInstallLocation"));
|
|
Status = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
|
|
|
|
// Now get the Symbols server connection string
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("SymSrv"), 0, &Type, Buffer, &BufferSize) != ERROR_SUCCESS)
|
|
{
|
|
LogFatalEvent(_T("Failed to get the symbol server value from the registry."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (StringCbCopy(ServiceParams->Symsrv,sizeof ServiceParams->Symsrv, (TCHAR *) Buffer) != S_OK)
|
|
{
|
|
LogEvent (_T("Failed to copy Symsrv reg value to ServiceParams->Symsrv"));
|
|
Status = FALSE;
|
|
}
|
|
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
|
|
|
|
// Now get the Delay -- Min time between kd launches
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("Delay"), 0, &Type, Buffer, &BufferSize))
|
|
{
|
|
LogEvent(_T("Failed to get the min delay between dbg launches."));
|
|
}
|
|
else
|
|
{
|
|
ServiceParams->dwDelay = *((DWORD*)Buffer);
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
|
|
// Now get the Primary Queue delay
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("PrimaryInterval"), 0, &Type, Buffer, &BufferSize))
|
|
{
|
|
LogFatalEvent(_T("Failed to get the Primary queue wait interval."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ServiceParams->dwPrimaryWait = *((DWORD*)Buffer);
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
|
|
|
|
|
|
// Now get the Primary Queue delay
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("IniWaitTime"), 0, &Type, Buffer, &BufferSize))
|
|
{
|
|
LogFatalEvent(_T("Failed to get the triage.Ini wait interval."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ServiceParams->IniCheckWaitTime = *((DWORD*)Buffer);
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
|
|
// Now get the Memory usage threshold
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("MaxKdProcesses"), 0, &Type, Buffer, &BufferSize))
|
|
{
|
|
LogFatalEvent(_T("Failed to get the Max Kd Processes setting."));
|
|
Status = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ServiceParams->dwMaxKdProcesses = *((DWORD*)Buffer);
|
|
}
|
|
BufferSize = MAX_PATH +1;
|
|
ZeroMemory(Buffer, BufferSize);
|
|
|
|
// Now get the Memory usage threshold
|
|
if (RegQueryValueEx(hDbgLauncherKey,_T("MaxDumpSize"), 0, &Type, Buffer, &BufferSize))
|
|
{
|
|
LogEvent(_T("Failed to get the Max Dump Size setting."));
|
|
ServiceParams->dwMaxDumpSize = -1;
|
|
}
|
|
else
|
|
{
|
|
ServiceParams->dwMaxDumpSize = *((DWORD*)Buffer);
|
|
}
|
|
RegCloseKey(hHKLM);
|
|
RegCloseKey(hDbgLauncherKey);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
RegCloseKey(hHKLM);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
return FALSE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
CServiceModule::CheckForIni (SVCPARAMS *ServiceParams)
|
|
{
|
|
FILETIME CreationTimeCurrent;
|
|
FILETIME CreationTimeNew;
|
|
TCHAR IniFileName[MAX_PATH];
|
|
TCHAR DebuggerPath[MAX_PATH];
|
|
TCHAR *Temp = NULL;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
HANDLE hFile2 = INVALID_HANDLE_VALUE;
|
|
|
|
ZeroMemory (&CreationTimeCurrent, sizeof FILETIME);
|
|
ZeroMemory (&CreationTimeNew, sizeof FILETIME);
|
|
|
|
if (_tcslen(ServiceParams->DebuggerName) + _tcslen(_T("\\winxp\\triage.ini")) < MAX_PATH)
|
|
{
|
|
if (StringCbCopy(DebuggerPath, sizeof DebuggerPath, ServiceParams->DebuggerName)!= S_OK)
|
|
{
|
|
LogEvent(_T("CheckForIni: Failed to build Debugger Path"));
|
|
}
|
|
Temp = DebuggerPath;
|
|
Temp += _tcslen(DebuggerPath);
|
|
if (Temp != DebuggerPath)
|
|
{
|
|
while(*Temp != _T('\\'))
|
|
{
|
|
-- Temp;
|
|
}
|
|
*(Temp+1) = _T('\0');
|
|
}
|
|
// Get the file path of the debugger remove the ocakd.exe string then add triage\\triage.ini
|
|
if (StringCbCat (DebuggerPath,sizeof DebuggerPath, _T("winxp\\triage.ini")) != S_OK)
|
|
{
|
|
LogEvent(_T("CheckForIni: Failed to build debugger path"));
|
|
}
|
|
// Check to see if we need a new triage.ini file.
|
|
// open a shared read handle to the existing ini file.
|
|
hFile = CreateFile(DebuggerPath,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
0,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
// Get the time date stamp of the existing triage ini file.
|
|
if ( GetFileTime(hFile,NULL,NULL,&CreationTimeCurrent) )
|
|
{
|
|
// Now get the filetime for the triage.ini replacement.
|
|
hFile2 = CreateFile(ServiceParams->IniInstallLocation,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
0,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hFile2 != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (GetFileTime(hFile2, NULL,NULL,&CreationTimeNew))
|
|
{
|
|
// LogEvent (_T("Comparing the creation times"));
|
|
if ( CompareFileTime( &CreationTimeNew , &CreationTimeCurrent) == 1)
|
|
{
|
|
// copy the new file here.
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle (hFile);
|
|
if (hFile2 != INVALID_HANDLE_VALUE)
|
|
CloseHandle (hFile2);
|
|
if (CopyFile(ServiceParams->IniInstallLocation, DebuggerPath,FALSE) )
|
|
{
|
|
// LogEvent(_T("Successfully copied triage.ini from: %s to %s"),
|
|
// ServiceParams->IniInstallLocation, DebuggerPath);
|
|
;
|
|
}
|
|
else
|
|
{
|
|
// LogEvent(_T("Copy of file:%s to %s failed\n error code: %d"),ServiceParams->IniInstallLocation, DebuggerPath, GetLastError());
|
|
;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
if (hFile2 != INVALID_HANDLE_VALUE)
|
|
CloseHandle (hFile2);
|
|
}
|
|
}
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle (hFile);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
HRESULT CServiceModule::ConnectToMSMQ(QUEUEHANDLE *hQueue, wchar_t *QueueConnectStr)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called when the WWW service is shutdown.
|
|
|
|
Arguments:
|
|
|
|
dwFlags - HSE_TERM_ADVISORY_UNLOAD or HSE_TERM_MUST_UNLOAD
|
|
|
|
Return Value:
|
|
|
|
TRUE when extension is ready to be unloaded,
|
|
|
|
--*/
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
DWORD i;
|
|
i = 0;
|
|
|
|
Hr = MQOpenQueue(QueueConnectStr,
|
|
MQ_RECEIVE_ACCESS,
|
|
MQ_DENY_NONE,
|
|
hQueue);
|
|
return Hr;
|
|
|
|
}
|
|
BOOL CServiceModule::Initialize(PSVCPARAMS pParams)
|
|
{
|
|
HRESULT hr;
|
|
if (!GetServiceParams(pParams) )
|
|
{
|
|
LogFatalEvent(_T("Failed to read initialization data from the registry."));
|
|
return FALSE;
|
|
}
|
|
|
|
//ConnectToMSMQ
|
|
hr = ConnectToMSMQ(&(pParams->hPrimaryQueue),pParams->PrimaryQueue);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LogEvent(_T("Connected to primary Queue"));
|
|
//pParams->PrimaryConnected = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//pParams->PrimaryConnected = FALSE;
|
|
LogEvent(_T("Cannot connected to primary Queue %s, error %lx"), pParams->PrimaryQueue, hr);
|
|
}
|
|
hr = ConnectToMSMQ(&(pParams->hSecondaryQueue),pParams->SecondaryQueue);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//pParams->PrimaryConnected = TRUE;
|
|
LogEvent(_T("Connected to secondary Queue"));
|
|
}
|
|
else
|
|
{
|
|
//pParams->PrimaryConnected = FALSE;
|
|
LogEvent(_T("Cannot connected to secondary Queue %s, error %lx"), pParams->SecondaryQueue, hr);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CServiceModule::ReceiveQueueMessage(PSVCPARAMS pParams,
|
|
wchar_t *RecMessageBody,
|
|
wchar_t *szMessageGuid,
|
|
BOOL *bUsePrimary,
|
|
int *Type,
|
|
wchar_t *szSR)
|
|
|
|
{
|
|
MSGPROPID PropIds[5];
|
|
MQPROPVARIANT PropVariants[5];
|
|
HRESULT hrProps[5];
|
|
MQMSGPROPS MessageProps;
|
|
DWORD i = 0;
|
|
wchar_t RecLabel[100];
|
|
wchar_t LocalRecBody[MAX_PATH];
|
|
DWORD RecMessageBodySize = sizeof LocalRecBody;
|
|
DWORD RecLabelLength = sizeof RecLabel;
|
|
HRESULT hResult = 0;
|
|
BOOL Status = FALSE;
|
|
|
|
TCHAR *Temp = NULL;
|
|
|
|
|
|
|
|
|
|
ZeroMemory(LocalRecBody,sizeof LocalRecBody);
|
|
ZeroMemory(RecLabel,sizeof RecLabel);
|
|
|
|
i = 0;
|
|
PropIds[i] = PROPID_M_LABEL_LEN;
|
|
PropVariants[i].vt = VT_UI4;
|
|
PropVariants[i].ulVal = RecLabelLength;
|
|
i++;
|
|
|
|
PropIds[i] = PROPID_M_LABEL;
|
|
PropVariants[i].vt = VT_LPWSTR;
|
|
PropVariants[i].pwszVal = RecLabel;
|
|
i++;
|
|
|
|
MessageProps.aPropID = PropIds;
|
|
MessageProps.aPropVar = PropVariants;
|
|
MessageProps.aStatus = hrProps;
|
|
MessageProps.cProp = i;
|
|
|
|
// retrieve the current message
|
|
i = 0;
|
|
PropIds[i] = PROPID_M_LABEL_LEN;
|
|
PropVariants[i].vt = VT_UI4;
|
|
PropVariants[i].ulVal = RecLabelLength;
|
|
i++;
|
|
|
|
PropIds[i] = PROPID_M_LABEL;
|
|
PropVariants[i].vt = VT_LPWSTR;
|
|
PropVariants[i].pwszVal = RecLabel;
|
|
|
|
i++;
|
|
PropIds[i] = PROPID_M_BODY_SIZE;
|
|
PropVariants[i].vt = VT_UI4;
|
|
|
|
i++;
|
|
PropIds[i] = PROPID_M_BODY_TYPE;
|
|
PropVariants[i].vt = VT_UI4;
|
|
|
|
i++;
|
|
PropIds[i] = PROPID_M_BODY;
|
|
PropVariants[i].vt = VT_VECTOR|VT_UI1;
|
|
PropVariants[i].caub.pElems = (LPBYTE) LocalRecBody;
|
|
PropVariants[i].caub.cElems = RecMessageBodySize;
|
|
|
|
i++;
|
|
|
|
MessageProps.aPropID = PropIds;
|
|
MessageProps.aPropVar = PropVariants;
|
|
MessageProps.aStatus = hrProps;
|
|
MessageProps.cProp = i;
|
|
|
|
hResult = MQReceiveMessage( pParams->hPrimaryQueue,
|
|
0,
|
|
MQ_ACTION_RECEIVE,
|
|
&MessageProps,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
MQ_NO_TRANSACTION);
|
|
|
|
if (FAILED (hResult) )
|
|
{
|
|
|
|
if (hResult != (HRESULT) MQ_ERROR_IO_TIMEOUT)
|
|
{
|
|
if (hResult == (HRESULT) MQ_ERROR_QUEUE_NOT_AVAILABLE)
|
|
{
|
|
// Non Fatal Event
|
|
LogFatalEvent(_T("The %s MSMQ is unavailable."), pParams->PrimaryQueue );
|
|
}
|
|
else
|
|
{
|
|
if (hResult == (HRESULT) MQ_ERROR_INVALID_HANDLE)
|
|
{
|
|
// Close the current handle and attempt to reconnect to the MSMQ
|
|
MQCloseQueue( pParams->hPrimaryQueue );
|
|
ConnectToMSMQ(&(pParams->hPrimaryQueue), pParams->PrimaryQueue );
|
|
}
|
|
}
|
|
}
|
|
//g_ReadQueueFlag = !g_ReadQueueFlag;
|
|
hResult = MQReceiveMessage( pParams->hSecondaryQueue,
|
|
0,
|
|
MQ_ACTION_RECEIVE,
|
|
&MessageProps,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
MQ_NO_TRANSACTION);
|
|
if (FAILED(hResult) )
|
|
{
|
|
Status = FALSE;
|
|
|
|
if (hResult != (HRESULT)MQ_ERROR_IO_TIMEOUT)
|
|
{
|
|
if (hResult == (HRESULT)MQ_ERROR_QUEUE_NOT_AVAILABLE)
|
|
{
|
|
// Non Fatal Event
|
|
LogFatalEvent(_T("The %s MSMQ is unavailable."), pParams->SecondaryQueue);
|
|
}
|
|
else
|
|
{
|
|
if (hResult == (HRESULT)MQ_ERROR_INVALID_HANDLE)
|
|
{
|
|
// Close the current handle and attempt to reconnect to the MSMQ
|
|
MQCloseQueue(pParams->hSecondaryQueue);
|
|
ConnectToMSMQ(&(pParams->hSecondaryQueue), pParams->SecondaryQueue);
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
//
|
|
// We have valid message from SecondaryQueue
|
|
//
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// We have valid message from Primary Queue
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// Copy the messge parameters
|
|
//
|
|
if (StringCbCopy(RecMessageBody,RecMessageBodySize, LocalRecBody) != S_OK)
|
|
{
|
|
LogEvent(_T("Failed to copy the recieved message body to RecMessageBody"));
|
|
}
|
|
if (StringCbCopy(szMessageGuid,RecLabelLength, RecLabel) != S_OK)
|
|
{
|
|
LogEvent(_T("Failed to copy the RecLabel into szMessageGuid."));
|
|
}
|
|
Status = TRUE;
|
|
*bUsePrimary = TRUE;
|
|
Temp = RecMessageBody;
|
|
while ( (*Temp != _T(';')) && (*Temp != _T('\0')))
|
|
{
|
|
++Temp;
|
|
}
|
|
if (*Temp != _T('\0'))
|
|
{
|
|
*Type = _wtoi (Temp+1);
|
|
// terminate the string here.
|
|
*Temp = _T('\0');
|
|
}
|
|
else
|
|
{
|
|
*Type = 1;
|
|
}
|
|
|
|
|
|
Temp = _tcsstr(LocalRecBody, _T(";SR="));
|
|
if (Temp != NULL)
|
|
{
|
|
// we got a SR number in message
|
|
Temp += 4;
|
|
StringCbCopy(szSR, 50, Temp);
|
|
} else
|
|
{
|
|
*szSR = _T('\0');
|
|
}
|
|
|
|
// Flip the read from queue flag for the next call
|
|
//g_ReadQueueFlag = !g_ReadQueueFlag;
|
|
return Status;
|
|
}
|
|
|
|
ULONG64
|
|
CServiceModule::GetFileSize(
|
|
LPWSTR wszFile
|
|
)
|
|
{
|
|
HANDLE hFile;
|
|
DWORD dwFileSize, dwFileSizeHi;
|
|
|
|
hFile = CreateFileW(wszFile, GENERIC_READ,
|
|
FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (hFile != NULL && hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
dwFileSizeHi = 0;
|
|
dwFileSize=::GetFileSize(hFile,&dwFileSizeHi);
|
|
|
|
return (ULONG64) dwFileSize + ((ULONG64)dwFileSizeHi << 32);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
VOID
|
|
CServiceModule::NotifyDebuggerLaunch(
|
|
PDBADDCRASH_PARAMS pDbParams
|
|
)
|
|
{
|
|
HANDLE hPipe;
|
|
DWORD dwMode, cbWritten;
|
|
OCAKD_MONITOR_MESSAGE Msg;
|
|
OVERLAPPED WriteOverlapped;
|
|
|
|
Msg.MessageId = OKD_MESSAGE_DBGLAUNCH_NOTIFY;
|
|
Msg.u.DbglNotice.SizeOfStruct = sizeof(Msg.u.DbglNotice);
|
|
Msg.u.DbglNotice.Source = pDbParams->Source;
|
|
Msg.u.DbglNotice.nKdsRunning = m_DebuggerCount;
|
|
if (StringCbPrintfA(Msg.u.DbglNotice.CrashGuid, sizeof(Msg.u.DbglNotice.CrashGuid),
|
|
"%ws", pDbParams->Guid) != S_OK ||
|
|
StringCbPrintfA(Msg.u.DbglNotice.OriginalPath,sizeof(Msg.u.DbglNotice.OriginalPath),
|
|
"%ws", pDbParams->DumpPath) != S_OK)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
for (hPipe = m_hMonNotifyPipe;m_hMonNotifyPipe == NULL;)
|
|
{
|
|
hPipe = CreateFile(c_tszCollectPipeName, FILE_WRITE_DATA,
|
|
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
|
|
NULL);
|
|
if (hPipe != INVALID_HANDLE_VALUE)
|
|
{
|
|
m_hMonNotifyPipe = hPipe;
|
|
break;
|
|
}
|
|
if (GetLastError() != ERROR_PIPE_BUSY)
|
|
{
|
|
return;
|
|
}
|
|
// Do not wait long, this might block other processes
|
|
if (!WaitNamedPipe(c_tszCollectPipeName, 5*1000))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// We are now connected to pipe
|
|
|
|
WriteOverlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
|
if (WriteOverlapped.hEvent != NULL)
|
|
{
|
|
// Send crash information to monitor pipe
|
|
if (!WriteFile(hPipe, (LPVOID) &Msg, sizeof(Msg),
|
|
&cbWritten, &WriteOverlapped))
|
|
{
|
|
|
|
if (GetLastError() == ERROR_NO_DATA ||
|
|
GetLastError() == ERROR_BAD_PIPE)
|
|
{
|
|
// Open a different pipe next time
|
|
CloseHandle(hPipe);
|
|
m_hMonNotifyPipe = NULL;
|
|
} else if (GetLastError() == ERROR_IO_PENDING ||
|
|
!GetOverlappedResult(hPipe, &WriteOverlapped, &cbWritten,
|
|
TRUE))
|
|
{
|
|
// failed to write, exit silently
|
|
// Its up to monitor if it is keeping track of kds launched
|
|
} else
|
|
{
|
|
// Open a different pipe next time
|
|
CloseHandle(hPipe);
|
|
m_hMonNotifyPipe = NULL;
|
|
}
|
|
|
|
}
|
|
CloseHandle(WriteOverlapped.hEvent);
|
|
}
|
|
FlushFileBuffers(hPipe);
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL CServiceModule::LaunchDebugger(
|
|
PDBADDCRASH_PARAMS pDbParams,
|
|
PPROCESS_INFORMATION pDbgProcess
|
|
)
|
|
{
|
|
STARTUPINFO StartupInfo;
|
|
wchar_t CommandLine [1024];
|
|
wchar_t SrParam[100];
|
|
HRESULT hr;
|
|
|
|
ZeroMemory(&StartupInfo,sizeof(STARTUPINFO));
|
|
StartupInfo.cb = sizeof(STARTUPINFO);
|
|
|
|
if ((pDbParams->dwMaxDumpSize != 0) && (pDbParams->dwMaxDumpSize != -1) &&
|
|
(GetFileSize(pDbParams->DumpPath) > pDbParams->dwMaxDumpSize))
|
|
{
|
|
LogEvent(_T("Dump %s is too large, deleting file\n"), pDbParams->DumpPath);
|
|
DeleteFileW(pDbParams->DumpPath);
|
|
return FALSE;
|
|
}
|
|
if (pDbParams->SrNumber[0])
|
|
{
|
|
hr = StringCbPrintf(SrParam, sizeof(SrParam), _T(" -sr %s"), pDbParams->SrNumber);
|
|
if (hr != S_OK)
|
|
{
|
|
LogEvent(_T("Bad SR %s: %lx"), pDbParams->SrNumber, hr);
|
|
return FALSE;
|
|
}
|
|
} else
|
|
{
|
|
SrParam[0] = _T('\0');
|
|
}
|
|
if ((hr = StringCbPrintf(CommandLine,sizeof CommandLine,
|
|
_T("%s -i %s -y %s -z \"%s\" -c \"!dbaddcrash -source %d -g %s -s %s -p %s%s;q\""),
|
|
pDbParams->Debugger,
|
|
pDbParams->SymPath,
|
|
pDbParams->SymPath,
|
|
pDbParams->DumpPath,
|
|
pDbParams->Source,
|
|
pDbParams->Guid,
|
|
pDbParams->ResponseMQ,
|
|
pDbParams->DumpPath,
|
|
SrParam)) != S_OK)
|
|
{
|
|
LogEvent(_T("Failed to build command line: %lx"), hr);
|
|
}
|
|
//LogEvent(_T("CommandLine Guid=%s queue=%d"),szMessageLabel,bUsePrimary);
|
|
//LogEvent(_T("CommandLine Path=%s"),szFilePath);
|
|
//LogEvent(_T("CommandLine: %s"),CommandLine);
|
|
if (!CreateProcess(NULL,
|
|
CommandLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
//CREATE_NEW_CONSOLE,
|
|
CREATE_NO_WINDOW,
|
|
NULL,
|
|
NULL,
|
|
&StartupInfo,
|
|
pDbgProcess))
|
|
{
|
|
hr = GetLastError();
|
|
LogEvent(_T("Failed to launch debugger. Commandline %s, error %lx\n"), CommandLine, hr);
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Notify Site monitor of debugger launch
|
|
//
|
|
NotifyDebuggerLaunch(pDbParams);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CServiceModule::PrepareForDebuggerLaunch()
|
|
{
|
|
|
|
HANDLE ProcessHandles[50];
|
|
PROCESS_INFORMATION ProcessInfo;
|
|
wchar_t szFilePath[MAX_PATH];
|
|
wchar_t szSR[100];
|
|
HRESULT hr = 0;
|
|
HANDLE hStopEvent = INVALID_HANDLE_VALUE;
|
|
SVCPARAMS ServiceParams;
|
|
DWORD dwIndex = 0;
|
|
DWORD FreeIndex = 0;
|
|
DWORD dwWaitResult = 0;
|
|
BOOL Done = FALSE;
|
|
__time64_t CurrentTime = 0;
|
|
__time64_t NextCheckTime = 0;
|
|
wchar_t szMessageLabel[255];
|
|
BOOL bUsePrimary = FALSE;
|
|
int Type = 1;
|
|
DBADDCRASH_PARAMS DbParams;
|
|
|
|
ZeroMemory (ProcessHandles,sizeof ProcessHandles);
|
|
ZeroMemory(&ServiceParams,sizeof SVCPARAMS);
|
|
ZeroMemory (szMessageLabel, sizeof szMessageLabel);
|
|
ZeroMemory (szFilePath, sizeof szFilePath);
|
|
ZeroMemory(&DbParams, sizeof(DbParams));
|
|
|
|
m_DebuggerCount = 0;
|
|
hStopEvent = OpenEvent(
|
|
EVENT_ALL_ACCESS,
|
|
FALSE,
|
|
s_cszStopEvent
|
|
);
|
|
|
|
if (hStopEvent == NULL)
|
|
{
|
|
LogFatalEvent(_T("Failed to open stop event. Terminating"));
|
|
goto Done;
|
|
}
|
|
|
|
// get reg data
|
|
|
|
|
|
// Insert the stop event into the ocakd queue
|
|
++ m_DebuggerCount;
|
|
ProcessHandles[m_DebuggerCount -1] = hStopEvent;
|
|
|
|
if (!Initialize(&ServiceParams))
|
|
{
|
|
goto Done;
|
|
}
|
|
// fill the ocakd queue
|
|
Done = FALSE;
|
|
|
|
|
|
while ( (m_DebuggerCount <= ServiceParams.dwMaxKdProcesses+1 ) && (!Done))
|
|
{
|
|
|
|
if (!ReceiveQueueMessage(&ServiceParams, szFilePath, szMessageLabel, &bUsePrimary, &Type, szSR))
|
|
{
|
|
|
|
Done = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DbParams.Debugger = ServiceParams.DebuggerName;
|
|
DbParams.DumpPath = szFilePath;
|
|
DbParams.Guid = szMessageLabel;
|
|
DbParams.SrNumber = szSR;
|
|
DbParams.ResponseMQ = (bUsePrimary) ?
|
|
ServiceParams.PrimaryResponseQueue : ServiceParams.SecondaryResponseQueue;
|
|
DbParams.SymPath = ServiceParams.Symsrv;
|
|
DbParams.Source = Type;
|
|
DbParams.dwMaxDumpSize = ServiceParams.dwMaxDumpSize;
|
|
|
|
if (LaunchDebugger(&DbParams, &ProcessInfo))
|
|
{
|
|
// LogEvent(_T("Launched: %s for file: %s with guid:%s and source: %d with return queue =%s"),
|
|
// ServiceParams.DebuggerName,szFilePath, szMessageLabel, Type, (bUsePrimary) ? ServiceParams.PrimaryResponseQueue : ServiceParams.SecondaryResponseQueue);
|
|
++ m_DebuggerCount;
|
|
ProcessHandles[m_DebuggerCount -1] = ProcessInfo.hProcess;
|
|
CloseHandle( ProcessInfo.hThread );
|
|
|
|
} // end else
|
|
}// end else
|
|
} // end while
|
|
if (m_DebuggerCount > ServiceParams.dwMaxKdProcesses+1)
|
|
m_DebuggerCount = ServiceParams.dwMaxKdProcesses+1;
|
|
|
|
while (1)
|
|
{
|
|
|
|
_time64(&CurrentTime);
|
|
if (CurrentTime > NextCheckTime)
|
|
|
|
{
|
|
// LogEvent (_T("Checking for new ini file"));
|
|
CheckForIni (&ServiceParams);
|
|
NextCheckTime= CurrentTime + (ServiceParams.IniCheckWaitTime * 60);
|
|
// LogEvent (_T("Back from ini file check"));
|
|
}
|
|
|
|
|
|
// now wait for one of the processes to complete or hStopEvent to be signaled.
|
|
dwWaitResult = WaitForMultipleObjects(m_DebuggerCount, (HANDLE *)ProcessHandles, FALSE, ServiceParams.dwDelay);
|
|
if (dwWaitResult == WAIT_FAILED)
|
|
{
|
|
LogFatalEvent(_T("Failed while waiting for prcesses to complete error code: %d"), GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
else
|
|
{
|
|
if (dwWaitResult-WAIT_OBJECT_0 == 0)
|
|
{
|
|
LogEvent(_T("Stop request received terminating"));
|
|
goto Cleanup;
|
|
}
|
|
else // we have an event we can take action on.
|
|
{
|
|
if ( dwWaitResult == WAIT_TIMEOUT)
|
|
{
|
|
// no process completed so let's fill any empty slots in the
|
|
// Process array.
|
|
if (m_DebuggerCount <= ServiceParams.dwMaxKdProcesses)
|
|
{
|
|
// fill the queue until m_DebuggerCount == ServiceParams.dwMaxKdProcesses
|
|
Done = FALSE;
|
|
dwIndex = 1;
|
|
while ( (!Done) && (m_DebuggerCount <= ServiceParams.dwMaxKdProcesses) )
|
|
{
|
|
if (ProcessHandles[dwIndex] == NULL)
|
|
{
|
|
if (ReceiveQueueMessage(&ServiceParams, szFilePath, szMessageLabel,&bUsePrimary,&Type,szSR))
|
|
{
|
|
|
|
DbParams.Debugger = ServiceParams.DebuggerName;
|
|
DbParams.DumpPath = szFilePath;
|
|
DbParams.Guid = szMessageLabel;
|
|
DbParams.SrNumber = szSR;
|
|
DbParams.ResponseMQ = (bUsePrimary) ?
|
|
ServiceParams.PrimaryResponseQueue : ServiceParams.SecondaryResponseQueue;
|
|
DbParams.SymPath = ServiceParams.Symsrv;
|
|
DbParams.Source = Type;
|
|
DbParams.dwMaxDumpSize = ServiceParams.dwMaxDumpSize;
|
|
|
|
if (LaunchDebugger(&DbParams, &ProcessInfo))
|
|
{
|
|
|
|
ProcessHandles[dwIndex] = ProcessInfo.hProcess;
|
|
CloseHandle( ProcessInfo.hThread );
|
|
++m_DebuggerCount;
|
|
} // end else
|
|
}
|
|
else
|
|
{
|
|
Done = TRUE;
|
|
}
|
|
} // end if
|
|
++dwIndex;
|
|
} // end while
|
|
}
|
|
} // end if
|
|
else // A kd process completed now lets clean it up and launch a new one.
|
|
{
|
|
FreeIndex = (dwWaitResult - WAIT_OBJECT_0);
|
|
// check to make sure we are within our array range.
|
|
if ( (FreeIndex > ServiceParams.dwMaxKdProcesses))
|
|
{
|
|
LogFatalEvent( _T("Invalid array index returned by WaitForMultipleObjects. \n Index = %d, Count = %d"), FreeIndex,m_DebuggerCount);
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(ProcessHandles[FreeIndex]);
|
|
ProcessHandles[FreeIndex] = NULL;
|
|
|
|
|
|
// if the queue is not now empty take the last Process handle and replace the current one.
|
|
if (m_DebuggerCount > 2)
|
|
{
|
|
// We have to do this because NULLs are not allowed in the HANDLE Array.
|
|
ProcessHandles[FreeIndex] = ProcessHandles[m_DebuggerCount-1];
|
|
ProcessHandles[m_DebuggerCount-1] = NULL;
|
|
-- m_DebuggerCount;
|
|
}
|
|
else
|
|
{
|
|
--m_DebuggerCount;
|
|
}
|
|
if (ReceiveQueueMessage(&ServiceParams, szFilePath, szMessageLabel,&bUsePrimary, &Type, szSR))
|
|
{
|
|
DbParams.Debugger = ServiceParams.DebuggerName;
|
|
DbParams.DumpPath = szFilePath;
|
|
DbParams.Guid = szMessageLabel;
|
|
DbParams.SrNumber = szSR;
|
|
DbParams.ResponseMQ = (bUsePrimary) ?
|
|
ServiceParams.PrimaryResponseQueue : ServiceParams.SecondaryResponseQueue;
|
|
DbParams.SymPath = ServiceParams.Symsrv;
|
|
DbParams.Source = Type;
|
|
DbParams.dwMaxDumpSize = ServiceParams.dwMaxDumpSize;
|
|
|
|
if (LaunchDebugger(&DbParams, &ProcessInfo))
|
|
{
|
|
++m_DebuggerCount;
|
|
ProcessHandles[m_DebuggerCount-1] = ProcessInfo.hProcess;
|
|
CloseHandle( ProcessInfo.hThread );
|
|
|
|
} // end else
|
|
} // end if
|
|
} // end else
|
|
} // end else
|
|
} // end else
|
|
} // end else
|
|
}// end while(1)
|
|
Cleanup:
|
|
//
|
|
// Cleanup - Close handle to the queue
|
|
//
|
|
|
|
Done:
|
|
// set the service status to stopped and return.
|
|
if (hStopEvent != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hStopEvent);
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Routine to Log Fatal Errors to NT Event Log
|
|
void CServiceModule::LogFatalEvent(LPCTSTR pFormat, ...)
|
|
{
|
|
TCHAR chMsg[256];
|
|
HANDLE hEventSource;
|
|
LPTSTR lpszStrings[1];
|
|
va_list pArg;
|
|
|
|
va_start(pArg, pFormat);
|
|
// _vstprintf(chMsg, pFormat, pArg);
|
|
if (StringCbVPrintf(chMsg,sizeof chMsg, pFormat, pArg)!= S_OK)
|
|
{
|
|
return;
|
|
}
|
|
va_end(pArg);
|
|
|
|
lpszStrings[0] = chMsg;
|
|
|
|
|
|
/* Get a handle to use with ReportEvent(). */
|
|
hEventSource = RegisterEventSource(NULL, _T("DBGLauncher"));
|
|
if (hEventSource != NULL)
|
|
{
|
|
/* Write to event log. */
|
|
ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, EVENT_ERROR, NULL, 1, 0, (LPCTSTR*) &lpszStrings[0], NULL);
|
|
DeregisterEventSource(hEventSource);
|
|
}
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Routine to setup NT Event logging
|
|
HRESULT CServiceModule::SetupEventLog ( BOOL fSetup )
|
|
{
|
|
CRegKey key;
|
|
TCHAR szEventKey[MAX_PATH];
|
|
LONG lRes = 0;
|
|
|
|
if (StringCbCopy(szEventKey, sizeof szEventKey,s_cszEventLogKey)!= S_OK)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
if (StringCbCat(szEventKey,sizeof szEventKey, _T("\\")) != S_OK)
|
|
return E_FAIL;
|
|
if (StringCbCat(szEventKey, sizeof szEventKey,(LPTSTR)m_szServiceName) != S_OK)
|
|
return E_FAIL;
|
|
|
|
lRes = key.Create(HKEY_LOCAL_MACHINE, szEventKey);
|
|
if (lRes != ERROR_SUCCESS)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
if( TRUE == fSetup )
|
|
{
|
|
TCHAR szMyName[MAX_PATH];
|
|
GetModuleFileName(NULL, szMyName, (sizeof szMyName)/(sizeof szMyName[0]) );
|
|
key.SetValue(szMyName, _T("EventMessageFile"));
|
|
key.SetValue(EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE,
|
|
_T("TypesSupported"));
|
|
}
|
|
else
|
|
{
|
|
RegDeleteKey(HKEY_LOCAL_MACHINE, szEventKey);
|
|
}
|
|
|
|
done:
|
|
key.Close();
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|