I am maintaining an application which currently checks to see whether MS Access 2007 is installed. It does this by verifying that a registry key exists.
public bool IsAccess2007Installed()
{
RegistryKey rootKey = Registry.ClassesRoot.OpenSubKey(#"Access.Application.12\shell\open\command", false);
return rootKey != null;
}
How would I go about verifying whether MS Access 2010 is installed? Or better yet, how would I verify that MS Access 2007 or later is installed?
It is assumed that the user has administrator privileges.
You can check this key for a value (eg. Access.Application.12) instead.
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Access.Application\CurVer
So your line of code would be:
RegistryKey rootKey = Registry.ClassesRoot.OpenSubKey(#"Access.Application\CurVer", false);
if (rootKey == null) return false;
string value = rootKey.GetValue("").ToString();
int verNum = int.Parse(value.subString(value.indexOf("Access.Application.")));
if (value.StartsWith("Access.Application.") && verNum >= 12)
{ return true; }
Related
I have a Project and i am trying to run the installer on a new pc to test my WPF application, but the registry key is not automatically created. I have tried adding it manually but i don't know why it is not working, i am sure i am not adding the key the right way. Also i am confused since it is a new PC how do i add something that will automatically create a path?
The one that i am creating is something like this in the Image:
[VS Image][1]
HKLM -- do you have Admin right? really privileged rights?
How to test that you have enough right to write to HKLM (just call OpenSubKey):
public bool CanSetRegKeyValue(string path, string valueName, RegistryKey registry = null)
{
bool result = true;
try
{
RegistryKey registryKey = null;
if (registry == null)
{
registryKey = Registry.LocalMachine;
}
using (RegistryKey key = registryKey.OpenSubKey(path, true))
{
result = key != null;
}
}
catch (NullReferenceException)
{
result = false;
}
catch (SecurityException)
{
result = false;
}
return result;
}
and usage sample, which checking write ability to Key DefaultLevel under node HKLM\SOFTWARE\Policies\Microsoft\Windows\safer\codeidentifiers:
bool result = CanSetRegKeyValue("SOFTWARE\\Policies\\Microsoft\\Windows\\safer\\codeidentifiers\\", "DefaultLevel");
I develop VSTO add-in for Word, Excel etc.
And I need to get information about user currently logged in Office application.
I need at least an email address.
I found these properties Globals.ThisAddIn.Application.UserName, .UserInitials and .UserAddress. But it's not about LiveID account. It is about office user settings.
How can I get required information?
I found only one way to retrieve this information - read the Registry...
There are key HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Common\Identity\Identities\
if it is Office 2016. There are subkey like xxxxx_LiveId where xxxxx matches to ProviderId value.
You can read at least EmailAddress value from that subkey.
So I wrote some C# code for retrieve an e-mail address of logged in LiveID user:
string GetUserEmailFromOffice365()
{
string Version = "16.0"; //TODO get from AddIn
string identitySubKey = $#"Software\Microsoft\Office\{Version}\Common\Identity\Identities";
using (var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(identitySubKey))
{
if (key != null && key.SubKeyCount > 0)
{
foreach (var subkeyName in key.GetSubKeyNames())
{
using (var subkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($#"{identitySubKey}\{subkeyName}"))
{
object value = null;
try
{
value = subkey.GetValue("EmailAddress");
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
if (value != null && value is string)
{
return value as string;
}
}
}
}
}
return null;
}
Of cource you shouldn't hardcode Version value. You can get and remember office version from Globals.ThisAddIn.Application.Version in ThisAddIn.cs file in ThisAddIn_Startup method.
I am writing a VS extension which will need to communicate with a server and identify the user, and I figured that if possible, since this extension will be the only client connecting to the server, using Visual Studio's built-in support for Microsoft accounts would make more sense than implementing my own account management infrastructure.
At first, because of the variety of useful APIs available to a Visual Studio developer, one might think that getting info on the current user would be easy. However, there actually don't seem to be any obvious APIs that can be used to access accounts; I checked here and there weren't any related services listed (the "profile" services just allow you to read/write settings that are stored for the current user).
Does anyone know of a (relatively) simple way to access the Microsoft account from a Visual Studio extension?
EDIT
I tried Hadi Brais's suggestion, and at first it appeared to work (I successfully retrieved the information); however, each time, Visual Studio would crash about 30s afterward. I commented out the lines that interacted with the registry and replaced them with static values for the variables, and the crashes stopped. Clearly, accessing Visual Studio's registry keys was causing it to crash. I even tried using statements and other safeguards, however there doesn't seem to be a way to safely access the Visual Studio registry keys from an extension. So does anyone know of any official APIs that can be used to retrieve this information without crashing Visual Studio?
For Visual Studio 2015 (Version 14.0), this is how to get information about the user that is currently signed in in Visual Studio. You need to add using Microsoft.Win32;.
private static string GetUserEmailAddressVS14()
{
// It's a good practice to request explicit permission from
// the user that you want to use his email address and any
// other information. This enables the user to be in control
// of his/her privacy.
// Assuming permission is granted, we obtain the email address.
const string SubKey = "Software\\Microsoft\\VSCommon\\ConnectedUser\\IdeUser\\Cache";
const string EmailAddressKeyName = "EmailAddress";
const string UserNameKeyName = "DisplayName";
RegistryKey root = Registry.CurrentUser;
RegistryKey sk = root.OpenSubKey(SubKey);
if (sk == null)
{
// The user is currently not signed in.
return null;
}
else
{
// Get user email address.
return (string)sk.GetValue(EmailAddressKeyName);
// You can also get user name like this.
// return (string)sk.GetValue(UserNameKeyName);
}
}
There are now multiple versions of the IdeUser key. I've reimplemented the algorithm from the other answer this way:
public static string GetUserEmailAddressFromVisualStudioRegistry()
{
try
{
const string ConnectedUserSubKey = #"Software\Microsoft\VSCommon\ConnectedUser";
const string EmailAddressKeyName = "EmailAddress";
RegistryKey connectedUserSubKey = Registry.CurrentUser.OpenSubKey( ConnectedUserSubKey );
string[] subKeyNames = connectedUserSubKey?.GetSubKeyNames();
if ( subKeyNames == null || subKeyNames.Length == 0 )
{
return null;
}
int[] subKeysOrder = new int[subKeyNames.Length];
for ( int i = 0; i < subKeyNames.Length; i++ )
{
Match match = Regex.Match( subKeyNames[i], #"^IdeUser(?:V(?<version>\d+))?$" );
if ( !match.Success )
{
subKeysOrder[i] = -1;
continue;
}
string versionString = match.Groups["version"]?.Value;
if ( string.IsNullOrEmpty( versionString ) )
{
subKeysOrder[i] = 0;
}
else if ( !int.TryParse( versionString, out subKeysOrder[i] ) )
{
subKeysOrder[i] = -1;
}
}
Array.Sort( subKeysOrder, subKeyNames );
for ( int i = subKeyNames.Length - 1; i >= 0; i++ )
{
string cacheSubKeyName = $#"{subKeyNames[i]}\Cache";
RegistryKey cacheKey = connectedUserSubKey.OpenSubKey( cacheSubKeyName );
string emailAddress = cacheKey?.GetValue( EmailAddressKeyName ) as string;
if ( !string.IsNullOrWhiteSpace( emailAddress ) )
{
return emailAddress;
}
}
}
catch
{
// Handle exceptions here if it's wanted.
}
return null;
}
This algorithm tries all versions from the newest one and then all other siblings. It returns null in case of a failure.
What is the best way to find out if reportviewer and WindowsInstaller-KB893803-v2-x86 is installed on a PC? Is there a way to find out what public key to use to find out if a specific program is installed on a PC? (Tried this, didn't work)
Best Way To Determine If .NET 3.5 Is Installed
This is how to check if .NET 3.5 is installed, but i take it you need a another public key to know if report viewer is installed, but I don't know how to get the public key.
All I can think of is to check if the installation directory exists on the computer, would that be an acceptable way to check?
You could check in the Registry
public bool IsInstalled()
{
RegistryKey registryBase = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, string.Empty);
if (registryBase != null)
{
return registryBase.OpenSubKey("Software\\Microsoft\\ReportViewer\\v2.0.50727") != null;
}
return false;
}
In my machine (Win7 & Server 2012), the registry key is different.
bool exist = false;
RegistryKey registryBase = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, string.Empty);
if (registryBase != null)
{
exist = registryBase.OpenSubKey("Software\\Wow6432Node\\Microsoft\\.NETFramework\\v2.0.50727\\AssemblyFoldersEx\\ReportViewer v10") != null;
}
You could also query the GAC for the assemblies, as shown in this SO question.
I did a Regshot diff on a MS Report Viewer version 10 install to find the key because neither of the others posted here were working.
Here is the actual diff results on a fresh windows server VM.
Anyways, the key I found for this version was:
SOFTWARE\Wow6432Node\Microsoft\ReportViewer\v10.0
The code I used:
public bool IsInstalledReportViewer()
{
try
{
RegistryKey registryBase = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, string.Empty);
if (registryBase != null)
{
// check the two possible reportviewer v10 registry keys
return registryBase.OpenSubKey(#"Software\Microsoft\ReportViewer\v2.0.50727") != null
|| registryBase.OpenSubKey(#"Software\Wow6432Node\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx\ReportViewer v10") != null
|| registryBase.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\ReportViewer\v10.0") != null;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
// put proper exception handling here
}
return false;
}
I am trying to query the following registry key values:
HKLM\SOFTWARE\Microsoft\MSSQLServer\Client\SharedMemoryOn
HKLM\SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib\ProtocolOrder
But depending on which machine I'm running the program the query returns null. When I debug on my local machine and I inspect the value for ValueCount for:
HKLM\SOFTWARE\Microsoft\MSSQLServer\Client
HKLM\SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib
The count is 0 and OpenSubKey returns null.
I am a domain admin, in the local administrators group and have added the following to my app.manifest:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Any idea why?
private static void ValidateSqlClientSettings()
{
Console.WriteLine("\r\n/////////////// LOCAL SQL CLIENT PROTOCOLS ////////////////");
RegistryKey keyHKLM = Registry.LocalMachine;
///TODO: nullreferenceexception - connect to remote machine and find out why
RegistryKey sqlClientKey = keyHKLM.OpenSubKey(#"SOFTWARE\Microsoft\MSSQLServer\Client");
if (sqlClientKey == null)
{
WriteLine2Console(#"WARNING: unable to read registry key '{0}\SOFTWARE\Microsoft\MSSQLServer\Client'", ConsoleColor.Yellow);
}
var cliKeyNames = from k in sqlClientKey.GetSubKeyNames()
where k == "SuperSocketNetLib"
select k;
///TODO: find out why these values are always missing (even if I can see them in regedit)
Console.Write("Shared Memory Disabled (cliconfg): ");
if (Convert.ToBoolean(sqlClientKey.GetValue("SharedMemoryOn")))
WriteLine2Console("FAILED", ConsoleColor.Red);
else if(sqlClientKey.GetValue("SharedMemoryOn") == null)
WriteLine2Console(String.Format("WARNING - unable to read '{0}\\SharedMemoryOn'", sqlClientKey.Name), ConsoleColor.Yellow);
else
WriteLine2Console("PASS", ConsoleColor.Green);
Console.Write("Client Protocol Order (cliconfg - tcp first): ");
foreach (string cliKey in cliKeyNames)
{
RegistryKey subKey = sqlClientKey.OpenSubKey(cliKey);
object order = subKey.GetValue("ProtocolOrder");
if (order != null && order.ToString().StartsWith("tcp") == false)
{
WriteLine2Console("FAILED", ConsoleColor.Red);
}
else if (order == null)
{
WriteLine2Console(String.Format("WARNING - unable to read '{0}\\ProtocolOrder'", subKey.Name), ConsoleColor.Yellow);
}
else
{
WriteLine2Console("PASS", ConsoleColor.Green);
}
subKey.Close();
}
sqlClientKey.Close();
keyHKLM.Close();
}
Another factor you should pay attention to is application bitness.
On Windows x64, your x86 build will look for the registry keys under (in regedit) "SOFTWARE\WOW6432Node\Microsoft\MSSQLServer\Client", when you specify (in code) "Software\Microsoft\MSSQLServer\Client"
That's a WOW64 redirection for registry keys.
As Visual Studio 2010 by default creates exe in x86 mode, you should pay attention to this tip.
Try changing your sqlclientkey to the following:
RegistryKey sqlClientKey = keyHKLM.OpenSubKey(#"SOFTWARE\\Microsoft\\MSSQLServer\\Client");