Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System.Windows.Forms.Screen.DeviceName gives garbage on Windows XP

My 3.5 .NET Framework program handles multiple monitors, so I use Screen.DeviceName to distinguish between different monitors (can't just compare references to the instances of the Screen object -- different instances can refer to the same screen).

The program works no problem on Windows 7, but on Windows XP SP3 with all .NET frameworks installed it would randomly do strange things, as if it failed to realise that the two given screens are in fact the same screen, which it should be able to recognize as they should have identical DeviceNames.

What is the problem and how do I fix it?

like image 409
GSerg Avatar asked Sep 07 '12 14:09

GSerg


1 Answers

There appears to be a bug somewhere in the framework or in Windows XP.

If you dump a Screen.DeviceName under Windows 7, you will get something like

\\.\DISPLAY1
\\.\DISPLAY2

But if you do the same on Windows XP, you will get something like

\\.\DISPLAY1    ????A??M?↕?☺  ?
\\.\DISPLAY2    ????☺ ? ☺ ?????

Apparently Microsoft was aware of the bug, so they put a note in the documentation:

This string may contain non-printable characters.

And that would be perfectly okay if the non-printable characters were the same each time.
But they are not, because in fact, they are garbage, random memory contents that goes after the terminating null character.

If you create just one cached instance of the Screen object and call its DeviceName property several times, the garbage will be the same each time, because the Screen object caches the name in itself. But if you create a new instance of the Screen object for each request, then the garbage is likely to be different for these instances, even if they refer to the same device:

System.Windows.Forms.Screen s = null;
System.Drawing.Point p = new System.Drawing.Point(0,0);

Console.WriteLine("Using same instance of Screen:");
s = System.Windows.Forms.Screen.FromPoint(p);
for (int i = 0; i < 5; ++i)
{
    Console.WriteLine(s.DeviceName);
}

Console.WriteLine();

Console.WriteLine("Using new instance of Screen:");
for (int i = 0; i < 5; ++i)
{
    Console.WriteLine(System.Windows.Forms.Screen.FromPoint(p).DeviceName);
}

If you run this snippet on Windows XP, you will get something like:

enter image description here

Note how you have at least three versions of DeviceName here.

On Windows 7, on contrary, the garbage part will be stripped out.

This is why the code fails to recognize screens -- device names are different each time.

To fix that, crop the DeviceName string after the first '\0' character.

like image 131
GSerg Avatar answered Sep 20 '22 16:09

GSerg