Thursday, February 17, 2005

I found this brief essay online today and it's definitely worth the read.  I've mentioned some of the tenets in past posts, but I whole-heartedly agree with Michael's assessment of the life and lifestyle within Microsoft.  Granted, though I was not on a product team or working on-campus as I was in our Salt Lake City branch office, much of what he said was directly applicable.

Individuals within the halls at Microsoft have a passion and a focus for software.  Software is the bread and butter of everything.  There is very little paperwork at all - pretty much everything besides the periodic reviews and printed expense reports (which simply provide a backup to the electronically filed expense reports) is done via software.

The two downsides that Michael mentions that stood out to me are Work/Life Balance and Managers.  He's spot on.  It seems that while the mantra is that one should strike a good, healthy, working balance between work and family life, it is the tendency of managers to judge that work is more important if you had to make a decision (of course it didn't help that my managers were in the Denver office).  Any decision to the contrary is detrimental to your review scores.

He mentions that 'most of lower management should be tossed'.  I'm behind him there.  In fact, I feel that's a big part to my being disillusioned in some respects.  Don't get me wrong, I love the leadership (BillG, SteveB, etc) and a select few of middle/upper management, but my direct managers left a lot to be desired and are probably the primary reasons and catalysts as to why I left in the first place.  I strongly feel that I'd work for MS again if I were to have different (and local) management.

All in all, a very good post.

Thursday, February 17, 2005 5:31:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, February 15, 2005

Frequently, when developing applications we go out of our way to be considerate to end users.  We pop up nice dialogs, use friendly colors, provide keyboard shortcuts as necessary, sometimes we even write help documentation.  But how often do we go out of our way to consider those that run our applications over a terminal session?

Sure, it's cool to have the fancy dialog that fades in and out, but over a terminal session that can be horrendously slow.  As a courtesy, our applications should check to see if they are running in a terminal session environment and, if so, degrade the graphics output gracefully.  But how do we check?  It's amazingly simple.  Dipping down to the GetSystemMetrics() function in the Win32 API is the key.

[DllImport(”user32.dll”)]
public static extern int GetSystemMetrics(int nIndex);

public const int SM_REMOTESESSION = 0x1000;

public static bool IsTerminalSession() {
   return ( 0 != GetSystemMetrics(SM_REMOTESESSION) );
}

The GetSystemMetrics() function will return a non-zero value with a SM_REMOTESESSION parameter value if the application is associated with a client terminal session.

