Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Une fois que le système appelle correctement votre fonction OpenPerformanceData , il appelle votre fonction CollectPerformanceData pour collecter les données de compteur. Si le fournisseur prend en charge les objets interrogés, il contacte le service, le pilote ou l’application avec lesquels il est associé et leur demande les données du compteur.
Le pQuery paramètre sera l’un des éléments suivants :
- Liste délimitée par un espace d’un ou plusieurs entiers décimaux : collectez les données de performances pour tous les types d’objets pris en charge dans la liste.
-
Global: Collectez les données de performances pour tous les types d’objets locaux pris en charge, à l’exception de ceux inclus dans laCostlycatégorie. -
Costly: collecter des données de performances pour tous les types d’objets locaux pris en charge dont les données sont coûteuses à collecter en termes de temps processeur ou d’utilisation de la mémoire. (Obsolète : il ne doit normalement pas y avoir de types d’objets dans cette catégorie.) -
Foreign: Collecte des données de performances pour tous les types d’objets distants pris en charge. (Obsolète : il ne doit normalement pas y avoir de types d’objets dans cette catégorie.) -
MetadataGlobal(nouveau) : Collectez les métadonnées pour tous les types d’objets locaux pris en charge, à l’exception de ceux inclus dans laCostlycatégorie. Il s'agit de la même chose queGlobal, sauf queNumInstancesdoit être défini sur soitPERF_METADATA_MULTIPLE_INSTANCESsoitPERF_METADATA_NO_INSTANCES, et le résultat ne doit pas inclure les blocsPERF_INSTANCE_DEFINITION. -
MetadataCostly(nouveau) : Collectez les métadonnées pour tous les types d’objets locaux pris en charge inclus dans laCostlycatégorie. Il s'agit de la même chose queCostly, sauf queNumInstancesdoit être défini àPERF_METADATA_MULTIPLE_INSTANCESou àPERF_METADATA_NO_INSTANCES, et le résultat ne doit pas inclure de blocsPERF_INSTANCE_DEFINITION.
Les types de requêtes MetadataGlobal et MetadataCostly sont nouveaux pour Windows 10 20H1 et versions ultérieures. Windows effectue des requêtes de métadonnées uniquement si votre fournisseur a ajouté une HKLM\CurrentControlSet\Services\<provider-name>\Performance\Collect Supports Metadata valeur de Registre. Définissez la valeur sur 1 pour indiquer que votre fournisseur les prend en charge. Les requêtes de métadonnées permettent à Windows de collecter des informations sur vos objets de performances pris en charge sans effectuer de collecte de données. Envisagez d’ajouter la prise en charge des requêtes de métadonnées à votre fournisseur, en particulier si la collecte de données est coûteuse.
L’exemple suivant montre une implémentation de la fonction CollectPerformanceData . Le fichier d’en-tête qui contient la définition des compteurs utilisés dans cette fonction est illustré dans Implémentation d’OpenPerformanceData. Si vous utilisez C++ pour implémenter cette fonction, veillez à utiliser l’extern « C » lorsque vous déclarez votre fonction.
// 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;
}