private void AttemptToGetUserIdSettingsFromDifferentChannel()
{
// We need to get the company name and exe name of the main application, without introducing a dependency on
// Windows.Forms, so we can't use the Windows.Forms.Application methods. For maximum robustness, we try two
// different approaches.
// REVIEW: The first approach will NOT work for plugins or calls from unmanaged code, but for maximum
// compatibility (to keep from breaking Bloom), we try it first. If it fails, we try the second approach,
// which should work for everyone (though until there is a plugin that supports channels, it will presumably
// never actually find a pre-existing config file from a different channel).
string settingsLocation;
string softwareName;
for (int attempt = 0; attempt < 2; attempt++)
{
if (attempt == 0)
{
if (!TryGetSettingsLocationInfoFromEntryAssembly(out settingsLocation, out softwareName))
continue;
}
else
{
if (!TryGetDefaultSettingsLocationInfo(out settingsLocation, out softwareName))
return;
}
// Coincidentally, 5 is a good length for Bloom...better heuristic later?
// For example, we could
// - look for the last capital letter, and truncate to there. BloomAlpha->Bloom; HearThisAlpha->HearThis; *HearThis->Hear; TEX->?TE; TEXAlpha->TEX; BloomBetaOne->*BloomBeta
// - look for the first non-initial capital letter, and truncate from there on. BloomAlpha->Bloom, HearThisAlpha->*Hear; HearThis->*Hear; TEX->*T' TEXAlpha->TEX; BloomBetaOne->Bloom
// - look for a non-initial capital letter following at least one LC letter. Similar except TEX->TEX, TEXAlpha->*TEXAlpha.
// In general, truncating too much is better than too little; too much just makes us slow, while too little may make us miss useful results.
// It's true that truncating too much (like TEX->TE) may cause us to fetch an analytics ID from the wrong program. But even this is harmless, AFAIK.
var index = Math.Min(5, softwareName.Length);
var prefix = softwareName.Substring(0, index);
var pattern = prefix + "*";
var possibleParentFolders = Directory.GetDirectories(settingsLocation, pattern);
var possibleFolders = new List<string>();
foreach (var folder in possibleParentFolders)
{
possibleFolders.AddRange(Directory.GetDirectories(folder).Where(f => File.Exists(Path.Combine(f, kUserConfigFileName))));
}
possibleFolders.Sort((first, second) =>
{
if (first == second)
return 0;
var firstConfigPath = Path.Combine(first, kUserConfigFileName);
var secondConfigPath = Path.Combine(second, kUserConfigFileName);
// Reversing the arguments like this means that second comes before first if it has a LARGER mod time.
// That is, we end up with the most recently modified user.config first.
return new FileInfo(secondConfigPath).LastWriteTimeUtc.CompareTo(new FileInfo(firstConfigPath).LastWriteTimeUtc);
});
foreach (var folder in possibleFolders)
{
try
{
var doc = XDocument.Load(Path.Combine(folder, kUserConfigFileName));
var idSetting =
doc.XPathSelectElement(
"configuration/userSettings/DesktopAnalytics.AnalyticsSettings/setting[@name='IdForAnalytics']");
if (idSetting == null)
continue;
string analyticsId = idSetting.Value;
if (string.IsNullOrEmpty(analyticsId))
continue;
AnalyticsSettings.Default.IdForAnalytics = analyticsId;
AnalyticsSettings.Default.FirstName = ExtractSetting(AnalyticsSettings.Default.FirstName, doc, "FirstName");
AnalyticsSettings.Default.LastName = ExtractSetting(AnalyticsSettings.Default.LastName, doc, "LastName");
AnalyticsSettings.Default.LastVersionLaunched = ExtractSetting(AnalyticsSettings.Default.LastVersionLaunched, doc, "LastVersionLaunched");
AnalyticsSettings.Default.Email = ExtractSetting(AnalyticsSettings.Default.Email, doc, "Email");
AnalyticsSettings.Default.Save();
return;
}
catch (Exception)
{
// If anything goes wrong we just won't try to get our ID from this source.
}
}
}
}