One of the WDM escapes in KMDF is EvtDeviceWdmIrpPreprocess (or EvtDevicePreprocessWdmIrp in the API in which you register it) which you can register for by calling WdfDeviceInitAssignWdmIrpPreprocessCallback. This function allows you to process a WDM PIRP before KMDF sees it and potentially processes it. From a KMDF adoption point of view, this functionaltiy was a very strong requirement. Without, there would be not be a defined way for a KMDF to support IRPs that KMDF did not natively support. For instance, the KMDF serial example registers a preprocess routine for IRP_MJ_FLUSH_BUFFERS, from [ddkroot]\src\kmdf\serial\pnp.c:
// // Since framework queues doesn't handle IRP_MJ_FLUSH_BUFFERS, // IRP_MJ_QUERY_INFORMATION and IRP_MJ_SET_INFORMATION requests, // we will register a preprocess callback to handle them. // status = WdfDeviceInitAssignWdmIrpPreprocessCallback( DeviceInit, SerialFlush IRP_MJ_FLUSH_BUFFERS, NULL, // pointer minor function table 0); // number of entries in the table
You should use this functionality in your driver only if this is the last resort you have; it does not come for free. When you register for any preprocess routine, KMDF will increase the StackSize in the underlying WDM PDEVICE_OBJECT. This is called out in the documention for "Preprocessing and Postprocessing IRPs" in KMDF. By increasing the stack size, all PIRPs that are sent to your device will have an extra IO stack location. This means that the PIRP is a bit larger than it would otherwise be; larger not only for the IRP_MJ code that you registered for, but for each and every PIRP that is sent to your device regardless of IRP_MJ code. Additionally, if your StackSize goes over an internal threshhold in the IO manager, the way the PIRP is allocated could be different (for instance, devices with a StackSize of <= N might have a PIRP allocated out of a lookaside list while a StackSize > N might always be allocated by calling ExAllocatePool each time). Mind you, the internal threshhold is a bit high so if you have a root enumerated device or your initial StackSize is low, this is not something that you will see.
So while registering a preprocess routine is a very useful thing to be able to do, you should consider your options carefully and only register a preprocess routine if you have no other option.