Damon Payne: Hand waving Silverlight Architect

103db signal to noise ratio at < .03% total harmonic distortion
Solution Architect, software developer, geek
Damon Payne at Blogged
2009 Microsoft MVP - Client App Dev
2007 Microsoft MVP - Solution Architecture
 Sunday, July 04, 2010

I have in hand a couple of one year MSDN Subscriptions with Visual Studio 2010 Ultimate.  Never you mind where they came from, but they didn’t fall of the back of a truck, they are legitimate. 

These are not for me, they are for YOU.  However, there are only two of these and according to my quick Twitter poll, a lot more than two people who’d like their own MSDN Ultimate.  Therefore, I pose to you a very simple contest.  Leave me a comment or send me an email telling me why you should get a subscription.  I will choose the winners late this week.

{Edit: I should be clear: I’m looking for community influencers here.  Tell me how this prize will touch more lives than just your own}



Sunday, July 04, 2010 8:10:59 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [9]  |  Trackback
 Thursday, November 05, 2009

In just over a week, on November 14th, I will be speaking at the Chippewa Valley Code Camp taking place way up in Menomonie, WI on the UW-Stout campus.  The topic is Advanced Silverlight Development however the content will be somewhat different than my talk by the same name I gave at MadCamp a little while ago.  Doug and company run a healthy community so I’m looking forward to good conversations.

Details on the code camp can be found at: http://www.chippewavalleycodecamp.com/ 

The schedule of topics can be found here: http://www.chippewavalleycodecamp.com/Schedule/2009Schedule/tabid/74/Default.aspx

The elusive Christopher J. Barwick will be accompanying me and making his return to Public Nerd Life.  I am looking forward to seeing Jason Bock and Chris speak, and I’ll probably check out some of the non-Microsoft or Building Better Software topics in between.  We’ll be up the night before and open to grabbing a drink with any local geeks or speakers who may be available.



Thursday, November 05, 2009 10:18:41 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [6]  |  Trackback
 Saturday, August 15, 2009

I have been happily using the Unity container for over a year now.  I had previously written my own IoC framework in Silverlight and used some other off the shelf and custom home-grown containers.  I have recently been getting started using MEF in Silverlight as part of some up and coming Patterns articles.

When you scratch the surface of MEF, I’ll warn you that you may be Underwhelmed.  What, exactly, is this?  The Ultimate IoC container?  What is this doing for me that Unity wasn’t already doing for me?  In fact, you can implement the IUnityContainer interface with MEF so what’s the big deal?

Is the big deal…

  • That MEF is the Visual Studio 2010 extensibility mechanism?  No. Microsoft has claimed that they needed MEF for internal efforts like this.  I believe they are earnest, that this is not just a public “Look at us eating our own dogfood” showing.  Still, Microsoft needed the Entity Relation model beneath the Entity Framework and we saw how well that was received by the community.
  • That MEF works in Silverlight?  No.  Other IoC containers were ported to Silverlight 2 long before Unity or MEF.  We’ve been able to use the same container for Silverlight/WPF/ASP.net/Winforms/Console apps for a long time.
  • That MEF has cool features like Catalogues, Dynamic Recomposition, Lazy<T> ? No.  These features are cool and I plan on exploring them further and talking about them to anyone who will listen.

No, the big deal is that MEF is shipping with .NET 4.

So what, you say? Let me explain.  A lot of you probably listen to .NET Rocks.  I do, I enjoy it.  The hosts are funny, the guests are bright, and I get bite-sized updates on what is going on out there in areas of the development universe that are important to me but not so important as to be in my overloaded RSS list.  .NET rocks succeeds for various reasons and to hone in on one of the big whys let’s take a look at one possible way to group developers:

  1. Brand new developers. 
  2. Developers who are lazy clock-punchers who don’t care about their craft whatsoever.  Enough said about these folks.
  3. Developers who know enough to know there are better ways.  They struggle within the bureaucracy.  They’ve heard testing is good, but why?  They feel they probably need abstractions, but where?  Some don’t quite have the motivation or the skills the find the answers themselves; some have never been afforded the opportunity to break out.
  4. Developers who think they have all of the answers but are full of $(‘.crap’).
  5. Developers who mostly “get it”, who have the motivation and skills to find the answers, refine their craft, and make things better.

Based on my own experience Group #3 makes up an awful large percentage of the developer world.  A lot of the folks in Group #5 start here until something snaps within them and they decide to stop playing WoW and get serious about figuring out what it takes to get better.   These #3 folks want to learn but the lure of American Idol keeps them from catching up on those blogs.  They want to try a new pattern but the Architecture Police have decreed that they must never do X and always do Z.  Maybe the political war required to get a new library into the solution to try a different way kills any initiative.  Maybe their employer never springs for training.  More often than not, the high turnover in IT isolates developers from the long term perspective that would otherwise be a great teacher.  Which abstractions worked and which turned out to be nightmares or at best simply unnecessary?  Who knows.  We don’t go back and ask because we’re afraid of the answers, and to be fair we all hate each others’ code anyway.

The .NET rocks show and things like it is a little beacon of light, a reminder that some people are really doing things right out there, and staying on the cutting edge, and delivering a lot of value.   But, Damon, how does this relate back to MEF?  Because Group #3 is looking for guidance.  How many guests have debated which Data Access technology Microsoft “wants us to use” ?  Do they want me to use LINQ to SQL or Entity Framework?  Yes, the good folks behind door #3 who are in the .NET space overwhelming look to Microsoft for that guidance.  When Microsoft showed creating SQL DataAdapters inside button click event handlers that’s what they did.  When Microsoft said Stored Procedures are the way that’s what they built.  When Microsoft said SOA was good we learned SOAP.  When Microsoft endorsed jQuery we learned jQuery. 

By putting MEF in the .NET framework the community of well-meaning folks who want to do better are going to see a new message, some new guidance.  “Microsoft wants me to think of my applications differently.”  Microsoft is telling me that my apps should be composed out of modules, perhaps modules hidden behind interfaces.  I should worry about the physical location of a module or its implementation later and program against abstractions.  When I write a class I should think about what the responsibility of this class is and what its dependencies are.  Microsoft is telling me to get onboard with loose coupling.  I don’t need to petition my overlords to bring in a new framework because the only thing between me and MEF is:

using System.ComponentModel.Composition;

Microsoft has always been a Platform company.  I like my Zune, the Xbox is cool, I’m a PC, and maybe the Microsoft Stores will be cool.  But let’s be real: what Microsoft does better than anything else is to build something that other people use to build something.  By including MEF in the core toolbox Microsoft is getting behind a lot of solid development ideas and removing another barrier between the Average Corporate Developer and Better.

 



Saturday, August 15, 2009 7:30:59 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [12]  |  Trackback
 Tuesday, July 14, 2009

One natural way to create some visual effects would seem to be animating the clipping path of a visual element.  Sitting down in either Visual Studio or Blend 3 will immediately show there’s not a straightforward way to do this.  There have been some other means of doing this posted online involving  creating a Storyboard and DoubleAnimation entirely in a code-behind.  Since one of our goals when using Silverlight and Blend should be a clean designer/developer separation,  I didn’t care for this approach. 

We’re going to build a “wipe” effect using animation and clipping paths and the only code behind will be the Storyboard trigger.

Setup

I’m first going to create a Silverlight 3 Navigation application and throw in my own styles.  I add a Page called AnimateClip.xaml and throw in a DataGrid containing some sample wine data and a button I can push to test the “wipe” effect.  The application looks like this when I navigate to the new page:

ss0

 

DataGrid XAML

I’m going to apply the Wipe effect to the DataGrid.  Here’s the initial XAML defining my grid.  As you’ve already seen above I created some Sample Wine data to populate the DataGrid.

<data:DataGrid x:Name="WineGrid" AutoGenerateColumns="True" IsReadOnly="True" CanUserResizeColumns="True" Grid.Row="1" Width="500" Height="200" RenderTransformOrigin="0,.5">
    <data:DataGrid.Clip>
        <RectangleGeometry Rect="0,0,500,200">
            <RectangleGeometry.Transform>
                <ScaleTransform x:Name="WipeScale" ScaleX="1" ScaleY="1"/>
            </RectangleGeometry.Transform>
        </RectangleGeometry>
    </data:DataGrid.Clip>
</data:DataGrid>

Note that I’ve given the DataGrid a clipping geometry that exactly matches the bounds the DataGrid has anyway.  The RectangleGeometry gets its dimensions from a Rect property.  The struct Rect has a Width property, but Rect.Width does not appear to be backed by a DependecyProperty, so we can’t simply animate the Width of a Rect.  Without creating new Rect structs and manually animating in C#, some trial and error was needed in order to find a workable XAML-only solution.  The solution is to name the ScaleTransform and animate its Properties.

I’m going to create the Storyboard manually in XAML, we’ll see why when moving to Blend 3 in a minute.

<Storyboard x:Name="WipeGrid">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="WipeScale"
                                   Storyboard.TargetProperty="ScaleX">
        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
        <EasingDoubleKeyFrame KeyTime="00:00:00.5000000" Value="0"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

So, this is fairly simple once we figure out how to effectively animate the bounds of the DataGrid.  Ordinarily this Storyboard would produce a uniform “shrink in” effect.  The default RenderTransformOrigin is of course the very center of a UIElement.  Because the RenderTransformOrigin of the DataGrid is set to 0, .5 we get the desired “wipe” effect as we are calculating from the left side rather than the center.

When I press the Wipe Out button the code-behind starts the Storyboard.  The wipe effect now works as desired.

Polish

As I enjoyed how the wipe effect looked, I thought perhaps I’d use some of the new built in easing functions to make it even better.  In the recently released Expression Blend 3 + SketchFlow, this is what I see when attempting to edit my Storyboard:

ss1

Despite the fact that the Storyboard works,  the clipping path is missing something needed for Blend to be able to show it for timeline editing.  I assume this is because it’s technically not a visual element in the tree, but just a humble RectangleGeometry used to modify a visual element.  I really don’t feel like learning the ins and outs of all of the easing functions and their parameters, so for now I had to create a bogus storyboard and copy it to this Page.  The Quadratic Ease (InOut) produced the effect I was going for.

<Storyboard x:Name="WipeGrid">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="WipeScale"
                                   Storyboard.TargetProperty="ScaleX">
        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1">
            <EasingDoubleKeyFrame.EasingFunction>
                <QuarticEase EasingMode="EaseInOut"/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
        <EasingDoubleKeyFrame KeyTime="00:00:00.5000000" Value="0">
            <EasingDoubleKeyFrame.EasingFunction>
                <QuarticEase EasingMode="EaseInOut"/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

So, while that would not be bad as far as hand-crafting XAML it would be better if I didn’t have to build fake Storyboards to create my visual effects.  With a more complex Storyboard mistakes might be made in the manual copy & conversion process.  You now have an alternate way to animate clipping paths in Silverlight using XAML.



Tuesday, July 14, 2009 7:46:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, July 05, 2009

I have just applied to join the recently created INETA Regional Speaker program.  It’s unclear whether or not there is an approval process.  This program is meant for people who “are not ready for the national program”; read: I’m no Scott Hanselman.  This is the “farm team” for the national program.  I have asked them to add Parallel Programming as a topic and I hope to take my Silverlight and PFX show on the road.



Sunday, July 05, 2009 2:06:47 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, July 01, 2009

I am proud to be able to announce today that I have been award the Microsoft MVP award in the proficiency of Smart Client technologies. 

I’m extremely appreciative of my nomination and of my new MVP Lead Suzanna Moran.  I’m already excited about the summit next year!  There’s a lot of exciting things coming from MSFT, and I’ve got a lot of community involvement planned for the coming year.



Wednesday, July 01, 2009 11:11:28 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, May 05, 2009

The Fox Valley .NET user’s group has posted a hand-out for the two sessions I’m doing this Saturday.  Cool!

http://fvnug.org/dnn/LinkClick.aspx?fileticket=ZGv%2fajN89eU%3d&tabid=36

{Edit: Here's the schedule of events too. http://fvnug.org/dnn/DayOfNet/Schedule/tabid/62/Default.aspx. I hope to see familiar faces there tomorrow.}



Tuesday, May 05, 2009 2:35:13 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, May 01, 2009

The next two stops on the Mix it Up! tour are quickly approaching.  My talk to the Wisconsin .NET Users Group (metro Milwaukee area) has been moved up to this coming Tuesday, May 5th. You can find details on how to register and where to go here.

The following night, Wednesday, May 6th, I will be in Madison.  You can find details on this talk here.

I hope to see you there!



Friday, May 01, 2009 8:00:22 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, April 10, 2009

Last night I did my first stop on the Mix it Up! tour: the Indy NDA group in Indianapolis, IN.  These guys have got it made.  They have an absolutely fantastic group of people, a great location, and a TON of swag at every meeting.  I was pleased to be bringing some t-shirts and copies of Expression Studio only to show up abd find 20 books, a webcam, and various other nice prices already on the swag table.

These guys are hard-core too:  Their attendance is 120 people and up for every event, and they hold various SIG groups right after the main user group meeting.  After I did the Mix it up content they invited me into their Architecture SIG meeting to discuss the MVC pattern and we ended up talking about map reduce and the Parallel Extensions for the .net framework.  Thanks, guys, for having me, and maybe I’ll be back again.



Friday, April 10, 2009 2:59:59 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, March 31, 2009

The What:

A whole lot of goodness was announced at MIX09.  Many of us were unable to attend.  Larry Clarkin and Dave Bost of Microsoft decided to locate some dedicated Web/RIA geeks in the Midwest region to bring an ultra-condensed version of the MIX09 announcements to user groups, conferences, and code camps.  While the level of detail won’t equal what you would have gotten by going to MIX09, we can hopefully get you excited about what’s coming up and answer some of your questions. 

The Who:

Corey Miller

Anthony Handley

Damon Payne

Josh Holmes

Larry Clarkin

The When:

  • 4/1 CD2UG (Corey Miller / Anthony Handley) – The first stop, I’ll be heading down to Chicago tomorrow to provide moral support and take notes on how things flow.
  • 4/9 Indianapolis, IN (Damon Payne)
  • 4/15 CNUG (Corey Miller/ Anthony Handley/ Josh Holmes)
  • 4/30 Lake County (Anthony Handley)
  • 5/6 Madison, WI (Damon Payne)
  • 5/8 RIAPalooza (Anthony Handley)
  • 5/9 Fox Valley Day of .NET (Damon Payne/ Larry Clarkin) – This is a day long conference, and our presentation will serve as the keynote for this event!
  • 5/12 Milwaukee (Damon Payne)
  • 5/12 Ft Wayne, IN (Corey Miller)
  • 5/14 Chippewa Falls, WI (Damon Payne) – hopefully I can be forgiven for looking forward to this date most of all.  Doug has promised to book the Leine Lodge for this presentation.  Beer + Silverlight = shangri-la
  • 5/16 Indy Code Camp (Josh Holmes)
  • 5/19 South Bend, IN (Corey Miller)
  • 5/26 Rockford, Il (Josh Holmes)
  • 5/30 Chicago Code Camp (Josh Holmes – possibly others?)

See you there!



Tuesday, March 31, 2009 9:11:15 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, January 14, 2009

I wanted to write up some thoughts based on attending yesterday's MSDN Dev Con in Chicago.  Since I knew this was coming, I purposely did not do much reading about the technologies announced at PDC.  This was my first exposure to these items. 

Keynote: Ron Jacobs's keynote was of course the typical "Lots of cool stuff you can't have yet".  I'm interested in Windows 7, I'm one of the folks who actually really likes Vista.  While I had hear about VS 2010 being rewritten in WPF this was the first time I had actually seen it, in this case showing some kind of comment view provider.  This will be huge.

A lap around Oslo: I've been following Dan Rigsby's blog for a while and I got a chance to meet him before the show. 

Here's what I learned from his talk: Oslo is the capital of Norway, and Microsoft wants to buy it.

Just kidding, Dan!

Now that I have a super-basic understanding of Oslo I have a couple of concerns.  The first regards Dan's comment about creating a DSL that some kind of business user could use to create functionality.  It is my firm belief that this won't happen in the next ten years, not because it's technically infeasible, but because Business Analysts, Managers, and the like do not want direct responsibility for systems.  They like a nice, thick neck to get their hands around if something goes wrong and by that I mean us Technical folks can always be blamed for any shortcomings in the implementation of any Grand Vision.  Maybe I'm pessimistic, but I cannot imagine this direct accountability happening any time soon.

My second concern is a smaller technical issue.  Dan showed an example of a DSL specific to WCF services.  This seemed well enough for expressing WCF specific ideas (endpoints, URL patterns, etc.) but I wonder if there is or will be a mechanism for using generic code from another CLR language.  For example, I may have a business logic or data access component already written in C#, and my WCF service is just a thin layer on top of it to expose it as a service.  Enquiring minds want to know.

Business Apps in Silverlight: I heard before the conference that this talk would involve a brief look at some new features in Silverlight 3 so I had to check it out.

The future stuff was billed as ideas taken from the Artist Formerly Known as Alexandria.  Overall, I'm sorry to say I was disappointed in what I saw and here's why:

  • A demo was shown whereby a server side business operation exposed via WPF was automatically linked to a generated Silverlight class in the client.  This was nice, since I have nothing but issues with the automatically generated endpoint configuration for WCF <--> Silverlight.
  • Data Source: MSFT is bringing the notion of an ASP.Net Data Source into Silverlight/XAML.  All in all, I wasn't sure I liked the magical nature of this, but it's optional.
  • Navigation: my ears perked up when the speakers said they were going to bring a notion of Navigation into Silverlight.  My problem with what was shown was that it was NOT NavigationWindow and Page, but something new: Frame and so forth.  Why not use WPF concepts?  I have heard many times that the intention is to bring more parity between Silverlight and WPF.  The ability to deep-link to the application using the URL query string is good at least.
  • An ASP.Net-ish Login control was shown as well as some declarative security you can place on functionality.  It wasn't clear if this would ONLY work with ASP.Net Membership and Role providers on the server, or if the client side mechanism would be extensible via a provider model as well.

Overall, I'd like to see Silverlight going in more of a WPF direction than an ASP.Net direction and I'm worried about what I'm seeing.  The vibe I got from this talk was that Silverlight is going to "Work real well with ASP.Net" or "Something you can do instead of Web Pages, if you want".  There was no mention of bringing Commanding or other awesome (fundamental) WPF features into Silverlight.  I hope that I'm wrong.

F#: I first looked at F# something like two years ago and got frustrated and dropped it.  Having done some functional style stuff in C# and LINQ of late, I've been meaning to pick it up.  Aaron Erickson gets big points from me for using the term "Hand Waving".  His presentation, however, I felt wasn't basic enough for an intro to F#.  If the goal was to tell the audience why they might want to look into F# then mission accomplished.  If his goal was to show us how to do some basic things, not so much.  What do the |> or -> operators mean in F#, things like that.  By this time of the day, my 100% lack of sleep the night before was seriously weighing on me, so these things may have actually been explained.

I do plan on getting the book he described as the Most Basic learning F# book he showed, if I can remember what it was called.

After the conference several of us went to Fogo de Chao where I had a tremendous amount of excellent meats with bell peppers and some Malbec.



Wednesday, January 14, 2009 11:51:59 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Saturday, December 06, 2008

Reggie Burnett of MySQL fame has finally spoken out on the oft-promised, never-delivered Entity Framework support coming in the 6.0 version of MySQL connector .NET.  You can comment here.

I wanted to post this as I am sure there are many people here who feel like they have been mislead. I can assure you that you have not been intentionally mislead. The 6.0 release that will have entity framework support was supposed to be out over 1 month ago. It was been delayed mainly for licensing reasons. There is a large chunk of code that we are planning to include in that release that is licensed as MS-PL and the MS-PL is not compatible with the GPL. I have some program managers and our legal department working on it and hope we can find an answer very soon.
I am very sorry for the delay and appreciate your patience. I am very committed to the .NET/Mono community and have been given full support from Sun. I have also been told that I will perhaps be getting some additional developer support in the near future. That will certainly help to speed things up.
Again, I apologize for the delay. I am not trying to duck your questions in this forum but have just been working hard on the 6.0 release. Even with the delay I think everyone will be pleased with it. The main features are:
1. Completely rewritten visual studio integration with improved table editing including change script generation
2. Improved performance of the connector in many scenarios (faster than libmysql in some cases). This is a _very_ big deal.
3. Entity framework support

That's good news!  Working for corporations with legal departments often means being extremely careful of what one says in the public forum so I'm willing to give Reggie the benefit of the doubt for his radio silence on certain topics.   This means I can actually start moving ahead on some personal projects of mine that use MySQL for $$ reasons.  MySQL should be ready to rock before I am done fighting with CSS.



Saturday, December 06, 2008 11:37:34 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, December 04, 2008

I will be at the "Mini PDC" MSDN developer conference on January 13th in Chicago, IL. 

http://msdndevcon.com/Pages/Chicago.aspx

It looks like I know several of the speakers and some of the content has likely already been seen online, but I'm eager to see this stuff in person and getting Windows 7 Beta is worth the train ride down!  The PDC was huge this year and it's nice to have a chance to hit the highlights.

I'm thinking a reservation at Fogo de Chão will be in order for after the show...



Thursday, December 04, 2008 2:23:30 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, September 21, 2008

This article and AGT[8] were written with Windows Live Writer, after Larry talked me into trying it.  So far, I really like the idea, but the implementation could be better.  I typically write my articles in Word 2007, since I may be working on one for days or weeks.  Cut 'n pasting out of Word into the DasBlog FreeTextBox just works.  Sure, it generates the ugliest HTML you've ever seen, but it looks like code in both IE7 and FF3.  Copy/pasting out of VS2008 into Live Writer looks like this:

ToolboxItem speakItem = new ToolboxItem("Tower speaker", "This is a generic 2-way tower speaker with horn-loaded mid & high range", typeof(HornSpeaker));
Toolbox.AddItem(speakItem, "Audio");

Copy/pasting out of MS Word 2007 into Live Writer looks like this, using the "keep formatting" option.

            ToolboxItem speakItem = new ToolboxItem("Tower speaker", "This is a generic 2-way tower speaker with horn-loaded mid & high range", typeof(HornSpeaker));

            Toolbox.AddItem(speakItem, "Audio");

It's not bad, but it insists on inserting some extra spaces between lines.  I've also been uploading a .zip file of the source code as it stands at the end of each article, and I find no way to do this from Live Writer - perhaps that's not supported by the blogger API.  I do like it inserting & uploading images for me.

For complex articles, I'll still be copy/pasting from Word, but for a free program I do rather like Live Writer.



Sunday, September 21, 2008 7:16:10 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Tuesday, September 16, 2008

You simply know you're doing good, important, awesome work when you are able to get this error at runtime:

An exception of type 'System.Security.VerificationException' occurred in DamonPayne.IoC.TempProxy but was not handled in user code

Additional information: Operation could destabilize the runtime.

The Type name "DamonPayne.IoC.TempProxy" is wrong, and doesn't exist, which just adds to the fun. This will factor into the AGT series of articles, but I took a brief break to share this badge of honor.  In the age of awesome search engines, a developer can often learn how to quickly do a search for their particular error type or error message or get lucky based on some aspect of their exception stack trace.  Sometimes, very rarely (rarely unless you are Dan) you will have an error so specific that no one has blogged about it, or documented it, or asked about it in newsgroups.  The first reaction to this situation is typically panic or disgust; "crap I'm in uncharted territory" or "I can't believe no one else has tried this".  Sometimes these feelings are followed by Pride.  In a time of rising water level, more and more abstractions between the programmer and the metal, there is a certain appeal to doing something that was clearly not intended by the developers of the frameworks you are consuming.  At the very least, you now know that you are down in the bowels of The Machine, far below the safety nets installed to save Mort from himself.



Monday, September 15, 2008 11:06:11 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, September 11, 2008

In VS2008 SP1, some of the project property pages include some minor changes.  For web sites and WCF projects, there is a "Servers" area under the Web tab.  You can, for these settings, store them in the Project file rather than the user-level settings.  I view this as a good thing.

The decision as to what settings are project level and what settings are user level have always made me scratch my head, I cannot determine any reasonable hueristic as to how the choice is made.  Should users be able to choose their own warning level?  Probably.  Should users be able to choose to optimize code or not?  Probably.  Should "allow unsafe code" be something that a user can toggle?  Probably not.  If my project contains unsafe and I build without that setting it will clearly not compile, what good is that?  Perhaps Team Server addresses some of these issues, but I for one would like to see more settings optionally tied to the project.



Thursday, September 11, 2008 11:35:41 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, July 07, 2008

Pardon me while I scratch my head and try to decipher this paradox:

 

This is one seriously confused program.



Monday, July 07, 2008 9:53:14 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Thursday, June 12, 2008

While looking on Reggie's blog for news on MySQL support for the Entity Framework, I enjoyed reading this article.  I continue to be amazed at the performance of the CLR.  Some people are absolutely baffled that managed code could be faster than native code, and the low-level reasons why have been blogged by people far smarter than I in the past.  Since someone just asked, A couple of the better-known reasons:

1) The managed heap rules:  If I say "object* foo = new object();" in C++, the OS looks around to find some memory it can give me.  CLR programs use a managed heap, however.  Despite the fact that calling "new()" is always expensive, the managed heap gives a huge advantage.  Instead of searching for free memory, the next chunk on the managed heap is returned immediately.  C developers writing games have used similar tricks for years, using malloc to get a big chunk of memory and managing bits of it themselves as needed.

