|
//---------------------------------------------------------------------------
//
// 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.PresentationCore;
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;
using DllImport=MS.Internal.PresentationCore.DllImport;
/*
*
* 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
};
/// <summary>
/// Lock replacement till the CLR team gives us support to resolve the reentrancy issues
/// with the CLR lock.
/// </summary>
/// <remark>
/// Prefered usage pattern:
///
/// <code>
/// using (CompositionEngineLock.Acquire())
/// {
/// ...
/// }
/// </code>
///
/// If you don't use this pattern remember to have a try finally block to release the lock
/// in the event of an exception.
/// </remark>
internal struct CompositionEngineLock : IDisposable
{
/// <summary>
/// Aquires the composition engine lock.
/// </summary>
/// <SecurityNote>
/// Critical - calls unmanaged code
/// TreatAsSafe - all inputs validated, locking is safe
/// </SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
internal static CompositionEngineLock Acquire()
{
UnsafeNativeMethods.MilCoreApi.EnterCompositionEngineLock();
return new CompositionEngineLock();
}
/// <summary>
/// Releases the composition engine lock. Using Dispose enables the using syntax.
/// </summary>
/// <SecurityNote>
/// Critical - calls unmanaged code
/// TreatAsSafe - all inputs validated, unlocking is safe
/// </SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
public void Dispose()
{
UnsafeNativeMethods.MilCoreApi.ExitCompositionEngineLock();
}
}
/// <summary>
/// The following class only exists to clearly separate the DUCE APIs
/// from the legacy resource APIs.
/// </summary>
internal partial class DUCE
{
/// <summary>
/// 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.
/// </summary>
/// <param name="pbTo"> byte* pointing to the "to" array. Must be DWORD aligned. </param>
/// <param name="pbFrom"> byte* pointing to the "from" array. Must be DWORD aligned. </param>
/// <param name="cbData"> int - count of bytes to copy. Must be a multiple of 4. </param>
/// <SecurityNote>
/// Critical: This code accesses an unsafe code block
/// </SecurityNote>
[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];
}
}
/// <SecurityNote>
/// Critical - pinvoke wrappers
/// </SecurityNote>
[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
);
}
/// <summary>
/// Define the value of an infinte wait in WaitForNextMessage.
/// </summary>
internal const UInt32 waitInfinite = UInt32.MaxValue;
internal static class MilMessage
{
/// <summary>
/// The ID of each type of back-channel notification messages.
/// </summary>
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;
};
/// <summary>
/// The union of all known back-channel notification messages.
/// </summary>
[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;
};
}
///<summary>
/// A channel set is a container for a matched pair of channels,
/// one primary channel and out of band channel
///</summary>
internal struct ChannelSet
{
internal Channel Channel;
internal Channel OutOfBandChannel;
}
/// <summary>
/// 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.
/// </summary>
internal sealed partial class Channel
{
/// <summary>
/// Primary channel.
/// </summary>
/// <SecurityNote>
/// Critical - Track usage of the channel pointer.
/// </SecurityNote>
[SecurityCritical]
IntPtr _hChannel;
private Channel _referenceChannel;
private bool _isSynchronous;
private bool _isOutOfBandChannel;
IntPtr _pConnection;
/// <summary>
/// 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.
/// </summary>
/// <SecurityNote>
/// Critical - accesses critical resources (handles)
/// </SecurityNote>
[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));
}
/// <summary>
/// Commits the commands enqueued into the Channel.
/// </summary>
/// <SecurityNote>
/// Critical: This code calls into MilConnection_CommitChannel which causes an elevation
/// TreatAsSafe: This commits operations to the channel. Committing to a channel is safe
/// </SecurityNote>
[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));
}
/// <summary>
/// Closes the current batch on the Channel.
/// </summary>
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[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));
}
/// <summary>
/// Flush the currently recorded commands to the target device and prepare
/// to receive new commands. Block until last command was executed.
/// </summary>
/// <SecurityNote>
/// Critical - This code calls into MilComposition_SyncFlush which causes an elevation.
/// TreatAsSafe - The net effect is to wait until render completes.
/// </SecurityNote>
[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));
}
/// <summary>
/// Commits the channel and then closes it.
/// </summary>
/// <SecurityNote>
/// 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).
/// </SecurityNote>
[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;
}
}
/// <summary>
/// Commits the commands enqueued into the Channel.
/// </summary>
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[SecurityCritical,SecurityTreatAsSafe]
internal void Present()
{
HRESULT.Check(UnsafeNativeMethods.WgxConnection_SameThreadPresent(_pConnection));
}
/// <summary>
/// Internal only: CreateOrAddRefOnChannel addrefs the resource corresponding to the
/// specified handle on the channel.
/// </summary>
/// <return>
/// Returns true iff the resource was created on the channel. The caller is responsible to
/// update the resource appropriately.
/// </return>
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[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;
}
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// It is the responsibility of the caller to commit the source channel
/// to assure that duplication took place.
/// tables.
/// </remarks>
/// <return>
/// Returns the duplicated handle (valid on the target channel) or the null
/// handle if duplication failed.
/// </return>
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[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;
}
/// <summary>
/// Internal only: ReleaseOnChannel releases the resource corresponding to the specified
/// handle on the channel.
/// </summary>
/// <return>
/// Returns true iff the resource is not on this channel anymore.
/// </return>
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[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);
}
/// <summary>
/// Internal only: GetRefCount returns the reference count of a resource
/// corresponding to the specified handle on the channel.
/// </summary>
/// <return>
/// Returns the ref count for a resource on this channel.
/// </return>
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[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;
}
/// <summary>
/// IsConnected returns true if the channel is connected.
/// </summary>
///<SecurityNote>
/// Critical - this code performs an elevation.
/// TreatAsSafe - it's safe to return whether a channel is connected or not.
///</SecurityNote>
internal bool IsConnected
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
return MediaContext.CurrentMediaContext.IsConnected;
}
}
/// <summary>
/// MarshalType returns the marshal type of the channel.
/// </summary>
///<SecurityNote>
/// Critical - this code performs an elevation.
/// TreatAsSafe - it's safe to return a channel's marshal type.
///</SecurityNote>
internal ChannelMarshalType MarshalType
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
Invariant.Assert(_hChannel != IntPtr.Zero);
ChannelMarshalType marshalType;
HRESULT.Check(UnsafeNativeMethods.MilChannel_GetMarshalType(
_hChannel,
out marshalType
));
return marshalType;
}
}
/// <summary>
/// Returns whether the given channel is synchronous.
/// </summary>
internal bool IsSynchronous
{
get
{
return _isSynchronous;
}
}
/// <summary>
/// Returns whether the given channel is an out of band channel.
/// </summary>
internal bool IsOutOfBandChannel
{
get
{
return _isOutOfBandChannel;
}
}
/// <summary>
/// SendCommand sends a command struct through the composition thread.
/// </summary>
/// <SecurityNote>
/// Critical - This code accepts a raw pointer and calls other SecurityCritical code.
/// </SecurityNote>
[SecurityCritical]
unsafe internal void SendCommand(
byte *pCommandData,
int cSize)
{
SendCommand(pCommandData, cSize, false);
}
/// <summary>
/// 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.
/// </summary>
/// <SecurityNote>
/// Critical - This code accepts a raw pointer and calls native code under SUC.
/// </SecurityNote>
[SecurityCritical]
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;
}
hr = UnsafeNativeMethods.MilResource_SendCommand(
pCommandData,
(uint)cSize,
sendInSeparateBatch,
_hChannel);
HRESULT.Check(hr);
}
}
/// <summary>
/// BeginCommand opens a command on a channel
/// </summary>
/// <SecurityNote>
/// Critical - This code accepts a raw pointer and calls native code under SUC.
/// </SecurityNote>
[SecurityCritical]
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;
}
hr = UnsafeNativeMethods.MilChannel_BeginCommand(
_hChannel,
pbCommandData,
(uint)cbSize,
(uint)cbExtra
);
HRESULT.Check(hr);
}
}
/// <summary>
/// AppendCommandData appends data to an open command on a channel
/// </summary>
/// <SecurityNote>
/// Critical - This code accepts a raw pointer and calls native code under SUC.
/// </SecurityNote>
[SecurityCritical]
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;
}
hr = UnsafeNativeMethods.MilChannel_AppendCommandData(
_hChannel,
pbCommandData,
(uint)cbSize
);
HRESULT.Check(hr);
}
}
/// <summary>
/// EndCommand closes an open command on a channel
/// </summary>
///<SecurityNote>
/// Critical - this code performs an elevation.
/// TreatAsSafe - it's safe to end a command in a well known channel.
///</SecurityNote>
[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));
}
/// <summary>
/// SendCommand that creates an slave bitmap resource
/// </summary>
/// <SecurityNote>
/// Critical - this code performs an elevation.
/// </SecurityNote>
[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));
}
/// <summary>
/// SendCommand that creates an slave media resource
/// </summary>
/// <SecurityNote>
/// Critical - this code performs an elevation.
/// </SecurityNote>
[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
));
}
/// <summary>
/// Specifies the window and window message to be sent when messages
/// become available in the back channel.
/// </summary>
/// <param name="hwnd">
/// The target of the notification messages. If this parameter is null
/// then the channel stop sending window messages.
/// </param>
/// <param name="message">
/// The window message ID. If the hwnd parameter is null then this
/// parameter is ignored.
/// </param>
/// <securitynote>
/// 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.
/// </securitynote>
[SecurityCritical]
internal void SetNotificationWindow(IntPtr hwnd, WindowMessage message)
{
Invariant.Assert(_hChannel != IntPtr.Zero);
HRESULT.Check(UnsafeNativeMethods.MilChannel_SetNotificationWindow(
_hChannel,
hwnd,
message
));
}
/// <summary>
/// Waits until a message is available on this channel. The message
/// can be later retrieved with the PeekNextMessage method.
/// </summary>
/// <remarks>
/// The method may return with no available messages if the channel
/// is disconnected while waiting.
/// </remarks>
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[SecurityCritical]
internal void WaitForNextMessage()
{
int waitReturn;
HRESULT.Check(UnsafeNativeMethods.MilComposition_WaitForNextMessage(
_hChannel,
0,
null,
1, /* true */
waitInfinite,
out waitReturn
));
}
/// <summary>
/// Gets the next available message on this channel. This method
/// does not wait if a message is not immediately available.
/// </summary>
/// <param name="message">
/// Receives the message.
/// </param>
/// <returns>
/// True if a message was retrieved, false otherwise.
/// </returns>
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[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);
}
}
/// <summary>
/// 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.
/// </summary>
internal struct Resource
{
public static readonly Resource Null = new Resource(DUCE.ResourceHandle.Null);
private DUCE.ResourceHandle _handle;
#if DEBUG
private Channel _debugOnly_Channel;
#endif
/// <summary>
/// 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.
/// </summary>
public Resource(DUCE.ResourceHandle h)
{
_handle = h;
#if DEBUG
_debugOnly_Channel = null;
#endif
}
/// <summary>
/// CreatesOrAddRefs the resource on the specified channel.
/// </summary>
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);
}
/// <summary>
/// Releases the resource from the specified channel.
/// Returns true if the resource is not anymore on the specified channel
/// otherwise false.
/// </summary>
/// <return>
/// Returns true iff the resource is not used on the specified channel anymore.
/// </return>
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;
}
/// <summary>
/// Checks if a resource was created on the specified channel.
/// </summary>
public bool IsOnChannel(Channel channel)
{
#if DEBUG
Debug.Assert(_debugOnly_Channel == channel);
#endif
return !_handle.IsNull;
}
/// <summary>
/// Returns the real UInt32 handle.
public DUCE.ResourceHandle Handle { get { return _handle; } }
}
/// <summary>
/// ResourceHandle currently encapsulates an unmanaged resource handle.
/// </summary>
[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; }
/// <summary>
/// Checks if the handle is null.
/// </summary>
public bool IsNull { get { return (_handle == 0); } }
}
/// <summary>
/// This is a generic map that maps a key to a value. It is heavily optimized
/// for a single entry.
/// </summary>
/// <remark>
/// 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.
/// </remark>
internal struct Map<ValueType>
{
/// <summary>
/// Struct for single entry.
/// </summary>
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<Entry> _others;
public bool IsEmpty()
{
if (_first._key != null)
{
return false;
}
if (_others != null)
{
return false;
}
return true;
}
/// <summary>
/// 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.
/// </summary>
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;
}
/// <summary>
/// Associates a key with the specified value. If the entry already exits the old value is overriden.
/// </summary>
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<Entry>(2); // by default we have two entries in the extra storage.
}
_others.Add(new Entry(key, value));
}
}
else
{
_others[index] = new Entry(key, value);
}
}
}
/// <summary>
/// Removes an entry from the map. Returns true if the entry to the specified index existed and was removed
/// otherwise false.
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
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;
}
}
}
/// <summary>
/// Gets the object count in the map.
/// </summary>
public int Count()
{
if (_first._key == null)
{
return 0;
}
else if (_others == null)
{
return 1;
}
else
{
return _others.Count + 1;
}
}
/// <summary>
/// Gets the object at a given index.
/// </summary>
public object Get(int index)
{
if (index >= Count())
{
return null;
}
if (index == 0)
{
return _first._key;
}
return _others[index - 1]._key;
}
}
/// <summary>
/// This is a generic map that maps a key to a value. It is heavily optimized
/// for a single entry.
/// </summary>
/// <remark>
/// 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.
/// </remark>
internal struct Map
{
/// <summary>
/// Struct for single entry.
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
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)
{
List<Entry> others = (List<Entry>)(_head._key);
for (int i = 0; i < others.Count; i++)
{
if (others[i]._key == key)
{
index = i;
break;
}
}
}
}
}
return index;
}
/// <summary>
/// Associates a key with the specified value. If the entry already exits the old value is overriden.
/// </summary>
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...
List<Entry> others = new List<Entry>(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<Entry>)(_head._key)).Add(new Entry(key, value));
}
}
}
else
{
((List<Entry>)(_head._key))[index] = new Entry(key, value);
}
}
}
/// <summary>
/// Removes an entry from the map. Returns true if the entry to the specified index existed and was removed
/// otherwise false.
/// </summary>
public bool Remove(object key)
{
int index = Find(key);
if (index == FOUND_IN_INLINE_STORAGE)
{
_head = new Entry();
return true;
}
else
{
if (index >= 0)
{
List<Entry> others = (List<Entry>)_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;
}
/// <summary>
/// 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.
/// </summary>
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<Entry>)_head._key)[index]._value;
return true;
}
else
{
return false;
}
}
}
/// <summary>
/// Gets the object count in the map.
/// </summary>
public int Count()
{
if (_head._key == null)
{
return 0;
}
else if (!_head._value.IsNull)
{
return 1;
}
else
{
return ((List<Entry>)_head._key).Count;
}
}
/// <summary>
/// Gets the object at a given index.
/// </summary>
public object Get(int index)
{
if ((index >= Count()) || (index < 0))
{
return null;
}
if (Count() == 1)
{
Debug.Assert(index == 0);
return _head._key;
}
return ((List<Entry>)_head._key)[index]._key;
}
}
/// <summary>
/// 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.
/// </summary>
internal class ShareableDUCEMultiChannelResource
{
public MultiChannelResource _duceResource;
}
/// <summary>
/// A multi-channel resource encapsulates a resource that can be used on multiple channels at the same time.
/// </summary>
internal struct MultiChannelResource
{
private Map _map;
/// <summary>
/// CreatesOrAddRefs the resource on the specified channel.
/// </summary>
/// <remark>
/// <return>
/// Returns true iff the resource is not used on the specified channel anymore.
/// </return>
/// 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.
/// </remark>
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;
}
/// <summary>
/// Attempts to duplicate a handle to the specified target channel.
/// </summary>
/// <remarks>
/// The idea here is to attempt to find a compatible channel among
/// the channels this resource has been marshalled to.
/// </remarks>
/// <param name="sourceChannel">The channel to duplicate the handle from.</param>
/// <param name="targetChannel">The channel to duplicate the handle to.</param>
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;
}
/// <summary>
/// Releases the resource from the specified channel.
/// Returns true if the resource is not anymore on the specified channel
/// otherwise false.
/// </summary>
/// <remark>
/// 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.
/// </remark>
/// <return>
/// Returns true iff the resource is not used on the specified channel anymore.
/// </return>
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;
}
/// <summary>
/// Returns the ResourceHandle for this resource on the specified channel.
/// </summary>
public DUCE.ResourceHandle GetHandle(Channel channel)
{
DUCE.ResourceHandle h;
if (channel != null)
{
_map.Get(channel, out h);
}
else
{
h = ResourceHandle.Null;
}
return h;
}
/// <summary>
/// Checks if a resource was created on the specified channel.
/// </summary>
public bool IsOnChannel(Channel channel)
{
return !GetHandle(channel).IsNull;
}
/// <summary>
/// Checks if a resource was created on any channel.
/// </summary>
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.
//
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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
{
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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
{
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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.
//
/// <SecurityNote>
/// Critical: This code calls into unsafe code blocks and initialized hwnd for composition target
/// </SecurityNote>
[SecurityCritical]
internal static void HwndInitialize(
DUCE.ResourceHandle hCompositionTarget,
IntPtr hWnd,
int nWidth,
int nHeight,
bool softwareOnly,
int dpiAwarenessContext,
DpiScale dpiScale,
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;
}
bool? enableMultiMonitorDisplayClipping =
System.Windows.CoreCompatibilityPreferences.EnableMultiMonitorDisplayClipping;
if (enableMultiMonitorDisplayClipping != null)
{
// The flag is explicitly set by the user in application manifest
command.flags |= (UInt32)MILRTInitializationFlags.MIL_RT_IS_DISABLE_MULTIMON_DISPLAY_CLIPPING_VALID;
if (!enableMultiMonitorDisplayClipping.Value)
{
command.flags |= (UInt32) MILRTInitializationFlags.MIL_RT_DISABLE_MULTIMON_DISPLAY_CLIPPING;
}
}
command.hBitmap = DUCE.ResourceHandle.Null;
command.stride = 0;
command.ePixelFormat = 0;
command.hSection = 0;
command.masterDevice = 0;
command.DpiAwarenessContext = dpiAwarenessContext;
command.DpiX = dpiScale.DpiScaleX;
command.DpiY = dpiScale.DpiScaleY;
unsafe
{
channel.SendCommand(
(byte*)&command,
sizeof(DUCE.MILCMD_HWNDTARGET_CREATE),
false /* sendInSeparateBatch */
);
}
}
[SecuritySafeCritical]
internal static void ProcessDpiChanged(
DUCE.ResourceHandle hCompositionTarget,
DpiScale dpiScale,
bool afterParent,
Channel channel
)
{
DUCE.MILCMD_HWNDTARGET_DPICHANGED command;
command.Type = MILCMD.MilCmdHwndTargetDpiChanged;
command.Handle = hCompositionTarget;
command.DpiX = dpiScale.DpiScaleX;
command.DpiY = dpiScale.DpiScaleY;
command.AfterParent = afterParent ? 1U : 0U;
unsafe
{
channel.SendCommand(
(byte*)&command,
sizeof(DUCE.MILCMD_HWNDTARGET_DPICHANGED),
sendInSeparateBatch: false);
}
}
/// <SecurityNote>
/// Critical - 1) The command being sent contains an unmanaged pointer.
/// 2) This code accesses an unsafe code block.
/// </SecurityNote>
[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.SendCommand(
(byte*)&command,
sizeof(DUCE.MILCMD_GENERICTARGET_CREATE),
false /* sendInSeparateBatch */
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// Critical: This code accesses an unsafe code block.
/// We also pass across a handle to an event, which we get via SafeWaitHandle.DangerousGetHandle.
/// </SecurityNote>
[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)
);
}
}
/// <SecurityNote>
/// 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
/// </SecurityNote>
[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.SendCommand(
(byte*)&command,
sizeof(DUCE.MILCMD_TARGET_INVALIDATE),
false /* sendInSeparateBatch */
);
}
channel.CloseBatch();
channel.Commit();
}
}
/// <summary>
/// See <see cref="MediaContext.ShouldRenderEvenWhenNoDisplayDevicesAreAvailable"/> for
/// details.
/// </summary>
/// <SecurityNote>
/// Critical: This code accesses an unsafe code block
/// Safe: Operation is ok to call, sending a pointer to a channel is safe,
/// and this does not return any Critical data to the caller
/// </SecurityNote>
[SecuritySafeCritical]
internal static void NotifyPolicyChangeForNonInteractiveMode(
bool forceRender,
Channel channel
)
{
var command = new DUCE.MILCMD_PARTITION_NOTIFYPOLICYCHANGEFORNONINTERACTIVEMODE
{
Type = MILCMD.MilCmdPartitionNotifyPolicyChangeForNonInteractiveMode,
ShouldRenderEvenWhenNoDisplayDevicesAreAvailable = (forceRender ? 1u : 0u)
};
unsafe
{
channel.SendCommand(
(byte*)&command,
sizeof(DUCE.MILCMD_PARTITION_NOTIFYPOLICYCHANGEFORNONINTERACTIVEMODE),
sendInSeparateBatch: false
);
}
// Caller should close and commit
}
internal static class ETWEvent
{
/// <SecurityNote>
/// Critical: This code accesses an unsafe code block
/// TreatAsSafe: It does not return any pointers and is safe to call
/// </SecurityNote>
[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)
);
}
}
}
///<summary>
/// DUCE.IResource
///</summary>
internal interface IResource
{
DUCE.ResourceHandle AddRefOnChannel(Channel channel);
int GetChannelCount();
DUCE.Channel GetChannel(int index);
void ReleaseOnChannel(Channel channel);
DUCE.ResourceHandle GetHandle(Channel channel);
/// <summary>
/// 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.
/// </summary>
DUCE.ResourceHandle Get3DHandle(Channel channel);
/// <summary>
/// Sends a command to compositor to remove the child
/// from its parent on the channel.
/// </summary>
void RemoveChildFromParent(
IResource parent,
DUCE.Channel channel);
}
}
}
|