Scott Hanselman

Request.Browser.Version may not be a double

November 11, 2005 Comment on this post [7] Posted in ASP.NET
Sponsored By

Avoid writing code like this to do browser detection:

if(Double.Parse(Request.Browser.Version) < 5.2) { // 5 or less

Why might this be a problem? Well, Request.Browser.Version is typed in the Base Class Library as a string. It's a string for a reason - because it may not necessarily be a double. When one writes Double.Parse(someString) they're basically saying that the folks who chose the type for Request.Browser.Version were mistaken, and that a double would have been a better chose.

This can be a problem when a browser like IE7.0 beta comes out and the value of Request.Browser.Version is "7.0b." This also applies to Mac's Safari and its User agent version which changed recently from 2.0 to 2.0.1 or 2.0.2.

Exception: Input string was not in a correct format.
Exception: System.FormatException
Message: Input string was not in a correct format.
Source: mscorlib
at System.Number.ParseDouble(String s, NumberStyles style, NumberFormatInfo info)
at System.Double.Parse(String s, NumberStyles style, IFormatProvider provider)
at System.Double.Parse(String s)

Unexpected exceptions tend to cramp one's style. I like the philosophy that "if you ever get an unexpected exception, you didn't test your code well enough." Why? Because clearly it wasn't anticipated, otherwise there'd have been code to handle it. This line (and the code around it you can't see) never expected a non-double to be in Request.Browser.Version, but the property's string type was the first tip that other things could happen.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

When .NET 2.0 Applications Attack - Debugging weirdness after installing the .NET Runtime

November 10, 2005 Comment on this post [10] Posted in Learning .NET | Bugs
Sponsored By

WeirdLogitechRemotingBugI've been developing using the Logitech io2 Pen SDK recently and also, coincidentally installed .NET 2.0 and Visual Studio 2005 around the same time.

I got this error a few days ago upon docking the pen: "Ticks must be between DateTime.MinValue and DateTime.MaxValue" and noticed that remoting was involved in the stack dump:

System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Logitech.Pen.Device.IPen.get_LastSynchronizationTime()
   at Logitech.Pen.TrayIcon.PenBalloon.DoRefresh()

So, two assemblies were chatting each other up via remoting and something went wrong. Logitech has a number of EXEs that all work together to make io2 Pen Services available in multiple contexts. Don't worry, they don't all run at the same time; they come and go as needed.

Io2Software

I knew that Logitech used .NET 1.1 for their development and I knew that on systems that have both .NET 2.0 and .NET 1.1 that 1.1 EXEs would get the 1.1 CLR loaded by default. However, the only thing that changed was the installation of 2.0.

Which of these was running .NET 2.0? Using Sysinternal's glorious ProcExp that can highlight processes that contain a .NET runtime as well as show exactly what DLLs are loaded in a process's memory space. Looks like Pen.LplsHost.exe gets 2.0 loaded, while EVERY other .EXE gets 1.1.

LplsHost

That's weird, and it would make sense that if a .NET 1.1 application remoted into a .NET 2.0 application that something odd might happened (Honest question: Doesn't it?).

When you install .NET 2.0, does it changed any 1.1 DLLs? Yes and no. The system-wide CLR loader, mscoree.dll changes when you install a new version of the .NET Framework. It's always the last version. This is necessary because the loader ultimately makes the decision of which CLR to load into that process. So, mscoree was updated to make the 1.0, 1.1 or 2.0 decision. 

Now, the real question is: What is it about Pen.LplsHost.exe that causes it to load .NET 2.0?

Here's why! It's NOT a .NET application! Reflector reminds me that it's an unmanaged C++ application. It does load the CLR though, so it's likely a CLR Host that does something like this to load the CLR:

LPWSTR pszFlavor = L"wks";
ICorRuntimeHost *pHost = NULL;
hr = CorBindToRuntimeEx(
                      //version
                      null,      
                      // svr or wks                       
                      pszFlavor,   
                      //domain-neutral"ness" and gc settings
                      STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN_HOST |       
                      STARTUP_CONCURRENT_GC,
                      CLSID_CorRuntimeHost,
                      IID_ICorRuntimeHost,
                      (void **)&pHost);

However, if you don't pass in a value for version, MSDN says:

"If the caller specifies null for pwszVersion, the latest version of the common language runtime is loaded. Passing null gives the host no control over which version of the runtime is loaded. While this may be appropriate in some scenarios, it is strongly recommended that the host supply a specific version to load."