2) JIT rules: C# is always JITified before execution.  JIT compiling turns your C# into machine code.  So what, you say, my C/C++ code is pre-compiled for the platform and doesn't pay the JIT penalty on application startup.  The advantage of the JIT is that it can be compiled each time the program is ran, and potentially take advantage of different situations and things specific not just to a processor architecture, but on each individual machine.  (I need to find a link to cite this appropriately) 

Anyway, read the article on Reggie's site, and thank him for the work he's doing.  Hey Reggie, when is that preview of Connector 5.3 come out?

.NET | C++ | O/R Mapping


Thursday, June 12, 2008 12:20:58 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, May 13, 2008

In addition to concurrency, the 64bit realm is another obvious place where the PC/Server world is going.  It’s faster than 32bit, we can address more memory, and we can have more accurate hardware floating point.  Ideally, it should be easy for everyone except low-level framework authors, device driver authors, and the like to migrate their applications to 64bit.  I mean this for Native applications too.  If you had to support both “interface X” and “interface Y” in your application, you’d create a level of indirection to do so, perhaps a Strategy pattern. 

If you are a .NET developer, all of your programs should magically become real 64bit applications when running on a 64bit .net framework on a 64bit machine.  Handy!

I have not written a non-trivial C program in quite some time, so I preface this statement with the disclaimer that it may be total crap: If you are a native developer you should also be able to effortlessly port your app to work with 64bit systems.  If you are NOT hard-coding any address sizes, struct sizes and the like, a simple recompile should work.  Using sizeof(), size_t, etc. the compiler becomes your level of indirection in a way.

