I have installed .NET application. Its config location is
%AppData%\[CompanyName]\[ExeName]_Url_[hash]\[version]\user.config.
I need to get [hash]
value from another application.
According with MSDN, user.config
path template is
[c:\Documents and Settings]\[username]\[Local Settings]\Application Data\[companyname]\[appdomainname]_[eid]_[hash]\[version]
where [hash]
is SHA1 hash of evidence (in my case eid=Url).
I noticed the following things:
[hash]
changes with application installation path changes.[hash]
is always 32 characters long, so it is not hex representation of SHA1 which is 40 characters long. It seems that [hash]=base32(sha1([install path]))
I have tried different values for [install path]
c:\Program Files...
file:///c:\Program Files....
file:///c:\Program%20Files..., etc
but [hash]
is always wrong.
After going through the same problem of trying to calculate a program's user.config
(local) path, i decided to complement @Gerard Sexton 's answer with a code snippet. The following method was done with the assumptions that the [eid]
equals "Url"
and [appdomainname]
is the executable file name.
public string GetExeLocalAppDataUserConfigPath(string fullExePath)
{
//E.g.: fullExePath = @"C:\Program Files (x86)\MyExeFolder\MyProgram.exe"
var localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var versionInfo = FileVersionInfo.GetVersionInfo(fullExePath);
var companyName = versionInfo.CompanyName;
var exeName = versionInfo.OriginalFilename;// or 'AppDomain.CurrentDomain.FriendlyName'
var assemblyName = AssemblyName.GetAssemblyName(fullExePath);
var version = assemblyName.Version.ToString();
var uri = "file:///" + fullExePath; //or 'assemblyName.CodeBase' if vshost (you can check the 'FriendlyName')
uri = uri.ToUpperInvariant();
var ms = new MemoryStream();
var bSer = new BinaryFormatter();
bSer.Serialize(ms, uri);
ms.Position = 0;
var sha1 = new SHA1CryptoServiceProvider();
var hash = sha1.ComputeHash(ms);
var hashstring = ToBase32StringSuitableForDirName(hash);
//<AppData Local User Path> + <Company Name> + <[ExeName]_[eid]_[Hash]> + <Version> + user.config
var userConfigLocalAppDataPath = Path.Combine(localAppDataPath, companyName, exeName+"_Url_"+hashstring, version, "user.config");
return userConfigLocalAppDataPath;
}
And here is the ToBase32StringSuitableForDirName
implementation found in Gerard's link!
static Char[] s_Base32Char = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5'};
private static string ToBase32StringSuitableForDirName(byte[] buff)
{
StringBuilder sb = new StringBuilder();
byte b0, b1, b2, b3, b4;
int l, i;
l = buff.Length;
i = 0;
// Create l chars using the last 5 bits of each byte.
// Consume 3 MSB bits 5 bytes at a time.
do
{
b0 = (i < l) ? buff[i++] : (byte)0;
b1 = (i < l) ? buff[i++] : (byte)0;
b2 = (i < l) ? buff[i++] : (byte)0;
b3 = (i < l) ? buff[i++] : (byte)0;
b4 = (i < l) ? buff[i++] : (byte)0;
// Consume the 5 Least significant bits of each byte
sb.Append(s_Base32Char[b0 & 0x1F]);
sb.Append(s_Base32Char[b1 & 0x1F]);
sb.Append(s_Base32Char[b2 & 0x1F]);
sb.Append(s_Base32Char[b3 & 0x1F]);
sb.Append(s_Base32Char[b4 & 0x1F]);
// Consume 3 MSB of b0, b1, MSB bits 6, 7 of b3, b4
sb.Append(s_Base32Char[(
((b0 & 0xE0) >> 5) |
((b3 & 0x60) >> 2))]);
sb.Append(s_Base32Char[(
((b1 & 0xE0) >> 5) |
((b4 & 0x60) >> 2))]);
// Consume 3 MSB bits of b2, 1 MSB bit of b3, b4
b2 >>= 5;
if ((b3 & 0x80) != 0)
b2 |= 0x08;
if ((b4 & 0x80) != 0)
b2 |= 0x10;
sb.Append(s_Base32Char[b2]);
} while (i < l);
return sb.ToString();
}
The advice for writing to a custom location is to provide your own SettingsProvider
. The default settings provider is LocalFileSettingsProvider
.
So starting in LocalFileSettingsProvider
, then following the code to ConfigurationManagerInternalFactory
then ConfigurationManagerInternal
then finally in ClientConfigPaths
. In ClientConfigPaths:412
you can see how the hash is determined from the current AppDomain's evidence.
Basically, for Uri type, it takes the Uri in the form
file:///c:\app\app.exe
This uri is then converted to upper case (invariant), then SHA-1 hashed, then the hash is encoded in base32. I don't know if the base32 used in the referenced source is a standard base32 implementation or not (if one exists).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With