VS 2008: Registering 32-bit ActiveX Control in Windows 7 64-bit


I got my new Dell Studio XPS 16 laptop a couple of weeks ago with Windows 7 64-bit. The transition from Windows Vista 32-bit was pretty painless and everything seemed to work great. I did have some issues migrating my VS 2008 projects due to references to some dlls that were loacted in the C:\Program Files\ directory on my Vista machine but that are now located in the C:\Program Files (x86)\ directory. After fixing those issues everything seemed to run great and all my projects built successfully. I thought I was home free until I built and ran an Installer package that registered an ActiveX control. Depsite the fact that the control was registered on installation, I kept getting the following error when opening the form that utilized the ActiveX control:

System.Runtime.InteropServices.COMException (0x80040154): Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))
at System.Windows.Forms.UnsafeNativeMethods.CoCreateInstance(Guid& clsid, Object punkOuter, Int32 context, Guid& iid)
at System.Windows.Forms.AxHost.CreateWithoutLicense(Guid clsid)
at System.Windows.Forms.AxHost.CreateWithLicense(String license, Guid clsid)
at System.Windows.Forms.AxHost.CreateInstanceCore(Guid clsid)
at System.Windows.Forms.AxHost.CreateInstance()
at System.Windows.Forms.AxHost.GetOcxCreate()
at System.Windows.Forms.AxHost.TransitionUpTo(Int32 state)
at System.Windows.Forms.AxHost.CreateHandle()
at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
at System.Windows.Forms.AxHost.EndInit()
...

I scoured the web and tried many different solutions including:

  • Manually registering the dll
  • Copying the dll to the C:\Windows\SysWOW64\ directory
  • Registering the dll in the C:\Windows\SysWOW64\ directory
  • And a bunch of other things that proved useless

The answer came from a blog post by Theo Gray. The issue was that VS 2008 was building the project to compile on “Any CPU” and apparently the ActiveX control is intended for x86 systems only. Given such, the project needed to be compiled for x86 systems only as well. Do the following to resolve the issue:

  1. Right click on the project title in the Solution Explorer.
  2. Click Properties.
  3. Click the Build tab.
  4. Select x86 from the Traget Platform ComboBox for both Debug and Release configuration.
  5. Build the project.

Alternatively, if you have multiple projects in a solution you can do the following to set this across all projects:

  1. Right click on the solution title in the Solution Explorer.
  2. Click Configuration Manager…
  3. In the Active solution platform select New…
  4. Select x86 from the first ComboBox
  5. Click OK
  6. Build the solution.

Thanks Theo Gray! Worked like a charm!

Crystal Reports: Sorting String Fields Numerically


Generally speaking, if you need to sort by a field in a numerical fashion, it is obviously best to have the value of the field be a number. But, I have had a few situations where I needed to store the value of the field as a string but sort it in a numerical fashion (for example, fields where letters are allowed but generally are all numbers). If you do a generic string sort on a set of numbers, it does not come out in numerical order due to the fact that lengths are not taken into account. Anything that starts with a 0 comes first, then with a 1 next, etc. So, the following strings ‘200’, ’10’, ‘3020’, ‘420’, ’11’, ‘8’ get sorted as follows:

10
11
200
3020
420
8

Obviously, not the desired result. On the other hand, if we prepend zeros to each of the strings like so, ‘0200’, ‘0010’, ‘3020’, ‘0420’, ‘0011’, ‘0008’, then the strings will be sorted in numeric order.

0008
0010
0011
0200
0420
3020

So, all you need to do is pad your string field with zeros so that each string is the same length. To do this in Crystal Reports, create a forumla field with the following code.

Right("000000000000000" & {Field},15)

The length of the string of zeros should be as long as the maximum length of the field and the second parameter of the Right function is as well the maximum length of the field. Then sort by this forumal field as opposed to the original field.

A simple solution that for some reason wasn’t completely apparent to me at first.

C#: Get NIST Internet Time


In one of the applications I have written I needed to get the current date to ensure that the user wasn’t using the software after their license expired. Given that using DateTime.Today could not be trusted as the user could just change their system date, I need ot retrieve the time from the internet somehow. Below is the code that I used to get the current date and time from various NIST Internet Time Services.

