If you've ever programmed a WDM driver, you're probably familiar with the difference between a DRIVER_OBJECT and a DEVICE_OBJECT. In NDIS, we also differentiate between a driver and a running instance created by the driver.
The most concrete example of this differentiation is the difference between a miniport driver, and an instance of a miniport adapter. When you install the miniport's .SYS file, that's a miniport driver. Now every time you plug in another network card, another instance of the miniport is created for the card. So if you plug in five identical network cards, there will be exactly one copy of your miniport driver in memory, but it will be associated with five different miniport adapter instances.
That's easy enough to picture in your head, but miniports are not the only kind of NDIS driver. Here's a summary of the terminology we use for three types of drivers:
Wait — "Open"? Yes, we use that word as a noun, even though we aren't playing tennis. It's a reference to the fact that a protocol opens a miniport with NdisOpenAdapterEx. The result of that call is an open. (To placate my inner grammarian, I like to mentally pretend the term is an open binding, which is more palatable). Therefore one protocol can have multiple opens. TCPIP, for example, is a protocol that will often have one open for each physical miniport.
If you see us referring to just a miniport, we usually mean that as shorthand for an instance of a miniport adapter. Likewise, the term filter is a casual way to refer to a filter module.
So after reading today's discussion, you can understand the difference between these two different "miniport" handles: the NdisMiniportDriverHandle returned from NdisMRegisterMiniportDriver, and the MiniportAdapterHandle passed into your MiniportInitializeEx handler. The former is the NDIS handle for your entire miniport driver, while the latter is the NDIS handle for each miniport instance. When you are referring to the miniport driver itself, use the first handle. When you are referring to an instance of that miniport, use the second handle. (Most of the time you'll be using the adapter handle, since most of the action occurs on a per-adapter basis. Note that some very generic APIs, like NdisAllocateMemoryWithTagPriority, will happily take either type of handle, since logically either your driver itself or one of your adapters might need to allocate memory.) Another way to look at it is that you can store the first handle in a scalar global variable in your driver. The second handle must be allocated per adapter, so to store it globally, you'd need a container like a linked list.