|
//------------------------------------------------------------------------------
// <copyright file="DesigntimeLicenseContext.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.ComponentModel.Design {
using System.Runtime.Remoting;
using System.Diagnostics;
using System;
using Microsoft.Win32;
using System.Net;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Security;
using System.Security.Permissions;
/// <devdoc>
/// <para>
/// Provides design-time support for licensing.
/// </para>
/// </devdoc>
[HostProtection(SharedState = true)]
[System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Name = "FullTrust")]
[System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
public class DesigntimeLicenseContext : LicenseContext {
internal Hashtable savedLicenseKeys = new Hashtable();
/// <devdoc>
/// <para>
/// Gets or sets the license usage mode.
/// </para>
/// </devdoc>
public override LicenseUsageMode UsageMode {
get {
return LicenseUsageMode.Designtime;
}
}
/// <devdoc>
/// <para>
/// Gets a saved license key.
/// </para>
/// </devdoc>
public override string GetSavedLicenseKey(Type type, Assembly resourceAssembly) {
return null;
}
/// <devdoc>
/// <para>
/// Sets a saved license key.
/// </para>
/// </devdoc>
public override void SetSavedLicenseKey(Type type, string key) {
savedLicenseKeys[type.AssemblyQualifiedName] = key;
}
}
[HostProtection(SharedState = true)]
internal class RuntimeLicenseContext : LicenseContext
{
private static TraceSwitch RuntimeLicenseContextSwitch = new TraceSwitch("RuntimeLicenseContextTrace", "RuntimeLicenseContext tracing");
const int ReadBlock = 400;
internal Hashtable savedLicenseKeys;
/// <devdoc>
/// This method takes a file URL and converts it to a local path. The trick here is that
/// if there is a '#' in the path, everything after this is treated as a fragment. So
/// we need to append the fragment to the end of the path.
/// </devdoc>
private string GetLocalPath(string fileName) {
System.Diagnostics.Debug.Assert(fileName != null && fileName.Length > 0, "Cannot get local path, fileName is not valid");
Uri uri = new Uri(fileName);
return uri.LocalPath + uri.Fragment;
}
public override string GetSavedLicenseKey(Type type, Assembly resourceAssembly) {
if (savedLicenseKeys == null || savedLicenseKeys[type.AssemblyQualifiedName]==null) {
Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose, "savedLicenseKey is null or doesnt contain our type");
if (savedLicenseKeys == null) {
savedLicenseKeys = new Hashtable();
}
Uri licenseFile = null;
if (resourceAssembly == null) {
Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"resourceAssembly is null");
string rawFile = (string)AppDomain.CurrentDomain.SetupInformation.LicenseFile;
Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"rawfile: " + rawFile);
string codeBase;
// FileIOPermission is required for ApplicationBase in URL-hosted domains
FileIOPermission perm = new FileIOPermission(PermissionState.Unrestricted);
perm.Assert();
try {
codeBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
}
finally {
CodeAccessPermission.RevertAssert();
}
if (rawFile != null && codeBase != null) {
licenseFile = new Uri(new Uri(codeBase), rawFile);
}
}
if (licenseFile == null) {
if(resourceAssembly == null) {
resourceAssembly = Assembly.GetEntryAssembly();
}
if (resourceAssembly == null) {
Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"resourceAssembly is null");
// If Assembly.EntryAssembly returns null, then we will
// try everything!
//
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
// Though, I could not repro this, we seem to be hitting an AssemblyBuilder
// when walking through all the assemblies in the current app domain. This throws an
// exception on Assembly.CodeBase and we bail out. Catching exceptions here is not a
// bad thing.
if (asm.IsDynamic)
continue;
// file://fullpath/foo.exe
//
string fileName;
FileIOPermission perm = new FileIOPermission(PermissionState.Unrestricted);
perm.Assert();
try
{
fileName = GetLocalPath(asm.EscapedCodeBase);
fileName = new FileInfo(fileName).Name;
}
finally
{
CodeAccessPermission.RevertAssert();
}
Stream s = asm.GetManifestResourceStream(fileName + ".licenses");
if (s == null) {
//Since the casing may be different depending on how the assembly was loaded,
//we'll do a case insensitive lookup for this manifest resource stream...
s = CaseInsensitiveManifestResourceStreamLookup(asm, fileName + ".licenses");
}
if (s != null) {
DesigntimeLicenseContextSerializer.Deserialize(s, fileName.ToUpper(CultureInfo.InvariantCulture), this);
break;
}
}
}
else if(!resourceAssembly.IsDynamic) { // EscapedCodeBase won't be supported by emitted assemblies anyway
Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"resourceAssembly is not null");
string fileName;
FileIOPermission perm = new FileIOPermission(PermissionState.Unrestricted);
perm.Assert();
try
{
fileName = GetLocalPath(resourceAssembly.EscapedCodeBase);
}
finally
{
CodeAccessPermission.RevertAssert();
}
fileName = Path.GetFileName(fileName); // we don't want to use FileInfo here... it requests FileIOPermission that we
// might now have... see VSWhidbey 527758
string licResourceName = fileName + ".licenses";
// first try the filename
Stream s = resourceAssembly.GetManifestResourceStream(licResourceName);
if (s == null) {
string resolvedName = null;
CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo;
string shortAssemblyName = resourceAssembly.GetName().Name;
// if the assembly has been renamed, we try our best to find a good match in the available resources
// by looking at the assembly name (which doesn't change even after a file rename) + ".exe.licenses" or + ".dll.licenses"
foreach(String existingName in resourceAssembly.GetManifestResourceNames()) {
if (comparer.Compare(existingName, licResourceName, CompareOptions.IgnoreCase) == 0 ||
comparer.Compare(existingName, shortAssemblyName + ".exe.licenses", CompareOptions.IgnoreCase) == 0 ||
comparer.Compare(existingName, shortAssemblyName + ".dll.licenses", CompareOptions.IgnoreCase) == 0) {
resolvedName = existingName;
break;
}
}
if (resolvedName != null) {
s = resourceAssembly.GetManifestResourceStream(resolvedName);
}
}
if (s != null) {
DesigntimeLicenseContextSerializer.Deserialize(s, fileName.ToUpper(CultureInfo.InvariantCulture), this);
}
}
}
if (licenseFile != null) {
Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"licenseFile: " + licenseFile.ToString());
Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"opening licenses file over URI " + licenseFile.ToString());
Stream s = OpenRead(licenseFile);
if (s != null) {
string[] segments = licenseFile.Segments;
string licFileName = segments[segments.Length - 1];
string key = licFileName.Substring(0, licFileName.LastIndexOf("."));
DesigntimeLicenseContextSerializer.Deserialize(s, key.ToUpper(CultureInfo.InvariantCulture), this);
}
}
}
Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"returning : " + (string)savedLicenseKeys[type.AssemblyQualifiedName]);
return(string)savedLicenseKeys[type.AssemblyQualifiedName];
}
/**
* Looks up a .licenses file in the assembly manifest using
* case-insensitive lookup rules. We do this because the name
* we are attempting to locate could have different casing
* depending on how the assembly was loaded.
**/
private Stream CaseInsensitiveManifestResourceStreamLookup(Assembly satellite, string name)
{
CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo;
//loop through the resource names in the assembly
// we try to handle the case where the assembly file name has been renamed
// by trying to guess the original file name based on the assembly name...
string assemblyShortName = satellite.GetName().Name;
foreach(string existingName in satellite.GetManifestResourceNames()) {
if (comparer.Compare(existingName, name, CompareOptions.IgnoreCase) == 0 ||
comparer.Compare(existingName, assemblyShortName + ".exe.licenses") == 0 ||
comparer.Compare(existingName, assemblyShortName + ".dll.licenses") == 0) {
name = existingName;
break;
}
}
//finally, attempt to return our stream based on the
//case insensitive match we found
//
return satellite.GetManifestResourceStream(name);
}
static Stream OpenRead(Uri resourceUri) {
Stream result = null;
PermissionSet perms = new PermissionSet(PermissionState.Unrestricted);
perms.Assert();
try {
WebClient webClient = new WebClient();
webClient.Credentials = CredentialCache.DefaultCredentials;
result = webClient.OpenRead(resourceUri.ToString());
}
catch (Exception e) {
Debug.Fail(e.ToString());
}
finally {
CodeAccessPermission.RevertAssert();
}
return result;
}
}
}
|