Returning IWICStream / IStream from unmanaged C++ DLL to managed C# and reading it -
within c# program receive image data (probably in form of istream
), returned function imported unmanaged c++ dll.
i have read several similar questions , msdn docs on general topic far have been unable figure out complete working solution.
c++ function exported consumption in managed c#:-
extern "c" __declspec(dllexport) istream* getimage(){ iwicbitmap *pbitmap = null; //... code emitted clarity //... bitmap creation , direct2d image manipulation //... iwicstream *pistream = null; istream *stream; createstreamonhglobal(null, true, &stream); hresult hr = pistream->initializefromistream(stream); //... pbmpencoder iwicbitmapencoder, pibitmapframe iwicbitmapframeencode //... pfactory iwicimagingfactory hr = pfactory->createencoder(guid_containerformattiff, null, &pbmpencoder); hr = pbmpencoder->initialize(pistream, wicbitmapencodernocache); //... hr = pbmpencoder->createnewframe(&pibitmapframe, &ppropertybag); //.. pibitmapframe->writesource(pbitmap, &rect); //... pibitmapframe->commit(); pbmpencoder->commit(); return stream; }
i have emitted code sake of clarity. important iwicbitmap
encoded .tiff
iwicstream
. iwicstream
initialized istream
. function returns *istream
.
c# imported function declaration:-
using system.runtime.interopservices.comtypes.istream; [dllimport(@"d:\mydlls\getimagedll.dll", callingconvention = callingconvention.cdecl)] public static extern istream getimage();
c# code consuming getimage()
function , attempting read istream
:-
public actionresult deliverimage() { istream stream = getimage(); unsafe { byte[] filebytes = new byte[4000]; int bytesread = 0; int* ptr = &bytesread; stream.read(filebytes, filebytes.length, (intptr)ptr); return file(filebytes, system.net.mime.mediatypenames.image.tiff, "image.tiff"); } }
there 3 things need with.
currently c++ function returning
*istream
although imported c# declaration hassystem.runtime.interopservices.comtypes.istream
return type.istream
pointer ,system.runtime.interopservices.comtypes.istream
not match. have tried returning istream object function intellisense warns 'function returning abstract class not allowed'. how canistream
returned , correctly marshalled managed c#system.runtime.interopservices.comtypes.istream
?when reading
istream
in c#, how can length of image data in stream discerned read buffer can set correct length?what correct way release istream in c++ or c# or both there isn't memory leak? can stream released in c++ returned or there need second function exported c# called after c# has finished using stream?
thank help!
your current code return istream*
works fine. here simple demonstration shows works fine:
c++
extern "c" __declspec(dllexport) istream* __stdcall getstream() { istream *stream; createstreamonhglobal(null, true, &stream); int = 42; stream->write(&i, sizeof(int), null); return stream; }
c#
[dllimport(dllname)] private static extern istream getstream(); .... istream stream = getstream(); intptr newposition = marshal.allochglobal(sizeof(long)); stream.seek(0, stream_seek_end, newposition); console.writeline(marshal.readint64(newposition)); stream.seek(0, stream_seek_set, intptr.zero); byte[] bytes = new byte[4]; stream.read(bytes, 4, intptr.zero); console.writeline(bitconverter.toint32(bytes, 0));
how find size of stream? code above shows how using seek
method. you'd want wrap up. instance:
static long getstreamsize(istream stream) { intptr ptr = marshal.alloccotaskmem(sizeof(long)); try { stream.seek(0, stream_seek_cur, ptr); long pos = marshal.readint64(ptr); stream.seek(0, stream_seek_end, ptr); long size = marshal.readint64(ptr); stream.seek(pos, stream_seek_set, intptr.zero); return size; } { marshal.freecotaskmem(ptr); } }
or bit more simple unsafe code if prefer:
unsafe static long getstreamsize(istream stream) { long pos; stream.seek(0, stream_seek_cur, new intptr(&pos)); long size; stream.seek(0, stream_seek_end, new intptr(&size)); stream.seek(pos, stream_seek_set, intptr.zero); return size; }
finally, ask how release istream
interface in c#. don't need to. c# compiler takes care of reference counting automatically. inserts appropriate calls addref
, release
.
Comments
Post a Comment