Scott Hanselman

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

November 10, '05 Comments [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. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Thursday, November 10, 2005 9:25:54 PM UTC
Fantastic post! You are the reigning king on Errors-that-most -people-get-and-ignore-but-you-can-figure-it-out award.

You must've been heated while writing this, I counted about 5 grammar/spelling errors :)
Friday, November 11, 2005 2:53:40 AM UTC
My first comment on your blog and unfortunately its a gripe. Not sure if anybody has pointed this out before but your blog page has an annoying horizontal scroll when viewed in standard(?) 1024x768. Both in IE and FireFox. Would be very glad to see it fixed. Thanks.
P.S.: I posted the same comment earlier and it never got posted. (Rejected as spam?)
P.P.S.:This comment page earlier (as of few days ago) did not have horizontal scroll. But now it does.
Piyush
Friday, November 11, 2005 4:51:20 AM UTC
Piyush - I don't (nor does the system) reject comments. Probably just got the code below wrong. On the scrolling thing, that's happening on a per post basis because of the giant screen shot above. It'll go back to normal once that post moves down.

Out of curiosity, seriously, not picking on you, but why run 1024?
Scott Hanselman
Friday, November 11, 2005 6:43:21 PM UTC
Hmm. Didnt think about the screen shot in particular because I have been seeing this scroll for as long as I remember. May be there always was some screenshot responsible for that. As to using 1024, (you are surely not the first one to ask me), I have little choice because my general purpose machine is 14" ThinkPad T41 and 1024x768 turns out to be the best. Having said that, it is quite widely considered a standard resolution. (http://en.wikipedia.org/wiki/Display_resolution). Perhaps most of the visitors to your blog have some honking 1920x1200. Regardless, as a developer of a web-app company catering to the masses, I refuse to feel embarrassed :-).
Sunday, November 13, 2005 8:07:11 AM UTC
Update: Peli mentioned to me that the Assembly Loader (CLR Hosting actually) folks at MSFT have an interest in this bug/feature. We may get an update on this soon.
Monday, November 14, 2005 8:50:06 PM UTC
Five bucks says they're not even hosting the framework directly- they're probably just using COM activation on a regasm'd managed ComVisible type (go ComTrace it and look for CoCreateInstance). That will load the newest CLR and host all the code in the default appdomain, with the AppBase set to the .exe's location. There are LOTS of things that can go wrong with that approach- though it's a little more forgivable in a "private" app like that than, say, an Office add-in (which I've seen frequently, too). "Throw an Excel.exe.config" into the Office install directory isn't exactly a great plan.
Matt Davis
Tuesday, November 15, 2005 8:08:00 AM UTC
Heh. I shipped code that did that once... It's been a pain in my butt ever since.

I'm pretty sure that what you describe with shell extensions (as an example) is exactly why MS did a complete about-face post-PDC2003, and reimplemented the Longhorn/Vista UI in *UN*managed code. Many of us were less than thrilled with the "system framework" notion that was required by such a setup. You completely lose the benefits of SxS when something as simple as displaying a messagebox loads whatever framework the system feels like into your process... :(
Matt Davis
Monday, December 05, 2005 10:12:41 PM UTC
Thanks for finding this! I was trying to fix it with a .exe.config file before I stumbled across this site and was unable to. The most frustrating thing was Logitech Tech Support kept referring me to something in their knowledge base ("issue 1969") that referred me to a Microsoft KB article that had nothing to do with the problem!

I even sent a letter, via snail mail, to Bob Wick, a VP at Logitech to make sure that the engineering team heard about this (I was unconvinced that the email support team forwards this information.)

Unfortunately for Logitech, we went to another solution for in-the-field data collection! You try to cut a few corners with tech support and look where it gets you--dissatisfied customers and lost sales.
Tuesday, December 27, 2005 8:21:19 PM UTC
Great find!!! I had a similar problem with QueryStudio from Austin Sierra. I fixed it by adding a .config file and manually forcing it to use the .net 1.1 framework with the requireRuntime element.
ML
Saturday, December 31, 2005 9:09:51 PM UTC
Scott:

After about 2 months, I got a SECOND answer from Logitech Tech Support. They have no clue. Here it is below:

-----

Dear Robert,

Thank you for your recent inquiry about your Digital Pen and Paper.
I apologize for not sending you the link. I also need to explain the link a little further. This happens because the performance information from some process is corrupted and we couldnt convert the information into DateTime. This may happen when a 3rd party program was installed. It may have changed an entry to the .Net reference our software is trying to make.

The error may also happen if you are running .Net Framework 2.0.

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=19247&SiteID=1

Unfortunately we do not have any specific list of programs that may change this entry our software is trying to call. You may find more information by doing a web search for the error "System.ArgumentOutOfRangeException: Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks." You will find alot of good information that may pertain to your specific message.

---

Logitech is now on my company's "Do Not Buy" list. This is just crazy. These companies try to save a few pennies by hiring cheapy kid "programmers" instead of experienced degreed professionals and we all suffer. To blame "other programs you installed" for their own incompetence is simply inexcusable.
Comments are closed.

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