Friday, June 12, 2009
This is definitely not news, but I wanted to blog it anyway.

Having recently just reset a development server to use Windows Server 2008, I needed to open the firewall to allow ICMP packets through.  Essentially, I wanted to have the server respond to PING requests.  On a fresh Windows Vista or Windows Server 2008 install (and I imagine Windows 7, though I've not checked), the ICMP protocol is blocked by default; the server won't respond to PINGs.  When you ping an IP address and don't get a reply that doesn't mean that there isn't a computer on the other end, but it sure is a handy way to check.

In Windows Vista/2008 enabling ICMP through the firewall isn't difficult, but if you want to use a GUI, you have to do it through an inbound rule in the Windows Firewall with Advanced Security option.

Personally, I prefer to do it via the command-line through this simple operation: netsh firewall set icmpsetting 8

Friday, June 12, 2009 3:41:21 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, May 03, 2009

As you may or may not be aware IE 7+ (and other browsers) support using CSS 2.1 attribute selectors.  Attribute selectors allow you to specify a style on an element whose element matches a particular pattern.  For instance:

td[x] { font-weight:bold; }

This selector will bold the text of any TD element on the page that has an attribute "x" (regardless of value).  Other attribute selector styles include:

...[x="value"] matches where x is exactly 'value'
...[x~="value"] matches where x contains a space-separated list of values, one of which is exactly 'value'
...[x^="value"] matches where the attribute x begins with 'value'
...[x$="value"] matches where the attribute x ends with 'value'
...[x*="value"] matches where the attribute x contains 'value'
...[x|="value"] matches where the attribute x begins with either 'value' or 'value-'

In and of themselves, these are pretty darn cool.  You can do some neat things with CSS and HTML.

I ran into an interested scenario this past week that I'd like to share.  I have some JavaScript that alters the value of attributes at runtime.  I found that the page doesn't automatically update according to the stylesheet specification.  Curiously, it would update when I moused-over the element in question.

I found, however, that I could force the issue by assigning the CSS classname to the element that it already has.  This is enough to trigger the change and have the element update according to its attribute values.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <style type="text/css">
      td[req] { font-weight:bold; }
      td[err="1"] { color:red !important; }
   </style>
   <script type="text/javascript">
      function fn() {
         var td = document.getElementById("t");
         td.err = "0";
         td.className = td.className;  // trigger the change by reassigning the CSS class
      }
   </script>
</head>
<body>
   <table>
      <tr><td class="test" err="1" req="1" id="t">Cell</td></tr>
   </table>
   <button onclick="javascript:fn();">Remove Error</button>
</body>
</html>

Interestingly, for this to work properly in a non-IE browser (such as Firefox), I found I could not use the object.property=value syntax.  Instead, I had to use the SetAttribute() function.  Also, with Firefox, reassigning the className was unnecessary.

td.setAttribute("err", "0");

That's probably the best way to handle it then, for cross-browser compliance.

CSS | Web
Sunday, May 03, 2009 9:28:44 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Thursday, April 23, 2009

My buddy Rob Bagby has announced this exciting event called XamlFest which will be in Salt Lake City on May 1st.  If you have the chance, I'd encourage you to sign up and attend.

Here's the info: http://blogs.msdn.com/bags/archive/2009/03/31/xamlfest-in-salt-lake-city-on-may-1.aspx

Thursday, April 23, 2009 12:35:44 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, April 06, 2009

I was putting together a WinForms utility application today that consists of a TabStrip control on the main dialog box.  On a themed system the TabStrip displays a nice gradual gradient on the page.  As part of this application I wanted to output statistical and detailed information about the user's selections in a readonly fashion, but I wanted to have the text appear as though it were written directly on the TabStrip page rather than within a control.

Of course my first thought was to use a Label control, but I almost immediately wrote that off as the amount of information to be displayed was prohibitive and variable.  The data being displayed might exceed the space on the TabStrip, so scrolling the information is a must.

Next I thought of using a TextBox control, but without some pretty intense subclassing and overriding, I wouldn't be able to achieve the 'written-on' look I was after.  The TextBox will always render an opaque background color.  Sure, there are ways of faking transparency, like overriding TextBox and adding a PictureBox and telling the parent control to WM_PRINT into it, but that seems to be a kludgy way of getting the results I wanted.

Additionally, there are mechanisms to use a RichTextBox (v5.0) to achieve transparency that are well documented online, but try as I might with these implementations, I found them to be quite buggy.  In particular, the appearance of the scrollbars was erratic and sometimes didn't render properly with the control was resized.  After battling with it for a few hours I gave up.  It wasn't for lack of desire, it just wasn't worth it given the scope of the project I was working on.

So this morning I went back to the drawing board and came up with a solution in about 45 minutes that seems to do exactly what I wanted.  I've called this control the ScrollableLabel.  Essentially, it offers the readonlyness of a Label control and the scrollability of a TextBox.  This implementation here is very fundamental.  I plan on enhancing it some more to incorporate user-defined colors, headers, and much more.

I made some executive decisions about how this control should render.  For instance, it will always use your system's colors for text and I set the BackColor property of the UserControl to Transparent via the designer.  For both of these I plan on making them user-selectable choices, but for not, they're the look I was after.

public partial class ScrollableLabel : UserControl {
   public ScrollableLabel() {
      InitializeComponent();
      SetStyle(ControlStyles.Selectable, false);
      // the preferred mechanism for enabling double-buffering is to set the DoubleBuffered property
      // of the control rather than the equivalent SetStyle(DoubleBuffer | UserPaint | AllPaintingInWmPaint, true).
      DoubleBuffered = true;
      AutoScroll = true;
      AutoScrollMinSize = Size.Empty;
   }

   private SizeF _actualTextSize;

   public override string Text {
      get { return base.Text; }
      set {
         base.Text = value;
         calcLabelDimensions();
         Invalidate();
      }
   }

   protected override void OnScroll(ScrollEventArgs se) {
      base.OnScroll(se);
      Invalidate();
   }

   public void Clear() {
      Text = string.Empty;
   }

   #region Hidden design-time properties
   [Browsable(false)]
   public override bool AutoScroll {
      get { return true; }
      set { /* do nothing for now; control is always AutoScroll */ }
   }


   [Browsable(false)]
   public override Color ForeColor {
      get { return SystemColors.ControlText; }
      set { /* do nothing for now; only ControlText is currently supported */ }
   }
   #endregion

   private void calcLabelDimensions() {
      using ( Graphics g = CreateGraphics() ) {
         // assume that no text should wrap
         _actualTextSize = g.MeasureString(Text, Font);
         AutoScrollMinSize = Size.Round(_actualTextSize);
      }
   }

   protected override void OnPaint(PaintEventArgs e) {
      RectangleF rct = new RectangleF(AutoScrollPosition, _actualTextSize);
     
Brush br = Enabled
                    ? SystemBrushes.ControlText
                    : SystemBrushes.GrayText;
      e.Graphics.DrawString(Text, Font, br, rct);
   }
}

When this control is added to a Form it will automatically add scrollbars if the contents exceed the dimensions of the control.  At design-time, however I wanted to make sure that I could see where the ScrollableLabel was positioned so I created a simple Designer.

public sealed class BorderlessBorderDesigner : ControlDesigner {
   protected override void OnPaintAdornments(PaintEventArgs pe) {
      base.OnPaintAdornments(pe);
      if ( BorderStyle.None == getBorderStyle() ) {
         Rectangle rct = Control.ClientRectangle;
         rct.Width -= 1;
         rct.Height -= 1;
         using ( Pen p = new Pen(SystemColors.ControlDark) ) {
            p.DashStyle = DashStyle.Dash;
            pe.Graphics.DrawRectangle(p, rct);
         }
      }
   }

   private BorderStyle getBorderStyle() {
      UserControl ctl = Control as UserControl;
      if ( null != ctl ) return ctl.BorderStyle;
      return BorderStyle.None;
   }
}

Then, I added [Designer(typeof(BorderlessBorderDesigner)] to my ScrollableLabel class declaration.

It's a simple control that achieves a simple goal.  I'll post my updates to it as I get a chance to modify it and make it all the more flexible and powerful.

Enjoy!

.NET | C# | WinForms | Controls
Monday, April 06, 2009 9:19:13 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, March 17, 2009

I have an external HDD that I use to store various files and products that I download.  Today, while downloading one such application my computer decided to freeze.  I've been having a sporatic issue with my hardware lately, so this freeze (while not entirely unexpected) happened at a most inopportune moment.

When my computer 'came-to' after rebooting, my HDD was put into a read-only state.  Any change I tried to make to the drive was greeted with a "The media is write protected" error message.  The only fix I could come up with was the following:

1. Open the command prompt.
2. Type DISKPART
3. LIST VOLUME (to identify the volume in question)
4. SELECT VOLUME # (where # represents the volume identifier)
5. ATTRIBUTES VOLUME CLEAR READONLY

After this, I could select the folders on my drive and unmark their read-only state.  Note that I had to clear the read-only flag even though DISKPART reported the volume as not being read-only.

We'll see whether the drive falls back into its read-only state in the future.

Tuesday, March 17, 2009 4:31:52 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, February 17, 2009

Years ago I created an InstallShield (InstallScript) installer for some software that I've maintained over the years.  While the installer has been run countless times (successfully, I might add), I recently witnessed the following error message:

An error (-5006 : 0x80070002) has occurred while running the setup.

Please make sure that you have finished any previous setup and closed other applications.

This usually happens after installing a related, but completely stand-alone and distinct product.  After a reboot (having supposed that the previous setup didn't completely finish) we get the same error message.  It turns out, that the error would occur whether or not the previous application had been installed.

Well, long story story short, I figured out that the reason this error message was cropping up was because the software was being installed on a Terminal Server.  In order to install some (not all) software on a Terminal Server, you must first put the server in Install mode, then run the installer (via the Control Panel), and then put the server back into its default Execute mode:

1. From the Command Prompt, type the following command:  change user /install.
2. Install the software via Add/Remove Programs in the Control Panel.
3. When complete, type change user /execute from the command prompt.

While I'm not a systems guy, this leads me to wonder why I had to do this for my installer (which I wrote with InstallScript) but I don't for other installers.  Perhaps there's a switch I can set or a script I can invoke that will do this automatically?  I must investigate.

Tuesday, February 17, 2009 9:47:23 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Thursday, February 12, 2009

In my development environment, I like to use SQL Express rather than the full-featured SQL Server editions mostly because its physical and memory footprints are smaller and its background processing is lighter, but also for support of User Instances.  I don't like to have a bunch of extraneous things running in the background that I'll rarely, if ever, use.  Using SQL Express, however, does come at a price.  There are a few features of SQL Server that don't get installed with it, most notably the SQL Profiler.

If you're like me and want to use SQL Express in development but also need the diagnostic tools like the Profiler, you can make it work.

  1. If you already have SQL Express installed, uninstall it and all SQL Express-related items.
  2. From the SQL Server disc, install just the Management Tools - Basic and Management Tools - Complete.  If you need other features like Integration Services, Notification Services, etc, you'll need to install them now as well.
  3. Install SQL Express.

That's all there is to it.  All you need to remember is to install the Management Tools from the SQL Server discs first and you should be good to go! :)

Thursday, February 12, 2009 3:29:07 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Come join us tonight at the Utah .NET User Group meeting.  We're excited to have Mike Erickson come and talk to us about the up-and-coming Visual Studio 2010.

Date: Tonight, Thursday, February 12th, 2009
Time: 6:00 PM
Place: Neumont University 3rd Floor (10701 South River Front Parkway, South Jordan, UT)

We are pleased to have TEKSystems sponsor this month's meeting.

Also, don't forget that we gather after the meeting for fun, food, and friendship at the neighboring Denny's after the meeting.  Please set aside the time and join us!  See you there :)

Thursday, February 12, 2009 11:46:02 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, December 23, 2008

A few weeks ago I made some updates to my Regular Expression Assembly Builder that I wrote some time back.  These updates have long been requested by users and I finally carved out some time to get them implemented.

These are the new features in verion 2.0.0.3:

  • NEW: Added the ability to assign a description to each regular expression.  These are stored in the RegexDescriptionAttribute class.
  • UPD: Rearranged the RegexEditor to accommodate the new description, changing some labels in the process, and tab order.
  • UPD: Made the validation textboxes 'public' so their references aren't be continually lost each time the editor is opened in the designer.
  • UPD: Updated About box link to point directly to http://blog.devstone.com/aaron.
  • UPD: Added the regular expression description to the regular expression grid.

Though perhaps a small update, I hope the changes are found to be useful.

NOTE: The File menu has two 'Save' options: Save Project and Save Release Version.  These were added a few versions ago, but I'd like to clarify their usage.  Save Project will save your .dll (because the application works natively with a .dll as its project).  Save Release Version will create a \Release directory and save your .dll there as well.  However, the Release Version has a few things (like the regular expression descriptions) stripped out.  It's the Release version you'll want to reference in your applications if you plan to distribute the .dll; otherwise, you'll end up with a dependency on RegexAssemblyBuilder.exe and you wouldn't want to distribute that :).  If you source control your .dll, I'd recommend storing both .dll files so you have your project and your release version on hand.

Also, partially due to my migration to dasBlog, I've not gotten around to updating my little downloader application.  Therefore, you can simply download the application directly here.  Let me know if you have any issues with it.

For a history of the application, please check out this post and its links as well.

Tuesday, December 23, 2008 10:21:32 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, December 22, 2008

Suppose you have a table (tblDemo) and a view (vwDemo) over that table that joins tblDemo to another table to retrieve their results.

The view might resemble the following:

CREATE VIEW vwDemo
AS
SELECT d.*, o.OtherField01, o.OtherField02
FROM tblDemo d
INNER JOIN tblOther o ON d.ID = o.ID

While I've never advocated selecting * from anything, it does have its uses; but it turns out there's potentially a nasty gotcha.  Personally, I like to err on the side of higher specificity, though that usually requires a bit more manual tweaking as time goes on.

What happens if the schema of tblDemo changes?  Well, if you don't update or recreate your view, you may very well get some unexpected side effects.

For instance, if a new field were added to tblDemo (e.g., ALTER TABLE tblDemo ADD NewField int), the view, when inspected in SQL shows the following:

SELECT d.ID, d.Field01, d.Field02, d.Field03, d.NewField AS OtherField01, o.OtherField01 AS OtherField02, o.OtherField02
FROM tblDemo d
INNER JOIN tblOther o ON d.ID = o.ID

Notice that the 'NewField' got aliased with the field name at the new fields position! That field, in turn, received the next field's alias, and so on. Understandably, this can have some very negative side effects in your applications.

For this reason I would strongly recommend AGAINST using SELECT * in a view in SQL Server.  Of course, if your view does nothing but SELECT * on a single table or the '*' is the last part of the SELECT clause (such as SELECT o.OtherField01, o.OtherField02, d.* FROM ...) then you circumvent the issue.  When used in conjunction with other columns, however, there are indeed repercussions.

I don't know that this is a bug in SQL Server, though it may appear to be at first.  I'm not a SQL Server guru (though I'm exceptionally dangerous with it :)), but I suspect that upon building the view, SQL catalogs all of the fields in a pseudo-table.  Changing the schema thereof, without updating the view causes a misalignment between the new schema and the pseudo-table that was build previously.

Can anyone confirm this or elaborate on the behavior?

Monday, December 22, 2008 5:47:24 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [4]  |  Trackback