EDN Admin
Well-known member
Hi guys,<o></o>
I met a very wired issue about using IStream.Read() to read data from clipboard. This only happens on several servers of one of our clients. The problem is that when user copying files from local machine and paste to our system in RDP mode, the file is corrupted because random data is appended after the end of file. <o></o>
Our code is reading data from clipboard as IStream, and then read the stream using a buffer of 4KB and write 4KB to a temp file every time. Normally the last segment of the file stream will be less than 4KB so it should just read the number of KB left. This works well for all our clients except one of them. On this particular clients servers, it always cannot identify the end of file and append random data to make a complete 4 KB when reading the last segment, and the file is corrupted.<o></o>
Here is the code we used to get data from clipboard and write to a file. public ZDataObject( object Data)
{
if (Data is DataObject )
{
this.inner = ( DataObject )Data;
}
else
{
this.inner = new DataObject (Data);
}
}
public void SaveStreamToTempFile()
{
System.Windows.Forms. IDataObject dataObject = Clipboard .GetDataObject();
WriteFileContentsFromIStream( new ZDataObject (dataObject), fileName);
}
public static bool WriteFileContentsFromIStream( ZDataObject Data, string FileName, int lindex)
{
STGMEDIUM StgMedium;
FORMATETC FormatEtc;
FormatEtc.cfFormat = (short )DataFormats .GetFormat( "FileContents").Id;
FormatEtc.dwAspect = DVASPECT.DVASPECT_CONTENT;
FormatEtc.lindex = lindex;
FormatEtc.ptd = IntPtr.Zero;
FormatEtc.tymed = TYMED.TYMED_ISTREAM;
bool Result = false;
var OleDataObject = Data.GetInnerOleDataObject();
if (OleDataObject != null)
{
OleDataObject.GetData( ref FormatEtc, out StgMedium);
var OleStream = Marshal .GetObjectForIUnknown(StgMedium.unionmember) as IStream;
try
{
if (OleStream != null)
{
WriteStreamToFile(FileName, OleStream);
Result = true;
}
}
finally
{
if (OleStream != null)
{
Marshal.ReleaseComObject(OleStream);
}
}
}
return Result;
}
protected static bool WriteStreamToFile( string FileName, IStream OleStream)
{
byte[] Buf = new byte[4096];
using ( FileStream FileStr = File .Open(FileName, FileMode .Create, FileAccess .Write))
{
uint count = 0;
IntPtr countptr = Marshal.AllocHGlobal(8);
try
{
Marshal.StructureToPtr(count, countptr, true);
while ( true)
{
OleStream.Read(Buf, Buf.Length, countptr); // SuppressCodeSmell Reason=This is an OLE call that returns through countptr
count = (uint )Marshal .PtrToStructure(countptr, typeof( uint));
if (count == 0)
{
break;
}
FileStr.Write(Buf, 0, (int )count);
}
}
finally
{
Marshal.Release(countptr);
}
}
return true;
}
public System.Runtime.InteropServices.ComTypes. IDataObject GetInnerOleDataObject()
{
System.Runtime.InteropServices.ComTypes. IDataObject Result = null ;
FieldInfo InnerDataField = typeof (DataObject ).GetField( "innerData", BindingFlags .NonPublic | BindingFlags .Instance);
object InnerData = Inner;
while (InnerData != null && InnerData is DataObject )
{
InnerData = InnerDataField.GetValue(InnerData);
}
if (InnerData != null)
{
FieldInfo InnerOleConverterField = InnerData.GetType().GetField("innerData" , BindingFlags .NonPublic | BindingFlags .Instance);
if (InnerOleConverterField != null)
{
Result = InnerOleConverterField.GetValue(InnerData) as System.Runtime.InteropServices.ComTypes.IDataObject ;
}
}
return Result;
}
the line failed to work is <o></o>
OleStream.Read(Buf, Buf.Length, countptr); <o></o>
in method WriteStreamToFile().<o></o>
Previously I had a fix for this issue which is to read the total size of stream using IStream.Stat(), then calculate and get the exact number of byte left for the last segment. but then I got "The method or operation is not implemented." exception for some cases, looks like not all IStream type support the Stat method.<o></o>
I also tried to printed the location of DLL used in COM operation in these methods (system.dll and mscorlib.dll, both are .NET 4 version), and replaced them with the ones on our machine, and it still doesnt work. <o></o>
The thing Im curious about most is why it only happens on that particular clients machine. they are using 64-bit Windows Server Enterprise on Intel Xeon E5450. Really appreciate it if someone can shed some light on this.
View the full article
I met a very wired issue about using IStream.Read() to read data from clipboard. This only happens on several servers of one of our clients. The problem is that when user copying files from local machine and paste to our system in RDP mode, the file is corrupted because random data is appended after the end of file. <o></o>
Our code is reading data from clipboard as IStream, and then read the stream using a buffer of 4KB and write 4KB to a temp file every time. Normally the last segment of the file stream will be less than 4KB so it should just read the number of KB left. This works well for all our clients except one of them. On this particular clients servers, it always cannot identify the end of file and append random data to make a complete 4 KB when reading the last segment, and the file is corrupted.<o></o>
Here is the code we used to get data from clipboard and write to a file. public ZDataObject( object Data)
{
if (Data is DataObject )
{
this.inner = ( DataObject )Data;
}
else
{
this.inner = new DataObject (Data);
}
}
public void SaveStreamToTempFile()
{
System.Windows.Forms. IDataObject dataObject = Clipboard .GetDataObject();
WriteFileContentsFromIStream( new ZDataObject (dataObject), fileName);
}
public static bool WriteFileContentsFromIStream( ZDataObject Data, string FileName, int lindex)
{
STGMEDIUM StgMedium;
FORMATETC FormatEtc;
FormatEtc.cfFormat = (short )DataFormats .GetFormat( "FileContents").Id;
FormatEtc.dwAspect = DVASPECT.DVASPECT_CONTENT;
FormatEtc.lindex = lindex;
FormatEtc.ptd = IntPtr.Zero;
FormatEtc.tymed = TYMED.TYMED_ISTREAM;
bool Result = false;
var OleDataObject = Data.GetInnerOleDataObject();
if (OleDataObject != null)
{
OleDataObject.GetData( ref FormatEtc, out StgMedium);
var OleStream = Marshal .GetObjectForIUnknown(StgMedium.unionmember) as IStream;
try
{
if (OleStream != null)
{
WriteStreamToFile(FileName, OleStream);
Result = true;
}
}
finally
{
if (OleStream != null)
{
Marshal.ReleaseComObject(OleStream);
}
}
}
return Result;
}
protected static bool WriteStreamToFile( string FileName, IStream OleStream)
{
byte[] Buf = new byte[4096];
using ( FileStream FileStr = File .Open(FileName, FileMode .Create, FileAccess .Write))
{
uint count = 0;
IntPtr countptr = Marshal.AllocHGlobal(8);
try
{
Marshal.StructureToPtr(count, countptr, true);
while ( true)
{
OleStream.Read(Buf, Buf.Length, countptr); // SuppressCodeSmell Reason=This is an OLE call that returns through countptr
count = (uint )Marshal .PtrToStructure(countptr, typeof( uint));
if (count == 0)
{
break;
}
FileStr.Write(Buf, 0, (int )count);
}
}
finally
{
Marshal.Release(countptr);
}
}
return true;
}
public System.Runtime.InteropServices.ComTypes. IDataObject GetInnerOleDataObject()
{
System.Runtime.InteropServices.ComTypes. IDataObject Result = null ;
FieldInfo InnerDataField = typeof (DataObject ).GetField( "innerData", BindingFlags .NonPublic | BindingFlags .Instance);
object InnerData = Inner;
while (InnerData != null && InnerData is DataObject )
{
InnerData = InnerDataField.GetValue(InnerData);
}
if (InnerData != null)
{
FieldInfo InnerOleConverterField = InnerData.GetType().GetField("innerData" , BindingFlags .NonPublic | BindingFlags .Instance);
if (InnerOleConverterField != null)
{
Result = InnerOleConverterField.GetValue(InnerData) as System.Runtime.InteropServices.ComTypes.IDataObject ;
}
}
return Result;
}
the line failed to work is <o></o>
OleStream.Read(Buf, Buf.Length, countptr); <o></o>
in method WriteStreamToFile().<o></o>
Previously I had a fix for this issue which is to read the total size of stream using IStream.Stat(), then calculate and get the exact number of byte left for the last segment. but then I got "The method or operation is not implemented." exception for some cases, looks like not all IStream type support the Stat method.<o></o>
I also tried to printed the location of DLL used in COM operation in these methods (system.dll and mscorlib.dll, both are .NET 4 version), and replaced them with the ones on our machine, and it still doesnt work. <o></o>
The thing Im curious about most is why it only happens on that particular clients machine. they are using 64-bit Windows Server Enterprise on Intel Xeon E5450. Really appreciate it if someone can shed some light on this.
View the full article