I have the following Delphi code:
var
Stream: TMemoryStream;
StreamI: TStreamAdapter;
OleStream: IStream;
begin
Stream:= TMemoryStream.Create;
Stream.LoadFromFile(filename);
StreamI:= TStreamAdapter.Create(Stream, soOwned);
VSPDFViewer1.LoadStream(StreamI as IStream, '');
end;
开发者_开发技巧
Which actually passes an IStream object to a COM component. .NET has the "System.Runtime.InteropServices.ComTypes.IStream" interface, but I can't figure out a proper way to use it. How to initialize IStream with data and pass it to COM object in .NET?
It kind of sucks, but you're going to have to write your own .NET StreamAdapter
class. Fortunately you can steal all the code from Microsoft:
public class StreamAdapter : System.Runtime.InteropServices.ComTypes.IStream
{
// Fields
protected Stream dataStream;
private long virtualPosition = -1L;
// Methods
internal StreamAdapter(Stream stream)
{
if (!stream.CanSeek)
{
int num;
byte[] sourceArray = new byte[0x100];
int offset = 0;
do
{
if (sourceArray.Length < (offset + 0x100))
{
byte[] destinationArray = new byte[sourceArray.Length * 2];
Array.Copy(sourceArray, destinationArray, sourceArray.Length);
sourceArray = destinationArray;
}
num = stream.Read(sourceArray, offset, 0x100);
offset += num;
}
while (num != 0);
this.dataStream = new MemoryStream(sourceArray);
}
else
{
this.dataStream = stream;
}
}
private void ActualizeVirtualPosition()
{
if (this.virtualPosition != -1L)
{
if (this.virtualPosition > this.dataStream.Length)
{
this.dataStream.SetLength(this.virtualPosition);
}
this.dataStream.Position = this.virtualPosition;
this.virtualPosition = -1L;
}
}
public virtual System.Runtime.InteropServices.ComTypes.IStream Clone()
{
NotImplemented();
return null;
}
public virtual void Commit(int grfCommitFlags)
{
this.dataStream.Flush();
this.ActualizeVirtualPosition();
}
[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode), UIPermission(SecurityAction.Demand, Window=UIPermissionWindow.AllWindows)]
public virtual long CopyTo(UnsafeNativeMethods.IStream pstm, long cb, long[] pcbRead)
{
int num = 0x1000;
IntPtr buf = Marshal.AllocHGlobal(num);
if (buf == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
long num2 = 0L;
try
{
while (num2 < cb)
{
int length = num;
if ((num2 + length) > cb)
{
length = (int) (cb - num2);
}
int len = this.Read(buf, length);
if (len == 0)
{
goto Label_006C;
}
if (pstm.Write(buf, len) != len)
{
throw EFail("Wrote an incorrect number of bytes");
}
num2 += len;
}
}
finally
{
Marshal.FreeHGlobal(buf);
}
Label_006C:
if ((pcbRead != null) && (pcbRead.Length > 0))
{
pcbRead[0] = num2;
}
return num2;
}
protected static ExternalException EFail(string msg)
{
throw new ExternalException(msg, -2147467259);
}
public virtual Stream GetDataStream()
{
return this.dataStream;
}
public virtual void LockRegion(long libOffset, long cb, int dwLockType)
{
}
protected static void NotImplemented()
{
throw new ExternalException(SR.GetString("NotImplemented"), -2147467263);
}
public virtual int Read(IntPtr buf, int length)
{
byte[] buffer = new byte[length];
int num = this.Read(buffer, length);
Marshal.Copy(buffer, 0, buf, length);
return num;
}
public virtual int Read(byte[] buffer, int length)
{
this.ActualizeVirtualPosition();
return this.dataStream.Read(buffer, 0, length);
}
public virtual void Revert()
{
NotImplemented();
}
public virtual long Seek(long offset, int origin)
{
long virtualPosition = this.virtualPosition;
if (this.virtualPosition == -1L)
{
virtualPosition = this.dataStream.Position;
}
long length = this.dataStream.Length;
switch (origin)
{
case 0:
if (offset > length)
{
this.virtualPosition = offset;
break;
}
this.dataStream.Position = offset;
this.virtualPosition = -1L;
break;
case 1:
if ((offset + virtualPosition) > length)
{
this.virtualPosition = offset + virtualPosition;
break;
}
this.dataStream.Position = virtualPosition + offset;
this.virtualPosition = -1L;
break;
case 2:
if (offset > 0L)
{
this.virtualPosition = length + offset;
break;
}
this.dataStream.Position = length + offset;
this.virtualPosition = -1L;
break;
}
if (this.virtualPosition != -1L)
{
return this.virtualPosition;
}
return this.dataStream.Position;
}
public virtual void SetSize(long value)
{
this.dataStream.SetLength(value);
}
public void Stat(IntPtr pstatstg, int grfStatFlag)
{
STATSTG structure = new STATSTG();
structure.cbSize = this.dataStream.Length;
Marshal.StructureToPtr(structure, pstatstg, true);
}
public virtual void UnlockRegion(long libOffset, long cb, int dwLockType)
{
}
public virtual int Write(IntPtr buf, int length)
{
byte[] destination = new byte[length];
Marshal.Copy(buf, destination, 0, length);
return this.Write(destination, length);
}
public virtual int Write(byte[] buffer, int length)
{
this.ActualizeVirtualPosition();
this.dataStream.Write(buffer, 0, length);
return length;
}
// Nested Types
[StructLayout(LayoutKind.Sequential)]
public class STATSTG
{
public IntPtr pwcsName = IntPtr.Zero;
public int type;
[MarshalAs(UnmanagedType.I8)]
public long cbSize;
[MarshalAs(UnmanagedType.I8)]
public long mtime;
[MarshalAs(UnmanagedType.I8)]
public long ctime;
[MarshalAs(UnmanagedType.I8)]
public long atime;
[MarshalAs(UnmanagedType.I4)]
public int grfMode;
[MarshalAs(UnmanagedType.I4)]
public int grfLocksSupported;
public int clsid_data1;
[MarshalAs(UnmanagedType.I2)]
public short clsid_data2;
[MarshalAs(UnmanagedType.I2)]
public short clsid_data3;
[MarshalAs(UnmanagedType.U1)]
public byte clsid_b0;
[MarshalAs(UnmanagedType.U1)]
public byte clsid_b1;
[MarshalAs(UnmanagedType.U1)]
public byte clsid_b2;
[MarshalAs(UnmanagedType.U1)]
public byte clsid_b3;
[MarshalAs(UnmanagedType.U1)]
public byte clsid_b4;
[MarshalAs(UnmanagedType.U1)]
public byte clsid_b5;
[MarshalAs(UnmanagedType.U1)]
public byte clsid_b6;
[MarshalAs(UnmanagedType.U1)]
public byte clsid_b7;
[MarshalAs(UnmanagedType.I4)]
public int grfStateBits;
[MarshalAs(UnmanagedType.I4)]
public int reserved;
}
}
精彩评论