Bug fix for viewing performance counters remotely

There are two bugs in the Performance Counter library and example servers that mean that performance counters built with the library and following the examples shown in the example servers will fail to work correctly when viewed remotely from another machine. What’s more the remote instance of perfmon will fail to display any counters from the machine with the broken performance counters installed.

The first problem is that the code that checks to see that the process that has loaded the counter dll has the correct privileges to be able to connect to the shared memory segment that is used to communicate between the service and the counters is broken when it’s called from within svchost.exe as it is when the counters are being viewed remotely. The code in question attempts to open the process token and query for the SE_CREATE_GLOBAL_NAME privilege which is required to create the shared memory segment. We do this so that we can report the problem accurately if the user doesn’t have this privilege rather than simply telling them that access was denied. Anyway, the thread that runs the code in our performance counter dll inside of svchost.exe has had its privileges reduced and can’t obtain the process token for this kind of access, this causes the creation of our performance data to fail. This happens in the performance counter dll’s Open() function and as this function can’t return an error to the code that is opening the performance counter dll that code continues on and calls the dll’s Collect() function.

The Collect() function can return an error but only in one situation; only if the buffer that it is supplied is not big enough. In that case Collect() can return ERROR_MORE_DATA, otherwise it has to return ERROR_SUCCESS; see http://msdn2.microsoft.com/en-us/library/aa371898.aspx for details. The Performance Counter library code abstracts this all away a little and the code that you’d implement to deal with counter collection returns true if it succeeds and false if the buffer space isn’t big enough. Unfortunately my examples don’t follow this rule and instead return false on any error condition.

The failure of the Open() due to the failed privilege check means that the code that the example server’s Collect() calls fails with an exception and the Collect() function then returns false which means that we actually return ERROR_MORE_DATA to our caller. Our caller tries quite hard to please and keeps calling back with increasingly large buffers until it gives up. Unfortunately when it gives up the remote instance of perfmon doesn’t display any counters.

Fixes to get the code working are actually quite simple; we try harder to determine if the code can create the required shared memory segment which means that Open() need not fail when called from within svchost.exe (which does run with SE_CREATE_GLOBAL_NAME enabled). This means that Collect() doesn’t fail which means that everything works OK. However Collect() is still broken. The easiest fix for this is to simply adjust how we deal with exceptions; always returning true unless the code we’re calling returns false to signal insufficient memory space in the buffer; however the whole little mess is fragile and needs a redesign. The redesign will occur in 6.3. The bug fixes mentioned here will find their way into the 6.2 release which is still in testing but which should be released next week.