Använda Driver-Defined-gränssnitt
Drivrutiner kan definiera enhetsspecifika gränssnitt som andra drivrutiner kan komma åt. Dessa drivrutinsdefinierade gränssnitt kan bestå av en uppsättning anropsbara rutiner, en uppsättning datastrukturer eller båda. Drivrutinen ger vanligtvis pekare till dessa rutiner och strukturer i en drivrutinsdefinierad gränssnittsstruktur, som drivrutinen gör tillgänglig för andra drivrutiner.
En busschaufför kan till exempel tillhandahålla en eller flera rutiner som drivrutiner på högre nivå kan anropa för att hämta information om en underordnad enhet, om den informationen inte är tillgänglig i den underordnade enhetens resurslista.
Ett exempel på en uppsättning drivrutinsdefinierade gränssnitt som dokumenteras i WDK finns i USB-rutiner. Se även den ramverksbaserade versionen av exempel på -brödrosten.
Skapa ett gränssnitt
Varje drivrutinsdefinierat gränssnitt anges av:
Ett GUID
Ett versionsnummer
En drivrutinsdefinierad gränssnittsstruktur
Referens- och avreferensieringsrutiner
För att skapa ett gränssnitt och göra det tillgängligt för andra drivrutiner kan ramverksbaserade drivrutiner använda följande steg:
Definiera en gränssnittsstruktur.
Den första medlemmen i den här drivrutinsdefinierade strukturen måste vara en GRÄNSSNITT rubrikstruktur. Ytterligare medlemmar kan innehålla gränssnittsdata och pekare till ytterligare strukturer eller rutiner som en annan drivrutin kan anropa.
Drivrutinen måste ange en WDF_QUERY_INTERFACE_CONFIG struktur som beskriver det gränssnitt som du har definierat.
Anmärkning
När du använder WDF_QUERY_INTERFACE_CONFIGstöder WDF inte flera versioner av ett enda gränssnitt som använder samma gränssnitts-GUID.
När du introducerar en ny version av ett befintligt gränssnitt rekommenderar vi därför att du skapar ett nytt GUID i stället för att ändra fälten Storlek eller Version i INTERFACE- struktur.
Om drivrutinen återanvänder samma gränssnitts-GUID med ändrade fälten Storlek eller Version ska drivrutinen inte ange WDF_QUERY_INTERFACE_CONFIG och i stället ange en EvtDeviceWdmIrpPreprocess återanropsrutin för IRP_MN_QUERY_INTERFACE.
Anropa WdfDeviceAddQueryInterface.
Metoden WdfDeviceAddQueryInterface gör följande:
- Lagrar information om gränssnittet, till exempel dess GUID, versionsnummer och strukturstorlek, så att ramverket kan identifiera en annan drivrutins begäran för gränssnittet.
- Registrerar en valfri EvtDeviceProcessQueryInterfaceRequest händelseåteranropsfunktion, som ramverket anropar när en annan drivrutin frågar efter gränssnittet.
Varje instans av ett drivrutinsdefinierat gränssnitt är associerat med en enskild enhet, så drivrutiner anropar vanligtvis WdfDeviceAddQueryInterface inifrån en EvtDriverDeviceAdd eller EvtChildListCreateDevice återanropsfunktion.
Åtkomst till ett gränssnitt
Om drivrutinen har definierat ett gränssnitt kan en annan ramverksbaserad drivrutin begära åtkomst till gränssnittet genom att anropa WdfFdoQueryForInterface och skicka ett GUID, versionsnummer, pekare till en struktur och strukturstorleken. Ramverket skapar en I/O-begäran och skickar den överst i drivrutinsstacken.
En drivrutin anropar vanligtvis WdfFdoQueryForInterface inifrån en EvtDriverDeviceAdd återanropsfunktion. Om drivrutinen måste släppa gränssnittet när enheten inte är i drift kan drivrutinen anropa WdfFdoQueryForInterface inifrån en EvtDevicePrepareHardware återanropsfunktion och kalla på gränssnittets dereference-rutin inifrån en EvtDeviceReleaseHardware återanropsfunktion.
Om drivrutinen A frågar drivrutinen B om ett gränssnitt som drivrutinen B har definierat hanterar ramverket begäran för drivrutinen B. Ramverket verifierar att GUID och version representerar ett gränssnitt som stöds och att den strukturstorlek som drivrutinen A har angett är tillräckligt stor för att rymma gränssnittet.
När en drivrutin anropar WdfFdoQueryForInterfacegår I/O-begäran som ramverket skapar hela vägen till botten av drivrutinsstacken. Om en enkel drivrutinsstack består av tre drivrutiner – A, B och C – och om drivrutinen A ber om ett gränssnitt kan både drivrutinen B och drivrutinen C stödja gränssnittet. Drivrutinen B kan till exempel fylla i drivrutins-A:s gränssnittsstruktur innan du skickar begäran till drivrutinen C. Drivrutinen C kan tillhandahålla en EvtDeviceProcessQueryInterfaceRequest återanropsfunktion som undersöker gränssnittsstrukturens innehåll och eventuellt ändrar dem.
Om drivrutinen A behöver komma åt drivrutinenS B-gränssnitt och drivrutinen B är ett fjärr-I/O-mål (det vill säga en drivrutin som finns i en annan drivrutinsstacken), måste drivrutinen A anropa WdfIoTargetQueryForInterface i stället för WdfFdoQueryForInterface.
Använda One-Way- eller Two-Way-kommunikation
Du kan definiera ett gränssnitt som tillhandahåller enkelriktad kommunikation eller ett som tillhandahåller dubbelriktad kommunikation. Om du vill ange dubbelriktad kommunikation anger drivrutinen ImportInterface-medlemmen i dess WDF_QUERY_INTERFACE_CONFIG-struktur till TRUE.
Om gränssnittet tillhandahåller enkelriktad kommunikation, och om drivrutinen A frågar efter drivrutinenS B-gränssnitt, flödar gränssnittsdata endast från drivrutin B till drivrutin A. När ramverket tar emot drivrutins-A:s begäran om ett gränssnitt som stöder enkelriktad kommunikation kopierar ramverket de drivrutinsdefinierade gränssnittsvärdena till drivrutins-A:s gränssnittsstruktur. Den anropar sedan drivrutinen B:s EvtDeviceProcessQueryInterfaceRequest återanropsfunktion, om den finns, så att den kan undersöka och eventuellt ändra gränssnittsvärdena.
Om gränssnittet tillhandahåller dubbelriktad kommunikation innehåller gränssnittsstrukturen några medlemmar som drivrutinen A fyller i innan begäran skickas till drivrutinen B. Drivrutinen B kan läsa de parametervärden som driver A som tillhandahålls och göra val, baserat på dessa värden, om vilken information som ska anges för drivrutinen A. När ramverket tar emot drivrutins-A:s begäran om ett gränssnitt som stöder dubbelriktad kommunikation anropar ramverket drivrutinen B:s EvtDeviceProcessQueryInterfaceRequest återanropsfunktion så att den kan undersöka mottagna värden och ange utdatavärden. För dubbelriktad kommunikation krävs återanropsfunktionen eftersom ramverket inte kopierar några gränssnittsvärden till drivrutinenS gränssnittsstruktur.
Upprätthålla ett referensantal
Varje gränssnitt måste innehålla en referensfunktion och en dereference-funktion, som ökar och minskar ett referensantal för gränssnittet. Drivrutinen som definierar gränssnittet anger adresserna för dessa funktioner i dess GRÄNSSNITT struktur.
När drivrutinen A frågar drivrutinen B för ett gränssnitt anropar ramverket gränssnittets referensfunktion innan gränssnittet blir tillgängligt för drivrutinen A. När drivrutinen A har slutförts med gränssnittet måste den anropa gränssnittets dereference-funktion.
Referens- och avreferensfunktionerna för de flesta gränssnitt kan vara no-op-funktioner som inte gör någonting. Ramverket innehåller no-op referensantalsfunktioner, WdfDeviceInterfaceReferenceNoOp och WdfDeviceInterfaceDereferenceNoOp, som de flesta drivrutiner kan använda.
Den enda gången som drivrutiner måste hålla reda på ett gränssnitts referensantal och tillhandahålla verkliga referens- och dereferencefunktioner är när drivrutinen A begär ett gränssnitt från ett fjärr-I/O-mål (det vill: en drivrutin som finns i en annan drivrutinsstacken). I det här fallet måste drivrutinen B (i en annan stack) implementera ett referensantal så att den kan förhindra att enheten tas bort medan drivrutinen A använder drivrutins-B-gränssnittet.
Om du utformar drivrutinen B, som definierar ett gränssnitt, måste du bestämma om drivrutinsgränssnittet ska nås från en annan drivrutinsstack. (Drivrutinen B kan inte avgöra om en begäran för dess gränssnitt kommer från den lokala drivrutinsstacken eller från en fjärrstack.) Om drivrutinen stöder gränssnittsförfrågningar från en fjärrstack måste drivrutinen implementera ett referensantal.
Om du utformar drivrutinen A, som kommer åt gränssnittet på fjärr-I/O-målet, måste drivrutinen tillhandahålla en EvtIoTargetQueryRemove återanropsfunktion som släpper gränssnittet när drivrutinen B:s enhet ska tas bort, en EvtIoTargetRemoveComplete återanropsfunktion som släpper gränssnittet när drivrutinen B:s enhet oväntat tas bort, och en EvtIoTargetRemoveCanceled återanropsfunktion som återfår gränssnittet om ett försök att ta bort enheten avbröts.