How do I know which symbolic link is being opened?

In my last post I showed how you can distinguish between to
different device interfaces being opened on the same device object. While device
interfaces are the Microsoft party line for how to expose a PnP device object
which can be opened, I realize that many of you want to use the old legacy
symbolic link where the name is fixed and can be more "easily" found (I disagreee
on that point, but I am not writing your code, am I? ). So how do you distinguish
between 2 different legacy symbolic links being opened against your device? There
are 2 ways to do this, which method you choose is mostly determined by how much
control you have over the application which is opening the link.

The first method is to append a reference string to the symbolic link name itself. Just like
device interfaces, the reference string will be passed to your create dispatch routine and you can use
the reference string to differentiate which name is being opened. For instance,
if you created a PDEVICE_OBJECT with the name \Device\Foo0, you could create
2 symbolic links (whose user mode names would be \\.\Foo\Ref1
and \\.\Foo\Ref2) like this:

 
    UNICODE_STRING strDevice, strLink1, strLink2;

    RtlInitUnicodeString(&strDevice, L"\\Device\\Foo0");
    RtlInitUnicodeString(&strLink1, L"\\??\\Foo\\Ref1");
    RtlInitUnicodeString(&strLink2, L"\\??\\Foo\\Ref2");

    IoCreateSymbolicLink(&strLink1, &strDevice);
    IoCreateSymbolicLink(&strLink2, &strDevice);

and then you would check the file name in the create dispatch handler for
L"\\Ref1" or L"\\Ref2" (remember there is a \
at the front of the string!)
and act appropriately. This method works if you can alter the application which
is opening your device, but what if you can't change the application? For instance,
let's say you are exposing 2 COM ports and you want to open them from HyperTerminal?

In the case where you can't change the application, you reverse where you
specify the reference strings. This is not the most intuitive way of doing this
(I didn't come up with it, Peter Wieland suggested it to me),
but it works very well. Instead of putting the reference string on the link
name, you append the string to the device name it links to. Let's say you are creating
2 COM port names (COM5 and COM6) for your device which is named
\Device\MySerialPort0, you would create the
symbolic links like this:

 
    UNICODE_STRING strDevice, strCOM5, strCOM6;

    RtlInitUnicodeString(&strCOM5, L"\\??\\COM5");
    RtlInitUnicodeString(&strDevice, L"\\Device\\MySerialPort0\\COM5");
    IoCreateSymbolicLink(&strCOM5, &strDevice);

    RtlInitUnicodeString(&strCOM6, L"\\??\\COM6");
    RtlInitUnicodeString(&strDevice, L"\\Device\\MySerialPort0\\COM6");
    IoCreateSymbolicLink(&strCOM6, &strDevice);

When the application opens COM5, your create dispatch routine can check for
the filename L"\\COM5" (again, remember there is
a \ at the front of the string) and if COM6 is being opened, the filename will
be L"\\COM6". So why can't you use this trick
for a device interface and specify the a reference string on the device name? It doesn't work because
device interfaces will use the PDO's name as the target device and the device
interface APIs do not allow you to specify the reference string on the symbolic link's
target device name, only a reference string on the symbolic link name itself.
In the end, it doesn't matter where the reference string is, it is passed to your create dispatch routine
either way.