459 lines
22 KiB
C#
459 lines
22 KiB
C#
|
//------------------------------------------------------------------------------
|
||
|
// <copyright file="EventlogProvider.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
namespace System.Web.Management {
|
||
|
using System;
|
||
|
using System.Configuration;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Collections.Specialized;
|
||
|
using System.Web.Util;
|
||
|
using System.Web.Configuration;
|
||
|
using System.Text;
|
||
|
using System.Reflection;
|
||
|
using System.Security.Permissions;
|
||
|
using System.IO;
|
||
|
using System.Runtime.InteropServices.ComTypes;
|
||
|
|
||
|
[ComImport, Guid("c84f668a-cc3f-11d7-b79e-505054503030"), System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
|
||
|
public interface IRegiisUtility {
|
||
|
|
||
|
void ProtectedConfigAction(long actionToPerform,
|
||
|
[In, MarshalAs(UnmanagedType.LPWStr)] string firstArgument,
|
||
|
[In, MarshalAs(UnmanagedType.LPWStr)] string secondArgument,
|
||
|
[In, MarshalAs(UnmanagedType.LPWStr)] string providerName,
|
||
|
[In, MarshalAs(UnmanagedType.LPWStr)] string appPath,
|
||
|
[In, MarshalAs(UnmanagedType.LPWStr)] string site,
|
||
|
[In, MarshalAs(UnmanagedType.LPWStr)] string cspOrLocation,
|
||
|
int keySize,
|
||
|
out IntPtr exception);
|
||
|
|
||
|
void RegisterSystemWebAssembly(int doReg, out IntPtr exception);
|
||
|
|
||
|
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
||
|
void RegisterAsnetMmcAssembly(int doReg, [In, MarshalAs(UnmanagedType.LPWStr)] string assemblyName, [In, MarshalAs(UnmanagedType.LPWStr)] string binaryDirectory, out IntPtr exception);
|
||
|
|
||
|
void RemoveBrowserCaps(out IntPtr exception);
|
||
|
}
|
||
|
|
||
|
public sealed class RegiisUtility : IRegiisUtility {
|
||
|
// The following two sets of constants are copied from register.cxx
|
||
|
|
||
|
const int WATSettingLocalOnly = 0;
|
||
|
const int WATSettingRequireSSL = 1;
|
||
|
const int WATSettingAuthSettings = 2;
|
||
|
const int WATSettingAuthMode = 3;
|
||
|
const int WATSettingMax = 4;
|
||
|
|
||
|
const int WATValueDoNothing = 0;
|
||
|
const int WATValueTrue = 1;
|
||
|
const int WATValueFalse = 2;
|
||
|
const int WATValueHosted = 3;
|
||
|
const int WATValueLocal = 4;
|
||
|
const int WATValueForms = 5;
|
||
|
const int WATValueWindows = 6;
|
||
|
|
||
|
// Note: this name has to match the name used in System.Configuration.RsaProtectedConfigurationProvider
|
||
|
const string DefaultRsaKeyContainerName = "NetFrameworkConfigurationKey";
|
||
|
|
||
|
const string NewLine = "\n\r";
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
public void RegisterSystemWebAssembly(int doReg, out IntPtr exception)
|
||
|
{
|
||
|
exception = IntPtr.Zero;
|
||
|
|
||
|
try {
|
||
|
Assembly webAssembly = Assembly.GetExecutingAssembly();
|
||
|
RegistrationServices rs = new RegistrationServices();
|
||
|
|
||
|
if (doReg != 0)
|
||
|
{
|
||
|
if (!rs.RegisterAssembly(webAssembly, AssemblyRegistrationFlags.None))
|
||
|
exception = Marshal.StringToBSTR((new Exception(SR.GetString(SR.Unable_To_Register_Assembly, webAssembly.FullName))).ToString());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!rs.UnregisterAssembly(webAssembly))
|
||
|
exception = Marshal.StringToBSTR((new Exception(SR.GetString(SR.Unable_To_UnRegister_Assembly, webAssembly.FullName))).ToString());
|
||
|
}
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
exception = Marshal.StringToBSTR(e.ToString());
|
||
|
}
|
||
|
}
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
||
|
public void RegisterAsnetMmcAssembly(int doReg, string typeName, string binaryDirectory, out IntPtr exception)
|
||
|
{
|
||
|
exception = IntPtr.Zero;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
Assembly webAssembly = Assembly.GetAssembly(Type.GetType(typeName, true));
|
||
|
RegistrationServices rs = new RegistrationServices();
|
||
|
|
||
|
if (doReg != 0)
|
||
|
{
|
||
|
if (!rs.RegisterAssembly(webAssembly, AssemblyRegistrationFlags.None))
|
||
|
exception = Marshal.StringToBSTR((new Exception(SR.GetString(SR.Unable_To_Register_Assembly, webAssembly.FullName))).ToString());
|
||
|
TypeLibConverter converter = new TypeLibConverter();
|
||
|
ConversionEventSink eventHandler = new ConversionEventSink();
|
||
|
|
||
|
IRegisterCreateITypeLib typeLib = (IRegisterCreateITypeLib)converter.ConvertAssemblyToTypeLib(webAssembly, System.IO.Path.Combine(binaryDirectory, "AspNetMMCExt.tlb"), 0, eventHandler);
|
||
|
typeLib.SaveAllChanges();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Consider deleting tlb file
|
||
|
if (!rs.UnregisterAssembly(webAssembly))
|
||
|
exception = Marshal.StringToBSTR((new Exception(SR.GetString(SR.Unable_To_UnRegister_Assembly, webAssembly.FullName))).ToString());
|
||
|
|
||
|
try {
|
||
|
File.Delete(System.IO.Path.Combine(binaryDirectory, "AspNetMMCExt.tlb"));
|
||
|
}
|
||
|
catch {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
exception = Marshal.StringToBSTR(e.ToString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[ComImport, GuidAttribute("00020406-0000-0000-C000-000000000046"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown), ComVisible(false)]
|
||
|
interface IRegisterCreateITypeLib
|
||
|
{
|
||
|
void CreateTypeInfo();
|
||
|
void SetName();
|
||
|
void SetVersion();
|
||
|
void SetGuid();
|
||
|
void SetDocString();
|
||
|
void SetHelpFileName();
|
||
|
void SetHelpContext();
|
||
|
void SetLcid();
|
||
|
void SetLibFlags();
|
||
|
void SaveAllChanges();
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
private const long DO_RSA_ENCRYPT = 0x0000000100000000;
|
||
|
private const long DO_RSA_DECRYPT = 0x0000000200000000;
|
||
|
private const long DO_RSA_ADD_KEY = 0x0000000400000000;
|
||
|
private const long DO_RSA_DEL_KEY = 0x0000000800000000;
|
||
|
private const long DO_RSA_ACL_KEY_ADD = 0x0000001000000000;
|
||
|
private const long DO_RSA_ACL_KEY_DEL = 0x0000002000000000;
|
||
|
private const long DO_RSA_EXPORT_KEY = 0x0000004000000000;
|
||
|
private const long DO_RSA_IMPORT_KEY = 0x0000008000000000;
|
||
|
private const long DO_RSA_PKM = 0x0000080000000000;
|
||
|
private const long DO_RSA_PKU = 0x0000100000000000;
|
||
|
private const long DO_RSA_EXPORTABLE = 0x0000400000000000;
|
||
|
private const long DO_RSA_FULL_ACCESS = 0x0000800000000000;
|
||
|
private const long DO_RSA_PRIVATE = 0x0001000000000000;
|
||
|
private const long DO_RSA_ENCRYPT_FILE = 0x0004000000000000;
|
||
|
private const long DO_RSA_DECRYPT_FILE = 0x0008000000000000;
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
public void ProtectedConfigAction(long options, string firstArgument, string secondArgument, string providerName, string appPath, string site, string cspOrLocation, int keySize, out IntPtr exception)
|
||
|
{
|
||
|
exception = IntPtr.Zero;
|
||
|
|
||
|
try {
|
||
|
if ((options & DO_RSA_ENCRYPT) != 0) {
|
||
|
DoProtectSection(firstArgument, providerName, appPath, site, cspOrLocation, (options & DO_RSA_PKM) != 0);
|
||
|
} else if ((options & DO_RSA_DECRYPT) != 0) {
|
||
|
DoUnprotectSection(firstArgument, appPath, site, cspOrLocation, (options & DO_RSA_PKM) != 0);
|
||
|
} else if ((options & DO_RSA_ENCRYPT_FILE) != 0) {
|
||
|
DoProtectSectionFile(firstArgument, secondArgument, providerName);
|
||
|
} else if ((options & DO_RSA_DECRYPT_FILE) != 0) {
|
||
|
DoUnprotectSectionFile(firstArgument, secondArgument);
|
||
|
} else if ((options & DO_RSA_ADD_KEY) != 0) {
|
||
|
DoKeyCreate(firstArgument, cspOrLocation, options, keySize);
|
||
|
} else if ((options & DO_RSA_DEL_KEY) != 0) {
|
||
|
DoKeyDelete(firstArgument, cspOrLocation, options);
|
||
|
} else if ((options & DO_RSA_EXPORT_KEY) != 0) {
|
||
|
DoKeyExport(firstArgument, secondArgument, cspOrLocation, options);
|
||
|
} else if ((options & DO_RSA_IMPORT_KEY) != 0) {
|
||
|
DoKeyImport(firstArgument, secondArgument, cspOrLocation, options);
|
||
|
} else if ((options & DO_RSA_ACL_KEY_ADD) != 0 || (options & DO_RSA_ACL_KEY_DEL) != 0) {
|
||
|
DoKeyAclChange(firstArgument, secondArgument, cspOrLocation, options);
|
||
|
} else {
|
||
|
exception = Marshal.StringToBSTR(SR.GetString(SR.Command_not_recognized));
|
||
|
}
|
||
|
} catch (Exception e) {
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
GetExceptionMessage(e, sb);
|
||
|
exception = Marshal.StringToBSTR(sb.ToString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void GetExceptionMessage(Exception exception, StringBuilder sb) {
|
||
|
if (sb.Length != 0) {
|
||
|
sb.Append(NewLine);
|
||
|
}
|
||
|
|
||
|
if (exception is ConfigurationErrorsException) {
|
||
|
foreach(ConfigurationErrorsException e in ((ConfigurationErrorsException)exception).Errors) {
|
||
|
sb.Append(e.Message);
|
||
|
sb.Append(NewLine);
|
||
|
|
||
|
if (e.InnerException != null) {
|
||
|
sb.Append(NewLine);
|
||
|
sb.Append(e.InnerException.Message);
|
||
|
sb.Append(NewLine);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
sb.Append(exception.Message );
|
||
|
sb.Append(NewLine);
|
||
|
|
||
|
if (exception.InnerException != null) {
|
||
|
GetExceptionMessage(exception.InnerException, sb);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void DoProtectSection(string configSection, string providerName, string appPath, string site, string location, bool useMachineConfig)
|
||
|
{
|
||
|
Configuration config;
|
||
|
ConfigurationSection section = GetConfigSection(configSection, appPath, site, location, useMachineConfig, out config);
|
||
|
if (section == null) // Throw an error that the section was not found.
|
||
|
throw new Exception(SR.GetString(SR.Configuration_Section_not_found, configSection));
|
||
|
section.SectionInformation.ProtectSection(providerName);
|
||
|
config.Save();
|
||
|
}
|
||
|
private void DoUnprotectSection(string configSection, string appPath, string site, string location, bool useMachineConfig)
|
||
|
{
|
||
|
Configuration config;
|
||
|
ConfigurationSection section = GetConfigSection(configSection, appPath, site, location, useMachineConfig, out config);
|
||
|
if (section == null) // Throw an error that the section was not found.
|
||
|
throw new Exception(SR.GetString(SR.Configuration_Section_not_found, configSection));
|
||
|
section.SectionInformation.UnprotectSection();
|
||
|
config.Save();
|
||
|
}
|
||
|
private void DoProtectSectionFile(string configSection, string dirName, string providerName)
|
||
|
{
|
||
|
Configuration config;
|
||
|
ConfigurationSection section = GetConfigSectionFile(configSection, dirName, out config);
|
||
|
if (section == null) // Throw an error that the section was not found.
|
||
|
throw new Exception(SR.GetString(SR.Configuration_Section_not_found, configSection));
|
||
|
section.SectionInformation.ProtectSection(providerName);
|
||
|
config.Save();
|
||
|
}
|
||
|
private void DoUnprotectSectionFile(string configSection, string dirName)
|
||
|
{
|
||
|
Configuration config;
|
||
|
ConfigurationSection section = GetConfigSectionFile(configSection, dirName, out config);
|
||
|
if (section == null) // Throw an error that the section was not found.
|
||
|
throw new Exception(SR.GetString(SR.Configuration_Section_not_found, configSection));
|
||
|
section.SectionInformation.UnprotectSection();
|
||
|
config.Save();
|
||
|
}
|
||
|
private ConfigurationSection GetConfigSectionFile(string configSection, string dirName, out Configuration config)
|
||
|
{
|
||
|
if (dirName == ".") {
|
||
|
dirName = Environment.CurrentDirectory;
|
||
|
} else {
|
||
|
if (!Path.IsPathRooted(dirName))
|
||
|
dirName = Path.Combine(Environment.CurrentDirectory, dirName);
|
||
|
if (!Directory.Exists(dirName))
|
||
|
throw new Exception(SR.GetString(SR.Configuration_for_physical_path_not_found, dirName));
|
||
|
}
|
||
|
WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
|
||
|
string appVPath = dirName.Replace('\\', '/');
|
||
|
if (appVPath.Length > 2 && appVPath[1] == ':')
|
||
|
appVPath = appVPath.Substring(2);
|
||
|
else if (appVPath.StartsWith("//", StringComparison.Ordinal)) // UNC share?
|
||
|
appVPath = "/";
|
||
|
fileMap.VirtualDirectories.Add(appVPath, new VirtualDirectoryMapping(dirName, true));
|
||
|
try {
|
||
|
config = WebConfigurationManager.OpenMappedWebConfiguration(fileMap, appVPath);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
throw new Exception(SR.GetString(SR.Configuration_for_physical_path_not_found, dirName), e);
|
||
|
}
|
||
|
|
||
|
return config.GetSection(configSection);
|
||
|
}
|
||
|
|
||
|
private ConfigurationSection GetConfigSection(string configSection, string appPath, string site, string location, bool useMachineConfig, out Configuration config)
|
||
|
{
|
||
|
if (string.IsNullOrEmpty(appPath)) {
|
||
|
appPath = null;
|
||
|
} else {
|
||
|
Debug.Assert(appPath.StartsWith("/", StringComparison.Ordinal), "This check is done in main.cxx in regiis");
|
||
|
}
|
||
|
|
||
|
if (string.IsNullOrEmpty(location))
|
||
|
location = null;
|
||
|
|
||
|
try {
|
||
|
if (useMachineConfig)
|
||
|
config = WebConfigurationManager.OpenMachineConfiguration(location);
|
||
|
else
|
||
|
config = WebConfigurationManager.OpenWebConfiguration(appPath, site, location);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
if (useMachineConfig) {
|
||
|
throw new Exception(SR.GetString(SR.Configuration_for_machine_config_not_found), e);
|
||
|
}
|
||
|
else {
|
||
|
throw new Exception(SR.GetString(SR.Configuration_for_path_not_found, appPath,
|
||
|
String.IsNullOrEmpty(site) ? SR.GetString(SR.DefaultSiteName) : site), e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return config.GetSection(configSection);
|
||
|
}
|
||
|
|
||
|
private void DoKeyCreate(string containerName, string csp, long options, int keySize)
|
||
|
{
|
||
|
if (containerName == null || containerName.Length < 1) {
|
||
|
containerName = DefaultRsaKeyContainerName;
|
||
|
}
|
||
|
|
||
|
uint returnHR = (uint)UnsafeNativeMethods.DoesKeyContainerExist(containerName, csp, ((options & DO_RSA_PKU) == 0) ? 1 : 0);
|
||
|
switch (returnHR) {
|
||
|
case 0:
|
||
|
throw new Exception(SR.GetString(SR.RSA_Key_Container_already_exists));
|
||
|
case 0x80090016: // Not found -- create it
|
||
|
RsaProtectedConfigurationProvider rsaProv = CreateRSAProvider(containerName, csp, options);
|
||
|
try {
|
||
|
rsaProv.AddKey(keySize, (options & DO_RSA_EXPORTABLE) != 0);
|
||
|
} catch {
|
||
|
rsaProv.DeleteKey();
|
||
|
throw;
|
||
|
}
|
||
|
return;
|
||
|
case 0x80070005:
|
||
|
throw new Exception(SR.GetString(SR.RSA_Key_Container_access_denied));
|
||
|
default:
|
||
|
Marshal.ThrowExceptionForHR((int)returnHR);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void DoKeyDelete(string containerName, string csp, long options)
|
||
|
{
|
||
|
if (containerName == null || containerName.Length < 1) {
|
||
|
containerName = DefaultRsaKeyContainerName;
|
||
|
}
|
||
|
|
||
|
MakeSureContainerExists(containerName, csp, (options & DO_RSA_PKU) == 0);
|
||
|
RsaProtectedConfigurationProvider rsaProv = CreateRSAProvider(containerName, csp, options);
|
||
|
rsaProv.DeleteKey();
|
||
|
}
|
||
|
|
||
|
private void DoKeyExport(string containerName, string fileName, string csp, long options)
|
||
|
{
|
||
|
if (!Path.IsPathRooted(fileName))
|
||
|
fileName = Path.Combine(Environment.CurrentDirectory, fileName);
|
||
|
|
||
|
if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(fileName)))
|
||
|
throw new System.IO.DirectoryNotFoundException();
|
||
|
|
||
|
if (containerName == null || containerName.Length < 1) {
|
||
|
containerName = DefaultRsaKeyContainerName;
|
||
|
}
|
||
|
|
||
|
MakeSureContainerExists(containerName, csp, (options & DO_RSA_PKU) == 0);
|
||
|
RsaProtectedConfigurationProvider rsaProv = CreateRSAProvider(containerName, csp, options);
|
||
|
rsaProv.ExportKey(fileName, (options & DO_RSA_PRIVATE) != 0);
|
||
|
}
|
||
|
|
||
|
private void DoKeyImport(string containerName, string fileName, string csp, long options)
|
||
|
{
|
||
|
if (!System.IO.File.Exists(fileName))
|
||
|
throw new System.IO.FileNotFoundException();
|
||
|
|
||
|
if (containerName == null || containerName.Length < 1) {
|
||
|
containerName = DefaultRsaKeyContainerName;
|
||
|
}
|
||
|
|
||
|
RsaProtectedConfigurationProvider rsaProv = CreateRSAProvider(containerName, csp, options);
|
||
|
rsaProv.ImportKey(fileName, (options & DO_RSA_EXPORTABLE) != 0);
|
||
|
}
|
||
|
|
||
|
private void DoKeyAclChange(string containerName, string account, string csp, long options)
|
||
|
{
|
||
|
if (containerName == null || containerName.Length < 1) {
|
||
|
containerName = DefaultRsaKeyContainerName;
|
||
|
}
|
||
|
|
||
|
MakeSureContainerExists(containerName, csp, (options & DO_RSA_PKU) == 0);
|
||
|
int flags = 0;
|
||
|
if ((options & DO_RSA_ACL_KEY_ADD) != 0)
|
||
|
flags |= 0x1; // Add access
|
||
|
if ((options & DO_RSA_PKU) == 0)
|
||
|
flags |= 0x2;
|
||
|
if ((options & DO_RSA_FULL_ACCESS) != 0)
|
||
|
flags |= 0x4;
|
||
|
int returnHR = UnsafeNativeMethods.ChangeAccessToKeyContainer(containerName, account, csp, flags);
|
||
|
if (returnHR != 0)
|
||
|
Marshal.ThrowExceptionForHR(returnHR);
|
||
|
}
|
||
|
|
||
|
private RsaProtectedConfigurationProvider CreateRSAProvider(string containerName, string csp, long options)
|
||
|
{
|
||
|
RsaProtectedConfigurationProvider prov = new RsaProtectedConfigurationProvider();
|
||
|
NameValueCollection nvc = new NameValueCollection();
|
||
|
nvc.Add("keyContainerName", containerName);
|
||
|
nvc.Add("cspProviderName", csp);
|
||
|
nvc.Add("useMachineContainer", ((options & DO_RSA_PKU) != 0) ? "false" : "true");
|
||
|
prov.Initialize("foo", nvc);
|
||
|
return prov;
|
||
|
}
|
||
|
private static void MakeSureContainerExists(string containerName, string csp, bool machineContainer) {
|
||
|
uint returnHR = (uint) UnsafeNativeMethods.DoesKeyContainerExist(containerName, csp, machineContainer ? 1 : 0);
|
||
|
switch (returnHR) {
|
||
|
case 0:
|
||
|
return; // success!
|
||
|
case 0x80090016:
|
||
|
throw new Exception(SR.GetString(SR.RSA_Key_Container_not_found));
|
||
|
case 0x80070005:
|
||
|
throw new Exception(SR.GetString(SR.RSA_Key_Container_access_denied));
|
||
|
default:
|
||
|
Marshal.ThrowExceptionForHR((int)returnHR);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void RemoveBrowserCaps(out IntPtr exception) {
|
||
|
try {
|
||
|
BrowserCapabilitiesCodeGenerator generator = new BrowserCapabilitiesCodeGenerator();
|
||
|
generator.UninstallInternal();
|
||
|
exception = IntPtr.Zero;
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
exception = Marshal.StringToBSTR(e.Message);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class ConversionEventSink : ITypeLibExporterNotifySink
|
||
|
{
|
||
|
public void ReportEvent(ExporterEventKind eventKind, int eventCode, string eventMsg)
|
||
|
{
|
||
|
// Handle the warning event here.
|
||
|
}
|
||
|
|
||
|
public Object ResolveRef(Assembly assemblyReference)
|
||
|
{
|
||
|
// Resolve the reference here and return a correct type library.
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|