Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Runtime / InteropServices / ComEventsMethod.cs / 1305376 / ComEventsMethod.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================ ** ** Class: ComEventsMethod ** ** Purpose: part of ComEventHelpers APIs which allow binding ** managed delegates to COM's connection point based events. ** ** Date: April 2008 **/ using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Runtime.InteropServices; using System.Reflection; #if FEATURE_COMINTEROP namespace System.Runtime.InteropServices { // see code:ComEventsHelper#ComEventsArchitecture internal class ComEventsMethod { // This delegate wrapper class handles dynamic invocation of delegates. The reason for the wrapper's // existence is that under certain circumstances we need to coerce arguments to types expected by the // delegates signature. Normally, reflection (Delegate.DynamicInvoke) handles types coercion // correctly but one known case is when the expected signature is 'ref Enum' - in this case // reflection by design does not do the coercion. Since we need to be compatible with COM interop // handling of this scenario - we are pre-processing delegate's signature by looking for 'ref enums' // and cache the types required for such coercion. internal class DelegateWrapper { private Delegate _d; private bool _once = false; private int _expectedParamsCount; private Type[] _cachedTargetTypes; public DelegateWrapper(Delegate d) { _d = d; } public Delegate Delegate { get { return _d; } set { _d = value; } } public object Invoke(object[] args) { if (_d == null) return null; if (_once == false) { PreProcessSignature(); _once = true; } if (_cachedTargetTypes != null && _expectedParamsCount == args.Length) { for (int i = 0; i < _expectedParamsCount; i++) { if (_cachedTargetTypes[i] != null) { args[i] = Enum.ToObject(_cachedTargetTypes[i], args[i]); } } } return _d.DynamicInvoke(args); } private void PreProcessSignature() { ParameterInfo[] parameters = _d.Method.GetParameters(); _expectedParamsCount = parameters.Length; Type[] enumTypes = new Type[_expectedParamsCount]; bool needToHandleCoercion = false; for (int i = 0; i < _expectedParamsCount; i++) { ParameterInfo pi = parameters[i]; // recognize only 'ref Enum' signatures and cache // both enum type and the underlying type. if (pi.ParameterType.IsByRef && pi.ParameterType.HasElementType && pi.ParameterType.GetElementType().IsEnum) { needToHandleCoercion = true; enumTypes[i] = pi.ParameterType.GetElementType(); } } if (needToHandleCoercion == true) { _cachedTargetTypes = enumTypes; } } } #region private fields ////// Invoking ComEventsMethod means invoking a multi-cast delegate attached to it. /// Since multicast delegate's built-in chaining supports only chaining instances of the same type, /// we need to complement this design by using an explicit linked list data structure. /// private DelegateWrapper [] _delegateWrappers; private int _dispid; private ComEventsMethod _next; #endregion #region ctor internal ComEventsMethod(int dispid) { _delegateWrappers = null; _dispid = dispid; } #endregion #region static internal methods internal static ComEventsMethod Find(ComEventsMethod methods, int dispid) { while (methods != null && methods._dispid != dispid) { methods = methods._next; } return methods; } internal static ComEventsMethod Add(ComEventsMethod methods, ComEventsMethod method) { method._next = methods; return method; } internal static ComEventsMethod Remove(ComEventsMethod methods, ComEventsMethod method) { if (methods == method) { methods = methods._next; } else { ComEventsMethod current = methods; while (current != null && current._next != method) current = current._next; if (current != null) current._next = method._next; } return methods; } #endregion #region public properties / methods internal int DispId { get { return _dispid; } } internal bool Empty { get { return _delegateWrappers == null || _delegateWrappers.Length == 0; } } internal void AddDelegate(Delegate d) { int count = 0; if (_delegateWrappers != null) { count = _delegateWrappers.Length; } for (int i = 0; i < count; i++) { if (_delegateWrappers[i].Delegate.GetType() == d.GetType()) { _delegateWrappers[i].Delegate = Delegate.Combine(_delegateWrappers[i].Delegate, d); return; } } DelegateWrapper [] newDelegateWrappers = new DelegateWrapper[count + 1]; if (count > 0) { _delegateWrappers.CopyTo(newDelegateWrappers, 0); } DelegateWrapper wrapper = new DelegateWrapper(d); newDelegateWrappers[count] = wrapper; _delegateWrappers = newDelegateWrappers; } internal void RemoveDelegate(Delegate d) { int count = _delegateWrappers.Length; int removeIdx = -1; for (int i = 0; i < count; i++) { if (_delegateWrappers[i].Delegate.GetType() == d.GetType()) { removeIdx = i; break; } } if (removeIdx < 0) return; Delegate newDelegate = Delegate.Remove(_delegateWrappers[removeIdx].Delegate, d); if (newDelegate != null) { _delegateWrappers[removeIdx].Delegate = newDelegate; return; } // now remove the found entry from the _delegates array if (count == 1) { _delegateWrappers = null; return; } DelegateWrapper [] newDelegateWrappers = new DelegateWrapper[count - 1]; int j = 0; while (j < removeIdx) { newDelegateWrappers[j] = _delegateWrappers[j]; j++; } while (j < count-1) { newDelegateWrappers[j] = _delegateWrappers[j + 1]; j++; } _delegateWrappers = newDelegateWrappers; } internal object Invoke(object[] args) { BCLDebug.Assert(Empty == false, "event sink is executed but delegates list is empty"); // Issue: see code:ComEventsHelper#ComEventsRetValIssue object result = null; DelegateWrapper[] invocationList = _delegateWrappers; foreach (DelegateWrapper wrapper in invocationList) { if (wrapper == null || wrapper.Delegate == null) continue; result = wrapper.Invoke(args); } return result; } #endregion } } #endif // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================ ** ** Class: ComEventsMethod ** ** Purpose: part of ComEventHelpers APIs which allow binding ** managed delegates to COM's connection point based events. ** ** Date: April 2008 **/ using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Runtime.InteropServices; using System.Reflection; #if FEATURE_COMINTEROP namespace System.Runtime.InteropServices { // see code:ComEventsHelper#ComEventsArchitecture internal class ComEventsMethod { // This delegate wrapper class handles dynamic invocation of delegates. The reason for the wrapper's // existence is that under certain circumstances we need to coerce arguments to types expected by the // delegates signature. Normally, reflection (Delegate.DynamicInvoke) handles types coercion // correctly but one known case is when the expected signature is 'ref Enum' - in this case // reflection by design does not do the coercion. Since we need to be compatible with COM interop // handling of this scenario - we are pre-processing delegate's signature by looking for 'ref enums' // and cache the types required for such coercion. internal class DelegateWrapper { private Delegate _d; private bool _once = false; private int _expectedParamsCount; private Type[] _cachedTargetTypes; public DelegateWrapper(Delegate d) { _d = d; } public Delegate Delegate { get { return _d; } set { _d = value; } } public object Invoke(object[] args) { if (_d == null) return null; if (_once == false) { PreProcessSignature(); _once = true; } if (_cachedTargetTypes != null && _expectedParamsCount == args.Length) { for (int i = 0; i < _expectedParamsCount; i++) { if (_cachedTargetTypes[i] != null) { args[i] = Enum.ToObject(_cachedTargetTypes[i], args[i]); } } } return _d.DynamicInvoke(args); } private void PreProcessSignature() { ParameterInfo[] parameters = _d.Method.GetParameters(); _expectedParamsCount = parameters.Length; Type[] enumTypes = new Type[_expectedParamsCount]; bool needToHandleCoercion = false; for (int i = 0; i < _expectedParamsCount; i++) { ParameterInfo pi = parameters[i]; // recognize only 'ref Enum' signatures and cache // both enum type and the underlying type. if (pi.ParameterType.IsByRef && pi.ParameterType.HasElementType && pi.ParameterType.GetElementType().IsEnum) { needToHandleCoercion = true; enumTypes[i] = pi.ParameterType.GetElementType(); } } if (needToHandleCoercion == true) { _cachedTargetTypes = enumTypes; } } } #region private fields ////// Invoking ComEventsMethod means invoking a multi-cast delegate attached to it. /// Since multicast delegate's built-in chaining supports only chaining instances of the same type, /// we need to complement this design by using an explicit linked list data structure. /// private DelegateWrapper [] _delegateWrappers; private int _dispid; private ComEventsMethod _next; #endregion #region ctor internal ComEventsMethod(int dispid) { _delegateWrappers = null; _dispid = dispid; } #endregion #region static internal methods internal static ComEventsMethod Find(ComEventsMethod methods, int dispid) { while (methods != null && methods._dispid != dispid) { methods = methods._next; } return methods; } internal static ComEventsMethod Add(ComEventsMethod methods, ComEventsMethod method) { method._next = methods; return method; } internal static ComEventsMethod Remove(ComEventsMethod methods, ComEventsMethod method) { if (methods == method) { methods = methods._next; } else { ComEventsMethod current = methods; while (current != null && current._next != method) current = current._next; if (current != null) current._next = method._next; } return methods; } #endregion #region public properties / methods internal int DispId { get { return _dispid; } } internal bool Empty { get { return _delegateWrappers == null || _delegateWrappers.Length == 0; } } internal void AddDelegate(Delegate d) { int count = 0; if (_delegateWrappers != null) { count = _delegateWrappers.Length; } for (int i = 0; i < count; i++) { if (_delegateWrappers[i].Delegate.GetType() == d.GetType()) { _delegateWrappers[i].Delegate = Delegate.Combine(_delegateWrappers[i].Delegate, d); return; } } DelegateWrapper [] newDelegateWrappers = new DelegateWrapper[count + 1]; if (count > 0) { _delegateWrappers.CopyTo(newDelegateWrappers, 0); } DelegateWrapper wrapper = new DelegateWrapper(d); newDelegateWrappers[count] = wrapper; _delegateWrappers = newDelegateWrappers; } internal void RemoveDelegate(Delegate d) { int count = _delegateWrappers.Length; int removeIdx = -1; for (int i = 0; i < count; i++) { if (_delegateWrappers[i].Delegate.GetType() == d.GetType()) { removeIdx = i; break; } } if (removeIdx < 0) return; Delegate newDelegate = Delegate.Remove(_delegateWrappers[removeIdx].Delegate, d); if (newDelegate != null) { _delegateWrappers[removeIdx].Delegate = newDelegate; return; } // now remove the found entry from the _delegates array if (count == 1) { _delegateWrappers = null; return; } DelegateWrapper [] newDelegateWrappers = new DelegateWrapper[count - 1]; int j = 0; while (j < removeIdx) { newDelegateWrappers[j] = _delegateWrappers[j]; j++; } while (j < count-1) { newDelegateWrappers[j] = _delegateWrappers[j + 1]; j++; } _delegateWrappers = newDelegateWrappers; } internal object Invoke(object[] args) { BCLDebug.Assert(Empty == false, "event sink is executed but delegates list is empty"); // Issue: see code:ComEventsHelper#ComEventsRetValIssue object result = null; DelegateWrapper[] invocationList = _delegateWrappers; foreach (DelegateWrapper wrapper in invocationList) { if (wrapper == null || wrapper.Delegate == null) continue; result = wrapper.Invoke(args); } return result; } #endregion } } #endif // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TrackingStringDictionary.cs
- ServiceHttpHandlerFactory.cs
- APCustomTypeDescriptor.cs
- SchemaTypeEmitter.cs
- WebPartConnectVerb.cs
- WebPartChrome.cs
- RequiredAttributeAttribute.cs
- Choices.cs
- ContentWrapperAttribute.cs
- CqlLexerHelpers.cs
- CompiledIdentityConstraint.cs
- OutOfMemoryException.cs
- ErrorHandlerModule.cs
- ColorDialog.cs
- ManagementEventWatcher.cs
- ResourceExpressionBuilder.cs
- ScrollData.cs
- MemberProjectedSlot.cs
- DataGridColumnCollectionEditor.cs
- MetadataArtifactLoaderCompositeFile.cs
- GradientBrush.cs
- Paragraph.cs
- WhitespaceSignificantCollectionAttribute.cs
- HostExecutionContextManager.cs
- ConvertersCollection.cs
- Utils.cs
- CodeDirectoryCompiler.cs
- CompositeActivityDesigner.cs
- SystemWebCachingSectionGroup.cs
- StretchValidation.cs
- RichTextBoxConstants.cs
- ModulesEntry.cs
- ELinqQueryState.cs
- EventProviderTraceListener.cs
- DataSetMappper.cs
- ControlCollection.cs
- GroupStyle.cs
- ScriptBehaviorDescriptor.cs
- NetStream.cs
- GeneralTransform2DTo3D.cs
- AppSettingsExpressionEditor.cs
- FlatButtonAppearance.cs
- VirtualDirectoryMappingCollection.cs
- WebPartTransformerAttribute.cs
- EncodingInfo.cs
- RtfToken.cs
- DbParameterCollectionHelper.cs
- SecurityResources.cs
- XslTransform.cs
- MimeMapping.cs
- TailPinnedEventArgs.cs
- PreDigestedSignedInfo.cs
- MsmqInputSessionChannelListener.cs
- ImageDrawing.cs
- ValueHandle.cs
- HeaderedContentControl.cs
- DESCryptoServiceProvider.cs
- LicenseException.cs
- Int64Storage.cs
- HealthMonitoringSectionHelper.cs
- MemoryPressure.cs
- ParsedAttributeCollection.cs
- CachedRequestParams.cs
- ProbeMatchesMessage11.cs
- RawAppCommandInputReport.cs
- ShaperBuffers.cs
- mediaeventargs.cs
- NoPersistProperty.cs
- TreeNode.cs
- BatchServiceHost.cs
- RemotingException.cs
- MethodToken.cs
- ResourceDictionaryCollection.cs
- DataGridViewColumn.cs
- TypeUsage.cs
- AnchoredBlock.cs
- Directory.cs
- WebException.cs
- BufferBuilder.cs
- PagePropertiesChangingEventArgs.cs
- XmlExtensionFunction.cs
- _KerberosClient.cs
- EncoderParameter.cs
- SiteMapNodeItemEventArgs.cs
- MenuItem.cs
- DllNotFoundException.cs
- HtmlHead.cs
- SymLanguageVendor.cs
- DocumentSchemaValidator.cs
- SamlDoNotCacheCondition.cs
- XmlEntityReference.cs
- UserMapPath.cs
- TypeBuilderInstantiation.cs
- SiteMapDataSource.cs
- CacheAxisQuery.cs
- CounterSet.cs
- MultitargetUtil.cs
- DbConnectionStringBuilder.cs
- KeysConverter.cs
- LOSFormatter.cs