Sharing Google Picasa Libraries between users on the same computer

After a few years of using Adobe Photoshop Elements, last year we switched over to using Google’s free Picasa for organising our photo collection. Consecutive versions of Photoshop Elements were just getting slower and slower mainly it seemed due to waiting for the ‘kewl’ interface to redraw itself. Picasa is really slick and fast on our 2.8GHz Pentium 4 home PC. It can also upload our photos for printing to PhotoBox, and share them online using Google’s own Picasa Web Albums.

Photoshop Elements keeps all of your photo tags and collections in a ‘*.psa’ database file (which is actually Microsoft Access database). The useful thing we found about this was that we could share all our photo collection settings and tags between users. Picasa, on the other hand, stores its settings in hidden Picasa.ini files in your photo directories as well as in your local app settings user profile folder (buried in ‘Documents and Settings’ on Windows XP or the ‘Users’ folder on Vista). The problem with this is that you can’t share your Picasa library between users on the same machine as Picasa is hard-coded to look in the currently logged on user’s profile directory, and can’t be coaxed to look elsewhere, such as a shared location.

So to workaround this, you can take advantage of a feature of NTFS called junctions, which allow you to wire up one folder to another (or symbolic links, I’m not sure what the difference is, but the end result is the same). Windows Vista has a command-line tool called MKLINK which will create these. On Windows XP you will need to use the Sysinternals Junction command-line tool. Here’s what I did:

  1. Copy %LocalAppData%GooglePicasa2 and Picasa2Albums to a shared location to which all users will have Modify access. (I chose C:UsersPublicAppDataLocalGoogle on Vista, it’d be something like C:Documents and SettingsPublic on XP)
  2. Rename %LocalAppData%GooglePicasa2 and Picasa2Albums e.g. “Picasa2.old” and “Picasa2Albums.old”
  3. Use MKLINK (Vista) or Junction (XP) to create a junction from
    %LocalAppData%GooglePicasa2 to
    <SharedLocation>GooglePicasa2
    and:
    %LocalAppData%GooglePicasa2Albums to <SharedLocation>GooglePicasa2Albums
  4. Repeat steps 2-3 for each user for whom you want to share the Picasa library

Of course this may break with a future version of Picasa, so proceed with caution and don’t blame me if it all goes horribly wrong.

Shortcut to Switch User in Windows Vista

At home, our PC running Vista is rarely rebooted and is either in a low power state sleeping or being used by either me or my wife. One thing we’ve taken great advantage since the XP days is Fast User Switching which allows someone else to log in to their desktop whilst yours is kept running in the background. My wife and I had got quite used to doing a quick WinKey+L (as you do) before relinquishing control of the PC to one another. In Windows XP WinKey+L is does a “lock workstation” which in non-domain machines takes you back to the Windows logon screen. Unfortunately on Vista it takes you to a “workstation locked” screen, so you then have another mouse click on the Switch User button (followed by monitor re-syncing itself – why does it do this? All users run at the same screen resolution) to take you to the users screen. Of course there is a “Switch User” command tucked away in the little menu next to the lock button on the start menu – but a quick keystroke is what we’re after here.

So – I go off searching for a shortcut key that does a “switch user” rather than “lock workstation”. After a 20 minutes fruitless Googling for some special key combination, I sat back, thought about it logically and came up with this solution:

  1. Create a shortcut on your desktop to TSDISCON (* see below) and call it something like “Switch User”
  2. Go the shortcut Properties page and assign a shortcut key. Note that unfortunately you can’t use the Windows Key in your shortcut – so I went for CTRL + ALT + SHIFT + L
  3. Right click Start button and choose “Open All Users” and move the shortcut into the Programs folder (confirming the UAC prompt as you go).
  4. Log out, and back in again. This is necessary because Explorer hasn’t noticed there’s now a shortcut with a new shortcut key it should be taking notice of.

And that did it. CTRL + ALT + SHIFT + L isn’t quite a neat as WinKey+L but it’s a hell of a lot better than poking around in the Start Menu.

* What is TSDISCON you ask? It’s the Terminal Services Disconnect command. Fast User Switching is all made possible by the core Terminal Services technologies which introduced the concept of multiple Window Stations or “sessions” running concurrently on the one machine. It was of course originally designed to support multiple users connecting concurrently to these sessions over the network using the Remote Desktop Protocol (RDP), but Windows XP took advantage of the multi-session architecture to enable Fast User Switching. (The RDP stuff is still there but hobbled to only allow one user to connect at a a time.)

