/*++ Copyright (c) 1996 Microsoft Corporation Module Name: perfnet.c Abstract: Author: Bob Watson (a-robw) Aug 95 Revision History: --*/ #include #include #include #include #include #include #include #define PERF_HEAP hLibHeap #include #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; }