Thursday, April 07, 2005

I'm sure there are quite a few of these out there, but after a little searching I didn't find one - well, at least I didn't find a good one, one that behaved like I wanted.  I'm sure we've all seen 'em, and some are quite a bit fancier that others, but I wanted to write a quick javascript that I could throw on a web page and get your basic 'countdown' functionality.

I desired to make the code semi-reusable.  That is, I didn't want the basic countdown functionality to be baked into the code, that way I could make the countdown arbitrary.  The code is extremely simple and straightforward, but in an effort to preserve it and make it available to anyone who wants this kind of functionality, I present it here for you.

The code does have a few limitations that you might notice right off the bat.  Most notably, and due to the way it is written, you can only ever have one countdown per page.  This limitation isn't that severe, but if you for some reason needed two or more, the code would have to be altered.  Also, I baked in some 'magic numbers' into the script.  These numbers are in essence constants and I didn't see the need to recalculate them on every iteration, each time the countdown text is updated.  [Updated 04/09//2006 - In reviewing the code, I meant to make the function calls Math.floor() rather than the parseInt() that I originally had - though they both have the same net result]

var _elem, _deadline, _doneHtml, _timer;

function startCountdown(elementId, deadline, doneHtml) {
   _elem = document.getElementById(elementId);
   _deadline = deadline;
   _doneHtml = doneHtml;
   _timer = setInterval("countdownTick()", 1000);
}

function countdownTick() {
   var diff = _deadline - new Date();
   if ( diff > 1000 ) {
      var s = Math.floor(diff / 1000 % 60);
      var m = Math.floor(diff / 60000 % 60);    // 1000 * 60
      var h = Math.floor(diff / 3600000 % 24);  // 1000 * 60 * 60
      var d = Math.floor(diff / 86400000);      // 1000 * 60 * 60 * 24
  
      _elem.innerHTML =
         d.toString() + " day" + (( 1 == d ) ? " " : "s ") +
         h.toString() + " hour" + (( 1 == h ) ? " " : "s ") +
         m.toString() + " minute" + (( 1 == m ) ? " " : "s ") +
         ( ( 60 == s ) ? "0" : s.toString() ) + " second" + (( 1 == s ) ? "" : "s");
   }
   else {
      _elem.innerHTML = _doneHtml;
      clearInterval(_timer);
   }
}

Simply call the startCountdown() function, providing the ID of the HTML element (such as a DIV, SPAN, P, etc) that will be the container for the countdown, the date (date and time) that the countdown expires, and the HTML text to render when the countdown expires.  When the timer counts down to zero, the countdown will replace the text with the appropriate notification.

<div id=“countdown“></div>
<script>
   startCountdown(“countdown“, new Date(2006, 0, 1, 0, 0, 0), “<b>Happy New Year!</b>“);
</script>

Thursday, April 07, 2005 4:15:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, April 06, 2005

I've seen this test floating around the internet over the past several days, and I finally caved and had to take it - seeing that this test is much more meaningful and useful than many out there.  I must say that I'm pretty happy with the results - especially since I took the test at 2:30 in the morning and I'm ready for bed.

Not the speediest out there, but pretty accurate - and that's where it counts ;)

Wednesday, April 06, 2005 7:52:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I'm not sure whether I've blogged about this before...gee! I guess I should add some sort of a search/find mechanism to my blog!  I don't think I have, so here goes.

Suppose you're creating some utility that renders graphics or deals with colors and you specifically desire to be able to work with colors in a hex format (e.g. #FF0000) in .NET.  How would you go about taking a hex number and turning it into a System.Drawing.Color?

You might be tempted to look at the Color structure to see if it supports a constructor that accepts such a parameter.  Unfortunately, you'll be hard pressed to find one...maybe if you squint real (and I mean REAL) hard at your monitor it will magically appear.  The Color structure does contain some .FromXXX() methods, but unfortunately none of them take a hex color value.

Following that fruitless foray you might be tempted to parse out the string in chunks of Red, Green, and Blue, convert the strings to their representative integer values and reconstruct a Color via the .FromArgb() method.  Well, that's doable, but it's a lot of work.  Not to mention that #F00 is the same as #FF0000 with respect to html hexadecimal colors, so you need to account for two different hex color formats.

However, after all this, you just can't believe that support for this type of conversion just isn't in the .NET Framework (after all, isn't .NET all about the web anyway? so why wouldn't it be there?), you haven't far to look, you just need to look in the right place.  It turns out that support for this conversion is built-in to the framework.  It's all a part of the System.Drawing.ColorTranslator class.  This handy class allows you to not only convert from a hex number (called an Html color) to a Color, but also your OLE colors, and a Win32 color.

using System.Drawing;
Color foreColor = ColorTranslator.FromHtml(“#FF0033“);

It's exceptionally easy, but it's kinda like the ControlPaint class - easily lost in the myriad of .NET classes.

Wednesday, April 06, 2005 3:23:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Tuesday, April 05, 2005

I just found out that Real Software, the creators of an alternative to Visual Basic called REALbasic, have extended a free license to their REALbasic 5.5 Standard Edition package to all Microsoft Visual Basic 6.0 users.  It seems that Real Software is leveraging the fact that Microsoft has discontinued support for their Visual Basic 6.0 product.

While, in days past I was a die-hard, very hardcore VB 6.0 programmer, I have not used a BASIC-derived language for just about 4 years since making the move to .NET as a C#/C++ developer.  I have a very soft spot in my heart for Visual Basic (not so much the .NET variety as I see it as a completely different language just slightly different than C# with respect to syntax due to a reliance on the .NET Framework), having worked exclusively with the language since version 2.0.

I don't have any experience with REALbasic, though I'll give it a whirl and see what it's all about, though I'll probably tend to agree with Bill McCarthy in that REALbasic after having read his review, that it's more of an alternative than an upgrade.  One aspect of REALbasic is that there is a Mac-variety.  Without yet diving into it, does anyone know if you can simply take your codebase and compile to Mac and have it run on the Mac OS?  That's pretty cool if it does.

Does anyone have any experience with it that can offer some good, insightful tidbits?

Tuesday, April 05, 2005 4:20:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback

I've not caught onto the Firefox craze like many of my cohorts.  Sure, I use it occasionally to verify my HTML and scripting for cross-browser support, but it's far from being my primary browser.  Just today I noticed that Firefox had a critical upgrade to version 1.0.2 - this might have been long released but I didn't know about it (I guess it was just released on March 25th).  I went to run it (via the handy dandy little update link in the upper-right corner of the browser window) and it began the download.

Once all the updates had been successfully delivered it warned me that I didn't have enough rights to install the update on my computer, being that I don't run as an Administrator or a Power User (just a lowly ol' User here).  Well, it conveniently crashed and never let me back in.  I couldn't run the application again - even after rebooting - it simply gave me a big fat warning that the installer had to finish and to wait.

While it's sad that I had to go an manually uninstall Firefox 1.0 and download 1.0.2 and install it to be back up and running with Firefox, it made me somewhat happy to see that the software is far from perfect, especially being that many of the users to which it caters moved to it from an alternative browser because of its imperfections (among other things).  Aren't we supposed to be writing software that encourages users to not run in an administrative capacity?

Tuesday, April 05, 2005 9:08:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, March 31, 2005

Once I had installed SQL Reporting Services I still had some work to do, because it didn't work right out of the box for me, at least the web-portion; the VS.NET portion worked fine.  Each time I attempted to browse to the Report Manager I was greeted with a Security Exception, proclaiming that

The application attempted to perform an operation not allowed by the security policy.  To grant this application the required permission please contact your system administrator or change the application's trust level in the configuration file.

Exception Details: System.Security.SecurityException: Request for the permission of type System.Web.AspNetHostingPermission, .... failed

This happened after I installed SP1.  Prior to that, I received the following:

Assembly microsoft.web.validatepathmodule.dll security permission grant set is incompatible between appdomains.

Then, I found this nifty article on support.microsoft.com which addressed the issue perfectly.  Once that was fixed, and I had updated both .config files, I had to activate my Reporting Services server with the following command line:

RSActivate -c “C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ReportServer\RSReportServer.config”

Thursday, March 31, 2005 10:37:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I attended a pretty sweet SQL 2000 Reporting Services presentation today by my good friend Scott Golightly.  I was inspired, following the presentation, to install it on my local development machine today - I have immediate need for it and some future needs as well.

One thing the installer does is read the <processModel /> key from the machine.config in order to acquire the credentials (user name and password) of the user under which the Report Server web service will run.  Usually, this would probably be fine - in a production environment - but not in my development environment.  Because I don't run as a local administrator, I've changed the userName and password attributes from their default values of 'machine' and 'AutoGenerate' respectively to another value so that I can effectively debug ASP.NET applications, among other things.

There's a pretty slick utility (aspnet_setreg) that will encrypt a set of credentials and store them in the registry.  Then you simply update the userName and password attributes to resemble 'registry:HKLM\Software\...\ASPNET_SETREG,userName' and 'registry:HKLM\Software\...\ASPNET_SETREG,password' respectively and the ASP.NET runtime will read the encrypted values from the registry and impersonate that user in order to execute the code...pretty slick.

However, it appears that the Reporting Services installer will simply read the values from the <processModel> attributes and use the strings straight from the file.  Well, unfortunately (or perhaps, fortunately) there is no user 'registry:HKLM\Software\...\ASPNET_SETREG,userName' on my system so the installer fails when attempting to grant that user access to the %WINDIR%\Framework\Microsoft.NET\v1.1.4322\Temporary ASP.NET Files\ folder.

The trick is to temporarily change the attribute values to the same user whose credentials are encrypted for the duration of the install, then change them back.

I hope Microsoft fixes this bug, because it's pretty annoying, not to mention insecure.

Thursday, March 31, 2005 8:12:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, March 30, 2005

A few years ago I gave a presentation to our local .NET User Group on creating Add-Ins for Visual Studio .NET using the .NET framework.  That presentation was a lot of fun and very well received.  Creating Add-Ins isn't rocket science by any stretch but it's not without its couple gotchas.

Visual Studio .NET provides a project wizard that accelerates the creation of Add-Ins but it by no means necessary.  If you use the wizard to create your project, it will yield two projects: your Add-In project and a deployment project.  The deployment project is not necessary either, but provides a convenient mechanism from within the IDE to install and uninstall your Add-In.  When creating your Add-In using the wizard you'll want to be careful to name your Add-In appropriately; should you decide to rename your Add-In later you'll need to make several changes.

The most basic of Add-Ins consists simply of a class that implements the IDTExtensibility2 interface.  This interface, available via a reference to Extensibility.dll, provides a set of methods useful for interacting with the Add-In's host environment.  The wizard will create a class called Connect for you that already has the method stubs for each of the interface's methods.  Being a masochist when it comes to code, I prefer to write it out by hand, but the wizard surely gives you a head start when creating your Add-Ins.

Despite being created using the .NET framework, IDTExtensibility2 Add-Ins need to be exposed to their host environments as COM objects (which makes sense being that the IDTExtensibility2 interface is a COM interface).  Therefore, it is necessary to take some action to facilitate this interoperation.

1.  Apply the GuidAttribute to your assembly; this effectively becomes the TypeLibID for your assembly.
2.  Assign a ProgIdAttribute to your class to define a unique, friendly name through which COM-based clients can instantiate your Add-In (e.g. CoCreateInstance, CreateObject, etc)
3.  Assign a GuidAttribute to your class to establish the CLSID.
4.  Apply the ClassInterfaceAttribute to your class with a value of ClassInterfaceType.AutoDispatch; this is not technically required, but I prefer to do this.
5.  Create a strong name (via sn.exe) and apply it to the assembly via the AssemblyKeyFileAttribute.
6.  Assign a version to the project via the AssemblyVersionAttribute.

If you are building your Add-In from within Visual Studio, open the project properties and make sure the 'Register for COM Interop' is set to true.  If, on the otherhand, you prefer command-line builds as I frequently do, you'll need to register it manually with the Assembly Registration Utility (RegAsm.exe).

For deeper integration with the host, you'll probably need to know more about the environment in which the Add-In will run.  The host environment will dictate in many ways the references you set in your project.

The IDTExtensibility2.OnConnection method, for example, accepts among other two parameters named application and addInInst.  For an Add-In that targets the VS.NET environment, the application object is really an EnvDTE._DTE object and the addInInst is an EnvDTE.AddIn object as illustrated in the following example:

using EnvDTE;
using Extensibility;

private _DTE   _app;
private AddIn  _addIn;

void IDTExtensibility2.OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom) {
   _app = (_DTE)application;
   _addIn = (AddIn)addInInst;  
}

However, if you're dealing with an Office Add-In, you have some other things to consider.  First is the question of references.  You may be tempted to simply add a reference to the appropriate COM library (e.g. Microsoft Excel 11.0 Object Library), but unless you installed Office properly, that is probably not the right course of action.

When developing Add-Ins for Office, you want to set a reference to the appropriate Primary Interop Assembly (PIA).  If the PIA is not registered in the GAC or inaccessible, VS.NET will, upon selecting the COM object library, create an interop assembly (e.g. Interop.Excel.dll) in your project folder.  This is not really a good thing; among other things it's not signed so if you signed your assembly it won't work.

You might be tempted to create your own using the Type Library Importer tool (TlbImp.exe).  In fact, you could do something similar to the following to create your own, signed interop assembly (in this case, for Outlook):

tlbimp msoutl.olb /out:Devstone.Interop.Outlook.dll
/namespace:Devstone.Interop.Outlook /asmversion:1.0.0.0 /keyfile:c:\junk\mytestkey.snk

In fact, this would work, but it's not the recommended way to approach the problem.

The recommendation is to establish a reference to the vendor-supplied PIA.  Only the publisher of a type library can produce a true PIA.  Fortunately, Microsoft has created PIAs for each of the Office applications, but they are not installed by default in a Typical or Custom installation of Office.  You must manually select them.

Once installed, you can set your reference to the COM type library using the standard mechanisms.  Visual Studio .NET will find the PIA registered in the GAC and will set a reference to the PIA rather than dynamically generating the interop assembly.  VS.NET will also set a reference to Microsoft.Office.Core.dll (which is the Microsoft Office 11.0 Object Library in the case of Office 2003).

The code from above may resemble the following for an Outlook Add-In:

using Microsoft.Office.Core;
using outlook = Microsoft.Office.Interop.Outlook;
using Extensibility;

private outlook.Application  _app;
private COMAddIn             _addIn;

void IDTExtensibility2.OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom) {
   _app = (outlook.Application)application;
   _addIn = (COMAddIn)addInInst;
}

The next step is the matter of registering the Add-In with the target Office application.  This is done in the registry.  If you've created the Add-In project using the wizard and have the deployment project, it contains these settings for you.  Otherwise, you may have to create them manually.  For development and testing purposes, this key must exist.  So this is what I do:

1.  Create the AddIns key in HKCU\Software\Microsoft\Office\Outlook
2.  Create a new key in the Addins key with the same value as the ProgIdAttribute assigned to the Add-In class
3.  In the ProgId key, create a DWORD value named LoadBehavior and give it a value of 3
4.  Create a string value named FriendlyName and give it the name as you would like it to appear within Office
5.  Create a string value named Description and assign it a value accordingly
6.  Export the ProgId key to a .reg file for later use
7.  Add the .reg file to my VS.NET Add-In project for quick access and so it automatically incorporates itself into source control

After that, you're pretty much off the races.  Creating Add-Ins can be a lot of fun and also pretty rewarding.

Happy coding!

Wednesday, March 30, 2005 4:08:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Wednesday, March 23, 2005

Have you ever double-clicked an XML document sitting on your local computer and have it open in Internet Explorer only to be greeted with the Information Bar?  Have you created HTML files and tried to preview them and had the same thing occur?  It gets a little frustrating, especially if you don't know why IE's doing it in the first place.  The reason IE is doing this is, more than likely, the page has or requires script to run.

With IE 6.0, Microsoft has (correctly, in my opinion) locked down security setting for the Local Machine Zone (LMZ) such that content run from the LMZ is not fully trusted (as it once was).  Attackers discovered that if they could get a file on your local machine (via exploit, convincing you to save, etc) their pages would be able to run fully trusted.  And because most users run their computers as Administrators (ack!), the saved content would have full permissions on the computer, giving the attacker a wide-open field to play in.  Now, however, rather than execute the file unrestricted, IE will pop up the Information Bar giving the user the opportunity to grant or deny permissions.

This can get a little frustrating, however, if you're developing HTML content (for documentation or to run from a CD) or XML documents and you want to test them out frequently.  As it turns out, you can tag your active documents with what's known as the Mark of the Web (MOTW) which IE will recognize and will elevate the page's permissions based on the url specified.

Basically, what it comes down to is a short HTML comment placed near the top of the document with IE willl parse.  It will extract the specified URL and compare it against the user's zone settings to grant it the proper level of permissions (i.e. Trusted, Restricted, Internet, etc).  Here's what it looks like:

<!-- saved from url=(0024)http://www.devstone.com/ -->

The 0024 is a decimal value identifying the number of characters to evaluate in reading the URL.  Alternatively you can specify the following to grant generic Internet Zone permissions to the document:

<!-- saved from url=(0014)about:internet -->

The recommended practice to to include this tag within documents that rely on scripting, frames, etc.  Recently, I have found it to be particularly beneficial in creating an HTML-based navigation system for a CD containing videos and media.  Now, users can pop in the CD/DVD and view the web pages without the annoying Information Bar popping up and ruining the experience.  Likewise, you can apply the tag to an XML document and view the document locally without the constant interruption.

Wednesday, March 23, 2005 3:57:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, March 18, 2005

I've seen plenty of hype about this product over the past months and today I decided to give in and give it a try.  I frequently hear people recommending that I run a spyware utility to make sure that my system is not infected with spyware, but haven't done it for one reason or another.

I downloaded and installed the utility.  I don't run my machine as an administrator, so in order to install it I had to run it as an administrator.  Rather than running the application as THE administrator account, I temporarily promoted my account to the Administrators group (through a slick tool by Aaron Margosis).  Interestingly, the application errored out upon first run as me as well as when I attempted to run it as Administrator.  I had to run it as me promoted to the Administrators group (I suspect that this is because the default owner of the application was me as an admin rather than the Administrators group).  Once I successfully started it, I performed an analysis of my system and I'm happy to see that I had ZERO spyware applications and registry keys/values on my machine.

I can now go along happily and feel even more secure in my computing ;)