So instead, they should note http://msdn.com/library/en-us/cpgenref/html/grfuncorbindtoruntimeex.asp and try this instead: 

LPWSTR pszVer = L"v1.1.4322"; // <!---- Oy!
LPWSTR pszFlavor = L"wks";
ICorRuntimeHost *pHost = NULL;
hr = CorBindToRuntimeEx(
                      //version
                      pszVer,  // <!---- Oy!
                      // svr or wks                       
                      pszFlavor,   
                      //domain-neutral"ness" and gc settings
                      STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN_HOST |       
                      STARTUP_CONCURRENT_GC,
                      CLSID_CorRuntimeHost,
                      IID_ICorRuntimeHost,
                      (void **)&pHost);

Speculation: I'd bet $100 that the devs aren't asking for .NET 1.1 in Pen.LplsHost.exe and they should have if they were following best practices. As I said, you can override it with the .config file, but the RIGHT thing to do (in the short term) is to ask for the version you want.

I'm chatting with Logitech Support about this, so until I update this post everything I've said so far is just my opinion and speculation and in no way means to impugn they or there developers. It's a difficult thing to anticipate these things and to include version-specific information, especially as a CLR Host.

Short term fix: You can easily force Pen.LplsHost.exe (or any application for that matter) to load the .NET 1.1 framework by dropping the attached file into C:\Program Files\Logitech\io2Software. I have done this and haven't see any problems since and noted with ProcExp that 1.1 is now correctly loaded in this process's space.

<configuration>
    <startup>
        <requiredRuntime version="v1.1.4322"  />
    </startup>
</configuration>

File Attachment: Pen.LplsHost.exe.config (118 bytes)

UPDATE: Matt Davis (see the comments for this post) nailed it. I was mistaken. I spoke to the team at Logitech and it was, in fact, C++ calling a .NET Assembly via COM Interop. This  could be controlled via the RunTimeVersion key for the InproServer32 key for this RCW within the Registry. However, everything in this post up to the CorBindToRuntimeEx conclusion holds, and the .exe.config solution is also workable one. Logitech is exploring ways to make this easier. My question is, what about Explorer.exe and hosting multiple shell extensions each written in different versions of .NET?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Windows Clippings - A Cropper Contender

November 10, 2005 Comment on this post [2] Posted in Reviews | ASP.NET
Sponsored By

I dig Cropper in a big way. It's a great, elegant and lightweight way to do screenshot. However, lately I've been using Kenny Kerr's Windows Clippings 1.0 for posting to my blog.

It goes in the tray and when you double click on it the screen dims. You single click on the window you want to get a screenshot of and just that window brightens. A double-click then will send the screenshot to the clipboard, OneNote, or a Folder. It's even smart enough to pick a good filename based on the Window's Title.

Not only that, but it will create transparency in all the appropriate places, which is very useful when you consider that even Windows Explorer uses irregular regions and curved edges.

Kudos to Kenny for another killer util!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Blogging directly from a Logitech IO2 Pen

November 09, 2005 Comment on this post [9] Posted in Coding4Fun
Sponsored By

UPDATE: In case this seemed like a non sequitur, this is in support of an upcoming article for Coding4Fun on the Logitech io2 pen.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

What is the difference between Type 1 and Type 2 Diabetes?

November 06, 2005 Comment on this post [11] Posted in Diabetes
Sponsored By

I'm asked all the time what the difference is between Type 1 and Type 2 Diabetes. I'm a Type 1 and I wear an Insulin Pump that pushes insulin into my system 24 hours a day. Sometimes folks will say, "Oh, my uncle has diabetes, he got it when he was fifty" and assume it's just like mine.

Type 1 diabetics don't produce enough insulin and need augmentation. Type 2 diabetics product too much because they are resistant to their own insulin. Both of us have high blood sugar because we're not using insulin effectively. Here's a very clear difference:

Dr. Michael Murray clearly identifies the difference between type 1 and type 2 diabetes when he states, "Healthy individuals secrete approximately 31 units of insulin daily; the obese type 2 individual secretes an average of 114 units daily.  Individuals with type 1 diabetes secrete only 4 units of insulin daily."

This is totally true, because I use about 30 units of insulin each day delivered from my pump.

UPDATE: You might also enjoy my "Diabetes: The Airplane Analogy" post from a while back.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.