Tuesday, August 4, 2009

Constructors for VB.NET Modules


Did you know that you can have a constructor on a module? I first got the notion to try this after thinking about static constructors in C#. In C#, you can do something like this:

class Class1
{
private static int _magicNumber;

static Class1()
{
_magicNumber = 4;
}
}
So the next thing to try was to test this out in VB.NET:

Module Module1

Sub New()
Debug.WriteLine("New")
End Sub

Public Sub Test()
Debug.WriteLine("Test")
End Sub

Public Sub Test2()
Debug.WriteLine("Test2")
End Sub
End Module
Running this and calling the methods Test / Test2 (in that order) yields this:

New
Test
Test2

So as you might expect, the construct only gets called once, but is called before any members are accessed in the module. Handy!

Tuesday, June 30, 2009

Gettinginto MSBuild / TFS Build

As you will no doubt agree, it's handy as heck to be able to get a fresh installer for your app on demand. Right now our build is a relatively manual process that takes a number of hours to complete. It's inefficient and error prone. The answer - automation of course!

I've already set up our environment so that it will automatically build our code whenever somebody checks in - this is a good thing. However, we're thinking about moving to the next step and getting our installer to be automatically built. We're not sure exactly how we're going to do this yet, but the components are:
  • Our .NET solution (most of our code is here).
  • Some VB 6 code (just enough here to have to make the build interesting).
  • An InstallShield installer (and dealing with the InstallShield licensing nonsense).
Our main options are:
  • Create our own MSBuild setup with custom tasks. Getting this to happen on our build server would be ideal because then anyone on the team could make an installer through the TFS build interface.
  • Write a .NET app from scratch. Not quite as slick as using MSBuild (considering MSBuild was sort of designed to do just this sort of thing), but I'll take whatever works.
Just to keep track of the resources, here are some of the pages I'm looking at:
  • This deals with incorporating VB6 and MSBuild
  • This has some links for creating custom build steps
  • This is getting started with MSBuild
We need to check in some files, so here are some links for that:
More to come as we narrow down the solution.

Sunday, May 10, 2009

OPC at RVNUG: The code and the slides


First things first: Here is the code and here are the slides.

Thanks to everyone who attended (and participated in) my resent presentation on the Open Packaging Convention (OPC) at the Roanoke Valley .NET User Group (RVNUG). It was a rowdy group (my favorite kind) and it was a blast.

Besides coming up with various connotations for the words 'Package', 'Parts' and 'Stream', we discussed some handy ways to use OPC:
  • Exporting / backing up data
  • Storing a gallery of images with additional metadata (geocoding, timestamp information,etc)
  • Grouping together log files. This application seemed to generate the most interest.
OPC is a dirt simple way to store data in one place without needing a database.

Monday, April 20, 2009

DebuggerStepThroughAttribute

Let's say you have some code that often throws an exception, but you just swallow it and carry on. This is usually fine, unless you have your debugger set to break on. So take some code like this:

Public Shared ReadOnly Property IsInstalled() As Boolean
Get
Dim isInstalled As Boolean = False

Try
Dim temp as Object = CreateObject("Some.ActiveX")
isInstalled = True
Catch ex as Exception
End Try

Return isInstalled

End Get
End Property

If the COM object doesn't create properly, it will generate an exception. This sort of code is usually in the start up of an application, so you might have to hit this every time you debug your app. It's annoying.

However, if you add the handy attribute DebuggerStepThrough just before the Get clause:

Public Shared ReadOnly Property IsInstalled() As Boolean
<DebuggerStepThrough()> _
Get
Dim isInstalled As Boolean = False

Try
Dim temp as Object = CreateObject("Some.ActiveX")
isInstalled = True
Catch ex as Exception
End Try

Return isInstalled

End Get
End Property
Then Visual Studio just runs over the code like nothing ever happened.

Saturday, April 18, 2009

Roanoke Code Camp 2009 - The Code



Apologies for not getting this published sooner... Between getting ready to move houses and my normal level of laziness and procrastination, I haven't done it. It also took some Googling to figure out how to include code in a BlogSpot post. Enough whinging, here's the code for the OPC (Open Packaging Convention) class I did.

By the way, here is my DevX article on the same subject that got published recently.

Here is the code to create a package:

'Open the package
Using package As Package = package.Open("c:\Example.zip", IO.FileMode.OpenOrCreate)

'Create the uri for the text file
Dim uri As New Uri("/TextFiles/MyTextFile.Text", UriKind.RelativeOrAbsolute)

'Create the part for the text file
Dim part As PackagePart = package.CreatePart(uri, System.Net.Mime.MediaTypeNames.Text.Plain)

'Get the stream for the part
Using stream As Stream = part.GetStream()

'This is the text we'll put in the part
Dim myText As String = "This is an ugly picture of a flower - Roanoke!"

'We need to get the string into a byte array to make it easy to write to the part stream
Dim buffer As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(myText)

'Write to the part stream
stream.Write(buffer, 0, buffer.Length)

End Using

'This is the uri for the flower
Dim uri2 As New Uri("/Images/Flower.jpg", UriKind.RelativeOrAbsolute)

'Create the part for the image
Dim part2 As PackagePart = package.CreatePart(uri2, _
System.Net.Mime.MediaTypeNames.Image.Jpeg)

'Get the stream for this part
Using stream As Stream = part2.GetStream()

'Read the data from the file
Dim buffer As Byte() = File.ReadAllBytes("c:\Flower.jpg")

'write the data to the part
stream.Write(buffer, 0, buffer.Length)

End Using

'Create a relationship between the parts
Dim relationship As PackageRelationship = _
part2.CreateRelationship(part.Uri, TargetMode.Internal, "flower_to_text")

End Using

And here is the code to read that package:

 'Create the package
Using package As Package = package.Open("c:\Example.zip", IO.FileMode.Open)

'We know the Uri for the flower, so let's start there
Dim flowerUri As New Uri("/Images/Flower.jpg", UriKind.RelativeOrAbsolute)

'Get the part using the uri we just set up
Dim flowerPackagePart As PackagePart = _
package.GetPart(flowerUri)

'Create a relationship from the
Dim relationships As PackageRelationshipCollection = _
flowerPackagePart.GetRelationshipsByType("flower_to_text")

'Get the first relationship (in real code, we would want some error checking here)
Dim relationship As PackageRelationship = _
relationships(0)

'Get the part from the relationship (once again, this would need some
' error protection because in a real world app this part might not exist anymore).
Dim textPart As PackagePart = package.GetPart(relationship.TargetUri)

'Get the stream
Using stream As Stream = textPart.GetStream()

'Create a buffer
Dim buffer(stream.Length) As Byte

'Read the stream
stream.Read(buffer, 0, stream.Length)

'Read the text
Dim myText As String = System.Text.ASCIIEncoding.ASCII.GetString(buffer)

'Show the text (the crowd should go wild here)
MessageBox.Show(myText)

End Using

End Using

End Sub

Wednesday, March 18, 2009

WPF Designer causes Visual Studio to Close

Okay, so we all know that the WPF designer in Visual Studio 2008 is suboptimal. And if you didn't, now you know. Besides not being particularly user friendly, it's buggy as hell.

Today, while trying to demonstrate the basics of XAML / WPF, I was trying to show the design view of a WPF Window. The problem was, every time I opened the designer, the IDE would just close. No error, no beep, just gone. That was awesome.

Here are the things that I did that didn't solve the problem:
  • Cursed.
  • Rebuilt all.
  • Cleaned solution, then rebuilt all.
  • Manually cleaned the solution by deleting the bin and object folders under each project in the solution.
  • Closed the solution and deleted the .suo file (Solution Options File).
  • Closed the solution and deleted the project user files.
  • Rebooted.
  • Cursed when it still didn't work.
  • Contemplated Harakiri.
Here's what did work:
  • Deleted all of the temp files in the temp directory.
WTF? So in XP, here is the temp directory that was causing the issue (it's a different path in Vista):

C:\Documents and Settings\\Local Settings\Temp

There were like almost 5,000 files in that directory. Apparently, the designer creates temp files. My best theory is that tt will keep bogging down trying to find unique temp file names until one day it runs out of combinations. Then there is no call for help, no suicide note, it just quietly and inexplicably goes away. It doesn't even hang itself (no process remains in Task Manager).

I had discovered this fix many moons ago, and had of course forgotten about it until months later when my temp directory filled up.

Thursday, March 5, 2009

Nomadic Programming

No, I don't mean driving all around town to program... Which isn't to say that wouldn't be fun. This refers to the tendency for a team to work on almost every module of a product at the same time.

So, how do you tell if this is happening? Draw a picture of your project. Break down your project into its major components. Pick a color scheme. This one is pretty straightforward:
  • Red - the module hasn't been touched
  • Yellow - the module is in progress
  • Green - the module is code complete.
And you'll end up with something like this:



Holy crap - there are very few modules that are complete, and very few that are untouched. That means that the team is wandering all over the featurescape almost randomly coding on different modules. This approach has all sorts of dangers:
  • This makes it very hard to ever get a project done because no individual item ever is completed.
  • This approach leads to the "throw it over the wall to testing at the end of a long development" method. Not a good thing. For example, a fundamental flaw in design / implementation could have happened months ago and propagated to the rest of the product. That could easily lead to orders of magnitude to fix all of those issues.
If all is going well, we would expect to see a very small part of the diagram showing up in yellow (in progress) with the rest of the modules being either red (untouched) or green (completed).