UPDATE: If you don’t have tsdiscon.exe on your system for some reason (maybe it’s only available in Business/Ultimate or something) then you can use the following C# code (compiled into a Windows EXE using C:WindowsMicrosoft.NETFrameworkv2.0.50727csc.exe if you don’t have Visual Studio) to do the same thing. Tsdiscon.exe is just a wrapper around WTSDisconnectSession. I used Dependency Walker (aka depends.exe) to find out what was being used:

UPDATE 2: For your convenience: I’ve compiled the below and packaged it into a ZIP along with the source for download here.

using System;
using System.Runtime.InteropServices;
using System.ComponentModel;

class Program
{
  [DllImport(&quot;wtsapi32.dll&quot;, SetLastError = true)]
  static extern bool WTSDisconnectSession(IntPtr hServer, int sessionId, bool bWait);

  const int WTS_CURRENT_SESSION = -1;
  static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

  static void Main(string[] args)
  {
    if (!WTSDisconnectSession(WTS_CURRENT_SERVER_HANDLE,
         WTS_CURRENT_SESSION, false))
      throw new Win32Exception();
  }
}

Microsoft Search Server and FAST

Microsoft have a new server product: Search Server 2008. Well I say “new” but it seems to be based the same technology they’ve been pushing since the days of Site Server, on which I spent most of the late 1990’s travelling the world doing training and consulting. The same technology is used in Index Server, SQL Server Full Text Search, SharePoint, and even Windows Desktop Search.

It’s a workmanlike search technology, but I think people are so used to Google being so effective on the Internet that when they come to search their intranet using these technologies they come up short. You have to do a bit more wading through useless hits before you find what you’re looking for. In fact it’s a bit like going back the bad old days of AltaVista, et al before Google revolutionised search with PageRank.

This begs the question how good any intranet search solution could be (including Google’s own Search Appliance) on a intranet that consists of file shares and SharePoint document libraries containing mostly Word documents, Excel spreadsheets, etc, with nary a hyperlink in sight. How would you get something like PageRank, which relies on incoming links to help rank content, working with a “corpus” (in search parlance) such as this?

So, Microsoft have now pretty much admitted that their search technology needs some work, because they’ve just shelled out $1.2 billion for FAST,a Norwegian search technology company. Or should that be “bailed out” as FAST seem to have had some financial difficulties recently? It’ll be interesting to see if FAST’s technology, when they integrate it, is more effective than Microsoft’s current offerings.

Fixing Vista folder annoyances

I found this gem in Dan Maharry’s RSS feed as part of his del.icio.us bookmarks. It’s a few registry edits to stop Windows Explorer auto-selecting a different folder view based on its content, e.g. normally if a folder happens to have a GIF or JPEG in it, Explorer will “helpfully” switch to thumbnail view.

Keith Miller posted a registry tweaks in the TechNet forums which I’ve rolled up here (mostly for for my own convenience) into a single batch file which also restarts Explorer:

setlocal

set BASE_KEY=HKCUSoftwareClassesLocal SettingsSoftwareMicrosoftWindowsShell

:: Delete cached folder views
reg delete "%BASE_KEY%Bags" /f
reg delete "%BASE_KEY%BagMRU" /f 

:: Set default folder template
reg add "%BASE_KEY%BagsAllFoldersShell" /v FolderType /d NotSpecified

:: Restart Explorer
taskkill /f /im explorer.exe
start explorer.exe

If you don’t know what a batch file is or how to use it then you shouldn’t be using this :-p. Likewise, it works for me but your mileage may vary…

WCF JSON Serialization is flawed

I’m working on a little internal app that involves some AJAX-y callbacks to the server for data. The data is returned in JSON format for easy consumption by the client side code and is being generated with very un-sexy Response.Writes, whose output looks something like this:

{
   "jbloggs" : 
   {
      fullName : "Fred Bloggs",
      title : "Chief Burger Flipper",
      tel : "512"
   },
   "jdoe" : 
   {
      fullName : "Jane Doe",
      title : "Assistant Burger Flipper",
      tel : "587"
   },
   ...
}

This works nicely as a information can be looked up on the client in JavaScript like so:

var person = peopleJson["jbloggs"];
alert(person.fullName);

Dead easy. JavaScript objects are just dictionaries/hash tables.

Now I was aware that Windows Communication Foundation (WCF) services can now do JSON serialization in .NET 3.5, so I thought I’d swap out my low-tech Response.Writes for a WCF Service that would let me come up with structures in my server-side code that would be serialized automatically to JSON. But I found that the the way WCF (which ultimately uses DataContractJsonSerializer) serializes Dictionaries is a bit lame. This is what it came up with:

[
   {
      "Key":"jbloggs",
      "Value":
      {
         fullName : "Joe Bloggs",
         title : "Chief Burger Flipper",
         tel : "512"
      }
   },
   {
      "Key":"jdoe",
      "Value":
      {
         fullName : "John Doe",
         title : "Assistant Burger Flipper",
         tel : "587"
      }
   },
   ...
]