public static DateTime GetNISTDate(bool convertToLocalTime)
{
    Random ran = new Random(DateTime.Now.Millisecond);
    DateTime date = DateTime.Today;
  string serverResponse = string.Empty;

    // Represents the list of NIST servers
    string[] servers = new string[] {
                         "64.90.182.55",
                         "206.246.118.250",
                         "207.200.81.113",
                         "128.138.188.172",
                         "64.113.32.5",
                         "64.147.116.229",
                         "64.125.78.85",
                         "128.138.188.172"
                          };

    // Try each server in random order to avoid blocked requests due to too frequent request
  for (int i = 0; i < 5; i++)
    {
        try
        {
  // Open a StreamReader to a random time server
  StreamReader reader = new StreamReader(new System.Net.Sockets.TcpClient(servers[ran.Next(0, servers.Length)], 13).GetStream());
  serverResponse = reader.ReadToEnd();
            reader.Close();

  // Check to see that the signiture is there
            if (serverResponse.Length > 47 && serverResponse.Substring(38, 9).Equals("UTC(NIST)"))
            {
                // Parse the date
  int jd = int.Parse(serverResponse.Substring(1, 5));
                int yr = int.Parse(serverResponse.Substring(7, 2));
                int mo = int.Parse(serverResponse.Substring(10, 2));
                int dy = int.Parse(serverResponse.Substring(13, 2));
                int hr = int.Parse(serverResponse.Substring(16, 2));
                int mm = int.Parse(serverResponse.Substring(19, 2));
                int sc = int.Parse(serverResponse.Substring(22, 2));

  if (jd > 51544)
                    yr += 2000;
                else
                    yr += 1999;

  date = new DateTime(yr, mo, dy, hr, mm, sc);

                // Convert it to the current timezone if desired
  if (convertToLocalTime)
                    date = date.ToLocalTime();

                // Exit the loop
                break;
            }

        }
        catch (Exception ex)
        {
            /* Do Nothing...try the next server */
        }
    }

    return date;
}

There are quite a number of different NIST servers available but I have chosen eight here that have proved to give the quickest results (for me that is). A list of NIST Internet Time Servers can be found here along with their current status.

Posted in Time and Date. Tags: , , . 29 Comments »

C#: Truncate a String at the End of a Word


It seems that just about everyone in the world has their own version of this method so I thought I would share mine as well. 

public static string Truncate(this string s, int length, bool atWord, bool addEllipsis)
{
     // Return if the string is less than or equal to the truncation length
     if (s == null || s.Length <= length)
          return s;

     // Do a simple tuncation at the desired length
     string s2 = s.Substring(0, length);

     // Truncate the string at the word
     if (atWord)
     {
          // List of characters that denote the start or a new word (add to or remove more as necessary)
          List<char> alternativeCutOffs = new List<char>() { ' ', ',', '.', '?', '/', ':', ';', '\'', '\"', '\'', '-' };

          // Get the index of the last space in the truncated string
          int lastSpace = s2.LastIndexOf(' ');

          // If the last space index isn't -1 and also the next character in the original
          // string isn't contained in the alternativeCutOffs List (which means the previous
          // truncation actually truncated at the end of a word),then shorten string to the last space
          if (lastSpace != -1 && (s.Length >= length + 1 && !alternativeCutOffs.Contains(s.ToCharArray()[length])))
               s2 = s2.Remove(lastSpace);
     }

     // Add Ellipsis if desired
     if (addEllipsis)
          s2 += "...";

     return s2;
}

This method returns a truncated string cut off at the nearest “end of word” location (the returned string will always be less than or equal to the length parameter).  The twist that I put on my version is that you can specify alternative cut offs rather that just spaces.  To illustrate the benefit of this, see the code below.

string s = "I like green, red, and yellow!";
string s2 = s.Truncate(12, true, false);

A straight forward truncation at the nearest space would result in the string “I like” as the last space before character 12 occurs right after the word “like”. But, ideally we want to truncate after green as that is the end of a word. In the code above, we check the next character after the ‘n’ in green and realize it is a comma, an alternative cut off, and preserve the word “green”.

For all you die-hard regex guys out there I do realize this can be done with less lines of code using regex, but this example doesn’t!

This method also takes advantage of the extension methods provided by the .Net Framework 3.5, if you didn’t notice already.

Follow

Get every new post delivered to your Inbox.

Join 69 other followers