Friday, March 18, 2005 8:52:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, March 17, 2005

As I have mentioned before, I very much enjoy working with ReSharper by JetBrains.  We recently purchased version 1.5 and I really like it.  It does have some interesting quirks when dealing with compilation directives.  It seems that ReSharper, in providing its own custom Intellisense, continues to evaluate compilation blocks that are excluded from the current build.  For example, ReSharper gets confused when you have something like this:

#if ( DEBUG )
   public class DevstoneTestControlBase : UserControl {
#else
   public abstract class DevstoneTestControlBase : UserControl {
#endif
      // actual class implementation here...
   }

I periodically decorate my classes this way (especially control-based, UI components) so that in a design, debug environment I can use a designer (which relies on publically creatable classes in order to render the UI) but to mark the classes as abstract when compiled in a 'Release' form so that the proper behaviors are enforced.

When you do this, however, ReSharper throws fits because it cannot resolve protected or public members in the derived class back to the base class.  However, with just a bit of cleverness you can overcome this ReSharper shortcoming and still have your cake and eat it too.

#if ( !DEBUG )
   abstract
#endif
   public class DevstoneTestControlBase : UserControl {
      // class implementation here...
   }

This way, the 'Release-only' modifiers are moved out of the declaration (but still valid when evaluated) and only class declaration exists.  While there are still other nuances with how ReSharper evaluates compilation directives (having different using clauses conditionally, or declaring variables within them, for example), I'm glad to be able to overcome this one.

Thursday, March 17, 2005 5:54:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, March 16, 2005

I just updated to the latest CAPTCHA control 1.3 by Miguel Jimenez  from version 1.2.   The upgrade was EXTREMELY seamless, just dropped the .dll in the \bin folder and removed the HttpHandler from the web.config...that was it!

It's great to see other .NET developers contributing such quality stuff to the community.  I was experiencing the error in which the HttpHandler would cause the browser to prompt to save a file rather than allowing a user onto the site...nice to see that one fixed.  This is great stuff Miguel!

Wednesday, March 16, 2005 9:42:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Within the ASP.NET framework there is built-in support for what is commonly known as Forms Authentication.  Forms Authentication provides a mechanism for the pages within the website to authenticate the caller by validating data (i.e. credentials, PIN, etc) against some data store (such as a database).  I won't bore anyone with a discussion on Forms Authentication as there are many references to be found and it's a pretty well-known topic.  I will, however, entertain another related thought.

When using Forms Authentication, an unauthenticated user will be directed to a designated login page.  ASP.NET will, in the request querystring, identify the page that was initially requested in the ReturnUrl variable thus:

http://localhost/myweb/login.aspx?ReturnUrl=%2fmyweb%2findex.aspx

Upon successful validation of the users credentials the login page will typically call the FormsAuthentication.RedirectFromLoginPage() method.  This method will redirect the user to the page designated by the ReturnUrl property.  Usually this is the desired and anticipated behavior.

There may be times, however, when you want to force a particular application to always (or at least to conditionally) redirect to a designated starting page regardless of the ReturnUrl value.  Probably the best way to accomplish this goal is to utilize an HttpModule that performs simple url rewriting.  The HttpApplication associated with the website in question has an event called AuthorizeRequest which is the prime location to perform the url rewriting.  You could add a handler for this event within the global.asax's Global class (and there's really nothing wrong with this approach) but I prefer to create my own HttpModule to isolate the functionality and compartmentalize it.  This is basically what it comes down to in its simplest form:

public class LoginRewriter : IHttpModule {

   void IHttpModule.Dispose() { }

   void IHttpModule.Init(HttpApplication app) {
      app.AuthorizeRequest += new EventHandler(authorizeRequest);
   }

   private void authorizeRequest(object sender, EventArgs e) {
      rewriteLoginPath(sender as HttpApplication);
   }

   private void rewriteLoginPath(HttpApplication app) {
      if ( !app.Request.IsAuthenticated ) {
         app.Context.RewritePath(“~/Login.aspx?ReturnUrl=~/StartPage.aspx“);
      }
   }

}

This simple module alters the requested path for all non-authenticated requests to point to StartPage.aspx page.  Therefore, despite the request (valid or invalid), upon successfully authenticating, the user will always be redirected to StartPage.aspx.  The last remaining step is to wire the module up in the web.config file:

<httpModules>
   <add type=”MyWeb.LoginRewriter, MyWeb” name=”LoginRewriter” />
</httpModules>

And there you have it...easy as pie!

Wednesday, March 16, 2005 9:23:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback