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.
417 lines
11 KiB
417 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
perfnet.c
|
|
|
|
Abstract:
|
|
|
|
|
|
Author:
|
|
|
|
Bob Watson (a-robw) Aug 95
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <winperf.h>
|
|
#include <ntprfctr.h>
|
|
#include <assert.h>
|
|
|
|
#define PERF_HEAP hLibHeap
|
|
#include <perfutil.h>
|
|
#include "perfnet.h"
|
|
#include "netsvcmc.h"
|
|
|
|
// bit field definitions for collect function flags
|
|
|
|
#define POS_COLLECT_SERVER_DATA ((DWORD)0x00000001)
|
|
#define POS_COLLECT_SERVER_QUEUE_DATA ((DWORD)0x00000002)
|
|
#define POS_COLLECT_REDIR_DATA ((DWORD)0x00000004)
|
|
#define POS_COLLECT_BROWSER_DATA ((DWORD)0x00000008)
|
|
|
|
#define POS_COLLECT_GLOBAL_DATA ((DWORD)0x0000000F)
|
|
#define POS_COLLECT_FOREIGN_DATA ((DWORD)0)
|
|
#define POS_COLLECT_COSTLY_DATA ((DWORD)0)
|
|
|
|
// global variables to this DLL
|
|
|
|
HANDLE ThisDLLHandle = NULL;
|
|
HANDLE hEventLog = NULL;
|
|
HANDLE hLibHeap = NULL;
|
|
|
|
// variables local to this module
|
|
|
|
static POS_FUNCTION_INFO posDataFuncInfo[] = {
|
|
{SERVER_OBJECT_TITLE_INDEX, POS_COLLECT_SERVER_DATA, 0, CollectServerObjectData},
|
|
{SERVER_QUEUE_OBJECT_TITLE_INDEX, POS_COLLECT_SERVER_QUEUE_DATA, 0, CollectServerQueueObjectData},
|
|
{REDIRECTOR_OBJECT_TITLE_INDEX, POS_COLLECT_REDIR_DATA, 0, CollectRedirObjectData},
|
|
{BROWSER_OBJECT_TITLE_INDEX, POS_COLLECT_BROWSER_DATA, 0, CollectBrowserObjectData}
|
|
};
|
|
|
|
#define POS_NUM_FUNCS (sizeof(posDataFuncInfo) / sizeof(posDataFuncInfo[1]))
|
|
|
|
BOOL bInitOk = FALSE;
|
|
DWORD dwOpenCount = 0;
|
|
|
|
BOOL bReportedNotOpen = FALSE;
|
|
|
|
PM_OPEN_PROC OpenNetSvcsObject;
|
|
PM_COLLECT_PROC CollecNetSvcsObjectData;
|
|
PM_CLOSE_PROC CloseNetSvcsObject;
|
|
|
|
static
|
|
BOOL
|
|
DllProcessAttach (
|
|
IN HANDLE DllHandle
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
perform any initialization function that apply to all object
|
|
modules
|
|
|
|
--*/
|
|
{
|
|
BOOL bReturn = TRUE;
|
|
|
|
UNREFERENCED_PARAMETER (DllHandle);
|
|
|
|
// create heap for this library
|
|
if (hLibHeap == NULL) hLibHeap = HeapCreate (0, 1, 0);
|
|
|
|
assert (hLibHeap != NULL);
|
|
|
|
if (hLibHeap == NULL) {
|
|
return FALSE;
|
|
}
|
|
// open handle to the event log
|
|
if (hEventLog == NULL) hEventLog = MonOpenEventLog((LPWSTR)L"PerfNet");
|
|
assert (hEventLog != NULL);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
static
|
|
BOOL
|
|
DllProcessDetach (
|
|
IN HANDLE DllHandle
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER (DllHandle);
|
|
|
|
if (dwOpenCount != 0) {
|
|
// make sure the object has been closed before the
|
|
// library is deleted.
|
|
// setting dwOpenCount to 1 insures that all
|
|
// the objects will be closed on this call
|
|
if (dwOpenCount > 1) dwOpenCount = 1;
|
|
CloseNetSvcsObject();
|
|
dwOpenCount = 0;
|
|
}
|
|
|
|
if (hLibHeap != NULL) {
|
|
HeapDestroy (hLibHeap);
|
|
hLibHeap = NULL;
|
|
}
|
|
|
|
if (hEventLog != NULL) {
|
|
MonCloseEventLog ();
|
|
hEventLog = NULL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
__stdcall
|
|
DllInit(
|
|
IN HANDLE DLLHandle,
|
|
IN DWORD Reason,
|
|
IN LPVOID ReservedAndUnused
|
|
)
|
|
{
|
|
ReservedAndUnused;
|
|
|
|
// this will prevent the DLL from getting
|
|
// the DLL_THREAD_* messages
|
|
DisableThreadLibraryCalls (DLLHandle);
|
|
|
|
switch(Reason) {
|
|
case DLL_PROCESS_ATTACH:
|
|
return DllProcessAttach (DLLHandle);
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
return DllProcessDetach (DLLHandle);
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
case DLL_THREAD_DETACH:
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
DWORD APIENTRY
|
|
OpenNetSvcsObject (
|
|
LPWSTR lpDeviceNames
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will initialize the data structures used to pass
|
|
data back to the registry
|
|
NOTE: This routine assumes it is being called in a MUTEX by the caller
|
|
and will not collide with Close & Collect call.
|
|
|
|
Arguments:
|
|
|
|
Pointer to object ID of each device to be opened (PerfGen)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DWORD status = ERROR_SUCCESS;
|
|
DWORD dwErrorCount = 0;
|
|
|
|
if (dwOpenCount == 0) {
|
|
|
|
status = OpenServerObject (lpDeviceNames);
|
|
// if this didn't open, it's not fatal, just no
|
|
// server stats will be returned
|
|
if (status != ERROR_SUCCESS) {
|
|
dwErrorCount++;
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
status = OpenServerQueueObject (lpDeviceNames);
|
|
// if this didn't open, it's not fatal, just no
|
|
// server queue stats will be returned
|
|
if (status != ERROR_SUCCESS) {
|
|
dwErrorCount++;
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
status = OpenRedirObject (lpDeviceNames);
|
|
// if this didn't open, it's not fatal, just no
|
|
// Redir stats will be returned
|
|
if (status != ERROR_SUCCESS) {
|
|
dwErrorCount++;
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
status = OpenBrowserObject (lpDeviceNames);
|
|
// if this didn't open, it's not fatal, just no
|
|
// Browser stats will be returned
|
|
if (status != ERROR_SUCCESS) {
|
|
dwErrorCount++;
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (dwErrorCount < POS_NUM_FUNCS) {
|
|
// then at least one object opened OK so continue
|
|
bInitOk = TRUE;
|
|
dwOpenCount++;
|
|
} else {
|
|
// none of the objects opened, so give up.
|
|
ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE,
|
|
0,
|
|
PERFNET_UNABLE_OPEN,
|
|
NULL,
|
|
0,
|
|
sizeof(DWORD),
|
|
NULL,
|
|
(LPVOID)&status);
|
|
}
|
|
} else {
|
|
// already opened so bump the refcount
|
|
dwOpenCount++;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
DWORD APIENTRY
|
|
CollectNetSvcsObjectData (
|
|
IN LPWSTR lpValueName,
|
|
IN OUT LPVOID *lppData,
|
|
IN OUT LPDWORD lpcbTotalBytes,
|
|
IN OUT LPDWORD lpNumObjectTypes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will return the data for the processor object
|
|
NOTE: This routine assumes it is being called in a MUTEX by the caller
|
|
and will not collide with Open & Close call.
|
|
|
|
Arguments:
|
|
|
|
IN OUT LPVOID *lppData
|
|
IN: pointer to the address of the buffer to receive the completed
|
|
PerfDataBlock and subordinate structures. This routine will
|
|
append its data to the buffer starting at the point referenced
|
|
by *lppData.
|
|
OUT: points to the first byte after the data structure added by this
|
|
routine. This routine updated the value at lppdata after appending
|
|
its data.
|
|
|
|
IN OUT LPDWORD lpcbTotalBytes
|
|
IN: the address of the DWORD that tells the size in bytes of the
|
|
buffer referenced by the lppData argument
|
|
OUT: the number of bytes added by this routine is writted to the
|
|
DWORD pointed to by this argument
|
|
|
|
IN OUT LPDWORD NumObjectTypes
|
|
IN: the address of the DWORD to receive the number of objects added
|
|
by this routine
|
|
OUT: the number of objects added by this routine is writted to the
|
|
DWORD pointed to by this argument
|
|
|
|
Returns:
|
|
|
|
0 if successful, else Win 32 error code of failure
|
|
|
|
--*/
|
|
{
|
|
LONG lReturn = ERROR_SUCCESS;
|
|
|
|
// build bit mask of functions to call
|
|
|
|
DWORD dwQueryType;
|
|
DWORD FunctionCallMask = 0;
|
|
DWORD FunctionIndex;
|
|
|
|
DWORD dwNumObjectsFromFunction;
|
|
DWORD dwOrigBuffSize;
|
|
DWORD dwByteSize;
|
|
|
|
if (!bInitOk) {
|
|
if (!bReportedNotOpen) {
|
|
bReportedNotOpen = ReportEvent (hEventLog,
|
|
EVENTLOG_ERROR_TYPE,
|
|
0,
|
|
PERFNET_NOT_OPEN,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
*lpcbTotalBytes = (DWORD) 0;
|
|
*lpNumObjectTypes = (DWORD) 0;
|
|
lReturn = ERROR_SUCCESS;
|
|
goto COLLECT_BAIL_OUT;
|
|
}
|
|
|
|
dwQueryType = GetQueryType (lpValueName);
|
|
|
|
switch (dwQueryType) {
|
|
case QUERY_ITEMS:
|
|
for (FunctionIndex = 0; FunctionIndex < POS_NUM_FUNCS; FunctionIndex++) {
|
|
if (IsNumberInUnicodeList (
|
|
posDataFuncInfo[FunctionIndex].dwObjectId, lpValueName)) {
|
|
FunctionCallMask |=
|
|
posDataFuncInfo[FunctionIndex].dwCollectFunctionBit;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case QUERY_GLOBAL:
|
|
FunctionCallMask = POS_COLLECT_GLOBAL_DATA;
|
|
break;
|
|
|
|
case QUERY_FOREIGN:
|
|
FunctionCallMask = POS_COLLECT_FOREIGN_DATA;
|
|
break;
|
|
|
|
case QUERY_COSTLY:
|
|
FunctionCallMask = POS_COLLECT_COSTLY_DATA;
|
|
break;
|
|
|
|
default:
|
|
FunctionCallMask = POS_COLLECT_COSTLY_DATA;
|
|
break;
|
|
}
|
|
|
|
// collect data
|
|
*lpNumObjectTypes = 0;
|
|
dwOrigBuffSize = dwByteSize = *lpcbTotalBytes;
|
|
*lpcbTotalBytes = 0;
|
|
|
|
for (FunctionIndex = 0; FunctionIndex < POS_NUM_FUNCS; FunctionIndex++) {
|
|
if (posDataFuncInfo[FunctionIndex].dwCollectFunctionBit &
|
|
FunctionCallMask) {
|
|
dwNumObjectsFromFunction = 0;
|
|
lReturn = (*posDataFuncInfo[FunctionIndex].pCollectFunction) (
|
|
lppData,
|
|
&dwByteSize,
|
|
&dwNumObjectsFromFunction);
|
|
|
|
if (lReturn == ERROR_SUCCESS) {
|
|
*lpNumObjectTypes += dwNumObjectsFromFunction;
|
|
*lpcbTotalBytes += dwByteSize;
|
|
dwOrigBuffSize -= dwByteSize;
|
|
dwByteSize = dwOrigBuffSize;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// *lppData is updated by each function
|
|
// *lpcbTotalBytes is updated after each successful function
|
|
// *lpNumObjects is updated after each successful function
|
|
|
|
COLLECT_BAIL_OUT:
|
|
|
|
return lReturn;
|
|
}
|
|
|
|
DWORD APIENTRY
|
|
CloseNetSvcsObject (
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine closes the open objects for the net services counters.
|
|
NOTE: This routine assumes it is being called in a MUTEX by the caller
|
|
and will not collide with Open & Collect call.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
if (dwOpenCount > 0) {
|
|
dwOpenCount--;
|
|
}
|
|
if (dwOpenCount == 0) {
|
|
// close stuff here
|
|
CloseServerQueueObject();
|
|
CloseServerObject();
|
|
CloseRedirObject();
|
|
CloseBrowserObject();
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|