1 //------------------------------------------------------------------------------
2 // <copyright file="DesigntimeLicenseContext.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.ComponentModel.Design {
8 using System.Runtime.Remoting;
9 using System.Diagnostics;
11 using Microsoft.Win32;
14 using System.Reflection;
15 using System.Collections;
16 using System.ComponentModel;
17 using System.Globalization;
18 using System.Security;
19 using System.Security.Permissions;
23 /// Provides design-time support for licensing.
26 [HostProtection(SharedState = true)]
27 [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Name = "FullTrust")]
28 [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
29 public class DesigntimeLicenseContext : LicenseContext {
30 internal Hashtable savedLicenseKeys = new Hashtable();
34 /// Gets or sets the license usage mode.
37 public override LicenseUsageMode UsageMode {
39 return LicenseUsageMode.Designtime;
44 /// Gets a saved license key.
47 public override string GetSavedLicenseKey(Type type, Assembly resourceAssembly) {
52 /// Sets a saved license key.
55 public override void SetSavedLicenseKey(Type type, string key) {
56 savedLicenseKeys[type.AssemblyQualifiedName] = key;
60 [HostProtection(SharedState = true)]
61 internal class RuntimeLicenseContext : LicenseContext
63 private static TraceSwitch RuntimeLicenseContextSwitch = new TraceSwitch("RuntimeLicenseContextTrace", "RuntimeLicenseContext tracing");
64 const int ReadBlock = 400;
66 internal Hashtable savedLicenseKeys;
69 /// This method takes a file URL and converts it to a local path. The trick here is that
70 /// if there is a '#' in the path, everything after this is treated as a fragment. So
71 /// we need to append the fragment to the end of the path.
73 private string GetLocalPath(string fileName) {
74 System.Diagnostics.Debug.Assert(fileName != null && fileName.Length > 0, "Cannot get local path, fileName is not valid");
76 Uri uri = new Uri(fileName);
77 return uri.LocalPath + uri.Fragment;
80 public override string GetSavedLicenseKey(Type type, Assembly resourceAssembly) {
82 if (savedLicenseKeys == null || savedLicenseKeys[type.AssemblyQualifiedName]==null) {
83 Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose, "savedLicenseKey is null or doesnt contain our type");
84 if (savedLicenseKeys == null) {
85 savedLicenseKeys = new Hashtable();
88 Uri licenseFile = null;
90 if (resourceAssembly == null) {
91 Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"resourceAssembly is null");
92 string rawFile = (string)AppDomain.CurrentDomain.SetupInformation.LicenseFile;
93 Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"rawfile: " + rawFile);
97 // FileIOPermission is required for ApplicationBase in URL-hosted domains
98 FileIOPermission perm = new FileIOPermission(PermissionState.Unrestricted);
101 codeBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
104 CodeAccessPermission.RevertAssert();
107 codeBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
109 if (rawFile != null && codeBase != null) {
110 licenseFile = new Uri(new Uri(codeBase), rawFile);
114 if (licenseFile == null) {
115 if(resourceAssembly == null) {
116 resourceAssembly = Assembly.GetEntryAssembly();
119 if (resourceAssembly == null) {
120 Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"resourceAssembly is null");
121 // If Assembly.EntryAssembly returns null, then we will
124 foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
126 // Though, I could not repro this, we seem to be hitting an AssemblyBuilder
127 // when walking through all the assemblies in the current app domain. This throws an
128 // exception on Assembly.CodeBase and we bail out. Catching exceptions here is not a
133 // file://fullpath/foo.exe
137 FileIOPermission perm = new FileIOPermission(PermissionState.Unrestricted);
141 fileName = GetLocalPath(asm.EscapedCodeBase);
142 fileName = new FileInfo(fileName).Name;
146 CodeAccessPermission.RevertAssert();
149 fileName = GetLocalPath(asm.EscapedCodeBase);
150 fileName = new FileInfo(fileName).Name;
153 Stream s = asm.GetManifestResourceStream(fileName + ".licenses");
155 //Since the casing may be different depending on how the assembly was loaded,
156 //we'll do a case insensitive lookup for this manifest resource stream...
157 s = CaseInsensitiveManifestResourceStreamLookup(asm, fileName + ".licenses");
161 DesigntimeLicenseContextSerializer.Deserialize(s, fileName.ToUpper(CultureInfo.InvariantCulture), this);
166 else if(!resourceAssembly.IsDynamic) { // EscapedCodeBase won't be supported by emitted assemblies anyway
167 Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"resourceAssembly is not null");
170 FileIOPermission perm = new FileIOPermission(PermissionState.Unrestricted);
175 fileName = GetLocalPath(resourceAssembly.EscapedCodeBase);
180 CodeAccessPermission.RevertAssert();
183 fileName = Path.GetFileName(fileName); // we don't want to use FileInfo here... it requests FileIOPermission that we
184 // might now have... see VSWhidbey 527758
185 string licResourceName = fileName + ".licenses";
186 // first try the filename
187 Stream s = resourceAssembly.GetManifestResourceStream(licResourceName);
189 string resolvedName = null;
190 CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo;
191 string shortAssemblyName = resourceAssembly.GetName().Name;
192 // if the assembly has been renamed, we try our best to find a good match in the available resources
193 // by looking at the assembly name (which doesn't change even after a file rename) + ".exe.licenses" or + ".dll.licenses"
194 foreach(String existingName in resourceAssembly.GetManifestResourceNames()) {
195 if (comparer.Compare(existingName, licResourceName, CompareOptions.IgnoreCase) == 0 ||
196 comparer.Compare(existingName, shortAssemblyName + ".exe.licenses", CompareOptions.IgnoreCase) == 0 ||
197 comparer.Compare(existingName, shortAssemblyName + ".dll.licenses", CompareOptions.IgnoreCase) == 0) {
198 resolvedName = existingName;
202 if (resolvedName != null) {
203 s = resourceAssembly.GetManifestResourceStream(resolvedName);
207 DesigntimeLicenseContextSerializer.Deserialize(s, fileName.ToUpper(CultureInfo.InvariantCulture), this);
213 if (licenseFile != null) {
214 Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"licenseFile: " + licenseFile.ToString());
215 Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"opening licenses file over URI " + licenseFile.ToString());
216 Stream s = OpenRead(licenseFile);
218 string[] segments = licenseFile.Segments;
219 string licFileName = segments[segments.Length - 1];
220 string key = licFileName.Substring(0, licFileName.LastIndexOf("."));
221 DesigntimeLicenseContextSerializer.Deserialize(s, key.ToUpper(CultureInfo.InvariantCulture), this);
226 Debug.WriteLineIf(RuntimeLicenseContextSwitch.TraceVerbose,"returning : " + (string)savedLicenseKeys[type.AssemblyQualifiedName]);
227 return(string)savedLicenseKeys[type.AssemblyQualifiedName];
231 * Looks up a .licenses file in the assembly manifest using
232 * case-insensitive lookup rules. We do this because the name
233 * we are attempting to locate could have different casing
234 * depending on how the assembly was loaded.
236 private Stream CaseInsensitiveManifestResourceStreamLookup(Assembly satellite, string name)
238 CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo;
240 //loop through the resource names in the assembly
241 // we try to handle the case where the assembly file name has been renamed
242 // by trying to guess the original file name based on the assembly name...
243 string assemblyShortName = satellite.GetName().Name;
244 foreach(string existingName in satellite.GetManifestResourceNames()) {
245 if (comparer.Compare(existingName, name, CompareOptions.IgnoreCase) == 0 ||
246 comparer.Compare(existingName, assemblyShortName + ".exe.licenses") == 0 ||
247 comparer.Compare(existingName, assemblyShortName + ".dll.licenses") == 0) {
253 //finally, attempt to return our stream based on the
254 //case insensitive match we found
256 return satellite.GetManifestResourceStream(name);
259 static Stream OpenRead(Uri resourceUri) {
260 Stream result = null;
262 PermissionSet perms = new PermissionSet(PermissionState.Unrestricted);
267 WebClient webClient = new WebClient();
268 webClient.Credentials = CredentialCache.DefaultCredentials;
269 result = webClient.OpenRead(resourceUri.ToString());
271 catch (Exception e) {
272 Debug.Fail(e.ToString());
276 CodeAccessPermission.RevertAssert();