Tuesday, August 4, 2009

Free Antivirus Recommendations (Protect Yourself Online With FreeAntiVirus Software).

I got tired of shelling out $40+ a year for antivirus protection long ago. Aside form the price, what really bugged me was the bloat! It became more and more difficult to find a simple antivirus or rootkit scanner, without system tuning, performance monitoring and benchmarking bloat that the big guys were packaging with their virus scanner.

The great thing is - with all the free antivirus programs available today, you don't need to shell out any money and most are simply virus protection without the bloat.

Free Antivirus Recommendations


There are many free antivirus programs on the Internet today. I've been looking for the best for my home PC, and to that end I examined ClamWin, Avast!, AVG, Antivir. Here are my thoughts on each:

ClamWin.




PROS:
ClamWin has an simple user interface, and is available in a portable version that can run on a USB thumb drive.

CONS:


Doesn't include an on-access, real-time scanner. This means it's basically relegated to an "after the fact" scanner - only worthwhile if you suspect you have an infection. This is enough to disqualify it from the running for my purpose, though I do use it on my thumb drive. I might come in handy if I need to diagnose a friend's PC problem someday, (which actually happens quite a bit to me!)

AVG.


I then moved on to AVG. I have used (and still use today on my laptop) AVG 7.5 for over a year now with no complaints. When I saw they had a new version (8.0), with a slick new interface and a scan engine revamped for speed I figured I'd upgrade to 8.0 and be loving life.

Not so much.

AVG 8.0 would not work when installed on my 2000 desktop. It installed, but would not scan. Neither would it save any settings. There was no error message, it just behaved as though I never issued a command. In short, it blew me off. So I blew it off, and when back to 7.5.

PROS:
The AVG 7.5 interface is simple, not slick but effective. It gets the job done, and uses minimal system resources to do it and that's a plus in my book. AVG free offers email protection (inbound and outbound) as well as protection against worms, viruses, and Trojans.

CONS:
AVG makes a rootkit detector and anti-phishing software, but offers both of these as separate programs. This might not bother some users, but it does provide a feature gap between its paid for counterparts like Symantec and McAfee.

Perhaps the biggest drawback to AVG 7.5 free is the scheduler. The user can schedule a full computer scan and daily definition updates, but they cannot choose the exact time of each. Instead, the interface offers a time range to choose from. For example, the user can select to have the definition updates downloaded between 6 am - 8 am, and the program will select a random time within that range. This is an annoyance, but could be problematic for users who shutdown their PCs at night.

AntiVir


Since the latest AVG interface was problematic on my older computer, I started my search again for a better option. Next I tried Avira Antivir Free. At first, this was a serious contender offering robust coverage of various types of attack. Then I noticed a serious flaw - no email scanner! Couple that with an obnoxious ad window, and it was on to the next candidate.

PROS:
While AVG offers rootkit detection as a separate product, Antivir includes rootkit detection, as well as protection against worms, viruses, and Trojans. Antivir also includes protection against phishing.

CONS:
Avira Antivir Free does not have an email scanner. This is something that is included with the other packages reviewed here, and it seems like a pretty big gap since email is a major entry point for virus infection. One of the biggest downsides, IMO, is an in-your-face very LARGE ad window that crops up daily. With the other options out there in the free antivirus market, this is enough to make me take a pass on AntiVir

Avast! 4 Home Edition.




The last free antivirus program I tried was Avast! 4 Home Edition. Quite frankly, it's the last one I tried because it was the best.

PROS:
Avast! includes Anti-spyware and Anti-rootkit built-in. Each is implemented in separate processes for scanning web, mail, P2P, IM, network and on access traffic. Each one of these processes can be stopped, started or disabled so if you don't have P2P or IM software - you can disable it. This is quite handy on older PCs with less available resources. It also offers Automatic updates, Virus Chest and System integration. The UI is excellent (especially for a free app) and it supports 64-bit Windows and Internationalization.

CONS:
I honestly haven't noticed any real problems with Avast!. If I had to choose something, I suppose I'd say that it is a bit more heavy on the RAM usage than some of the others, but given the completeness of the features, I don't think it's excessive. Besides, the modular scanner architecture allows you to shut down or disable unneeded services.

Thursday, July 30, 2009

Free Firewall Recommendations (Protect Yourself Online With These FreeFirewalls)

If your home computer is connected to the internet, or to other computers that are connected to the internet - you need a firewall. It's as simple as that.

Hackers and hacker software are constantly probing the internet for computers without a firewall. When such a computer (A.K.A. "victim") is found, it is targeted with spyware, viruses, trojans, key stroke loggers and anything else a deviant mind can devise. If you don't want to be a victim, then you need to protect yourself.

How not to be a victim.


Here are 2 really great personal firewall programs that are absolutely free for personal use.

Comodo



