Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
Mono organizations on
GitHub to continue tracking issues. Bugzilla will remain
available for reference in read-only mode. We will continue to work
on open Bugzilla bugs, copy them to the new locations
as needed for follow-up, and add the new items under Related
Our sincere thanks to everyone who has contributed on this bug
tracker over the years. Thanks also for your understanding as we
make these adjustments and improvements for the future.
Please create a new report on
GitHub or Developer Community with
your current version information, steps to reproduce, and relevant error
messages or log files if you are hitting an issue that looks similar to
this resolved bug and you do not yet see a matching new report.
I encountered following behavior and it might be wrong:
There is a Stream object. A managed callback function which reads data from the Stream object is passed to unmanaged function. Unmanaged function then calls the managed callback several times for getting data from the stream.
The data from the stream are read and stream position is changed correctly.
But when the unmanaged code calls the callback again, the position of the stream is lost. Position is zero and should be greater than zero because it was already read from the stream. So the reading itself starts from the beginning again.
It seems that stream is somehow reset or created again. I don't understand. It might be a bug in Mono runtime or Stream or marshaling.
Stream is hold in a static field of the class where the callback function is defined. It cannot be passed directly to the callback function because there is IntPtr parametr and Stream is object. Mono runtime can't marshall an object to an IntPtr and back. Also pinned gc handle is not possible to used because Stream is complex type and cannot be serialized. I don't know about other ways of passing object to IntPtr argument so I pass the Stream object in static field (I know that it isn't good for multithreaded apps).
The callback delegate:
private delegate Cairo.Status cairo_read_func_t(
IntPtr closure, IntPtr data, int length);
The unmanaged function declaration:
private static extern IntPtr cairo_image_surface_create_from_png_stream(
cairo_read_func_t read_func, IntPtr closure);
The static field:
private static Stream stream_hack;
Method that calls unmanaged cairo_image_surface_create_from_png_stream:
public static Cairo.ImageSurface CreateImageSurfaceFromPngStream(Stream stream)
// HACK: stream is passed to callback through static field
// it can't be passed as closure parameter in cairo_image_surface_create_from_png_stream
// because 1. object/IntPtr marshaling doesn't work, 2. gc handle pinned object is too complex and I don't know how to do it in other way currently
stream_hack = stream;
IntPtr handle = cairo_image_surface_create_from_png_stream(StreamFeederFce, IntPtr.Zero); // here, Cairo will call StreamFeederFce several times
The managed callback method:
public static Cairo.Status StreamFeederFce(IntPtr closure, IntPtr data, int length)
byte mdata = new byte[length];
// stream_hack.Position == 0 - every time when StreamFeederFce is called (why the position is reset? it reads the beginning of the stream again and again)
int read = stream_hack.Read(mdata, 0, length);
// stream_hack.Position == length - after Read call position is 8 which is correct, but it is not remembered for next call of StreamFeederFce, why?
if (read != length) return Cairo.Status.ReadError;
Marshal.Copy(mdata, 0, data, length);
Created attachment 2171 [details]
Mmm, I've found out that it is not the problem in Mono.
I thought that the callback is called more times, but it isn't. I loaded more images and the callback is called only once for every image.
Cairo calls the callback only once, read 8 bytes and returns empty ImageSurface (width 0, height 0, etc.).
So the problem migth be in Cairo or in the data passing. The same data are loaded correctly from the file by ImageSurface constructor, but only 8 bytes are read from stream by calling cairo_image_surface_create_from_png_stream.
If you can still reproduce with latest mono version, please feel free to reopen the bug. Thank you.