|
namespace System.Media {
using System;
using System.IO;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Diagnostics;
using System.Threading;
using System.Net;
using System.Globalization;
using System.Security.Permissions;
using System.Security;
using System.Diagnostics.CodeAnalysis;
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer"]/*' />
[
Serializable,
ToolboxItem(false),
SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes"), // This is the first class added to System.Media namespace.
SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly"), // vsw 427356
HostProtection(UI = true)
]
public class SoundPlayer : Component, ISerializable {
const int blockSize = 1024;
const int defaultLoadTimeout = 10000;// 10 secs
private Uri uri = null;
private string soundLocation = String.Empty;
private int loadTimeout = defaultLoadTimeout;
private object tag = null;
// used to lock all synchronous calls to the SoundPlayer object
private ManualResetEvent semaphore = new ManualResetEvent(true);
// the worker copyThread
// we start the worker copyThread ONLY from entry points in the SoundPlayer API
// we also set the tread to null only from the entry points in the SoundPlayer API
private Thread copyThread = null;
// local buffer information
int currentPos = 0;
private Stream stream = null;
private bool isLoadCompleted = false;
private Exception lastLoadException = null;
private bool doesLoadAppearSynchronous = false;
private byte[] streamData = null;
private AsyncOperation asyncOperation = null;
private readonly SendOrPostCallback loadAsyncOperationCompleted;
// event
private static readonly object EventLoadCompleted = new object();
private static readonly object EventSoundLocationChanged = new object();
private static readonly object EventStreamChanged = new object();
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.SoundPlayer"]/*' />
public SoundPlayer() {
loadAsyncOperationCompleted =
new SendOrPostCallback(LoadAsyncOperationCompleted);
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.SoundPlayer1"]/*' />
public SoundPlayer(string soundLocation) : this() {
if(soundLocation == null) {
soundLocation = String.Empty;
}
SetupSoundLocation(soundLocation);
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.SoundPlayer2"]/*' />
public SoundPlayer(Stream stream) : this() {
this.stream = stream;
}
/**
* Constructor used in deserialization
*/
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.SoundPlayer4"]/*' />
[
SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes"), // SerializationInfo stores LoadTimeout as an object.
SuppressMessage("Microsoft.Performance", "CA1801:AvoidUnusedParameters") // Serialization constructor needs a Context parameter.
]
protected SoundPlayer(SerializationInfo serializationInfo, StreamingContext context) {
foreach(SerializationEntry entry in serializationInfo) {
switch (entry.Name) {
case "SoundLocation" :
SetupSoundLocation((string) entry.Value);
break;
case "Stream" :
stream = (Stream) entry.Value;
// when we deserialize a stream we have to reset its seek position
// vsWhidbey 180361
if (stream.CanSeek) {
stream.Seek(0, SeekOrigin.Begin);
}
break;
case "LoadTimeout" :
this.LoadTimeout = (int) entry.Value;
break;
}
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.LoadTimeout"]/*' />
public int LoadTimeout {
get {
return loadTimeout;
}
set {
if (value < 0) {
throw new ArgumentOutOfRangeException("LoadTimeout", value, SR.GetString(SR.SoundAPILoadTimeout));
}
loadTimeout = value;
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.Path"]/*' />
public string SoundLocation {
get {
if (uri != null && uri.IsFile) {
FileIOPermission fiop = new FileIOPermission(PermissionState.None);
fiop.AllFiles = FileIOPermissionAccess.PathDiscovery;
fiop.Demand();
}
return soundLocation;
}
set {
if (value == null)
value = String.Empty;
if (soundLocation.Equals(value))
return;
SetupSoundLocation(value);
OnSoundLocationChanged(EventArgs.Empty);
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.Stream"]/*' />
public Stream Stream {
get {
// if the path is set, we should return null
// Path and Stream are mutually exclusive
if (uri != null)
return null;
return this.stream;
}
set {
if (stream == value)
return;
SetupStream(value);
OnStreamChanged(EventArgs.Empty);
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.IsLoadCompleted"]/*' />
public bool IsLoadCompleted {
get {
return isLoadCompleted;
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.Tag"]/*' />
public object Tag {
get {
return tag;
}
set {
tag = value;
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.LoadAsync"]/*' />
public void LoadAsync() {
// if we have a file there is nothing to load - we just pass the file to the PlaySound function
// if we have a stream, then we start loading the stream async
//
if (uri!= null && uri.IsFile){
Debug.Assert(stream == null, "we can't have a stream and a path at the same time");
isLoadCompleted = true;
FileInfo fi = new FileInfo(uri.LocalPath);
if (!fi.Exists) {
throw new FileNotFoundException(SR.GetString(SR.SoundAPIFileDoesNotExist), this.soundLocation);
}
OnLoadCompleted(new AsyncCompletedEventArgs(null, false, null));
return;
}
// if we are actively loading, keep it running
if (copyThread != null && copyThread.ThreadState == System.Threading.ThreadState.Running) {
return;
}
isLoadCompleted = false;
streamData = null;
currentPos = 0;
asyncOperation = AsyncOperationManager.CreateOperation(null);
LoadStream(false);
}
private void LoadAsyncOperationCompleted(object arg)
{
OnLoadCompleted((AsyncCompletedEventArgs)arg);
}
// called for loading a stream synchronously
// called either when the user is setting the path/stream and we are loading
// or when loading took more time than the time out
private void CleanupStreamData() {
this.currentPos = 0;
this.streamData = null;
this.isLoadCompleted = false;
this.lastLoadException = null;
this.doesLoadAppearSynchronous = false;
this.copyThread = null;
this.semaphore.Set();
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.Load"]/*' />
public void Load() {
// if we have a file there is nothing to load - we just pass the file to the PlaySound function
// if we have a stream, then we start loading the stream sync
//
if (uri != null && uri.IsFile){
Debug.Assert(stream == null, "we can't have a stream and a path at the same time");
FileInfo fi = new FileInfo(uri.LocalPath);
if (!fi.Exists) {
throw new FileNotFoundException(SR.GetString(SR.SoundAPIFileDoesNotExist), this.soundLocation);
}
isLoadCompleted = true;
OnLoadCompleted(new AsyncCompletedEventArgs(null, false, null));
return;
}
LoadSync();
}
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")] // FileIOPermission based on URI path, but path isn't gonna change during scope of Demand
private void LoadAndPlay(int flags) {
// bug 16794: when the user does not specify a sound location nor a stream, play Beep
if (String.IsNullOrEmpty(soundLocation) && stream == null) {
SystemSounds.Beep.Play();
return;
}
if (uri != null && uri.IsFile) {
// VSW 580992: With more than one thread, someone could call SoundPlayer::set_Location
// between the time LoadAndPlay demands FileIO and the time it calls PlaySound under elevation.
//
// Another scenario is someone calling SoundPlayer::set_Location between the time
// LoadAndPlay validates the sound file and the time it calls PlaySound.
// The SoundPlayer will end up playing an un-validated sound file.
// The solution is to store the uri.LocalPath on a local variable
string localPath = uri.LocalPath;
// request permission to read the file:
// pass the full path to the FileIOPermission
FileIOPermission perm = new FileIOPermission(FileIOPermissionAccess.Read, localPath);
perm.Demand();
// play the path
isLoadCompleted = true;
System.Media.SoundPlayer.IntSecurity.SafeSubWindows.Demand();
System.ComponentModel.IntSecurity.UnmanagedCode.Assert();
// ValidateSoundFile calls into the MMIO API so we need UnmanagedCode permissions to do that.
// And of course we need UnmanagedCode permissions to all Win32::PlaySound method.
try {
// don't use uri.AbsolutePath because that gives problems when there are whitespaces in file names
ValidateSoundFile(localPath);
UnsafeNativeMethods.PlaySound(localPath, IntPtr.Zero, NativeMethods.SND_NODEFAULT | flags);
} finally {
System.Security.CodeAccessPermission.RevertAssert();
}
} else {
LoadSync();
ValidateSoundData(streamData);
System.Media.SoundPlayer.IntSecurity.SafeSubWindows.Demand();
System.ComponentModel.IntSecurity.UnmanagedCode.Assert();
try {
UnsafeNativeMethods.PlaySound(streamData, IntPtr.Zero, NativeMethods.SND_MEMORY | NativeMethods.SND_NODEFAULT | flags);
} finally {
System.Security.CodeAccessPermission.RevertAssert();
}
}
}
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")] // WebPermission based on URI path, but path isn't gonna change during scope of Demand
private void LoadSync() {
Debug.Assert((uri == null || !uri.IsFile), "we only load streams");
// first make sure that any possible download ended
if (!semaphore.WaitOne(LoadTimeout, false)) {
if (copyThread != null)
copyThread.Abort();
CleanupStreamData();
throw new TimeoutException(SR.GetString(SR.SoundAPILoadTimedOut));
}
// if we have data, then we are done
if (streamData != null)
return;
// setup the http stream
if (uri != null && !uri.IsFile && stream == null) {
WebPermission webPerm = new WebPermission(NetworkAccess.Connect, uri.AbsolutePath);
webPerm.Demand();
WebRequest webRequest = WebRequest.Create(uri);
webRequest.Timeout = LoadTimeout;
WebResponse webResponse;
webResponse = webRequest.GetResponse();
// now get the stream
stream = webResponse.GetResponseStream();
}
if (stream.CanSeek) {
// if we can get data synchronously, then get it
LoadStream(true);
} else {
// the data can't be loaded synchronously
// load it async, then wait for it to finish
doesLoadAppearSynchronous = true; // to avoid OnFailed call.
LoadStream(false);
if(!semaphore.WaitOne(LoadTimeout, false)) {
if (copyThread != null)
copyThread.Abort();
CleanupStreamData();
throw new TimeoutException(SR.GetString(SR.SoundAPILoadTimedOut));
}
doesLoadAppearSynchronous = false;
if (lastLoadException != null)
{
throw lastLoadException;
}
}
// we don't need the worker copyThread anymore
this.copyThread = null;
}
private void LoadStream(bool loadSync) {
if (loadSync && stream.CanSeek) {
int streamLen = (int) stream.Length;
currentPos = 0;
streamData = new byte[streamLen];
stream.Read(streamData, 0, streamLen);
isLoadCompleted = true;
OnLoadCompleted(new AsyncCompletedEventArgs(null, false, null));
} else {
// lock any synchronous calls on the Sound object
semaphore.Reset();
// start loading
copyThread = new Thread(new ThreadStart(this.WorkerThread));
copyThread.Start();
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.Play"]/*' />
public void Play() {
LoadAndPlay(NativeMethods.SND_ASYNC);
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.PlaySync"]/*' />
public void PlaySync() {
LoadAndPlay(NativeMethods.SND_SYNC);
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.PlayLooping"]/*' />
public void PlayLooping() {
LoadAndPlay(NativeMethods.SND_LOOP | NativeMethods.SND_ASYNC);
}
private static Uri ResolveUri(string partialUri) {
Uri result = null;
try {
result = new Uri(partialUri);
} catch (UriFormatException) {
// eat URI parse exceptions
}
if (result == null) {
// try relative to appbase
try {
result = new Uri(Path.GetFullPath(partialUri));
} catch (UriFormatException) {
// eat URI parse exceptions
}
}
return result;
}
private void SetupSoundLocation(string soundLocation) {
// if we are loading a file, stop it right now
//
if (copyThread != null) {
copyThread.Abort();
CleanupStreamData();
}
uri = ResolveUri(soundLocation);
this.soundLocation = soundLocation;
stream = null;
if (uri == null) {
if (!String.IsNullOrEmpty(soundLocation))
throw new UriFormatException(SR.GetString(SR.SoundAPIBadSoundLocation));
} else {
if (!uri.IsFile) {
// we are referencing a web resource ...
//
// we treat it as a stream...
//
streamData = null;
currentPos = 0;
isLoadCompleted = false;
}
}
}
private void SetupStream(Stream stream) {
if (this.copyThread != null) {
copyThread.Abort();
CleanupStreamData();
}
this.stream = stream;
this.soundLocation = String.Empty;
this.streamData = null;
this.currentPos = 0;
isLoadCompleted = false;
if (stream != null) {
uri = null;
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.Stop"]/*' />
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
public void Stop() {
IntSecurity.SafeSubWindows.Demand();
UnsafeNativeMethods.PlaySound((byte[]) null, IntPtr.Zero, NativeMethods.SND_PURGE);
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.LoadCompleted"]/*' />
public event AsyncCompletedEventHandler LoadCompleted {
add {
Events.AddHandler(EventLoadCompleted, value);
}
remove {
Events.RemoveHandler(EventLoadCompleted, value);
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.SoundLocationChanged"]/*' />
public event EventHandler SoundLocationChanged {
add {
Events.AddHandler(EventSoundLocationChanged, value);
}
remove {
Events.RemoveHandler(EventSoundLocationChanged, value);
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.StreamChanged"]/*' />
public event EventHandler StreamChanged {
add {
Events.AddHandler(EventStreamChanged, value);
}
remove {
Events.RemoveHandler(EventStreamChanged, value);
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.OnLoadCompleted"]/*' />
protected virtual void OnLoadCompleted(AsyncCompletedEventArgs e) {
AsyncCompletedEventHandler eh = (AsyncCompletedEventHandler) Events[EventLoadCompleted];
if (eh != null)
{
eh(this, e);
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.OnSoundLocationChanged"]/*' />
protected virtual void OnSoundLocationChanged(EventArgs e) {
EventHandler eh = (EventHandler) Events[EventSoundLocationChanged];
if (eh != null)
{
eh(this, e);
}
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.OnStreamChanged"]/*' />
protected virtual void OnStreamChanged(EventArgs e) {
EventHandler eh = (EventHandler) Events[EventStreamChanged];
if (eh != null)
{
eh(this, e);
}
}
[
SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes") // The set of reasons why WorkerThread should fail is not finite
]
private void WorkerThread() {
try
{
// setup the http stream
if (uri != null && !uri.IsFile && stream == null) {
WebRequest webRequest = WebRequest.Create(uri);
WebResponse webResponse = webRequest.GetResponse();
stream = webResponse.GetResponseStream();
}
this.streamData = new byte[blockSize];
int readBytes = stream.Read(streamData, currentPos, blockSize);
int totalBytes = readBytes;
while (readBytes > 0) {
currentPos += readBytes;
if (streamData.Length < currentPos + blockSize) {
byte[] newData = new byte[streamData.Length * 2];
Array.Copy(streamData, newData, streamData.Length);
streamData = newData;
}
readBytes = stream.Read(streamData, currentPos, blockSize);
totalBytes += readBytes;
}
lastLoadException = null;
}
catch (Exception exception)
{
lastLoadException = exception;
}
if (!doesLoadAppearSynchronous)
{
// Post notification back to the UI thread.
asyncOperation.PostOperationCompleted(
loadAsyncOperationCompleted,
new AsyncCompletedEventArgs(lastLoadException, false, null));
}
isLoadCompleted = true;
semaphore.Set();
}
private unsafe void ValidateSoundFile(string fileName) {
NativeMethods.MMCKINFO ckRIFF = new NativeMethods.MMCKINFO();
NativeMethods.MMCKINFO ck = new NativeMethods.MMCKINFO();
NativeMethods.WAVEFORMATEX waveFormat = null;
int dw;
IntPtr hMIO = UnsafeNativeMethods.mmioOpen(fileName, IntPtr.Zero, NativeMethods.MMIO_READ | NativeMethods.MMIO_ALLOCBUF);
if (hMIO == IntPtr.Zero)
throw new FileNotFoundException(SR.GetString(SR.SoundAPIFileDoesNotExist), this.soundLocation);
try {
ckRIFF.fccType = mmioFOURCC('W', 'A','V','E');
if (UnsafeNativeMethods.mmioDescend(hMIO, ckRIFF, null, NativeMethods.MMIO_FINDRIFF) != 0)
throw new InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveFile, this.soundLocation));
while (UnsafeNativeMethods.mmioDescend(hMIO, ck, ckRIFF, 0) == 0) {
if (ck.dwDataOffset + ck.cksize > ckRIFF.dwDataOffset + ckRIFF.cksize)
throw new InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveHeader));
if (ck.ckID == mmioFOURCC('f','m','t',' ')) {
if (waveFormat == null) {
dw = ck.cksize;
if (dw < Marshal.SizeOf(typeof(NativeMethods.WAVEFORMATEX)))
dw = Marshal.SizeOf(typeof(NativeMethods.WAVEFORMATEX));
waveFormat = new NativeMethods.WAVEFORMATEX();
byte[] data = new byte[dw];
if (UnsafeNativeMethods.mmioRead(hMIO, data, dw) != dw)
throw new InvalidOperationException(SR.GetString(SR.SoundAPIReadError, this.soundLocation));
fixed(byte* pdata = data) {
Marshal.PtrToStructure((IntPtr) pdata, waveFormat);
}
} else {
//
// multiple formats?
//
}
}
UnsafeNativeMethods.mmioAscend(hMIO, ck, 0);
}
if (waveFormat == null)
throw new InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveHeader));
if (waveFormat.wFormatTag != NativeMethods.WAVE_FORMAT_PCM &&
waveFormat.wFormatTag != NativeMethods.WAVE_FORMAT_ADPCM &&
waveFormat.wFormatTag != NativeMethods.WAVE_FORMAT_IEEE_FLOAT)
throw new InvalidOperationException(SR.GetString(SR.SoundAPIFormatNotSupported));
} finally {
if (hMIO != IntPtr.Zero)
UnsafeNativeMethods.mmioClose(hMIO, 0);
}
}
private static void ValidateSoundData(byte[] data) {
int position = 0;
Int16 wFormatTag = -1;
bool fmtChunkFound = false;
// the RIFF header should be at least 12 bytes long.
if (data.Length < 12)
throw new System.InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveHeader));
// validate the RIFF header
if (data[0] != 'R' || data[1] != 'I' || data[2] != 'F' || data[3] != 'F')
throw new System.InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveHeader));
if (data[8] != 'W' || data[9] != 'A' || data[10] != 'V' || data[11] != 'E')
throw new System.InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveHeader));
// we only care about "fmt " chunk
position = 12;
int len = data.Length;
while (!fmtChunkFound && position < len - 8) {
if (data[position] == (byte)'f' && data[position + 1] == (byte)'m' && data[position + 2] == (byte)'t' && data[position+3] == (byte)' ') {
//
// fmt chunk
//
fmtChunkFound = true;
int chunkSize = BytesToInt(data[position+7], data[position+6], data[position+5], data[position+4]);
//
// get the cbSize from the WAVEFORMATEX
//
int sizeOfWAVEFORMAT = 16;
if (chunkSize != sizeOfWAVEFORMAT) {
// we are dealing w/ WAVEFORMATEX
// do extra validation
int sizeOfWAVEFORMATEX = 18;
// make sure the buffer is big enough to store a short
if (len < position + 8 + sizeOfWAVEFORMATEX - 1)
throw new System.InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveHeader));
Int16 cbSize = BytesToInt16(data[position+8 + sizeOfWAVEFORMATEX - 1],
data[position+8 + sizeOfWAVEFORMATEX-2]);
if (cbSize + sizeOfWAVEFORMATEX != chunkSize)
throw new System.InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveHeader));
}
// make sure the buffer passed in is big enough to store a short
if(len < position + 9)
throw new System.InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveHeader));
wFormatTag = BytesToInt16(data[position+9], data[position+8]);
position += chunkSize + 8;
} else {
position += 8 + BytesToInt(data[position+7], data[position+6], data[position+5], data[position+4]);
}
}
if (!fmtChunkFound)
throw new System.InvalidOperationException(SR.GetString(SR.SoundAPIInvalidWaveHeader));
if (wFormatTag != NativeMethods.WAVE_FORMAT_PCM &&
wFormatTag != NativeMethods.WAVE_FORMAT_ADPCM &&
wFormatTag != NativeMethods.WAVE_FORMAT_IEEE_FLOAT)
throw new System.InvalidOperationException(SR.GetString(SR.SoundAPIFormatNotSupported));
}
private static Int16 BytesToInt16(byte ch0, byte ch1) {
int res;
res = (int) ch1;
res |= (int) (((int)ch0) << 8);
return (Int16) res;
}
private static int BytesToInt(byte ch0, byte ch1, byte ch2, byte ch3) {
return mmioFOURCC((char) ch3, (char)ch2, (char) ch1, (char)ch0);
}
private static int mmioFOURCC(char ch0, char ch1, char ch2, char ch3) {
int result = 0;
result |= ((int) ch0);
result |= ((int) ch1) << 8;
result |= ((int) ch2) << 16;
result |= ((int) ch3) << 24;
return result;
}
/// <include file='doc\SoundPlayer.uex' path='docs/doc[@for="SoundPlayer.GetObjectData"]/*' />
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")] // vsw 427356
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
if (!String.IsNullOrEmpty(this.soundLocation)) {
info.AddValue("SoundLocation", this.soundLocation);
}
if (this.stream != null) {
info.AddValue("Stream", this.stream);
}
info.AddValue("LoadTimeout", this.loadTimeout);
}
private class IntSecurity {
// Constructor added because of FxCop rules
private IntSecurity() {}
private static volatile CodeAccessPermission safeSubWindows;
internal static CodeAccessPermission SafeSubWindows {
get {
if (safeSubWindows == null) {
safeSubWindows = new UIPermission(UIPermissionWindow.SafeSubWindows);
}
return safeSubWindows;
}
}
}
private class NativeMethods {
// Constructor added because of FxCop rules
private NativeMethods() {}
internal const int WAVE_FORMAT_PCM = 0x0001,
WAVE_FORMAT_ADPCM = 0x0002,
WAVE_FORMAT_IEEE_FLOAT = 0x0003;
internal const int MMIO_READ = 0x00000000,
MMIO_ALLOCBUF = 0x00010000,
MMIO_FINDRIFF = 0x00000020;
internal const int SND_SYNC = 0000,
SND_ASYNC = 0x0001,
SND_NODEFAULT = 0x0002,
SND_MEMORY = 0x0004,
SND_LOOP = 0x0008,
SND_PURGE = 0x0040,
SND_FILENAME = 0x00020000,
SND_NOSTOP = 0x0010;
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
internal class MMCKINFO {
internal int ckID;
internal int cksize;
internal int fccType;
internal int dwDataOffset;
internal int dwFlags;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
internal class WAVEFORMATEX {
internal System.Int16 wFormatTag;
internal System.Int16 nChannels;
internal int nSamplesPerSec;
internal int nAvgBytesPerSec;
internal System.Int16 nBlockAlign;
internal System.Int16 wBitsPerSample;
internal System.Int16 cbSize;
}
}
private class UnsafeNativeMethods {
// Constructor added because of FxCop rules
private UnsafeNativeMethods() {}
[DllImport(ExternDll.WinMM, CharSet=CharSet.Auto)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern bool PlaySound([MarshalAs(UnmanagedType.LPWStr)] string soundName, IntPtr hmod, int soundFlags);
[DllImport(ExternDll.WinMM, ExactSpelling=true, CharSet=CharSet.Auto)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern bool PlaySound(byte[] soundName, IntPtr hmod, int soundFlags);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2101:SpecifyMarshalingForPInvokeStringArguments")]
[DllImport(ExternDll.WinMM, CharSet=CharSet.Auto)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern IntPtr mmioOpen(string fileName, IntPtr not_used, int flags);
[DllImport(ExternDll.WinMM, CharSet=CharSet.Auto)]
[ResourceExposure(ResourceScope.None)]
internal static extern int mmioAscend(IntPtr hMIO, NativeMethods.MMCKINFO lpck, int flags);
[DllImport(ExternDll.WinMM, CharSet=CharSet.Auto)]
[ResourceExposure(ResourceScope.None)]
internal static extern int mmioDescend(IntPtr hMIO,
[MarshalAs(UnmanagedType.LPStruct)] NativeMethods.MMCKINFO lpck,
[MarshalAs(UnmanagedType.LPStruct)] NativeMethods.MMCKINFO lcpkParent,
int flags);
[DllImport(ExternDll.WinMM, CharSet=CharSet.Auto)]
[ResourceExposure(ResourceScope.None)]
internal static extern int mmioRead(IntPtr hMIO, [MarshalAs(UnmanagedType.LPArray)] byte[] wf, int cch);
[DllImport(ExternDll.WinMM, CharSet=CharSet.Auto)]
[ResourceExposure(ResourceScope.None)]
internal static extern int mmioClose(IntPtr hMIO, int flags);
}
}
}
|