Comodo is free for home use. You may be wondering why a company would give away a program for free that is sold for $40 and more by other companies. This thought alone is often enough for many computer owners to skip the free alternative and shell out the money for the "internet protection" software suites.

This is a very normal concern, but here are some things to consider that will probably alleviate those worries.

1). Take a look at those Internet protection suites and see what's included.
Often times, it's not just a firewall but anti spyware, anti virus, web filters, system tuning and maintenance - in other words, the kitchen sink! This is because the makers of the all-inclusive software suites know that each piece isn't worth the full price alone, or they would charge for each piece. So they package them all together and charge one price hoping you'll need at least one of those products enough to buy the whole suite.

2). Most free alternatives offer a slim feature set in the free version, but increased features for the professional version. Also, the free version is often times only free for indiviual use, not businesses. So the company or developer makes money from business use.

That being said, the free versions of Comodo and Zonealarm are more than enough for most home users.

Comodo Features (courtesy of the Comodo website):
  • Complete protection from Hackers, Spyware, Trojans and Identity theft
  • Host Intrusion Prevention System stops malware from being installed
  • Free Download. No charges or license fees ever
  • Powerful and intuitive Security Rules Interface
  • 'Smart' Popup Alerts
  • Application Behavior Analysis
  • Automatic 'Firewall Training' mode
  • Windows Security Center Integration
  • Self Protection against Critical Process Termination
  • Application Recognition Database
  • Automatic Updates
  • Improved Firewall Event Logging
  • Submit Suspicious Files to Comodo

System Requirements (version 3.9)
  • Windows XP - 32 and 64 bit versions
  • Windows Vista - 32 and 64 bit versions
  • 64 Mb RAM
  • 50 Mb free disk space

You can read more about the benefits Comodo Firewall here.
You can download Comodo Personal Firewall here.

ZoneAlarm


ZoneAlarm started as a free only firewall, but experienced significant success and rapidly evolved into a Pro verison. I have used ZoneAlarm on my personal computers for years, with great results. When gathering links for this article, I realized it's become pretty difficult to find the free for persoanla use version. It seems that ZoneLabs (the maker of ZoneAlarm) has gotten aggressive in promoting their professional (read: not-free) version. so far, the actual software has remained ad free, so I can't complain too much.

Features:
  • Systematically identifies hackers and blocks access attempts
  • Automatically makes your computer invisible to anyone on the Internet (Stealth Mode)
  • Intrusion Blocking systematically identifies hackers and blocks access attempts.
  • Stealth Mode automatically makes your computer invisible to anyone on the Internet.
  • Automatic Program Configuration provides safety and simplicity by automatically configuring programs. Automatically decides whether to allow or deny Internet access to individual programs.
  • Expert Controls give savvy users precise control over security settings.

You can download ZoneAlarm Free here.

Conclusion


As I said, I've used ZoneAlarm for years and love it. I have only been using Comodo for a little over a year on my laptop and have had no problems with it.

The only downside to both is that the learning mode can be confusing for inexperienced users. Often times a popup will display asking the user if they want to allow application XYZ to act as a server. Most inexperienced users don't know what the hell that means and can get flustered. What I've done is after installing the firewall, I run all known internet user apps (browser, IM chat, anti-virus update, email, etc...) to "teach" the firewall that these are certified apps. After that, I tell the user (usually a relative or close friend) if it prompts you in the future click "no" or call me.

Comodo advertises "Comodo Firewall offers the highest levels of perimeter security against inbound and outbound threats" I tend to believe them only because I've found that comodo prompts me WAY more than Zonealarm. It seems that Comodo distinguishes how a url was requested by a browser. For example, if the user clicks a link from a word doc, then Comodo will interrupt and inform the user that another application has requested the browser load ".. www.abc.com..." This is great for experienced users, but will definitely be too much for the inexperenced grandma looking to chat with the grand kids... In that situation, I would recommend ZoneAlarm.

Tuesday, July 28, 2009

Are Free Antivirus and Firewall Products Really Any Good?

There was a time in my life when I used security and protection suites like Norton and McAfee, but after a while I grew unsatisfied with them.

"But Norton and McAfee are giants in the industry that pack every last bit of there software with features users never dreamed of! What more could you want?", I hear you ask.

Well, that's kind of the point. Over the years, software suites like these just continued full speed down the road to bloatware. They kept accumulating features like a snowball rolling down hill. They've got features and functionality I never used, and don't really need quite frankly. Often times the system tuning and performance components just sat idle, using my system's increasingly valuable and every more rare RAM.

I did what most people do, I suppose. I bitched incessantly about paying for features I didn't use, didn't want, and worst of all had to actively work at removing from my system! Most times that wasn't even an option, since everything threaded together in a tight knot, with system failure at every turn so that you couldn't pick and choose the features you needed without having all the needless bloat to go along with it.

Then I realized that some other bright people were experiencing the same headaches and were in a position to do something about it. What they did was create their own programs to solve each discrete problem. In other words my friends, say farewell to bloatware!

