Here are some options I found that worked for me when I tried them on my machine:
- Add a new sub-key under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx (or the same sub-key under HKEY_CURRENT_USER if you want the assemblies to appear only for the current user instead of all users). The default value of the sub-key should be the folder path that you want Visual Studio to look in for assemblies to include in the Add References dialog. This registry path is specific to VS 2005 and the .NET Framework 2.0 and will not work for previous versions of VS or the .NET Framework. It is documented in this MSDN document.
- Add a new sub-key under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders (or the same sub-key under HKEY_CURRENT_USER if you want the assemblies to appear only for the current user instead of all users). The default value of the sub-key should be the folder path that you want Visual Studio to look in for assemblies to include in the Add References dialog. This registry path is global and any folders listed here will be processed by VS .NET 2002, VS .NET 2003 and VS 2005 as well as the .NET Framework 1.0, 1.1 and 2.0. It is documented in this KB article.
- Place a copy of the file in the folder c:\Program Files\Microsoft Visual Studio 8\Common7\IDE\PublicAssemblies. This path is dependent on the version of Visual Studio that you have installed and whether or not you installed it to the default path, so you may need to adjust it as needed for your system. The path that I list is for a default install of VS 2005.
[Aaron Stebner's WebLog]
Tuesday, November 29, 2005
Monday, November 28, 2005
A counterstring is a graduated string of arbitrary length. No matter where you are in the string, you always know the character position. This comes in handy when you are pasting huge strings into fields and they get truncated at a certain point. You want to know how many characters that is.
Here is a 35 character counterstring:
Each asterisk in the string occurs at a position specified by the immediately preceding number. Thus, the asterisk following the 29 is the 29th character in that string. So, you can chop the end of the string anywhere, and you know exactly where it was cut. Without having to count, you know that the string "2*4*6*8*11*14*17*2" has exactly 18 characters in it. This saves some effort when you're dealing with a half million characters. I pasted a 4000 character counterstring into the address field of Explorer and it was truncated at "2045*20", meaning that 2047 characters were pasted.
I realize this is may not be a very interesting sort of testing, except perhaps for security purposes or when you're first getting to know the app. But security is an increasingly important issue in our field, and sometimes when no one tells you the limits and dynamics of text fields, this can come in handy.[James Bach's Blog (Testing)]
This is a really cool and simple way to verify the length of an entry field in an application. He also has a small applet, downloadable from that blog entry, that will let you create counterstrings of various patterns. I may code a clone up in Delphi for my own nefarious purposes.
Friday, November 25, 2005
I'm not sure why Microsoft went that way, but it's tied to how the Windows Installer works. A Windows Installer file (.msi) installs just one install of itself. If you try running it again, the installer locates itself on the machine and brings the installer up in maintenance mode. It's not designed to let you install multiple copies of a single application. If you want to do that, you have to go down the multiple instance transform route. A multiple instance transform file (.mst) is basicly the difference between two .msi files. You use the .mst file to change some of the values in a .msi file so that it gets considered to be a different installer by the Windows Installer runtime. By that's a whole 'nother story in and of itself.
Because each instance is essentially a separate installation, you don't want to mess around with the source installer bits. Otherwise, you'll make it difficult to install patches or upgrades. I'm pretty sure that's why Microsoft prefers that you to use their executable to install SQL Server/MSDE/Express. If you use the .msi files, then the patches have be generated against the .msi files that you used. If you merged the SQL Server .msi into your .msi, then upgrades to SQL Server on that machine will required your .msi file. Ouch.
Each instance has to have a .mst file, it's a one to one relationship. I'm not sure what MS is doing under the hood in the SQL Server install process, but my guess is that it's creating .mst files at runtime when you specify an instance name. Otherwise it have to include X number of .mst files in the package, and if they did that some twisted person would try to install X+1 instances and break the installer. Creating a .mst file on the fly is doable, but it's not something I would want to implement. When the user specifies a new instance you need to take your .msi installer file, copy it to a new .msi file. Then you modify that .msi file with the instance name, increment a property, and generate a new product GUID. You then generate the .mst file from the difference between the original .msi file and the new one. After that, you delete the new .msi file, it's no longer needed. Then you call msiexec with the .msi file and the .mst with the appropriate parameters. I'm not sure that you could reliably generate installer patches (.msp files) under that scenario.
I'm not a fan of how Microsoft implemented the multiple instances. When I wrote the server end of e-Link, I used the Windows Installer to install the service. If the user wants to install a second instance of e-Link, they can use an administration utility that I wrote that can register additional instances of the service, but using the same executable. It provides the same functionality to the user, but only requires one set of files. This makes updating the service much easier as the patch only has to target one installed instance.
I can see why MS went along the single instance route with Windows Installer. It prevents the user from accidently installing 8 copies of "Hunt the Wumpus". It makes it easy to allow installers to repair existing installations or modify the original setup. It does makes some tasks extremely difficult for installing. The big thing that I can see what would require multiple installs are web sites. There you could have multiple installations as people usually install a web a couple of times to try different settings, of have "live" and "staging" versions of a site.
If you want to install a web site with Windows Installer multiple times on the same machine, you have a few choices.
- You could limit the install to a single instance. If the user wants multiple copies of the web site files, they have to do that part manually. We do that with the web gui end of e-Link and we document how to do it. Another way (which I have not tried) would be to rename the web site or virtual directory and it the physical name of the folder that it was installed into. Then run the installer again. It will come up in maintenance mode and you would select repair and it should install another set of files into the previously selected location. The draw to both methods is that the installer will repair or uninstall only the files it knows about. If you add anything manually, then you must remove it manually.
- You could supply a fixed number of instance transforms. If you do this, you'll need an intelligent front end application to your installer so that you can prompt the user for the instance name. Then you have to check to see if that instance is already installed. If not, then you get the next available instance number and see if you have enough transfoms to use one for this install. Lots of error checking required here, it's not something I would want to do.
- You could generate instance transforms at run time. Much of the same logic as the previous option, plus the additional work of creating the transform. I definitely don't want to ever have to do this.
This is why you don't see many .msi files for installing web sites.
Trackback to Dana's post
Wednesday, November 23, 2005
Following, is the method that I use to determine if a user is an Administrator. Note that in .NET 1.0/1.1 the using construct wrapped around the creation of the WindowsIdentity won't compile as its implementation of IDisposable is new for .NET 2.0. Previously you had to rely on the finalizer of the object to run so that the handle of the user token could be freed.using System;
public static bool IsAdministrator
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
WindowsPrincipal wp = new WindowsPrincipal(identity);
There is also a check to determine if the operating system is secure (ie Windows NT platform) - the documentation states that the IsInRole method returns no results on Windows 98 and Windows Millennium Edition. I'm not entirely sure how a method that returns a boolean value can return no results, so it is wrapped in the Secure check just in case an exception is thrown when using it on Windows 9x/ME.
from [Managed from down under]
Monday, November 21, 2005
Writing in-process \shell extensions in managed code is actually a very dangerous thing to do because it has the effect of injecting your managed code (and the .NET Framework) into every application on the machine that has a file open dialog.
The problems occur because only one version of the .NET Framework can be loaded in a process at any given time (other shared components such as java and msxml have the same property and thus the same restriction).
If you write your shell extension using the 2.0 .NET Framework and an application built with the 1.1 .NET Framework uses a file open dialog, your shell extension will fail because it can not run on an earlier version. Things can get even worse if your shell-extension manages to get loaded in a process before another applications managed code does: your extension may force an existing application onto a different runtime version than the one it was expecting and cause it to fail.
Because of these problems we strongly recomend against using any single-instance-per-process runtime or library (such as the .NET Framework, java, or msxml) in an in-process shell extension.
The study is worth reading, the testing methodology was objective and at pretty much validates what fonts you think should be used for a given type of web site. The other good tip in Jeff's post was that Software Usability Research Laboratory (SURL) at Wichita State has an excellent newsletter that documents their usability studies.
This is stuff isn't directly applicable to our development patterns, but it has some useful information.
"Grayscreen" prototyping (building a simple HTML model of a website) provides an extremely effective way of communicating a website's content, structure, and functionality before design and programming begin. Prototyping overcomes many other difficulties commonly associated with web development, such as managing expectations, communicating effectively, working through the design process, and creating and delivering content.It's another example of how design up front methods save time and money.
Good article plus a free book in PDF format.
Thursday, November 17, 2005
Wednesday, November 16, 2005
These problems left me stranded for days, then today, on another machine, I hit a different set of problems I kept getting the following "Failed to generate user instance of SQL Server due to a failure in starting the process for the user instance. The connection will be closed." and if I set "User Instance" to false the following "An attempt to attach an auto-named database for file C:\[app_path]\ASPNetDB.mdf failed. A database with the same name exists, or specified file cannot be opened, or it is located on UNC share."
If you don't want to follow the link, the short answer is that SQLExpress creates a directory per user in "c:\Documents and Settings\[user]\Local Settings\Application Data\Microsoft\Microsoft SQL Server Data\SQLEXPRESS" that it uses to store information. Deleting this directory has fixed both of my problems.
[from Enjoy Every Sandwich]
A customer from Las Vegas DevConnections asks:
It seems like, but I may be mistaken, that you said something about posting some new set of toolbar icons on your blog? Was I in a Vegas-induced stupor or did you really say that?
To install the Visual Studio 2005 Image Library
Locate the file VS2005ImageLibrary.zip. This file is normally installed in \...\Program Files\Microsoft Visual Studio 8\Common7\VS2005ImageLibrary\.
- Right-click VS2005ImageLibrary.zip and click Extract All.
- The Extraction Wizard appears.
- Follow the directions in the wizard to extract the images.
It looks like, this is something you'll need the full Visual Studio install for - the zip file does not install with the Express editions of Visual Studio.
[via jfo's coding]
Tuesday, November 15, 2005
One of the adjustments to make when moving from ASP.NET 1.1 to 2.0 is how to produce debug and release builds.....
Here is the most important concept to come to terms with in 2.0: Visual Studio 2005 knows nothing about compiling a web application. In 1.1 VS built the code-behind and ASP.NET built the web forms. In 2.0 Visual Studio 2005 delegates all compilation responsibilities to the ASP.NET platform.....
Jump here for the full article, it neatly describes what has changed and how it works. He doesn't go into why it changed, that's the part I don't get. What's the advantage of the new build method? In the end, as long as I can get FinalBuilder to build it, I'll be happy.
Monday, November 14, 2005
I’m a loyal Canadian. I enjoy Tim Hortons, and don’t mind the Canadian Tire guy. But as Canadians, I think we need to get the message across to Americans that we’re not all that much different from them, and not that far away.
Why do I say this? Because one too many times I’ve been shopping online, found the exact product I want, and then find the dreaded statement:
Sorry, we are able to ship (and mail printed catalogs) only to the US, its territories and possessions, and APO or FPO addresses.
Why? Why why why?
What you need to do is convince FedEx and/or UPS to offer virtual mail addresses. Packages sent to a virtual address would automaticly get forwarded to a real Canadian address, with the recipient paying the additional fees. It's mailbox forwarding, except with non virtual bits. It's a win-win situation for everyone. Steve gets his reasonably priced borosilicate lab glassware, the vendor makes a new sale, and the delivery company makes a few dollars (or loonies).
I hope folks understand that by following a few simple rules and creating a defect report that you would like to get is actually you contributing to your own success. In this one case I have to say that karma is the best way to describe this process. But paying it forward and actually becoming a part of the solution, it will all eventually come back to you. Even though you may think your contribution is tiny and insignificant, the fact of the matter is that your contribution when compounded with everyone else's can pay back in large dividends.
Having been on both ends of the defect report, I completely concur with Allen. A long time ago (and in a galaxy far away), I was moonlighted as the tech support "department" for a well known reporting package that used to be installed with Delphi. On average, I would get between 30 to 60 emails a day from other developers who bought this package. It never failed to amaze me how hard it would be to get people to send specific information to duplicate a badly worded or vague bug description. Mind you, this reporting package had plenty of issues to deal with, but many times I couldn't duplicate the bug that was reported by the description that was included. I would usually send a followup email asking for the steps required to duplicate the bug.
I tried to avoid getting sent entire projects. This was 1997-2000, and I was doing support from a dialup account, it woul take forever to download everyone's projects as they usually sent me everything, binary files included. Sometimes, I needed the full project to duplicate the problem. That part was always interesting, you learn that the users will use the code in ways that you did not expect. There were always a few people who would refuse to provide detailed information and I would get a ranting email about not wanting to peform QA work for free. I actually received an invoice from one guy for the "services" that he had provided in tracking down the problem. [more about that when I finally decide to blog about that job].
On the other end of the spectrum, I spent a considerable amount of time documenting flaws in Sybase's ADO provider for Adaptive Server Anywhere. In the beginning, they wouldn't take my bug reports seriously. They would tell me that it was a Delphi ADO issue and not a problem with their provider. The problems were not with Delphi or it's ADO components, but they couldn't duplicate the bugs from my descriptions and they were not inclined to look at Delphi source code. I ended up coding detailed examples as VBScript files. One of the nice things about ADO was that it behaved the same way no matter who it called it. With those examples, I was able to get Sybase to spend time tracking down the problems that I was having. They were never able to fix those problems, but I did appreciate their efforts. What came out of those examples was that I was using Sybase's ADO provider in a different way than they were testing and apparently, their testing did not include all of the features supported by the provider.
Friday, November 11, 2005
One of the nice new features you get in .NET 2.0 Winforms is the new BackgroundWorker component. It allows safely executing long tasks in a different thread than the GUI, while allowing an easy event-driven interface to perform the task and respond to events (such as detecting work progress). There are even versions of this for .NET 1.1 courtesy of Juval Lowy.One of the things it does not support is the ability to Cancel the running task immediately rather than waiting for the code to process the Cancel Request (which is vital if your "DoWork" code contains tasks that individually take a long time to process). With some Reflectoring, I was able to overcome this obstacle and provide a solution for this problem.For the full details and download in VB.NET and C#, read the full article:[ISerializable - Roy Osherove's Blog]
[Update] There's a good article by Juval Löwy, titled Asynchronous Windows Forms Programming that covers this in great detail
Michael Campbell has blogged about removing data from a table in chunks http://sqladvice.com/blogs/repeatableread/archive/2005/09/20/12795.aspx. This can be simplified even further in SQL Server 2005
DELETE TOP (2000) FROM MyBigTableWHERE someCondition = true ORDER BY Dateolumn ASC
[ via WebLogs @ SqlJunkies.com]
Thursday, November 10, 2005
On a slightly separate target, why RSS Bandit is such a resource hog? I loved the interface, but it would bring the performace of my PC to a flying stop. I just started using Omea Reader, and it plays well with others much better than RSS Bandit did.
....Microsoft promosed that DLL Hell would go away, but with the .NET Framework betas, they dropped us into the biggest DLL Hell I’ve ever seen. I can’t uninstall MSH from my system because I installed the .NET Framework 2.0, which required that I uninstall the beta versions. The MSH uninstaller requires the beta framework, which I uninstalled, so I’m stuck. I can’t install the release version of MSH. This sort of thing is just silly, and I thought it was a problem that we’d solved. (To be fair, they did promise that this won’t be a problem for release versions of the framework, but how many millions of times were the betas downloaded?)
from Stevex's blog
Wednesday, November 09, 2005
tasklist /svc /fi "imagename eq svchost.exe"
That will list each instance of svchost.exe with all of the services being run by that instance.
Forbidden Planet has always been one of my favorite movies. As a kid, I always wanted my very own "Robbie the Robot". If I start playing the lottery, I can now order one from the Hammacher Schlemmer catalog for the mere sum of $49,999.95.
Robbie was a cool robot. None of this wimpy C-3PO nonsense. Robbie embodied the cutting edge of 1950's computer technology. Vacuum tubes glowing, relays clacking, and don't forget little metal spinning things on the side of his head. That's a man's robot.
I know a few people who were deeply affected by that movie. There used to be an audio store just outside of Albany, NY, named "Altair Audio". It was named after the planet Altair IV. It was actually a decent place, they carried the high end stuff and knew how to sell it. And of course, they carried the Krell line of amplifiers.
And the movie had Leslie Neilsen back when he was known as a dramatic actor. It's hard to watch him in serious roles after seeing Airplane and the Naked Gun shows/movies. I actually Leslie Neilsen once. About 15 years agao, I went to Irvine CA to visit my brother. On the way back, I flew out of John Wayne (aka Santa Ana) airport. While I was waiting for my fliight, I saw a production crew fiming a commercial. The commercial featured Leslie Neilsen. He had a break in the filming and I walked up to him and introduced my self. He was very gracious and we chatted for a minute or two. I was probably stammering like an idiot. I was too nervous to get a picture of the two of us. I do have a blurry picture of the back of his head.
Then a couple of older women came up. They were huge fans of his dramatic roles and they just kept talking and talking. They would ask him a question and then talk about something else before he could answer. And that's when the fun began. Mr. Neilsen had a llittle device in his suit jacket pocket that made fart sounds. He would stand there and smile at the women or make small talk, and at the same time, he was pressing the button on the fart sound device. The women didn't know how to react. They were trying to get their cues from Leslie, but he played it straight. I wanted to laugh so hard, I was dying. If he was goiing to play it straight, I was going to do so. I wanted to see how far he could take this. After a few minutes, I had to leave to catch my flight. I never knew how far he was able to play the gag, but I still laugh to myself just picturing it in my head.
Monday, November 07, 2005
The latest addition to the story is still worth reading. The company that wrote the rootkit, First 4 Internet, responded to Mark in a comment on his blog. They address his concerns item by item, and of course, obsfuscate the issues. Mark's latest blog entry goes over First 4 Internet's comments, blowing huge gaping holes on each of their points. When this finally blows over, the Sony/First 4 Internet saga will be a text example of how NOT to address a growing PR disaster.
Thursday, November 03, 2005
After coming back to Cubeland from lunch, I saw a small package on my chair. It had airmail stamps and came from Middlesex, England. I had no idea what it was, so I ripped it open to find Boland's inflatable action figures. The images are courtesy of the crapmatic instant picture device. The top one is Delphi Man, lord of the cubicle. The lower picture is of Doctor Deadline, trusty companion of Delphi Man.
There are limited edition items, Borland only made 1000 of each one. So far they haven't turned up on eBay. Oddly enough, the website that advertised the super duo, www.delphisuperhero.com has been replaced with the Delphi 2006 web site. In addtion to registering to win the inflatable characters, there were PDF files that you could download and print your own.
Wednesday, November 02, 2005
Tuesday, November 01, 2005
I prefer to take a different tack for debugging a service. I separate the code of what the service is supposed to do from the actual service code. I'll build a Windows App (or Winforms app) that calls the same code that the service would call. It's much easier to debug the code from an application instead of a service. 99.9% of the time, the problem is not part of the service controller code, it's the in the code that service uses. The other 0.01% of the time where the problem is in the service creation code, I just add a lines to send data to the Windows event log. This technique works well for Win32 Delphi and .NET programming.