Wednesday, April 13, 2005

All too often do I attempt to add a new project to my solutions....who doesn't?  Upon viewing the code window, however, I am greeted by the all-to-familiar, yet undesired VB.NET code.  Now, I'm not saying that VB is bad or undesirous (I happen to very much like the non-.NET varieties), but I was expecting to see C# code.  I guess I get too wrapped up in selecting 'Windows Application' or 'ASP.NET Web Application' and not paying attention to the type of project being created.  Then I have to go remove the project from the solution and delete the new project directory before adding the C# project in its stead.

All this because VB.NET appears before C# in the Project Types list and is selected by default (of course if you've installed SQL Reporting Services, this isn't as much of an issue because 'Business Intelligence Projects' is the default.  Of course if VS.NET were polite enough to ask if I really, really wanted to create a VB.NET project in the first place, this wouldn't be an issue...but I digress).

As it turns out, you can rearrange the order in which these appear by opening the registry (via regedit, et al) and opening the key HKLM\SOFTWARE\Microsoft\VisualStudio\7.1\NewProjectTemplates\TemplateDirs.  Within this key exists several sub keys, each named with a GUID.  Beneath each GUID is a key named 1 or /1 or /2.  These contain a SortPriority DWORD value.  The lower the value, the higher on the list the specified project file appears.

I simply swapped the C# value (20) with the VB.NET value (10) and now C# appears higher on my list and more to my liking. :-)

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

Miguel Jimenez keeps on providing updates to his excellent CAPTCHA control.  It's now on version 1.4.  If I ever make the move to Community Server 1.0 from .Text then I know I'll have CAPTCHA support.

Again, the upgrade was seamless.  Simply replace my existing .dll and done.  I really like the support for supressing the CAPTCHA if I'm logged in to the site.  Good job, Miguel!

Wednesday, April 13, 2005 4:17:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

In tweaking Visual Studio's font and color settings today I stumbled upon a nice discovery.  If you've every seen my development box, you'd know that I prefer a non-white background...the stark white helps accelerate headaches and I'm pretty prone to those.  I prefer a slightly off-white, very light tan (RGB 241, 234, 220) as the background for my code windows.

Well, anyway, I have been using ReSharper for some time now (and thoroughly enjoying it).  I was in the process of changing various color settings (e.g. changing the background color of strings, font color for numbers and operators, etc) so that certain items would stand out more prominantly.

It turns out that ReSharper leverages the exact same mechanism for customizing colors within Visual Studio by adding a slew of ReSharper-specific color settings in the 'Display items' list.  Nice to know it's there if I ever want to customize ReSharper's color scheme.

Wednesday, April 13, 2005 2:53:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I broke down last week and installed the latest in the family of MSN Messenger products - version 7.0.  I had been using Trillian for some time now and for the most part enjoyed it, though there were some annoyances about it that encouraged the switch.  Not to mention that I wanted to try out the latest MSN Messenger.

All in all I have greatly appreciated many of the advancements made.

  • Much more stable (at least it seems to be so far)
  • Nicer presentation
  • I like that you can set a default status on sign-in
  • I like that the last conversation appears when you converse with a contact
  • I like the personal message.  I got sick and tired of people constantly changing their name to reflect their mood, thoughts, etc.  I'm thinking this is to encourage people to not do that.  That said, however, I would still prefer it if I could change how I see them (alias them) so if their name is vulgar (which has happened) or very obscure I get a common presentation.
  • I like the fact that what I listening to via Media Player can get shared
  • Though I doubt I'll really ever use it, the 'My Space' feature is pretty neat.  I saw the other day if one of my contacts updates their 'My Space' I get a pulsing, glowing star next to their contact information so I can go check it out - that's pretty cool.
  • I like that you can turn off nudges, winks, handwriting, etc
  • I like that I could finally truly delete old contacts from my block list so I don't have useless, outdated contacts building up in there.

The product isn't without its glaring problems, though.  Despite all of its advances and useability improvements, there are several things that I hope (though in vain, I'm sure) will be addressed.

  • More than ever it seems that the Messenger world is proliferating advertisements.  MSN is no exception.  It's all about pushing ads in front of the consumer, buy this add-on, pay $.99 for this feature.  The insanity has got to stop.
  • I have always despised the 'ad' panel on the main Messenger window.  There were patched 6.x .exes out there that, through altering a byte or two in the .exe, would suppress this.  Does anyone know of one for 7.0?
  • I will never, ever use the search bar on the main Messenger window.  Ever.  I wish I could hide it.
  • I will never, ever search from a conversation window.  Not only do I think it's pointless that a search is shared, but you never know what a search will pull back as results.  Can the Search button be hidden?
  • I thoroughly despise the status bar on the conversation window - yet another means to push ads to the user.  Can I hide that?
  • I don't like the 'Packs' button on the conversation window - I will never use it.
  • I wish I could hide the toolbar on the conversation window - I will never use it either. [Updated 04/13/2005 - I forgot that I could hide the toolbar]
  • The Conversationator ??? How stupid is that?
  • I am so excited and happy to be able to share and view “Movie Trailers & More” with my friends and associates online.  This feature is particularly enticing because though we are apart and at remote locations while viewing these trailers, I will be able to feel my associate's excitement and enthusiasm for the “Movie Trailer or More“.

Basically, the things that bug me most revolve around advertisements and the fact that it all takes up precious screen real estate...I want my space back!  I don't mind so much that they're there (even by default), but I really wish you could turn them all off.

One question...<sarcasm>why don't nudges send a force feedback to my mouse because that would really get my attention and not be obtrusive in any way?</sarcasm>.  Actually, I think nudges are cool and somewhat useful.

Does anyone else get annoyed by these things? or am I simply insane? (don't answer that last question ;)

Wednesday, April 13, 2005 1:57:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Tuesday, April 12, 2005

Have you ever been debugging an application and you start stepping through code that

  • you don't care to step through because it's all designer generated (a la InitializeComponent()) and pretty boring (and long) to step through
  • is called so repetitively (such as in a loop) that its difficult to concentrate (though Step Over has been known to alleviate such symptoms through repeated usage)
  • is long and/or complex and really has nothing to do with what you're debugging and stepping for in the first place
  • works perfectly and would prefer to bypass it completely

If you frequently suffer from IRDSS (Induced Repetitive Debug Step Syndrome) have we got a cure for you!  Sure, past developers might have recommended a simple dosage of 'Step Out' (also called Shift+F11).  Said remedy, however, has been shown to show side effects such as opening undesired windows and exposing clients to unwanted code.

Studies have shown that simply applying the DebuggerStepThroughAttribute to your methods and classes increases your ability to debug by at least an order of magnitude.  A single dose of this powerful and useful attribute has been linked to higher productivity and fewer developer headaches.  If you would like to learn more about DebuggerStepThroughAttribute, contact your help documentation or call them online.

There are no known side effects.

Tuesday, April 12, 2005 1:22:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Sunday, April 10, 2005

Today, marks the 1st birthday of my blog, the “Zupancic Perspective”.  To say the least, this has been a fun year.  I've learned a lot and have attempted to impart some of the journey with everyone.  I hope that the content that I have shared has in some way been insightful and helpful to a few as it has become a part of me.

Glancing back through the almost two hundred entries, I'm happy with the diversity and breadth of the topics covered.  I can't say that I've really had a goal with the blog, except to identify and preserve many of my diverse interests, which apparently are more than I would have originally anticipated.

I only hope that the coming years can be as exciting, as diverse, and as interesting as this past one.  Thanks to all those that have shared this journey with me in some part.

Sunday, April 10, 2005 4:31:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 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