Fixing EVEMon’s Crashy C++ DLLs

Saturday, April 18th, 2009

I have been working on EVEMon for about two months now, taking on the responsibility of committing changes to the trunk, fixing bugs and adding new features. As a project I have been involved for several years submitting bug fixes and little features, it was down to my experiences with EVEMon that I decided to implement Subversion and Trac at work.

Unfortunately the first time it came to me to be responsible for a release, it seemed to go terribly wrong. The updated installer worked fine, and it seemed initially there were no problems with the updated code base. However BattleClinic shortly went a little mad with bug reports similar to this one:

EVEMon Version: 1.2.7.1283
.NET Runtime Version: 2.0.50727.1434
Operating System: Microsoft Windows NT 6.0.6001 Service Pack 1
Executable Path: “C:\Program Files\EVEMon\EVEMon.exe”

System.IO.FileLoadException: Could not load file or assembly ‘lgLCDNETWrapper, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log for more detail. (Exception from HRESULT: 0x800736B1)
File name: ‘lgLCDNETWrapper, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null’ —> System.Runtime.InteropServices.COMException (0x800736B1): The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log for more detail. (Exception from HRESULT: 0x800736B1)
at EVEMon.LogitechG15.Lcdisplay.Dispose(Boolean bDisposing)
at EVEMon.LogitechG15.Lcdisplay.Finalize() in D:\EVEMon\EveMon.LogitechG15\Lcdisplay.cs:line 70

For those who are not familiar the above is the crash report generated by EVEMon when a .NET exception is unhandled. lgLCDNETWrapper is the C++ library EVEMon uses to communicate with the Logitech G15. A similar error was generated for EVEMons other C++ component the window relocator.

Tonto Auri quickly spotted that the problem was something to do with the re-compiled C++ DLLs and switching the new DLLs with those from an older package resolved the problems. Whilst this was a fix, I wasn’t willing to just revert the changes and give up on the changes we had made to the G15 library, additionally I was concerned that we had not made changes to the window relocation code and that was causing at least one person a problem.

Quite a bit of searching about with Google and Stack Overflow resulting in finding these two little gems of information:

These two posts basically gave me the tools and the knowledge to fix EVEMon’s problems.

First I made the sudden (and “facepalm”) realization that EVEMon deployed the Visual Studio 2005 Redistributable; we had moved to Visual Studio 2008 SP1 about a month before the release of 1.2.7. I confirmed this with the Dependency Walker utility, by walking lgLCDNETWrapper.dll I was able to confirm that version 9.0.21022.8 of the Microsoft CRT Library (Microsoft.VC90.CRT) would be required.

The next trick was figuring out which re-distributables to deploy with EVEMon to ensure the end user would have all the dependencies required to use all of the features; frustratingly it seems that Microsoft only bundles the latest version of the re-distributables with Visual Studio 2008 and that was version 9.0.30729.1 which was not going to cut it.

Enter Nuonsofts excellent article providing a step by step guide on adding the required compiler flags to ensure the latest version of the CRT was bound. I did find a nice GUI resource editor that was capable of getting the manifests out in XN Resource Editor which made the process a little faster.

A little bit of hacking later the updated Visual Studio 2008 SP1 CRT DLLs and manifest file were deployed to the Microsoft.VC90.CRT folder within the EVEMon program files directory as the VC80 CRT libraries were in the past and the two C++ projects were setup to bind to the latest version with the _BIND_TO_CURRENT_CRT_VERSION=1 preprocessor definition.

A bit more poking arround with XN Resource Editor and Dependency Walker showed we were now in a far better position to have a working copy of EVEMon in the hands of our end users.

Strange SPQuery Behaviour

Friday, February 13th, 2009

I have been working on a very simple web part for a long time, the actual code for the web part takes less than an hour to write and merely displays a colour coded letter based on a query from a SharePoint list taking the date as a parameter.

It has taken a long time because of some strange behaviour with the SPQuery object, initially there was a problem with every row in the table being returned irrespective of the query, the odd thing was that if you ran the query in U2U CAML Query Builder it worked and the SPListItemCollection.count method would return 1 suggesting the query was working.

After adding a copious number of debugging command, I built up a pattern of what was happening and why. However no matter what I changed it either threw an exception as expected or returned all of the rows. I started commenting out lines of code one at a time trying to find the culprit, eventually moving on to commenting out the Debug.WriteLine statements, until I hit this line:

86
Debug.WriteLine(fetchCurrentWeek.ViewXml);

After commenting out this line the whole thing worked perfectly, I can put the date forward on the server and it will update I can change the source table and it reflects the changes after the cache has been cleared. I have looked over the Microsoft Documentation on SPQuery.ViewXml and can’t find any reference to it actually affecting the functionality of the object.

I have included my code at the end of this post for anyone to see, feel free to experiment with it. If you figure it out please do let me know.

using (SPWeb site = SPControl.GetContextSite(Context).OpenWeb())
{
 SPList weekList = site.GetList(this.SourceList);
 // sharepoint requires that we use a ISO8601 DateTime string,
 // generate it and insert it into the query
 string mondayOfCurrentWeek = SPUtility.CreateISO8601DateTimeFromSystemDateTime(GetMondayOfCurrentWeek().Date);
 StringBuilder camlBuilder = new StringBuilder();
 camlBuilder.AppendLine  ("<Where>");
 camlBuilder.AppendLine  ("  <Eq>");
 camlBuilder.AppendLine  ("    <FieldRef Name='WeekCommencing'/>");
 camlBuilder.AppendFormat("    <Value Type='DateTime'>{0}</Value>\r\n", mondayOfCurrentWeek);
 camlBuilder.AppendLine  ("  </Eq>");
 camlBuilder.AppendLine  ("</Where>");
 
 string getWeekCAML = camlBuilder.ToString();
 SPQuery fetchCurrentWeek = new SPQuery(weekList.DefaultView);
 // fetch all of the matching weeks from the table
 fetchCurrentWeek.Query = getWeekCAML;
 SPListItemCollection matchingWeeks = weekList.GetItems(fetchCurrentWeek); // the results of the query should only ever equal 1 if it dosn't something is wrong
 if (matchingWeeks.Count == 1)
 {
  SPListItem week = (SPListItem)matchingWeeks[0];
  WeekType = week["Week Type"].ToString();
  WeekType = SPEncode.HtmlEncode(WeekType); // HtmlEncode the result to make sure it dosn't contain any nastys
  String WeekNumber = week["Week Number"].ToString();
  WeekNumber = SPEncode.HtmlEncode(WeekNumber);
  Debug.WriteLine(String.Format(CultureInfo.InvariantCulture, "[WeekWidget] Found record for {0} as Week {1} - Number {2}", mondayOfCurrentWeek, WeekType, WeekNumber));
  // cache the WeekType for 7 days from midnight on Monday as this is when the changeover between weeks happenswou
  Context.Cache.Insert(CACHE_WEEKTYPE, WeekType, null, GetMondayOfCurrentWeek().AddDays(7), TimeSpan.Zero);
 } // end if matchingWeeks count equal to 1
 else
 {
  // more than one week matched, we can not determine the output correctly
  ErrorText.Text = "More than one week matched in the table, please check the table.";
  LogEvent("More than one week (" + matchingWeeks.Count.ToString() + ") matched in the table, please check the table.");
 } // end else

Happy Hunting