Today I sat down to start testing TestDrivenàxUnitàNCover; I pretty much need TestDriven and NCover to do serious work. xUnit.Net ships with an easy installer that tells TestDriven it exists.  It reports success.  It doesn’t work.  I happen to have the xUnit code on hand so I run it through the debugger.  TestDriven looks at a registry key (HKEY_LOCAL_MACHINE\SOFTWARE\MutantDesign\TestDriven.NET\TestRunners) for a list of assemblies containing a class that implements its test runner interface and their locations.  The following code returns “true”:

        public static bool IsRunnerInstalled

        {

            get

            {

                using (RegistryKey runnerKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\MutantDesign\TestDriven.NET\TestRunners\xunit", true))

                    return (runnerKey != null);

            }

        }

The problem is, inspection using Regedit shows that the key is clearly not there.  What’s going on?  Just on a hunch, I thought I’d google for some 64bit issues.  Since there’s \Program Files\ and \Program Files(x86)\ on my 64bit machine, I wondered if there was a second 64bit/32bit registry somewhere.  Almost…

Microsoft, in their wisdom, decided that the registry needs a layer of indirection for 32bit applications.  What purpose this serves I cannot fathom, but you can read all about it here:

http://support.microsoft.com/kb/305097

So, something you THINK is in one place may really be below a “Wow6432Node” registry key.  As I’ve already stated, though, .NET programs should magically be 64bit on a 64bit framework.  There is a way to break this though, and sure enough, the xunit.installer assembly is marked with a Platform Target of x86 in its build properties.  Since the default is the magical “Any CPU” I assume there was a good reason to change this.  My missing registry key, sure enough, is being created in HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\MutantDesign\TestDriven.NET\TestRunners.   TestDriven is looking in the Correct location and not finding what it needs.  I copied the Wow6432 data up into the 64bit area of the registry, disabled and re-loaded TestDriven in the VS2008 add-in manager, and now I’m in business.  Xunit does not appear in the “Test With” menu but Run Tests and Test with debugger now run my XUnit tests.

Test withàCoverage using NCover works too.  I can now ditch NUnit.  Looking at the xUnit à TestDriven code, I’m sure I can get concurrent xUnit tests running from Visual Studio using TestDriven whenever I’m ready. 

Native Windows developers may know what issue this registry redirection practice solves, but it’s lost on me.  Maybe it’s a thunking limitation, I don’t know.  At any rate, it’s something to be aware of when combining 32 and 64 bit code.

 



Tuesday, May 13, 2008 10:11:56 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, April 08, 2008

Someone in my fan club has too much time/money on their hands.  I took this screenshot just now:

 



Tuesday, April 08, 2008 10:41:53 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Monday, March 31, 2008

Before I go ahead and publish my next article, I have two minor gripes about Extension Method Syntax.  Suppose I have a simple extension method:

public static string FriendlyClassName(this object o)

{

string className = o.ToString();

return className.Substring(className.LastIndexOf(".") + 1);

}

I don't care much for explicity use of "this", sice this is basic OO:

//I don't like Extension Methods making me explicitly use "this"

Console.WriteLine(this.FriendlyClassName() + " complete");

I also don't care much for the following being invalid syntax:

Console.WriteLine(base.FriendlyClassName() + " complete");

That one informs me that type "Object" does not contain the FriendlyClassName() method, it would appear that the "this" keyword triggers the syntactical sugar of the extension method paths of the compiler? 

Take a look at the next one, which Dan thinks is wonderful.  Using this extension method:

        public static bool IsNullOrEmpty(this System.Collections.ICollection collection)

        {

            if (null == collection || 0 == collection.Count)

            { return true; }

            return false;           

        }

The following code does not throw any exceptions:

            List<string> nullList = null;

            if (nullList.IsNullOrEmpty())

            {

                //Whiskey Tango Foxtrot?

            }

Hmm... you can read about the NullObject pattern here http://www.cs.oberlin.edu/~jwalker/nullObjPattern/

In a disgusting way, we could use a set of Extension Methods to impliment the NullObject pattern.  IF it makes sense in your program, IF doing the usual coding for nulls isn't appropriate, IF the classical Null Object pattern isn't appropirate, IF Nullable<T> isn't appropriate for your scenario.  That's a lot of ifs.  Still, I found this to be useful in certain cases.



Monday, March 31, 2008 12:58:11 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, March 30, 2008

A small part in my decision to make the leap to Vista 64 was Scott Hanselman's findings upon building his home office and a new workstation therein: moving to 64bit was a non issue.  I wish I could report the same.

My first issue was with installation.  With certain hardware configurations Vista x64 will crash with 4gb of RAM installed until a hotfix is applied.  My understanding of the state of the 64bit world is this: the current 64bit processors are not entirely 64bit.  They have 64 bit registers and some 64 bit instructions.  To the average PC hotrodder or developer the preceived benefit is the ability to use 4gb of RAM instead of 2gb.  I installed the hotfix, got my 4gb of RAM working, and set about playing the Sweeny Todd soundtrack whilst I decided what order to install things in...

The drivers for my X-Fi sound card installed, I started Windows Media Player.  Windows Media Player crashes the first time I start it 100% of the time.  Vista Sp1 and a horde of updates has not fixed this.  Since the X-Fi is probably the most popular aftermarket sound card in the known universe at this time this ought to to work.  It may have nothing to do with sound drivers at all.  The 2nd or 3rd time I launch WMP it will work happily forever.

My graphics card is a PNY GeForce 8800GT series.  It clearly lables itself as having both 32 and 64 bit drivers on the driver disc.  I experienced an new Vista phenomenon with this product: installing the drivers using the OEM program declared that no changes were made to the system.  I pointed Vista at the .inf file on the disc for x64 and Vista basically said its own driver ("Standard VGA Port", yeah right) was better and refused to take the OEM drivers.  Only the Nvidia unified driver install would work.  Odd...

My next stage is to get my various messenger programs up and running so I can chat whilst I wait on things to intall.  MSN messenger is objectively the best messenging experience by far so that went worst, no issues there.  I have used Pidigin for AIM (most CarSpot folks and some friends are on AIM) since having crashtastic experiences with Trillian and an absolutely astounding clusterfuck with the actual AIM product ruining a Vista install; it would seem AOL is the reigning champ for the national heavyweight Invasive Install Championships.  Pidgin has similar behavior as WMP, it will crash and then run perfectly for as long as the machine is up.

My Blu-Ray drive was working fine as a Serial ATA DVD drive.  Folks, installations of things like Office 2007 are actually quite painless with something better than an IDE CD drive.  This alone is worth the extra expense.  Still, it came with software that can play Blu-Ray and there are nights (like tonight) where I'd like to watch a movie on my 1080p monitor while some long-running tasks scroll by on my ancient 19" CRT.  My first attempts at getting Blu-Ray playback working met with failure.  The install process (damn you Pioneer) demanded ridiculously old and specific versions of DirectX that were clearly not going to happen on Vista 64.  Some combination of Windows Update and SP1 magically fixed this, so I watched Blood Diamond on Blu-Ray while logs scrolled by tonight. 

My last two 64bit issues dealt with actual software development.  Visual Studio and the like installed and ran fine except for one issue so infuriating I have a dent in my forehead: copying an ASP.net solution from one machine to another suddenly started claiming that "{MyCustomThinger} RoleProvider has already been added", and commenting this part of Web.config out certainly allows the site to run.  As expected, putting this web.config with the role provider commented out on any other machine (including my development laptop and the two servers where the site actually lies) crashes because of course the configuration is incorrect.  I still can't explain this one.  The next issue was the most time consuming.

MySQL comes in 32 and 64 bit flavors for Windows.  I needed MySQL for one of my development efforts.  MySQL x64 does not like Vista x64.  In fact, the slightly out of date platform notes on their site claims Vista x64 is not supported, but there are enough success stories out there suggesting this is just a CYA that I gave it a whirl anyway.  MySQL 64bit would not run, claimin a "side by side configuration" was incorrect.  OK, knowing very litting about anything this sounds like some sort of thunking layer issue, so I'll try the 32bit version.  Same error.  What does Google say?  Google says that the Application Manifest in the server configuration process is broken for 64bit windows.  The MySQL forums claim that only a program called Reshack can fix this.  The problem with Reshack is that it runs on 32bit platforms only.  For those who don't know: the various Icons, embedded resources, and execution manifests for a Windows .exe get compiled into a special section of a windows PE and programs like Reshack can read/write this area without doing anything to the code itself.  I eventually found a Delphi program posted by a company in the UK that would work for me.  Having had some bad experience with libraries without a strong name that I am missing the code to recompile, I was glad MySQL doesn't attempt to use authenticode signatures with their releases.  I changed the Vista application manifest XML to the appropriate "requireAdministrator" and I was finally off and running.

The last issue I experienced this weekend was with some code I "inherited".  It uses Microsoft Jet ODBC to treat a file as a "data source", access the file rows using DataReader constructs, and sort the contents in a DataGrid.  This code bombed when I ran it.  Google tells me that Jet does not exist for x64.  I had planned on rewriting this code anyway but wasn't up to the task tonight, so I kept looking.  .NET programs are usually targetted to "any CPU" by default, but Google told me changing the target specifically to x86 would allow some extra Thunking Magic to happen, and as soon as I did this I was back on my way with Jet magically found now.

After these experiments, I'm definately going to test all of my production code to make sure I haven't done anything that won't work with 64bit editions of Windows or the .NET framework.  I also need to take it upon myself to do some research: what does 64bit do for me and for Joe Consumer besides 4gb of RAM on Vista?

.NET | ASP.NET | Rant


Sunday, March 30, 2008 1:17:26 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Saturday, March 15, 2008

Dan has posted an excellent article on implementing a Tree structure in C#.  He has beaten me to the punch, after talking about my "Tree of dependent tasks" idea over beers.  I should have something to add to the discussion in the coming weeks.



Saturday, March 15, 2008 3:45:31 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, March 03, 2008

I have never been more ready for spring than I am this year.

It was a whopping 40degrees here yesterday and I took advantage of it.  I spent hours chopping ice out of my driveway, I can't type so well today due to the blisters on my fingertips.  The huge piles of snow on either side of my driveway make surprisingly good reach-level beer holding areas, and I pulled out the bbq pit and made some brats.

I also wrote a Mapping tool this weekend.  When you're first getting started it's interesting to note the similarities in flat file, XML, object-to-object, and SQL to Object mapping: at least in terms of the initial abstractions that present themselves.  I specifically wanted to solve a flat-file to complex object problem and write a tool that previews the mapping in real time and realized I couldd do quite a bit more if I weren't lazy.  The main place I could see using this in my own efforts are class-to-class mapping.  For example: if you are consuming a web service the proxy generated will return to you class instances using whatever naming conventions and object structure the designers of said service wanted to give you.  Even if another team in your organization is the maintainer of this service, Directly using these proxy types within your code is probably a mistake; mapping ProxyObject.PrimaryKey to MyDomainObject.Id quickly becomes tedious.  A mapping tool that does the annoying work for you and saves the mapping as an easy XML file or better yet generates transformation code might be helpful. 



Monday, March 03, 2008 9:50:15 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, February 27, 2008

Got the Zune today.  So far I am underwhelmed.  My very fast and very up to date Vista Laptop failed to install the Zune software the first time.  The error code explains this could be one of a number of thigns: .net 2, encoders and a lot of other developer-sounding nonsense.  Since the Zune installer checks for updates etc. this is unacceptable.  I am directed to a page with a svelte 173mb download to get all of the correct versions at once. 

Downloading...

.NET | Rant


Wednesday, February 27, 2008 2:37:04 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Tuesday, February 26, 2008

Invoking a .NET program on Device Insert

Given the popularity of the .NET Platform it seems odd that Microsoft does not provide easier means of doing certain incredibly useful and easy to imagine tasks from the .NET framework.  It took what seems like a ridiculous amount of research to accomplish a simple task:

Lots of programs come up as ‘launch’ options when I insert a storage card/camera/video camera/PDA/Mp3Player/younameit device into a USB port.  I’d like my .NET program to be in that list and to run if the user selects it.

File Types & WIA

The most useful thing you get in Visual Studio towards this goal is file types.  You can build an MSI for your desktop application and make your “.damon” files open with this program and have right clickàOpen appear in the shell context menu for “.damon” files.  I’ve written before about how to do multiple-select and some useless and goofy things with this scenario, but this doesn’t get us anywhere near where we want to be. 

WIA is very useful for media-specific actions like this, and handles the “something was plugged in” scenario in specific cases.  There is a WIA Automation Layer and managed wrappers for this.  Obviously if you care about something besides JPGs and AVIs WIA may not work for you.  Also, WIA requires that the device you’re speaking to has a WIA driver.  WIA drivers are certainly very common for the appropriate device types, but when you are distributing desktop software that depends on an OEM’s drivers you’re stepping into a world of pain (Not a world of Payne, which is actually a wonderful place).    Can the OEM give you merge-modules for the install?  Are their drivers buggy?  Be sure to treat your Support Group very well if you go down this path.

The Problem Solution: Shell Extensions and Managed Code

I’m going to focus on a simple subset of the overall problem.  Despite the perceived simplicity of the final solution, I couldn’t find a single working example of this online so if you got here via Goolge you’ve hit the jackpot.   Suppose you have an SD card, an SD card reader, and some family photos on said SD card.  You would like a .NET program to automatically create thumbnails of these when the SD card is inserted into your card reader.

Step 1

Step 1 is to read some obscure documentation found here: http://msdn.microsoft.com/msdnmag/issues/01/11/autoplay/

The first part of this is easy to follow. The Windows Autoplay functionality mostly resides in the sub keys of HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\AutoplayHandlers\EventHandlers\

Oddly enough, the names of these sub-keys are almost meaningful and you can do some Googling Windows Live Searching to get an idea of what exactly will cause this or that handler to be invoked.  In our case, the key we want for XP and Vista is ShowPicturesOnArrival.  Windows scans the SD card after it’s inserted and finds JPGs or whatever and checks this sub key to determine what choices the Shell should offer the user.  What can be gleaned from the MSDN article in Step 1 is that we can make up a Handler name, so I’ll call mine TestPhotoHandler.  This “TestPhotoHandler” must correspond to a sub key of HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\AutoplayHandlers\Handlers (../../Handlers from ShowPicturesOnArrival), which will in turn contain some values that describe what TestPhotoHandler is to the Windows Shell.

Step 2

Step two is to populate our Handler.

·         Action=what will appear to the user they are doing with this handler. 

·         DefaultIcon=Pretty self explanatory.  You can also use the Foo.exe,-1 syntax to specify an embedded resource. 

·         Provider=Name of your program

·         InvokeProgID, InvokeVerb=the interesting part, keep reading.

o   Note that it would be FAR too easy to just let you include the path to your .exe or .dll here…

With just the above work done, you can see the following behavior in Windows:

Step 3

Telling Windows where to go from here is far more difficult than it needs to be, and I could not find a single working example of getting this stuff to work with managed code.  In addition to telling Windows how to find our .NET program, Windows must be able to communicate with our program.  There are three interfaces that are interesting for these purposes:

1.       IHWEventHandler

2.       IHWEventHandler2

3.       IDropTarget

These are COM interfaces.  Because I keep meaning to get back into C++ development I always install C++ accessories in Visual Studio.  This means I have the various COM header and IDL files installed, and I can dig up some useful information.  Recall that .NET classes can implement COM interfaces as long as you know the GUID of the COM interface.  Here, then, is my IDropTarget interface definition for .NET objects.

    [ComImport,

     InterfaceType(ComInterfaceType.InterfaceIsIUnknown),

     Guid("00000122-0000-0000-C000-000000000046")]

    public interface IDropTarget

    {

        [PreserveSig()]

        int DragEnter(IntPtr pDataObj,               //  IDataObject

                      ulong grfKeyState,             //  DWORD

                      POINTL pt,

                      ref ulong pdwEffect);          //  DWORD*

 

        [PreserveSig()]

        int DragOver(ulong grfKeyState,              //  DWORD

                     POINTL pt,

                     ref ulong pdwEffect);           //  DWORD*

 

        [PreserveSig()]

        int DragLeave();

 

        [PreserveSig()]

        int Drop(IntPtr pDataObj,                    //  IDataObject

                 ulong grfKeyState,                  //  DWORD

                 POINTL pt,

                 ref ulong pdwEffect);               //  DWORD*

 

    }

 

    [StructLayout(LayoutKind.Sequential)]

    public struct POINTL

    {

        public POINTL(long xx, long yy) { x = xx; y = yy; }

        public long x;

        public long y;

        public override string ToString()

        {

            String s = String.Format("({0},{1})", x, y);

            return s;

        }

    }

 

PointL was copied from Dino Esposito’s excellent article on Shell Extensions on The Server Side.  At any rate, these three attributes on IDropTarget basically tells COM that we can speak the COM lingo and have the behaviors specified by the Interface identified by this GUID.

Step 4

Next we’ll implement the IDropTarget Interface.  The implementation can supposedly reside either in an .exe or .dll, but for our purposes it only works and is only safe when the implementation is on the Entry Point of an .exe project.  So,

    [Guid("C1D0D2F6-5F45-4462-9835-C463AFE367E3")]

    [ComVisible(true)]

    public class Program : IDropTarget

    {

        /// <summary>

        /// The main entry point for the application.

        /// </summary>

        static void Main()

        {

There are some things to take note of here.  Since we wish to enter the world of COM (and COM is love…) we put a ComVisible attribute on the class.  The default Program created for you in VS2008 has Program as a static class, which cannot have attributes so we’ve removed that.  We also have used the Tools in Visual Studio to create a GUID for this class.  We are using an API known as “HackingtheRegistrySinceNoRealRegistrationAPIExists” and guids are the coin of the realm.  I happen to hate this API but options are scarce.

Step 5

The next step is to register our code in such a way that it is findable via the appropriate magic.  For .NET programs RegAsm.exe is our registrar of choice.  Note that RegAsm will pout if your Assembly is not strongly named.  If we now “Regasm.exe /codebase LaunchTestProg.exe” we get some interesting registry settings created for us.  Under HKEY_CLASSES_ROOT\CLSID we find our Program’s GUID, along with the following:

A sub key named “ProgId” containing the fully qualified class name of the .NET program we’d like to run is nestled beneath our class id guid.  This is part of the explanation for the values in Step 2.  Continuing to search for our GUID in the registry we find that HKEY_CLASSES_ROOT\LaunchTestProg.Program has been created for us. 

Step 6

Rather than be clever I’ll just show the final piece we need to create.  The Shell depends on various lookups and naming conventions to determine what it needs to do. 

Below HKEY_CLASSES_ROOT\LaunchTestProg.Program, we need to create some registry keys and values ourselves.  We create sub keys shell, open, DropTarget, and put the GUID of our .NET program as a clsid attribute of the DropTarget key.  The entire process can now ask the user, find, and Invoke our .NET program when a USB device is inserted and it meets the original Handler criteria.

Further Investigation

Upon testing this, I found some interesting behaviors.  It appears that while the .NET project must be an .exe, what Windows is really doing is instantiating the Program object and invoking the members of IDropTarget on it.  I have not tried too hard to get Main to run.  In normal cases, IDropTarget.DragEnter and then IDropTarget.Drop will be called.  For my particular needs, the arguments to either method are throw-away, but using these should be normal P/Invoke & Marshalling exercises.  If you just want to start some other .NET code you can now do so from the your Drop()  implementation.

I will also warn that you want to read this and understand what it means: http://blogs.msdn.com/junfeng/archive/2005/11/18/494572.aspx

I will also warn that the class library Assembly that contains my IDropTarget interface seems to be file-locked once I actually invoke my program.  Restarting Explorer.exe fixes this, which may be a consideration if you are going to be auto-updating the program in some way.  It seems odd that the .exe containing the actual program is not locked.  I plan on investigating the registry areas of Windows\CurrentVersion\ShellExt\Cached to see if clearing that and firing the appropriate Registry Changed event will unlock the assembly. 

Other Avenues...

You will notice DeviceGroups and DeviceHandlers keys as siblings of the “EventHandlers” subkey.  I also mentioned IHWEventHandler and IHWEventHandler2.  The latter is merely the Vista version of the former that adds an extra method, presumably for UAC.  It seems that allowing a .NET program to reconfigure itself if a new input device is plugged in is certainly not out of the range of possibilities.

Would you like some thrown-together code that does all of this for you?  I’ve been meaning to get better about posting more code, so here we are:

    public class DropTargetInstaller

    {

 

        public bool Install(Assembly exe, string entryPointTypeName, string desiredHandlerName, string iconPath, string actionText, string usingText)

        {           

            Type t = exe.GetType(entryPointTypeName);

            object[] attributes = t.GetCustomAttributes(false);

            GuidAttribute guid = GetGUID(attributes);

 

            //Throws ArgumentExceptions to caller if the Assembly/class does not meet requirements

            VerifySuitability(entryPointTypeName, t, attributes, guid);

            string guidVal = guid.Value;

 

            Regasm(exe);

            WriteRegistryValues(desiredHandlerName, actionText, iconPath, entryPointTypeName, usingText,guidVal);

            

            return true;

        }

 

        /// <summary>

        /// Suitable classes must Implement the COM IDropTarget interface, be marked COMVisible, and contain a valid GUID attribute

        /// </summary>

        /// <param name="entryPointTypeName"></param>

        /// <param name="t"></param>

        /// <param name="attributes"></param>

        /// <param name="guid"></param>

        private void VerifySuitability(string entryPointTypeName, Type t, object[] attributes, GuidAttribute guid)

        {

            if (!VerifyDropTarget(t))

            {

                string msg = string.Format("Type {0} does not implement IDropTarget", entryPointTypeName);

                throw new ArgumentException(msg);

            }

            //

            if (!VerifyCOMVisible(attributes))

            {

                string msg = string.Format("Type {0} is missing COMVisble attribute", entryPointTypeName);

                throw new ArgumentException(msg);

            }

            //                        

            if (null == guid)

            {

                string msg = string.Format("Type {0} is missing Guid attribute", entryPointTypeName);

                throw new ArgumentException(msg);

            }

        }

 

        /// <summary>

        ///

        /// </summary>

        /// <param name="exe"></param>

        protected void Regasm(Assembly exe)

        {

            string regasmExe = @"Microsoft.NET\Framework\v2.0.50727\RegAsm.exe";           

            string regPath = Path.Combine(@"c:\windows\", regasmExe);

 

            //RegAsm does not support URI format (file:////c:blahblah

            ProcessStartInfo info = new ProcessStartInfo(regPath, "/codebase " + exe.CodeBase.Replace("file:///",string.Empty));

            info.RedirectStandardOutput = true;

            info.RedirectStandardError = true;

            info.UseShellExecute = false;

           

            Process p = Process.Start(info);

            using (StreamReader stdOut = p.StandardOutput)

            {

                using (StreamReader stdErr = p.StandardError)

                {

                    p.WaitForExit();

                    string output = stdOut.ReadToEnd();

                    string errput = stdErr.ReadToEnd();

                    //Do error logging here if stdErr is not blank, etc.

                    int code = p.ExitCode;

                }

            }                      

        }

 

        /// <summary>

        ///

        /// </summary>

        /// <param name="desiredHandlerName"></param>

        /// <param name="actionName"></param>

        /// <param name="iconPath"></param>

        /// <param name="entryPointName"></param>

        /// <param name="usingString"></param>

        /// <param name="guid"></param>

        protected void WriteRegistryValues(string desiredHandlerName, string actionName, string iconPath,

            string entryPointName, string usingString, string guid)

        {

            WriteHandlerRoot(desiredHandlerName, actionName, iconPath, entryPointName, usingString);

 

            WritePhotosOnArrival(desiredHandlerName);

 

            WriteDropTarget(entryPointName, guid);

        }

 

        private static void WriteDropTarget(string entryPointName, string guid)

        {

            RegistryKey classesRoot = Registry.ClassesRoot;

            if (classesRoot.GetSubKeyNames().Contains<string>(entryPointName))

            {

                RegistryKey invokeProgId = classesRoot.OpenSubKey(entryPointName, true);

                if (invokeProgId.GetSubKeyNames().Contains<string>("shell"))//Start over

                {

                    invokeProgId.DeleteSubKeyTree("shell");

                }

                RegistryKey shell = invokeProgId.CreateSubKey("shell");

                RegistryKey open = shell.CreateSubKey("open");

                RegistryKey dropTarget = open.CreateSubKey("DropTarget");

                dropTarget.SetValue("clsid", "{" + guid + "}");

                dropTarget.Close();

                open.Close();

                shell.Close();

                invokeProgId.Close();

            }

            else

            {

                //Regasm did not run

            }

            //

            classesRoot.Close();

        }

 

        private static void WritePhotosOnArrival(string desiredHandlerName)

        {

            RegistryKey photosOnArrival =

                Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\AutoPlayHandlers\EventHandlers\ShowPicturesOnArrival", true);

            if (!photosOnArrival.GetValueNames().Contains<string>(desiredHandlerName))

            {

                photosOnArrival.SetValue(desiredHandlerName, string.Empty);

            }

            photosOnArrival.Close();

        }

 

        private static void WriteHandlerRoot(string desiredHandlerName, string actionName, string iconPath, string entryPointName, string usingString)

        {

            RegistryKey handlerRoot = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\AutoPlayHandlers\Handlers", true);

            if (handlerRoot.GetSubKeyNames().Contains<string>(desiredHandlerName))

            {

                handlerRoot.DeleteSubKey(desiredHandlerName);

            }

            RegistryKey handler = handlerRoot.CreateSubKey(desiredHandlerName);

            handler.SetValue("Action", actionName);

            handler.SetValue("DefaultIcon", iconPath);

            handler.SetValue("InvokeProgID", entryPointName);

            handler.SetValue("InvokeVerb", "open");

            handler.SetValue("Provider", usingString);

            handler.Close();

            handlerRoot.Close();

        }

 

 

        protected bool VerifyDropTarget(Type t)

        {

            Type[] interfaceTypes = t.GetInterfaces();

            bool dropTarg = interfaceTypes.Contains<Type>(typeof(IDropTarget));

            return dropTarg;

        }

 

        protected bool VerifyCOMVisible(object[] attributes)

        {

            for (int i = 0; i < attributes.Length; ++i)

            {

                if (attributes[i] is ComVisibleAttribute)

                {

                    return true;

                }

            }

            return false;

        }

 

        protected GuidAttribute GetGUID(object[] attributes)

        {

            GuidAttribute g = null;

 

            for (int i = 0; i < attributes.Length; ++i)

            {

                if (attributes[i] is GuidAttribute)

                {

                    return (GuidAttribute)attributes[i];

                }

            }

 

            return g;

        }

    }

To use this class just do the following from Main:

            DropTargetInstaller dti = new DropTargetInstaller();

            string iconPath = Path.Combine(Application.StartupPath, "LaunchTest.ico");

            dti.Install(System.Reflection.Assembly.GetExecutingAssembly(), "LaunchTestProg.Program", "TestHandler", iconPath, "Do something cool", "Launch Test Prog");

 

And there you have it: you can invoke .NET programs when certain Windows Shell events occur.  I plan on doing some basic Zune testing when it arrives and exploring uses for the IHWEventHandler code. As far as I know this is the only example of its type online which is a shame.  Enjoy.



Tuesday, February 26, 2008 11:32:49 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, February 23, 2008

What's wrong with this picture?  (I wish I had found this during RC0)

 



Saturday, February 23, 2008 9:49:08 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, December 26, 2007

http://thirstydeveloper.com/2007/12/23/Episode6ProjectEuler.aspx

My podcast regarding Project Euler is up. Go check it out.



Wednesday, December 26, 2007 10:10:27 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I installed Beta3 of the ADO.Net Entity Framework today as well as the Visual Studio integration tool and started using it on a project that's not mission critical.  So far my only complaint is that it does not (seemingly) include the capability to apply a Regex to the Table Name-->Entity Name process.  For example, I've gotten into the habit of naming tables in the plural, so "select * from Questions" seems natural, however having an object of type Questions annoys me.  Once I think of (or see someone else's) a means of testing performance vs. raw SQL and decide to actually use this I suppose I can rename my tables, seems a shame though. 

Oh, and, I would like for it to be an actual "shipping" product.



Wednesday, December 26, 2007 3:48:09 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, December 21, 2007

Hmm, it's been a while since I've posted anything worth reading to anyone but my Mom!  I shall soon remedy this.

I'm in the process of securing the approval of Klipsch for my final edited version of the Podcast I did this week, so that should be up on KlipschCorner.com soon.  During this endeavor, I thought of an excellent idea for code/architecture podcasts, which I will not share until I have an example.

I've had the good fortune to actually interview some people lately.  Yesterday I thought up my favorite new interview question

"If you were interviewing me and wanted to stump me with a reasonable .NET question, what would it be?"

I need to qualify what "reasonable" means or come up with a better way of stating the challenge to avoid lame questions.  Yesterday the question I was asked was "What is the default file size limit for the FileUpload control in ASP.Net?".  Legitimate question to ask a senior .NET person or too specific to know unless you just used it this morning?  I'll let you be the judge.



Friday, December 21, 2007 12:00:05 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Tuesday, November 27, 2007

http://www.syncmyride.com/#/home/

I wonder if there's a developer program...



Tuesday, November 27, 2007 7:19:42 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, November 17, 2007

I suppose it's going to be fashionable to slam Microsoft until the end of time.  Check out this headline at Slashdot, which I have generaly enjoyed for 9 years or so:

Developers: C# Memory Leak Torpedoed Princeton's DARPA Chances

"In a case of 20/20 hindsight, Princeton DARPA Grand Challenge team member Bryan Cattle reflects on how their code failed to forget obstacles it had passed. It was written in Microsoft's C#, which isn't supposed to let you have memory leaks. 'We kept noticing that the computer would begin to bog down after extended periods of driving. This problem was pernicious because it only showed up after 40 minutes to an hour of driving around and collecting obstacles. The computer performance would just gradually slow down until the car just simply stopped responding, usually with the gas pedal down, and would just drive off into the bush until we pulled the plug. We looked through the code on paper, literally line by line, and just couldn't for the life of us imagine what the problem was.'"

Damn Microsoft and their bad products!  Why doesn't everyone just get a Mac so things will "just work"?  The commentary by the team that wrote the code is a bit more telling:

http://www.codeproject.com/showcase/IfOnlyWedUsedANTSProfiler.asp

So, the problem was not C#, but a bit of confusion in that subscribing to an event keeps a reference to the subscriber in memory, hence no objects can be deleted.  So this issue would occur in pretty much any modern managed programming language.  Am I wrong to occasionally be miffed at the constant misrepresentation of Microsoft's excellent developer technologies?

.NET | Rant


Saturday, November 17, 2007 10:34:33 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, November 13, 2007

I got the AT&T tilt today.  I have done the Smartphone thing for a few years but this is my first full PDA phone.  I ported a stripped down version of one of our data collection apps to run on the phone, man do I love the compact framework.  I'm going to see about getting CF 3.5 on here tonight and maybe port my incomplete Asteroids clone to the phone.



Tuesday, November 13, 2007 4:21:38 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, November 01, 2007

There are various little gotchas writing software for Vista.  I've posted before about ridiculous things like logging not working.  You must use the Admin token to write to the Program Files directory so in some cases your program will silently fail and create no logs.  I've also been looking for a way to elevate a single action from .NET: an application that can run without elevation but has a button with the cute shield icon that invokes an action that requests elevation from the user.  At any rate, I just switched to Enterprise Library from log4net and had to get it to produce log files in a User location rather than \program files\myprogdir and the configuration (though the tools are nice) do not support this.  Luckily Enterprise Library 3.1 comes with the source so I dug around and found what to do.  To save you the trouble.

I'm using RollingFlatFileTraceListener.  This class only has one constructor:

public class UserScopeRollingFileListener : Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener
{
public UserScopeRollingFileListener(string fileName, string header, string footer, ILogFormatter formatter, int rollSizeKB, string timeStampPattern, RollFileExistsBehavior rollFileExistsBehavior, RollInterval rollInterval)
: base(GetUserScopedFilePath(fileName), header, footer, formatter, rollSizeKB, timeStampPattern, rollFileExistsBehavior, rollInterval)
{
}

protected static string GetUserScopedFilePath(string logFileName)
{
string path = logFileName;
if (Environment.OSVersion.Version.Major > 5)
{
string homeDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
path = System.IO.Path.Combine(homeDir, logFileName);
}

return path;
}
}

So, in the constructor call the GetUserScopedFilePath().  If the OS is Vista, it takes the log file name from the app.config file and maps it into My Documents.  It could just as easily be Local Application Data or something else.  The Logging configuration uses a "Data" class associated with each listener to build to the listener class.  This seems odd since this Data class explicitly invokes the constructor of the Listener even though the configuration requires the Type of the listener to be present in the app.config.


/// <summary>
/// Represents the configuration data for a <see cref="RollingFlatFileTraceListenerData"/>.
/// </summary>    
[Assembler(typeof(UserScopedRollingTraceListenerAssembler))]
public class UserScopedRollingTraceListenerData : Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData
{
public UserScopedRollingTraceListenerData()
{
}
}

/// <summary>
/// This type supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
/// Represents the process to build a <see cref="RollingFlatFileTraceListener"/> described by a <see cref="RollingFlatFileTraceListenerData"/> configuration object.
/// </summary>
/// <remarks>This type is linked to the <see cref="RollingFlatFileTraceListenerData"/> type and it is used by the Custom Factory
/// to build the specific <see cref="TraceListener"/> object represented by the configuration object.
/// </remarks>
public class UserScopedRollingTraceListenerAssembler : RollingTraceListenerAssembler
{
public UserScopedRollingTraceListenerAssembler()
{
}

/// <summary>
/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
/// Builds a <see cref="FlatFileTraceListener"/> based on an instance of <see cref="FlatFileTraceListenerData"/>.
/// </summary>
/// <seealso cref="TraceListenerCustomFactory"/>
/// <param name="context">The <see cref="IBuilderContext"/> that represents the current building process.</param>
/// <param name="objectConfiguration">The configuration object that describes the object to build. Must be an instance of <see cref="FlatFileTraceListenerData"/>.</param>
/// <param name="configurationSource">The source for configuration objects.</param>
/// <param name="reflectionCache">The cache to use retrieving reflection information.</param>
/// <returns>A fully initialized instance of <see cref="FlatFileTraceListener"/>.</returns>
public override TraceListener Assemble(IBuilderContext context, TraceListenerData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
{
UserScopedRollingTraceListenerData castObjectConfiguration
= (UserScopedRollingTraceListenerData)objectConfiguration;

ILogFormatter formatter = GetFormatter(context, castObjectConfiguration.Formatter, configurationSource, reflectionCache);

UserScopeRollingFileListener createdObject
= new UserScopeRollingFileListener(
castObjectConfiguration.FileName,
castObjectConfiguration.Header,
castObjectConfiguration.Footer,
formatter,
castObjectConfiguration.RollSizeKB,
castObjectConfiguration.TimeStampPattern,
castObjectConfiguration.RollFileExistsBehavior,
castObjectConfiguration.RollInterval
);

return createdObject;
}
}

Now, if you used the Enterprise Library configuration tool to create the RollingFlatFileListener configuration, you need to make two changes:

<listeners>

<add fileName="MyLogFileName.log" rollSizeKB="0" timeStampPattern="yyyy-MM-dd"

rollFileExistsBehavior="Overwrite" rollInterval="None" formatter="Text Formatter"

header="" footer=""

listenerDataType="MyNS.MyNS.UserScopedRollingTraceListenerData, MyAssembly.Name"

traceOutputOptions="None"

type="MyNS.MyNS.UserScopeRollingFileListener, MyAssembly.Name"

name="Rolling Flat File Trace Listener" />

</listeners>

One other thing I wanted to change about the logging, is that I like the log4net syntax for different log levels.  You would get an ILog implementation and call log.Debug(message) or log.Error(message) or log.Fatal(message).  With the joy of Extension Methods you can create your own on-the-fly facade with the compiler doing most of the work:

    public static class LogExtensions

    {

        static void Debug(this LogWriter l, string message)

        {

            LogEntry entry = new LogEntry();

            entry.Message = message;

            entry.Severity = System.Diagnostics.TraceEventType.Verbose;

            l.Write(entry);

        }

 

        static void Error(this LogWriter l, string message)

        {

            LogEntry entry = new LogEntry();

            entry.Message = message;

            entry.Severity = System.Diagnostics.TraceEventType.Error;

            l.Write(entry);

        }

    }

So extension methods now allow me to say Logger.Writer.Error("An error has occurred: value was null").  I am now happy with the Logging application block.



Thursday, November 01, 2007 8:36:15 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Wednesday, October 03, 2007

I need to hire some people into my department at CarSpot.com, I cannot share very many details right now but I'm hoping to get clearance to make some kind of announcement before Q1 2008.  I am looking for the following full time positions:

  • An entry level person, hiring from now to December.  UW-Whitewater, UW-Madison, MSOE, UW-Milwaukee December grads with .Net classroom experience are encouraged to apply.  This is a good chance to start your career doing real work.  May 2008 graduates, save my address.
  • An Electrical Engineer:  I can't share solid requirements on this position yet but will open dialogue with interested parties.
  • A very solid mobile/compact framework person, or an extremely solid .NET developer who can demonstrate ability to very quickly become a mobile superstar.  This position is unique in that it offers a combination of maintenance of current products, creation of new products, and will involve some open-ended R&D.
  • An all-around .NET person.  Windows Forms, Web Forms, Web Services, SQL skills, knowledge of UML, design patterns, likes NUnit and NCover, possibly interested in doing high level design.

It would be fantastic if one of these people had strong Win32/COM/C++ skills.  I will also consider local consultants for some specific work.

As I mentioned before,  I can't make any public announcement right now, but I can share the details in person with serious candidates.  I don't think I can over-state how f()*&*!ng cool CarSpot is right now.  We are taking over a very large space in our current building above the Milwaukee Ale House with a pool table and other niceties.  We've got .NET/Windows people, Linux people, MAC people, and there are some very cool things happening right now which should be obvious if I'm considering bringing four people on board.  There aren't many places in Milwaukee where beer-infested programmer meetings are expensable, you can get a wireless data card and work in the park, and the department head (moi) will feed you ribs and sweet corn during the summer.  Flexibility is critical here, once trust is established and it's shown that you get your work done, you are given a long leash.  I work from home sometimes, I work from the bar downstairs sometimes, some people work from the park, etc. 

We will be working with recruiters very soon, but for now forward resumes to damon.payne@carspot.com .



Wednesday, October 03, 2007 9:08:05 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, September 25, 2007

In other news, installing .NET 3.5 beta 2 seems to have robbed Live Messenger of it's ability to display smiley faces and such.  How bizzar.



Tuesday, September 25, 2007 12:49:15 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

ClickOnce is so close to greatness, as I’ve said before.  Yes, I know the “official word” is that this is not really meant for software ISVs deploying software to end users but it seems with a few extra things it could indeed be very good for this.  With some features in the Orcas Beta 2, I think ClickOnce is getting much closer to providing the plumbing I’ve been wanting in some cases and home rolling in others.  A new product I’m working on has some Architectural Desires.  I call them “desires” because we’ve been selling desktop applications without these architectural features for a while but I really want to meet some Service Level Requirements that will make my life easier, the customer’s life easier, and our support staff’s life easier.

Environment

·         I have an existing web system that users sign into.  Credentials are stored in an app-specific schema in a MySQL database.  Users of the current desktop application must be in this MySQL database and authenticate over web services.  Users of the new system increasingly do not need access to the web based system.  Putting their credentials in MySQL is polluting this system.

·         We have an OpenLDAP server we are slowing moving credential stores to.

·         We have a Windows2003 server that’s not doing much right now

·         We have a client application that ships with specialized hardware and an install disk.

·         Upgrades go out to customers via installing a new MSI

Requirements/Desires

1.       My software requires some specialized hardware.  I’d like to ship this without install disks.

2.       I’d like the desktop application to be able to have the Role information and authenticate against our existing credential stores.  I don’t want users to be able to run this within a very short time period if we turn them off.

3.       I’d like to stop polluting the existing web system credential store with users that should not ever be able to log into this system, however SOME users of the web based system will also need to be able to authenticate using the client application.

4.       I’d like to be able to keep random people from stealing software.

5.       I’d like to be able to keep random people from installing my software.

 

Solution in Code and UML

Let’s take the big red pill and see where it leads us.

ClickOnce - Part 1

I start with .NET 3.5 Beta 2, VS 2008 Beta 2, and my current environment.  Setting up ClickOnce deployment is easy enough, I set the application to check for updates before it runs, and verify that this works.  Oddly enough with Beta 2, 100% of my testers who have tried to click “Install” rather than installing .NET 3.5 and choosing “launch” have had the install .exe lock up.  Hopefully this gets fixed.

Client Application Services – Server Side

There is a wonderful bit of plumbing available now Called Client Application Services.  In order to use this you need an ASP.Net web site.  You need to add a reference to System.Web.Extensions, and configure your web.config such that the Role and Membership services are enabled.  With .NET 3.5 this is done like so:

      <system.web.extensions>

            <scripting>

                  <webServices>

                        <authenticationService enabled="true" requireSSL="false"/>                   

                        <roleService enabled="true"/>

Now, the Role and Membership providers I have configured are my LDAP based home rolled code.  Discussing these is outside the scope of this article; suffice to say they are straight up Provider implementations.  I will need to set up my Forms authentication a certain way to meet my single sign on goals:

            <authentication mode="Forms">

                  <forms domain=".office.carspot"

                           enableCrossAppRedirects="true"

                           cookieless="UseCookies"

                           slidingExpiration="false"

                           defaultUrl="Cookies.aspx"

                           path="/"

                           protection="Encryption"

                           timeout="1440"

                           name="FooBar"/>

            </authentication>

For testing I am allowing the clients to sign on once for a day.  The domain attribute is important, as the cookie created by my web site will now be passed to anysite.office.carspot.  There is one more thing to configure here.  At this point I intended that I would manually provide the Symmetric Key to Trusted Applications written in PERL or Python etc. to decrypt the data in the cookie.  I therefore manually created some keys for a MachineKey element.  This will still be needed when I cluster this solution.

      <system.web>

            <machineKey validationKey="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"

            decryptionKey="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"

            validation="SHA1" decryption="AES" />

Client Application Services – Client Side

With the server side set up, I return to my ClickOnce application.  There will be some work to do in the Properties of my app and some work to do in code.  The first step is to enable Client Application Services.

Only the root directory of the ASP.Net application is required.  This also requires references to System.Web and System.Web.Extensions in my Client application.  This is the first hole I’ve seen thus far in my argument that a Client-only .NET install should be available.  The advanced tab bears some discussion now and also a little later:

In my case I want to make sure they are authenticating to the server at regular intervals.  The Use custom connection string setting is the key to a later problem.  Interested readers may want to use reflector on System.Web.ClientServices.Providers.ClientData,  System.Web.ClientServices.Providers.ClientDataManager, and System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, as well as exploring the new System.IO.IsolatedStorage namespace, unless using Reflector on system assemblies is against some rule, in which case you should not and I never have done so.

Now I need to write some code and see if I can log in.  Note that back in the Services tab I included a Class and Assembly name for a credential provider type.  This tells the plumbing what method to invoke in order to request credentials from the users.  The class must implement IClientFormsAuthenticationCredentialsProvider, in my case this is a login window written in WPF.  Insofar as my research has gone so far, authenticating members and checking roles must be done explicitly.  The code to do so is simple:

bool valid = System.Web.Security.Membership.ValidateUser("", "");

This will cause the plumbing to invoke my Login window and give me an answer as to whether authentication was successful, and since Role management is enabled I should be able to get at my roles as well.  Now I’m going to set up a proxy and try to log in.  Here’s what Fiddler shows me:

 

You can see the AJAX/JSON requests going back and forth, and I’m showing the headers of the response in order to show you the persistant cookie.  The actual body of the response is just {“d”, true}.  Now I’m going to try to get this to authenticate against a Web service written in another language on a different server.

This Cookie is not for you

My thought was to use cookies with a common Domain in order to authenticate against my ASP.NET site via Client Services but have the information available in a usable form to other non-.NET systems.  This turned out to be a pipe dream at first.

·         Authenticating via Login.aspx returns a cookie as expected.  Cookies are turned off for HttpWebRequest by default.  Nothing I could find would get Windows/.NET to nicely populate cookies on my HttpWebRequest once I gave it a CookieContainer.  This is probably desired behavior.

·         Authenticating via Client Services does not create a cookie in the same way IE does anyway (more on this in a moment).

·         Any IE specific hacks I do are likely to be broken in Firefox, and supposedly ClickOnce will work with Firefox later this year.

I started by experimenting with the Use Custom Connection String setting, but realized this may be problematic in ClickOnce since the actual Application directory is not a clean or dependable Path.  When facing a dilemma like this I pull out my handy File System Watcher program and go to work. 

While logging in, this “User_damonpayne.clientdata” file created and changed looks promising, and it turns out to be.  I can already tell by calling Thread.CurrentPrincipal.Identity.Name that my server-side user name “damonpayne”, is indeed available on the Client.  Opening up this .clientdata file reveals the following:

<?xml version="1.0" encoding="utf-8"?>

<ClientData>

      <LastLoggedInUserName></LastLoggedInUserName>

      <LastLoggedInDateUtc>1C6E0B92F1DBE7E</LastLoggedInDateUtc>

      <PasswordHash></PasswordHash>

      <PasswordSalt></PasswordSalt>

      <Roles>

            <item>Default</item>

            <item>Technology</item>

            <item>ScrumMaster</item>

      </Roles>

      <RolesCachedDateUtc>1C7FF8AA84CDD3E</RolesCachedDateUtc>

      <SettingsNames></SettingsNames>

      <SettingsStoredAs></SettingsStoredAs>

      <SettingsValues></SettingsValues>

      <SettingsNeedReset>0</SettingsNeedReset>

      <SettingsCacheIsMoreFresh>0</SettingsCacheIsMoreFresh>

      <CookieNames>

            <item>09a630885b744552b25cf95da4f7e20f</item>

      </CookieNames>

      <CookieValues>

      <item>SoloAuth=9816CAC289A2ADBE7E88A0498E71733E0C480CAD631CB57460BF8AB9822747A43FE1ABE6F0D20DCAA95D8339FE8EC866C878A10A1A2BB188AE42B50DCB4C9862</item>

      </CookieValues>

</ClientData>

Those are indeed my roles, and that does look like my server cookie value.  How convenient.  Of course from the Client I can simply call System.Web.Security.Roles.GetRolesForUser() to get my roles, but remember that I sought to pass a token to someone else that would vouch for who I am.  I will now spare you some of the details of my research and skip to the punch line.  By converting my Hex string from <machinekey/> back to a byte array I was hoping to privately share this Symmetric Algorithm key with trusted systems and allow them to decrypt the cookie value.  Well, this didn’t work, and switching algorithms from AES to 3DES didn’t work, and changing the key sizes didn’t work.  Digging through FormsAuthentication through reflector I found the 1st issue: the data is not plain text but rather a binary serialized object.  Ok, so one could use BitConverter to pull out the desired values.  The real sticking point is that FormsAuthentication, when it creates a Symmetric Algorithm of the type specified by your <machineKey/> setting, creates a random Initialization Vector that is not available to you.  How this voodoo works in a clustered environment I don’t know, but this behavior is somewhat disappointing.   Community Server, for example, allows you to put the IV in the web.config as well since this is a very necessary part of the cryptographic process.  My hopes of sharing a symmetric key with a trusted application were killed, and I spent quite a bit of time on Google and USENET looking for a solution.  This was one of those situations where the obvious answer eluded me for a while because I had been too close to this problem for too many hours. 

I can still write code to dig out the cookie value:

        /// <summary>

        /// Assuming local storage, get the client data cookie for this application

        /// </summary>

        /// <returns></returns>

        public static string GetClientDataCookie()

        {

            string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

            string ver = Assembly.GetCallingAssembly().GetName().Version.ToString();

            appData = Path.Combine(appData, @"CarSpot\CarSpot.Solo\" + ver);

 

            string userName = Thread.CurrentPrincipal.Identity.Name;

 

            string userFile = "User_" + userName + ".clientdata";

            string path = Path.Combine(appData, userFile);

            XmlDocument doc = new XmlDocument();

            doc.Load(path);

            string token = doc["ClientData"]["CookieValues"]["item"].InnerText;

            token = token.Substring(token.IndexOf("=") + 1);

            return token;

        }

… and I still have a public facing Web server that magically (in memory?) has access to the Initialization Vector:

        [WebMethod(Description="Attempt to decrypt a Forms auth ticket issued from this server farm")]

        [SoapDocumentMethod(ParameterStyle=SoapParameterStyle.Bare)]

        public ValidateClientTicketResponse ValidateClientTicket(string ticketString)

        {

            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(ticketString);

            ValidateClientTicketResponse response = new ValidateClientTicketResponse();

            response.Expiration = ticket.Expiration;

            response.Name = ticket.Name;

            response.UserData = ticket.UserData;

            return response;

        }

… and of course, for trusted systems, I can secure this Endpoint however I please.  I can pass my Ticket from the client to anyone, who can call this service to determine if I am who I say I am and if this is a valid, unexpired ticket.

 

Solution Diagram

So, this is my environment with the solution in place.  Users who only need my Client Application and its accompanying Web Application are created in LDAP.  Users of the special Perl web site that also need to have access to my client are pushed to LDAP via a replication scheme.    My client application can pass it’s authentication ticket value as a SOAP header or an in-band argument when communicating with other trusted endpoints. 

Since I worked through this step by step, there may be a slightly cleaner way to do some of this.  I have been meaning to see if WS-Federation could be used, if only as a more standard API for the web service.

Final Thoughts

Of my original requirements, I have met most of them.  I can keep random people from stealing my code by deploying Obfuscated assemblies via ClickOnce.  I can keep people from running my application using the authentication, and with this method many customers will only have a single password to remember for all their CarSpot products.  I did not write about it here but the ASP.Net Profile information is available via this method as well.  This opens up the door for many unexpected niceness for our users; by implementing a new custom Profile provider, someone might log into one of the Perl web sites and change their display preferences, to discover them magically reflected in their client application as well. 

As for keeping random people from ever even installing my software to begin with, that will have to come later or Obfuscation will have to do.  It would be ideal to protect the .application file for my program so that unwanted visitors cannot even download the manifest in the first place.  Are you listening, Microsoft?  ClickOnce should be able to respond to an authorization challenge or SSL certificate warning in some fashion.   In our tests, Firefox still does not work for launching a ClickOnce application. Are you listening Microsoft?



Tuesday, September 25, 2007 11:57:32 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Thursday, September 20, 2007

My time continues to be eaten up by something I cannot discuss yet.  I am seeking permission to make an announcement...

I'm running VS2008 Beta 2 in a non VM environment now.  So far there's only been one crash and the performance is acceptable though not as fast as VS2005 runs for me right now.  I am working on a WPF application right now and I have to say so far I greatly prefer the designer from the August CTP of Expression Blend 2 to the WPF designer in VS2008.

.NET | WPF


Thursday, September 20, 2007 9:35:50 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, September 05, 2007

Suppose you are developing an ASP.Net application in a primarily open source/linux/MySQL environment, you might run into some odd issues with interoperability.  A top-secret project of mine (that I intend to open source once I've got a handle on which license is appropriate) needs minimally to work with MySQL and OpenLDAP.  MySQL is no problem as the builds of the MySQL connector for ADO.NET 2 have been very solid, though it does give me odd "warnings" about unnecessary conversions when using reader.GetInt32(0) and such. 

OpenLDAP, well, it seems decent enough for our purposes but there are some stumbling blocks.  The ActiveDirectory Membership and Role providers that come with .NET 2.0 will not work for you.  Oh, I know the connection string misleadingly takes LDAP://ou=blah blah;cn=blahblah;dnblahblah syntax but the implementation uses various AD specific calls so you have to home roll your own.  There are two decent solutions here: you can use the classes in System.DirectoryServices to implement the various searches.  I was concerned at first that this would not work under Mono, which is one thing I'm shooting for, but I should have done my homework as the Mono project does have a System.DirectoryServices implementation.  I also found some old Novell C# code hanging around that gives you some LDAP specific abstractions.  Either way, you can roll your own Role and Membership providers that talk to OpenLDAP.  OpenLDAP does not support the memberOf syntax, apparently, which is annoying.  You can search under the ou=Groups for objects of type posixGroup and get the memberUid attribute to sort of go at it backwards to implement the GetUsersForRole functionality for your Role provider:

public List<string> GetUsersForRoleName(string roleName)

{

List<string> userNames = new List<string>();

string searchPattern = "(&(objectclass=posixGroup)(cn={0}))";

string searchStr = string.Format(searchPattern, roleName);

LdapSearchResults sr = _ldapCon.Search("ou=Groups," + _rootDn, LdapConnection.SCOPE_SUB, searchStr, null, false);

while (sr.hasMore())

{

LdapEntry entry = sr.next();

LdapAttribute att = entry.getAttribute("memberUid");

string[] names = att.StringValueArray;

for (int i = 0; i < names.Length; ++i)

{

userNames.Add(names[i]);

}

}

return userNames;

}

 

I should surely post this project once it's mostly done, as it's potentially quite useful.



Wednesday, September 05, 2007 2:36:18 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, July 03, 2007

There are various talks online about ClickOnce improvements in Orcas.  I installed a Vista Virtual PC and Orcas Beta 1, which took a rather long amount of time since I had work to do on this PC while VPC was fighting for resources.  Details were scarce but I had hoped the gaping hole of no authentication mechanisms being supported by ClickOnce would be in some way addressed out of the box with Orcas and .NET 3.5.  No Joy, at least not without a little bit of work and digging.  There are references to the ability to customize the User Interface you see while downloading the application files, ostensibly for branding but I have some hope that this may also allow one to provide a user interface to responde to an authentication challenge.  If not, I'll begin brainstorming some kind of frankenstein solution that may end up being no easier than home rolling the whole shebang.



Tuesday, July 03, 2007 2:54:10 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, July 02, 2007
MVP

My day was off to a late start today as my wife and I were both standing up in a wedding last night.  Nonetheless, when I finally waded through my email I was pleased to see that I have officially been awarded the 2007 Microsoft MVP award in the category "Visual Developer - Solutions Architect."  Thanks go out to my nominator (you know who you are) and I hope to keep living up to this title over the next year.



Monday, July 02, 2007 10:28:04 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, June 29, 2007

My company is growing to the point where customers are asking for features that may be useful to other customers and we'd generally like to be able to easily push out new versions of desktop software.  The immediate choices seem to be the Application Updater block, ClickOnce, and home-rolling a solution.  Since the App Updater block seems to want me to write code to determine when updates happen and such, and I'd like to avoid reinventing the wheel with a complete home grown solution, ClickOnce seems like a very good possibility.  I can publish to FTP from Visual Studio, I don't have to write extra code, I can specify Full Trust, force minimum versions, firewall friendly, etc.  Yes, its got a lot going for it. 

My first concern was that as a mixed-technology shop, we might not be able to use ClickOnce.  Our production environment is predominantly Linux and BSD based and it doesn't seem out of the realm of possibility that there might be some IIS specific functionality needed for ClickOnce to work.  Luckily this is not the case, and I have an important Internal tool running with ClickOnce deployment now.  To be safe I added .application and such as mime types in the Apache config but it seems only some people actually require this step.  For this initial deployment I found only two irksome issues:

1) IE only.  Some of the people here have Firefox set up as their default browser for some reason.  Clicking on the link to the Publish.htm in their email launches Firefox which happily displays the raw Application Manifest.  Cruising around MSDN I can see that this is addressed in .NET 3.0 or 3.5, which one is not clear.  It would also seem likely that there is a way to register an external program-handler for .application in FireFox, but if I wanted users to have to do work I'd keep on giving them MSI files.  This internal tool is also the Pilot for using ClickOnce for end-user deployments, and obviously those people would prefer things to be as easy as possible.  To some degree I can cordially invite internal users to go pound sand if they think the setup is too hard but any problem my customers have, no matter how silly or made up, becomes a real problem for me.

2) Security.  My apache skills are rusty.  Still, I was able to setup basic auth with .htaccess files in my ClickOnce directory with only minimally bothering our sysadmin.  See, I have this odd notion that if I'm going to put a public URL out there that any person could stumble on to or share with their friends, I'd like some form of authentication so I can at least tell who is sharing his password with 50 of his closest friends.  Let me be explicit in that I am not looking for some type of hack-proof system, I just want the ritual of authentication and authorization to be observed here.  Basic auth blows up when you try to Launch the ClickOnce app, and this is expected behavior.  Supposedly NTLM is the solution: protect the resource with NTLM challenge/response, tell it to "remember me", and you're on your way.  Well, not really.  The sysadmin, no longer so lucky as to be only minimally burdened by my experiment, was shanghaid to track down an NTLM compatible add on for apache and cook up some form of domain to authenticate it against.  We found mod_ntlm, we configured mod_ntlm against a Samba domain, we protected the test directory with mod_ntlm.  As soon as I enter the domain credentials and check "Remember this password" I hit launch, to be met with the same kaboom as Basic Auth.  Larry Clarkin reminded me that in the Internet Zone remember me won't work.  Adding to trusted sites does not help either, at least not in my experimenting.  ClickOnce has no mechanism for asking you for credentials, nor can it ask you to confirm continuing on to a site with a self-signed SSL cert, as you are sure to find ina  test environment.

It seems likely that I might be able to tweak IE settings to a custom level for trusted sites, but if my users could infalliably do that task I wouldn't need ClickOnce.  With so many excellent designs within .NET, it seems very odd indeed that there is no Provider Model for authentication, no Event we can respond to in order to handle self-signed test certificates.  I'm trying Orcas Beta 1 this weekend, but I'm not overly optimistic.



Friday, June 29, 2007 1:43:28 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, May 27, 2007

A respectable fellow recently asked me where I was on the Unit Testing spectrum: Skeptic <----> Zealot, or in between.  Fair question.

I am right-leaning towards zealot though far from what I'd call a unit testing zealot.  For one thing, I'm not into Test-first development.  I've heard the arguments enough times but its not a mental barrier I care to break down.  After years of struggling with laziness and mulling over the value of different approaches, this is a summary of my Unit Testing habits today:

  1. I use NUnit, TestDriven.Net, and NCover.
  2. I don't like unit testing strictly GUI aspects: Web Forms or Windows Forms, UserControl, etc.  I know that there ARE ways to do this but it doesn't resonate with me right now.  I somewhat dogmaticaly use Model-View-Presenter in ASP.Net and the desktop to minimize what is in the code behinds anyway.  I use NUnit.Mocks to work with Mock instances of my View interfaces.
  3. I do a lot of up front design before I write anything non-trivial but I do not create models at the Implementation level.  Writing the code is the first validation of my design, writing the unit tests is the second validation of my design.  Sorry for bludgeoning the deceased equine but if I can't get at method to test it and it also doesn't make sense to test said method through some other calling method, then there's likely a smell in the design.  I will typically revisit my preferred tool (currently StarUML) to see where the smell is, reimpliment, and take another stab at creating the appropriate tests.
  4. Unit tests are the most appropriate artifact you can leave behind for a project.  It seems to me that I run across very few people who do what I would call Real modeling and fewer who make an effort to update models as a system evolves.  I don't update models as a system evolves, but I do update unit tests.  The tests are only valuable as an artifact if they pass and if they can be shown to actually exercise the system.  See #5 regarding this.
  5. Code Coverage is the piece that finally made Unit Testing really click for me.  Forming the habit of using NCover directly from Visual Studio via TestDriven is the single largest improvement to the quality of my code, ever.  I find that I have difficulty inciting the same excitement about Coverage in other people, maybe because it forces one to admit they need to write more unit tests.  So you've tested everything you thought of on the first iteration and NCover shows only 80% coverage of your business logic assembly.  Sometimes you'll see you only tested the "Main success" flow through the code and you need to test the alternates and exceptions.  Sometimes you will see NCover highlighting code that is absolutely never going to be called from your application.  Many times I have caught "premature abstracting" using Ncover, classes or methods I assumed I'd need but nevered ended up needing.  This may not be a defect but I'm of the opinion that if I ever need it I'll recover it from version control so I delete unused methods/properties/classes to make my assembly smaller and compile faster.  Code Coverage is also a good aspect of a Code Review, if you're into those.
  6. I shoot for > 95% code coverage.
  7. While we work on stabalizing a release, testers sometimes find bugs!   As I look at each bug, I think, could this have been caught before acceptance testing if there'd been a specific unit test?  If I can think of a unit test for the bug situation, I add one.
  8. This one should be very obvious: I feel much better making huge changes to important code if there is a unit test suite.

 



Sunday, May 27, 2007 10:04:05 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Wednesday, May 23, 2007

I have seen several tutorials online on creating non-rectilinear windows in WPF using transparent images and no Background Brush.  Oddly enough this leaves you with the issue of not being able to grab the title bar (since it does not exist) and drag your curvey new window around.  I initially found no workable solution for this and even asked around to those who are wiser than I; no answer.  By rephrasing my request to google I found the following:

  1. Using Expression Blend, highlight your Window class.  Add an event handler for MouseLeftButtonDown
  2. In Visual Studio, add the following code to said event handler:

private void ExifViewer_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
   DragMove();
}

Fantastic.  The plumbing was already there, easy, and obvious, but because this is a new platform I could not find it.

.NET | WPF


Wednesday, May 23, 2007 3:00:30 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, May 18, 2007

If you haven't looked at WPF and Expression Blend yet it's important that you do so immediately.  The fact that I can do those cool effects from managed code is fantastic.  For example, I had a tool written for our support teams that would allow them to right-click on a JPG in Windows and choose "View Exif" from the menu.  We have customers (if you're a customer and you're reading this, I don't mean you, I mean someone else) who call us saying that their images didn't get associated with a vehicle and this way they can see the image metadata and if the scanner was used right.  I thought it would be cool if this could be in the shape of my company logo instead of a rectangular window, with some partial transparency.  Ignore my pan roasted broccoli with ginger and chilli sauce partially visible through the form.

My first few hours of experimentation with Expression Blend and WPF are very promising.  Besides creating this non-rectilinear window you can scale and rotate about anything and give the appearance of things being detached from your main window.  Behold my incredibly confusing rotated ListBox and detached close button.  The rotated ListBox shows the danger in this tool: remember things like the <blink> and <marquee> tags?  Bad ideas that looked cool for about five seconds and later made the bad-design hall of fame will be oh-so-easy for developers to unleash on unsuspecting users now.  Mitigating that risk is the fact that it appears seperation of the Designer's World from the Programmer's World is cleaner and more appropriate than many past attempts at supporting this separation of labor.  This aspect is most exciting to me: I would love to be able to tell our marketing partner who does our graphics to just go crazy with the user interface and email me the XAML so that I can work on putting functionality behind a top-notch design and not worry too much about us unintentionally trampling each other's work.  This is very, very cool.

.NET | Rant | WPF


Friday, May 18, 2007 3:03:42 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I registered DamonPayne.net and pointed it to this site, in case you'd rather think of .net when you go to read about .net, or home theater, or politics, or see pictures of food, or something.

 

.NET | Rant


Friday, May 18, 2007 8:52:14 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, May 03, 2007

Some of those thoughts I didn’t get to last night.

First of all I should say that the threading in .NET rocks in my opinion.  It’s fast, easy to program for, and very complete for a managed platform.   The inclusion of intra-process mutexen is especially nice.  So, here’s some code for utilizing some of the functionality I showed designs for yesterday.

            PrimeSieveContext ctx = new PrimeSieveContext(1000000);

 

            WorkDispatcher<long, PrimeSieveContext> facade = new WorkDispatcher<long, PrimeSieveContext>(3,ctx);

            PrimeAdderWorkUnit wu0 = new PrimeAdderWorkUnit(1, 500000);

            PrimeAdderWorkUnit wu1 = new PrimeAdderWorkUnit(500001, 750000);

            PrimeAdderWorkUnit wu2 = new PrimeAdderWorkUnit(750001, 1000000);

            facade.AddWorker(wu0);

            facade.AddWorker(wu1);

            facade.AddWorker(wu2);

<snip/>

long result = facade.Execute();

So when I said there’s a lot of room for improvement, the first item I’d like to look into is setting it up so that the WorkDispatcher decides for itself how many work units to split the problem domain into.  That is somewhat at odds with the first improvement I made.  Here’s a bit of the WorkDispatcher Execute method:

            if (_maxThreads > 1)

            {

                //Start beyond the 1st one, spawn threads, wait until they are all done

                for (int i = 1; i < _maxThreads; ++i)

                {

                    ThreadPool.QueueUserWorkItem(new WaitCallback(_workers[i].ExecuteAsync), _ctx);

                }

                TResultType rslt = _workers[0].Execute(_ctx);

 

                WorkerSharedContext<TResultType> finalCtx = _ctx as WorkerSharedContext<TResultType>;

                for (int i = 1; i < _maxThreads; ++i)

                {

                    _workers[i].CompleteHandle.WaitOne();                   

                    finalCtx.AddResultComponent(_workers[i].Result);

                }

                return finalCtx.GetContextualResult();

            }

First of all, I love the Generics in .NET 2 but several times I’ve ran across a situation where I wish one of the Template types could also be specified as implementing an interface or extending a base class.  I suppose I need to refactor the design here.   At any rate I noticed depending on which chunk of work I placed in the _workers[0] spot that I could keep both my CPUs maxed for longer and finish the work a few seconds sooner.    Ideally I should just give the WorkDispatcher hints about this rather than ordering the chunks myself, so I added the following:

        /// <summary>

        /// May cause the WorkDispatcher to re-order upon Setting this value.  The default value is FIFO

        /// </summary>

        public WorkDispatcherScheduleTypes ScheduleType

        {

            get { return _scheduleType; }

            set

            {

                _scheduleType = value;

                if (_scheduleType.Equals(WorkDispatcherScheduleTypes.OrderSensitive))

                {

                    _workers.Sort(new WorkUnitOrderComparison<TResultType, TSharedContext>());  

                }

                else if (_scheduleType.Equals(WorkDispatcherScheduleTypes.WeightSensitive))

                {

                    _workers.Sort(new WorkUnitWeightComparison<TResultType, TSharedContext>());

                    _workers.Reverse();

                }

The WorkUnits  now have assignable Weight and Order properties, no rocket science here.  Looking at the threading code in the previous figure we see where I am not yet meeting my stated goal of keeping the CPUs maxed as much as possible to complete the work using all the power available.  In this example with 3 WorkUnits and two physical processors the ideal would be to run two in parallel with the 3rd one being assigned to a physical processor as soon as one becomes available.   I read recently that this technique is being used with success in optimizing games for the PS3.  Neither ThreadPool.QueueUserWorkItem nor the framework I have here so far support any sort of event for saying “I’m done” so the WorkDispatcher can put the next WorkUnit on a physical CPU so I’ve got some more code to write.

Lastly, the PrimeAdderWorkUnit class is currently responsible for properly locking the pieces of the SharedContext it might be working with at any time.  It would be nice to create a mechanism for doing this automatically if such a means can be found in .NET.  It would be oh so nice to be able to overload the “.” or “->” operator.   I’ll revisit this when I can.

 



Thursday, May 03, 2007 9:42:39 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, May 02, 2007

Thanks to Mr. Heidenreich I lost most of my free time this afternoon.

I had posted about the programming problems on Project Euler and Mr. Gerry Heidenreich got addicted right away and we had been talking back and forth about some of our solutions.  He pings me to tell me that he is having dreams (nightmares?) about Problem 10 in the set.  It was taking too long to run, way too long since the problems should complete in less than one minute.  We both have almost the same computer oddly enough, a 2.13ghz Core 2 Duo.  If you’re too lazy to follow the link, the problem is to add the prime numbers that are less than 1 million.

I started with his algorithm and got the run time down to about 80 seconds with some plain code optimizations and expanding upon the Sieve he was using for eliminating factors of primes.  To be fair this took a while.  To be even more fair, there are probably Math-only optimizations that would eliminate the need for what you are about to see, but there is a larger lesson here.

I’ve been saying to anyone who’ll listen that chip-makers have been letting us down for about 3 years.  We can no longer expect significantly faster and faster sequential processors to speed up the more complex apps we are using and writing.  The Consolation Prize is ubiquitous multi-core chips in laptops, desktops, and servers.   I have engaged in various debates about the magnitude of the benefit of this approach, especially for Game Programming or other tasks where the solutions (at least the currently practiced and taught ones) are fundamentally sequential in nature.  I had been meaning to look into the cost of context switching, memory copying and synchronization primitives for problems that don’t immediately appear to lend themselves to SMP.  My mediocre math skills gave me a test problem. 

My first attempt was lightning fast but gave the wrong results due to an obvious synchronization issue.  I decided to give this problem at least a fraction of the thought it deserves and came up with some initial goals.  I wanted to make a class that can encapsulate a chunk of the work.  Some sort of controller class should organize the chunks of work, and be able to handle work broken up into arbitrary #s of slices.  The controller should be able to make sure all work is done before calculating the final solution.  To solve my obviously sloppy threading issues, tasks running concurrently should be able to safely share some sort of read/write context that may be necessary to manage dependencies between chunks of work or at least the final results.

To skip to the punchline, the multithreaded method using the pattern I came up with is almost twice as fast as the single threaded method, gets the correct result, and has given me food for thought on future problems requiring significant computing.  Almost twice as fast on 2 procs as on 1 is about as good as you can get so at least I got that part right.

Now, to rewind to the solution. The first thing that jogged my memory was watching the single-threaded method run.

CPU usage would not peg the CPU even when setting the process to Highest priority and turning off everything else that was running.  I know very little about the details of the Core 2 Duo but unlike hyperthreading its two real processors, so somehow either Windows, the BIOS, or Intel are spreading the load across two processors while half of my overall horsepower goes wasted.

Here is a model of the first iteration of my work-splitting solution:

 

WorkUnit made the most sense for the Command class name, not to be confused with other Unit-Of-Work patterns.

Obviously one goal is to make something I can keep refining as I come across new problems and have a .NET pattern/framework for speeding up execution of large tasks in the future.  The problem I’m solving here is probably one of the simplest examples of concurrent tasks with data interdependencies both constantly during execution was well as result assembly when all WorkUnits are done.  In this case the shared context is that all threads of execution will be reading and writing to an array of flags.  These flags mark numbers later on in processing as “Not possibly a prime candidate” when they are factors of already processed numbers.  The process in action looks something like this:

Now I ran with two WorkUnits, each sharing part of the range of possible prime #s and calculating their own sub-sums to be contributed to the final tally when all analysis was done.  I was happy to see a different CPU load…

… as well as obtaining the correct answer at the end and in far less time than single threaded solution.  I think there is still room for improvement, quite a bit in fact.  As soon as the one work unit is done the CPU load goes back down to 50% while the WorkUnit with the larger #s completes.

I have some other initial thoughts on this framework that I’ll get to later tonight, time permitting.



Wednesday, May 02, 2007 7:16:24 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Tuesday, May 01, 2007

Someone asked me the following today (paraphrased)

"If I have versions 1.0.0.0 and 2.2.2.2 of TestAsssebly both in the gac, and a program TestApp.exe that needs TestAssembly, can I instantiate classes from each assembly inside the same app domain.  Can I use both versions of the Foo class in my program?"

So I sat down to do a simple experiment.  Two versions of Test Assembly are created in the GAC and a console program is run.  Foo.ToString() returns the full name of the assembly that the Foo instance comes from.

Program:

using System;

using System.Collections.Generic;

using System.Text;

using System.Reflection;

using TestAssembly;

 

namespace TestApp

{

    class Program

    {

        static void Main(string[] args)

        {

            try

            {

                Console.WriteLine("Loading Foo...");

                Assembly foo1 =

                AppDomain.CurrentDomain.Load("TestAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=612615ef384d0cd0, processorArchitecture=MSIL");

 

                Foo f = new TestAssembly.Foo();

                Console.WriteLine("Typeof Foo: " + f.ToString());

 

                object f2 = foo1.CreateInstance("TestAssembly.Foo");

                Console.WriteLine("Typeof f2: " + f2.ToString());

 

                Foo f3 = (Foo)foo1.CreateInstance("TestAssembly.Foo");

                Console.WriteLine("Typeof f3: " + f3.ToString());

            }

            catch (Exception ex)

            {

                Console.WriteLine(ex);

            }

        }

    }

}

Output:

C:\Projects\StrongNameTest\TestApp\bin\Debug>TestApp.exe
Loading Foo...
Typeof Foo: TestAssembly.Foo TestAssembly, Version=2.2.2.2, Culture=neutral, Pub
licKeyToken=612615ef384d0cd0
Typeof f2: TestAssembly.Foo TestAssembly, Version=1.0.0.0, Culture=neutral, Publ
icKeyToken=612615ef384d0cd0
System.InvalidCastException: Unable to cast object of type 'TestAssembly.Foo' to
 type 'TestAssembly.Foo'.
   at TestApp.Program.Main(String[] args) in c:\Projects\StrongNameTest\TestApp\
Program.cs:line 25

The part in bold is entertaining, at least.  I have a strong suspician that if I interact with f3 as an Object only, using Reflection to Invoke properties and methods then I could in fact use all the version 1.0.0.0 Foo functionality (which is vast and important) within the same app domain.

I also hit a bit of a snag when testing this application.  I was previously unaware that Visual Studio does not let you add references to assemblies added to the GAC via gacutil on the local machine.  See: http://msdn2.microsoft.com/en-us/library/wkze6zky(VS.80).aspx

 



Tuesday, May 01, 2007 1:29:02 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Thursday, April 26, 2007

Someone turned me on to Project Euler last night and I have to admit its quite a gem.  From the site:

"Project Euler is a series of challenging mathematical/computer programming problems that will require more than just mathematical insights to solve. Although mathematics will help you arrive at elegant and efficient methods, the use of a computer and programming skills will be required to solve most problems."

Each problem should take less than a minute to solve once the solution is implemented; my newer computer gives me a much needed handicap.  This is excellent for me since Math is an area where I've not been very successful at self study.  I didn't register yet but I solved #1 and #2 as fast as I could type and then began over-engineering my solution to #3 by attempting to implement a Sieve of Atkin in C#.



Thursday, April 26, 2007 9:26:02 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, April 24, 2007

Hosting a Designer Surface in Windows Forms Part Zero

Note that my 1st article in this series begins with Zero because I am partial to c-family languages.  Yes, I'm hilarious.  My apologies to those with smaller screen sizes, but the screenshots need to be readable.

The first step we take is to create  UserControl that will contain the entire UI representation of the designer surface.  You could put all of this on a Form but in my case It'd be handy to have several of these open at once using a tab page interface.  On the UserControl I place a Panel with AutoScroll=true and a PropertyGrid.  The PropertyGrid should look familiar as its essentially what you've come to know and love from VS2005.  I also add another UserControl I’ve created called DefaultToolboxService.  This control has a Checkbox and a ListBox control on it.  So far I’ve got something like this:

 

As you can tell my initial goal is simple: I want to select an item in my ListBox and have it be automagically created when I click on my designer area. The next step will be to start tying in some of the plumbing to allow this to happen.  This is a good place to introduce the notion of Designer Services.

Designer Services

From the class library documentation:

Services are a foundation of the .NET Framework design-time architecture. Services provide design-time objects access to specific features and methods implemented by a service object that provides a service or services.  Let’s look at a few lines of code from the constructor of the TemplateDesignerControl:

        public TemplateDesignerControl()

        {

            InitializeComponent();

            _serviceContainer = new ServiceContainer();

            _serviceContainer.AddService(typeof(INameCreationService), new DefaultNameCreationService());

            _serviceContainer.AddService(typeof(IUIService), new DefaultUIService());

            _designerHost = new DefaultDesignerHost(_serviceContainer);

 

            _serviceContainer.AddService(typeof(IToolboxService), _toolboxSvc);

            _toolboxSvc.DesignPanel = _viewHostPnl;

            LoadToolboxItems();

ServiceContainer is a framework class that’s already implemented for me.  Obviously this instance is going to hold all the Services I need for my designer.  INameCreationService and IUIService we’ll come back to in the next article so for now we’ll look at DefaultToolBoxService.  DefaultToolBoxService was instantiated in InitializeComponent() because it is also a UserControl as mentioned above.  Now might be a good time to start modeling these relationships:

We’ll continue to flesh this diagram out as we move along.

Obviously the declaration for DefaultToolboxService, then, is...

public class DefaultToolBoxService : UserControl, IToolboxService

...because it is both a visual Control and an implementation of an important Service class.  In my case, these do not need to vary independently but the implementations could be separate.  If you wish, you can review (http://msdn2.microsoft.com/en-us/library/system.drawing.design.itoolboxservice(vs.80).aspx) the IToolBoxService interface before moving on.  The implementation is straightforward: Add the types of items you’d like to create to the ListBox and implement the IToolboxService accordingly.  The design-time environment, which in our case is also the run-time environment, can query what item is selected and attempt to create an instance of the appropriate class.  Adding items is accomplished like so:

        protected void LoadToolboxItems()

        {

            ToolboxItem labelItem = new ToolboxItem(typeof(CarSpot.TemplateDesigner.Controls.CustomLabel));

            labelItem.DisplayName = "Text";

            _toolboxSvc.AddToolboxItem(labelItem);

Running the code so far you would see a Toolbox, a Panel with nothing in it, and a PropertyGrid with no selected object.  In the next article we’ll start to look at our IDesignerHost implementation and the sequence of events that occur when I want to see a designer view of my “designed document” with a CarSpot.TemplateDesigner.Controls.CustomLabel on it.



Tuesday, April 24, 2007 11:28:37 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, April 19, 2007

We have a cool feature in our backend data hub we call Image Overlay.  Basically given images of a vehicle we can do all sorts of transformations including overlaying text ("Buy this car!"), overlaying images ("GM Certified logo") scaling and matte-ing (shrinking the input image down to have a single color margin to draw text in) and support for various geometric primitives.  Our implementation is one of the few in our industry and is probably far more complete, flexible, and better-er than the few competing implementations.  Our backend uses some PERL stuff for this and I wondered if a .NET engine would be as fast or faster and how it would scale, given that the claim has been made that C# is 1:1 performance with C++ and despite my love of C# I found this claim questionable.  So, supposing I have an input image which is assuredly not a car:

And a tiny screenshot of my most anticipated upcoming PS3 game, LAIR:

And I want to do a few operations in realtime in .NET:

  • create a Matte
  • scale the source image
  • Add some text
  • import the Dragon screenshot from LAIR
  • Time the operation

Here is the source code for entering some parameters, which could obviously come from some other source:

<div>

<h3>Source Image:</h3>

<asp:HyperLink ID="_exampleLnk" runat="server" Target="_blank" NavigateUrl="~/sample.jpg">

View source image

</asp:HyperLink>

<br />

Matte and overlay some text:

<asp:TextBox ID="_overlayTxt" runat="server" Text="go MSFT!"></asp:TextBox>

<br />

Import Img X <asp:TextBox runat="server" ID="_xTxt" Width="2em" Text="100"></asp:TextBox>

Import Img Y <asp:TextBox runat="server" ID="_yTxt" Width="2em" Text="100"></asp:TextBox>

<asp:Button ID="_submitBtn" runat="server" Text="Lay it over" OnClick="_submitBtn_Click" />

<br />

<asp:Label ID="_resultTimeLbl" runat="server"></asp:Label>

<br />

<asp:Image ID="_resultImg" runat="server" />

</div>

... and the code behind....

protected void _submitBtn_Click(object sender, EventArgs e)
{
string getQuery = "Image.aspx?overlay={0}&x={1}&y={2}";
int x;
int y;
int.TryParse(_xTxt.Text, out x);
int.TryParse(_yTxt.Text, out y);
_resultImg.ImageUrl = string.Format(getQuery, _overlayTxt.Text, x, y);
}

... and the result...

So, on a Windows Server 2003 running ASP.Net 2.0, how much code does it take to generate this?  Surprisingly little:

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);

bool high = true;

HighResTimer hpt = new HighResTimer();
hpt.Start();
System.Drawing.Imaging.ImageCodecInfo codecInfo;
System.Drawing.Imaging.EncoderParameters parms;

System.Drawing.Imaging.ImageCodecInfo[] infoz = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
codecInfo = infoz[1];
parms = new System.Drawing.Imaging.EncoderParameters(1);
parms.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);

string txt = Request["overlay"];
int x = int.Parse(Request["x"]);
int y = int.Parse(Request["y"]);
Response.ContentType = codecInfo.MimeType;
System.Drawing.Image newImage = new Bitmap(640, 480);
System.Drawing.Image srcImage = System.Drawing.Image.FromFile(Server.MapPath("~/sample.jpg"));
System.Drawing.Image lairImage = System.Drawing.Image.FromFile(Server.MapPath("~/lair.jpg"));
Graphics g = Graphics.FromImage(newImage);

//Interpolation mode, smoothing mode, CompositingQuality,PixellOffsetMode,etc.
if (high)
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
}

try
{
//Matte color
g.Clear(Color.LightGray);

//Overlay font
Font textFont = new Font("Verdana", 9.0f, FontStyle.Bold | FontStyle.Underline);
Brush fontBrush = Brushes.Black;
//Scales the image down to matte it
g.DrawImage(srcImage, new RectangleF(0, 0, 600, 440));
g.DrawImage(lairImage, new RectangleF(x, y, 150, 84));
g.DrawString(txt, textFont, fontBrush, new PointF(10, 441));
g.DrawString("Damon Certified used o-scope", textFont, Brushes.Red, new PointF(430, 370));
hpt.Stop();
g.DrawString("RenderTime=" + hpt.Duration.ToString("n4") + "seconds", textFont, fontBrush, new PointF(10, 455));

//Stream
newImage.Save(Response.OutputStream, codecInfo, parms);
}
finally
{
if (null != srcImage)
{
srcImage.Dispose();
}

if (null != lairImage)
{
lairImage.Dispose();
}

if (null != g)
{
g.Dispose();
}

if (null != parms) // Seems to want to save in BMP anyway with this code in
{
parms.Dispose();
}
}
}

And I'd say 6/100th of a second on my very slow server (its an Emachine's POS we confiscated from someone after a pr0n escapade) is pretty good performance.  I have one bug in that it does not always save as a JPEG like I told it to but I'm sure a little research would clear that up.  So there you have it, a simple bit of image watermarking code in C#.

 

 



Thursday, April 19, 2007 11:35:38 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, April 12, 2007

I am hiring into my department @ CarSpot.com in downtown Milwaukee. 

Right now I am hoping for one Summer intern and one full time person based on the work that is going on.  We are doing cool stuff and growing.  As we staff up we are hoping to have some Google-eque policies such as spending part of your time on fun research projects.  I'm setting up a Quake server tomorrow as well.  We are not a .com company, however.

Do you...

  • Have .NET skills in C#
  • Understand design patterns
  • Understand UML
  • Enjoy drinking beer (we are upstairs from the Milwaukee Ale House)
  • Like an ultra-flexible work schedule
  • Like a small company environment
  • Multi-task well (we all wear many hats in a small company)
  • Like working with NUnit, CruiseControl, NCover
  • Have interest in developing cutting edge stuff that is far ahead of its time?

Ok, I had to throw the last one in.  There is room for help in Windows Forms, Compact Framework, ASP.net web services, ASP.net web forms, some win32/C++  dev, and probably some things I'm forgetting.  Forward your interest to damon.payne@carspot.com

 



Thursday, April 12, 2007 3:53:10 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, April 11, 2007

I got a new laptop yesterday: Dell inspiron, 17" screen, core 2 duo 2.13ghz, 2gb ram@667mhz, 7200rpm serial ata drive, more 3d card than one needs unless one is playing Quake4.  Hmm, sounds like we need to install Quake4 at work for Team Building.  My previous laptop was on its 4th year of service, its 2nd round of ram and 2nd hard drive, with the 2nd one looking like it was on its way out due to more and more bad sectors being found by chkdsk.

Its amazing how fast Outlook 2007, Visual Studio 2005, etc. run with the fastest hardware Dell would currently sell me. 

 

.NET | Rant


Wednesday, April 11, 2007 12:26:41 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, April 03, 2007

Why would you want to take something very technical, such as the Visual Studio designer environment, and put it into the hands of end users?  I suppose it depends on who your end users are.  In my case, I had a controlled group of people who needed a WYSIWYG way to design window stickers for cars, a tool with deep integration into our backend and handheld systems.  When I was given the first example background PDF I realized this was doable.  I can create an image that is exactly %print resolution% x 8.5" x 11", and my handheld ONLY supports printing at 72dpi.  Easy enough: make a background image that's 612x792 pixels.  1 pixel on screen=1 point on my printed document, and I'm on my way to creating a window sticker designer.  Here's a simple example of the beta of my new designer using the VS2005 surface:

While the Visual Studio designer surface is not Visio, it does work well for things that need to be shown in spatial relations to other things, and in some cases allows user interface design elements to be chosen after deployment, and by someone besides me.  You can see here I have the basic elements you see in VS2005: a toolbox, a property grid, and a surface I am dragging and editing controls on.  An XML file format describes the locations of various things on the form.  So, how did I build this?  Its about 6000 lines of not very straightforward code before you get into anything specific to your problem domain.  Speaking of problem domains, could you use DSL tools for this type of thing?  Maybe, but I have quite a bit of control by hosting this myself and of course I'm not distributing Visual Studio to non-programmers.  In a future project, I may look into what it would take to host the DSL tools outside of visual studio, but I expect its fairly similar to what I'm doing here.  Anyway, as far as building this, I thought I'd see if the VS Class Diagram tool could reverse engineer some relationships for me before I get into code.  No such luck:

 

 

I gave up after this point, although these are some of the most important classes,  so I'll need to invest some time into StarUML or just jump into code.  Its a long road to getting a Form to show up in designable fashion, stay tuned.



Tuesday, April 03, 2007 2:15:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, March 30, 2007

For me, it comes down to a question of innovation and real-world improvement.  Is find . -name *cpp -exec ls {} (or similar) still the best way to find files on a computer?  If I want to know rougly how large a project is, is find . -name *java |xargs wc -l the best way to see how many lines of code the team has produced?  Is make the best way to group many files into a single logical output?  Are ex macros the best way to refactor your code?

Is James Gosling's statement that most real development is still done in emacs (Java developer's journal, July 2000)the most bullshit words to be spoken since "No one will ever need more than 640k..." ?

.NET | Rant


Friday, March 30, 2007 11:25:46 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Sunday, March 11, 2007

I am running VS2005 on Vista with the Beta of the patch that allows it to run on Vista or with some Vista specific enhancements.  I set the ide .exe to always run as administrator and cannot get over the fact that it still asks me if I'm sure every time I run it.  This is ridiculous.  Of course I could turn off UAC but part of the reason for doing this was to learn the ins and outs of what my clients will experience with Vista.

I got the Smartphone 2005 SDK and am working on a smartphone video game which will be the subject of a few posts: nothing innovative at this point but if I can leave MotorStorm alone for long enough I'll get into some interesting code.

.NET | Gaming


Sunday, March 11, 2007 5:00:51 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Thursday, February 15, 2007

News about UAC in Vista is all over the web.  As a developer of shrink-wrap desktop software I thought I’d continue my string of “comments” (ok, bitching) about Vista now that I’m in a better place.

The most obvious places where UAC “helps you be more secure” are:

·         Writing to the registry requires elevation

·         Assumes any setup program needs to be run with Admin privileges

·         Writing to the \windows folder requires elevation

·         Writing to the \program files\ folder (and all folders below it) requires elevation

Another interesting tidbit is that Vista ships with .NET 2.0 installed.  That’s good news.  However MSI files built in VS 2003 will demand that .NET 1.1.4322 is installed despite the fact that .NET 2 should run those apps just fine.  Oddly enough, navigating to \windows\Microsoft.Net\Framework\ on a Vista install will show the following directories:

1)      V1.0

2)      V1.1

3)      V2.0

4)      V3.0

However the v1 directories do not have the full install, just some GAC tools presumably for sort of tool compatibility, so tests detecting a specific  1.x version will fail.

One interesting thing I tried but ultimately did not go with was marking my application so Vista knows it needs to run with Admin permissions by embedding a manifest in the .exe.  I found instructions for what the manifest should look like and a made a post-build event that would embed the resource in the assembly.  This worked well and Vista displayed my .exe with a nice “shield” overlay letting the users know they’d be prompted to elevate.  Sticking this .exe inside an MSI seems to clobber the manifest however, using dumpbin.exe confirms this.  Rather than dig for the answer to this I made some code changes as indicated below.

For this software developer, here are the changes I had to make to get a product running on Vista as painless for the user as possible:

1)      Created a .NET v2 version of our product.  Granted, I’d rather use 2.0 across the board but some of our customers won’t upgrade and we sometimes distribute via http so a bootstrap including the 2.0 install is a little bigger than where I’d like to be.  I did this by sharing the individual files across two VSS projects and just creating separate project/solution files for 2.0 in a different location.  Thanks to Matt Terski for the tip.  This feels evil for some reason but it works.

