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