Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Graphics / include / exports.cs / 1305600 / exports.cs
//---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: exports.cs // // Description: // Managed exports from MIL core. //--------------------------------------------------------------------------- using System; using System.Collections; using System.ComponentModel; using System.Threading; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Media.Effects; using System.Windows.Media.Media3D; using System.Runtime.InteropServices; using System.Windows.Media.Animation; using MS.Internal; using MS.Internal.Interop; using MS.Utility; using MS.Win32; using System.Diagnostics; using System.Collections.Generic; using System.Security; using System.Security.Permissions; using Microsoft.Internal; using Microsoft.Win32.SafeHandles; using UnsafeNativeMethods=MS.Win32.PresentationCore.UnsafeNativeMethods; using SafeNativeMethods=MS.Win32.PresentationCore.SafeNativeMethods; using HRESULT=MS.Internal.HRESULT; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; /* * * For the time being the flat composition api will be implemented on * top of milcore.h (the protocol api), this is only temporary we will * be adding type safe unmanaged exports to milcore.dll which will be * be called from the static functions. * */ namespace System.Windows.Media.Composition { // enumeration of marshal types supported by the transport. internal enum ChannelMarshalType { ChannelMarshalTypeInvalid = 0x0, ChannelMarshalTypeSameThread = 0x1, ChannelMarshalTypeCrossThread = 0x2 }; ////// Lock replacement till the CLR team gives us support to resolve the reentrancy issues /// with the CLR lock. /// ////// Prefered usage pattern: /// /// internal struct CompositionEngineLock : IDisposable { ////// using (CompositionEngineLock.Acquire()) /// { /// ... /// } ///
/// /// If you don't use this pattern remember to have a try finally block to release the lock /// in the event of an exception. ////// Aquires the composition engine lock. /// ////// Critical - calls unmanaged code /// TreatAsSafe - all inputs validated, locking is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static CompositionEngineLock Acquire() { UnsafeNativeMethods.MilCoreApi.EnterCompositionEngineLock(); return new CompositionEngineLock(); } ////// Releases the composition engine lock. Using Dispose enables the using syntax. /// ////// Critical - calls unmanaged code /// TreatAsSafe - all inputs validated, unlocking is safe /// [SecurityCritical, SecurityTreatAsSafe] public void Dispose() { UnsafeNativeMethods.MilCoreApi.ExitCompositionEngineLock(); } } ////// The following class only exists to clearly separate the DUCE APIs /// from the legacy resource APIs. /// internal partial class DUCE { ////// CopyBytes - Poor-man's mem copy. Copies cbData from pbFrom to pbTo. /// pbFrom and pbTo must be DWORD aligned, and cbData must be a multiple of 4. /// /// byte* pointing to the "to" array. Must be DWORD aligned. /// byte* pointing to the "from" array. Must be DWORD aligned. /// int - count of bytes to copy. Must be a multiple of 4. ////// Critical: This code accesses an unsafe code block /// [SecurityCritical] internal static unsafe void CopyBytes(byte* pbTo, byte* pbFrom, int cbData) { // We'd like to only handle QWORD aligned data, but the CLR can't enforce this. // If there's no data to copy, it's ok if the pointers aren't aligned Debug.Assert((cbData == 0) || ((Int64)(IntPtr)pbFrom) % 4 == 0); Debug.Assert((cbData == 0) || ((Int64)(IntPtr)pbTo) % 4 == 0); Debug.Assert(cbData % 4 == 0); Debug.Assert(cbData >= 0); Int32* pCurFrom32 = (Int32*)pbFrom; Int32* pCurTo32 = (Int32*)pbTo; for (int i = 0; i < cbData / 4; i++) { pCurTo32[i] = pCurFrom32[i]; } } ////// Critical - pinvoke wrappers /// [SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity] private static class UnsafeNativeMethods { [DllImport(DllImport.MilCore)] internal static extern /*HRESULT*/ int MilResource_CreateOrAddRefOnChannel( IntPtr pChannel, DUCE.ResourceType resourceType, ref DUCE.ResourceHandle hResource ); [DllImport(DllImport.MilCore)] internal static extern /*HRESULT*/ int MilResource_DuplicateHandle( IntPtr pSourceChannel, DUCE.ResourceHandle original, IntPtr pTargetChannel, ref DUCE.ResourceHandle duplicate ); [DllImport(DllImport.MilCore, EntryPoint = "MilConnection_CreateChannel")]//CASRemoval: internal static extern int MilConnection_CreateChannel( IntPtr pTransport, IntPtr hChannel, out IntPtr channelHandle); [DllImport(DllImport.MilCore, EntryPoint = "MilConnection_DestroyChannel")]//CASRemoval: internal static extern int MilConnection_DestroyChannel( IntPtr channelHandle); [DllImport(DllImport.MilCore, EntryPoint = "MilChannel_CloseBatch")]//CASRemoval: internal static extern int MilConnection_CloseBatch( IntPtr channelHandle); [DllImport(DllImport.MilCore, EntryPoint = "MilChannel_CommitChannel")]//CASRemoval: internal static extern int MilConnection_CommitChannel( IntPtr channelHandle); [DllImport(DllImport.MilCore)]//CASRemoval: internal static extern int WgxConnection_SameThreadPresent( IntPtr pConnection); [DllImport(DllImport.MilCore, EntryPoint = "MilChannel_GetMarshalType")] internal static extern int MilChannel_GetMarshalType(IntPtr channelHandle, out ChannelMarshalType marshalType); [DllImport (DllImport.MilCore, EntryPoint = "MilResource_SendCommand")]//CASRemoval: unsafe internal static extern int MilResource_SendCommand( byte *pbData, uint cbSize, bool sendInSeparateBatch, IntPtr pChannel); [DllImport (DllImport.MilCore, EntryPoint = "MilChannel_BeginCommand")]//CASRemoval: unsafe internal static extern int MilChannel_BeginCommand( IntPtr pChannel, byte *pbData, uint cbSize, uint cbExtra ); [DllImport (DllImport.MilCore, EntryPoint = "MilChannel_AppendCommandData")]//CASRemoval: unsafe internal static extern int MilChannel_AppendCommandData( IntPtr pChannel, byte *pbData, uint cbSize ); [DllImport (DllImport.MilCore, EntryPoint = "MilChannel_EndCommand")]//CASRemoval: unsafe internal static extern int MilChannel_EndCommand( IntPtr pChannel); [DllImport (DllImport.MilCore, EntryPoint = "MilResource_SendCommandMedia")]//CASRemoval: unsafe internal static extern int MilResource_SendCommandMedia( ResourceHandle handle, SafeMediaHandle pMedia, IntPtr pChannel, bool notifyUceDirect ); [DllImport (DllImport.MilCore, EntryPoint = "MilResource_SendCommandBitmapSource")]//CASRemoval: unsafe internal static extern int MilResource_SendCommandBitmapSource( ResourceHandle handle, BitmapSourceSafeMILHandle /* IWICBitmapSource */ pBitmapSource, IntPtr pChannel); [DllImport(DllImport.MilCore, EntryPoint = "MilResource_ReleaseOnChannel")]//CASRemoval: internal static extern /*HRESULT*/ int MilResource_ReleaseOnChannel( IntPtr pChannel, DUCE.ResourceHandle hResource, out int deleted ); [DllImport(DllImport.MilCore)] internal static extern int MilChannel_SetNotificationWindow( IntPtr pChannel, IntPtr hwnd, WindowMessage message ); [DllImport(DllImport.MilCore)] internal static extern int MilComposition_WaitForNextMessage( IntPtr pChannel, int nCount, IntPtr[] handles, int bWaitAll, UInt32 waitTimeout, out int waitReturn ); [DllImport(DllImport.MilCore)] internal static extern int MilComposition_PeekNextMessage( IntPtr pChannel, out MilMessage.Message message, /* size_t */ IntPtr messageSize, out int messageRetrieved ); [DllImport(DllImport.MilCore, EntryPoint = "MilResource_GetRefCountOnChannel")] internal static extern /*HRESULT*/ int MilResource_GetRefCountOnChannel( IntPtr pChannel, DUCE.ResourceHandle hResource, out uint refCount ); } ////// Define the value of an infinte wait in WaitForNextMessage. /// internal const UInt32 waitInfinite = UInt32.MaxValue; internal static class MilMessage { ////// The ID of each type of back-channel notification messages. /// internal enum Type { Invalid = 0x00, SyncFlushReply = 0x01, Caps = 0x04, PartitionIsZombie = 0x06, SyncModeStatus = 0x09, Presented = 0x0A, BadPixelShader = 0x10, ForceDWORD = unchecked((int)0xffffffff) }; [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct CapsData { [FieldOffset(0)] internal Int32 CommonMinimumCaps; [FieldOffset(4)] internal UInt32 DisplayUniqueness; [FieldOffset(8)] internal MilGraphicsAccelerationCaps Caps; }; [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct PartitionIsZombieStatus { [FieldOffset(0)] internal int HRESULTFailureCode; }; [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct SyncModeStatus { [FieldOffset(0)] internal int Enabled; }; [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct Presented { [FieldOffset(0)] internal MIL_PRESENTATION_RESULTS PresentationResults; [FieldOffset(4)] internal int RefreshRate; [FieldOffset(8)] internal long PresentationTime; }; ////// The union of all known back-channel notification messages. /// [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct Message { [FieldOffset(0)] internal Type Type; [FieldOffset(4)] internal int Reserved; [FieldOffset(8)] internal CapsData Caps; [FieldOffset(8)] internal PartitionIsZombieStatus HRESULTFailure; [FieldOffset(8)] internal Presented Presented; [FieldOffset(8)] internal SyncModeStatus SyncModeStatus; }; } ////// A channel set is a container for a matched pair of channels, /// one primary channel and out of band channel /// internal struct ChannelSet { internal Channel Channel; internal Channel OutOfBandChannel; } ////// A Channel is a command pipe into a composition device. /// The commands send through a Channel are not executed till /// Channel.Commit is called. Committing a Channel is an atomic operation. In /// other words, all the commands are executed before the next frame is /// rendered. /// /// A channel is also a hard boundary for UCE resources. That means that UCE /// resources created on one channel can not interact with resources on a different /// channel. /// internal sealed partial class Channel { ////// Primary channel. /// ////// Critical - Track usage of the channel pointer. /// [SecurityCritical] IntPtr _hChannel; private Channel _referenceChannel; private bool _isSynchronous; private bool _isOutOfBandChannel; IntPtr _pConnection; ////// Creates a channel and associates it with channel group (partition). /// New create channel will belong to the same partition as the given referenceChannel. /// To create the very first channel in the group, use null argument. /// ////// Critical - accesses critical resources (handles) /// [SecurityCritical] public Channel(Channel referenceChannel, bool isOutOfBandChannel, IntPtr pConnection, bool isSynchronous) { IntPtr referenceChannelHandle = IntPtr.Zero; _referenceChannel = referenceChannel; _pConnection = pConnection; _isOutOfBandChannel = isOutOfBandChannel; _isSynchronous = isSynchronous; if (referenceChannel != null) { referenceChannelHandle = referenceChannel._hChannel; } HRESULT.Check(UnsafeNativeMethods.MilConnection_CreateChannel( _pConnection, referenceChannelHandle, out _hChannel)); } ////// Commits the commands enqueued into the Channel. /// ////// Critical: This code calls into MilConnection_CommitChannel which causes an elevation /// TreatAsSafe: This commits operations to the channel. Committing to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal void Commit() { if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state when more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } HRESULT.Check(UnsafeNativeMethods.MilConnection_CommitChannel( _hChannel)); } ////// Closes the current batch on the Channel. /// ////// Critical: This code calls into MilConnection_CloseBatch which causes an elevation /// TreatAsSafe: Closing a batch is safe and nothing is exposed. Batches are in the /// render thread, and can only be written to from the UI thread while /// they're open using other SC/STAS methods on DUCE.Channel. Once closed, /// the only operation that can be done on a batch is Channel.Commit. /// [SecurityCritical,SecurityTreatAsSafe] internal void CloseBatch() { if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state when more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } HRESULT.Check(UnsafeNativeMethods.MilConnection_CloseBatch( _hChannel)); } ////// Flush the currently recorded commands to the target device and prepare /// to receive new commands. Block until last command was executed. /// ////// Critical - This code calls into MilComposition_SyncFlush which causes an elevation. /// TreatAsSafe - The net effect is to wait until render completes. /// [SecurityCritical, SecurityTreatAsSafe] internal void SyncFlush() { if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } HRESULT.Check(MilCoreApi.MilComposition_SyncFlush(_hChannel)); } ////// Commits the channel and then closes it. /// ////// Critical - This code calls into MilConnection_CommitChannel and /// MilConnection_DestroyChannel which causes an elevation. /// TreatAsSafe - Even if called prematurely, this will simply make all the subsequent /// channel operations fail (whether silently or by raising an exception). /// [SecurityCritical, SecurityTreatAsSafe] internal void Close() { if (_hChannel != IntPtr.Zero) { HRESULT.Check(UnsafeNativeMethods.MilConnection_CloseBatch(_hChannel)); HRESULT.Check(UnsafeNativeMethods.MilConnection_CommitChannel(_hChannel)); } _referenceChannel = null; if (_hChannel != IntPtr.Zero) { HRESULT.Check(UnsafeNativeMethods.MilConnection_DestroyChannel(_hChannel)); _hChannel = IntPtr.Zero; } } ////// Commits the commands enqueued into the Channel. /// ////// Critical -- Calls into MilChannel_Present which causes an elevation. /// TreatAsSafe -- This call is only relevant to synchronous channels and causes the compositor /// associated with the synchronous channel to compose and present, which is /// considered safe. Asynchronous channels no-op this call. /// [SecurityCritical,SecurityTreatAsSafe] internal void Present() { HRESULT.Check(UnsafeNativeMethods.WgxConnection_SameThreadPresent(_pConnection)); } ////// Internal only: CreateOrAddRefOnChannel addrefs the resource corresponding to the /// specified handle on the channel. /// ////// Returns true iff the resource was created on the channel. The caller is responsible to /// update the resource appropriately. /// ////// Critical - Calls into MilResource_CreateOrAddRefOnChannel which causes an elevation. /// TreatAsSafe - All inputs are safe wrappers, manipulating handle on the channel /// will only affect resources that belong to the current process. /// [SecurityCritical, SecurityTreatAsSafe] internal bool CreateOrAddRefOnChannel(object instance, ref DUCE.ResourceHandle handle, DUCE.ResourceType resourceType) { bool handleNeedsCreation = handle.IsNull; Invariant.Assert(_hChannel != IntPtr.Zero); HRESULT.Check(UnsafeNativeMethods.MilResource_CreateOrAddRefOnChannel( _hChannel, resourceType, ref handle )); if (EventTrace.IsEnabled(EventTrace.Keyword.KeywordGraphics | EventTrace.Keyword.KeywordPerf, EventTrace.Level.PERF_LOW)) { EventTrace.EventProvider.TraceEvent(EventTrace.Event.CreateOrAddResourceOnChannel, EventTrace.Keyword.KeywordGraphics | EventTrace.Keyword.KeywordPerf, EventTrace.Level.PERF_LOW, PerfService.GetPerfElementID(instance), _hChannel, (uint) handle, (uint) resourceType); } return handleNeedsCreation; } ////// DuplicateHandle attempts to duplicate a handle from one channel to another. /// Naturally, this can only work if both the source and target channels are /// within the same partition. /// ////// It is the responsibility of the caller to commit the source channel /// to assure that duplication took place. /// tables. /// ////// Returns the duplicated handle (valid on the target channel) or the null /// handle if duplication failed. /// ////// Critical - Calls security critical code. /// TreatAsSafe - All inputs are safe wrappers, manipulating handle on the channel /// will only affect resources that belong to the current process. /// [SecurityCritical, SecurityTreatAsSafe] internal DUCE.ResourceHandle DuplicateHandle( DUCE.ResourceHandle original, DUCE.Channel targetChannel ) { DUCE.ResourceHandle duplicate = DUCE.ResourceHandle.Null; //Debug.WriteLine(string.Format("DuplicateHandle: Channel: {0}, Resource: {1}, Target channel: {2}, ", _hChannel, original._handle, targetChannel)); HRESULT.Check(UnsafeNativeMethods.MilResource_DuplicateHandle( _hChannel, original, targetChannel._hChannel, ref duplicate )); return duplicate; } ////// Internal only: ReleaseOnChannel releases the resource corresponding to the specified /// handle on the channel. /// ////// Returns true iff the resource is not on this channel anymore. /// ////// Critical - Calls security critical code. /// TreatAsSafe - All inputs are safe wrappers, manipulating handle on the channel /// will only affect resources that belong to the current process. /// [SecurityCritical, SecurityTreatAsSafe] internal bool ReleaseOnChannel(DUCE.ResourceHandle handle) { Invariant.Assert(_hChannel != IntPtr.Zero); Debug.Assert(!handle.IsNull); //Debug.WriteLine(string.Format("ReleaseOnChannel: Channel: {0}, Resource: {1}", _hChannel, handle._handle)); int releasedOnChannel; HRESULT.Check(UnsafeNativeMethods.MilResource_ReleaseOnChannel( _hChannel, handle, out releasedOnChannel )); if ((releasedOnChannel != 0) && EventTrace.IsEnabled(EventTrace.Keyword.KeywordGraphics | EventTrace.Keyword.KeywordPerf, EventTrace.Level.PERF_LOW)) { EventTrace.EventProvider.TraceEvent(EventTrace.Event.ReleaseOnChannel, EventTrace.Keyword.KeywordGraphics | EventTrace.Keyword.KeywordPerf, EventTrace.Level.PERF_LOW, _hChannel, (uint) handle); } return (releasedOnChannel != 0); } ////// Internal only: GetRefCount returns the reference count of a resource /// corresponding to the specified handle on the channel. /// ////// Returns the ref count for a resource on this channel. /// ////// Critical - Calls security critical code. /// TreatAsSafe - All inputs are safe wrappers, manipulating handle on the channel /// will only affect resources that belong to the current process. /// [SecurityCritical, SecurityTreatAsSafe] internal uint GetRefCount(DUCE.ResourceHandle handle) { Invariant.Assert(_hChannel != IntPtr.Zero); Debug.Assert(!handle.IsNull); uint refCount; HRESULT.Check(UnsafeNativeMethods.MilResource_GetRefCountOnChannel( _hChannel, handle, out refCount )); return refCount; } ////// IsConnected returns true if the channel is connected. /// ////// Critical - this code performs an elevation. /// TreatAsSafe - it's safe to return whether a channel is connected or not. /// internal bool IsConnected { [SecurityCritical, SecurityTreatAsSafe] get { return MediaContext.CurrentMediaContext.IsConnected; } } ////// MarshalType returns the marshal type of the channel. /// ////// Critical - this code performs an elevation. /// TreatAsSafe - it's safe to return a channel's marshal type. /// internal ChannelMarshalType MarshalType { [SecurityCritical, SecurityTreatAsSafe] get { Invariant.Assert(_hChannel != IntPtr.Zero); ChannelMarshalType marshalType; HRESULT.Check(UnsafeNativeMethods.MilChannel_GetMarshalType( _hChannel, out marshalType )); return marshalType; } } ////// Returns whether the given channel is synchronous. /// internal bool IsSynchronous { get { return _isSynchronous; } } ////// Returns whether the given channel is an out of band channel. /// internal bool IsOutOfBandChannel { get { return _isOutOfBandChannel; } } ////// SendCommand sends a command struct through the composition thread. /// ////// Critical - This code performs an elevation. /// TreatAsSafe - This method is safe, as Channel structures can only be created /// by MediaContext and are hardened against invalid data. /// [SecurityCritical, SecurityTreatAsSafe ] unsafe internal void SendCommand( byte *pCommandData, int cSize) { SendCommand(pCommandData, cSize, false); } ////// SendCommand sends a command struct through the composition thread. The /// sendInSeparateBatch parameter determines whether the command is sent in the /// current open batch, or whether it will be added to a new and separate batch /// which is then immediately closed, leaving the current batch untouched. /// ////// Critical - This code performs an elevation. /// TreatAsSafe - This method is safe, as Channel structures can only be created /// by MediaContext and are hardened against invalid data. /// [SecurityCritical, SecurityTreatAsSafe ] [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions] unsafe internal void SendCommand( byte *pCommandData, int cSize, bool sendInSeparateBatch) { checked { Invariant.Assert(pCommandData != (byte*)0 && cSize > 0); int hr = HRESULT.S_OK; if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state when more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } // // The pCommandData should not contain SecurityCritical resources; // SendSecurityCriticalCommand should be called instead. // Invariant.Assert(!IsSecurityCriticalCommand(pCommandData)); try { hr = UnsafeNativeMethods.MilResource_SendCommand( pCommandData, (uint)cSize, sendInSeparateBatch, _hChannel); } catch (AccessViolationException) { throw new ArgumentException(SR.Get(MS.Internal.PresentationCore.SRID.Channel_InvalidCommandBufferPointer)); } HRESULT.Check(hr); } } ////// SendSecurityCriticalCommand sends a command struct to the composition thread. /// It is used for sending commands which contain security critical fields like /// hwnd and pointers /// ////// Critical - This code performs an elevation. /// [SecurityCritical] unsafe internal void SendSecurityCriticalCommand( byte *pCommandData, int cSize, bool sendInSeparateBatch ) { checked { Invariant.Assert(pCommandData != (byte*)0 && cSize > 0); int hr = HRESULT.S_OK; if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } // // Make sure that this function is only called for SecurityCritical // command. Otherwise SendCommand should be called. // Debug.Assert(IsSecurityCriticalCommand(pCommandData)); try { hr = UnsafeNativeMethods.MilResource_SendCommand( pCommandData, (uint)cSize, sendInSeparateBatch, _hChannel); } catch (AccessViolationException) { throw new ArgumentException(SR.Get(SRID.Channel_InvalidCommandBufferPointer)); } HRESULT.Check(hr); } } ////// BeginCommand opens a command on a channel /// ////// Critical - This code performs an elevation. /// TreatAsSafe - This method is safe, as Channel structures can only be created /// by MediaContext and are hardened against invalid data. /// [SecurityCritical, SecurityTreatAsSafe] unsafe internal void BeginCommand( byte *pbCommandData, int cbSize, int cbExtra) { checked { Invariant.Assert(cbSize > 0); int hr = HRESULT.S_OK; if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } try { hr = UnsafeNativeMethods.MilChannel_BeginCommand( _hChannel, pbCommandData, (uint)cbSize, (uint)cbExtra ); } catch (AccessViolationException) { throw new ArgumentException(SR.Get(SRID.Channel_InvalidCommandBufferPointer)); } HRESULT.Check(hr); } } ////// AppendCommandData appends data to an open command on a channel /// ////// Critical - This code performs an elevation. /// TreatAsSafe - This method is safe, as Channel structures can only be created /// by MediaContext and are hardened against invalid data. /// [SecurityCritical, SecurityTreatAsSafe] unsafe internal void AppendCommandData( byte *pbCommandData, int cbSize) { checked { Invariant.Assert(pbCommandData != (byte*)0 && cbSize > 0); int hr = HRESULT.S_OK; if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } try { hr = UnsafeNativeMethods.MilChannel_AppendCommandData( _hChannel, pbCommandData, (uint)cbSize ); } catch (AccessViolationException) { throw new ArgumentException(SR.Get(SRID.Channel_InvalidCommandBufferPointer)); } HRESULT.Check(hr); } } ////// EndCommand closes an open command on a channel /// ////// Critical - this code performs an elevation. /// TreatAsSafe - it's safe to end a command in a well known channel. /// [SecurityCritical, SecurityTreatAsSafe] internal void EndCommand() { if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } HRESULT.Check(UnsafeNativeMethods.MilChannel_EndCommand(_hChannel)); } ////// SendCommand that creates an slave bitmap resource /// ////// Critical - this code performs an elevation. /// [SecurityCritical] internal void SendCommandBitmapSource( DUCE.ResourceHandle imageHandle, BitmapSourceSafeMILHandle pBitmapSource ) { Invariant.Assert(pBitmapSource != null && !pBitmapSource.IsInvalid); Invariant.Assert(_hChannel != IntPtr.Zero); HRESULT.Check(UnsafeNativeMethods.MilResource_SendCommandBitmapSource( imageHandle, pBitmapSource, _hChannel)); } ////// SendCommand that creates an slave media resource /// ////// Critical - this code performs an elevation. /// [SecurityCritical] internal void SendCommandMedia( DUCE.ResourceHandle mediaHandle, SafeMediaHandle pMedia, bool notifyUceDirect ) { Invariant.Assert(pMedia != null && !pMedia.IsInvalid); Invariant.Assert(_hChannel != IntPtr.Zero); HRESULT.Check(UnsafeNativeMethods.MilResource_SendCommandMedia( mediaHandle, pMedia, _hChannel, notifyUceDirect )); } ////// Specifies the window and window message to be sent when messages /// become available in the back channel. /// /// /// The target of the notification messages. If this parameter is null /// then the channel stop sending window messages. /// /// /// The window message ID. If the hwnd parameter is null then this /// parameter is ignored. /// ////// Critical - Passes a window handle to native code. This will /// cause milcore to periodically post the specified /// message to the specified window. The caller is /// safe if it owns the window and the message was /// registered with RegisterMessage. /// [SecurityCritical] internal void SetNotificationWindow(IntPtr hwnd, WindowMessage message) { Invariant.Assert(_hChannel != IntPtr.Zero); HRESULT.Check(UnsafeNativeMethods.MilChannel_SetNotificationWindow( _hChannel, hwnd, message )); } ////// Waits until a message is available on this channel. The message /// can be later retrieved with the PeekNextMessage method. /// ////// The method may return with no available messages if the channel /// is disconnected while waiting. /// ////// Critical - Blocks the thread until the channel receives /// a message. This is unsafe if done by any /// component other than the owner of the channel /// because the channel may not send any /// messages, in which case the function will /// never return. Only the owner of the channel /// knows whether a message can be reasonably /// expected to eventually be sent. /// [SecurityCritical] internal void WaitForNextMessage() { int waitReturn; HRESULT.Check(UnsafeNativeMethods.MilComposition_WaitForNextMessage( _hChannel, 0, null, 1, /* true */ waitInfinite, out waitReturn )); } ////// Gets the next available message on this channel. This method /// does not wait if a message is not immediately available. /// /// /// Receives the message. /// ////// True if a message was retrieved, false otherwise. /// ////// Critical - Removes a message from the channel. This is /// unsafe if done by any component other than /// the owner of the channel because eating /// messages may result in the process hanging. /// Also has an unsafe block, but that is safe /// to callers because we just need it to use /// the sizeof operator. /// [SecurityCritical] internal bool PeekNextMessage(out MilMessage.Message message) { Invariant.Assert(_hChannel != IntPtr.Zero); int messageRetrieved; checked { unsafe { HRESULT.Check(UnsafeNativeMethods.MilComposition_PeekNextMessage( _hChannel, out message, (IntPtr)sizeof(MilMessage.Message), out messageRetrieved )); } } return (messageRetrieved != 0); } } ////// The Resource structure encapsulates the functionality /// required to hold on to a UCE resource. A resource can be sent to a /// channel by calling CreateOrAddRefOnChannel. The resource can be deleted /// from a channel by calling ReleaseOnChannel. /// /// With resources the handle management is completely hidden from the caller. /// internal struct Resource { public static readonly Resource Null = new Resource(DUCE.ResourceHandle.Null); private DUCE.ResourceHandle _handle; #if DEBUG private Channel _debugOnly_Channel; #endif ////// THIS IS A TEMPORARY API; DO NOT USE FOR ANYTHING ELSE. /// Creates a resource from a type and ResourceHandle. /// This is currently only used for some hwnd interop code in the VisualManager. /// public Resource(DUCE.ResourceHandle h) { _handle = h; #if DEBUG _debugOnly_Channel = null; #endif } ////// CreatesOrAddRefs the resource on the specified channel. /// public bool CreateOrAddRefOnChannel(object instance, Channel channel, DUCE.ResourceType type) { Debug.Assert(channel != null); #if DEBUG _debugOnly_Channel = channel; #endif return channel.CreateOrAddRefOnChannel(instance, ref _handle, type); } ////// Releases the resource from the specified channel. /// Returns true if the resource is not anymore on the specified channel /// otherwise false. /// ////// Returns true iff the resource is not used on the specified channel anymore. /// public bool ReleaseOnChannel(Channel channel) { Debug.Assert(channel != null); #if DEBUG Debug.Assert(_debugOnly_Channel == channel); #endif if (channel.ReleaseOnChannel(_handle)) { _handle = DUCE.ResourceHandle.Null; return true; } return false; } ////// Checks if a resource was created on the specified channel. /// public bool IsOnChannel(Channel channel) { #if DEBUG Debug.Assert(_debugOnly_Channel == channel); #endif return !_handle.IsNull; } ////// Returns the real UInt32 handle. public DUCE.ResourceHandle Handle { get { return _handle; } } } /// /// ResourceHandle currently encapsulates an unmanaged resource handle. /// [StructLayout(LayoutKind.Explicit)] internal struct ResourceHandle { public static readonly ResourceHandle Null = new ResourceHandle(0); public static explicit operator uint(ResourceHandle r) { return r._handle; } [FieldOffset(0)] private UInt32 _handle; public ResourceHandle(UInt32 handle) { _handle = handle; } ////// Checks if the handle is null. /// public bool IsNull { get { return (_handle == 0); } } } ////// This is a generic map that maps a key to a value. It is heavily optimized /// for a single entry. /// ////// We are using this map to map a resource onto multple channels. This is non-optimal /// solution. The map is currently used by the MultiChannelResource. Eventually, when all /// the UCE underlyings are in place, we will be able to remove the MultiChannelResource. /// internal struct Map{ /// /// Struct for single entry. /// private struct Entry { public Entry(object k, ValueType v) { _key = k; _value = v; } public object _key; public ValueType _value; } private const int FOUND_IN_INLINE_STORAGE = -1; private const int NOT_FOUND = -2; // This data structure is optimized for single entry. _first is the one entry that we inline // into the struct for that purpose. private Entry _first; // All other entries go into the generic _others list. private List_others; public bool IsEmpty() { if (_first._key != null) { return false; } if (_others != null) { return false; } return true; } /// /// Finds the index of the entry with the specified key. Returns FOUND_IN_INLINE_STORAGE if the /// key is stored in the _first inlined entry and NOT_FOUND if the key could not be found. /// Otherwise the method returns the index into the _others list. /// private int Find(object key) { int index = NOT_FOUND; // Not found. if (_first._key != null) { if (_first._key == key) { index = FOUND_IN_INLINE_STORAGE; // It's stored in our inlined storage. } else { if (_others != null) { for (int i = 0; i < _others.Count; i++) { if (_others[i]._key == key) { index = i; break; } } } } } #if DEBUG else { Debug.Assert(_others == null, "There shouldn't be anything stored in the others array."); } #endif return index; } ////// Associates a key with the specified value. If the entry already exits the old value is overriden. /// public void Set(object key, ValueType value) { int index = Find(key); if (index == FOUND_IN_INLINE_STORAGE) { _first._value = value; } else { if (index == NOT_FOUND) { if (_first._key == null) { _first = new Entry(key, value); } else { if (_others == null) { _others = new List(2); // by default we have two entries in the extra storage. } _others.Add(new Entry(key, value)); } } else { _others[index] = new Entry(key, value); } } } /// /// Removes an entry from the map. Returns true if the entry to the specified index existed and was removed /// otherwise false. /// public bool Remove(object key) { int index = Find(key); if (index == FOUND_IN_INLINE_STORAGE) { if (_others != null) { Debug.Assert(_others.Count > 0); int j = _others.Count-1; _first = _others[j]; if (j == 0) // Only one entry in the array. { _others = null; } else { _others.RemoveAt(j); } } else { _first = new Entry(); } return true; } else { if (index >= 0) { if (_others.Count == 1) { Debug.Assert(index == 0); _others = null; } else { _others.RemoveAt(index); } return true; } } return false; } ////// Gets the value for the specified key. If the entry for the specified key could not /// be found the Get method returns false otherwise true. /// public bool Get(object key, out ValueType value) { int index = Find(key); value = default(ValueType); if (index == FOUND_IN_INLINE_STORAGE) { value = _first._value; return true; } else { if (index >= 0) { value = _others[index]._value; return true; } else { return false; } } } ////// Gets the object count in the map. /// public int Count() { if (_first._key == null) { return 0; } else if (_others == null) { return 1; } else { return _others.Count + 1; } } ////// Gets the object at a given index. /// public object Get(int index) { if (index >= Count()) { return null; } if (index == 0) { return _first._key; } return _others[index - 1]._key; } } ////// This is a generic map that maps a key to a value. It is heavily optimized /// for a single entry. /// ////// We are using this map to map a resource onto multple channels. This is non-optimal /// solution. The map is currently used by the MultiChannelResource. Eventually, when all /// the UCE underlyings are in place, we will be able to remove the MultiChannelResource. /// internal struct Map { ////// Struct for single entry. /// private struct Entry { public Entry(object k, DUCE.ResourceHandle v) { _key = k; _value = v; } public object _key; public DUCE.ResourceHandle _value; } private const int FOUND_IN_INLINE_STORAGE = -1; private const int NOT_FOUND = -2; // This data structure is optimized for single entry. _head is the one entry that we inline // into the struct for that purpose. If there are more than one entries, we store a list of // entries in _head._key and DUCE.ResourceHandle.Null in _value. private Entry _head; public bool IsEmpty() { return _head._key == null; } ////// Finds the index of the entry with the specified key. Returns FOUND_IN_INLINE_STORAGE if the /// key is stored in the _head inlined entry and NOT_FOUND if the key could not be found. /// Otherwise the method returns the index into the "others" list. /// private int Find(object key) { int index = NOT_FOUND; // Not found. if (_head._key != null) { if (_head._key == key) { index = FOUND_IN_INLINE_STORAGE; // It's stored in our inlined storage. } else { if (_head._value.IsNull) { Listothers = (List )(_head._key); for (int i = 0; i < others.Count; i++) { if (others[i]._key == key) { index = i; break; } } } } } return index; } /// /// Associates a key with the specified value. If the entry already exits the old value is overriden. /// public void Set(object key, DUCE.ResourceHandle value) { int index = Find(key); if (index == FOUND_IN_INLINE_STORAGE) { _head._value = value; } else { if (index == NOT_FOUND) { // The key was not found. // Is the Map empty? if (_head._key == null) { _head = new Entry(key, value); } else { // The Map isn't empty - does it have 1 entry (!_value.IsNull) or more? if (!_head._value.IsNull) { // There's 1 entry - allocate a list... Listothers = new List (2); // by default we have two entries in the extra storage. // ...move the old single entry into the List... others.Add(_head); // ...add the new entry... others.Add(new Entry(key, value)); // ... and replace the single entry _head._key = others; _head._value = DUCE.ResourceHandle.Null; } else { // There's already a List - simply add the new entry to the list. ((List )(_head._key)).Add(new Entry(key, value)); } } } else { ((List )(_head._key))[index] = new Entry(key, value); } } } /// /// Removes an entry from the map. Returns true if the entry to the specified index existed and was removed /// otherwise false. /// public bool Remove(object key) { int index = Find(key); if (index == FOUND_IN_INLINE_STORAGE) { _head = new Entry(); return true; } else { if (index >= 0) { Listothers = (List )_head._key; // If the Count() is 1, index would either have been FOUND_IN_INLINE_STORAGE or // NOT_FOUND, so Count() must be 2 or more. // If it is exactly 2, this means that after removal there will only be one // value left, which will be stored in _head. if (Count() == 2) { Debug.Assert(index <= 1); // If the index is 0, we remove 0 and store 1 in _head. // If the index is 1, we remove 1 and store 0 in _head. _head = others[1 - index]; } else { others.RemoveAt(index); } return true; } } return false; } /// /// Gets the value for the specified key. If the entry for the specified key could not /// be found the Get method returns false otherwise true. /// public bool Get(object key, out DUCE.ResourceHandle value) { int index = Find(key); value = DUCE.ResourceHandle.Null; if (index == FOUND_IN_INLINE_STORAGE) { value = _head._value; return true; } else { if (index >= 0) { value = ((List)_head._key)[index]._value; return true; } else { return false; } } } /// /// Gets the object count in the map. /// public int Count() { if (_head._key == null) { return 0; } else if (!_head._value.IsNull) { return 1; } else { return ((List)_head._key).Count; } } /// /// Gets the object at a given index. /// public object Get(int index) { if ((index >= Count()) || (index < 0)) { return null; } if (Count() == 1) { Debug.Assert(index == 0); return _head._key; } return ((List)_head._key)[index]._key; } } /// /// ShareableDUCEMultiChannelResource class - this class simply wraps a MultiChannelResource, /// enabling it to be shared/handed off/etc via reference semantics. /// Note that this is ~8 bytes larger than the struct MultiChannelResource. /// internal class ShareableDUCEMultiChannelResource { public MultiChannelResource _duceResource; } ////// A multi-channel resource encapsulates a resource that can be used on multiple channels at the same time. /// internal struct MultiChannelResource { private Map _map; ////// CreatesOrAddRefs the resource on the specified channel. /// ////// public bool CreateOrAddRefOnChannel(object instance, Channel channel, DUCE.ResourceType type) { Debug.Assert(channel != null); DUCE.ResourceHandle handle; bool inmap = _map.Get(channel, out handle); bool created = channel.CreateOrAddRefOnChannel(instance, ref handle, type); if (!inmap) { _map.Set(channel, handle); } return created; } ////// Returns true iff the resource is not used on the specified channel anymore. /// /// The method is not synchronized. If the resource is used in a multi-threaded scenario, the /// caller is responsible for taking a lock before calling CreateOrAddRefOnChannel or ReleaseOnChannel. ////// Attempts to duplicate a handle to the specified target channel. /// ////// The idea here is to attempt to find a compatible channel among /// the channels this resource has been marshalled to. /// /// The channel to duplicate the handle from. /// The channel to duplicate the handle to. public DUCE.ResourceHandle DuplicateHandle(Channel sourceChannel, Channel targetChannel) { Debug.Assert(sourceChannel != null); DUCE.ResourceHandle duplicate = DUCE.ResourceHandle.Null; DUCE.ResourceHandle handle = DUCE.ResourceHandle.Null; bool found = _map.Get(sourceChannel, out handle); Debug.Assert(found); // // The multi channel resource should not exist on the target channel. // Our current implementation only keeps a map of the channel and the handle // so only one instance of this resource can be on one channel. // Debug.Assert(!(_map.Get(targetChannel, out duplicate))); duplicate = sourceChannel.DuplicateHandle(handle, targetChannel); if (!duplicate.IsNull) { _map.Set(targetChannel, duplicate); } return duplicate; } ////// Releases the resource from the specified channel. /// Returns true if the resource is not anymore on the specified channel /// otherwise false. /// ////// The method is not synchronized. If the resource is used in a multi-threaded scenario, the /// caller is responsible for taking a lock before calling CreateOrAddRefOnChannel or ReleaseOnChannel. /// ////// Returns true iff the resource is not used on the specified channel anymore. /// public bool ReleaseOnChannel(Channel channel) { Debug.Assert(channel != null); DUCE.ResourceHandle handle; bool found = _map.Get(channel, out handle); Debug.Assert(found); if (channel.ReleaseOnChannel(handle)) { // // The handle isn't used on the specified channel anymore. Therefore // we can reclaim the handle. _map.Remove(channel); return true; } return false; } ////// Returns the ResourceHandle for this resource on the specified channel. /// public DUCE.ResourceHandle GetHandle(Channel channel) { DUCE.ResourceHandle h; if (channel != null) { _map.Get(channel, out h); } else { h = ResourceHandle.Null; } return h; } ////// Checks if a resource was created on the specified channel. /// public bool IsOnChannel(Channel channel) { return !GetHandle(channel).IsNull; } ////// Checks if a resource was created on any channel. /// public bool IsOnAnyChannel { get { return !_map.IsEmpty(); } } public int GetChannelCount() { return _map.Count(); } public DUCE.Channel GetChannel(int index) { return _map.Get(index) as DUCE.Channel; } public uint GetRefCountOnChannel(Channel channel) { Debug.Assert(channel != null); DUCE.ResourceHandle handle; bool found = _map.Get(channel, out handle); Debug.Assert(found); return channel.GetRefCount(handle); } } internal static class CompositionNode { // ----------------------------------------------------------------------------------------------------------------------- // Public imports for composition nodes. // ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetTransform( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hTransform, Channel channel) { DUCE.MILCMD_VISUAL_SETTRANSFORM command; command.Type = MILCMD.MilCmdVisualSetTransform; command.Handle = hCompositionNode; command.hTransform = hTransform; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETTRANSFORM) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetEffect( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hEffect, Channel channel) { DUCE.MILCMD_VISUAL_SETEFFECT command; command.Type = MILCMD.MilCmdVisualSetEffect; command.Handle = hCompositionNode; command.hEffect = hEffect; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETEFFECT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetCacheMode( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hCacheMode, Channel channel) { DUCE.MILCMD_VISUAL_SETCACHEMODE command; command.Type = MILCMD.MilCmdVisualSetCacheMode; command.Handle = hCompositionNode; command.hCacheMode = hCacheMode; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETCACHEMODE) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetOffset( DUCE.ResourceHandle hCompositionNode, double offsetX, double offsetY, Channel channel) { DUCE.MILCMD_VISUAL_SETOFFSET command; command.Type = MILCMD.MilCmdVisualSetOffset; command.Handle = hCompositionNode; command.offsetX = offsetX; command.offsetY = offsetY; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETOFFSET) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetContent( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hContent, Channel channel) { DUCE.MILCMD_VISUAL_SETCONTENT command; command.Type = MILCMD.MilCmdVisualSetContent; command.Handle = hCompositionNode; command.hContent = hContent; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETCONTENT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetAlpha( DUCE.ResourceHandle hCompositionNode, double alpha, Channel channel) { DUCE.MILCMD_VISUAL_SETALPHA command; command.Type = MILCMD.MilCmdVisualSetAlpha; command.Handle = hCompositionNode; command.alpha = alpha; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETALPHA) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetAlphaMask( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hAlphaMaskBrush, Channel channel) { DUCE.MILCMD_VISUAL_SETALPHAMASK command; command.Type = MILCMD.MilCmdVisualSetAlphaMask; command.Handle = hCompositionNode; command.hAlphaMask = hAlphaMaskBrush; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETALPHAMASK) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetScrollableAreaClip( DUCE.ResourceHandle hCompositionNode, Rect? clip, Channel channel) { DUCE.MILCMD_VISUAL_SETSCROLLABLEAREACLIP command; command.Type = MILCMD.MilCmdVisualSetScrollableAreaClip; command.Handle = hCompositionNode; command.IsEnabled = (uint) (clip.HasValue ? 1 : 0); if (clip.HasValue) { command.Clip = clip.Value; } else { command.Clip = Rect.Empty; } unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETSCROLLABLEAREACLIP) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetClip( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hClip, Channel channel) { DUCE.MILCMD_VISUAL_SETCLIP command; command.Type = MILCMD.MilCmdVisualSetClip; command.Handle = hCompositionNode; command.hClip = hClip; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETCLIP) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetRenderOptions( DUCE.ResourceHandle hCompositionNode, MilRenderOptions renderOptions, Channel channel) { DUCE.MILCMD_VISUAL_SETRENDEROPTIONS command; command.Type = MILCMD.MilCmdVisualSetRenderOptions; command.Handle = hCompositionNode; command.renderOptions = renderOptions; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETRENDEROPTIONS) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void RemoveChild( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hChild, Channel channel) { DUCE.MILCMD_VISUAL_REMOVECHILD command; command.Type = MILCMD.MilCmdVisualRemoveChild; command.Handle = hCompositionNode; command.hChild = hChild; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_REMOVECHILD) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void RemoveAllChildren( DUCE.ResourceHandle hCompositionNode, Channel channel) { DUCE.MILCMD_VISUAL_REMOVEALLCHILDREN command; command.Type = MILCMD.MilCmdVisualRemoveAllChildren; command.Handle = hCompositionNode; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_REMOVEALLCHILDREN) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void InsertChildAt( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hChild, UInt32 iPosition, Channel channel) { DUCE.MILCMD_VISUAL_INSERTCHILDAT command; Debug.Assert(!hCompositionNode.IsNull); command.Type = MILCMD.MilCmdVisualInsertChildAt; command.Handle = hCompositionNode; command.hChild = hChild; command.index = iPosition; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_INSERTCHILDAT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetGuidelineCollection( DUCE.ResourceHandle hCompositionNode, DoubleCollection guidelinesX, DoubleCollection guidelinesY, Channel channel ) { checked { DUCE.MILCMD_VISUAL_SETGUIDELINECOLLECTION command; Debug.Assert(!hCompositionNode.IsNull); int countX = guidelinesX == null ? 0 : guidelinesX.Count; int countY = guidelinesY == null ? 0 : guidelinesY.Count; int countXY = countX + countY; command.Type = MILCMD.MilCmdVisualSetGuidelineCollection; command.Handle = hCompositionNode; command.countX = (UInt16)countX; command.countY = (UInt16)countY; if (countX == 0 && countY == 0) { unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETGUIDELINECOLLECTION) ); } } else { double[] doubleArray = new double[countXY]; if (countX != 0) { guidelinesX.CopyTo(doubleArray, 0); Array.Sort(doubleArray, 0, countX); } if (countY != 0) { guidelinesY.CopyTo(doubleArray, countX); Array.Sort(doubleArray, countX, countY); } float[] floatArray = new float[countXY]; for (int i = 0; i < countXY; i++) { floatArray[i] = (float)(double)(doubleArray[i]); } unsafe { channel.BeginCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETGUIDELINECOLLECTION), sizeof(float) * countXY ); fixed (float* pData = floatArray) { channel.AppendCommandData( (byte*)pData, sizeof(float) * countXY ); } channel.EndCommand(); } } } } } internal static class Viewport3DVisualNode { ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetCamera( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hCamera, Channel channel) { unsafe { DUCE.MILCMD_VIEWPORT3DVISUAL_SETCAMERA command; command.Type = MILCMD.MilCmdViewport3DVisualSetCamera; command.Handle = hCompositionNode; command.hCamera = hCamera; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VIEWPORT3DVISUAL_SETCAMERA) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetViewport( DUCE.ResourceHandle hCompositionNode, Rect viewport, Channel channel) { unsafe { DUCE.MILCMD_VIEWPORT3DVISUAL_SETVIEWPORT command; command.Type = MILCMD.MilCmdViewport3DVisualSetViewport; command.Handle = hCompositionNode; command.Viewport = viewport; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VIEWPORT3DVISUAL_SETVIEWPORT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void Set3DChild( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hVisual3D, Channel channel) { unsafe { DUCE.MILCMD_VIEWPORT3DVISUAL_SET3DCHILD command; command.Type = MILCMD.MilCmdViewport3DVisualSet3DChild; command.Handle = hCompositionNode; command.hChild = hVisual3D; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VIEWPORT3DVISUAL_SET3DCHILD) ); } } } internal static class Visual3DNode { ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void RemoveChild( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hChild, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_REMOVECHILD command; command.Type = MILCMD.MilCmdVisual3DRemoveChild; command.Handle = hCompositionNode; command.hChild = hChild; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_REMOVECHILD) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void RemoveAllChildren( DUCE.ResourceHandle hCompositionNode, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_REMOVEALLCHILDREN command; command.Type = MILCMD.MilCmdVisual3DRemoveAllChildren; command.Handle = hCompositionNode; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_REMOVEALLCHILDREN) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void InsertChildAt( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hChild, UInt32 iPosition, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_INSERTCHILDAT command; Debug.Assert(!hCompositionNode.IsNull); command.Type = MILCMD.MilCmdVisual3DInsertChildAt; command.Handle = hCompositionNode; command.hChild = hChild; command.index = iPosition; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_INSERTCHILDAT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetContent( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hContent, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_SETCONTENT command; command.Type = MILCMD.MilCmdVisual3DSetContent; command.Handle = hCompositionNode; command.hContent = hContent; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_SETCONTENT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetTransform( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hTransform, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_SETTRANSFORM command; command.Type = MILCMD.MilCmdVisual3DSetTransform; command.Handle = hCompositionNode; command.hTransform = hTransform; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_SETTRANSFORM) ); } } } internal static class CompositionTarget { // ----------------------------------------------------------------------------------------------------------------------- // Public imports for composition targets. // ////// Critical: This code calls into unsafe code blocks and initialized hwnd for composition target /// [SecurityCritical] internal static void HwndInitialize( DUCE.ResourceHandle hCompositionTarget, IntPtr hWnd, int nWidth, int nHeight, bool softwareOnly, Channel channel ) { DUCE.MILCMD_HWNDTARGET_CREATE command; command.Type = MILCMD.MilCmdHwndTargetCreate; command.Handle = hCompositionTarget; unsafe { // // If the HWND has the highest bit set, casting it to UInt64 // directly will cause sign extension. Prevent this by casting // through a pointer and UIntPtr first. // UIntPtr hWndUIntPtr = new UIntPtr(hWnd.ToPointer()); command.hwnd = (UInt64)hWndUIntPtr; } command.width = (UInt32)nWidth; command.height = (UInt32)nHeight; command.clearColor.b = 0.0f; command.clearColor.r = 0.0f; command.clearColor.g = 0.0f; command.clearColor.a = 1.0f; command.flags = (UInt32)(MILRTInitializationFlags.MIL_RT_PRESENT_IMMEDIATELY | MILRTInitializationFlags.MIL_RT_PRESENT_RETAIN_CONTENTS); if (softwareOnly) { // // In some scenarios, we will want to ensure that the rendered content is // accessible through ntuser redirection. This is to allow graphics stream // clients to selectively magnify some WPF applications through the use // of the graphics stream, and some of them through legacy magnification // (it could be triggered by versioning problems, rendering errors on the // graphics stream client side, etc.). // command.flags |= (UInt32)MILRTInitializationFlags.MIL_RT_SOFTWARE_ONLY; } command.hBitmap = DUCE.ResourceHandle.Null; command.stride = 0; command.ePixelFormat = 0; command.hSection = 0; command.masterDevice = 0; unsafe { channel.SendSecurityCriticalCommand( (byte*)&command, sizeof(DUCE.MILCMD_HWNDTARGET_CREATE), false /* sendInSeparateBatch */ ); } } ////// Critical - 1) The command being sent contains an unmanaged pointer. /// 2) This code accesses an unsafe code block. /// [SecurityCritical] internal static void PrintInitialize( DUCE.ResourceHandle hCompositionTarget, IntPtr pRenderTarget, int nWidth, int nHeight, Channel channel ) { DUCE.MILCMD_GENERICTARGET_CREATE command; command.Type = MILCMD.MilCmdGenericTargetCreate; command.Handle = hCompositionTarget; command.hwnd = 0; command.pRenderTarget = (UInt64)pRenderTarget; command.width = (UInt32)nWidth; command.height = (UInt32)nHeight; command.dummy = 0; unsafe { channel.SendSecurityCriticalCommand( (byte*)&command, sizeof(DUCE.MILCMD_GENERICTARGET_CREATE), false /* sendInSeparateBatch */ ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetClearColor( DUCE.ResourceHandle hCompositionTarget, Color color, Channel channel ) { DUCE.MILCMD_TARGET_SETCLEARCOLOR command; command.Type = MILCMD.MilCmdTargetSetClearColor; command.Handle = hCompositionTarget; command.clearColor.b = color.ScB; command.clearColor.r = color.ScR; command.clearColor.g = color.ScG; command.clearColor.a = color.ScA; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_SETCLEARCOLOR) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetRenderingMode( DUCE.ResourceHandle hCompositionTarget, MILRTInitializationFlags nRenderingMode, Channel channel ) { DUCE.MILCMD_TARGET_SETFLAGS command; command.Type = MILCMD.MilCmdTargetSetFlags; command.Handle = hCompositionTarget; command.flags = (UInt32)nRenderingMode; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_SETFLAGS) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetRoot( DUCE.ResourceHandle hCompositionTarget, DUCE.ResourceHandle hRoot, Channel channel ) { DUCE.MILCMD_TARGET_SETROOT command; command.Type = MILCMD.MilCmdTargetSetRoot; command.Handle = hCompositionTarget; command.hRoot = hRoot; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_SETROOT) ); } } ////// Critical: This code accesses an unsafe code block. /// We also pass across a handle to an event, which we get via SafeWaitHandle.DangerousGetHandle. /// [SecurityCritical] internal static void UpdateWindowSettings( ResourceHandle hCompositionTarget, NativeMethods.RECT windowRect, Color colorKey, float constantAlpha, MILWindowLayerType windowLayerType, MILTransparencyFlags transparencyMode, bool isChild, bool isRTL, bool renderingEnabled, int disableCookie, Channel channel ) { DUCE.MILCMD_TARGET_UPDATEWINDOWSETTINGS command; command.Type = MILCMD.MilCmdTargetUpdateWindowSettings; command.Handle = hCompositionTarget; command.renderingEnabled = (uint)(renderingEnabled ? 1 : 0); command.disableCookie = (uint) disableCookie; command.windowRect = windowRect; command.colorKey.b = colorKey.ScB; command.colorKey.r = colorKey.ScR; command.colorKey.g = colorKey.ScG; command.colorKey.a = colorKey.ScA; command.constantAlpha = constantAlpha; command.transparencyMode = transparencyMode; command.windowLayerType = windowLayerType; command.isChild = (uint)(isChild ? 1 : 0); command.isRTL = (uint)(isRTL ? 1 : 0); unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_UPDATEWINDOWSETTINGS) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void Invalidate( DUCE.ResourceHandle hCompositionTarget, ref NativeMethods.RECT pRect, Channel channel ) { DUCE.MILCMD_TARGET_INVALIDATE command; command.Type = MILCMD.MilCmdTargetInvalidate; command.Handle = hCompositionTarget; command.rc = pRect; unsafe { channel.SendSecurityCriticalCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_INVALIDATE), false /* sendInSeparateBatch */ ); } channel.CloseBatch(); channel.Commit(); } } internal static class ETWEvent { ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: It does not return any pointers and is safe to call /// [SecurityCritical, SecurityTreatAsSafe] internal static void RaiseEvent( DUCE.ResourceHandle hEtwEvent, UInt32 id, Channel channel ) { DUCE.MILCMD_ETWEVENTRESOURCE command; command.Type = MILCMD.MilCmdEtwEventResource; command.Handle = hEtwEvent; command.id = id; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_ETWEVENTRESOURCE) ); } } } ////// DUCE.IResource /// internal interface IResource { DUCE.ResourceHandle AddRefOnChannel(Channel channel); int GetChannelCount(); DUCE.Channel GetChannel(int index); void ReleaseOnChannel(Channel channel); DUCE.ResourceHandle GetHandle(Channel channel); ////// Only Vieport3DVisual and Visual3D implement this. /// Vieport3DVisual has two handles. One stored in _proxy /// and the other one stored in _proxy3D. This function returns /// the handle stored in _proxy3D. /// DUCE.ResourceHandle Get3DHandle(Channel channel); ////// Sends a command to compositor to remove the child /// from its parent on the channel. /// void RemoveChildFromParent( IResource parent, DUCE.Channel channel); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: exports.cs // // Description: // Managed exports from MIL core. //--------------------------------------------------------------------------- using System; using System.Collections; using System.ComponentModel; using System.Threading; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Media.Effects; using System.Windows.Media.Media3D; using System.Runtime.InteropServices; using System.Windows.Media.Animation; using MS.Internal; using MS.Internal.Interop; using MS.Utility; using MS.Win32; using System.Diagnostics; using System.Collections.Generic; using System.Security; using System.Security.Permissions; using Microsoft.Internal; using Microsoft.Win32.SafeHandles; using UnsafeNativeMethods=MS.Win32.PresentationCore.UnsafeNativeMethods; using SafeNativeMethods=MS.Win32.PresentationCore.SafeNativeMethods; using HRESULT=MS.Internal.HRESULT; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; /* * * For the time being the flat composition api will be implemented on * top of milcore.h (the protocol api), this is only temporary we will * be adding type safe unmanaged exports to milcore.dll which will be * be called from the static functions. * */ namespace System.Windows.Media.Composition { // enumeration of marshal types supported by the transport. internal enum ChannelMarshalType { ChannelMarshalTypeInvalid = 0x0, ChannelMarshalTypeSameThread = 0x1, ChannelMarshalTypeCrossThread = 0x2 }; ////// Lock replacement till the CLR team gives us support to resolve the reentrancy issues /// with the CLR lock. /// ////// Prefered usage pattern: /// /// internal struct CompositionEngineLock : IDisposable { ////// using (CompositionEngineLock.Acquire()) /// { /// ... /// } ///
/// /// If you don't use this pattern remember to have a try finally block to release the lock /// in the event of an exception. ////// Aquires the composition engine lock. /// ////// Critical - calls unmanaged code /// TreatAsSafe - all inputs validated, locking is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static CompositionEngineLock Acquire() { UnsafeNativeMethods.MilCoreApi.EnterCompositionEngineLock(); return new CompositionEngineLock(); } ////// Releases the composition engine lock. Using Dispose enables the using syntax. /// ////// Critical - calls unmanaged code /// TreatAsSafe - all inputs validated, unlocking is safe /// [SecurityCritical, SecurityTreatAsSafe] public void Dispose() { UnsafeNativeMethods.MilCoreApi.ExitCompositionEngineLock(); } } ////// The following class only exists to clearly separate the DUCE APIs /// from the legacy resource APIs. /// internal partial class DUCE { ////// CopyBytes - Poor-man's mem copy. Copies cbData from pbFrom to pbTo. /// pbFrom and pbTo must be DWORD aligned, and cbData must be a multiple of 4. /// /// byte* pointing to the "to" array. Must be DWORD aligned. /// byte* pointing to the "from" array. Must be DWORD aligned. /// int - count of bytes to copy. Must be a multiple of 4. ////// Critical: This code accesses an unsafe code block /// [SecurityCritical] internal static unsafe void CopyBytes(byte* pbTo, byte* pbFrom, int cbData) { // We'd like to only handle QWORD aligned data, but the CLR can't enforce this. // If there's no data to copy, it's ok if the pointers aren't aligned Debug.Assert((cbData == 0) || ((Int64)(IntPtr)pbFrom) % 4 == 0); Debug.Assert((cbData == 0) || ((Int64)(IntPtr)pbTo) % 4 == 0); Debug.Assert(cbData % 4 == 0); Debug.Assert(cbData >= 0); Int32* pCurFrom32 = (Int32*)pbFrom; Int32* pCurTo32 = (Int32*)pbTo; for (int i = 0; i < cbData / 4; i++) { pCurTo32[i] = pCurFrom32[i]; } } ////// Critical - pinvoke wrappers /// [SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity] private static class UnsafeNativeMethods { [DllImport(DllImport.MilCore)] internal static extern /*HRESULT*/ int MilResource_CreateOrAddRefOnChannel( IntPtr pChannel, DUCE.ResourceType resourceType, ref DUCE.ResourceHandle hResource ); [DllImport(DllImport.MilCore)] internal static extern /*HRESULT*/ int MilResource_DuplicateHandle( IntPtr pSourceChannel, DUCE.ResourceHandle original, IntPtr pTargetChannel, ref DUCE.ResourceHandle duplicate ); [DllImport(DllImport.MilCore, EntryPoint = "MilConnection_CreateChannel")]//CASRemoval: internal static extern int MilConnection_CreateChannel( IntPtr pTransport, IntPtr hChannel, out IntPtr channelHandle); [DllImport(DllImport.MilCore, EntryPoint = "MilConnection_DestroyChannel")]//CASRemoval: internal static extern int MilConnection_DestroyChannel( IntPtr channelHandle); [DllImport(DllImport.MilCore, EntryPoint = "MilChannel_CloseBatch")]//CASRemoval: internal static extern int MilConnection_CloseBatch( IntPtr channelHandle); [DllImport(DllImport.MilCore, EntryPoint = "MilChannel_CommitChannel")]//CASRemoval: internal static extern int MilConnection_CommitChannel( IntPtr channelHandle); [DllImport(DllImport.MilCore)]//CASRemoval: internal static extern int WgxConnection_SameThreadPresent( IntPtr pConnection); [DllImport(DllImport.MilCore, EntryPoint = "MilChannel_GetMarshalType")] internal static extern int MilChannel_GetMarshalType(IntPtr channelHandle, out ChannelMarshalType marshalType); [DllImport (DllImport.MilCore, EntryPoint = "MilResource_SendCommand")]//CASRemoval: unsafe internal static extern int MilResource_SendCommand( byte *pbData, uint cbSize, bool sendInSeparateBatch, IntPtr pChannel); [DllImport (DllImport.MilCore, EntryPoint = "MilChannel_BeginCommand")]//CASRemoval: unsafe internal static extern int MilChannel_BeginCommand( IntPtr pChannel, byte *pbData, uint cbSize, uint cbExtra ); [DllImport (DllImport.MilCore, EntryPoint = "MilChannel_AppendCommandData")]//CASRemoval: unsafe internal static extern int MilChannel_AppendCommandData( IntPtr pChannel, byte *pbData, uint cbSize ); [DllImport (DllImport.MilCore, EntryPoint = "MilChannel_EndCommand")]//CASRemoval: unsafe internal static extern int MilChannel_EndCommand( IntPtr pChannel); [DllImport (DllImport.MilCore, EntryPoint = "MilResource_SendCommandMedia")]//CASRemoval: unsafe internal static extern int MilResource_SendCommandMedia( ResourceHandle handle, SafeMediaHandle pMedia, IntPtr pChannel, bool notifyUceDirect ); [DllImport (DllImport.MilCore, EntryPoint = "MilResource_SendCommandBitmapSource")]//CASRemoval: unsafe internal static extern int MilResource_SendCommandBitmapSource( ResourceHandle handle, BitmapSourceSafeMILHandle /* IWICBitmapSource */ pBitmapSource, IntPtr pChannel); [DllImport(DllImport.MilCore, EntryPoint = "MilResource_ReleaseOnChannel")]//CASRemoval: internal static extern /*HRESULT*/ int MilResource_ReleaseOnChannel( IntPtr pChannel, DUCE.ResourceHandle hResource, out int deleted ); [DllImport(DllImport.MilCore)] internal static extern int MilChannel_SetNotificationWindow( IntPtr pChannel, IntPtr hwnd, WindowMessage message ); [DllImport(DllImport.MilCore)] internal static extern int MilComposition_WaitForNextMessage( IntPtr pChannel, int nCount, IntPtr[] handles, int bWaitAll, UInt32 waitTimeout, out int waitReturn ); [DllImport(DllImport.MilCore)] internal static extern int MilComposition_PeekNextMessage( IntPtr pChannel, out MilMessage.Message message, /* size_t */ IntPtr messageSize, out int messageRetrieved ); [DllImport(DllImport.MilCore, EntryPoint = "MilResource_GetRefCountOnChannel")] internal static extern /*HRESULT*/ int MilResource_GetRefCountOnChannel( IntPtr pChannel, DUCE.ResourceHandle hResource, out uint refCount ); } ////// Define the value of an infinte wait in WaitForNextMessage. /// internal const UInt32 waitInfinite = UInt32.MaxValue; internal static class MilMessage { ////// The ID of each type of back-channel notification messages. /// internal enum Type { Invalid = 0x00, SyncFlushReply = 0x01, Caps = 0x04, PartitionIsZombie = 0x06, SyncModeStatus = 0x09, Presented = 0x0A, BadPixelShader = 0x10, ForceDWORD = unchecked((int)0xffffffff) }; [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct CapsData { [FieldOffset(0)] internal Int32 CommonMinimumCaps; [FieldOffset(4)] internal UInt32 DisplayUniqueness; [FieldOffset(8)] internal MilGraphicsAccelerationCaps Caps; }; [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct PartitionIsZombieStatus { [FieldOffset(0)] internal int HRESULTFailureCode; }; [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct SyncModeStatus { [FieldOffset(0)] internal int Enabled; }; [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct Presented { [FieldOffset(0)] internal MIL_PRESENTATION_RESULTS PresentationResults; [FieldOffset(4)] internal int RefreshRate; [FieldOffset(8)] internal long PresentationTime; }; ////// The union of all known back-channel notification messages. /// [StructLayout(LayoutKind.Explicit, Pack = 1)] internal struct Message { [FieldOffset(0)] internal Type Type; [FieldOffset(4)] internal int Reserved; [FieldOffset(8)] internal CapsData Caps; [FieldOffset(8)] internal PartitionIsZombieStatus HRESULTFailure; [FieldOffset(8)] internal Presented Presented; [FieldOffset(8)] internal SyncModeStatus SyncModeStatus; }; } ////// A channel set is a container for a matched pair of channels, /// one primary channel and out of band channel /// internal struct ChannelSet { internal Channel Channel; internal Channel OutOfBandChannel; } ////// A Channel is a command pipe into a composition device. /// The commands send through a Channel are not executed till /// Channel.Commit is called. Committing a Channel is an atomic operation. In /// other words, all the commands are executed before the next frame is /// rendered. /// /// A channel is also a hard boundary for UCE resources. That means that UCE /// resources created on one channel can not interact with resources on a different /// channel. /// internal sealed partial class Channel { ////// Primary channel. /// ////// Critical - Track usage of the channel pointer. /// [SecurityCritical] IntPtr _hChannel; private Channel _referenceChannel; private bool _isSynchronous; private bool _isOutOfBandChannel; IntPtr _pConnection; ////// Creates a channel and associates it with channel group (partition). /// New create channel will belong to the same partition as the given referenceChannel. /// To create the very first channel in the group, use null argument. /// ////// Critical - accesses critical resources (handles) /// [SecurityCritical] public Channel(Channel referenceChannel, bool isOutOfBandChannel, IntPtr pConnection, bool isSynchronous) { IntPtr referenceChannelHandle = IntPtr.Zero; _referenceChannel = referenceChannel; _pConnection = pConnection; _isOutOfBandChannel = isOutOfBandChannel; _isSynchronous = isSynchronous; if (referenceChannel != null) { referenceChannelHandle = referenceChannel._hChannel; } HRESULT.Check(UnsafeNativeMethods.MilConnection_CreateChannel( _pConnection, referenceChannelHandle, out _hChannel)); } ////// Commits the commands enqueued into the Channel. /// ////// Critical: This code calls into MilConnection_CommitChannel which causes an elevation /// TreatAsSafe: This commits operations to the channel. Committing to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal void Commit() { if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state when more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } HRESULT.Check(UnsafeNativeMethods.MilConnection_CommitChannel( _hChannel)); } ////// Closes the current batch on the Channel. /// ////// Critical: This code calls into MilConnection_CloseBatch which causes an elevation /// TreatAsSafe: Closing a batch is safe and nothing is exposed. Batches are in the /// render thread, and can only be written to from the UI thread while /// they're open using other SC/STAS methods on DUCE.Channel. Once closed, /// the only operation that can be done on a batch is Channel.Commit. /// [SecurityCritical,SecurityTreatAsSafe] internal void CloseBatch() { if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state when more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } HRESULT.Check(UnsafeNativeMethods.MilConnection_CloseBatch( _hChannel)); } ////// Flush the currently recorded commands to the target device and prepare /// to receive new commands. Block until last command was executed. /// ////// Critical - This code calls into MilComposition_SyncFlush which causes an elevation. /// TreatAsSafe - The net effect is to wait until render completes. /// [SecurityCritical, SecurityTreatAsSafe] internal void SyncFlush() { if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } HRESULT.Check(MilCoreApi.MilComposition_SyncFlush(_hChannel)); } ////// Commits the channel and then closes it. /// ////// Critical - This code calls into MilConnection_CommitChannel and /// MilConnection_DestroyChannel which causes an elevation. /// TreatAsSafe - Even if called prematurely, this will simply make all the subsequent /// channel operations fail (whether silently or by raising an exception). /// [SecurityCritical, SecurityTreatAsSafe] internal void Close() { if (_hChannel != IntPtr.Zero) { HRESULT.Check(UnsafeNativeMethods.MilConnection_CloseBatch(_hChannel)); HRESULT.Check(UnsafeNativeMethods.MilConnection_CommitChannel(_hChannel)); } _referenceChannel = null; if (_hChannel != IntPtr.Zero) { HRESULT.Check(UnsafeNativeMethods.MilConnection_DestroyChannel(_hChannel)); _hChannel = IntPtr.Zero; } } ////// Commits the commands enqueued into the Channel. /// ////// Critical -- Calls into MilChannel_Present which causes an elevation. /// TreatAsSafe -- This call is only relevant to synchronous channels and causes the compositor /// associated with the synchronous channel to compose and present, which is /// considered safe. Asynchronous channels no-op this call. /// [SecurityCritical,SecurityTreatAsSafe] internal void Present() { HRESULT.Check(UnsafeNativeMethods.WgxConnection_SameThreadPresent(_pConnection)); } ////// Internal only: CreateOrAddRefOnChannel addrefs the resource corresponding to the /// specified handle on the channel. /// ////// Returns true iff the resource was created on the channel. The caller is responsible to /// update the resource appropriately. /// ////// Critical - Calls into MilResource_CreateOrAddRefOnChannel which causes an elevation. /// TreatAsSafe - All inputs are safe wrappers, manipulating handle on the channel /// will only affect resources that belong to the current process. /// [SecurityCritical, SecurityTreatAsSafe] internal bool CreateOrAddRefOnChannel(object instance, ref DUCE.ResourceHandle handle, DUCE.ResourceType resourceType) { bool handleNeedsCreation = handle.IsNull; Invariant.Assert(_hChannel != IntPtr.Zero); HRESULT.Check(UnsafeNativeMethods.MilResource_CreateOrAddRefOnChannel( _hChannel, resourceType, ref handle )); if (EventTrace.IsEnabled(EventTrace.Keyword.KeywordGraphics | EventTrace.Keyword.KeywordPerf, EventTrace.Level.PERF_LOW)) { EventTrace.EventProvider.TraceEvent(EventTrace.Event.CreateOrAddResourceOnChannel, EventTrace.Keyword.KeywordGraphics | EventTrace.Keyword.KeywordPerf, EventTrace.Level.PERF_LOW, PerfService.GetPerfElementID(instance), _hChannel, (uint) handle, (uint) resourceType); } return handleNeedsCreation; } ////// DuplicateHandle attempts to duplicate a handle from one channel to another. /// Naturally, this can only work if both the source and target channels are /// within the same partition. /// ////// It is the responsibility of the caller to commit the source channel /// to assure that duplication took place. /// tables. /// ////// Returns the duplicated handle (valid on the target channel) or the null /// handle if duplication failed. /// ////// Critical - Calls security critical code. /// TreatAsSafe - All inputs are safe wrappers, manipulating handle on the channel /// will only affect resources that belong to the current process. /// [SecurityCritical, SecurityTreatAsSafe] internal DUCE.ResourceHandle DuplicateHandle( DUCE.ResourceHandle original, DUCE.Channel targetChannel ) { DUCE.ResourceHandle duplicate = DUCE.ResourceHandle.Null; //Debug.WriteLine(string.Format("DuplicateHandle: Channel: {0}, Resource: {1}, Target channel: {2}, ", _hChannel, original._handle, targetChannel)); HRESULT.Check(UnsafeNativeMethods.MilResource_DuplicateHandle( _hChannel, original, targetChannel._hChannel, ref duplicate )); return duplicate; } ////// Internal only: ReleaseOnChannel releases the resource corresponding to the specified /// handle on the channel. /// ////// Returns true iff the resource is not on this channel anymore. /// ////// Critical - Calls security critical code. /// TreatAsSafe - All inputs are safe wrappers, manipulating handle on the channel /// will only affect resources that belong to the current process. /// [SecurityCritical, SecurityTreatAsSafe] internal bool ReleaseOnChannel(DUCE.ResourceHandle handle) { Invariant.Assert(_hChannel != IntPtr.Zero); Debug.Assert(!handle.IsNull); //Debug.WriteLine(string.Format("ReleaseOnChannel: Channel: {0}, Resource: {1}", _hChannel, handle._handle)); int releasedOnChannel; HRESULT.Check(UnsafeNativeMethods.MilResource_ReleaseOnChannel( _hChannel, handle, out releasedOnChannel )); if ((releasedOnChannel != 0) && EventTrace.IsEnabled(EventTrace.Keyword.KeywordGraphics | EventTrace.Keyword.KeywordPerf, EventTrace.Level.PERF_LOW)) { EventTrace.EventProvider.TraceEvent(EventTrace.Event.ReleaseOnChannel, EventTrace.Keyword.KeywordGraphics | EventTrace.Keyword.KeywordPerf, EventTrace.Level.PERF_LOW, _hChannel, (uint) handle); } return (releasedOnChannel != 0); } ////// Internal only: GetRefCount returns the reference count of a resource /// corresponding to the specified handle on the channel. /// ////// Returns the ref count for a resource on this channel. /// ////// Critical - Calls security critical code. /// TreatAsSafe - All inputs are safe wrappers, manipulating handle on the channel /// will only affect resources that belong to the current process. /// [SecurityCritical, SecurityTreatAsSafe] internal uint GetRefCount(DUCE.ResourceHandle handle) { Invariant.Assert(_hChannel != IntPtr.Zero); Debug.Assert(!handle.IsNull); uint refCount; HRESULT.Check(UnsafeNativeMethods.MilResource_GetRefCountOnChannel( _hChannel, handle, out refCount )); return refCount; } ////// IsConnected returns true if the channel is connected. /// ////// Critical - this code performs an elevation. /// TreatAsSafe - it's safe to return whether a channel is connected or not. /// internal bool IsConnected { [SecurityCritical, SecurityTreatAsSafe] get { return MediaContext.CurrentMediaContext.IsConnected; } } ////// MarshalType returns the marshal type of the channel. /// ////// Critical - this code performs an elevation. /// TreatAsSafe - it's safe to return a channel's marshal type. /// internal ChannelMarshalType MarshalType { [SecurityCritical, SecurityTreatAsSafe] get { Invariant.Assert(_hChannel != IntPtr.Zero); ChannelMarshalType marshalType; HRESULT.Check(UnsafeNativeMethods.MilChannel_GetMarshalType( _hChannel, out marshalType )); return marshalType; } } ////// Returns whether the given channel is synchronous. /// internal bool IsSynchronous { get { return _isSynchronous; } } ////// Returns whether the given channel is an out of band channel. /// internal bool IsOutOfBandChannel { get { return _isOutOfBandChannel; } } ////// SendCommand sends a command struct through the composition thread. /// ////// Critical - This code performs an elevation. /// TreatAsSafe - This method is safe, as Channel structures can only be created /// by MediaContext and are hardened against invalid data. /// [SecurityCritical, SecurityTreatAsSafe ] unsafe internal void SendCommand( byte *pCommandData, int cSize) { SendCommand(pCommandData, cSize, false); } ////// SendCommand sends a command struct through the composition thread. The /// sendInSeparateBatch parameter determines whether the command is sent in the /// current open batch, or whether it will be added to a new and separate batch /// which is then immediately closed, leaving the current batch untouched. /// ////// Critical - This code performs an elevation. /// TreatAsSafe - This method is safe, as Channel structures can only be created /// by MediaContext and are hardened against invalid data. /// [SecurityCritical, SecurityTreatAsSafe ] [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions] unsafe internal void SendCommand( byte *pCommandData, int cSize, bool sendInSeparateBatch) { checked { Invariant.Assert(pCommandData != (byte*)0 && cSize > 0); int hr = HRESULT.S_OK; if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state when more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } // // The pCommandData should not contain SecurityCritical resources; // SendSecurityCriticalCommand should be called instead. // Invariant.Assert(!IsSecurityCriticalCommand(pCommandData)); try { hr = UnsafeNativeMethods.MilResource_SendCommand( pCommandData, (uint)cSize, sendInSeparateBatch, _hChannel); } catch (AccessViolationException) { throw new ArgumentException(SR.Get(MS.Internal.PresentationCore.SRID.Channel_InvalidCommandBufferPointer)); } HRESULT.Check(hr); } } ////// SendSecurityCriticalCommand sends a command struct to the composition thread. /// It is used for sending commands which contain security critical fields like /// hwnd and pointers /// ////// Critical - This code performs an elevation. /// [SecurityCritical] unsafe internal void SendSecurityCriticalCommand( byte *pCommandData, int cSize, bool sendInSeparateBatch ) { checked { Invariant.Assert(pCommandData != (byte*)0 && cSize > 0); int hr = HRESULT.S_OK; if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } // // Make sure that this function is only called for SecurityCritical // command. Otherwise SendCommand should be called. // Debug.Assert(IsSecurityCriticalCommand(pCommandData)); try { hr = UnsafeNativeMethods.MilResource_SendCommand( pCommandData, (uint)cSize, sendInSeparateBatch, _hChannel); } catch (AccessViolationException) { throw new ArgumentException(SR.Get(SRID.Channel_InvalidCommandBufferPointer)); } HRESULT.Check(hr); } } ////// BeginCommand opens a command on a channel /// ////// Critical - This code performs an elevation. /// TreatAsSafe - This method is safe, as Channel structures can only be created /// by MediaContext and are hardened against invalid data. /// [SecurityCritical, SecurityTreatAsSafe] unsafe internal void BeginCommand( byte *pbCommandData, int cbSize, int cbExtra) { checked { Invariant.Assert(cbSize > 0); int hr = HRESULT.S_OK; if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } try { hr = UnsafeNativeMethods.MilChannel_BeginCommand( _hChannel, pbCommandData, (uint)cbSize, (uint)cbExtra ); } catch (AccessViolationException) { throw new ArgumentException(SR.Get(SRID.Channel_InvalidCommandBufferPointer)); } HRESULT.Check(hr); } } ////// AppendCommandData appends data to an open command on a channel /// ////// Critical - This code performs an elevation. /// TreatAsSafe - This method is safe, as Channel structures can only be created /// by MediaContext and are hardened against invalid data. /// [SecurityCritical, SecurityTreatAsSafe] unsafe internal void AppendCommandData( byte *pbCommandData, int cbSize) { checked { Invariant.Assert(pbCommandData != (byte*)0 && cbSize > 0); int hr = HRESULT.S_OK; if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } try { hr = UnsafeNativeMethods.MilChannel_AppendCommandData( _hChannel, pbCommandData, (uint)cbSize ); } catch (AccessViolationException) { throw new ArgumentException(SR.Get(SRID.Channel_InvalidCommandBufferPointer)); } HRESULT.Check(hr); } } ////// EndCommand closes an open command on a channel /// ////// Critical - this code performs an elevation. /// TreatAsSafe - it's safe to end a command in a well known channel. /// [SecurityCritical, SecurityTreatAsSafe] internal void EndCommand() { if (_hChannel == IntPtr.Zero) { // // If the channel has been closed, fail silently. This could happen // for the service channel if we are in disconnected state whhen more // that one media contexts are present and not all of them have finished // processing the disconnect messages. // return; } HRESULT.Check(UnsafeNativeMethods.MilChannel_EndCommand(_hChannel)); } ////// SendCommand that creates an slave bitmap resource /// ////// Critical - this code performs an elevation. /// [SecurityCritical] internal void SendCommandBitmapSource( DUCE.ResourceHandle imageHandle, BitmapSourceSafeMILHandle pBitmapSource ) { Invariant.Assert(pBitmapSource != null && !pBitmapSource.IsInvalid); Invariant.Assert(_hChannel != IntPtr.Zero); HRESULT.Check(UnsafeNativeMethods.MilResource_SendCommandBitmapSource( imageHandle, pBitmapSource, _hChannel)); } ////// SendCommand that creates an slave media resource /// ////// Critical - this code performs an elevation. /// [SecurityCritical] internal void SendCommandMedia( DUCE.ResourceHandle mediaHandle, SafeMediaHandle pMedia, bool notifyUceDirect ) { Invariant.Assert(pMedia != null && !pMedia.IsInvalid); Invariant.Assert(_hChannel != IntPtr.Zero); HRESULT.Check(UnsafeNativeMethods.MilResource_SendCommandMedia( mediaHandle, pMedia, _hChannel, notifyUceDirect )); } ////// Specifies the window and window message to be sent when messages /// become available in the back channel. /// /// /// The target of the notification messages. If this parameter is null /// then the channel stop sending window messages. /// /// /// The window message ID. If the hwnd parameter is null then this /// parameter is ignored. /// ////// Critical - Passes a window handle to native code. This will /// cause milcore to periodically post the specified /// message to the specified window. The caller is /// safe if it owns the window and the message was /// registered with RegisterMessage. /// [SecurityCritical] internal void SetNotificationWindow(IntPtr hwnd, WindowMessage message) { Invariant.Assert(_hChannel != IntPtr.Zero); HRESULT.Check(UnsafeNativeMethods.MilChannel_SetNotificationWindow( _hChannel, hwnd, message )); } ////// Waits until a message is available on this channel. The message /// can be later retrieved with the PeekNextMessage method. /// ////// The method may return with no available messages if the channel /// is disconnected while waiting. /// ////// Critical - Blocks the thread until the channel receives /// a message. This is unsafe if done by any /// component other than the owner of the channel /// because the channel may not send any /// messages, in which case the function will /// never return. Only the owner of the channel /// knows whether a message can be reasonably /// expected to eventually be sent. /// [SecurityCritical] internal void WaitForNextMessage() { int waitReturn; HRESULT.Check(UnsafeNativeMethods.MilComposition_WaitForNextMessage( _hChannel, 0, null, 1, /* true */ waitInfinite, out waitReturn )); } ////// Gets the next available message on this channel. This method /// does not wait if a message is not immediately available. /// /// /// Receives the message. /// ////// True if a message was retrieved, false otherwise. /// ////// Critical - Removes a message from the channel. This is /// unsafe if done by any component other than /// the owner of the channel because eating /// messages may result in the process hanging. /// Also has an unsafe block, but that is safe /// to callers because we just need it to use /// the sizeof operator. /// [SecurityCritical] internal bool PeekNextMessage(out MilMessage.Message message) { Invariant.Assert(_hChannel != IntPtr.Zero); int messageRetrieved; checked { unsafe { HRESULT.Check(UnsafeNativeMethods.MilComposition_PeekNextMessage( _hChannel, out message, (IntPtr)sizeof(MilMessage.Message), out messageRetrieved )); } } return (messageRetrieved != 0); } } ////// The Resource structure encapsulates the functionality /// required to hold on to a UCE resource. A resource can be sent to a /// channel by calling CreateOrAddRefOnChannel. The resource can be deleted /// from a channel by calling ReleaseOnChannel. /// /// With resources the handle management is completely hidden from the caller. /// internal struct Resource { public static readonly Resource Null = new Resource(DUCE.ResourceHandle.Null); private DUCE.ResourceHandle _handle; #if DEBUG private Channel _debugOnly_Channel; #endif ////// THIS IS A TEMPORARY API; DO NOT USE FOR ANYTHING ELSE. /// Creates a resource from a type and ResourceHandle. /// This is currently only used for some hwnd interop code in the VisualManager. /// public Resource(DUCE.ResourceHandle h) { _handle = h; #if DEBUG _debugOnly_Channel = null; #endif } ////// CreatesOrAddRefs the resource on the specified channel. /// public bool CreateOrAddRefOnChannel(object instance, Channel channel, DUCE.ResourceType type) { Debug.Assert(channel != null); #if DEBUG _debugOnly_Channel = channel; #endif return channel.CreateOrAddRefOnChannel(instance, ref _handle, type); } ////// Releases the resource from the specified channel. /// Returns true if the resource is not anymore on the specified channel /// otherwise false. /// ////// Returns true iff the resource is not used on the specified channel anymore. /// public bool ReleaseOnChannel(Channel channel) { Debug.Assert(channel != null); #if DEBUG Debug.Assert(_debugOnly_Channel == channel); #endif if (channel.ReleaseOnChannel(_handle)) { _handle = DUCE.ResourceHandle.Null; return true; } return false; } ////// Checks if a resource was created on the specified channel. /// public bool IsOnChannel(Channel channel) { #if DEBUG Debug.Assert(_debugOnly_Channel == channel); #endif return !_handle.IsNull; } ////// Returns the real UInt32 handle. public DUCE.ResourceHandle Handle { get { return _handle; } } } /// /// ResourceHandle currently encapsulates an unmanaged resource handle. /// [StructLayout(LayoutKind.Explicit)] internal struct ResourceHandle { public static readonly ResourceHandle Null = new ResourceHandle(0); public static explicit operator uint(ResourceHandle r) { return r._handle; } [FieldOffset(0)] private UInt32 _handle; public ResourceHandle(UInt32 handle) { _handle = handle; } ////// Checks if the handle is null. /// public bool IsNull { get { return (_handle == 0); } } } ////// This is a generic map that maps a key to a value. It is heavily optimized /// for a single entry. /// ////// We are using this map to map a resource onto multple channels. This is non-optimal /// solution. The map is currently used by the MultiChannelResource. Eventually, when all /// the UCE underlyings are in place, we will be able to remove the MultiChannelResource. /// internal struct Map{ /// /// Struct for single entry. /// private struct Entry { public Entry(object k, ValueType v) { _key = k; _value = v; } public object _key; public ValueType _value; } private const int FOUND_IN_INLINE_STORAGE = -1; private const int NOT_FOUND = -2; // This data structure is optimized for single entry. _first is the one entry that we inline // into the struct for that purpose. private Entry _first; // All other entries go into the generic _others list. private List_others; public bool IsEmpty() { if (_first._key != null) { return false; } if (_others != null) { return false; } return true; } /// /// Finds the index of the entry with the specified key. Returns FOUND_IN_INLINE_STORAGE if the /// key is stored in the _first inlined entry and NOT_FOUND if the key could not be found. /// Otherwise the method returns the index into the _others list. /// private int Find(object key) { int index = NOT_FOUND; // Not found. if (_first._key != null) { if (_first._key == key) { index = FOUND_IN_INLINE_STORAGE; // It's stored in our inlined storage. } else { if (_others != null) { for (int i = 0; i < _others.Count; i++) { if (_others[i]._key == key) { index = i; break; } } } } } #if DEBUG else { Debug.Assert(_others == null, "There shouldn't be anything stored in the others array."); } #endif return index; } ////// Associates a key with the specified value. If the entry already exits the old value is overriden. /// public void Set(object key, ValueType value) { int index = Find(key); if (index == FOUND_IN_INLINE_STORAGE) { _first._value = value; } else { if (index == NOT_FOUND) { if (_first._key == null) { _first = new Entry(key, value); } else { if (_others == null) { _others = new List(2); // by default we have two entries in the extra storage. } _others.Add(new Entry(key, value)); } } else { _others[index] = new Entry(key, value); } } } /// /// Removes an entry from the map. Returns true if the entry to the specified index existed and was removed /// otherwise false. /// public bool Remove(object key) { int index = Find(key); if (index == FOUND_IN_INLINE_STORAGE) { if (_others != null) { Debug.Assert(_others.Count > 0); int j = _others.Count-1; _first = _others[j]; if (j == 0) // Only one entry in the array. { _others = null; } else { _others.RemoveAt(j); } } else { _first = new Entry(); } return true; } else { if (index >= 0) { if (_others.Count == 1) { Debug.Assert(index == 0); _others = null; } else { _others.RemoveAt(index); } return true; } } return false; } ////// Gets the value for the specified key. If the entry for the specified key could not /// be found the Get method returns false otherwise true. /// public bool Get(object key, out ValueType value) { int index = Find(key); value = default(ValueType); if (index == FOUND_IN_INLINE_STORAGE) { value = _first._value; return true; } else { if (index >= 0) { value = _others[index]._value; return true; } else { return false; } } } ////// Gets the object count in the map. /// public int Count() { if (_first._key == null) { return 0; } else if (_others == null) { return 1; } else { return _others.Count + 1; } } ////// Gets the object at a given index. /// public object Get(int index) { if (index >= Count()) { return null; } if (index == 0) { return _first._key; } return _others[index - 1]._key; } } ////// This is a generic map that maps a key to a value. It is heavily optimized /// for a single entry. /// ////// We are using this map to map a resource onto multple channels. This is non-optimal /// solution. The map is currently used by the MultiChannelResource. Eventually, when all /// the UCE underlyings are in place, we will be able to remove the MultiChannelResource. /// internal struct Map { ////// Struct for single entry. /// private struct Entry { public Entry(object k, DUCE.ResourceHandle v) { _key = k; _value = v; } public object _key; public DUCE.ResourceHandle _value; } private const int FOUND_IN_INLINE_STORAGE = -1; private const int NOT_FOUND = -2; // This data structure is optimized for single entry. _head is the one entry that we inline // into the struct for that purpose. If there are more than one entries, we store a list of // entries in _head._key and DUCE.ResourceHandle.Null in _value. private Entry _head; public bool IsEmpty() { return _head._key == null; } ////// Finds the index of the entry with the specified key. Returns FOUND_IN_INLINE_STORAGE if the /// key is stored in the _head inlined entry and NOT_FOUND if the key could not be found. /// Otherwise the method returns the index into the "others" list. /// private int Find(object key) { int index = NOT_FOUND; // Not found. if (_head._key != null) { if (_head._key == key) { index = FOUND_IN_INLINE_STORAGE; // It's stored in our inlined storage. } else { if (_head._value.IsNull) { Listothers = (List )(_head._key); for (int i = 0; i < others.Count; i++) { if (others[i]._key == key) { index = i; break; } } } } } return index; } /// /// Associates a key with the specified value. If the entry already exits the old value is overriden. /// public void Set(object key, DUCE.ResourceHandle value) { int index = Find(key); if (index == FOUND_IN_INLINE_STORAGE) { _head._value = value; } else { if (index == NOT_FOUND) { // The key was not found. // Is the Map empty? if (_head._key == null) { _head = new Entry(key, value); } else { // The Map isn't empty - does it have 1 entry (!_value.IsNull) or more? if (!_head._value.IsNull) { // There's 1 entry - allocate a list... Listothers = new List (2); // by default we have two entries in the extra storage. // ...move the old single entry into the List... others.Add(_head); // ...add the new entry... others.Add(new Entry(key, value)); // ... and replace the single entry _head._key = others; _head._value = DUCE.ResourceHandle.Null; } else { // There's already a List - simply add the new entry to the list. ((List )(_head._key)).Add(new Entry(key, value)); } } } else { ((List )(_head._key))[index] = new Entry(key, value); } } } /// /// Removes an entry from the map. Returns true if the entry to the specified index existed and was removed /// otherwise false. /// public bool Remove(object key) { int index = Find(key); if (index == FOUND_IN_INLINE_STORAGE) { _head = new Entry(); return true; } else { if (index >= 0) { Listothers = (List )_head._key; // If the Count() is 1, index would either have been FOUND_IN_INLINE_STORAGE or // NOT_FOUND, so Count() must be 2 or more. // If it is exactly 2, this means that after removal there will only be one // value left, which will be stored in _head. if (Count() == 2) { Debug.Assert(index <= 1); // If the index is 0, we remove 0 and store 1 in _head. // If the index is 1, we remove 1 and store 0 in _head. _head = others[1 - index]; } else { others.RemoveAt(index); } return true; } } return false; } /// /// Gets the value for the specified key. If the entry for the specified key could not /// be found the Get method returns false otherwise true. /// public bool Get(object key, out DUCE.ResourceHandle value) { int index = Find(key); value = DUCE.ResourceHandle.Null; if (index == FOUND_IN_INLINE_STORAGE) { value = _head._value; return true; } else { if (index >= 0) { value = ((List)_head._key)[index]._value; return true; } else { return false; } } } /// /// Gets the object count in the map. /// public int Count() { if (_head._key == null) { return 0; } else if (!_head._value.IsNull) { return 1; } else { return ((List)_head._key).Count; } } /// /// Gets the object at a given index. /// public object Get(int index) { if ((index >= Count()) || (index < 0)) { return null; } if (Count() == 1) { Debug.Assert(index == 0); return _head._key; } return ((List)_head._key)[index]._key; } } /// /// ShareableDUCEMultiChannelResource class - this class simply wraps a MultiChannelResource, /// enabling it to be shared/handed off/etc via reference semantics. /// Note that this is ~8 bytes larger than the struct MultiChannelResource. /// internal class ShareableDUCEMultiChannelResource { public MultiChannelResource _duceResource; } ////// A multi-channel resource encapsulates a resource that can be used on multiple channels at the same time. /// internal struct MultiChannelResource { private Map _map; ////// CreatesOrAddRefs the resource on the specified channel. /// ////// public bool CreateOrAddRefOnChannel(object instance, Channel channel, DUCE.ResourceType type) { Debug.Assert(channel != null); DUCE.ResourceHandle handle; bool inmap = _map.Get(channel, out handle); bool created = channel.CreateOrAddRefOnChannel(instance, ref handle, type); if (!inmap) { _map.Set(channel, handle); } return created; } ////// Returns true iff the resource is not used on the specified channel anymore. /// /// The method is not synchronized. If the resource is used in a multi-threaded scenario, the /// caller is responsible for taking a lock before calling CreateOrAddRefOnChannel or ReleaseOnChannel. ////// Attempts to duplicate a handle to the specified target channel. /// ////// The idea here is to attempt to find a compatible channel among /// the channels this resource has been marshalled to. /// /// The channel to duplicate the handle from. /// The channel to duplicate the handle to. public DUCE.ResourceHandle DuplicateHandle(Channel sourceChannel, Channel targetChannel) { Debug.Assert(sourceChannel != null); DUCE.ResourceHandle duplicate = DUCE.ResourceHandle.Null; DUCE.ResourceHandle handle = DUCE.ResourceHandle.Null; bool found = _map.Get(sourceChannel, out handle); Debug.Assert(found); // // The multi channel resource should not exist on the target channel. // Our current implementation only keeps a map of the channel and the handle // so only one instance of this resource can be on one channel. // Debug.Assert(!(_map.Get(targetChannel, out duplicate))); duplicate = sourceChannel.DuplicateHandle(handle, targetChannel); if (!duplicate.IsNull) { _map.Set(targetChannel, duplicate); } return duplicate; } ////// Releases the resource from the specified channel. /// Returns true if the resource is not anymore on the specified channel /// otherwise false. /// ////// The method is not synchronized. If the resource is used in a multi-threaded scenario, the /// caller is responsible for taking a lock before calling CreateOrAddRefOnChannel or ReleaseOnChannel. /// ////// Returns true iff the resource is not used on the specified channel anymore. /// public bool ReleaseOnChannel(Channel channel) { Debug.Assert(channel != null); DUCE.ResourceHandle handle; bool found = _map.Get(channel, out handle); Debug.Assert(found); if (channel.ReleaseOnChannel(handle)) { // // The handle isn't used on the specified channel anymore. Therefore // we can reclaim the handle. _map.Remove(channel); return true; } return false; } ////// Returns the ResourceHandle for this resource on the specified channel. /// public DUCE.ResourceHandle GetHandle(Channel channel) { DUCE.ResourceHandle h; if (channel != null) { _map.Get(channel, out h); } else { h = ResourceHandle.Null; } return h; } ////// Checks if a resource was created on the specified channel. /// public bool IsOnChannel(Channel channel) { return !GetHandle(channel).IsNull; } ////// Checks if a resource was created on any channel. /// public bool IsOnAnyChannel { get { return !_map.IsEmpty(); } } public int GetChannelCount() { return _map.Count(); } public DUCE.Channel GetChannel(int index) { return _map.Get(index) as DUCE.Channel; } public uint GetRefCountOnChannel(Channel channel) { Debug.Assert(channel != null); DUCE.ResourceHandle handle; bool found = _map.Get(channel, out handle); Debug.Assert(found); return channel.GetRefCount(handle); } } internal static class CompositionNode { // ----------------------------------------------------------------------------------------------------------------------- // Public imports for composition nodes. // ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetTransform( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hTransform, Channel channel) { DUCE.MILCMD_VISUAL_SETTRANSFORM command; command.Type = MILCMD.MilCmdVisualSetTransform; command.Handle = hCompositionNode; command.hTransform = hTransform; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETTRANSFORM) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetEffect( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hEffect, Channel channel) { DUCE.MILCMD_VISUAL_SETEFFECT command; command.Type = MILCMD.MilCmdVisualSetEffect; command.Handle = hCompositionNode; command.hEffect = hEffect; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETEFFECT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetCacheMode( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hCacheMode, Channel channel) { DUCE.MILCMD_VISUAL_SETCACHEMODE command; command.Type = MILCMD.MilCmdVisualSetCacheMode; command.Handle = hCompositionNode; command.hCacheMode = hCacheMode; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETCACHEMODE) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetOffset( DUCE.ResourceHandle hCompositionNode, double offsetX, double offsetY, Channel channel) { DUCE.MILCMD_VISUAL_SETOFFSET command; command.Type = MILCMD.MilCmdVisualSetOffset; command.Handle = hCompositionNode; command.offsetX = offsetX; command.offsetY = offsetY; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETOFFSET) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetContent( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hContent, Channel channel) { DUCE.MILCMD_VISUAL_SETCONTENT command; command.Type = MILCMD.MilCmdVisualSetContent; command.Handle = hCompositionNode; command.hContent = hContent; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETCONTENT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetAlpha( DUCE.ResourceHandle hCompositionNode, double alpha, Channel channel) { DUCE.MILCMD_VISUAL_SETALPHA command; command.Type = MILCMD.MilCmdVisualSetAlpha; command.Handle = hCompositionNode; command.alpha = alpha; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETALPHA) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetAlphaMask( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hAlphaMaskBrush, Channel channel) { DUCE.MILCMD_VISUAL_SETALPHAMASK command; command.Type = MILCMD.MilCmdVisualSetAlphaMask; command.Handle = hCompositionNode; command.hAlphaMask = hAlphaMaskBrush; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETALPHAMASK) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetScrollableAreaClip( DUCE.ResourceHandle hCompositionNode, Rect? clip, Channel channel) { DUCE.MILCMD_VISUAL_SETSCROLLABLEAREACLIP command; command.Type = MILCMD.MilCmdVisualSetScrollableAreaClip; command.Handle = hCompositionNode; command.IsEnabled = (uint) (clip.HasValue ? 1 : 0); if (clip.HasValue) { command.Clip = clip.Value; } else { command.Clip = Rect.Empty; } unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETSCROLLABLEAREACLIP) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetClip( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hClip, Channel channel) { DUCE.MILCMD_VISUAL_SETCLIP command; command.Type = MILCMD.MilCmdVisualSetClip; command.Handle = hCompositionNode; command.hClip = hClip; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETCLIP) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetRenderOptions( DUCE.ResourceHandle hCompositionNode, MilRenderOptions renderOptions, Channel channel) { DUCE.MILCMD_VISUAL_SETRENDEROPTIONS command; command.Type = MILCMD.MilCmdVisualSetRenderOptions; command.Handle = hCompositionNode; command.renderOptions = renderOptions; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETRENDEROPTIONS) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void RemoveChild( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hChild, Channel channel) { DUCE.MILCMD_VISUAL_REMOVECHILD command; command.Type = MILCMD.MilCmdVisualRemoveChild; command.Handle = hCompositionNode; command.hChild = hChild; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_REMOVECHILD) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void RemoveAllChildren( DUCE.ResourceHandle hCompositionNode, Channel channel) { DUCE.MILCMD_VISUAL_REMOVEALLCHILDREN command; command.Type = MILCMD.MilCmdVisualRemoveAllChildren; command.Handle = hCompositionNode; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_REMOVEALLCHILDREN) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void InsertChildAt( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hChild, UInt32 iPosition, Channel channel) { DUCE.MILCMD_VISUAL_INSERTCHILDAT command; Debug.Assert(!hCompositionNode.IsNull); command.Type = MILCMD.MilCmdVisualInsertChildAt; command.Handle = hCompositionNode; command.hChild = hChild; command.index = iPosition; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_INSERTCHILDAT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetGuidelineCollection( DUCE.ResourceHandle hCompositionNode, DoubleCollection guidelinesX, DoubleCollection guidelinesY, Channel channel ) { checked { DUCE.MILCMD_VISUAL_SETGUIDELINECOLLECTION command; Debug.Assert(!hCompositionNode.IsNull); int countX = guidelinesX == null ? 0 : guidelinesX.Count; int countY = guidelinesY == null ? 0 : guidelinesY.Count; int countXY = countX + countY; command.Type = MILCMD.MilCmdVisualSetGuidelineCollection; command.Handle = hCompositionNode; command.countX = (UInt16)countX; command.countY = (UInt16)countY; if (countX == 0 && countY == 0) { unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETGUIDELINECOLLECTION) ); } } else { double[] doubleArray = new double[countXY]; if (countX != 0) { guidelinesX.CopyTo(doubleArray, 0); Array.Sort(doubleArray, 0, countX); } if (countY != 0) { guidelinesY.CopyTo(doubleArray, countX); Array.Sort(doubleArray, countX, countY); } float[] floatArray = new float[countXY]; for (int i = 0; i < countXY; i++) { floatArray[i] = (float)(double)(doubleArray[i]); } unsafe { channel.BeginCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL_SETGUIDELINECOLLECTION), sizeof(float) * countXY ); fixed (float* pData = floatArray) { channel.AppendCommandData( (byte*)pData, sizeof(float) * countXY ); } channel.EndCommand(); } } } } } internal static class Viewport3DVisualNode { ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetCamera( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hCamera, Channel channel) { unsafe { DUCE.MILCMD_VIEWPORT3DVISUAL_SETCAMERA command; command.Type = MILCMD.MilCmdViewport3DVisualSetCamera; command.Handle = hCompositionNode; command.hCamera = hCamera; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VIEWPORT3DVISUAL_SETCAMERA) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetViewport( DUCE.ResourceHandle hCompositionNode, Rect viewport, Channel channel) { unsafe { DUCE.MILCMD_VIEWPORT3DVISUAL_SETVIEWPORT command; command.Type = MILCMD.MilCmdViewport3DVisualSetViewport; command.Handle = hCompositionNode; command.Viewport = viewport; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VIEWPORT3DVISUAL_SETVIEWPORT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void Set3DChild( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hVisual3D, Channel channel) { unsafe { DUCE.MILCMD_VIEWPORT3DVISUAL_SET3DCHILD command; command.Type = MILCMD.MilCmdViewport3DVisualSet3DChild; command.Handle = hCompositionNode; command.hChild = hVisual3D; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VIEWPORT3DVISUAL_SET3DCHILD) ); } } } internal static class Visual3DNode { ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void RemoveChild( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hChild, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_REMOVECHILD command; command.Type = MILCMD.MilCmdVisual3DRemoveChild; command.Handle = hCompositionNode; command.hChild = hChild; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_REMOVECHILD) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void RemoveAllChildren( DUCE.ResourceHandle hCompositionNode, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_REMOVEALLCHILDREN command; command.Type = MILCMD.MilCmdVisual3DRemoveAllChildren; command.Handle = hCompositionNode; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_REMOVEALLCHILDREN) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void InsertChildAt( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hChild, UInt32 iPosition, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_INSERTCHILDAT command; Debug.Assert(!hCompositionNode.IsNull); command.Type = MILCMD.MilCmdVisual3DInsertChildAt; command.Handle = hCompositionNode; command.hChild = hChild; command.index = iPosition; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_INSERTCHILDAT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetContent( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hContent, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_SETCONTENT command; command.Type = MILCMD.MilCmdVisual3DSetContent; command.Handle = hCompositionNode; command.hContent = hContent; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_SETCONTENT) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical,SecurityTreatAsSafe] internal static void SetTransform( DUCE.ResourceHandle hCompositionNode, DUCE.ResourceHandle hTransform, Channel channel) { unsafe { DUCE.MILCMD_VISUAL3D_SETTRANSFORM command; command.Type = MILCMD.MilCmdVisual3DSetTransform; command.Handle = hCompositionNode; command.hTransform = hTransform; channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_VISUAL3D_SETTRANSFORM) ); } } } internal static class CompositionTarget { // ----------------------------------------------------------------------------------------------------------------------- // Public imports for composition targets. // ////// Critical: This code calls into unsafe code blocks and initialized hwnd for composition target /// [SecurityCritical] internal static void HwndInitialize( DUCE.ResourceHandle hCompositionTarget, IntPtr hWnd, int nWidth, int nHeight, bool softwareOnly, Channel channel ) { DUCE.MILCMD_HWNDTARGET_CREATE command; command.Type = MILCMD.MilCmdHwndTargetCreate; command.Handle = hCompositionTarget; unsafe { // // If the HWND has the highest bit set, casting it to UInt64 // directly will cause sign extension. Prevent this by casting // through a pointer and UIntPtr first. // UIntPtr hWndUIntPtr = new UIntPtr(hWnd.ToPointer()); command.hwnd = (UInt64)hWndUIntPtr; } command.width = (UInt32)nWidth; command.height = (UInt32)nHeight; command.clearColor.b = 0.0f; command.clearColor.r = 0.0f; command.clearColor.g = 0.0f; command.clearColor.a = 1.0f; command.flags = (UInt32)(MILRTInitializationFlags.MIL_RT_PRESENT_IMMEDIATELY | MILRTInitializationFlags.MIL_RT_PRESENT_RETAIN_CONTENTS); if (softwareOnly) { // // In some scenarios, we will want to ensure that the rendered content is // accessible through ntuser redirection. This is to allow graphics stream // clients to selectively magnify some WPF applications through the use // of the graphics stream, and some of them through legacy magnification // (it could be triggered by versioning problems, rendering errors on the // graphics stream client side, etc.). // command.flags |= (UInt32)MILRTInitializationFlags.MIL_RT_SOFTWARE_ONLY; } command.hBitmap = DUCE.ResourceHandle.Null; command.stride = 0; command.ePixelFormat = 0; command.hSection = 0; command.masterDevice = 0; unsafe { channel.SendSecurityCriticalCommand( (byte*)&command, sizeof(DUCE.MILCMD_HWNDTARGET_CREATE), false /* sendInSeparateBatch */ ); } } ////// Critical - 1) The command being sent contains an unmanaged pointer. /// 2) This code accesses an unsafe code block. /// [SecurityCritical] internal static void PrintInitialize( DUCE.ResourceHandle hCompositionTarget, IntPtr pRenderTarget, int nWidth, int nHeight, Channel channel ) { DUCE.MILCMD_GENERICTARGET_CREATE command; command.Type = MILCMD.MilCmdGenericTargetCreate; command.Handle = hCompositionTarget; command.hwnd = 0; command.pRenderTarget = (UInt64)pRenderTarget; command.width = (UInt32)nWidth; command.height = (UInt32)nHeight; command.dummy = 0; unsafe { channel.SendSecurityCriticalCommand( (byte*)&command, sizeof(DUCE.MILCMD_GENERICTARGET_CREATE), false /* sendInSeparateBatch */ ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetClearColor( DUCE.ResourceHandle hCompositionTarget, Color color, Channel channel ) { DUCE.MILCMD_TARGET_SETCLEARCOLOR command; command.Type = MILCMD.MilCmdTargetSetClearColor; command.Handle = hCompositionTarget; command.clearColor.b = color.ScB; command.clearColor.r = color.ScR; command.clearColor.g = color.ScG; command.clearColor.a = color.ScA; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_SETCLEARCOLOR) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetRenderingMode( DUCE.ResourceHandle hCompositionTarget, MILRTInitializationFlags nRenderingMode, Channel channel ) { DUCE.MILCMD_TARGET_SETFLAGS command; command.Type = MILCMD.MilCmdTargetSetFlags; command.Handle = hCompositionTarget; command.flags = (UInt32)nRenderingMode; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_SETFLAGS) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void SetRoot( DUCE.ResourceHandle hCompositionTarget, DUCE.ResourceHandle hRoot, Channel channel ) { DUCE.MILCMD_TARGET_SETROOT command; command.Type = MILCMD.MilCmdTargetSetRoot; command.Handle = hCompositionTarget; command.hRoot = hRoot; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_SETROOT) ); } } ////// Critical: This code accesses an unsafe code block. /// We also pass across a handle to an event, which we get via SafeWaitHandle.DangerousGetHandle. /// [SecurityCritical] internal static void UpdateWindowSettings( ResourceHandle hCompositionTarget, NativeMethods.RECT windowRect, Color colorKey, float constantAlpha, MILWindowLayerType windowLayerType, MILTransparencyFlags transparencyMode, bool isChild, bool isRTL, bool renderingEnabled, int disableCookie, Channel channel ) { DUCE.MILCMD_TARGET_UPDATEWINDOWSETTINGS command; command.Type = MILCMD.MilCmdTargetUpdateWindowSettings; command.Handle = hCompositionTarget; command.renderingEnabled = (uint)(renderingEnabled ? 1 : 0); command.disableCookie = (uint) disableCookie; command.windowRect = windowRect; command.colorKey.b = colorKey.ScB; command.colorKey.r = colorKey.ScR; command.colorKey.g = colorKey.ScG; command.colorKey.a = colorKey.ScA; command.constantAlpha = constantAlpha; command.transparencyMode = transparencyMode; command.windowLayerType = windowLayerType; command.isChild = (uint)(isChild ? 1 : 0); command.isRTL = (uint)(isRTL ? 1 : 0); unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_UPDATEWINDOWSETTINGS) ); } } ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: Operation is ok to call. It does not return any pointers and sending a pointer to a channel is safe /// [SecurityCritical, SecurityTreatAsSafe] internal static void Invalidate( DUCE.ResourceHandle hCompositionTarget, ref NativeMethods.RECT pRect, Channel channel ) { DUCE.MILCMD_TARGET_INVALIDATE command; command.Type = MILCMD.MilCmdTargetInvalidate; command.Handle = hCompositionTarget; command.rc = pRect; unsafe { channel.SendSecurityCriticalCommand( (byte*)&command, sizeof(DUCE.MILCMD_TARGET_INVALIDATE), false /* sendInSeparateBatch */ ); } channel.CloseBatch(); channel.Commit(); } } internal static class ETWEvent { ////// Critical: This code accesses an unsafe code block /// TreatAsSafe: It does not return any pointers and is safe to call /// [SecurityCritical, SecurityTreatAsSafe] internal static void RaiseEvent( DUCE.ResourceHandle hEtwEvent, UInt32 id, Channel channel ) { DUCE.MILCMD_ETWEVENTRESOURCE command; command.Type = MILCMD.MilCmdEtwEventResource; command.Handle = hEtwEvent; command.id = id; unsafe { channel.SendCommand( (byte*)&command, sizeof(DUCE.MILCMD_ETWEVENTRESOURCE) ); } } } ////// DUCE.IResource /// internal interface IResource { DUCE.ResourceHandle AddRefOnChannel(Channel channel); int GetChannelCount(); DUCE.Channel GetChannel(int index); void ReleaseOnChannel(Channel channel); DUCE.ResourceHandle GetHandle(Channel channel); ////// Only Vieport3DVisual and Visual3D implement this. /// Vieport3DVisual has two handles. One stored in _proxy /// and the other one stored in _proxy3D. This function returns /// the handle stored in _proxy3D. /// DUCE.ResourceHandle Get3DHandle(Channel channel); ////// Sends a command to compositor to remove the child /// from its parent on the channel. /// void RemoveChildFromParent( IResource parent, DUCE.Channel channel); } } } // 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
- DriveNotFoundException.cs
- PointAnimationUsingPath.cs
- ConfigXmlElement.cs
- SyndicationFeedFormatter.cs
- ScriptMethodAttribute.cs
- QilVisitor.cs
- RemotingAttributes.cs
- XmlExceptionHelper.cs
- DecimalAnimation.cs
- SafeProcessHandle.cs
- ArgumentException.cs
- ButtonAutomationPeer.cs
- DataGridViewRowPostPaintEventArgs.cs
- TraceUtility.cs
- CompareInfo.cs
- ContainerUtilities.cs
- Light.cs
- KnownBoxes.cs
- StaticDataManager.cs
- InvalidPropValue.cs
- DeliveryRequirementsAttribute.cs
- WebServiceReceiveDesigner.cs
- CngAlgorithm.cs
- ErrorHandler.cs
- LayoutUtils.cs
- UndoEngine.cs
- ApplicationInfo.cs
- Material.cs
- AsyncPostBackTrigger.cs
- AttachedAnnotation.cs
- RadioButtonRenderer.cs
- TextEditorThreadLocalStore.cs
- GridViewRowPresenterBase.cs
- GroupBox.cs
- FormViewDeleteEventArgs.cs
- ActivityDesignerHelper.cs
- WindowsIdentity.cs
- LineSegment.cs
- Timer.cs
- WorkflowOperationInvoker.cs
- DataGridViewCellStyleContentChangedEventArgs.cs
- ApplicationContext.cs
- ProfileServiceManager.cs
- XamlSerializer.cs
- TextBreakpoint.cs
- DbBuffer.cs
- Version.cs
- OdbcDataReader.cs
- PropertyManager.cs
- BulletDecorator.cs
- MarkerProperties.cs
- PackagingUtilities.cs
- ProviderBase.cs
- ToolStripLabel.cs
- StreamSecurityUpgradeProvider.cs
- XmlObjectSerializerWriteContext.cs
- HtmlTitle.cs
- DataPager.cs
- ServiceActivationException.cs
- TextBreakpoint.cs
- GetPageCompletedEventArgs.cs
- MessageSecurityProtocolFactory.cs
- CheckBoxList.cs
- StringResourceManager.cs
- EntityEntry.cs
- PageBreakRecord.cs
- DataRelationPropertyDescriptor.cs
- WindowsTab.cs
- DynamicResourceExtensionConverter.cs
- InkCanvasInnerCanvas.cs
- Dynamic.cs
- AssemblyInfo.cs
- cookiecontainer.cs
- SqlMetaData.cs
- SystemWebCachingSectionGroup.cs
- X509Chain.cs
- ObjectDataSourceDisposingEventArgs.cs
- BypassElement.cs
- WebPartTracker.cs
- ConsoleCancelEventArgs.cs
- SingleObjectCollection.cs
- PrintDialogException.cs
- Configuration.cs
- LinkedList.cs
- SchemaReference.cs
- filewebresponse.cs
- IODescriptionAttribute.cs
- FlowDocumentPage.cs
- SQLByteStorage.cs
- PageThemeBuildProvider.cs
- __ComObject.cs
- ActivitySurrogate.cs
- MemberPath.cs
- SafeNativeMethods.cs
- DesignerWithHeader.cs
- EntityFunctions.cs
- XmlSchemas.cs
- Events.cs
- _LocalDataStore.cs
- FontEmbeddingManager.cs