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.

  1. currently c++ function returning *istream although imported c# declaration has system.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 can istream returned , correctly marshalled managed c# system.runtime.interopservices.comtypes.istream?

  2. when reading istream in c#, how can length of image data in stream discerned read buffer can set correct length?

  3. 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

Popular posts from this blog

PHPMotion implementation - URL based videos (Hosted on separate location) -

javascript - Using Windows Media Player as video fallback for video tag -

c# - Unity IoC Lifetime per HttpRequest for UserStore -