So now I assemble a patch work of software products that do what I need. They do one thing, and do it well. I use one free program for firewall protection, another free program for virus protection, and various other applications for system tuning and performance, spyware, etc....

I admit, I was hesitant at first. I had questions about how safe and effect these products were. I thought that they couldn't be that good if they were free. Why would someone (or a company) produce software for free if other companies could make $40+ selling it?

Well, the answer is pretty simple. Makers of Comodo, and ZoneAlarm (my firewall products) as well as AVG Antivirus make money on the professional versions of their software as well as business users.

The general idea is that they offer a fully functional version free for personal use, and a different version with more features for a price. So far, with Comodo, ZoneAlarm, and AVG Antivirus I have been very satisfied with the performance and feature set of the free versions.

Thursday, July 23, 2009

How To Control Disk Thrash From ccmexec.exe (SMS Agent).

Today started like any other day at work. I sat down, logged into my PC and was greeted by the thrashing sound of my hard drive. I've come to realize that the bottleneck in my work PC is by far the hard drive. I don't need any bench marking software, I simple try to access a file or two. Sometimes, I simply open windows explorer and wait.

I finally got so disgusted I fired up procman and dug through the activity to find the culprit.

I had to scroll down to the bottom of a couple thousand lines of activity before I saw a clear pattern, but lo and behold what I saw was incredible!

There were literally thousands of disk writes to my pagefile - and all I had done was log in!

The bizarre part was that the files being read and written to the swap file were files I was not touching.

I saw that the process performing all this thrashing was something called "ccmexec.exe". I'd actually never heard of this process, but after some quick googling I discovered its the exe for the SMS Agent service.

This service (the  Systems Management Server service) performs an indexing or cataloging of all the files on the disk so that windows update will have the latest info on versions of OS files that may need patching. Sounds great, but I'm not sure it's worth the cost considering the downtime and aggravation I experience waiting for this thing to chew through my 150GB drive.

My first instinct was to disable the service in the services control panel applet, but I figured that the corporate IT staff would eventually get a tad upset when they realized my system didn't have the latest patches installed because I disabled the service.

So, I was faced with my own kobayashi maru scenario : I was ineffective while this thing chewed threw my file system, but I couldn't disable the service without sending up corporate red flags that I was a bad citizen.

Then I hit on a solution - a scheduled task to ensure the service did run, just not when I was busy working. I actually used two batch files, one for each task of starting and stopping the service.

Open up notepad (or your text editor of choice), and type the following:
net start CcmExec

save the file as "SMS Agent start.bat"


Now, start a new text file and enter:

net stop CcmExec

save the file as "SMS Agent stop.bat"

Note: you can also replace "net" with "sc", to use the newer Service Control manager command line tool.

Then, set the startup type of the SMS Agent Host service to "Manual" in the services control panel applet.



Next, create a scheduled task to run after hours that runs the "SMS Agent start.bat" file, and another task that runs the  "SMS Agent stop.bat" before you get into the office.



The best of both worlds - you remain productive and a good corporate citizen (after hours)!

Tuesday, July 21, 2009

Lessons in Software Development From the Apollo Moon Missions.


Monday was the 40th anniversary of the Apollo 11 lunar landing. The story of the Apollo program is an historic and inspirational one, but it's also relevant to software development.

To understand the significance of the Apollo program from an engineering standpoint, we must begin at the beginning...
Gus Grissom, Ed White and Roger B. Chaffee were killed on the launch pad when the Apollo 1 capsule burst into flames just prior to the launch test. What happened? Well, according to Wikipedia (I know, far from an unimpeachable source, but bear with me here):

"Although the ignition source of the fire was never conclusively identified, the astronauts' deaths were attributed to a wide range of lethal design hazards in the early Apollo command module. Among these were the use of a high-pressure 100 percent-oxygen atmosphere for the test, wiring and plumbing flaws, flammable materials in the cockpit (such as Velcro), an inward-opening hatch that would not open in this kind of an emergency and the flight suits worn by the astronauts."

In short, no one knows for sure what specifically caused the fire, but everyone agrees that some fundamental errors led to the conditions (whatever they ultimately were).

what really went wrong was at the planning and design stage. NASA was in such a rush to make up lost time in the space race with the USSR, that they got cocky after early successes, cut corners and went full bore toward a fully manned, Apollo capsule before they were really ready.

The precursor missions to Apollo were the Mercury and Gemini projects. These projects had highly specific mission statements and each was directed toward a discrete piece of the overall lunar landing mission. Project Mercury was directed toward getting a man into space, and back again. The goal of project Gemini was to perform extra-vehicular activity (pre-cursor to space walk), and docking maneuvers.

NASA began the mission to the moon with an iterative approach, but switch to a more waterfall like approach where they tried to construct a whole new capsule module from scratch, with the intent of landing on the moon and returning. They used the knowledge gained from the earlier Mercury and Gemini projects, but constructed new - and untested - equipment for Apollo.