Odd. Dictionaries are serialised as arrays of objects whose members consist of a Key and Value. So in order to look up an entry I’d have to do a linear search through this array. I mean, you would have thought the fact there is dictionary functionality built-in to the JavaScript Object prototype (in fact, fundamental to JavaScript) – that it would be the sensible format to use rather than the Key/Value format. I just can’t quite see why Microsoft thought that this Key/Value format was necessary as it’s such a pain to consume on the client.

Looks like my low-tech Response.Writes are going to get a stay of execution for the time being.

SQL Server database space usage

Ever wanted to know what the biggest table in your database is, and what the other space hogs are? There is the sp_spaceused system stored procedure that either shows headline stats for the database as a whole, or those for a particular table. Annoyingly it doesn’t tell you which table is taking up all the space relative to all the others. If you have SQL Server SP2 installed then it ups SQL Management Studio

So, here’s a T-SQL batch that shows all the space taken up by tables in the current database. The main column to look at is “Total size”, which is a sum of the Data size, Index size and Unused columns.

SET NOCOUNT ON
DBCC UPDATEUSAGE(0)
CREATE TABLE #spaceused
(
    Name nvarchar(255),
    Rows int,
    [Total size] varchar(50),
    [Data size] varchar(50),
    [Index size] varchar(50),
    Unused varchar(50)
)
DECLARE @table_name nvarchar(255) 

DECLARE tables_cursor CURSOR LOCAL FORWARD_ONLY FOR
    SELECT name FROM sysobjects WHERE type='U'
OPEN tables_cursor
FETCH NEXT FROM tables_cursor INTO @table_name
WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO #spaceused EXEC sp_spaceused @table_name
    FETCH NEXT FROM tables_cursor INTO @table_name
END

SELECT * FROM #spaceused
    ORDER BY CONVERT(int, LEFT([Total size],
                     CHARINDEX(' KB', [Total size]))) DESC 

DROP TABLE #spaceused
CLOSE tables_cursor
DEALLOCATE tables_cursor

Of note is the very useful INSERT INTO table EXEC proc technique for capturing the output of a stored proc.

The script works on SQL Server 2000 and 2005 (and possibly later).

Exchange 2007 – Custom IP Block List Provider Error Message

We use Microsoft Exchange 2007 at InfoBasis for email, and for my sins I have to manage it. It seems a little enterprisey unwieldy at times for an organisation as small as ours but the Outlook calendaring integration is a must for us and I’ve mostly worked out how it works and how to keep it running happily (thanks to Brian Reid of C7 Solutions who helped us implement it).

We use the built-in anti-spam filtering – specifically the IP Block Listing, aka “DNS blacklist” (or DNSBL) to block emails from known spam sources. I won’t explain how to set it up here as there are plenty of other resources that cover this. Because occasionally we’d get a false positive (eg. from a legitimate AOL or Yahoo account) I was investigating how to write Transport/Edge providers to provide some sort of dynamic spam white list functionality which didn’t seem to be provided out of the box. In so doing I discovered that most of the Exchange 2007 code base seems to have been re-written in .NET (which may explain why some feel it was released unfinished/too early). So I pointed Lutz Roeder’s .NET Reflector (which reverse-engineers .NET DLLs) at a few of the Exchange Server DLLs in Program FilesMicrosoftExchange ServerBin and had a snoop around. Thankfully, I eventually stumbled on the Update-Safelist PowerShell cmdlet which does white listing based on Outlook’s Safe Senders – so I didn’t have to write any code after all.

Anyway, on my travels I came across ConnectionFilteringAgent.BlockListDnsCallback (in the Microsoft.Exchange.Transport.Agent.ConnectionFiltering namespace) in Microsoft.Exchange.Transport.Agent.Hygiene.dll. This method formats the message that gets returned to the senders mail server should they be listed by a DNSBL. This was of interest because in Exchange 2003 you could use format codes in the error message (e.g. “The IP address %0 was rejected by black list %2”) to help legitimate email senders work out why their email was blocked (as documented in KB 823866). But, I couldn’t find any documentation on how to use similar format codes in Exchange 2007 – but here in BlockListDnsCallback was this line of code:

message = string.Format((string) provider.RejectionResponse,
   this.queryData.hostIP,
   this.queryData.provider.Name,
   this.queryData.provider.LookupDomain);

Which means you can use the following sort of custom error message in Exchange Management Console > Organization Configuration > Hub Transport > Anti-spam > IP Block List Providers > Edit > Error Messages:

Your IP address {0} has been found on '{1}' (looked up on {2})

Hope that helps!