410 lines
9.9 KiB
C
410 lines
9.9 KiB
C
/*++
|
||
|
||
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>
|
||
#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]))
|
||
|
||
static bInitOk = FALSE;
|
||
static DWORD dwOpenCount = 0;
|
||
|
||
static 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
|
||
|
||
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
|
||
|
||
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.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
if (dwOpenCount > 0) {
|
||
dwOpenCount--;
|
||
}
|
||
if (dwOpenCount == 0) {
|
||
// close stuff here
|
||
CloseServerQueueObject();
|
||
CloseServerObject();
|
||
CloseRedirObject();
|
||
CloseBrowserObject();
|
||
}
|
||
return ERROR_SUCCESS;
|
||
}
|