The parallel to software development is using an iterative approach to develop phase I of a project, only to throw it away and start over on phase II. The whole purpose of the iterative approach is to focus on small, achievable parts of a greater whole to maintain momentum but also to limit what must be tested and hence limit (theoretically) the universe of possible bugs.

I think the 2 most important software development lessons we can learn from the Mercury, Gemini and Apollo missions are:
  1. To be successful, have clear and concise mission objectives (goals).
  2. Start small, and build on each success.

This is what made the Gemini and Mercury missions so successful, and ultimately made Apollo 11 possible and it will drastically improve the odds of your next software project being a success as well.

Friday, July 17, 2009

Fun with Cryptography

Here's a little Friday fun from Monty at MR01001101.

He's got Cryptography and Steganography essays and, here's the fun bit, puzzles that take the user through a chain of tests through his site.

Puzzles range from simple alphabetic substitution to symbolic images to Egyptian hieroglyphs. Fun stuff, and it'll give your brain a workout too.

Wonder what's behind the cryptic sounding name of MR01001101 ? Well, it's not as mysterious as it sounds:


"Why 01001101? It is binary for M and it arrived when I signed up for my first geocities site drunk. I also bought this domain intoxicated. Will I ever learn?"



:-)

Tuesday, July 14, 2009

The 3 Most Important Questions You Should Ask About Each Bug You Find.

I stumbled upon (quite literally) an article by Tom Van Vleck titled Three Questions About Each Bug You Find today, and thought I would share it:
"The key idea behind these questions is that every bug is a symptom of an underlying process. You have to treat the symptoms, but if all you do is treat symptoms, you'll continue to see more symptoms forever. You need to find out what process produced the bug and change the process. The underlying process that caused your bug is probably non-random and can be controlled, once you identify what happened and what caused it to happen."

Tom uses these questions to get to the heart of the matter and weed out the root cause of the bug.

1. Is this mistake somewhere else also?


You want to know if this bug was unique, or due to a problem in a pattern of approach to the specific problem. If it's unique, you can move on to the next question, but if it's systemic, you'll need to address your approach to the development problem the code was intended to solve and devise a new pattern or correct the one in place.

2. What next bug is hidden behind this one?


Often times a bug will either halt the execution of code, or cause the lines after the bug to be bypassed. once you fix the bug, those other lines of code will begin to execute. Be sure to check those for any bugs. Also, consider whether your fix to this bug could cause any new bugs to be introduced.

3. What should I do to prevent bugs like this?


Learn from this mistake. Could the problem be avoided by adding a new test condition to your NUnit test(s)? Should you implement a change to your pattern to check for null reference or out of bounds exceptions sooner? Bugs happen, but if you can use them as teachable moments and learn from them, then they will at least provide some value and make you less likely to run into the same bug in the future.

It's not always an easy process, mostly because it requires a sort of detached introspection and willingness to be critical and objective when looking at your work. These character traits are not always in high supply, and we humans can often get in the way, but if you can master these techniques you will go far young padawan.

Thursday, July 9, 2009

Google Chrome: the OS.

Google announced last Tuesday that it has its sights on dethroning Microsoft as desktop OS king:



"The new operating system, announced late Tuesday night on Google's Web site, will be based on the company's nine-month-old Web browser, Chrome. Google intends to rely on help from the community of open-source programmers to develop the Chrome operating system, which is expected to begin running computers in the second half of 2010."




Google is focusing on the Netbook market, which is a smart first step. I'm not sure how successful they will ultimately be beyond that though. Netbooks are perfectly suited to a browser based OS - they've got inherently less RAM and CPU power and are targeted specifically to the Internet/e-mail user. I don't see any wholesale switch from Windows anytime soon for one of Microsoft's major demographics - business users.

Also, gamers and developer are likely to stay with Linux and Windows, at least for the time being. But, having said that, Google's OS is built on Linux, so there probably wouldn't be that big a change from, say Ubunto to Chrome (or whatever they end up calling it)..

Of course, I'll still have to give it a try when it comes out... just for curiosity's sake! ;-)

Tuesday, July 7, 2009

Dude, Where's my Folder treeview?!

After a wee bit O' overzealous registry cleaning last week, I had a minor panic. Well, a picture being worth a 1000 words, here's what I saw when I opened windows explorer:



The good news (I suppose) is that I knew the instant I hit the Delete key that I had selected the wrong key. The bad news was that I had no way of finding out what key that was.

So, I did some Googling for various permutations of "missing windows explorer folder treeview" and eventually stumble upon the following registry edit:

REGEDIT4


[HKEY_CLASSES_ROOT\CLSID\{EFA24E64-B078-11d0-89E4-00C04FC9E26E}]
@="Explorer Band"


