Access Navision Stream From DotNet

AdministratorAdministrator Member, Moderator, Administrator Posts: 2,500
edited 2008-10-03 in Download section
Access Navision Stream From DotNet
Simple example how to pass Navision stream (InStream/OutStream) to COM DLL written in .NET (Framework 2.0).

VS2005 solution and sample Navision object are included in archive. Current example reading picture from Item.Picture field and saving it to disk.

Thank you everybody who kicked my in right direction (wakestar, chrido, TonyH and Reflector (tool) )

http://www.mibuso.com/dlinfo.asp?FileID=776

Discuss this download here.

Comments

  • akraehenbuehlakraehenbuehl Member Posts: 4
    Thank you for this really great and useful solution. I can use it as basis for the idea in one of my current project.

    I've just one small annotation: Close the Streamwriter before return the flag1 value. So you can access the file with an extern process, otherwise first Navision has to be closed. Because the file handle will not be released.
    public bool LoadFromNavision([In, MarshalAs(UnmanagedType.AsAny)] object COMStream)
            {
                bool flag1 = true;
                Stream stream1 = new MemoryStream();
                byte[] buffer1 = new byte[0xafc8];
                this.rwBytes = Marshal.AllocHGlobal(4);
                IStream COMStream1 = COMStream as IStream;
                FileStream writer = new FileStream(@"C:\stream.dat", FileMode.CreateNew);
                int _rwBytes = 0;
    
                do
                {
                    COMStream1.Read(buffer1, 0xafc8, this.rwBytes);
                    _rwBytes = Marshal.ReadInt32(this.rwBytes);
                    writer.Write(buffer1, 0, _rwBytes);
                }
                while (_rwBytes > 0);
                Marshal.FreeHGlobal(this.rwBytes);
                writer.Close();
                return flag1;
            }
    

    Greets from Switzerland
    Andy
  • toortoor Member Posts: 52
    Thanks for the very nice sample.

    Does anyone have an example on how to pass a stream back to navision?

    I wan't to pass the string representation of a msxml.xmldom to a .NET-Com-Controller and back to navision by using the stream objects in navision.

    Why do you use 0xafc8 in byte[] buffer1 = new byte[0xafc8];?

    I see that you can't get the length of the IStream object, so you have to initialize the byte array with a assumed maximum, but why 0xafc8?

    thanks & best regards
    tobias
  • AdministratorAdministrator Member, Moderator, Administrator Posts: 2,500
    Access Navision Stream From DotNet
    Simple example how to pass Navision stream (InStream/OutStream) to COM DLL written in .NET (Framework 2.0).

    VS2005 solution and sample Navision object are included in archive. Current example reading picture from Item.Picture field and saving it to disk.

    Thank you everybody who kicked my in right direction (wakestar, chrido, TonyH and Reflector (tool) )

    Update 21.12.2006:
    + Added code to import data into NAV.

    http://www.mibuso.com/dlinfo.asp?FileID=776

    Discuss this download here.
  • AteAte Member Posts: 2
    Hi.
    Thanks for that sample.
    I am making a DLL to convert any image format to BMP format to allow Navision show that.
    The DLL have 2 functions, the first one get data from a Navision Stream and save it to a Bitmap variable with the original format, and the second return this Bitmap in BMP format to Navision Stream.
    The first function works correctly and save the image, but the second one I do not obtain that it gives back stream directly, that I must pass it to a temporary BMP file and read it and pass it to a stream.
    This is the code of the second function:
    		public void GetIMGBuffer([Out, MarshalAs(UnmanagedType.AsAny)] object COMStream)
    		{
                Stream stream1 = new MemoryStream();
                
                System.Drawing.Imaging.ImageFormat BMPformat;
                BMPformat = System.Drawing.Imaging.ImageFormat.Bmp;
                BMPData.Save(stream1, BMPformat);
                BMPData.Dispose();
                BMPData = null;
                
                IStream COMStream1 = COMStream as IStream;
                this.rwBytes = Marshal.AllocHGlobal(4);
                byte[] buffer1 = new byte[0xafc8];
                //IStream COMStream = new IStream();
                
                int _rwBytes = 0xafc8;
                int bytesRead = 0;
                do
                {
                    bytesRead = stream1.Read(buffer1, 0, _rwBytes);
                    Marshal.WriteInt32(this.rwBytes, bytesRead);
                    COMStream1.Write(buffer1, bytesRead, this.rwBytes);
                }
                while (bytesRead > 0);
                //COMStream1.Commit(0);
                stream1.Dispose();
                Marshal.FreeHGlobal(this.rwBytes);
            }
    

    And this is the code with temporary file:
    		public void GetIMGBuffer([Out, MarshalAs(UnmanagedType.AsAny)] object COMStream)
    		{
                Stream stream1 = new MemoryStream();
                
                System.Drawing.Imaging.ImageFormat BMPformat;
                BMPformat = System.Drawing.Imaging.ImageFormat.Bmp;
                BMPData.Save(stream1, BMPformat);
                BMPData.Save("C:/export.bmp", BMPformat);
                BMPData.Dispose();
                BMPData = null;
                
                IStream COMStream1 = COMStream as IStream;
                this.rwBytes = Marshal.AllocHGlobal(4);
                byte[] buffer1 = new byte[0xafc8];
                FileStream reader = new FileStream("C:/export.bmp", FileMode.Open);
                //IStream COMStream = new IStream();
                
                int _rwBytes = 0xafc8;
                int bytesRead = 0;
                do
                {
                    bytesRead = reader.Read(buffer1, 0, _rwBytes);
                    //bytesRead = stream1.Read(buffer1, 0, _rwBytes);
                    Marshal.WriteInt32(this.rwBytes, bytesRead);
                    COMStream1.Write(buffer1, bytesRead, this.rwBytes);
                }
                while (bytesRead > 0);
                //COMStream1.Commit(0);
                reader.Close();
                reader.Dispose();
                Marshal.FreeHGlobal(this.rwBytes);
                System.IO.File.Delete("C:/export.bmp");
            }
    

    I think that I am reading bad stream.
    Thanks for all.

    PD: I can upload the VS2005 project to you if needed. I don't know if if this is the correct place to put it.
    PD2: sorry for my bad English.
  • Bastian_SelonkeBastian_Selonke Member Posts: 5
    Hey guys,
    I've been messing around with getting this to work, but without any effort. It seems like there is no way to use the IStream interface out of .NET :(
    The sample does not compile for me either. Here is what the linker says:
    Warning: Type contains [MarshalAs(AsAny)], which is only valid for PInvoke. The MarshalAs directive was ignored.

    When trying to use the IStream interface directly, it tells me the following:
    Warning: Type library exporter could not find the type library for 'System.Runtime.InteropServices.ComTypes.IStream'. IUnknown was substituted for the interface.

    I use a fresh installation of VS 2005 Professional with SP1 (?) extension. According to Navisions Application Designers Guide, Navision is able to use VT_STREAM (with is IStream) and maps it to its In-/Outstream types in C/SIDE. To be honest, i think this sample does not work at all, because it uses VARIANT instead of IStream.

    There must be a working way to use the IStream interface out of C#.NET, but how? Any ideas?
  • gerdhuebnergerdhuebner Member Posts: 155
    ...To be honest, i think this sample does not work at all, because ...

    To be true, I tried it and it worked for me. Ok, I did some minor (but may be irrelevant) changes:
    I'm running VS2005 .NET express edition and Navision 5.0.
    The project compiled as downloaded except the warnings you mentioned and an unused int variable "bytes", which I deleted. As the compiler said, the MarshalAs directive is ignored, I deleted it, too and the project finally compiled without any warnings. To make things easy, I checked "Register for COM Interop" in the project properties and what shall I say, it worked promptly (I tested only the LoadFromNavision method since it is the only one I will need for the moment...) -
    Many Thanks to Alexey for this very usefull sample piece of code.
  • jony_kwa888jony_kwa888 Member Posts: 9
    Hi all,

    I'm using the code given in NAV4.03. It works great. But the problem is: it crash randomly. Sometimes it success; somtimes just memory error.
    Sometimes NAV error saying cannot read from empty BLOB.

    any one has the some experience?
  • chridochrido Member Posts: 12
    I'm also using this since a year or so in production without crash. The component is something like a http server and raises data into Navision, in peak hours about ~200 requests per minute.

    I had also crashes. You have to be very careful with multiple threads. I have a queue before raising the data into Navision as an event. Then I'm waiting till the event has finished and i get the returnvalue, manual garbage collection, waiting additional a few ticks and then raise the next blob into Navision.

    With Navision 3.70a i never had these problems.

    ... I personally see this solution as a hack and under normal circumstances I wouldn't use it in production, but their is currently no better solution which provides a similar performance.
  • vandeninivandenini Member Posts: 2
    Just a small notice.

    If you receive a very general error message "Object reference not set to an instance of an object", be sure to check whether you InStream in Navision is created properly.
    Hope this saves you a couple of hours...
Sign In or Register to comment.