[Slim-Checkins] r11852 - in /branches/6.5: platforms/win32/SlimTray.pl server/Slim/Utils/Prefs.pm

adrian at svn.slimdevices.com adrian at svn.slimdevices.com
Sat Apr 28 10:16:35 PDT 2007


Author: adrian
Date: Sat Apr 28 10:16:34 2007
New Revision: 11852

URL: http://svn.slimdevices.com?rev=11852&view=rev
Log:
Bug: 4748, 4898, 4899, 4905 potential improvements
Description: Hopefully improve operation on Vista when running UAC
- prefs and server url moved to location which is not virtualised by
Vista (as per r11828)
- modify options available in SlimTray when run as a user - don't show
options which require installing/starting/stopping a service, start
manually as an app rather than service
- add info menu option that SlimTray can be started with "run as admin" to
enable all previous options

Note this version will not stop mysqld when run as a user and the
server is stopped.  To do this would require killing a process called
'mysqld' without knowing whether this is the slim mysqld!


Modified:
    branches/6.5/platforms/win32/SlimTray.pl
    branches/6.5/server/Slim/Utils/Prefs.pm

Modified: branches/6.5/platforms/win32/SlimTray.pl
URL: http://svn.slimdevices.com/branches/6.5/platforms/win32/SlimTray.pl?rev=11852&r1=11851&r2=11852&view=diff
==============================================================================
--- branches/6.5/platforms/win32/SlimTray.pl (original)
+++ branches/6.5/platforms/win32/SlimTray.pl Sat Apr 28 10:16:34 2007
@@ -31,6 +31,19 @@
 use Win32::TieRegistry ('Delimiter' => '/');
 use Win32::Service;
 
+
+# Vista only:
+#
+# When running on Vista SlimTray may be run as a normal user or as administrator depending on how it is started
+# With the default install it will run as admin the first time when launched from the installer, all subsequent times it will
+# run as a normal user.  Vista UAC means that we can only install windows services and start/stop them when running as admin.
+# To avoid user confusion we therefore disable all options which are not available when running as a normal user.
+#
+# prefs and the Slimserver url are stored in a different location on Vista to avoid Vista file virtualisation.
+
+my $vista          = ((Win32::GetOSName())[0] =~ /Vista/);  # running on Vista
+my $vistaUser      = $vista && !Win32::IsAdminUser();       # running on Vista as a user (not admin) - reduce menu options
+
 my $timerSecs      = 10;
 my $ssActive       = 0;
 my $starting       = 0;
@@ -46,7 +59,8 @@
 
 my $serviceName    = 'slimsvc';
 my $sqlServiceName = 'SlimServerMySQL';
-my $appExe         = File::Spec->catdir(baseDir(), 'server', 'slim.exe');
+my $appExe         = File::Spec->catdir(installDir(), 'server', 'slim.exe');
+my $serverUrl      = File::Spec->catdir(writableDir(), "SlimServer Web Interface.url");
 
 my $errString      = 'SlimServer Failed. Please see the Event Viewer & Contact Support';
 
@@ -56,16 +70,22 @@
 sub PopupMenu {
 	my @menu = ();
 
+	my $type = startupType(); # = none, login, manual or auto
+
+	# As a user on Vista we only allow the following as these are all a user can perform:
+	# - starting/stopping of the server if type is none, login
+	# - toggling of startup type between login and none
+
 	if ($ssActive) {
 		push @menu, ["*Open SlimServer",\&openSlimServer]; 
 		push @menu, ["--------"];
-		push @menu, ["Stop SlimServer", \&stopSlimServerMySQL];
+		push @menu, ["Stop SlimServer", \&stopSlimServerMySQL] if (!$vistaUser || $type =~ /none|login/);
 	}
 	elsif ($starting) {
 		push @menu, ["Starting SlimServer...", ""];
 	}
 	else {
-		push @menu, ["*Start SlimServer", \&startSlimServer];
+		push @menu, ["*Start SlimServer", \&startSlimServer] if (!$vistaUser || $type =~ /none|login/);
 	}
 
 	my $serviceString = 'Automatically run at system start';
@@ -84,31 +104,35 @@
 		$setLogin  = sub { setStartupType('login') };
 	}
 
-	# Startup can be in one of three states: At boot (service), at login
-	# (app), or Off, which leaves the service installed in a manual state. 
-	my $type = startupType();
-
 	if ($type eq 'login') {
 
-		push @menu, ["_ $serviceString", $setAuto, undef];
+		push @menu, ["_ $serviceString", $setAuto, undef] unless $vistaUser;
 		push @menu, ["v $appString", $setManual, 1];
 
 	} elsif ($type eq 'auto') {
 
-		push @menu, ["v $serviceString", $setManual, 1];
+		push @menu, ["v $serviceString", $setManual, 1] unless $vistaUser;
+		push @menu, ["_ $appString", $setLogin, undef]  unless $vistaUser;
+
+	} else {
+
+		push @menu, ["_ $serviceString", $setAuto, undef] unless $vistaUser;
 		push @menu, ["_ $appString", $setLogin, undef];
-
-	} else {
-
-		push @menu, ["_ $serviceString", $setAuto, undef];
-		push @menu, ["_ $appString", $setLogin, undef];
-	}
+	}
+
+	push @menu, ["Additional Options", \&vistaHelp] if $vistaUser;
 
 	push @menu, ["--------"];
 	push @menu, ["Go to Web Site", "Execute 'http://www.slimdevices.com'"];
 	push @menu, ["E&xit", "exit"];
-	
+
 	return \@menu;
+}
+
+sub vistaHelp {
+	my $msg = "As you are running on Windows Vista some menu options are disabled.\nRestart with 'Run as administrator' to access all options.";
+
+	MessageBox($msg, "SlimServer", MB_OK | MB_ICONINFORMATION);
 }
 
 # Called when the tray application is invoked again. This can handle
@@ -158,7 +182,7 @@
 		# If we were waiting for SS to start before this check, show the SS home page.
 		if (checkForHTTP()) {
 
-			Execute("SlimServer Web Interface.url");
+			Execute($serverUrl);
 
 		} else {
 
@@ -169,7 +193,7 @@
 
 		$checkHTTP = 0;
 
-		Execute("SlimServer Web Interface.url");
+		Execute($serverUrl);
 	}
 
 	# Check if user has requested to stop SlimServer And MySQL
@@ -181,19 +205,17 @@
 
 		if (scalar keys %status != 0) {
 
-			# Service already stopped
 			if ($status{'CurrentState'} == 1) {
 
-				$stopMySQL = 0;
-				return;
-			}
-
-			if (Win32::Service::StopService('', $sqlServiceName)) {
-
-		   		$stopMySQL = 0;
-				return;
+				# Service already stopped
+
+			} elsif (Win32::Service::StopService('', $sqlServiceName)) {
+
+				# Sucessfully stopped service
 
 			} else {
+
+				# Service running which we can't stop
 
 				my $t = 'GetStatus Failed';
 
@@ -208,7 +230,6 @@
 			}
 		}
 
-		# MySQL service is not running - perhaps slimserver is started at system level.
    		$stopMySQL = 0;
 	}
 }
@@ -237,19 +258,22 @@
 	# Add paths if they don't exist.
 	my $startupType = startupType();
 
-	if ($startupType eq 'none') {
+	if (!$startupType) {
+
+		# NB running Vista as a user means we can't read this - we hope the first run is as admin
+		my $serviceStart = $Registry->{"LMachine/SYSTEM/CurrentControlSet/Services/$serviceName/Start"};
 
 		my $cKey = $Registry->{'CUser/Software/'};
 		my $lKey = $Registry->{'LMachine/Software/'};
 
 		$cKey->{'SlimDevices/'} = {
 			'SlimServer/' => {
-				'/StartAtBoot'  => 0,
+				'/StartAtBoot'  => ($serviceStart && oct($serviceStart) == 2) ? 1 : 0,
 				'/StartAtLogin' => 0,
 			},
 		};
 
-		$lKey->{'SlimDevices/'} = { 'SlimServer/' => { '/Path' => baseDir() } };
+		$lKey->{'SlimDevices/'} = { 'SlimServer/' => { '/Path' => installDir() } };
 	}
 
 	# If we're set to Start at Login, do it, but only if the process isn't
@@ -281,10 +305,15 @@
 		} else {
 
 			# Don't launch the browser if we start at login time.
-			Execute("SlimServer Web Interface.url");
+			Execute($serverUrl);
 		}
 
 		$cliStart = 0;
+	}
+
+	if ($vistaUser && !$ssActive && $startupType eq 'auto') {
+		# running as a user on Vista so we can't start a service, fallback to running as an app
+		setStartupType('none');
 	}
 }
 
@@ -329,8 +358,12 @@
 
 		if (!Win32::Service::StartService('', $serviceName)) {
 
-			# can't start as a service - try starting as a process
-			runBackground($appExe);
+			showErrorMessage("Starting $errString");
+
+			$starting = 0;
+			$ssActive = 0;
+
+			return;
 		}
 
 	} else {
@@ -349,11 +382,16 @@
 
 sub stopSlimServer {
 
-	if (startupTypeIsService() && Win32::Service::StopService('', $serviceName)) {
-
-		# service stopped
-
-	}  else {
+	if (startupTypeIsService()) {
+
+		if (!Win32::Service::StopService('', $serviceName)) {
+
+			showErrorMessage("Stopping $errString");
+
+			return;
+		}
+
+	} else {
 
 		my $pid = processID();
 
@@ -380,7 +418,7 @@
 
 	# Check HTTP first in case slimserver has changed the HTTP port while running
 	checkForHTTP ();	
-	Execute("SlimServer Web Interface.url");
+	Execute($serverUrl);
 }
 
 sub stopSlimServerMySQL {
@@ -414,6 +452,10 @@
 	my $atBoot  = $Registry->{"$registryKey/StartAtBoot"};
 	my $atLogin = $Registry->{"$registryKey/StartAtLogin"};
 
+	if (!defined $atBoot || !defined $atLogin) {
+		return undef;
+	}
+	
 	if ($atLogin) {
 		return 'login';
 	}
@@ -427,6 +469,11 @@
 			# Start of 2 is auto, 3 is manual.
 			return oct($serviceStart) == 2 ? 'auto' : 'manual';
 		}
+
+		if ($vistaUser) {
+			# Vista users can't read the registry key for $serviceStart - assume auto [we can't manually start the service]
+			return 'auto';
+		}
 	}
 
 	return 'none';
@@ -472,7 +519,7 @@
 }
 
 # Return the SlimServer install directory.
-sub baseDir {
+sub installDir {
 
 	# Try and find it in the registry.
 	# This is a system-wide registry key.
@@ -483,20 +530,31 @@
 	}
 
 	# Otherwise look in the standard location.
-	my $baseDir = File::Spec->catdir('C:\Program Files', 'SlimServer');
+	my $installDir = File::Spec->catdir('C:\Program Files', 'SlimServer');
 
 	# If it's not there, use the current working directory.
-	if (!-d $baseDir) {
-
-		$baseDir = cwd();
-	}
-
-	return $baseDir;
+	if (!-d $installDir) {
+
+		$installDir = cwd();
+	}
+
+	return $installDir;
+}
+
+# Return directory for files which Slimserver can save - i.e. location of prefs file
+# This is the server dir unless we are running on Vista when it is %ALLUSERSPROFILE%\SlimServer
+sub writableDir {
+
+	if ($vista) {
+		return File::Spec->catdir($ENV{'ALLUSERSPROFILE'}, 'SlimServer');
+	}
+
+	return File::Spec->catdir(installDir(), 'server');
 }
 
 sub checkForHTTP {
 
-	my $prefFile = File::Spec->catdir(baseDir(), 'server', 'slimserver.pref');
+	my $prefFile = File::Spec->catdir(writableDir(), 'slimserver.pref');
 	my $httpPort = 9000;
 
 	# Quick and dirty finding of the httpport. Faster than loading YAML.
@@ -608,18 +666,16 @@
 #  One parameter the new port number
 
 sub updateSlimServerWebInterface {
-	my $port    = shift;
-
-	my $urlfile = File::Spec->catfile(baseDir(), "SlimServer Web Interface.url");
-
-	if (open(URLFILE, ">:crlf", $urlfile)) {
+	my $port = shift;
+
+	if (open(URLFILE, ">:crlf", $serverUrl)) {
 
 		print URLFILE "[InternetShortcut]\nURL=http://127.0.0.1:$port\n";
 		close URLFILE;
 
 	} else {
 
-		showErrorMessage("Can't open to write to $urlfile: $!");	
+		showErrorMessage("Can't open to write to $serverUrl: $!");	
 	}
 }
 

Modified: branches/6.5/server/Slim/Utils/Prefs.pm
URL: http://svn.slimdevices.com/branches/6.5/server/Slim/Utils/Prefs.pm?rev=11852&r1=11851&r2=11852&view=diff
==============================================================================
--- branches/6.5/server/Slim/Utils/Prefs.pm (original)
+++ branches/6.5/server/Slim/Utils/Prefs.pm Sat Apr 28 10:16:34 2007
@@ -1048,6 +1048,18 @@
 
 	if (Slim::Utils::OSDetect::OS() eq 'win')  {	
 		$prefsFile = catdir($pref_path, 'slimserver.pref');
+
+		# copy over old prefs file to new location on Vista, excluding cachedir (which is moved too)
+		if (!-r $prefsFile && Slim::Utils::OSDetect::details->{'osName'} =~ /Vista/ && -r catdir($Bin, 'slimserver.pref')) {
+			open OLD, catdir($Bin, 'slimserver.pref');
+			open NEW, ">$prefsFile";
+			while (my $line = <OLD>) {
+				print NEW $line unless $line =~ /cachedir/;
+			}
+			close OLD;
+			close NEW;
+		}
+
 	} elsif (Slim::Utils::OSDetect::OS() eq 'mac') {
 		$prefsFile = catdir($pref_path, 'slimserver.pref');
 	} else {



More information about the checkins mailing list