[HKEY_CLASSES_ROOT\CLSID\{EFA24E64-B078-11d0-89E4-00C04FC9E26E}\InProcServer32]
@="C:\\WINNT\\SYSTEM32\\SHDOCVW.DLL"
"ThreadingModel"="Apartment"


[HKEY_CLASSES_ROOT\CLSID\{EFA24E64-B078-11d0-89E4-00C04FC9E26E}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\{EFA24E64-B078-11d0-89E4-00C04FC9E26E}\Implemented Categories\{00021493-0000-0000-C000-000000000046}]

I saved that to a new notepad document, saved it with an ".reg" extension and double-clicked it. Voila, my missing treeview returned!



It sure beats reinstalling the OS for something so simple.

Tuesday, June 30, 2009

10 Useful, Often Overlooked HTML Tags.

Pop quiz: When would you use the <wbr> tag, and what does it do?

Yeah, I had no idea either. In fact, I had never even seen this tag before, but it's a list of 10 Rare HTML Tags You Really Should Know from Nettuts+

I have to say that most of these I hadn't heard of, but they are actually quite useful. Granted, I do most of my work in the .NET code behind and middle ware layers, but I do occasionally get to sling a bit of HTML, and I think I may start using some of these...

Oh, I almost forgot - the <wbr> tag allows you to specify a place where you think a line break might be useful, if needed.

Thursday, June 25, 2009

Annoying "next message" behavior in Thunderbird, and how to stop it!

I love the Thunderbird email client. I use the portable version on my thumb drive, but one thing has always bugged the hell out of me when I use it: whenever I delete an email that I have opened in a popup window, Thunderbird automatically opens the next message. Most of the quasi-official entries on the forums state that this is the default behavior, and how 90% of email users use the app anyway, so there is no simple check box for disabling the "feature".

I must be an odd duck then, because it is most certainly not how I use my email client. I distinctly remember disabling the annoying feature in older versions of Outlook Express. Well, I am the type who will not be denied. I go through great pains to get around such roadblocks - out of principle alone!

So I went digging and found many dead ends, and tips & tricks pages that proved to be unrelated. A lot of forums suggest things like adding the delete button to the toolbar, but that only works if you delete it from the main window. I want to read the email first, then delete it. Reading, closing (clicking the "X") then deleting seems more tedious than necessary.

Then I found this handy add-on. Only one problem: it was for pre 2.0 versions of Thunderbird. The solution: How to hack the add-on to make it work in 2.0+.


Open the install.rdf file, and locate the MaxVersion key:



Then change the 1.6 to 2.1, like so:




and voila!

Sweet!

It's worked great ever since, and I no longer curse Thunderbird. For automatically advancing to the next message, anyway. ;-)

Tuesday, June 23, 2009

How to fake a TreeNodeCollection subclass in .NET

If you've ever had reason to try to extend the standard Microsoft web TreeView control, you will have no doubt noticed that MS was quite unkind to you and sealed (or declared NotInheritable for you VB.NET types) the System.Web.UI.WebControls.TreeNodeCollection class.

The problem arises when you want to overload the default behavior that is implemented by the TreeNodeCollection class. For example, when a node was added to my TreeView class (via the TreeView.Nodes.add method), I needed to be able to analyze it for the ultimate purpose of my subclass.

However, this was not possible because the TreeNodeCollection class is sealed, so I wasn't able to inherit from it and overload the add method behavior as I should have been able to do.

There are always possibilities.



Anyone who knows me knows I don't give up easily (if ever), and I eventually plowed through many false starts but hit upon a solution.

I decided to wrap the underlying TreeNodeCollection class with my own, and overload the Nodes property on the TreeView class, and the ChildNodes property on the TreeNode class.

The Wrapper.



Here's what the wrapper looks like:
Public Class MyTreeNodeCollection

  Private mtvwChildNodes As System.Web.UI.WebControls.TreeNodeCollection
  Private mMyTreeViewOwner As IMyNodeContainer

  Public Sub New(ByVal Owner As IMyNodeContainer, _
       ByVal TreeViewChildren As System.Web.UI.WebControls.TreeNodeCollection)
     mtvwChildNodes = TreeViewChildren
     mMyTreeViewOwner = Owner
  End Sub

  Public Sub Add(ByVal child As MyTreeNode)
     mtvwChildNodes.Add(CType(child, System.Web.UI.WebControls.TreeNode))
     mMyTreeViewOwner.RegisterNodeForLookup(child)
  End Sub
End Class

As you can see, the constructor takes the real, underlying TreeNodeCollection to pass all node to prior to being "registered" (analyzed). It also takes something that implements the IMyNodeContainer interface.

The IMyNodeContainer interface.



I had to implement this because I wanted to be able to use this wrapper class for both TreeView and TreeNode objects, but the signature of their properties is different - TreeView.Nodes and TreeNode.ChildNodes, respectively. So I opted for the interface to keep things clean.

Here's what the interface looks like:

Public Interface IMyNodeContainer

    Sub RegisterNodeForLookup(ByVal node As MyTreeNode)
    ReadOnly Property Nodes() As MyTreeNodeCollection

End Interface

Wrapping things up.



This is where the magic happens.

To put the wrapper (MyTreeNodeCollection) in place, I overload the collection getting properties in the base class - TreeView.Nodes and TreeNode.ChildNodes, respectively, like so:

Public Overloads ReadOnly Property Nodes() As MyTreeNodeCollection Implements IMyNodeContainer.Nodes
  Get
    Return mNodeCollection
  End Get
End Property

So, for those of you playing along at home, when the developer calls .Nodes on an instance of MyTreeView class, an instance of MyTreeNodeCollection is returned and the resulting add method in performed on the underlying TreeNodeCollection, thusly:

Public Sub Add(ByVal child As MyTreeNode)
    mtvwChildNodes.Add(CType(child, System.Web.UI.WebControls.TreeNode))
    mMyTreeViewOwner.RegisterNodeForLookup(child)
End Sub

You can see why I had to use the IMyNodeContainer interface here. The RegisterNodeForLookup performs the functionality I was originally trying to subclass the TreeNodeCollection for.

Tuesday, June 16, 2009

IE7 WebControl TreeView line gap in quirks mode.

I've been writing a subclass of the MS Webcontrol.TreeView control for one of our Web Applications at work. I figured this would be a fairly easy task, since I only needed to extended it with a few properties. It turns out that I was caught on a nit-picky annoyance in the TreeView control itself.

The TreeView control renders verticals lines with gaps.



Here's a screen cap of the problem.




As you can see, the TreeView control renders the vertical line with a gap, or break (looks like a dashed line!). It didn't matter how I loaded the data - dynamic/runtime/design time - I get the same gap no matter what!

I was able to see that it was not a problem in IE 6 or less, but what good is that? Well, it turns out that it was a bit of a clue because starting with version 5, IE didn't render things correctly per the CSS boxing specification. This was fixed in IE 7, but to provide backwards compatibility, Microsoft carried this busted form of rendering forward in IE 6 as QuirksMode. The line gap problem only occurs in strict mode (default for IE 7 and 8, as well as firefox). I could make the line gap go away by forcing the browser into QuirksMode (by adding a comment, ex:

< ! - - QUIRK! - - >

to the very top of the HTML file), but I was writing a web control and would not always have the luxury of controlling my container.

I needed to find a long term solution to this problem.

Next, I looked at the HTML source of the rendered page, and saw this:

<table cellpadding="0" cellspacing="0" style="border-width:0;">
<tr>
<td>
<div style="width:20px;height:1px">
<img src="/TreeviewControlTest/WebResource.axd?d=OYmDnVppVECKIpxOWC8o8Y7DO6QwB2J3EY4s4RR8zAU1&amp;t=633765128008804061" alt="">
</div>
</td>
<td>
<img src="/TreeviewControlTest/WebResource.axd?d=OYmDnVppVECKIpxOWC8o8UGy0bLoCc8gOB1oQm6Pzj81&amp;t=633765128008804061" alt="">
</td>
<td class="TreeView1_WebTree_1" style="white-space:nowrap;">
<a class="TreeView1_WebTree_0" href="javascript:__doPostBack('TreeView1$WebTree','Root//Tree')" onclick="TreeView_SelectNode(TreeView1_WebTree_Data, this,'TreeView1_WebTreet6');" id="TreeView1_WebTreet6" name="TreeView1_WebTreet6">Tree</a>
</td>
</tr>
</table>

Each node is rendered as a table, with the vertical line and expand/collapse icons being in their own table cell and wrapped in a div. The problem was the style applied to the outer div - style="width:20px;height:1px".

That 1px height was causing the vertical line image to be compressed, but where did it come from?

Reflecting on System.Web.UI.WebControls.TreeNode


I spent almost an hour delving into the various (and copious!) style properties for the tree and its nodes, looking for where this height setting was generating from. I couldn't find it! I eventually opened the System.Web.UI.WebControls.dll in Reflector to see what the render code for the node was doing:




Well, once I saw that the code was hard-wired to render this CSS style, I was done. Or was I?

!important



Well, it wasn't going to be as easy as setting the style in the code behind, but I could override the style in my own class.

The trick is to define, and apply the following CSS class:

<style type="text/css">
.MyTreeView TD Div
{
height: 20px!important; 
}
</style>

The !important CSS directive overrides the style applied in the System.Web.UI.WebControls.TreeNode render method.




Again, just as with the QuirksMode comment above, I was able to add the CSS style to the page and voila - problem solved. But this still wasn't good enough. I needed this to work out of the box for any consumers of my control.

The ultimate answer was to override the RenderBeginTag of the TreeView control, and render this style before the control itself:

Public Overrides Sub RenderBeginTag(ByVal writer As System.Web.UI.HtmlTextWriter)
'/////////////////////////////////////////////////////////////////////////////////////////
'///  This is a total hack to get around some Microsoft BS which hardwires
'///        a style attribute on the node div to set the height = 1px!
'///
'///    This renders a css override to force the div to the proper height
'/////////
Me.CssClass = String.Concat(Me.CssClass, " MyTreeView")
writer.WriteBeginTag(HtmlTextWriterTag.Style.ToString)
writer.WriteAttribute(HtmlTextWriterAttribute.Type.ToString, "text/css")
writer.WriteLine(HtmlTextWriter.TagRightChar)
writer.Write(".MyTreeView TD Div  ")
writer.WriteLine("{ height: 20px!important; }")
writer.WriteEndTag(HtmlTextWriterTag.Style.ToString)
writer.WriteLine()
'//////////////////////////////////////////////////

'/// Render the Standard Begin Tag
MyBase.RenderBeginTag(writer)
End Sub

Thursday, June 11, 2009

How to find what's running under SVCHost.exe

My PC was behaving sluggishly the other day. I tried to be patient, but had to fire up the task manager when I could bear it no longer. That's when I noticed great gobs of my swap file allocated to "SVCHOST.EXE":




The problem is, SVCHOST is a catch all windows service container. Meaning, many windows services run under the same instance of SVCHOST. How was I going to figure out which services might be the culprit?

Enter the tasklist command.

Tasklist displays info about running tasks, including SVCHOST.

Simply running tasklist at the command prompt displays a laundry list of all running processes. This wasn't going to do it, so I ran it with the "/?" switch to try and find how to narrow the info...
/SVC Displays services hosted in each process.
/FI filter Displays a set of tasks that match a given criteria specified by the filter.

Looks good so far, now I need to know what filter to apply:

Filters:
Filter Name     Valid Operators           Valid Value(s)
-----------     ---------------           --------------------------
IMAGENAME       eq, ne                    Image name


OK, this gives us:



"C:\>tasklist /svc /FI "IMAGENAME EQ SCVHOST.EXE"




But it seems the filter is case sensitive, because when I run that command, I get this:



INFO: No tasks are running which match the specified criteria.




So, switching to lower case gives me what I want:
"C:\>tasklist /svc /FI "IMAGENAME EQ svchost.exe"
Image Name     PID        Services
=========== =====  =======================
svchost.exe     744        DcomLaunch
svchost.exe     844        RpcSs
svchost.exe     888        AeLookupSvc, AppMgmt, 
AudioSrv, BITS, Browser, 
CryptSvc, dmserver, 
EventSystem,lanmanserver,
lanmanworkstation, Netman,
Nla, RasMan, Schedule,
seclogon, SENS,ShellHWDetection,
Themes, winmgmt, wuauserv
svchost.exe     928         Dhcp, Dnscache
svchost.exe     976         LmHosts, W32Time
svchost.exe     1772       Net Driver HPZ12
svchost.exe     1816       Pml Driver HPZ12
svchost.exe     2424       TermService
svchost.exe     3312       TapiSrv
svchost.exe     2688       W3SVC


From there, it's just a matter of shutting down or restarting each of the services listed under the process id 888 ( I got this from taskmanager).

Tuesday, June 9, 2009

Arraylist and generics don't mix with IEnumerable(Of T).GetEnumerator.

The other day I was writing an in-house tool to assist in some upgrades we were performing on client installations. This tool was supposed to perform its operations on a batch of items, and display the results upon completion.

Since processing this batch of items was a lengthy endeavor, I wanted the failure to process one of the items to simply be recorded and allow the processing of the others to continue. Part of the processing of each item was a call to multiple web services, so I would need a way to handle the collection of errors along the way and make them available for their eventual display.

I had what I thought was a clever idea: a private Arraylist of exceptions that occurred during processing.

Public Class BatchExceptions
Implements ICollection(Of System.Exception)

Private mExceptionlist As ArrayList
.
.
.
End Class

That way, I could simply iterate over the list and perform the standard exception handling, like so:

Dim exc As Exception
For Each exc In BatchExceptions
HandleError(exc)
Next

Of course, in order to make use of the "For Each" construct, I had to implement the GetEnumerator of the ICollection interface.

Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of System.Exception) _
Implements System.Collections.Generic.IEnumerable(Of System.Exception).GetEnumerator
Return (mExceptionlist.GetEnumerator)
End Function

Cool. Only one problem:




That was OK though, because I was using generics after all. The compiler was being helpful and reminding me that I had to specify 'IEnumerator(Of Exception)':




Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of System.Exception) _
Implements System.Collections.Generic.IEnumerable(Of System.Exception).GetEnumerator
Return (DirectCast(mExceptionlist.GetEnumerator, IEnumerator(Of Exception)))
End Function

