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.
321 lines
8.6 KiB
321 lines
8.6 KiB
// DglogsCom.cpp : Implementation of CDglogsCom
|
|
#include "stdafx.h"
|
|
#include "Dglogs.h"
|
|
#include "DglogsCom.h"
|
|
#include "Commdlg.h"
|
|
|
|
|
|
// Counts the total number of worker threads running.
|
|
//
|
|
LONG g_lThreadCount;
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
Collects the diagnostics information that the client requested. A worker thread is spawened so
|
|
the UI (webpage) does not have to wait for the diagnostics to complete. If the UI waits
|
|
the web page freezes.
|
|
|
|
Arguments
|
|
lpParameter -- Pointer to the DglogsCom Object
|
|
|
|
Return Value
|
|
error code
|
|
|
|
--*/
|
|
DWORD WINAPI DiagnosticsThreadProc(LPVOID lpParameter)
|
|
{
|
|
BSTR bstrResult;
|
|
CDglogsCom *pDglogsCom = (CDglogsCom *)lpParameter;
|
|
HRESULT hr;
|
|
|
|
|
|
// Every thread in COM needs to initialize COM in order to use COM
|
|
//
|
|
hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
// Each thread needs to reference the class
|
|
//
|
|
pDglogsCom->AddRef();
|
|
|
|
// Tell the Diagnostics object that we are accessing it though COM not netsh
|
|
//
|
|
pDglogsCom->m_Diagnostics.SetInterface(COM_INTERFACE);
|
|
|
|
// Tell the Diagnostics object to send status reports to the client
|
|
//
|
|
pDglogsCom->m_Diagnostics.RequestStatusReport(TRUE,pDglogsCom);
|
|
|
|
// Execute the clients query
|
|
//
|
|
pDglogsCom->m_Diagnostics.ExecQuery();
|
|
|
|
// We are done referencing the Class, dec the ref count
|
|
//
|
|
pDglogsCom->Release();
|
|
|
|
// Uniniatlize COM
|
|
//
|
|
CoUninitialize();
|
|
}
|
|
else
|
|
{
|
|
// We no longer need the class
|
|
pDglogsCom->Release();
|
|
}
|
|
|
|
// Tell the main thread that the worker thread has completed
|
|
//
|
|
SetEvent(pDglogsCom->m_hThreadTerminated);
|
|
|
|
// There are 0 local threads. (Only one thread can be in here at any given time)
|
|
//
|
|
pDglogsCom->m_lThreadCount = 0;
|
|
|
|
// The thread has completed its work. Thus the thread count is 0 again. (Only one thread at a time)
|
|
//
|
|
InterlockedExchange(&g_lThreadCount,0);
|
|
|
|
ExitThread(0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
Initialize the COM object and the Diagnostics object
|
|
|
|
Arguments
|
|
pbstrResult -- Not used
|
|
|
|
Return Value
|
|
HRESULT
|
|
|
|
--*/
|
|
STDMETHODIMP CDglogsCom::Initialize(BSTR *pbstrResult)
|
|
{
|
|
if( _Module.GetLockCount() > 1)
|
|
{
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
Process the clients request by creating a thread to collect the data,
|
|
|
|
Arguments
|
|
bstrCatagory -- List of the catagories to collect divided by semicollens i.e. "ieproxy;mail;news;adapter"
|
|
bFlag -- The actions to perform i.e. PING, SHOW, CONNECT
|
|
pbstrResult -- Stores the result as an XML string
|
|
|
|
Return Value
|
|
HRESULT
|
|
|
|
--*/
|
|
|
|
STDMETHODIMP CDglogsCom::ExecQuery(BSTR bstrCatagory, LONG bFlag, BSTR *pbstrResult)
|
|
{
|
|
|
|
HANDLE hThread;
|
|
WCHAR szFilename[MAX_PATH+1];
|
|
|
|
*pbstrResult = NULL;
|
|
|
|
// For security reason we can not run inside of internet explorer. Otherwise
|
|
// someone could create a web page using this active X component and collect
|
|
// the clients info. If IE is renamed to something else other than explorer,exe
|
|
// IE will not run Active X controls or scripts
|
|
if( GetModuleFileName(NULL,szFilename,MAX_PATH) )
|
|
{
|
|
LPWSTR ExeName;
|
|
LONG len = wcslen(szFilename) - wcslen(L"helpctr.exe");
|
|
if( len <= 0 || _wcsicmp(&szFilename[len], L"helpctr.exe") != 0 )
|
|
{
|
|
// The name of process is not helpctr, refuse to run but do not tell the
|
|
// user why.
|
|
*pbstrResult = SysAllocString(ids(IDS_FAILED));
|
|
//return E_FAIL;
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Unable to get process name, fail and abort. Do not provide rason for
|
|
// failure.
|
|
*pbstrResult = SysAllocString(ids(IDS_FAILED));
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Check if an other thread is already in this function
|
|
//
|
|
if( InterlockedCompareExchange(&g_lThreadCount,1,0) == 0 )
|
|
{
|
|
|
|
// Need to make sure that CDiagnostics Initialized correctly in the CDglogsCom constructor
|
|
if( !m_Diagnostics.m_bDiagInit )
|
|
{
|
|
*pbstrResult = SysAllocString(ids(IDS_FAILED));
|
|
InterlockedExchange(&g_lThreadCount,0);
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
m_lThreadCount = 1;
|
|
|
|
// The information is passed to the thread via gloabl parameters. In the near future it will be passed
|
|
// as parameters.
|
|
//
|
|
m_Diagnostics.SetQuery((WCHAR *)bstrCatagory,bFlag);
|
|
|
|
// In order to cancel the thread we set events. The worker thread checks to see if the main thread
|
|
// has set the cancel event
|
|
//
|
|
m_hThreadTerminated = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
m_hTerminateThread = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
// Set the cancel option so the worker thread can be canceled at any time.
|
|
//
|
|
m_Diagnostics.SetCancelOption(m_hTerminateThread);
|
|
|
|
// Add the ref count to the thread so the class does not dissappear underneath it
|
|
AddRef();
|
|
|
|
// Create a worker thread to collect the information from WMI.
|
|
//
|
|
hThread = CreateThread(NULL, // Security Attributes
|
|
0, // Stack Size
|
|
DiagnosticsThreadProc, // Start Proc
|
|
this, // Thread Paramter
|
|
0, // Creation flags
|
|
&m_dwThreadId // ID of thethread being created
|
|
);
|
|
|
|
if( hThread )
|
|
{
|
|
// We are done with the thread. Close it.
|
|
//
|
|
CloseHandle(hThread);
|
|
*pbstrResult = SysAllocString(ids(IDS_PASSED));
|
|
// Do not do a release cause the thread succeeded and is referencing the class now
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
// Could not create the thread. So the thread count is 0 again;
|
|
//
|
|
InterlockedExchange(&g_lThreadCount,0);
|
|
*pbstrResult = SysAllocString(ids(IDS_FAILED));
|
|
// The thread failed to be created not referencing the class.
|
|
Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
}
|
|
|
|
// Another instance is already running. We only allow one instance at a time.
|
|
*pbstrResult = SysAllocString(ids(IDS_FAILED));
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
Cancels the worker thread
|
|
|
|
Arguments
|
|
|
|
Return Value
|
|
HRESULT
|
|
|
|
--*/
|
|
STDMETHODIMP CDglogsCom::StopQuery()
|
|
{
|
|
// Check if there is a worker thread.
|
|
//
|
|
if( m_lThreadCount )
|
|
{
|
|
// There is a worker thread for this instance. Set an event to tell it to stop processing
|
|
//
|
|
SetEvent(m_hTerminateThread);
|
|
|
|
// If the worker thread is doing an RPC call send the quit message.
|
|
// In theory this should cancel the RPC call
|
|
//
|
|
PostThreadMessage(m_dwThreadId, WM_QUIT, NULL, NULL);
|
|
|
|
// Wait until it's terminated
|
|
//
|
|
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hThreadTerminated, 10000))
|
|
{
|
|
ResetEvent(m_hThreadTerminated);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
Inialize the COM object
|
|
|
|
Arguments
|
|
|
|
Return Value
|
|
HRESULT
|
|
|
|
--*/
|
|
CDglogsCom::CDglogsCom()
|
|
{
|
|
if( m_Diagnostics.Initialize(COM_INTERFACE) == FALSE )
|
|
{
|
|
// If m_Diagnostics.Initialize fails it sets m_bDiagInit to false. Need to check if this
|
|
// value is TRUE inorder to execute anyfunctions in CDiagnostics
|
|
return;
|
|
}
|
|
|
|
if( _Module.GetLockCount() == 0)
|
|
{
|
|
// Reset globals only for the first instance of the object
|
|
//
|
|
g_lThreadCount = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
Uninialize the COM object
|
|
|
|
Arguments
|
|
|
|
Return Value
|
|
HRESULT
|
|
|
|
--*/
|
|
CDglogsCom::~CDglogsCom()
|
|
{
|
|
|
|
if( m_hThreadTerminated )
|
|
{
|
|
CloseHandle(m_hThreadTerminated);
|
|
m_hThreadTerminated = NULL;
|
|
}
|
|
if( m_hTerminateThread )
|
|
{
|
|
CloseHandle(m_hTerminateThread);
|
|
m_hTerminateThread = NULL;
|
|
}
|
|
}
|
|
|
|
|