123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601 |
- //------------------------------------------------------------------------------
- // <copyright file="ActiveXMessageFormatter.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- //------------------------------------------------------------------------------
- using Experimental.System.Messaging.Interop;
- using System;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Text;
- namespace Experimental.System.Messaging
- {
- /// <include file='doc\ActiveXMessageFormatter.uex' path='docs/doc[@for="ActiveXMessageFormatter"]/*' />
- /// <devdoc>
- /// <para>
- /// Formatter class that serializes and deserializes
- /// primitives, classes, enumeration, and other objects into and from <see cref='System.Messaging.MessageQueue'/>
- /// messages using binary format.
- /// </para>
- /// </devdoc>
- public class ActiveXMessageFormatter : IMessageFormatter
- {
- internal const short VT_ARRAY = 0x2000;
- internal const short VT_BOOL = 11;
- internal const short VT_BSTR = 8;
- internal const short VT_CLSID = 72;
- internal const short VT_CY = 6;
- internal const short VT_DATE = 7;
- internal const short VT_I1 = 16;
- internal const short VT_I2 = 2;
- internal const short VT_I4 = 3;
- internal const short VT_I8 = 20;
- internal const short VT_LPSTR = 30;
- internal const short VT_LPWSTR = 31;
- internal const short VT_NULL = 1;
- internal const short VT_R4 = 4;
- internal const short VT_R8 = 5;
- internal const short VT_STREAMED_OBJECT = 68;
- internal const short VT_STORED_OBJECT = 69;
- internal const short VT_UI1 = 17;
- internal const short VT_UI2 = 18;
- internal const short VT_UI4 = 19;
- internal const short VT_UI8 = 21;
- internal const short VT_VECTOR = 0x1000;
- private byte[] internalBuffer;
- private UnicodeEncoding unicodeEncoding;
- private ASCIIEncoding asciiEncoding;
- private char[] internalCharBuffer;
- /// <include file='doc\ActiveXMessageFormatter.uex' path='docs/doc[@for="ActiveXMessageFormatter.CanRead"]/*' />
- /// <devdoc>
- /// When this method is called, the formatter will attempt to determine
- /// if the contents of the message are something the formatter can deal with.
- /// </devdoc>
- public bool CanRead(Message message)
- {
- if (message == null)
- throw new ArgumentNullException("message");
- int variantType = message.BodyType;
- if (variantType != VT_BOOL && variantType != VT_CLSID &&
- variantType != VT_CY && variantType != VT_DATE &&
- variantType != VT_I1 && variantType != VT_UI1 &&
- variantType != VT_I2 && variantType != VT_UI2 &&
- variantType != VT_I4 && variantType != VT_UI4 &&
- variantType != VT_I8 && variantType != VT_UI8 &&
- variantType != VT_NULL && variantType != VT_R4 &&
- variantType != VT_I8 && variantType != VT_STREAMED_OBJECT &&
- variantType != VT_STORED_OBJECT &&
- variantType != (VT_VECTOR | VT_UI1) &&
- variantType != VT_LPSTR && variantType != VT_LPWSTR &&
- variantType != VT_BSTR && variantType != VT_R8)
- return false;
- return true;
- }
- /// <include file='doc\ActiveXMessageFormatter.uex' path='docs/doc[@for="ActiveXMessageFormatter.Clone"]/*' />
- /// <devdoc>
- /// This method is needed to improve scalability on Receive and ReceiveAsync scenarios. Not requiring
- /// thread safety on read and write.
- /// </devdoc>
- public object Clone()
- {
- return new ActiveXMessageFormatter();
- }
- /// <include file='doc\ActiveXMessageFormatter.uex' path='docs/doc[@for="ActiveXMessageFormatter.InitStreamedObject"]/*' />
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- public static void InitStreamedObject(object streamedObject)
- {
- IPersistStreamInit persistStreamInit = streamedObject as IPersistStreamInit;
- if (persistStreamInit != null)
- persistStreamInit.InitNew();
- }
- /// <include file='doc\ActiveXMessageFormatter.uex' path='docs/doc[@for="ActiveXMessageFormatter.Read"]/*' />
- /// <devdoc>
- /// This method is used to read the contents from the given message
- /// and create an object.
- /// </devdoc>
- public object Read(Message message)
- {
- if (message == null)
- throw new ArgumentNullException("message");
- Stream stream;
- byte[] bytes;
- byte[] newBytes;
- int size;
- int variantType = message.BodyType;
- switch (variantType)
- {
- case VT_LPSTR:
- bytes = message.properties.GetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY);
- size = message.properties.GetUI4(NativeMethods.MESSAGE_PROPID_BODY_SIZE);
- if (this.internalCharBuffer == null || this.internalCharBuffer.Length < size)
- this.internalCharBuffer = new char[size];
- if (asciiEncoding == null)
- this.asciiEncoding = new ASCIIEncoding();
- this.asciiEncoding.GetChars(bytes, 0, size, this.internalCharBuffer, 0);
- return new String(this.internalCharBuffer, 0, size);
- case VT_BSTR:
- case VT_LPWSTR:
- bytes = message.properties.GetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY);
- size = message.properties.GetUI4(NativeMethods.MESSAGE_PROPID_BODY_SIZE) / 2;
- if (this.internalCharBuffer == null || this.internalCharBuffer.Length < size)
- this.internalCharBuffer = new char[size];
- if (unicodeEncoding == null)
- this.unicodeEncoding = new UnicodeEncoding();
- this.unicodeEncoding.GetChars(bytes, 0, size * 2, this.internalCharBuffer, 0);
- return new String(this.internalCharBuffer, 0, size);
- case VT_VECTOR | VT_UI1:
- bytes = message.properties.GetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY);
- size = message.properties.GetUI4(NativeMethods.MESSAGE_PROPID_BODY_SIZE);
- newBytes = new byte[size];
- Array.Copy(bytes, newBytes, size);
- return newBytes;
- case VT_BOOL:
- bytes = message.properties.GetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY);
- newBytes = new byte[1];
- Array.Copy(bytes, newBytes, 1);
- if (bytes[0] != 0)
- return true;
- return false;
- case VT_CLSID:
- bytes = message.properties.GetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY);
- newBytes = new byte[16];
- Array.Copy(bytes, newBytes, 16);
- return new Guid(newBytes);
- case VT_CY:
- bytes = message.properties.GetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY);
- newBytes = new byte[8];
- Array.Copy(bytes, newBytes, 8);
- return Decimal.FromOACurrency(BitConverter.ToInt64(newBytes, 0));
- case VT_DATE:
- bytes = message.properties.GetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY);
- newBytes = new byte[8];
- Array.Copy(bytes, newBytes, 8);
- return new DateTime(BitConverter.ToInt64(newBytes, 0));
- case VT_I1:
- case VT_UI1:
- stream = message.BodyStream;
- bytes = new byte[1];
- stream.Read(bytes, 0, 1);
- return bytes[0];
- case VT_I2:
- stream = message.BodyStream;
- bytes = new byte[2];
- stream.Read(bytes, 0, 2);
- return BitConverter.ToInt16(bytes, 0);
- case VT_UI2:
- stream = message.BodyStream;
- bytes = new byte[2];
- stream.Read(bytes, 0, 2);
- return BitConverter.ToUInt16(bytes, 0);
- case VT_I4:
- stream = message.BodyStream;
- bytes = new byte[4];
- stream.Read(bytes, 0, 4);
- return BitConverter.ToInt32(bytes, 0);
- case VT_UI4:
- stream = message.BodyStream;
- bytes = new byte[4];
- stream.Read(bytes, 0, 4);
- return BitConverter.ToUInt32(bytes, 0);
- case VT_I8:
- stream = message.BodyStream;
- bytes = new byte[8];
- stream.Read(bytes, 0, 8);
- return BitConverter.ToInt64(bytes, 0);
- case VT_UI8:
- stream = message.BodyStream;
- bytes = new byte[8];
- stream.Read(bytes, 0, 8);
- return BitConverter.ToUInt64(bytes, 0);
- case VT_R4:
- stream = message.BodyStream;
- bytes = new byte[4];
- stream.Read(bytes, 0, 4);
- return BitConverter.ToSingle(bytes, 0);
- case VT_R8:
- stream = message.BodyStream;
- bytes = new byte[8];
- stream.Read(bytes, 0, 8);
- return BitConverter.ToDouble(bytes, 0);
- case VT_NULL:
- return null;
- case VT_STREAMED_OBJECT:
- stream = message.BodyStream;
- ComStreamFromDataStream comStream = new ComStreamFromDataStream(stream);
- return NativeMethods.OleLoadFromStream(comStream, ref NativeMethods.IID_IUnknown);
- case VT_STORED_OBJECT:
- throw new NotSupportedException(Res.GetString(Res.StoredObjectsNotSupported));
- default:
- throw new InvalidOperationException(Res.GetString(Res.InvalidTypeDeserialization));
- }
- }
- /// <include file='doc\ActiveXMessageFormatter.uex' path='docs/doc[@for="ActiveXMessageFormatter.Write"]/*' />
- /// <devdoc>
- /// This method is used to write the given object into the given message.
- /// If the formatter cannot understand the given object, an exception is thrown.
- /// </devdoc>
- public void Write(Message message, object obj)
- {
- if (message == null)
- throw new ArgumentNullException("message");
- Stream stream;
- int variantType;
- if (obj is string)
- {
- int size = ((string)obj).Length * 2;
- if (this.internalBuffer == null || this.internalBuffer.Length < size)
- this.internalBuffer = new byte[size];
- if (unicodeEncoding == null)
- this.unicodeEncoding = new UnicodeEncoding();
- this.unicodeEncoding.GetBytes(((string)obj).ToCharArray(), 0, size / 2, this.internalBuffer, 0);
- message.properties.SetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY, this.internalBuffer);
- message.properties.AdjustSize(NativeMethods.MESSAGE_PROPID_BODY, size);
- message.properties.SetUI4(NativeMethods.MESSAGE_PROPID_BODY_SIZE, size);
- message.properties.SetUI4(NativeMethods.MESSAGE_PROPID_BODY_TYPE, VT_LPWSTR);
- return;
- }
- else if (obj is byte[])
- {
- byte[] bytes = (byte[])obj;
- if (this.internalBuffer == null || this.internalBuffer.Length < bytes.Length)
- this.internalBuffer = new byte[bytes.Length];
- Array.Copy(bytes, this.internalBuffer, bytes.Length);
- message.properties.SetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY, this.internalBuffer);
- message.properties.AdjustSize(NativeMethods.MESSAGE_PROPID_BODY, bytes.Length);
- message.properties.SetUI4(NativeMethods.MESSAGE_PROPID_BODY_SIZE, bytes.Length);
- message.properties.SetUI4(NativeMethods.MESSAGE_PROPID_BODY_TYPE, VT_UI1 | VT_VECTOR);
- return;
- }
- else if (obj is char[])
- {
- char[] chars = (char[])obj;
- int size = chars.Length * 2;
- if (this.internalBuffer == null || this.internalBuffer.Length < size)
- this.internalBuffer = new byte[size];
- if (unicodeEncoding == null)
- this.unicodeEncoding = new UnicodeEncoding();
- this.unicodeEncoding.GetBytes(chars, 0, size / 2, this.internalBuffer, 0);
- message.properties.SetUI1Vector(NativeMethods.MESSAGE_PROPID_BODY, this.internalBuffer);
- message.properties.SetUI4(NativeMethods.MESSAGE_PROPID_BODY_SIZE, size);
- message.properties.SetUI4(NativeMethods.MESSAGE_PROPID_BODY_TYPE, VT_LPWSTR);
- return;
- }
- else if (obj is byte)
- {
- stream = new MemoryStream(1);
- stream.Write(new byte[] { (byte)obj }, 0, 1);
- variantType = VT_UI1;
- }
- else if (obj is bool)
- {
- stream = new MemoryStream(1);
- if ((bool)obj)
- stream.Write(new byte[] { 0xff }, 0, 1);
- else
- stream.Write(new byte[] { 0x00 }, 0, 1);
- variantType = VT_BOOL;
- }
- else if (obj is char)
- {
- stream = new MemoryStream(2);
- byte[] bytes = BitConverter.GetBytes((Char)obj);
- stream.Write(bytes, 0, 2);
- variantType = VT_UI2;
- }
- else if (obj is Decimal)
- {
- stream = new MemoryStream(8);
- byte[] bytes = BitConverter.GetBytes(Decimal.ToOACurrency((Decimal)obj));
- stream.Write(bytes, 0, 8);
- variantType = VT_CY;
- }
- else if (obj is DateTime)
- {
- stream = new MemoryStream(8);
- byte[] bytes = BitConverter.GetBytes(((DateTime)obj).Ticks);
- stream.Write(bytes, 0, 8);
- variantType = VT_DATE;
- }
- else if (obj is Double)
- {
- stream = new MemoryStream(8);
- byte[] bytes = BitConverter.GetBytes((Double)obj);
- stream.Write(bytes, 0, 8);
- variantType = VT_R8;
- }
- else if (obj is Int16)
- {
- stream = new MemoryStream(2);
- byte[] bytes = BitConverter.GetBytes((short)obj);
- stream.Write(bytes, 0, 2);
- variantType = VT_I2;
- }
- else if (obj is UInt16)
- {
- stream = new MemoryStream(2);
- byte[] bytes = BitConverter.GetBytes((UInt16)obj);
- stream.Write(bytes, 0, 2);
- variantType = VT_UI2;
- }
- else if (obj is Int32)
- {
- stream = new MemoryStream(4);
- byte[] bytes = BitConverter.GetBytes((int)obj);
- stream.Write(bytes, 0, 4);
- variantType = VT_I4;
- }
- else if (obj is UInt32)
- {
- stream = new MemoryStream(4);
- byte[] bytes = BitConverter.GetBytes((UInt32)obj);
- stream.Write(bytes, 0, 4);
- variantType = VT_UI4;
- }
- else if (obj is Int64)
- {
- stream = new MemoryStream(8);
- byte[] bytes = BitConverter.GetBytes((Int64)obj);
- stream.Write(bytes, 0, 8);
- variantType = VT_I8;
- }
- else if (obj is UInt64)
- {
- stream = new MemoryStream(8);
- byte[] bytes = BitConverter.GetBytes((UInt64)obj);
- stream.Write(bytes, 0, 8);
- variantType = VT_UI8;
- }
- else if (obj is Single)
- {
- stream = new MemoryStream(4);
- byte[] bytes = BitConverter.GetBytes((float)obj);
- stream.Write(bytes, 0, 4);
- variantType = VT_R4;
- }
- else if (obj is IPersistStream)
- {
- IPersistStream pstream = (IPersistStream)obj;
- ComStreamFromDataStream comStream = new ComStreamFromDataStream(new MemoryStream());
- NativeMethods.OleSaveToStream(pstream, comStream);
- stream = comStream.GetDataStream();
- variantType = VT_STREAMED_OBJECT;
- }
- else if (obj == null)
- {
- stream = new MemoryStream();
- variantType = VT_NULL;
- }
- else
- {
- throw new InvalidOperationException(Res.GetString(Res.InvalidTypeSerialization));
- }
- message.BodyStream = stream;
- message.BodyType = variantType;
- }
- [ComVisible(false)]
- private class ComStreamFromDataStream : IStream
- {
- private Stream dataStream;
- // to support seeking ahead of the stream length...
- private long virtualPosition = -1;
- public ComStreamFromDataStream(Stream dataStream)
- {
- if (dataStream == null) throw new ArgumentNullException("dataStream");
- this.dataStream = dataStream;
- }
- private void ActualizeVirtualPosition()
- {
- if (virtualPosition == -1) return;
- if (virtualPosition > dataStream.Length)
- dataStream.SetLength(virtualPosition);
- dataStream.Position = virtualPosition;
- virtualPosition = -1;
- }
- public IStream Clone()
- {
- NotImplemented();
- return null;
- }
- public void Commit(int grfCommitFlags)
- {
- dataStream.Flush();
- // Extend the length of the file if needed.
- ActualizeVirtualPosition();
- }
- public long CopyTo(IStream pstm, long cb, long[] pcbRead)
- {
- int bufSize = 4096;
- IntPtr buffer = Marshal.AllocHGlobal((IntPtr)bufSize);
- if (buffer == IntPtr.Zero) throw new OutOfMemoryException();
- long written = 0;
- try
- {
- while (written < cb)
- {
- int toRead = bufSize;
- if (written + toRead > cb) toRead = (int)(cb - written);
- int read = Read(buffer, toRead);
- if (read == 0) break;
- if (pstm.Write(buffer, read) != read)
- {
- throw EFail(Res.GetString(Res.IncorrectNumberOfBytes));
- }
- written += read;
- }
- }
- finally
- {
- Marshal.FreeHGlobal(buffer);
- }
- if (pcbRead != null && pcbRead.Length > 0)
- {
- pcbRead[0] = written;
- }
- return written;
- }
- public Stream GetDataStream()
- {
- return dataStream;
- }
- public void LockRegion(long libOffset, long cb, int dwLockType)
- {
- }
- protected static ExternalException EFail(string msg)
- {
- ExternalException e = new ExternalException(msg, NativeMethods.E_FAIL);
- throw e;
- }
- protected static void NotImplemented()
- {
- ExternalException e = new ExternalException(Res.GetString(Res.NotImplemented), NativeMethods.E_NOTIMPL);
- throw e;
- }
- public int Read(IntPtr buf, int length)
- {
- byte[] buffer = new byte[length];
- int count = Read(buffer, length);
- Marshal.Copy(buffer, 0, buf, length);
- return count;
- }
- public int Read(byte[] buffer, int length)
- {
- ActualizeVirtualPosition();
- return dataStream.Read(buffer, 0, length);
- }
- public void Revert()
- {
- NotImplemented();
- }
- public long Seek(long offset, int origin)
- {
- long pos = virtualPosition;
- if (virtualPosition == -1)
- {
- pos = dataStream.Position;
- }
- long len = dataStream.Length;
- switch (origin)
- {
- case NativeMethods.STREAM_SEEK_SET:
- if (offset <= len)
- {
- dataStream.Position = offset;
- virtualPosition = -1;
- }
- else
- {
- virtualPosition = offset;
- }
- break;
- case NativeMethods.STREAM_SEEK_END:
- if (offset <= 0)
- {
- dataStream.Position = len + offset;
- virtualPosition = -1;
- }
- else
- {
- virtualPosition = len + offset;
- }
- break;
- case NativeMethods.STREAM_SEEK_CUR:
- if (offset + pos <= len)
- {
- dataStream.Position = pos + offset;
- virtualPosition = -1;
- }
- else
- {
- virtualPosition = offset + pos;
- }
- break;
- }
- if (virtualPosition != -1)
- {
- return virtualPosition;
- }
- else
- {
- return dataStream.Position;
- }
- }
- public void SetSize(long value)
- {
- dataStream.SetLength(value);
- }
- public void Stat(IntPtr pstatstg, int grfStatFlag)
- {
- // GpStream has a partial implementation, but it's so partial rather
- // restrict it to use with GDI+
- NotImplemented();
- }
- public void UnlockRegion(long libOffset, long cb, int dwLockType)
- {
- }
- public int Write(IntPtr buf, int length)
- {
- byte[] buffer = new byte[length];
- Marshal.Copy(buf, buffer, 0, length);
- return Write(buffer, length);
- }
- public int Write(byte[] buffer, int length)
- {
- ActualizeVirtualPosition();
- dataStream.Write(buffer, 0, length);
- return length;
- }
- }
- }
- }
|