Interestingly, the vast majority of the GetSystemMetrics() functionality was ported over to the .NET Framework to the System.Windows.Forms.SystemInformation class, but the SM_REMOTESESSION is missing (unless I'm just blind).  It actually makes sense to be missing from the standpoint that it really doesn't have anything to do with the Forms namespace.  Is it somewhere else in the Framework and I just don't know about it?

For the time being, however, that one-liner is all it takes!

Tuesday, February 15, 2005 8:04:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [7]  |  Trackback

Let's face it...we're all accustomed to them by now; they're pretty much everywhere.  I'm talking about irregularly-shaped windows, of course.  For a few years it seemed that every new application that came out had to take advantage of the ability to create windows that weren't the same ol', standard, boring rectangular windows that were so commonplace.

I believe that the first application I ever saw to leverage this capability of creating non-rectangular windows was a Norton Anti-Virus - it had a 'shield-shaped' dialog...or maybe it was McAfee.  I was blown away at first by it.  How on earth did they do that!?  Then, predictably, almost every 'cool' tool and application had to have it - especially those in the multimedia arena.  Well, there can be too much of a good thing, but I feel that they have their place.

This capability is made available by Windows via a GDI object known as a Region.  Regions come in a variety of geometric shapes: rectangular, elliptical, polygonal.  Once a region has been established, it can be assigned a window handle (hWnd) such as a Form, Button, etc via SetWindowRgn().  Regions, when applied to an hWnd determine which parts of the window are to be visible and which parts are transparent.

Not to be outdone, this capability is not lost on the .NET framework.  In fact, it's alarmingly easy to create windows with non-rectangular borders.  By using the TransparencyKey property of a Form you're pretty much there.  However, this isn't without it's costs.  When you create a Form that relies on a transparency key for this effect, the system recreates the region at runtime everytime the form loads.  This can impact load time significantly.  It would be much better if we could know before hand exactly what the region was and apply it without having to regenerate it repetitively.

And, as luck would have it...there is a way!  We simply need to dip down into the Win32 using P/Invoke.  Once a region is created (via any of the prescribed methods such as CreateRectRgn, CreateEllipticRgn, CombineRgn, etc), you can call the GetRegionData() GDI function.  This function will return to the buffer that represents the region.  The inverse of GetRegionData is the ExtCreateRegion function, which simply takes the buffer and creates a GDI Region object.  This region object can then be applied to an hWnd via SetWindowRgn and we're off the races.

Back in my VB days about 5-6 years ago I had created a utility which I dubbed the 'Region Generator'.  This utility would accept as parameters a bitmap image and a color to be treated as transparent.  It would cycle through the pixels of the image and generate a complex Region via CombineRgn and the XOR flag which would effectively mark all pixels of the given color as transparent.  Then it would output a binary file containing the buffer from GetRegionData.  I would use this file by embedding it within an application's resource file to be read out and applied at runtime.  It was pretty slick and pretty easy to use.

Unfortunately, I've since misplaced the tool (I know I have it somewhere), but rather than digging up the fossil, I thought I'd recreate the dinosaur.  It only took a couple of hours and some excursions back into the long under-utilized recesses of my mind to remember how to do it.  I have plans to add some other features to it (such as manually entered RGB/Web color values, a color tolerance so you don't have to get the color exactly right which might be especially useful for .jpg images, etc).

Once you have a region saved, it's a pretty simple task of taking the region data and loading it up to assign it to a window.  This example demonstrates how to load the data from a file and applying it (reading it from a resource file is just as easy):

[DllImport("gdi32.dll")]
public static extern IntPtr ExtCreateRegion(int lpXform, int nCount, byte[] lpRgnData);

[DllImport("user32.dll")]
internal static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw);

// read the data from disk into a byte array
byte[] regionData = null;
using ( FileStream fs = new FileStream(@"C:\MyRegion.rgn", FileMode.Open, FileAccess.Read, FileShare.Read) ) {
   BinaryReader reader = new BinaryReader(fs);
   regionData = reader.ReadBytes((int)fs.Length);
}

// create the region from the byte array and assign it to the window
HandleRef hWnd = new HandleRef(this, this.Handle);
IntPtr hRgn = ExtCreateRegion(0, regionData.Length, regionData);
SetWindowRgn(hWnd.Handle, hRgn, true);

Of course in true .NET form, we can use the Region property of the Form rather than having to use SetWindowRgn thus:

this.Region = Region.FromHrgn(ExtCreateRegion(0, regionData.Length, regionData));

Feel free to download and use this tool and let me know what you think.

Tuesday, February 15, 2005 6:51:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Monday, February 14, 2005

An application that I'm writing relies on a Sql Server database.  This database is readonly for users of the website that feeds off of the data.  However, the application utilizes two roles: Publishers and Readers.  Web users fall into the 'Readers' role.  Publishers, however have read/write access to the database in order to push changes to it.  This is not an uncommon scenario by any stretch.

As the Publishers push out their content, the database log file grows, and grows, and grows.  Well I don't need the log file at all, especially since the database can be replaced at anytime simply by dropping it and recreating it.  It never ever has need of being backed up either.

Today, my good friend, Scott Golightly, reminded me of the stored proc sp_dboption.  Using this stored proc upon creating the database I can avoid more complicated commands later on:

EXEC master.dbo.sp_dboption 'dbName', 'trunc. log on chkpt.', 'TRUE'

rather than the following which also carries the byproduct of requiring that the user be a member of the db_backoperator and db_owner fixed roles:

BACKUP LOG dbName WITH TRUNCATE_ONLY
DBCC SHRINKDATABASE(dbName, TRUNCATEONLY)

Monday, February 14, 2005 8:12:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, February 11, 2005

If you happen to ever create ASP.NET UserControls (e.g. .ASCX files) then this might be of interest.  Oftentimes, in an attempt to create useful, dynamic pages, developers will, via code, load control instances rather than rely solely on <tagPrefix:tagName /> declarations on the .ascx page itself.

Instead, we'll frequently call this.LoadControl(”...ascx”) to load the control and then add it to the .Controls collection of the parent .ascx.  This is all well and good and works remarkably well.  However, if you start to do anything fancy in the child .ascx files you may be greeted with the all-too-helpful HttpException: “External component has thrown an exception”.  This can be somewhat disconcerting because the error throws on the call to LoadControl and doesn't provide any feedback as to the cause of the error.

It's time to investigate the child .ascx's HTML.  More often than not, you have some malformed HTML that the server just cannot process.  A situation that I frequently encounter is that the developer created a server-side HTML table control that contains malformed child controls.  The following exemplifies this:

<%@ Control language=”c#” AutoEventWireup=”false” Inherits=”...” %>
<%@ Register tagPrefix=“custom“ tagName=“MyDataRow“ src=“~/.../childcontrol.ascx“ %>
<table id=t runat=server>
   <custom:MyDataRow id=row runat=server />
</table>

While the MyDataRow class might render the contents within <tr><td>...</td></tr> tags that results in good client code, the server code is malformed and the HTML table cannot initialize properly within the UserControl on the web server.

Word to the wise, when dealing with UserControls (especially those that rely on runat=server controls), always ensure that the HTML is well-formed.

Friday, February 11, 2005 7:47:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Thursday, February 10, 2005

Wow!  We had a great .NET User Group meeting tonight.  We had two local consultants, Jason Seeley and Troy Fillerup, present on the topics of .NET Remoting and Web Services respectively.  We had a good turnout and the topics were well received.  Additionally, STG (Software Technology Group) sponsored the meeting and did a fantastic job providing pizzas, drinks, some really cool giveaways.  I'm really proud of the group too.

We've had increasingly more enthusiasm and involvement for the group and it's great to see things coming together.

In the coming months, we already have lined up some exciting topics and presenters.  Carl Prothman is coming in April and will present on ADO.NET and then the following month Joe Mayo on some VS/C# 2005 goodies.  There is a great community in the Salt Lake Valley and it's really starting to pick up this year!

Thursday, February 10, 2005 3:47:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, February 07, 2005

This always bites me, but I wanted to post it here so that I don't waste another 15 or 20 minutes trying to remember this in the future.

If you want to create a new IIS site/virtual directory and designate an application pool with it's own identity, you'll probably be greeted with the all too wonderful and descriptive

Service Unavailable

message when you try to browse to the site.  This can get pretty infuriating to fix unless you remember a few simple rules:

1.  The identity under which the pool will execute needs to be a member of the local IIS_WPG group.
2.  The IIS_WPG group needs Read & Execute, List Folder Contents, and Read permissions on the folder.
3.  You might also need to manually assign the Adjust memory quotas for a process and Replace a process level token rights in your Local Security Policy.

Simply stop and start your application pool once the changes are made and you should be up and running.

See the brief, but excellent Tech Net article on the topic.

Monday, February 07, 2005 5:57:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Sunday, February 06, 2005

A colleague of mine encountered an interesting dilemma today.  All of the sudden, and seemingly out of the blue, Visual Studio .NET 2003 was reporting the following error: “...Web server is not running ASP.NET 1.1” when we've been developing applications using ASP.NET daily.  Now before we go blaming Microsoft for writing crappy software, let's take a look at the situation and try to fix it.

We did a bit of research online and the most prevalent remedy was to run aspnet_regiis -i.  In my experience you'll never really need to run that unless you install IIS after having installed Visual Studio .NET.  So we backtracked to what had changed recently.

It turns out that he had installed Skype this morning.  Everything was working great this morning, but once he rebooted, VS.NET could no longer interact with IIS.  As is so happens, Skype will steal port 80 before IIS has a chance to grab the port for its own uses.  You can, however, open Skype's options dialog and disable it from doing that.

I wonder why Skype decided to use port 80?  Perhaps it should check whether something already uses port 80 (like IIS) before auto-selecting that option...?

Sunday, February 06, 2005 6:19:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Saturday, February 05, 2005

[Updates 02/23/2005, 11/20/2006 - fixed spelling errors]

I'd like to think that I'm reasonably level headed.  It is part of my nature to analyze a situation before making an precipitated response that I might regret.  Of late I have found myself having to bite my tongue and not respond in an almost defensive posture on issues that are not even personally directed nor personal in nature (come to think of it, they might be, slightly just to try to make me mad).

My tenure with Microsoft (now a few years past) was one of the most evocative and eye-opening experiences in my professional career.  One the biggest messages that I gained from joining ranks with Microsoft was passion.  The vast majority of those with which I worked had an intense passion; passion for success, passion for technology, a raw, intense passion.  It was in many ways exhilirating...I absolutely loved it.

Prior to joining the company I had been a developer / trainer that specialized in the tools and technologies that Microsoft published.  For several years I was thus employed.

A few years ago, while I was with Microsoft, I attended the wedding of my cousin and her husband.  As we were performing the customary task of going through the line to greet the bride's and groom's respective families and to congratulate the couple I came upon some other cousins (same family as the bride, of course).  I made to shake their hands and instead of the complimentary 'thank you for coming' or 'good to see you', the following exchange ensued:


Cousin:  "Hey, Aaron, you work for Microsoft, right? With Windows XP?"
Me:  "Uh, yeah"
Cousin:  "It sucks!  Worst software ever.  It broke all my programs."


Needless to say, I was a little taken aback.  I guess I should have known than rather that having greeted my cousin and her new family warmly, I should have been preparing a comeback or a defense for such an imminent and predictable attack - of course! I was at a wedding, what else would I be thinking about?  I don't accurately recall my response except that I committed to talk to them afterwards and see if I could help them out of their predicaments.  I should have seen that one coming, though, because that particular cousin has always treated me (especially) and my family with a certain disdain and disrespect.

As it turns out, the problem wasn't with Windows XP, per se, but rather with a particular Math application that was designed to work on Windows 98.  Something in how Windows XP was created broke compatibility (even attempting to run the application in a Windows 98 emulated environment didn't work).  Therefore, Windows XP was crap and the worst thing to come out of Redmond.  As an aside, I have personally run Windows XP since Beta 2 (when it was the required OS for MS employees) and have seen 2 crashes in total.  Yes TWO.  It has been the best desktop operating system that I've worked with bar none.  The server OS's (e.g. Server 2003) has been even better.  Heh, the guy at the computer store the other day suggested that my server's hard drive crashed because I wasn't running Linux.  It crashed because I was running Windows Server 2003.