2)      Re-wrote the installers.  The .NET 1.1 installers accomplish some of the installation tasks with Custom Actions written in .NET.  Some of these actions do things like registering a device with a WIA event using the WIA automation layer and therefore require admin permissions.   While I would think the MSI would spawn my .net EXE with the same security tokens  (already elevated and using the admin token) as the parent process this did not seem to be the case as the custom actions reliably crashed the install every time.  I set up the MSI to write the same registry keys that the WIA code would have done and worked around the other custom actions so that everything is part of the MSI.  Since the installer writes to the registry, it must still install with elevated permissions.

3)      Non-Admin Logging Mode.  Previously the application did innocuous things like Write a log file in the same directory as the .exe using log4net.  I had to do some digging to find how to change a DOM configurated FileAppender location at runtime (http://insario.com/blog/jfk/archive/2004/11/30/164.aspx) and change this from \Program Files\MyProgram\ to a user-specific location if the code runs on Vista. (OS version = NT 6.0blahblah)

4)      Non-Admin App settings.  Written in .NET 1.1 initially the app used some dynamic windows forms properties: GUI features bound to an App.config setting.  Since App.config lives in \Program Files\MyProgram updating these properties also wasn’t going to be non-admin friendly.  Somewhat loathingly, I added a “Settings” file to the .NET 2 project.  And set the code to use settings vs. writing to app.config with some conditional compilation.  Hooray for #if NET2.  The Settings feature wasn’t trumpeted like MASTER PAGES AND GENERICS when .NET 2 was rolling out but it’s worth looking into if you are not familiar with it.  Settings can be marked with a UserScopedSettingAttribute()  or regular old Application Scope.  User scope settings are stored in a User specific location (although I’m damned if I could find the file itself but it works) and therefore no elevation needed.  Nice of .NET 2 to handle that for me.  This is probably a better design choice anyway but again it’s mainly a 1.1 app.

Now my code installs as Admin and then happily does all its Camera/WIA/Exif/Internet hooha without requiring elevation.  Digging through the UAC documentation to see where I was going wrong was frustrating at first, and if anyone knows how I can keep an MSI created in VS2005 from clobbering my manifest (at install time or packaging time, I’m not sure which) that will probably come in handy at some point.



Thursday, February 15, 2007 10:46:02 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, February 07, 2007

After the huge user uproar that happened when the Compact Framework 2.0 initially did not support CE 4.2 devices, one would think MSFT would have taken the point, instead, today I get another fun Vista Fact.

ActiveSync 4.2 and before will not run on Vista.  It's blocked, and tells you so when you try to run it;  Nice of them to let me install it first though.  The Vista solution is the Windows Mobile Device Center, which sounds very swell.  However it explicitly does not support CE 4.2.  Old version won't run, new version won't talk to my devices.  Of course I tried anyway and on my hardware any attempt to connect reliably crashes the Service Host over and over again.  So, for now, we can't sell our most expensive product on Vista.  Granted, I mostly blame this on the OEM who has refused to upgrade to CE 5 for over two years now.

 



Wednesday, February 07, 2007 4:04:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

So, I have already had one customer complaint about this or that not working on Vista.  That didn't take long.  So far I can see that:

-Vista does not ship with .net 1.1, only 2.0.  This wouldn't bother me as 2.0 is overwhelmingly backward compatible with 1.1 assemblies with very few breaking changes.  However my MSIs created with VS2003 demand 1.1.4blahblah explicitly, so I need to build new installers or include a 1.1 bootstrap.

-With 1.1 installed, my .net custom actions for registering my camera software with wia and doing some custom regsvr32 bombs and aborts the install.  Copying the files and assemblies needed and running the registration manually does not complain, however my 1.1 assembly will not start, giving an evil looking runtime error before a single line of .net is executed.  That's nice.

-My Camera software that uses the WIA automation layer seems to be able to register WIA events properly, at least I've got that going for me.

-Seemingly EVERYTHING requires me to confirm changes to my computer.  Manually Creating a folder under \program files requires two confirmations?  What the hell is that?  If that's security, I'll take my chances, thanks.

So, you can probably tell I didn't follow Vista very closely before launch, maybe some of these are known issues with simple solutions.  I'll be working on getting my company's most successful app installing and running under Vista now...



Wednesday, February 07, 2007 10:55:23 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Monday, January 29, 2007

A little .NET news today.

It appears that something fundamental like Application.StartupPath is broken in .Net 1.1 in some situations.  If your application was not started via a shortcut, but some other system service like registering a device plug-in event with the WIA Automation tools then .NET will report the StartupPath as \windows\system32 instead of the actual location of your .exe. 



Monday, January 29, 2007 12:04:23 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Tuesday, December 05, 2006

Why, oh why, is it that I cannot get a version of dotnetfx.exe that does not include the ASP.Net runtime and such?  It would be nice for my end users if such a thing existed.

.NET | Rant


Tuesday, December 05, 2006 3:57:45 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, November 15, 2006

I spent a bit of time yesterday hacking Codus to work on .NET 2.0 and generate generic classes and collections for data access.  Talking to Sean from Adapdev a bit it looks like I'm going to try to clean this up and contribute the changes so they're available in future Codus and Adapdev.Net releases.  So, if you have been looking for .Net 2 support in these excellent tools, it seems its on the way.



Wednesday, November 15, 2006 11:11:13 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, November 01, 2006

For some reason I had been under the impression that there was not a provider model for session state in ASP2.0.  It seemed a shame that I could not provide my own iplementation for session state in my app.

http://msdn2.microsoft.com/en-us/library/aa479034.aspx shows that this was an incorrect assumption.

You may wonder what could possibly make someone want to implement their own session state provider?  While doing some pie in the sky architectural thinking about my current production environment I noticed that it does not seem that StateServer is clusterable.  I somehow don't think I'll ever get around to digging into this seriously, but I wonder what it would take to create a clusterable StateServer implementation?



Wednesday, November 01, 2006 1:18:27 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Tuesday, October 31, 2006

As I have posted myself, and not too long ago either, using the "as" operator in C#, as in SomeType t = obj as SomeType; does not throw an InvalidCastException, but rather returns null if the type conversion did not work.  In my Sorting example, the catch() should be changed to catch null pointer instead.



Tuesday, October 31, 2006 10:12:57 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, October 27, 2006

You gotta love Generics in .Net 2.0.  I had to do some Object-sorting in memory with some List<T> stuff. 

/// <summary>
/// Compare objects of type T using a certain property
/// </summary>
/// <typeparam name="T"></typeparam>
public class PropertyComparison<T> : System.Collections.Generic.IComparer<T>
{
/// <summary>
/// What property of the objects to use to compare one to another
/// </summary>
/// <param name="property"></param>
public PropertyComparison(string property)
{
_propName = property;
}

private string _propName;
private PropertyInfo _prop;

public int Compare(T x, T y)
{
if (null == _prop)
{
_prop = x.GetType().GetProperty(_propName);
}

try
{
IComparable xVal = _prop.GetValue(x, null) as IComparable;
IComparable yVal = _prop.GetValue(y, null) as IComparable;
return xVal.CompareTo(yVal);
}
catch (System.NullReferenceException)
{
throw new ApplicationException("Type " + _prop.PropertyType.ToString() + " is not IComparable");
}

}
}

So then I would use it:

if (!string.IsNullOrEmpty(prop))
{
CarSpot.Mobile.Types.PropertyComparison<Vehicle> c = new CarSpot.Mobile.Types.PropertyComparison<Vehicle>(prop);
try
{
_dataSource.Sort(c);

 

 



Friday, October 27, 2006 12:52:29 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, September 12, 2006

If you know me, you know I am an audio nut.  A peak at my living room (pictured here) might give you an idea I'm not well in the head, let alone the lunacy involved in the custom home theater that's being built in the basement right now.

The world of audio is a great place to observe tons of Snake Oil being sold and a sad, sad departure from the available Science that could guide us towards better sound.  Its not unlike many areas of computer science, where the Morts have never even heard of the science their day-to-day work is based on.  If you know SQL experts who are great at their job but who weren't aware that the concepts come from relational algebra, set theory, etc. then you know what I mean.

Over the past year I've become very interested in the effect the listening room has on sound.  Audiophiles like me spend a fortune on equipment that has perfect frequency response and near-zero harmonic distortion then put the system in a room that creates 30db peaks and valleys and flutter echos that ruin the stereo image, the list of room problems goes on and on.

I recently created a Room Mode calculator for my audio site, http://www.KlipschCorner.com/.  Room Modes are essentially the frequencies your room will cause to sound louder than they should due to the dimensions of the room.  For example, a 60hz sound wave is 19 feet long making a room with any dimension being 19feet a bad call.  Rooms with the common 8ft ceiling are tough to treat due to the frequency ranges being close to 8ft or 4ft.  A room mode calculator is useful when planning a new listening room because one can quickly see if there will be room modes at any "problem" frequencies and also see the distribution of room modes, where an even distribution is desirable.

There is a graphical component as well as a tabular component.  My hosting provider, while their service is great, chose to license a rather poor charting utility, so if anyone wants to send a free license of Infragistics my way you'd be saving me a lot of pain.

You can see the end results at http://www.KlipschCorner.com/Tools/ModeCalc.aspx and I suppose I can make the KlipschCorner.Acoustics library as it stands now available via some open source license.

I wonder if DirectSound could be made to do some time-domain analysis (using test tones and a microphone for input) for calculating sound decay rates vs ambient noise in a room?

.NET | ASP.NET | DirectX | Rant


Tuesday, September 12, 2006 9:41:47 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [6]  |  Trackback
 Wednesday, August 16, 2006

After becoming frustrated at "Visual Studio 2005 command prompt" yet again I become a powershell user today.  I'm not doing any scripting right now but its good to see MSFT recognize that a good command line can be very handy.



Wednesday, August 16, 2006 9:49:11 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, August 01, 2006

private const string DOLLAR_SIGN = "$";
private const string COMMA = ",";

Hmm...

.NET | Rant


Tuesday, August 01, 2006 1:11:20 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback

Which bit of code do you think is more maintainable by someone other than the original developer:

if(_speakerTypeCode == 543678){

//do something

}

or

enum SpeakerTypes {

HornLoaded = 543678,

Electrostatic = 12334
}

if(_speakerTypeCode.Equals( SpeakerTypes.HornLoaded)){

//do something

}

I'm still amazed at some of the things I find in code, sometimes even my own code.  The above monstrosity is not mine, although I do occasionally find something abhorrent in my own code.  I read a blog recently, I believe it was the Shade Tree Developer, who said that this is a great way to gage personal growth.  Go back and look at code you wrote and see if you find things that you'd never do today.

.NET | Rant


Tuesday, August 01, 2006 11:52:54 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [52]  |  Trackback
 Friday, July 28, 2006

I really don't like the C# "as" operator.  I have to admit that I made it a point not to use this solely because it made me have a brief moment of "VB.NET flashback".  I personally have a strong dislike for VB.NET syntax but that's just my preference.  Because of my VB.NET bias I did not look at the C# language spec to see if "as" functioned differently from

string foo = (string)myType;

As it turns out I tracked down a difficult bug in our system that was due to the fact that using "as" returns a null reference rather than throwing a class cast exception like c-style casting does.  Granted part of the problem was people swallowing exceptions in code, but I'm wondering: under what circumstances would one want the behavior that "as" provides?

.NET | Rant


Friday, July 28, 2006 9:35:19 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Monday, June 19, 2006

For various reasons I've had to get back into unmanaged code in C++.  This turned out to be a lot worse than I thought it would be.  My college courses were in C++ and I did a little OpenGL programming using visual C++5 or 6, and my first job was doing a lot of cool C++ stuff.  However, that was most on the Solaris platform using stuff like Vi, the sun workshop compiler, and the RogueWave libraries for things like Time, Strings, and Money.  I never got into MFC or programming C++ on Win32.  Obviously things like LPSTR and "DEF" files and such are completely new to me, if it wasn't for Chad Albrecht I would have lost my mind already.  When I take a look at the things that are coming up on my plate, though, I can see that this isn't necessarily going to just go away, SO...

If anyone can recommend some good literature for getting into MFC and Win32 programming using eVC4 and/or VS2005 I'd appreciate it.

.NET | Rant


Monday, June 19, 2006 12:05:11 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Sunday, April 02, 2006
I will follow up on my solution for the "transaction" post later, however with that problem solved I have a more immediate need: I'm looking for a free Code Coverage tool for .NET.  I found a lot of blog posts pointing to CoverageEye but I wanted to know if anyone is using anything else and having good experiences?


Sunday, April 02, 2006 2:20:28 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, March 23, 2006

This is a follow up to my previous post.  After today, I have a small distant idea of how NASA must feel when a "trivial" item causes a big problem.  My trucks in Detroit were having issues today, and long support calls were getting me nowhere.  I finally came around to thinking that our data synchronization is time-based (rather than GUID based like Merge Replication) and wondered if I had not setup the Detroit units properly.  All times are convered to UTC on the units so there is no hoo-ha for trucks outside of good ole  GMT - 6 where the server lives, and on my checklist for building new handhelds is a bullet point "Verify time zone".  I did this however forgot to verify Time as well so my units had GMT -5 but the hour set to the same hour as current local time.  A small thing caused a very big SNAFU today.  Obviously I can't trust truck drivers (nor myself, clearly) to not screw up the time on the units and I should automate the system time from the backend.  Things like time-zones for nation-wide deployments will play a larger role in my testing strategy in the future...

 



Thursday, March 23, 2006 6:12:48 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, February 20, 2006

optionsScalper will be giving what is sure to be an interesting presentation on F#.NET at the Wisconsin .NET user's group tomorrow.  optionsScalper has a very serious math background, a scientific mind, and an excellent singing voice.   I like to think of him as someone who's putting the Science back in Computer Science.

He has piqued my interest in F# so I hope to have it installed and working before the presentation so I can follow along.  I won't attempt to describe F# until I've written some, suffice to say it is a different programming model than the stack-based imperative languages most of us are familiar with and thus presents a paradigm that is much more friendly to certain types of problem solving.



Monday, February 20, 2006 9:41:10 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, January 12, 2006

Many applications have scaling, or zoom-in, zoom-out features of some kind.  Acrobat reader, Word, Graphics programs, etc.  We have these great Skin and Theme features in ASP.NET 2.0 but not so in Windows forms.  You can enable XP visual styles though, check out this Help article:

ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VSADD.v10.en/dv_vstechart/html/vbtchUsingWindowsXPVisualStylesWithControlsOnWindowsForms.htm

While trying to determine a good design approach to creating a skin-able windows app I stumbled across some odd behavior which I assumed must be a bug:

  1. Create a windows forms app and throw some controls on it.  Leave everything the default size/font/color since I am going to apply a skin to it anyway.
  2. At runtime, change the font to the "skin" font.
  3. If the design-time font was good ole MS sans-serif 8.25pt and I assigned a font with a different size (Verdana, 12pt) the form would suddenly get tremendously larger.

My forms extend from a BaseForm, so this must be a Visual Ineritence bug, I thought, and the client decided not to spend $$ on the skinable feature just yet anyway.  When a request came in to allow parts of the application to Scale via zoom-in, zoom-out, I came back to this.  My odd resizing forms are exhibiting behavior as designed.

ScaleMode

Windows Forms in .Net 2.0 are designed to automatically scale under one of two events: the Font assigned to the form changes, or the screen resolution changes.  There is an AutoScaleMode property on a Form, with the enumerated values being

  • None
  • Inherit
  • Font
  • DPI

It seems I could find my way through this in order to meet my scaling requirement and also revisit the Skin feature in future.  A Form keeps track of what dimensions it was designed to regardless of other resizing and such.  This is stored in the AutoScaleDimensions property.  From the set_Font method of a Form, the Scale and ultimately ScaleControl methods will be called.  These can be overridden to alter scaling behavior, or just observed to determine how to manipulate scaling.  So, I have an MDI application and the area I want to scale will be contained in a "ScalableForm" like so:

Now, a simple way to give the user the ability to zoom out, I create a simple ScaleData class.

public class ScaleData
{
public ScaleData(float size, string desc)
{
_fontSize = size;
_display = desc;
}
private float _fontSize;

public float FontSize
{
get { return _fontSize; }
set { _fontSize = value; }
}
private string _display;

public string Display
{
get { return _display; }
set { _display = value; }
}
}

... and populate some scale values in the ScalableForm constructor:

public ScalableForm()
{
InitializeComponent();
ScaleSizes = new List<ScaleData>();
ScaleSizes.Add(new ScaleData(this.Font.Size / 2f, "50%"));
ScaleSizes.Add(new ScaleData(this.Font.Size, "100%"));//This will be the design-time size
ScaleSizes.Add(new ScaleData(this.Font.Size * 2f, "200%"));

...

There is certainly no need to pre-calculate a limited set of zoom values but it removes the need for calculations later to get back to 100% .  Now I provide a menu item that will scale the currently active child Form and the code is very simple:

private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
  _scale.Font = new Font(_scale.Font.FontFamily,_scale.ScaleSizes[0].FontSize);
}

So telling it to zoom to 50% looks like:

A couple of other things bear mentioning.  Note that "a bunch of text in a label" appears the same size in both cases , although the Location of the Label was scaled down.  By default the ScaleChildren called from ContainerControl will not scale controls set to be automatically sized, so in this case I would need to tell my label not to auto size itself.  Also, the documentation for scaling claims you can have a control on this form not ever scale itself by extending a control class and providing the following:

public class UnscalableComboBox : ComboBox
{
   protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
   {
      base.SetBoundsCore(x, y, 121, 21, BoundsSpecified.None);
   }
}

However, neither this, not setting Locked=true, not setting MaximumSize and MinimumSize would stop a control from being scaled when I changed the font.  For now I put the scaling function in the menu (rather than a combo box on this form somewhere) but will continue to investigate this feature as I work on this project.

 



Thursday, January 12, 2006 10:51:44 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, November 20, 2005

No, that's not a typo.

I have long been enamoured of the Amazon.com WebService API and have recently began actually using them in a semi productive fashion.  In the web service developer's newsletter I see this in tonight's release:

"When we think of interfaces between human beings and computers, we usually assume that the human being is the one requesting that a task be completed, and the computer is completing the task and providing the results. What if this process were reversed and a computer program could ask a human being to perform a task and return the results? What if it could coordinate many human beings to perform a task?

Amazon Mechanical Turk provides a web services API for computers to integrate Artificial Artificial Intelligence directly into their processing by making requests of humans. Developers use the Amazon Mechanical Turk web services API to submit tasks to the Amazon Mechanical Turk web site, approve completed tasks, and incorporate the answers into their software applications. To the application, the transaction looks very much like any remote procedure call - the application sends the request, and the service returns the results. In reality, a network of humans fuels this Artificial Artificial Intelligence by coming to the web site, searching for and completing tasks, and receiving payment for their work."

You can read more about it here: http://www.amazon.com/gp/browse.html/ref=aws_gen_nl13amt/104-4070773-8438325?node=15879911

I find this interesting in light of all the captcha and captcha breaking and ideas for better captcha going on.  It seems necessary for irony's sake to now implemented an automated system that can respond to these requests and get it right...

.NET | Rant


Sunday, November 20, 2005 10:16:23 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Monday, September 26, 2005

I recall reading a best practice somewhere that you should neither give nor expect null as the result of a method invocation.  This was absolutely the norm in C++ despite the somewhat common notion of the NullObject pattern (http://www.eli.sdsu.edu/courses/spring98/cs635/notes/strategy/strategy.html#slide8); the practice is still so common in .NET languages that I doubt many people are familiar with the notion of a null object.

Today I began self-reviewing my code for a mobile project I am in the process of wrapping up.  I found that this notion had made its way into some of my code and for the sake of consistancy I went about repairing my error.  The fact that I had things like

CustomerDataAccess dao = new CustomerDataAccess();
CustomerTruck ct = dao.FindByBarcode(bc);
if (null != ct) {
//Do something
}

in (shamefully) about half my code made me take a step back and question the value of what I was doing. First of all, I find it amusing that I still keep to the old C++ "Put your constants on the left hand hand side of any comparison" practice.  For those of you who never had the honor of programming C++ the following code would compile, but give you unexpected results:

if (lValue == 3){
// do something
}
//Versus:
if (lValue = 3) {
//whoops...
}

...since both "=" and "==" are valid inside an if statement.  To make a long story short, any successful action such as this will return a non-zero value and failure a zero value.  In C++ "if (0) " is valid syntax and therfore this could result in a hard to track down issue.  My question to my mentors was always "Well, if I can remember to use the const expression as the Lvalue why can't I just remember to do it right?"; but that's neither here nor there.

There are some examples of a NullObject pattern in the current .NET framework, for example using string.Empty instead of "" or null. 

Thinking further, many have accidently (mis)used this pattern for value-types in the current .NET language.  Have you ever used DateTime.MinValue in your code to signify "No value here" ?  In .NET 2.0 we will have nullable value types (http://msdn2.microsoft.com/en-us/library/b3h38hb0) to make this a little bit cleaner for us. 

As I replaced code such as if (null != ct) with if( ct != CustomerTruck.None) it certainly did look cleaner and made me feel better about myself as a person but I wondered if it was worth going back over working code to do.  One additional benefit is that if I DO forget to check for null (or proper NullObject) in code somewhere, I will likely get some expected behavior rather than a NullReferenceException.  

My questions to the community are these: do you have your own argument for using a NullObject Pattern?  Do you use the NullObject pattern?

(Thanks to Terski for being my pre-post sounding board yet again)



Monday, September 26, 2005 2:40:44 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Wednesday, August 31, 2005

Random Task is my idea for a Visual Studio add in.  The premise is simple, as are many good ideas.  Either you will immediately see the value in this due to your own work habits or you will think it trite.

I do a lot of work on various different things: I have several different solutions for my day job, I have a couple of solutions for side work I spend a lot of time in, and several solutions I only spend time working on from time to time.  Visual Studio is always open if my laptop is on.  My issue is that I often switch between three or more solutions in a sitting and find it difficult to guestimate how much time I spend working on Project A, then Project B, and billing those clients accordingly.

Random Task, then, is a Visual Studio add in that records timestamps for when I open and close solutions.  The UI for the add in can then report on how much time was spent on each solution (and therefore client) just by keeping track of Visual Studio .NET time.  This would save me a lot of pain in "Erring on the side of safety" and essentially under-billing everyone in my efforts to be fair.

I did a quick proof of concept in VS 2003, but there are actually a couple of code contests I could submit this to if I upgrade to VS 2005.  The extensibility IDEs are not a part of the normal Beta 2 distribution so I had to join the Visual Studio Partner Program and download the VS 2005 version of the SDK from http://www.vsipdev.com/downloads/ 



Wednesday, August 31, 2005 9:16:09 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Monday, July 18, 2005

Well, this is what, four non-code posts in a row?  I'm slipping.

I spent some time going over some client work this weekend and it seems that I am catching up.  It seems that I might be getting close to the Period of Rest I've been looking for, this is less satisfying that it would be if my new home was anywhere near completion.  I still have a couple of bigger things that I could work on but these hold the danger of me getting too far ahead of client requirements, the old "Go ahead and work on it but I won't have time to tell you if its right" hurry-up-and-wait.  In light of this, I turned back to something that had been shelved for a while: something I call Project Cesium.  I have alluded to Cesium a couple of times on this blog and to friends, hinting that this may be a press-release-worthy item at some point.  I started working on a re design and some code Saturday afternoon.  Stay tuned for an early 2006 release of something that will hopefully be a big deal.



Monday, July 18, 2005 8:52:49 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Tuesday, June 21, 2005

I believe that every good developer should be familiar with the idea of leaky abstractions, after all we live in a time when many of our computing concepts involve higher and higher levels of abstraction in our coding model.  I might go so far as to say that Joel characterizing this notion of Leaky Abstractions is a noteworthy contribution to the field of software development.  I like to know what's going on behind the scenes of any tool that I'm using, in case the abstraction breaks and I am forced to pull out my pipe wrench and fix some plumbing.  Perhaps this makes me a "Computer Science Elitist" or a Dinosaur who still has a "close to the metal" mindset in an age of abstraction.  I like to know what's under the hood.

XML Web Services in .NET is a big abstraction.  This abstraction tells me that I don't need to worry much about XML.  This abstraction tells me that if I put [WebMethod] on a method, it will handle the plumbing of SOAP endpoints and my clients can interact with this code via discoverable types and I don't need to worry about how things are serialized.  There are many cases where these great (and they are great) XML Web Services are leaky abstractions.  Some of the more well known ones involve DateTime parsing and Serialization and such.  I'll share a new one today to illustrate Leaky Abstractions.

I return Messages from my web services.  One of the types inside my message is an enumeration, defined like so:

    [Flags]
    public enum PullOption
    {
        None = 0,
        PullChangesOnly = 2,
        PushChanges = 4,
        EmptyTableAfterPush = 8,
        StoredProcedure = 16
    }

The system handles enums well enough.  Note also that I have used the [Flags] attribute.  Whenver I see [Flags] I have to do a double take to make sure I'm not writing code that is hard to read or maintain; often times, especially when dealing with the Win32 API, there are so many different options to deal with that [Flags] really is the best way to go about it.  This code works fine on the server.  Now, on my client, I notice that the results I get are not quite what I expected.  The whole abstraction of XML Web Services and WSDL.exe in .NET is broken, and I have to start looking under the hood.  My OperationDescription for this enum field looks something like:

<PullOption> None or PullChangesOnly or PushChanges or EmptyTableAfterPush or StoredProcedure</PullOption>

and the WSDL looks something like:

- <s:simpleType name="PullOption">
- <s:restriction base="s:string">
  <s:enumeration value="None" />
  <s:enumeration value="PullChangesOnly" />
  <s:enumeration value="PushChanges" />
....etc.  Clearly this abstraction leaks when you want to treat an Enum as Flags.  I did not see a special SOAP attribute that would tell the Serializer to handle my Enum as an int, but I didn't spend all day on it either.
I changed the field to an int and now I can write bitwise and/or code on my client.  The downside is that this enum must be duplicated to the client via code or assembly sharing now.
 
Beware leaky abstractions.  A good developer uses abstractions and tools to become more productive.  A good developer can look under the hood at the internals of an abstractiono, too.


Tuesday, June 21, 2005 10:38:50 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [7]  |  Trackback
 Thursday, June 16, 2005
OK, so, I have quite a few things on the burner right now as well as some items optionsScalper would call "Off the Block".  As Murphy's Law would have it, several "Critical Must-have improvements" came up in two of my side projects.  One of them is a mobile application I support.  I have come to think of ActiveSync as my sworn enemy.  Being such a critical component it should just work but as a casual parusal of the user groups will tell you, it does not.  I have an issue where trying to FTP 50 or more files from the device eventually "locks up" making any new FTP connections until Active Sync is stopped/started again.  I was hoping Active Sync 4.0 would solve the issue, but no such luck.  If I can get ShellExecute of repllog.exe to work I should be able to detect the error situation and bounce active sync to fix whatever ActiveSync proxy/network quirk this is.  If anyone knows all the possible command line args to repllog.exe on CE.NET it would save me some time.


Thursday, June 16, 2005 10:15:29 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [6]  |  Trackback
 Sunday, June 12, 2005

 I finished this book on the plane coming back from Tech Ed.  The book is pretty well laid out and if you download the source code for all the samples to read as you go along everything makes a lot of sense.  If I had never even looked into game programming before and this was the first book I'd read, the book would be highly motivating; it leaves one with the feeling of "Holy crap, I could actually do this."

If you've never done game programming before, I'd suggest going through the motions of doing the 2D games before getting into all the Managed D3D stuff.  2D games have all the same elements: game loops, render loops, collision detection, etc and you need to learn all those things before moving on to more complicated vectors.  Reading this book also gave an introduction to DirectInput, DirectSound, and DirectPlay: the developer story for making a DirectX game is really fantastic. While there is always a performance hit for working within managed code, as Tom Miller points out Managed DirectX is a very thin wrapper and in terms of pure graphics performance the managed apps get very similar framerates to the unmanaged apps.

I'm going to re-work my current Tank simulation with DirectInput and some sound before moving back to my neural net.



Sunday, June 12, 2005 12:45:09 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [40]  |  Trackback
 Saturday, June 04, 2005

Well we are in Florida in a nice hotel with a not so nice internet connection.  No hard-wire in my room so I'm sitting in the lobby.  Bah. Seriously folks, what year is it?  I have already learned something on this trip: My Laptop + Beta 2 + no plugin on the plane = battery dead in 40 minutes flat.  Nice.  I know that a couple of other Wisconsin people are around so maybe I'll hook up with them this coming week.

As I mentioned in the "Simulation" article I have some fabolous (cough) graphics in a Direct 3D game I'm using as a simulation for various theory testing.  The next step was to implement some kind of AI so that the bad guys shoot back at me.  I'm almost done with the pre-simulation-simulation-tester for my neural net.  Why a neural net?  I should say before optionsScalper slams me for mis-applying the idea, wait for my next post where I justify why this notion is very fitting for mimicing how a human would look at something on a screen and try to guess at a trajectory and how to acheive it.  Stay tuned.

.NET | TechEd


Saturday, June 04, 2005 7:15:22 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Tuesday, May 31, 2005

A quick mini rant as I work on some code tonight.  Disclaimer: I am far from perfect but I strive to improve at all times.

If you are developing a class library that you make freely available on the internet, you should realize that someone might actually download and use it.  In light of this, error handling is important.  I am using an FTP library for the compact framework that I downloaded from a reputable site..  My clients were having FTP issues this past week though, and I had to duplicate a situation that did not come up in my testing.  For reasons I won't get into, their servers have issues sometimes, so I had to implement a Re-try mechanism for the FTP items in question.  I tracked the issue down to this code:

FileStream fs = new FileStream(localFileName,FileMode.Open);
SendStream(fs, remoteFileName, type);
fs.Close();

See any issues here?  Maybe if I compare it to what I changed it to?

            FileStream fs = null;
            try
            {
                fs = new FileStream(localFileName,FileMode.Open);
                SendStream(fs, remoteFileName, type);
            }
            finally
            {
                if (null != fs)
                {
                    fs.Close();
                }
            }

Sometimes things will blow up.  In this example, if the FTP send fails, which is entirely likely due to network connectivity issues then the file stream will not be closed and cannot be closed because I've lost my reference to it.  The Re-try was then pointless since the file is locked by an object off in la-la land that has not been garbage collected yet.  While I'm at it, I don't know how many obscure bugs I have traced back to a resource such as a SqlConnection or DataReader not being taken care of in a Finally or Using block.

There, I feel better.  The author has still saved me a ton of time with a very easy to use library.  The next step is for me to be a good citizen and politely inform them of the issue.  Better code for all.  I would certainly want someone to inform me if I had released a library with bugs.  Happy coding.



Tuesday, May 31, 2005 9:13:17 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback

Update: The Agile Developer pointed out that refactoring support and some other features are in fact supported for VB in VS 2005.  This is not meant to be controversial, as I despise the practice of being offensive just to try to create traffic.  This article is a combination of my own biases and a possible explanation for "Why do people bash VB?" Don't kill the messenger.

The google searches are a little slow today and The Agile Developer made a post and used VB.NET in his example so now's as good a time as any to resurrect my extreme dislike of VB.NET.  VB.NET is not "equal" to C#, regardless of what marketing material you may have read that tells you it is. I could drone on all day about how much worse my carpal tunnel would be if I had to keep typing

public overridable shadows Sub ThisIsMyMethodName() as MyReturnType

or about how much I dislike setting

option Strict on;
option Explicit on;

in order to enforce strong typing in an already strongly typed language.  Without these options there would be nothing wrong casting an instance of System.Web.Form to say, an instance of System.Integer.  Nor will I drone on all afternoon about how annoying these options make any form of OO programming, since turning them on means if I have a type Child that extends type Parent and a method that accepts an argument of type Parent I have to cast descending classes down to the base type (I guess strict means "So strict we don't trust you with Object Oriented programming") before the compiler will accept it.  If I enjoyed using obscure pre-compiler directives to make things work right I'd go back to creating C++ apps that run on multiple unix flavors: no shortage of #pragma directives there to keep me happy.

  Also missing from my lecture this afternoon will be how crippling not being able to override operators is, since many framework class methods such as ArrayList.Contains make use of "==" and not "MyClass.Equals" for its testing.  If anyone can remind me how to initialize an Array with a given size in VB I would congratulate you for keeping the roughly 39 uses of the paren "()" straight.  Finally, if I think it is ludicrious to have to specify which one of my methods implements an Interface method (public sub MyFunction() as string implements ICrap.MyFunction) then that's just one man's opinion, of course.  Since the man in question is obviously an elitist anyway we should not concern outselves.  If you want to program in an IDE that enforces Word-like AutoCorrect syntax fixers on your code, that's your problem.  Many times on user groups I have seen a question posted regarding some data binding or Reflection issue related to case sensitivity, ie MyMethod is not the same as mymethod to the CLR.  "How can this matter in a language that's not case sensitive?"  If the previous statement does indeed seem like a very good question to you, please stop reading now.

For various logical reasons, a lot of people do not like VB.Net.  Some of these are stylistic choices and some are just plain pains in the ass where certain programming tasks are concerned.  Before I go on, let me make a couple of disclaimers:

  • I know some kick-ass VB developers.
  • I am proficient in VB.NET
  • You can indeed create very serious, robust, scalable, well-designed Enterprise applications in VB.NET

The VB community has gotten a bad reputation over time.  There, I said it.  For many years there were C/C++, Java, Smalltalk developers who just plain did not consider VB a "real" programming language.  In the heyday of pre-.NET VB people developed the notion that "serious" programming was done in a different language, and VB was for creating poorly-designed front ends to a database.  The fact that many VB developers did not have a traditional software engineering background and no Computer Science degree tells us a couple of things:

  1. VB was very good at its job of making simple programming more accessable to more people.
  2. Everyone from managers to programmers can develop bias towards a technology platform.

Let me propose this: When choosing a technology platform, you are also choosing the community of people who subscribe to that platform. This is not an original idea.  C++ people tend to be different than Java people, who are slightly different than C# people, who are slightly different than VB.NET people. I claim the source of this often goes back to education : If you got a CS degree you probably took classes in C++, Assembler, had some Calculus, etc.  If you got an "MIS" degree (or in some cases taught yourself) you probably had classes in SQL, COBOL, Accounting, and Visual Basic.  In a world of elitist programmers, the former background is considered better than the latter.  Don't shoot the messenger, I'm merely saying what everyone is thinking.  If you want another warm body to write stored procedures, post an ad looking for someone with VB.NET; if you want someone with excellent software engineering skills, post a C++ ad.

Nowhere is this difference acknowledged better than at Microsoft itself.  The Visual Studio team takes its direction to a great degree from ehancement requests by the user communities.  While there are some differences in the way VS 2003 behaves based on programming language, the disparity gets wider in VS 2005.  Take note of some popular new C# features

  • Anonymous delegates
  • Edit & Continue
  • Rich Refactoring support

Versus VB

  • The "My" namespace to make already simple tasks simpler
  • Crippled refactoring support
  • Still no "post build" commands

I'm vastly summarizing and obviously I am biased.  My point is that things like this perpetuate the idea that VB.NET is inferior because a different type of person chooses VB vs. C# for their .Net development.  We've all heard the rumour that the average C# guy makes a lot more than the average VB guy.  Companies perpetuate this idea with hiring practices such as "We need 10 VB guys and 1 C# Architect on this project"; one large local company I know of goes so far as to have a Frameworks/Architect team that develops tools in C#, which are then consumed by the project teams consisting of all VB.NET developers.

That is why I use C#: because I recognize the world-wide bias against the Visual Basic community.

I am proficient in VB.NET because I recognize that when it comes down to the code, there is very little real difference, with the only major item being stylistic preference.  Comments and flames welcome as always.



Tuesday, May 31, 2005 12:26:13 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [6]  |  Trackback
 Monday, May 30, 2005

I've been talking about DirectX and games lately, and I've come up with a simulation for me to experiment with some things I've been wanting to learn or see in action.  Essentially, my brain has been going in several directions at once and this will be a first effort at exploring some ideas I have.  These areas of interest are:

  • Physics: Realistically modeling shockwaves from explosions.  Coming up with a mathematical model for uniform and non-uniform force vectors and fluid dynamics such that a virutal world can react realistically with no "arbitrary" parameters defined, ergo "How come this can blows up but not this wall?"
  • Destoryable terrain technology.  Using the above to be able to model bezier surfaces that represent a surface after an explosion.  
  • AI: I'm very interested in AI, mostly just for academic nerd reasons ,but I may come up with business or gaming related applications

So, I've decided my simulation for all this will be a DirectX remake of the classic game scorched earth.  It will start out as a 2D version and move to a 3D version as soon as I find a good (free) 3D modeling tool.  I already have the game and graphics part of it pretty much done.  Next step: program some AI that shoots back at you.

If you read the site because of the .NET Compact Framework or other "useful" content this may seem ridiculous to you.  Never you mind, games are some of the most complex systems you can write today, presenting very complex design challenges.  Consider it a mental workout.

Of course, if I have fun with this I will try to make a product out of it...



Monday, May 30, 2005 12:38:14 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Thursday, May 26, 2005

Saw this in the google searches today, this one is somewhat tricky.  I haven't looked yet but I am hoping they have fixed this in .NET 2 with Template methods.

So, you have a class that you are displaying in either your own designer or at design time in Visual Studio.  One of the properties on this class is a collection that contains members of a Type you have created.  When you click the ellipses (...) button next to this property in the property grid, the designer Adds and Removes instances of System.Object in the collection, which is not very useful.  Here's how I got this to work, with examples from the very neglected TRAP project:

First, instead of something like ArrayList for the type of the property containing the collection items, I created a class that implements CollectionBase, IList, ICollection.  Take note of the class-level attributes

    [Editor("DamonPayne.Trap.UI.PersistentPropertyEditor", "System.Drawing.Design.UITypeEditor")
    ]
    public class PersistentPropertyCollection : CollectionBase, IList, ICollection    

then, these designer attributes on the property of this type:

        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always),
        Editor(typeof(PersistentPropertyEditor), typeof(System.Drawing.Design.UITypeEditor) ),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Description("Collection of Properties that are persisted to the data store")
        ]
        public PersistentPropertyCollection PersistentProperties
        {
            get{return _persisentProperties;}
            set{_persisentProperties = value;}
        }

Now, on the type contained within my PersistentPropertyCollection (PersistentProperty), I have the following designer attributes:

    [TypeConverter(typeof(PersistentPropertyConverter)),
    EditorBrowsable(EditorBrowsableState.Always), Category("Misc"),
    ]
    public class PersistentProperty

The PersistentPropertyConverter is just a class that extends ExpandableObjectConverter and implments custom functionality.  That part is not important for this example.

The final code snippet here is the most important part.  When providing implemntations for some of the IList, etc members, I do not use the type Object but rather my own concrete type:

(...)    
    public PersistentProperty this[int index] // Indexer
        {
(...)
        public void Remove(PersistentProperty value)
        {
            _list.Remove(value);
        }

        public void Remove(object value)
        {
            _list.Remove(value);
        }
(...)
        public int Add(PersistentProperty value)
        {
            return _list.Add(value);
        }

        public int Add(object value)
        {
            if (_list.Contains(value))
            {
                return -1;
            }
            return _list.Add(value);
        }

        public void AddRange(PersistentProperty[] items)
        {
            foreach(PersistentProperty p in items)
            {
                Add(p);
            }
        }
(...)

Notice that for some of these the methods are overloaded for type Object and my concrete type.  The designer is able to figure it out, and voila, my custom collection editor for the TRAP gui looks like so:

I'll have to post more on .NET designer stuff when I get the chance.



Thursday, May 26, 2005 3:36:49 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [5]  |  Trackback

I'm not sure if I've mentioned before how much I love delegates, but I do.  I made a new friend today in the form of System.Predicate<T>, another powerful aspect of the generics support in .NET 2.

A Predicate is a delegate wraps a method that accepts an instance of the Teplate type and returns whether or not the specific instance matches whatever condition the predicate represents.  Many of the framework classes in .NET 2 work with the Predicate<T> generic.  One example might be a generic List<T>,

(...)
public World(Device dev)
{
_device = dev;
WorldEntities = new List<Entity>(100);
_removePredicate = new Predicate<Entity>(ShouldRemove);
}
(...)
public List<Entity> WorldEntities;
private Device _device;
private Predicate<Entity> _removePredicate;
(...)
protected void RemoveDisposed()
{
WorldEntities.RemoveAll(_removePredicate);
}

protected bool ShouldRemove(Entity target)
{
return target.IsDisposed;
}
(...)

That is the first use I came across, but obviously there are many other saucy uses for this.  Obviously you could do something almost this good in .NET 1, but the strong typing of the parameter class is what makes it cool.



Thursday, May 26, 2005 2:56:13 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Before Beta 2 came out I had been reading that SQL Mobile databases and the System.Data.SqlServerCe namespace would work from the full .NET 2 framework.  Once I actually tried this I could find very little conversation on the subject, except for here.  I tried exactly what this author had done and I was getting all kinds of assembly loading errors. I was finally able to access a .sdf database from my winforms app, but I'm not happy with the solution.

Beta 2 installs several System.Data.SqlServerCe .Dll files.  The one that will actually load from a desktop winforms application is in C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\, with a description of "Microsoft SQL Mobile" and version 9.0.242.0.  When I tried this at first, I was still getting errors thrown out of this assembly with descriptions like "sqlcese.sys.dll".  In the same IDE directory mentioned above there are several .DLL files with similar names.  I was ultimately able to get my SqlCe connection to work by copying some of these to my application's bin\Debug directory:

  • sqlceca30.dll
  • sqlcecompact30.dll
  • sqlceer30en.dll
  • sqlceme30.dll
  • sqlceoledb30.dll
  • sqlceqp30.dll
  • sqlcese30.dll

This is the part I'm not happy with.  The fact that the .DLL that works is in a visual studio directory and apparently needs some other DLLs from the same to run probably means one of two things.  Either my Beta 2 installation is slightly funky, or Sql Mobile from Full framework is not going to be something you can do on a computer without Visual Studio installed.  I hope the latter is not the case.  It would be very nice to be able to use Sql Mobile instead of access, and also to be able to use the power of a desktop PC to build .SDF databases.  I have not messed with the bulk copy functionality in Sql Server 2005 yet, so perhaps that is easy to automate.  Again though, this implies you should be able to use a .SDF datbase from desktop code.



Thursday, May 26, 2005 9:00:14 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Wednesday, May 25, 2005

As many of you nerds know, DasBlog has a feature whereby it will record search strings used by search engines to reach your site.  Its become part of my daily entertainment to look at this list and click back to the referring searches.  Some of the items are scary or ridiculous like "Damon payne milwaukee salary last year" but a lot of them are related to content I've posted, which is cool.

A lot of the search items are looking for questions I did not answer but could answer easily.  I may make this part of my daily routine to post an answer to something that was the topic of someone's search but not already on my site.  A lot of these are compact framework/smartphone questions but some other interesting things as well.



Wednesday, May 25, 2005 7:56:43 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, May 24, 2005

OK, so, I've had a chance to mess with Direct 3D more.  As soon as you figure out basically how to draw 1 thing on the screen and you want to experiment, its best to create some kind of framework.  It would be nice to draw a scene, isolate your experiment to one class, and make it easy to add/remove/alter a particular aspect of the scene you are drawing.  A dynamic scene could be rendered given the following metaphors:

An Entity class that represents any draw-able item.  The Entity is responsible for loading its vertices, points, textures, etc.  A non-staic light source could also be an entity in which case the Entity would load its color information etc.  The Entity could be an abstract base class.  Entities are added to a World which represents all the dynamic items that could be rendered.  While Entities might not be visible at all times (View Coordinates, World Coordinates, Painter's Algorithm discussions in future posts) they might be thinking/acting elsewhere so they need periodic chances to do something even if they are not visible.  A simple DirectX program/Render loop might go like this:

  1. Initialize Device and drawing surface properties
  2. Create a World
  3. Create some Entity objects to go in the world
    1. Entity objects load their Model (vertices, colors, textures, etc) information
    2. Entities are given a reference to the Device so that they can Render themselves later.
  4. While your World is running
    1. Given each item a chance to update itself
    2. Process user input if applicable
    3. Begin a scene
    4. Tell each item to Render itself
    5. Do lights/effects passes etc
    6. End Scene
    7. Present Scene
    8. Repeat

All in all, the render loop for a simple game/simulation might be pretty simple.  The internet could use a lot more sample code for Direct3D, at least I've been unable to find much on how various things are typically done.  For example, when an Entity changes position in the World is it customary to rebuild it or to Transform its vertices to reflect the new position?  From what I can see, Transformations are used to model the observer changing its view position from one place to another, yet, rebuilding a vertex list seems very inefficient.  Consider this partial snippet for drawing a triangle with 3 vertices and some color:

...
class MovingTriangle : Entity
{
private CustomVertex.TransformedColored[] _verts;
private VertexBuffer _vertBuffer;
private float _topX;

...

public override void Render(Microsoft.DirectX.Direct3D.Device dev)
{
dev.SetStreamSource(0, _vertBuffer, 0);
dev.VertexFormat = CustomVertex.TransformedColored.Format;
dev.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}

public override void DeviceAquire()
{
_vertBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, _dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);
_vertBuffer.Created += new EventHandler(_vertBuffer_Created);
_vertBuffer_Created(null, EventArgs.Empty);
}

void _vertBuffer_Created(object sender, EventArgs e)
{
DoCreateBuffer();
}

private void DoCreateBuffer()
{
GraphicsStream stream = _vertBuffer.Lock(0, 0, 0);
_verts = new CustomVertex.TransformedColored[3];

_verts[0].X = _topX;
_verts[0].Y = 50;
_verts[0].Z = -0;
_verts[0].Rhw = 1;
_verts[0].Color = System.Drawing.Color.Red.ToArgb();
//
_verts[1].X = _topX + 100;
_verts[1].Y = 250;
_verts[1].Z = -0;
_verts[1].Rhw = 1;
_verts[1].Color = System.Drawing.Color.Red.ToArgb();
//
_verts[2].X = _topX - 100;
_verts[2].Y = 250;
_verts[2].Z = -0;
_verts[2].Rhw = 1;
_verts[2].Color = System.Drawing.Color.Red.ToArgb();

stream.Write(_verts);
_vertBuffer.Unlock();
}
}
...

It seems as though vertex recreation would be horribly inefficient.  I just ordered a pile of DirectX books from my favorite online store to shed some light on common D3D practices.  As soon as I get through the next chapter in my Physics book I can share the nature of my ridiculous DirectX test project.

 



Tuesday, May 24, 2005 9:58:40 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [5]  |  Trackback
 Monday, May 23, 2005

 After passing it at B&N several times I picked this book up yesterday.  I really enjoyed my Physics in college but of course being in a hurry to graduate left no time for pursuing any interesting things.  I do regret that my physics class was not Calculus based.  When I did take Calculus the physics applications were by far the most interesting parts.  When we were shown that the first derrivative of the acceleration function is the distance function I was blown away as it was the first time I'd ever seen a mathematical idea (derrivatives) explain not a phenomenon in reality (If the train is going 100 km/h and the city is 50 km away...) but an actual aspect of reality.

Back to the book, I just started reading the first few chapters: a refresher on basic physics.  More impressions as I read through it but you can probably expect to see a DamonPayne.Physics C# library posted here. 

When picking this book up I also realized how utterly ludicrous it is that the English measurement system is still in use.  Over the course of the year, I'm going to try to convert to thinking of things in terms of Kilometers to my house and my car's 0-100km acceleration time.



Monday, May 23, 2005 8:06:15 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Tuesday, May 10, 2005
Cage Builders


Monday, May 09, 2005 11:00:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, April 22, 2005
VB.NET Part 1


Thursday, April 21, 2005 11:00:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, April 13, 2005
CLR Performance


Tuesday, April 12, 2005 11:00:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, April 11, 2005
Smartphone Impressions


Sunday, April 10, 2005 11:00:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Wednesday, April 06, 2005
Smartphone


Tuesday, April 05, 2005 11:00:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, March 29, 2005
carmack on Java


Tuesday, March 29, 2005 12:00:00 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, March 07, 2005
Multi key sort with custom Types


Monday, March 07, 2005 12:00:00 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, February 21, 2005
Will code for food


Monday, February 21, 2005 12:00:00 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Sunday, February 13, 2005
Product keys


Sunday, February 13, 2005 12:00:00 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Friday, February 11, 2005
Slacking


Friday, February 11, 2005 12:00:00 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Thursday, December 09, 2004
New Blog is almost done


Thursday, December 09, 2004 12:00:00 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Friday, December 03, 2004
Sorting Custom Types in code


Friday, December 03, 2004 12:00:00 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [5]  |  Trackback
I am not famous


Friday, December 03, 2004 12:00:00 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback