2016-08-03 10:59:49 +00:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// <copyright file="ClientConfigPaths.cs" company="Microsoft">
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
// </copyright>
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace System.Configuration {
|
|
|
|
using System;
|
|
|
|
using System.Collections;
|
|
|
|
using System.IO;
|
|
|
|
using System.Reflection;
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
|
|
using System.Security;
|
|
|
|
using System.Security.Cryptography;
|
|
|
|
using System.Security.Policy;
|
|
|
|
using System.Security.Permissions;
|
|
|
|
using System.Text;
|
|
|
|
using System.Globalization;
|
|
|
|
using Microsoft.Win32;
|
|
|
|
|
|
|
|
class ClientConfigPaths {
|
|
|
|
internal const string UserConfigFilename = "user.config";
|
|
|
|
|
|
|
|
const string ClickOnceDataDirectory = "DataDirectory";
|
|
|
|
const string ConfigExtension = ".config";
|
|
|
|
const int MAX_PATH = 260;
|
2016-11-10 13:04:39 +00:00
|
|
|
const int MAX_UNICODESTRING_LEN = short.MaxValue;
|
|
|
|
const int ERROR_INSUFFICIENT_BUFFER = 122; //https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
|
2016-08-03 10:59:49 +00:00
|
|
|
const int MAX_LENGTH_TO_USE = 25;
|
|
|
|
const string FILE_URI_LOCAL = "file:///";
|
|
|
|
const string FILE_URI_UNC = "file://";
|
|
|
|
const string FILE_URI = "file:";
|
|
|
|
const string HTTP_URI = "http://";
|
|
|
|
const string StrongNameDesc = "StrongName";
|
|
|
|
const string UrlDesc = "Url";
|
|
|
|
const string PathDesc = "Path";
|
|
|
|
|
|
|
|
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'};
|
|
|
|
|
|
|
|
static volatile ClientConfigPaths s_current;
|
|
|
|
static volatile bool s_currentIncludesUserConfig;
|
|
|
|
static volatile SecurityPermission s_serializationPerm;
|
|
|
|
static volatile SecurityPermission s_controlEvidencePerm;
|
|
|
|
|
|
|
|
bool _hasEntryAssembly;
|
|
|
|
bool _includesUserConfig;
|
|
|
|
string _applicationUri;
|
|
|
|
string _applicationConfigUri;
|
|
|
|
string _roamingConfigDirectory;
|
|
|
|
string _roamingConfigFilename;
|
|
|
|
string _localConfigDirectory;
|
|
|
|
string _localConfigFilename;
|
|
|
|
string _companyName;
|
|
|
|
string _productName;
|
|
|
|
string _productVersion;
|
|
|
|
|
|
|
|
|
|
|
|
[FileIOPermission(SecurityAction.Assert, AllFiles=FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read)]
|
|
|
|
[SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)]
|
|
|
|
private ClientConfigPaths(string exePath, bool includeUserConfig) {
|
|
|
|
|
|
|
|
_includesUserConfig = includeUserConfig;
|
|
|
|
|
|
|
|
Assembly exeAssembly = null;
|
|
|
|
string applicationUri = null;
|
|
|
|
string applicationFilename = null;
|
|
|
|
|
|
|
|
// get the assembly and applicationUri for the file
|
|
|
|
if (exePath == null) {
|
|
|
|
// First check if a configuration file has been set for this app domain. If so, we will use that.
|
|
|
|
// The CLR would already have normalized this, so no further processing necessary.
|
|
|
|
AppDomain domain = AppDomain.CurrentDomain;
|
|
|
|
AppDomainSetup setup = domain.SetupInformation;
|
|
|
|
_applicationConfigUri = setup.ConfigurationFile;
|
|
|
|
|
|
|
|
// Now figure out the application path.
|
|
|
|
exeAssembly = Assembly.GetEntryAssembly();
|
|
|
|
if (exeAssembly != null) {
|
|
|
|
_hasEntryAssembly = true;
|
|
|
|
applicationUri = exeAssembly.CodeBase;
|
|
|
|
|
|
|
|
bool isFile = false;
|
|
|
|
|
|
|
|
// If it is a local file URI, convert it to its filename, without invoking Uri class.
|
|
|
|
// example: "file:///C:/WINNT/Microsoft.NET/Framework/v2.0.x86fre/csc.exe"
|
|
|
|
if (StringUtil.StartsWithIgnoreCase(applicationUri, FILE_URI_LOCAL)) {
|
|
|
|
isFile = true;
|
|
|
|
applicationUri = applicationUri.Substring(FILE_URI_LOCAL.Length);
|
|
|
|
}
|
|
|
|
// If it is a UNC file URI, convert it to its filename, without invoking Uri class.
|
|
|
|
// example: "file://server/share/csc.exe"
|
|
|
|
else if (StringUtil.StartsWithIgnoreCase(applicationUri, FILE_URI_UNC)) {
|
|
|
|
isFile = true;
|
|
|
|
applicationUri = applicationUri.Substring(FILE_URI.Length);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isFile) {
|
|
|
|
applicationUri = applicationUri.Replace('/', '\\');
|
|
|
|
applicationFilename = applicationUri;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
applicationUri = exeAssembly.EscapedCodeBase;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
StringBuilder sb = new StringBuilder(MAX_PATH);
|
2016-11-10 13:04:39 +00:00
|
|
|
int noOfTimes = 1;
|
|
|
|
int length = 0;
|
|
|
|
// Iterating by allocating chunk of memory each time we find the length is not sufficient.
|
|
|
|
// Performance should not be an issue for current MAX_PATH length due to this change.
|
|
|
|
while (((length = UnsafeNativeMethods.GetModuleFileName(new HandleRef(null, IntPtr.Zero), sb, sb.Capacity)) == sb.Capacity)
|
|
|
|
&& Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER
|
|
|
|
&& sb.Capacity < MAX_UNICODESTRING_LEN) {
|
|
|
|
noOfTimes += 2; // increasing buffer size by 520 in each iteration - perf.
|
|
|
|
int capacity = noOfTimes * MAX_PATH < MAX_UNICODESTRING_LEN ? noOfTimes * MAX_PATH : MAX_UNICODESTRING_LEN;
|
|
|
|
sb.EnsureCapacity(capacity);
|
|
|
|
}
|
|
|
|
sb.Length = length;
|
2016-08-03 10:59:49 +00:00
|
|
|
applicationUri = Path.GetFullPath(sb.ToString());
|
|
|
|
applicationFilename = applicationUri;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
applicationUri = Path.GetFullPath(exePath);
|
|
|
|
if (!FileUtil.FileExists(applicationUri, false))
|
|
|
|
throw ExceptionUtil.ParameterInvalid("exePath");
|
|
|
|
|
|
|
|
applicationFilename = applicationUri;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fallback if we haven't set the app config file path yet.
|
|
|
|
if (_applicationConfigUri == null) {
|
|
|
|
_applicationConfigUri = applicationUri + ConfigExtension;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set application path
|
|
|
|
_applicationUri = applicationUri;
|
|
|
|
|
|
|
|
// In the case when exePath was explicitly supplied, we will not be able to
|
|
|
|
// construct user.config paths, so quit here.
|
|
|
|
if (exePath != null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip expensive initialization of user config file information if requested.
|
|
|
|
if (!_includesUserConfig) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isHttp = StringUtil.StartsWithIgnoreCase(_applicationConfigUri, HTTP_URI);
|
|
|
|
|
|
|
|
SetNamesAndVersion(applicationFilename, exeAssembly, isHttp);
|
|
|
|
|
|
|
|
// Check if this is a clickonce deployed application. If so, point the user config
|
|
|
|
// files to the clickonce data directory.
|
|
|
|
if (this.IsClickOnceDeployed(AppDomain.CurrentDomain)) {
|
|
|
|
string dataPath = AppDomain.CurrentDomain.GetData(ClickOnceDataDirectory) as string;
|
|
|
|
string versionSuffix = Validate(_productVersion, false);
|
|
|
|
|
|
|
|
// NOTE: No roaming config for clickonce - not supported.
|
|
|
|
if (Path.IsPathRooted(dataPath)) {
|
|
|
|
_localConfigDirectory = CombineIfValid(dataPath, versionSuffix);
|
|
|
|
_localConfigFilename = CombineIfValid(_localConfigDirectory, UserConfigFilename);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (!isHttp) {
|
|
|
|
// If we get the config from http, we do not have a roaming or local config directory,
|
|
|
|
// as it cannot be edited by the app in those cases because it does not have Full Trust.
|
|
|
|
|
|
|
|
// suffix for user config paths
|
|
|
|
|
|
|
|
string part1 = Validate(_companyName, true);
|
|
|
|
|
|
|
|
string validAppDomainName = Validate(AppDomain.CurrentDomain.FriendlyName, true);
|
|
|
|
string applicationUriLower = !String.IsNullOrEmpty(_applicationUri) ? _applicationUri.ToLower(CultureInfo.InvariantCulture) : null;
|
|
|
|
string namePrefix = !String.IsNullOrEmpty(validAppDomainName) ? validAppDomainName : Validate(_productName, true);
|
|
|
|
string hashSuffix = GetTypeAndHashSuffix(AppDomain.CurrentDomain, applicationUriLower);
|
|
|
|
|
|
|
|
string part2 = (!String.IsNullOrEmpty(namePrefix) && !String.IsNullOrEmpty(hashSuffix)) ? namePrefix + hashSuffix : null;
|
|
|
|
|
|
|
|
string part3 = Validate(_productVersion, false);
|
|
|
|
|
|
|
|
string dirSuffix = CombineIfValid(CombineIfValid(part1, part2), part3);
|
|
|
|
|
|
|
|
string roamingFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
|
|
|
if (Path.IsPathRooted(roamingFolderPath)) {
|
|
|
|
_roamingConfigDirectory = CombineIfValid(roamingFolderPath, dirSuffix);
|
|
|
|
_roamingConfigFilename = CombineIfValid(_roamingConfigDirectory, UserConfigFilename);
|
|
|
|
}
|
|
|
|
|
|
|
|
string localFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
|
|
|
if (Path.IsPathRooted(localFolderPath)) {
|
|
|
|
_localConfigDirectory = CombineIfValid(localFolderPath, dirSuffix);
|
|
|
|
_localConfigFilename = CombineIfValid(_localConfigDirectory, UserConfigFilename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static ClientConfigPaths GetPaths(string exePath, bool includeUserConfig) {
|
|
|
|
ClientConfigPaths result = null;
|
|
|
|
|
|
|
|
if (exePath == null) {
|
|
|
|
if (s_current == null || (includeUserConfig && !s_currentIncludesUserConfig)) {
|
|
|
|
s_current = new ClientConfigPaths(null, includeUserConfig);
|
|
|
|
s_currentIncludesUserConfig = includeUserConfig;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = s_current;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result = new ClientConfigPaths(exePath, includeUserConfig);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static void RefreshCurrent() {
|
|
|
|
s_currentIncludesUserConfig = false;
|
|
|
|
s_current = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static ClientConfigPaths Current {
|
|
|
|
get {
|
|
|
|
return GetPaths(null, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal bool HasEntryAssembly {
|
|
|
|
get {
|
|
|
|
return _hasEntryAssembly;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string ApplicationUri {
|
|
|
|
get {
|
|
|
|
return _applicationUri;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string ApplicationConfigUri {
|
|
|
|
get {
|
|
|
|
return _applicationConfigUri;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string RoamingConfigFilename {
|
|
|
|
get {
|
|
|
|
return _roamingConfigFilename;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string RoamingConfigDirectory {
|
|
|
|
get {
|
|
|
|
return _roamingConfigDirectory;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal bool HasRoamingConfig {
|
|
|
|
get {
|
|
|
|
// Assume we have roaming config if we haven't loaded user config file information.
|
|
|
|
return RoamingConfigFilename != null || !_includesUserConfig;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string LocalConfigFilename {
|
|
|
|
get {
|
|
|
|
return _localConfigFilename;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string LocalConfigDirectory {
|
|
|
|
get {
|
|
|
|
return _localConfigDirectory;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal bool HasLocalConfig {
|
|
|
|
get {
|
|
|
|
// Assume we have roaming config if we haven't loaded user config file information.
|
|
|
|
return LocalConfigFilename != null || !_includesUserConfig;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string ProductName {
|
|
|
|
get {
|
|
|
|
return _productName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string ProductVersion {
|
|
|
|
get {
|
|
|
|
return _productVersion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static SecurityPermission ControlEvidencePermission {
|
|
|
|
get {
|
|
|
|
if (s_controlEvidencePerm == null) {
|
|
|
|
s_controlEvidencePerm = new SecurityPermission(SecurityPermissionFlag.ControlEvidence);
|
|
|
|
}
|
|
|
|
return s_controlEvidencePerm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static SecurityPermission SerializationFormatterPermission {
|
|
|
|
get {
|
|
|
|
if (s_serializationPerm == null) {
|
|
|
|
s_serializationPerm = new SecurityPermission(SecurityPermissionFlag.SerializationFormatter);
|
|
|
|
}
|
|
|
|
return s_serializationPerm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Combines path2 with path1 if possible, else returns null.
|
|
|
|
private string CombineIfValid(string path1, string path2) {
|
|
|
|
string returnPath = null;
|
|
|
|
|
|
|
|
if (path1 != null && path2 != null) {
|
|
|
|
try {
|
|
|
|
string combinedPath = Path.Combine(path1, path2);
|
|
|
|
if (combinedPath.Length < MAX_PATH) {
|
|
|
|
returnPath = combinedPath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return returnPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a type and hash suffix based on app domain evidence. The evidence we use, in
|
|
|
|
// priority order, is Strong Name, Url and Exe Path. If one of these is found, we compute a
|
|
|
|
// SHA1 hash of it and return a suffix based on that. If none is found, we return null.
|
|
|
|
private string GetTypeAndHashSuffix(AppDomain appDomain, string exePath) {
|
|
|
|
string suffix = null;
|
|
|
|
string typeName = null;
|
|
|
|
object evidenceObj = null;
|
|
|
|
|
|
|
|
evidenceObj = GetEvidenceInfo(appDomain, exePath, out typeName);
|
|
|
|
|
|
|
|
if (evidenceObj != null && !String.IsNullOrEmpty(typeName)) {
|
|
|
|
MemoryStream ms = new MemoryStream();
|
|
|
|
BinaryFormatter bSer = new BinaryFormatter();
|
|
|
|
SerializationFormatterPermission.Assert();
|
|
|
|
bSer.Serialize(ms, evidenceObj);
|
|
|
|
ms.Position = 0;
|
|
|
|
string evidenceHash = GetHash(ms);
|
|
|
|
|
|
|
|
if (!String.IsNullOrEmpty(evidenceHash)) {
|
|
|
|
suffix = "_" + typeName + "_" + evidenceHash;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return suffix;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mostly borrowed from IsolatedStorage, with some modifications
|
|
|
|
private static object GetEvidenceInfo(AppDomain appDomain, string exePath, out string typeName) {
|
|
|
|
ControlEvidencePermission.Assert();
|
|
|
|
Evidence evidence = appDomain.Evidence;
|
|
|
|
StrongName sn = null;
|
|
|
|
Url url = null;
|
|
|
|
|
|
|
|
if (evidence != null) {
|
|
|
|
IEnumerator e = evidence.GetHostEnumerator();
|
|
|
|
object temp = null;
|
|
|
|
|
|
|
|
while (e.MoveNext()) {
|
|
|
|
temp = e.Current;
|
|
|
|
|
|
|
|
if (temp is StrongName) {
|
|
|
|
sn = (StrongName) temp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (temp is Url) {
|
|
|
|
url = (Url) temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object o = null;
|
|
|
|
|
|
|
|
// The order of preference is StrongName, Url, ExePath.
|
|
|
|
if (sn != null) {
|
|
|
|
o = MakeVersionIndependent(sn);
|
|
|
|
typeName = StrongNameDesc;
|
|
|
|
}
|
|
|
|
else if (url != null) {
|
|
|
|
// Extract the url string and normalize it to use as evidence
|
|
|
|
o = url.Value.ToUpperInvariant();
|
|
|
|
typeName = UrlDesc;
|
|
|
|
}
|
|
|
|
else if (exePath != null) {
|
|
|
|
o = exePath;
|
|
|
|
typeName = PathDesc;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
typeName = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static String GetHash(Stream s) {
|
|
|
|
byte[] hash;
|
|
|
|
|
|
|
|
using (SHA1 sha1 = new SHA1CryptoServiceProvider()) {
|
|
|
|
hash = sha1.ComputeHash(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ToBase32StringSuitableForDirName(hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool IsClickOnceDeployed(AppDomain appDomain) {
|
|
|
|
// NOTE: For perf & servicing reasons, we don't want to introduce a dependency on
|
|
|
|
// System.Deployment.dll here. The following code is an alternative to calling
|
|
|
|
// ApplicationDeployment.IsNetworkDeployed.
|
|
|
|
|
|
|
|
ActivationContext actCtx = appDomain.ActivationContext;
|
|
|
|
|
|
|
|
// Ensures the app is running with a context from the store.
|
|
|
|
if (actCtx != null && actCtx.Form == ActivationContext.ContextForm.StoreBounded) {
|
|
|
|
string fullAppId = actCtx.Identity.FullName;
|
|
|
|
if (!String.IsNullOrEmpty(fullAppId)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static StrongName MakeVersionIndependent(StrongName sn) {
|
|
|
|
return new StrongName(sn.PublicKey, sn.Name, new Version(0,0,0,0));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void SetNamesAndVersion(string applicationFilename, Assembly exeAssembly, bool isHttp) {
|
|
|
|
Type mainType = null;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get CompanyName, ProductName, and ProductVersion
|
|
|
|
// First try custom attributes on the assembly.
|
|
|
|
//
|
|
|
|
if (exeAssembly != null) {
|
|
|
|
object[] attrs = exeAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
|
|
|
|
if (attrs != null && attrs.Length > 0) {
|
|
|
|
_companyName = ((AssemblyCompanyAttribute)attrs[0]).Company;
|
|
|
|
if (_companyName != null) {
|
|
|
|
_companyName = _companyName.Trim();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
attrs = exeAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false);
|
|
|
|
if (attrs != null && attrs.Length > 0) {
|
|
|
|
_productName = ((AssemblyProductAttribute)attrs[0]).Product;
|
|
|
|
if (_productName != null) {
|
|
|
|
_productName = _productName.Trim();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_productVersion = exeAssembly.GetName().Version.ToString();
|
|
|
|
if (_productVersion != null) {
|
|
|
|
_productVersion = _productVersion.Trim();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// If we couldn't get custom attributes, try the Win32 file version
|
|
|
|
//
|
|
|
|
if (!isHttp && (String.IsNullOrEmpty(_companyName) || String.IsNullOrEmpty(_productName) || String.IsNullOrEmpty(_productVersion))) {
|
|
|
|
string versionInfoFileName = null;
|
|
|
|
|
|
|
|
if (exeAssembly != null) {
|
|
|
|
MethodInfo entryPoint = exeAssembly.EntryPoint;
|
|
|
|
if (entryPoint != null) {
|
|
|
|
mainType = entryPoint.ReflectedType;
|
|
|
|
if (mainType != null) {
|
|
|
|
versionInfoFileName = mainType.Module.FullyQualifiedName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (versionInfoFileName == null) {
|
|
|
|
versionInfoFileName = applicationFilename;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (versionInfoFileName != null) {
|
|
|
|
System.Diagnostics.FileVersionInfo version = System.Diagnostics.FileVersionInfo.GetVersionInfo(versionInfoFileName);
|
|
|
|
if (version != null) {
|
|
|
|
if (String.IsNullOrEmpty(_companyName)) {
|
|
|
|
_companyName = version.CompanyName;
|
|
|
|
if (_companyName != null) {
|
|
|
|
_companyName = _companyName.Trim();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(_productName)) {
|
|
|
|
_productName = version.ProductName;
|
|
|
|
if (_productName != null) {
|
|
|
|
_productName = _productName.Trim();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(_productVersion)) {
|
|
|
|
_productVersion = version.ProductVersion;
|
|
|
|
if (_productVersion != null) {
|
|
|
|
_productVersion = _productVersion.Trim();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(_companyName) || String.IsNullOrEmpty(_productName)) {
|
|
|
|
string ns = null;
|
|
|
|
if (mainType != null) {
|
|
|
|
ns = mainType.Namespace;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Desperate measures for product name
|
|
|
|
if (String.IsNullOrEmpty(_productName)) {
|
|
|
|
// Try the remainder of the namespace
|
|
|
|
if (ns != null) {
|
|
|
|
int lastDot = ns.LastIndexOf(".", StringComparison.Ordinal);
|
|
|
|
if (lastDot != -1 && lastDot < ns.Length - 1) {
|
|
|
|
_productName = ns.Substring(lastDot+1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_productName = ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
_productName = _productName.Trim();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try the type of the entry assembly
|
|
|
|
if (String.IsNullOrEmpty(_productName) && mainType != null) {
|
|
|
|
_productName = mainType.Name.Trim();
|
|
|
|
}
|
|
|
|
|
|
|
|
// give up, return empty string
|
|
|
|
if (_productName == null) {
|
|
|
|
_productName = string.Empty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Desperate measures for company name
|
|
|
|
if (String.IsNullOrEmpty(_companyName)) {
|
|
|
|
// Try the first part of the namespace
|
|
|
|
if (ns != null) {
|
|
|
|
int firstDot = ns.IndexOf(".", StringComparison.Ordinal);
|
|
|
|
if (firstDot != -1) {
|
|
|
|
_companyName = ns.Substring(0, firstDot);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_companyName = ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
_companyName = _companyName.Trim();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If that doesn't work, use the product name
|
|
|
|
if (String.IsNullOrEmpty(_companyName)) {
|
|
|
|
_companyName = _productName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Desperate measures for product version - assume 1.0
|
|
|
|
if (String.IsNullOrEmpty(_productVersion)) {
|
|
|
|
_productVersion = "1.0.0.0";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Borrowed from IsolatedStorage
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Makes the passed in string suitable to use as a path name by replacing illegal characters
|
|
|
|
// with underscores. Additionally, we do two things - replace spaces too with underscores and
|
|
|
|
// limit the resultant string's length to MAX_LENGTH_TO_USE if limitSize is true.
|
|
|
|
private string Validate(string str, bool limitSize) {
|
|
|
|
string validated = str;
|
|
|
|
|
|
|
|
if (!String.IsNullOrEmpty(validated)) {
|
|
|
|
// First replace all illegal characters with underscores
|
|
|
|
foreach (char c in Path.GetInvalidFileNameChars()) {
|
|
|
|
validated = validated.Replace(c, '_');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Replace all spaces with underscores
|
|
|
|
validated = validated.Replace(' ', '_');
|
|
|
|
|
|
|
|
if (limitSize) {
|
|
|
|
validated = (validated.Length > MAX_LENGTH_TO_USE) ? validated.Substring(0, MAX_LENGTH_TO_USE) : validated;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return validated;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|