Tomer Gabel's annoying spot on the 'net RSS 2.0
# Sunday, December 10, 2006

Quick link: To download the wrapper classes click here

While working on a large application targetting the .NET Compact Framework 2.0 I realized that I'll need to feed some native code (specifically, the XSLT processor in MSXML 3.0 SP1) with an IStream implementation.

Articles about interoperating with unmanaged code in the CF are not exactly abundant; to save you the time I spent on incorrect and/or conflicting research, here's the bottom line:

  • There is no Managed C/C++ for .NET Compact Framework 2.0. To some this may be old news, but you should really pay attention to this point if you're going to do any serious development against CF. 2.0 adds support for managed COM/ActiveX interop, but otherwise you're completely stuck with P/Invoke.
  • Although it's not immediately obvious, CF 2.0 does support exposing managed classes via COM.
  • The CF is missing some usually-minor classes from the BCL; in this case I was missing System.Runtime.InteropServices.ComTypes.IStream. Annoying but easy to work around.
  • Finally, as an aside, MSXML 3.0 SP1 for Windows Mobile does not support the IXslTemplate and IXslProcessor interfaces, meaning that MSXML 3.0's already lackluster performance in XSLT transformations is further hindered by not being able to cache the interpreted stylesheets. This means that, if you use XSLT, your application will not scale. I was not initially aware of this issue, so I hope our data sets are small enough to handle this, or I may yet come to regret the decision to use XSLT in this project.

I managed to save quite a bit of time by leveraging Oliver Sturm's work, which was originally intended for the desktop. Since the CF is missing a whole bunch of minor classes, the managed definition of IStream included, I originally mucked about with midl trying to generate these definitions from the .IDL files. After this proved to be a genuine chore, I just ripped the definitions straight out of the .NET Framework 2.0 assemblies with the ever-useful Reflector.

You can download the class file here. If you use this it would really be cool if you could drop me an e-mail, and I bet Oliver would be equally appreciative. Enjoy!

Sunday, December 10, 2006 3:31:16 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [12] -
Development | Compact Framework
Tuesday, April 07, 2009 1:08:02 AM (Jerusalem Standard Time, UTC+02:00)
Hi

I have a dll written in C, and there is a parameter of type IStream** retval

Now, I would like to use this parameter from a C# application, I defined it in this way:
ref System.Runtime.InteropServices.ComTypes.IStream retval

so do you think the above line is Ok or I have to use the IStream class you wrote. Is so, how can I use it ?
thanks
Khayralla
Tuesday, April 07, 2009 10:21:42 AM (Jerusalem Standard Time, UTC+02:00)
The prototype you specified seems to indicate the C function takes an "out" parameter which returns an IStream? If that's the case and I remember correctly, you should define retval as an out parameter ("out" instead of "ref" in your example).

Oliver's wrapper (and my version as well) is actually intended for the reverse direction: providing a read-only IStream implementation over .NET streams. You'll need to write another wrapper class to handle the other direction, i.e. wrapping a COM IStream with a .NET stream.
Friday, April 10, 2009 11:55:42 PM (Jerusalem Standard Time, UTC+02:00)
thanks, it is working now.
Wednesday, August 12, 2009 9:11:15 AM (Jerusalem Standard Time, UTC+02:00)
Great work : http://www.tomergabel.com/SearchView.aspx?q=istream

I just cannot seem to understand how it works.

All I want to do is take a standard .net memory stream and pass it to your wrapper so that it will return a istream object which i can then use.

is this possible with your wrapper?
Wednesday, August 12, 2009 11:10:18 AM (Jerusalem Standard Time, UTC+02:00)
You should just pass your stream object to the constructor, e.g. new IStreamWrapper( new MemoryStream(...) ). The IStreamWrapper object itself implements IStream, so you can pass it freely to methods taking IStream.
Wednesday, August 12, 2009 1:17:24 PM (Jerusalem Standard Time, UTC+02:00)


code:
COMOBJECT.Load() - requires a iStream

Tried your suggestion:
COMOBJECT.Load(new TomerGabel.Examples.IStreamWrapper (oMemoryStreamObject)))

Here is the error I get:

Error 5 Argument '1': cannot convert from 'TomerGabel.Examples.IStreamWrapper' to 'System.Runtime.InteropServices.ComTypes.IStream' 568 60

I need to make sure that your wrapper returns a pure
'System.Runtime.InteropServices.ComTypes.IStream' so that the com object can use it properly.
Wednesday, August 12, 2009 1:30:20 PM (Jerusalem Standard Time, UTC+02:00)
I think I see the problem. This wrapper was adapted for the .NET Compact Framework, and contains an IStream declaration different from that under InteropServices.ComTypes. You should get rid of it and ensure IStreamWrapper derives from the same type, i.e. ComTypes.IStream. Assuming no significant differences between the canonical .NET declaration for IStream and the one I included you should have no problem.
Wednesday, August 12, 2009 2:02:58 PM (Jerusalem Standard Time, UTC+02:00)

when I made the change it gives the following error:

Error 3 'TomerGabel.Examples.IStreamWrapper' does not implement interface member 'System.Runtime.InteropServices.ComTypes.IStream.Stat(out System.Runtime.InteropServices.ComTypes.STATSTG, int)'


There is one :
void IStream.Stat(out STATSTG pstatstg, int grfStatFlag)
{
pstatstg = new STATSTG();
}


If I can resolve this one it will probably compile.
Wednesday, August 12, 2009 3:15:12 PM (Jerusalem Standard Time, UTC+02:00)
Same thing with STATSTG -- it's a type that's defined in the full framework but not in CF. Just remove the type definition (and probably any other type that results in the same error).
Friday, August 14, 2009 7:54:01 AM (Jerusalem Standard Time, UTC+02:00)
The entire error lay in the .position

When reading the stream into memory it would set the position to the end of the file.

When I tried to read it with your object it couldn't because it was already at the end of the stream so it would show an error.

All I had to do was set the position = 0 before running it.

Your wrapper is really cool!
Wednesday, December 08, 2010 10:54:17 AM (Jerusalem Standard Time, UTC+02:00)
Please do not copy 64 bits into the pdbWritten and pcbRead pointers of Read() and Write() - these are ULONG values, which are unsigned 32 bit (even in Win64). This might cause unexpected behaviour (memory overwrites on the stack).

And you might consider to write the cbSize entry with the "Length()" result of the Stream. It might come handy for programs using it ;)

Christian
Wednesday, December 08, 2010 4:07:24 PM (Jerusalem Standard Time, UTC+02:00)
Heh, I'm amazed this is still useful to anyone :-) Still no built-in support for this stuff, even years after?
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Live Comment Preview
Me!
Send mail to the author(s) Be afraid.
Archive
<May 2013>
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
All Content © 2013, Tomer Gabel
Based on the Business theme for dasBlog created by Christoph De Baene (delarou)