CollectPerformanceData implementeren
Nadat het systeem uw OpenPerformanceData-functie aanroept, roept het uw CollectPerformanceData--functie aan om de tellergegevens te verzamelen. Als de provider de opgevraagde objecten ondersteunt, neemt deze contact op met de service, het stuurprogramma of de toepassing waaraan deze is gekoppeld en vraagt deze om de tellergegevens.
De parameter pQuery
is een van de volgende:
- Een door spaties gescheiden lijst met een of meer decimale gehele getallen: prestatiegegevens verzamelen voor ondersteunde objecttypen in de lijst.
-
Global
: Prestatiegegevens verzamelen voor alle ondersteunde lokale objecttypen, met uitzondering van de gegevens die zijn opgenomen in de categorieCostly
. -
Costly
: Prestatiegegevens verzamelen voor alle ondersteunde lokale objecttypen waarvan de gegevens duur zijn om te verzamelen in termen van processortijd of geheugengebruik. (Verouderd: normaal gesproken zijn er geen objecttypen in deze categorie.) -
Foreigh
: prestatiegegevens verzamelen voor alle ondersteunde typen externe objecten. (Verouderd: normaal gesproken zijn er geen objecttypen in deze categorie.) -
MetadataGlobal
(nieuwe): Verzamel metagegevens voor alle ondersteunde lokale objecttypen, met uitzondering van de metagegevens die zijn opgenomen in de categorieCostly
. Dit is hetzelfde alsGlobal
, behalve datNumInstances
moet worden ingesteld opPERF_METADATA_MULTIPLE_INSTANCES
ofPERF_METADATA_NO_INSTANCES
, en het resultaat mag geenPERF_INSTANCE_DEFINITION
blokken bevatten. -
MetadataCostly
(nieuwe): Verzamel metagegevens voor alle ondersteunde lokale objecttypen die zijn opgenomen in de categorieCostly
. Dit is hetzelfde alsCostly
, behalve datNumInstances
moet worden ingesteld opPERF_METADATA_MULTIPLE_INSTANCES
ofPERF_METADATA_NO_INSTANCES
, en het resultaat mag geenPERF_INSTANCE_DEFINITION
blokken bevatten.
De querytypen MetadataGlobal
en MetadataCostly
zijn nieuw voor Windows 10 20H1 en hoger. Windows maakt alleen metagegevensquery's als uw provider een HKLM\CurrentControlSet\Services\<provider-name>\Performance\Collect Supports Metadata
registerwaarde heeft toegevoegd. Stel de waarde in op 1 om aan te geven dat uw provider deze ondersteunt. Met metagegevensquery's kan Windows informatie verzamelen over uw ondersteunde prestatieobjecten zonder gegevensverzameling uit te voeren. Overweeg om ondersteuning toe te voegen voor metagegevensquery's aan uw provider, met name als het verzamelen van gegevens duur is.
In het volgende voorbeeld ziet u een implementatie van de functie CollectPerformanceData. Het headerbestand dat de definitie bevat van de tellers die in deze functie worden gebruikt, wordt weergegeven in OpenPerformanceData-implementeren. Als u C++ gebruikt om deze functie te implementeren, moet u extern C gebruiken wanneer u uw functie declareert.
// Callback that the performance service calls when the consumer wants to sample
// your counter data. Get the counter data and return it to the consumer.
extern "C" DWORD APIENTRY CollectPerfData(LPWSTR pQuery,
LPVOID* ppData,
LPDWORD pcbData,
LPDWORD pObjectsReturned)
{
BOOL fQuerySupported = FALSE;
DWORD TotalQuerySize = 0;
PBYTE pObjects = (PBYTE)*ppData; // Used to add counter objects to the buffer.
PEER_INSTANCE inst;
*pObjectsReturned = 0;
if (0 == g_OpenCount) // Open did not successfully initialize
{
*pcbData = 0;
*pObjectsReturned = 0;
return ERROR_SUCCESS;
}
// Confirm that we support the requested objects. The query string is passed
// to this function as it was passed to RegQueryValueEx. For this example,
// it should never be the case that we are being asked for objects that
// we do not support because we included the [objects] section in the .ini file.
fQuerySupported = IsQuerySupported(pQuery, &g_QueriedObjects);
if (fQuerySupported == FALSE)
{
*pcbData = 0;
*pObjectsReturned = 0;
return ERROR_SUCCESS;
}
// If multiple instance objects are queried, you need to discover how many
// instances exist so you can determine the buffer size that the
// query requires. This value can potentially change from query to query.
// The Peer object is a multiple instance object. For this example,
// set the number of instances to 2 if the Peer object was queried.
if (QUERIED_PEER_OBJECT == (g_QueriedObjects & QUERIED_PEER_OBJECT))
{
g_Peer.Object.NumInstances = 2;
g_Peer.Object.TotalByteLength = sizeof(PEER) +
sizeof(PEER_INSTANCE) * g_Peer.Object.NumInstances;
}
// Check pcbData to see if ppData is large enough to hold our counters.
// If the buffer is not large enough, return ERROR_MORE_DATA. This tells
// the calling application to increase the buffer size and query again.
TotalQuerySize = GetQuerySize(g_QueriedObjects);
if (TotalQuerySize > *pcbData)
{
*pcbData = 0;
*pObjectsReturned = 0;
return ERROR_MORE_DATA;
}
else
{
*pcbData = TotalQuerySize;
}
// If the query includes the Transfer object, collect the counter data
// for the Transfer object and copy it to the ppData buffer.
if (QUERIED_TRANSFER_OBJECT == (g_QueriedObjects & QUERIED_TRANSFER_OBJECT))
{
// Add calls to retrieve counter data from the server/driver/application.
// This example hard codes the counter data.
g_Transfer.BytesSentData = 5;
g_Transfer.AvailableBandwidthData = 20;
g_Transfer.TotalBandwidthData = 50;
// Since this is a single instance object, just copy the object
// to the buffer.
memcpy((PTRANSFER)pObjects, &g_Transfer, sizeof(TRANSFER));
pObjects += g_Transfer.Object.TotalByteLength;
(*pObjectsReturned)++;
}
// If the query includes the Peer object, collect the counter data
// for the Peer object and its instances and copy it to the ppData buffer.
if (QUERIED_PEER_OBJECT == (g_QueriedObjects & QUERIED_PEER_OBJECT))
{
// Copy the object and counter definition pieces to the buffer,
// the instance data follows.
memcpy((PPEER)pObjects, &g_Peer, sizeof(PEER));
pObjects += sizeof(PEER);
// Initialize the instance information.
ZeroMemory(&inst, sizeof(PEER_INSTANCE));
inst.Instance.ByteLength = sizeof(PERF_INSTANCE_DEFINITION) + sizeof(inst.InstanceName);
inst.Instance.UniqueID = PERF_NO_UNIQUE_ID;
inst.Instance.NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
inst.CounterBlock.ByteLength = EndOfPeerData;
// Instance-specific data for the first instance. This information is
// hard coded for this example.
inst.Instance.NameLength = sizeof(INSTANCE_NAME_1);
StringCchCopy(inst.InstanceName, MAX_INSTANCE_NAME_LEN+1, INSTANCE_NAME_1);
inst.BytesServedData = 15;
// Copy the instance.
memcpy((PPEER_INSTANCE)pObjects, &inst, sizeof(PEER_INSTANCE));
pObjects += sizeof(PEER_INSTANCE);
// Instance-specific data for the second instance.
inst.Instance.NameLength = sizeof(INSTANCE_NAME_2);
StringCchCopy(inst.InstanceName, MAX_INSTANCE_NAME_LEN+1, INSTANCE_NAME_2);
inst.BytesServedData = 30;
// Copy the instance.
memcpy((PPEER_INSTANCE)pObjects, &inst, sizeof(PEER_INSTANCE));
pObjects += sizeof(PEER_INSTANCE);
(*pObjectsReturned)++;
}
*ppData = (LPVOID)pObjects;
return ERROR_SUCCESS;
}
// Scan the query string to see if we support the objects.
BOOL IsQuerySupported(LPWSTR pQuery, DWORD* pQueriedObjects)
{
BOOL fSupported = FALSE;
WCHAR IndexString[33+1];
LPWSTR pCopy = NULL;
DWORD dwQueryLen = 0;
*pQueriedObjects = 0;
// Copy the query string and make it lowercase.
dwQueryLen = wcslen(pQuery) + 1;
pCopy = new WCHAR[dwQueryLen];
wcscpy_s(pCopy, dwQueryLen, pQuery);
_wcslwr_s(pCopy, dwQueryLen);
if (wcsstr(pCopy, L"global"))
{
fSupported = TRUE;
*pQueriedObjects |= QUERIED_ALL_OBJECTS;
}
else
{
// See if the query contains the index value for
// the Transfer object.
_ultow_s(g_TransferIndex, IndexString, 33, 10);
if (wcsstr(pCopy, IndexString))
{
fSupported = TRUE;
*pQueriedObjects |= QUERIED_TRANSFER_OBJECT;
}
// See if the query contains the index value for
// the Peer object.
_ultow_s(g_PeerIndex, IndexString, 33, 10);
if (wcsstr(pCopy, IndexString))
{
fSupported = TRUE;
*pQueriedObjects |= QUERIED_PEER_OBJECT;
}
}
if (pCopy)
delete pCopy;
return fSupported;
}
// Determine the required buffer size for the query.
DWORD GetQuerySize(DWORD QueriedObjects)
{
DWORD QuerySize = 0;
if (QUERIED_TRANSFER_OBJECT == (QueriedObjects & QUERIED_TRANSFER_OBJECT))
QuerySize = g_Transfer.Object.TotalByteLength;
if (QUERIED_PEER_OBJECT == (g_QueriedObjects & QUERIED_PEER_OBJECT))
QuerySize += g_Peer.Object.TotalByteLength;
return QuerySize;
}