Everything compiled fine, but at run-time I got the following RTE:

Unable to cast object of type 'ArrayListEnumeratorSimple' to type 'System.Collections.Generic.IEnumerator`1[System.Exception]'.




This was frustrating. It seemed like the compiler failed to warn me of this incompatibility, and simply kicked the can on down the road to the run-time to deal with.

Solution:


Well, I did a little poking around and finally ended up replacing my Arraylist with a list like so:

private mExceptionlist as System.Collections.Generic.list

Well, that did the trick but I can't say it was as intuitive as it would seem. It makes sense, in hindsight, but why did I have to get some cryptic RTE? Why couldn't the compiler have picked up on my use of an ArrayList and say, "Hey dummy - use a generic list!"? Still, I have a new trick to toss in my bag for the time I want to implement an enumerator on an Arraylist!

Thursday, June 4, 2009

How to Delete Empty Folders - FREE!

While performing a disk cleanup recently, I had cause to locate and delete any empty folders under a root folder. I knew there had to be a batch file command to accomplish this, but I couldn't for the life of me remember what it was!

Enter Google.

five minutes of some keyword searching with surgical precision and piecing together commands yielded my solution.
DIR /AD/B/S | SORT > FOLDERLIST.BAT

How It Works.


The Dir command is the familiar directory list command that comes standard with all versions of Windows since 95. The magic is in the switches:
/A Displays files with specified attributes.
When applied to the "D" attribute, it returns directories
/B Uses bare format (no heading information or summary).
/S Displays files in specified directory and all subdirectories.

SORT is an often overlooked command for, you guessed it, sorting. Here, the results of the Dir command are piped ("|") into the SORT command as input. The result of the SORT command is then redirected from the command prompt to a file called FOLDERLIST.BAT.

Kick it up a notch.


Now that you've created this list, say you want to automate the deletion of each entry in the list. This is where pumping the output to a ".bat" file comes in. Open the bat file in textpad, or notepad, or your text editor

For example:
Typing:
DIR /AD/B/S | SORT > FOLDERLIST.BAT

in my C:\Program Files\Microsoft Visual Studio 8\VC folder yields the following results:


Next, open the file in a text editor, word, or open office and replace the beginning of each line with the RD command followed by a space and a single quote. Like so:



This should give you the following:



Notice how each line now begins with "RD "" This is the old DOS Remove Directory command. Don't worry, it only removes empty directories. But you still need to add an ending quote to each line. This is where Word or Open Office is handy. You can do another search and replace, but this time search for "^p" (new paragraph) and replace with ""^p" (end quote and new paragraph).

Save the file, and you're all done except the double clicking.

Tuesday, June 2, 2009

Microsoft FxCop doesn't like Microsoft generated code!

The other day I thought it might be nice to "do the right thing" and give my code a run against Microsoft's FxCop.

I ran it right out of the box - I didn't bother making my own rules or changing the defaults. I was bored. Anyway, here's one of the results that actually made be chuckle once I read it carefully:
Warning, Certainty 90, for DoNotInitializeUnnecessarily
{

Target : #.ctor() (IntrospectionTargetMember)
Location : <735>> (String)
Resolution : "'MyDocument.New()' initializes field 'MyDocument.disposedValue'
of type 'Boolean' to false. Remove this initialization
because it will be done automatically by the runtime."

Help : (String)
Category : Microsoft.Performance (String)
CheckId : CA1805 (String)
RuleFile : Performance Rules (String)
Info : "Do not make initializations that have already been
done by the runtime."
Created : 3/6/2009 6:58:21 PM (DateTime)
LastSeen : 3/6/2009 8:36:25 PM (DateTime)
Status : Active (MessageStatus)
Fix Category : NonBreaking (FixCategories)

}

The reason for the chuckle was that the code which triggered this violation of the rule was written by the Microsoft IDE! My role in this infraction was really quite simple: I typed "Implements IDisposable" and hit Enter. The IDE was "nice" enough to plugin the rest for me:

' To detect redundant calls
Private disposedValue As Boolean = False

' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
Array.Clear(mDocumentContent, 0, mDocumentContent.Length)
End If
End If
Me.disposedValue = True
End Sub

It's bad enough that the IDE writes code for me without prompting, but maybe the FxCop team should talk to the IDE team to avoid such embarrassing nuisances (I had dozens of similar warnings to weed through) in the future.

According to the Code Analysis Team, this is the new default for FxCop 1.36.

Here's how to avoid it:

Using an FxCop project:
  1. Open your FxCop project in FxCop
  2. Choose Project -> Options -> Spelling & Analysis
  3. Check Suppress analysis results against generated code
  4. Click OK

OR, if you prefer the command-line:
  1. Pass the /ignoregeneratedcode switch, for example:

FxCopCmd.exe /file:MyAssembly.dll /out:AnalysisResults.xml /ignoregeneratedcode