Ok, that was a little bit of a segue, but it brings me to my point of defensiveness.  It is difficult not to take attacks on Microsoft semi-personally, though my affiliation has always been somewhat peripheral (as an evangelist, proponent, consultant, trainer, developer, etc).

I frequently deal with individuals that have absolutely nothing but negative to say about Microsoft's products.  I have yet to hear a single sentence of praise, appreciation, or respect for a single thing.  The negative comments are quite literally every 3rd or 4th sentence uttered.  Such comments are invariably directed at Microsoft's poor decisions and are very rarely accompanied with any semblance of a solution; it's just a gripe session.

I simply bite my tongue and don't respond unless it's to offer a solution (which 95% of the time there is one), I let these individuals have their fun griping, for apparently there's fun in it.

Evidently, Microsoft has made all the wrong assumptions on a clean install of the operating system; that, as users, we must go through the drudgery of customizing our systems to undo all of the bad things that Microsoft assumed we wanted because we are not the typical 'dumb, brainless, idiot' user that was profiled when Microsoft performed its user testing is madness!

  • How could Microsoft assume that I'd EVER want to have a CD autoplay when I insert it in my drive!!?  Bad Microsoft!  How dare they assume that!
  • How dare they assume that I want 'My Documents' to store my files!?  Come to think of it, why do I need the stupid directory anyway?  No! I don't want to save my files in 'My Documents'!
  • ...and many more

