Run ClickOnce app on startup
· 2009-08-26 14:07 by Thijs Kroesbergen for Brokenwire.NET
While toying with a small ClickOnce application I found out that there wasn’t an easy way to launch the app automatically on Windows startup. Of course I wasn’t the first one to have this problem so I started reading Ben Griswold aka Johnny Coder’s blog post on this topic. He sums up the pros and cons of several solutions nicely. (So go read that now, I’ll wait here.)
After trying out some of his suggestions I came up with the following plan:
I’ll put a shortcut in the Startup folder of the start menu. This shortcut will point to the executable file of my application, but it will start it with an additional parameter (“-L”). When the application detects that it is being run with this parameter it doesn’t show any of its forms, but just starts the .appref-ms shortcut that is already in the start menu. This shortcut will then start the application just as if the user him/herself clicked it.
The good thing about this solution is that this also fools Vista in starting a ClickOnce app on startup (so it WORKS!).
Why is this the best solution?
- If you start the executable directly from the Startup folder (without having it launch itself via the .appref-ms) then the application isn’t “ClickOnce-enabled” any more, and it won’t function properly.
- If you put a shortcut the to the .appref-ms file in the startup folder the application won’t start on Vista.
- If you put a shortcut to the deployment URL in the startup folder a browser window will be opened.
One small drawback: if the application is uninstalled then the shortcut in the startup folder will be left behind…
Code, show me code! Okay, so here is the code:
To install the shortcut in the startup folder of the start menu I’ve written this Install method. The ShellLink class is a wrapper around the windows API to make a shortcut. The corresponding article about creating and modifying shortcuts using C# can be found on vbaccelerator.com.
public static void Install() { ShellLink shortcut = new ShellLink(); shortcut.Target = Application.ExecutablePath; shortcut.Arguments = "-l"; shortcut.WorkingDirectory = Path.GetDirectoryName(Application.ExecutablePath); shortcut.Description = "Start TestApp"; shortcut.DisplayMode = ShellLink.LinkDisplayMode.edmMinimized; shortcut.Save(shortcutFileName); }
Then to have the application launch itself, I've modified the Main method in Program.cs:
/// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { if (args.Contains("-L")) { AppLauncher.Launch(); } else { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new TestForm()); } }
The “Launch” method that finds the shortcut for the ClickOnce application and starts it via Process.Start. The determination of the location of the .appref-ms file can be a bit tricky, this code works for me but your mileage may vary.
public static void Launch() { string shortcutFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), "Start TestApp.lnk"); string publisherName = Application.CompanyName; string productName = Application.ProductName; string allProgramsPath = Environment.GetFolderPath(Environment.SpecialFolder.Programs); string shortcutPath = Path.Combine(allProgramsPath, publisherName); shortcutPath = Path.Combine(shortcutPath, productName) + ".appref-ms"; System.Diagnostics.Process.Start(shortcutPath); }
You can try it out for yourself with this small sample:
ClickOnceStartupTestApp.zip which is also published here: http://www.brokenwire.net/~thijs/clickoncestartup/publish.htm
Have fun!
The madness of “exclusive” row locks
· 2009-06-24 15:19 by Thijs Kroesbergen for Brokenwire.NET
Yesterday I discovered some really weird behavior of SQL Server. I had a case where I could read a record that was exclusively locked by someone else. Considering the word “exclusive” you would expect that when one transaction has an exclusive rowlock an other transaction would be unable to read that same row. But there is one specific case where this isn’t true. In that case it is possible to read a record that is locked exclusively by someone else.
It took me (together with a colleague) a lot of time to finally find out what was happening.
To reproduce this behavior you need a test-table with some random data in it.
CREATE TABLE [MyTable] ([Col1] bigint PRIMARY KEY CLUSTERED, [Col2] bigint) INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (1,10) INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (2,20) INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (3,30) INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (4,40) INSERT INTO [MyTable] ([Col1], [Col2]) VALUES (5,50)
You can put this table in any database, as long as it doesn’t have snapshot isolation turned on. The recovery model for your database doesn’t matter.
Now let’s run some queries and see what happens. To be able to test this properly you should run two different session against this table. To be able to hold (and see) the locks that used you need to start a transaction and run some statements, but don’t complete the transaction (yet).
First in the first window of the Query Analyzer (which I’ll refer to as session 1) select one row from the table and request an exclusive rowlock on it with the XLOCK and ROWLOCK table hints.
session 1:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED BEGIN TRAN SELECT Col1 FROM [MyTable] WITH (XLOCK, ROWLOCK) WHERE [Col1] = 3
To verify the locks that where put into place you can run sp_locks to check the locks that are granted to the connection (spid) that you used to perform the actions for session 1.
spid dbid ObjId IndId Type Resource Mode Status ------ ------ ----------- ------ ---- -------------------------------- -------- ------ 56 21 69575286 1 PAG 1:41 IX GRANT 56 21 69575286 1 KEY (030075275214) X GRANT 56 21 69575286 0 TAB IX GRANT
As you can see there is an “X” (exclusive) lock on the first key of this table. (The other locks are “IX” (intentional)). Now let’s move to session 2 and see if we can we retrieve that record.
session 2:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED BEGIN TRAN SELECT Col1 FROM [MyTable] WHERE [Col1] = 3
I did expected this statement to just “hang” while waiting for the record to come available. But I was surprised to see that the record could be retrieved without a problem. Also, sp_locks doesn’t show any additional locks for this statement, not even a shared lock!
If you rollback session 2 (to clear everything that might have happened) and retry it with the HOLDLOCK table hint you do get the expected behavior, because the select in session 2 now will wait for the transaction in session 1 to complete.
To understand what is happening here you should remember one of the rules of read committed data access. This rule says that you can read any row as long as it’s in a committed state. The row we’re trying to read here is in a “clean” state (it’s not marked “dirty” by the system). In this case the optimizer decides that it doesn’t hurt to retrieve it via the index without checking for locks. So your table doesn’t even need a primary key, a long as you have an index containing the requested data the rowlocks may be skipped at will.
So if the locked record has not changed and the data for requested columns is stored in an index and you are working from an READ COMMITTED isolation level then the exclusive lock is possibly not honored.
One possible workaround is to add a “HOLDLOCK” table hint to the select in session 2. Alternatively you can actually update the record to have it exclusively locked (and marked “dirty”) in session 1. The last possibility is to lock an entire page instead of just one row by using the PAGLOCK hint. Exclusive page locks do prevent all other readers for the rows in that page.
There’s a thread on http://social.msdn.microsoft.com/ posted by someone who has observed the same weird locking behavior. A Microsoft employee responded with:
Using XLOCK in SELECT statements will not prevent reads from happening. This is because SQL Server has a special optimization under read committed isolation level that checks if the row is dirty or not and ignores the xlock if the row has not changed. Since this is acceptable under the read committed isolation level semantics it is by design.
Perhaps the worst thing about all this is that this behavior cannot be found easily in the Books Online. A small note somewhere in the section about table hints would have be nice. There are some hints in KB324417 (which applies to Sql Server 2000). Combine all that with the fact that the optimizer may choose to do this at will, you’ll have a very hard to find bug in your sql code.
Conclusion:
It took me a lot of time to find out what was going on here. So remember kids: a SELECT with XLOCK and ROWLOCK hints doesn’t mean that you are the only one who can read those rows!
Pimp my software
· 2009-06-23 09:00 by Thijs Kroesbergen for Brokenwire.NET
Everyone who has done some (serious?) software development knows that we have several different methods to run our project. We also know that not all methods are equally successful. But one of our favorite things to do is compare our ways of doing things with others in the more “traditional” trades.
So a little while ago I was watching MTV’s "Pimp My Ride", and then I was thinking, what would software development look like if we did it the “Pimp My Ride” way?
So let’s see what that would look like. For those of you who don’t know the Pimp My Ride TV show, it goes like this:
The show starts by showing a teenager with a banged up car. That car gets picked up by the shows host and brought to a garage. Then a team of mechanics goes wild on the car by remodeling it completely. Then the owner is brought in, the car is presented and a happy guy (or girl) leaves the shop with a new ride. If you want to see this for yourself, take a look at the MTV website.
Now let’s break that down into the parties involved. The core group of people involved is of course the team of mechanics. This team designs and builds the car. The way this team is composed is that several people with different specialties are brought together in the right mix. In our world this would be team of highly skilled software engineers. This way each member should have its own specialty like data-access, user interfaces and such. Perhaps the most important thing to notice is that all team members are involved from start to finish.
Then there’s the host of the show, he gets to pick up the car, monitor the work on it and deliver it back to the owner. In the software development world this could be the project manager with a bit of help from some sales guy perhaps.
Last but not least we have the owner of the crappy car. This is comparable our customer, who has a problem (a crappy car, or some complex business process) and needs someone to solve it for him.
That wraps up the parties involved, now lets move to the process.
At the start of each episode (project) the old car gets picked up from some lucky bastard by the presenter of the show, a rapper known as “Xzibit”. They chat a bit and X gets a pretty good idea about the likes and dislikes of the car’s owner. This translates to an combination of sales and analysis. There’s communication with the customer, and both the scope and the requirements are set. For example, the owner drives a VW Beetle (scope) and likes to sing (requirement).
Once this is done the car is brought back to the garage and the whole team gets to take a good look at it. Then they sit together and each specialist tells what he thinks that needs to be done to the car.
Lets see how that meeting works out…
Paint specialist:
“I’m gonna put on a base layer of toxic green paint, and then I’ll airbrush some hot flames on the side of this wicked car!”
User Interface guy:
“I’m going to design a WPF based interface with nice glowing buttons which animate on mouse-over”
Engine tuner:
“Let’s upgrade the engine so it can do 0-60mph in 2.9 seconds! For that I’ll use this nice turbocharger kit.”
Database guru:
“I recommend that we store our data in a clustered SQL Server database, and we’ll use LINQ for our data access layer. This way we will have performance and speedy development all at once!”
You get the point ;). This meeting is like the project kickoff. Here the architecture is determined and the individual components are defined.
Then they get to work. Each specialist does what he does best, and they work together as the gears of a well oiled machine. Sometimes they encounter something unexpected, but with all the knowledge they have on board they will continue to deliver the finished product right on schedule. This is actually exactly the same thing that is (or should be) happening in any software delivery process.
Finally during the last minutes before the car’s owner arrives the finishing touches, such as polishing the car, are applied. Then the big unveiling takes place, and a happy customer leaves the building.
“You’ve officially been pimped”
The handover of the car’s keys translates to the delivery phase in our world. This where the happy customer accepts the finished product. And a happy customer is what we are aiming for!
To conclude this rant, lets see why this “Pimp My Ride” process should work for software as well:
- We both do the same trick over and over again. Almost every application is an assembly of standard components, just like a car is build of standardized parts.
- A mechanic is just as much an expert in his field of work as a software engineer is. We know what we are doing…
- Both teams are used to delivering a the project in a fixed (or rather, predictable) amount of time.
- In the end a happy (paying) customer is all that matters. The customer tells what he wants, and that is just what he’ll get.
But of course there are some differences as well, so why doesn’t this work for software?
- The “architecture” of a car hasn’t really changed in the last decades (Or has it…?), for software we have many different solution for many different problems. So is creating software that much more complex?
- If you get back your once-rusty now-pimped car for free, without cash involved, you are not going to be very picky about requirements. Software is usually well paid for, so the delivered product has to live up to much more well defined expectations. Does this mean we can’t educate our customers on what to expect? Have you ever seen them building a flying car? No? Maybe because it IS possible, but its just very hard to get right. Now compare that to software, how many times do we say something just isn’t possible?
- Perhaps the size of software development projects isn’t as consistent as the size of a pimping-a-car project is. Some project are like building a bike, others could be the size of building a complete cruise ship. Then again, for completing such a huge project you need to split it up in manageable chunks anyway. So the real question is, how big should a project be to have the optimal size?
- We tend to separate our teams in architects, designers and builders. But in the Pimp My Ride team each member is a specialist in both designing and building his part, from start to finish.
It looks like this comparison doesn’t hold up too well (but I had fun trying it anyway). I do think that we like to over-complicate things because with software it’s so easy to create anything our mind can come up with. And because of our human nature we just love to try stuff that hasn’t been done before. Perhaps, given some more time and thought, the expectations for software will become just as clear as the expectations we have of a car.
So what do you think? Does any of this make sense? Is building software harder then building a custom car? Are we spoiled by all the options we have and do we over-complicate?
New feature: Webslice
· 2009-04-20 14:31 by Thijs Kroesbergen for Brokenwire.NET
Brokenwire.NET now has it’s own webslice. You may wonder what a webslice is. Remember 1997 ? That’s when we had snippets of web pages on our active desktop! Well a web slice is just that, it’s a piece of information from a site inside a small window in your browser. Internet Explorer 8 is the only browser that supports these things right now.
When you have installed the slice on you browser’s favorites bar it will look like this:
So if you have IE8 you can click on the small link in the right sidebar on this site to add the Brokenwire.NET webslice to your own browser.
Creating such a slice is very easy, with some help of this blogpost about webslices I was able to do this in 10 minutes.
The basic HTML structure:
<html><head> <title>Page Title</title> </head><body> <div class="hslice" id="techologynews"> <h2 class="entry-title">IE 8 web slice</h2> <div class="entry-content"> <p><a href='#'>Link 1</a></p> <p><a href='#'>Link 2</a></p> <p><a href='#'>Link 3</a></p> </div></div> </body></html>
The basic rules:
- The WebSlice must use the class name hslice in the container.
- Each WebSlice must contain an ID in the container. This is how the WebSlice will be differentiated from others on the page.
- The WebSlice must have at least one entry-title element defined. This will be displayed both in the page and in the feed button that appear in the Favorites Bar when a user subscribes to the WebSlice.
- While not required, each WebSlice should contain at least one entry-content element. This is the information that will appear when the user selects the WebSlice from their Favorites Bar.
There is also an official Microsoft whitepaper about webslices.
I wonder if anybody is actually going to use this, but it was a nice thing to play with for a bit.
Enjoy!
Quick Visual Studio Tip
· 2009-04-19 14:07 by Thijs Kroesbergen for Brokenwire.NET
Press CTRL + SHIFT + V to cycle through previous clipboard entries (and paste them). This way you can “cut” several pieces of code, and “paste” them somewhere else without going back and forth. (You could also use “copy” multiple times and then use this to “paste” that, but of course nobody is interested in copying code…)
There are more hotkeys in Visual Studio that are not so well known, take a look here.
Decrypting Sql 2005 SPs made easy
· 2009-03-25 15:05 by Thijs Kroesbergen for Brokenwire.NET
Today I ran across a problem where I desperately needed to peek inside a stored procedure used by Team Foundation Server. The only trouble was that the stored procedure was created with the “WITH ENCRYPTION” clause appended, so I couldn’t see the source.
To decrypt the stored procedure I used a stored procedure called dbo.sp_SpDeObfuscation, which can be found here and/or downloaded here.
Please keep in mind that you need to run the SP from an DAC (Dedicated Admin Connection)