I guess the real intentions of Microsoft are laid bare:  They want to make life harder on everyone by assuming certain behaviors; assumptions that were made based off of their spending of billions of R&D dollars annually.

I am somewhat of an advanced user of Windows and, upon installing a fresh system, will go through my little routine of flipping all the switches.  For example, I like to show hidden files (how could they assume I wouldn't want to see them?), to disable Simple Sharing (if you don't know how security works you shouldn't use the computer!), and change my resolution settings - plus much more).  In all, I probably take about 20 minutes configuring my system to the way I like it.  If something comes up later that I forgot to change or hadn't yet done, I'll fix it rather than curse Microsoft for making my life so hard.  Sure, some of the software that Microsoft has published in the past has some gaping holes in terms of functionality and security.  It's these same individuals that gripe about all of these oversights and weaknesses yet still insist on using these older applications.  I am happy to see the progress the MS has made with the likes of Windows XP SP2 and the various server platforms.

In fact, I have a novel idea:  Why not try to work WITH the system rather than AGAINST it?  Rather than curse Microsoft everytime the Save Dialog appears on 'My Documents' as the default, and begrudgingly navigate away to C:\Files\blah to save the file, CHANGE the folder to which My Documents refers and use it the way 90% of the applications out there are designed to function?  If Microsoft is making your life hard, change it...or perhaps rethink the way you're using software.  Please don't constantly yell at your computer because the application you're using (not the OS) has decided to do something a particular way.

These individuals dread having to install a utility (such as TweakUI) in order to make system settings changes (Why can't you change these settings within Windows itself rather than having to install ANOTHER program).  How ironic that the question never even arises if one must install the same type of utility on a different, non-Microsoft system (such as Linux).

Personally, I have found that the VAST majority of the decisions made in the base applications are sound and spot on.  The software that comes out of Redmond is designed to enable just about ANYONE to accomplish their tasks without having to understand all of the nitty-gritty details of HOW it works.  Rather, IJW (It Just Works).  Sure, once you need to step beyond the routine, simple tasks your knowledge needs to be expanded.  You may need to learn something new to accomplish that out-of-the-ordinary task.  Perhaps you need to disable on option here or enable another option there - but the switches are available.  Generally, if the software isn't working the way I'd want it to work, I find that I'm trying to get it to do something for which it was not designed.  Maybe I don't fully understand why it was designed that way in the first place.  There are times I'm at odds with the decisions anyway, but that is the exception, not the rule.

I find it interesting, too, that the same individuals that routinely curse Microsoft for one bad decision will not reciprocate the same attitude against a piece of software not from Redmond in which the same 'bad decision' is made.  It's as though the blinders are on and it is just Microsoft that is pure evil.

All of this isn't to say that I LOVE Microsoft.  I really appreciate the software that is developed on campus; were it not for Microsoft, I'd probably be a farmer, or a professional trampolinist, or a gypsy, or a Jedi Knight (though that might still be cool) and not a software engineer.  Microsoft has some of the most intelligent people working on their software, and I'd like to believe that they know what they're doing.  This is not to say that I blindly accept the food they feed me...I'll test it out and come to my own conclusions.  I, for one, praise the likes of Raymond Chen, for example, for enlightening us on why things are the way they are.  99% of the time there is a reasonable explanation.  I think the software they create is DANG good, and I'm proud to work with it and not against it.

Saturday, February 05, 2005 8:40:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [24]  |  Trackback
 Wednesday, February 02, 2005

Well, despite having my Domain Controller's hard drive go south last night, I'm back up and running!

I scurried down to the local computer store this afternoon and picked me up a brand new 160 GB drive (oh, and I also grabbed a 250 GB, 16MB Cache drive along with it).  This time I also got a 2 year warranty with them - I'm sick and tired of dealing with downed drives.

Well, prior to today, I had not had the experience of restoring an Active Directory and an Exchange Server...so this was uncharted territory for me.  I had made a backup of my System State last night and the Exchange data, so I was all set there; it was just a matter of restoring it properly.

These are the steps that I underwent:

  1. Put new drive in computer
  2. Format/Partition it as NTFS
  3. Installed the base OS (Windows Server 2003)
  4. Configured the NIC and IP address
  5. Installed IIS, DNS, and DHCP (though I did not configure them)
  6. Rebooted into Directory Recovery mode
  7. Restored my System State data, thereby bringing back the domain
  8. Rebooted
  9. Installed AntiVirus software
  10. Installed Exchange 2003 and SP1
  11. Restored the Exchange backup
  12. Repaired the database (ESEUTIL /P ...)

It's all up and working now and I'm so excited.  What pleased me most was that from taking out the old drive and being completely back up and running it took less than 90 minutes actual time (a few hrs real time including dinner and other sundry items).  Now the whole domain is back and it feels good!

Wednesday, February 02, 2005 3:10:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I must be a magnet.  A magnet for hard drive failures.  Which makes sense when you think about it.

Last night, during a not-so-routine backup of data on my domain controller (which happens to dual as my DNS, DHCP, Exchange, some file storage, etc), it encountered several Cyclical Redundancy Check (CRC) errors.  Dismayed, but not to the point of depression, I trudged forward and backed up the System State and the Exchange data and verified them.  I then proceeded to run CHKDSK /R which necessitated a reboot.  Durinng the CHKDSK it displayed each of the segments that were unreadable (starting at about 36,000 it went well into the 100,000s with the occasional skipping of a just few segments).  My rudimentary math tells me that it must have been about 50% of the drive that was bad.

So this turns out to be my 4th drive in about 2 years to go out (though officially this one hasn't crashed per se (yet) like the others).  Not only is it my 4th drive to go out, it's always been the boot volume on the domain controller that has gone out.  On reboot it warns me of imminent failure of the disk...nice, <sarcasm>at least I'm not sweating here</sarcasm>.

Maybe I'm a magnet for bad equipment? for bad luck?  Anyway, I'm on a budget and can't afford anything 'state of the art', nor do I expect 5 9's here at my house where it's only me and a few other people, but I'm heading down to my local Comp USA, Best Buy, or Office Max to get a new drive (as I need it TODAY).  Recommendations before I make the march in a bit here?  Anyone have recommendations for the 'best' drive?  My domain controller isn't even a 'server-class' box, but it's a pretty capable workstation, no SCSI or anything like that.

Wednesday, February 02, 2005 3:45:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback