Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Autoupdate NAV with C#

4.83/5 (34 votes)
3 Apr 2009Public Domain4 min read 106.4K   1.4K  
This article contains a DLL with sample code which is used as a reference in a C# Windows application to import FOB to Navision.

Introduction

This sample application is developed in C# as a library with the project name “ImportFOB”. The DLL “ImportFOB.dll” can be used in a C# Windows application to import the Microsoft Dynamics Navision FOBS into Navision without opening the Navision Object Designer. This sample DLL uses the Microsoft runtime COM Interop services. This DLL has functions which can be used to import and export FOB into Navision. The sample Windows application created is used to demonstrate the import functionality without opening and using the Navision Object Designer.

I had developed “ImportFOB” as a library project which can be used in any project as a reference to import and compile Navision FOBS without opening the Navision Object Designer.

For the demo purpose, I have provided a sample Windows application developed in C# to provide a user interface that anyone can use to import the following FOB types to Microsoft Dynamics Navision.

  1. CodeUnit
  2. Form
  3. Report

We can use “ImportFOB.dll” to also develop our own version management system for Microsoft Dynamics Navision.

This ImportFOB DLL can connect to a Navision Native database or a Navision Native database server.

Scenario 1

If Navision is not installed as a database server and if you are using Navision on a PC for testing this sample application, then it is necessary to run the Navision client and open a sample database. In this case, the sample application will automatically connect to the database and will import the desired FOB to Navision.

Scenario 2

If Navision is installed as a database server, then it is not required to open the Navision client. The only requirement is that the Navision database server must be running. We will create the DLL in Step 1 and the sample application in Step 2. The Sample application will use the DLL as a reference.

Let's begin...

Step 1: Creation of "ImportFOB.dll"

Create a C# project of type Class Library with the namespace IMPORTFOB.NAV. Let us assume that we have named the solution, “ImportFOB”.

Step A

First, we will create the “IObjectDesigner” interface as follows:

C#
namespace IMPORTFOB.NAV
{
    using System;
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes;

    [ComImport, Guid("50000004-0000-1000-0001-0000836BD2D2"),
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IObjectDesigner
    {
        [PreserveSig, DispId(1)]
        int ReadObject([In] int objectType, [In] int objectId, [In] IStream destination);
        [PreserveSig, DispId(2)]
        int ReadObjects([In] string filter, [In] IStream destination);
        [PreserveSig, DispId(3)]
        int WriteObjects([In] IStream source);
        [PreserveSig, DispId(4)]
        int CompileObject([In] int objectType, [In] int objectId);
        [PreserveSig, DispId(5)]
        int CompileObjects([In] string filter);
        [PreserveSig, DispId(6)]
        int GetServerName(out string serverName);
        [PreserveSig, DispId(7)]
        int GetDatabaseName(out string databaseName);
        [PreserveSig, DispId(8)]
        int GetServerType(out int serverType);
        [PreserveSig, DispId(9)]
        int GetCSIDEVersion(out string csideVersion);
        [PreserveSig, DispId(10)]
        int GetApplicationVersion(out string applicationVersion);
        [PreserveSig, DispId(11)]
        int GetCompanyName(out string companyName);
    }
}

The above code clearly specifies the use of COM Interop services. In the Registry, it shows it has fourteen methods. Most of the methods are very simple, and just return a string, and thus they are very easy to implement. For example:

C#
Public string GetDatabaseName ()
{
    string databaseName;
    int num = this._objectDesigner.GetDatabaseName(out databaseName);
    return databaseName;
}

Step B

Now, we will create the StreamSupport class that handles it in .NET:

C#
namespace IMPORTFOB.NAV
{
    using System;
    using System.IO;
    using System.Runtime.InteropServices.ComTypes;

    public class StreamSupport
    {
        public static unsafe IStream ToIStream(Stream stream, 
                             ref IStream comStream)
        {
            byte[] buffer = new byte[stream.Length];
            stream.Read(buffer, 0, buffer.Length);
            uint num = 0;
            IntPtr pcbWritten = new IntPtr((void*) &num);
            comStream.Write(buffer, buffer.Length, pcbWritten);
            return comStream;
        }

        public static unsafe MemoryStream ToMemoryStream(IStream comStream)
        {
            MemoryStream stream = new MemoryStream();
            byte[] pv = new byte[100];
            uint num = 0;

            IntPtr pcbRead = new IntPtr((void*) &num);

            do
            {
                num = 0;
                comStream.Read(pv, pv.Length, pcbRead);
                stream.Write(pv, 0, (int) num);
            }
            while (num > 0);
            return stream;
        }
    }
}

The above code specifies simple stream handling functions to read and write.

Step C

Now, we will create the class “ObjectDesigner” as follows:

C#
namespace IMPORTFOB.NAV
{
    using System;
    using System.Collections;
    using System.Globalization;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes;
    using System.Security;

    public class ObjectDesigner
    {
        private IObjectDesigner _objectDesigner;
        private const string DefaultMonikerName = "!C/SIDE";
        private const string ObjectDesignerGuid = "50000004-0000-1000-0001-0000836BD2D2";

        public ObjectDesigner()
        {
            Guid guid = new Guid("50000004-0000-1000-0001-0000836BD2D2");

            Hashtable runningObjects = GetActiveObjectList(DefaultMonikerName);

            foreach (DictionaryEntry de in runningObjects)
            {
                string progId = de.Key.ToString();
                if (progId.IndexOf("{") != -1)
                {
                    // Convert a class id into a friendly prog Id
                    progId = ConvertClassIdToProgId(de.Key.ToString());
                }
                object getObj = GetActiveObject(progId);
                if (getObj != null)
                {

                    this._objectDesigner = getObj as IObjectDesigner;
                    if (this._objectDesigner == null)
                    {
                        throw new Exception("Could not connect to Dynamics NAV");
                    }
                }
                }
            }

            public void CompileObject(NavObjectType navObjectType, int objectId)
            {
                int result = this._objectDesigner.CompileObject((int) navObjectType,
                    objectId);
                this.ProcessResult(result);
            }

            public void CompileObjects(string filter)
            {
                int result = this._objectDesigner.CompileObjects(filter);
                this.ProcessResult(result);
            }

            [DllImport("ole32.dll")]
            public static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
            [DllImport("OLE32.DLL")]
            public static extern int CreateStreamOnHGlobal(int hGlobalMemHandle,
                bool fDeleteOnRelease, out IStream pOutStm);
            public string GetCompanyName()
            {
                string companyName;
                int num = this._objectDesigner.GetCompanyName(out companyName);
                return companyName;
            }

            public string GetDatabaseName()
            {
                string databaseName;
                int num = this._objectDesigner.GetDatabaseName(out databaseName);
                return databaseName;
            }

            public static Hashtable GetActiveObjectList(string filter)
            {
                Hashtable result = new Hashtable();

                IntPtr numFetched = IntPtr.Zero;
                IRunningObjectTable runningObjectTable;
                IEnumMoniker monikerEnumerator;
                IMoniker[] monikers = new IMoniker[1];

                GetRunningObjectTable(0, out runningObjectTable);
                runningObjectTable.EnumRunning(out monikerEnumerator);
                monikerEnumerator.Reset();
                Console.WriteLine("Select client:");
                int clientNo = 0;
                while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
                {
                    IBindCtx ctx;
                    CreateBindCtx(0, out ctx);

                    string runningObjectName;
                    monikers[0].GetDisplayName(ctx, null, out runningObjectName);
                    System.Guid classId;
                    monikers[0].GetClassID(out classId);
                    object runningObjectVal;
                    runningObjectTable.GetObject(monikers[0], out runningObjectVal);

                    if (runningObjectName.IndexOf(filter) != -1 &&
                        runningObjectName.IndexOf("company") != -1)
                    {
                        clientNo += 1;
                        result[runningObjectName] = runningObjectVal;
                    }
                }

                return result;
            }

            [DllImport("oleaut32.dll", CharSet=CharSet.Unicode)]
            internal static extern int GetErrorInfo(int dwReserved,
                [MarshalAs(UnmanagedType.Interface)] out IErrorInfo ppIErrorInfo);
            public static object GetObjectFromRot(string monikerName, Guid guid)
            {
                IRunningObjectTable prot;
                IEnumMoniker ppenumMoniker;
                IntPtr pceltFetched = IntPtr.Zero;
                IMoniker[] rgelt = new IMoniker[1];
                object ppvResult = null;
                GetRunningObjectTable(0, out prot);
                prot.EnumRunning(out ppenumMoniker);
                ppenumMoniker.Reset();
                while (ppenumMoniker.Next(1, rgelt, pceltFetched) == 0)
                {
                    IBindCtx ppbc;
                    string ppszDisplayName;
                    CreateBindCtx(0, out ppbc);
                    rgelt[0].GetDisplayName(ppbc, null, out ppszDisplayName);
                    if (!(!ppszDisplayName.StartsWith(monikerName) || 
                        ppszDisplayName.Equals(monikerName)))
                    {
                        rgelt[0].BindToObject(ppbc, null, ref guid, out ppvResult);
                        return ppvResult;
                    }
                }
                return ppvResult;
            }
            public static object GetActiveObject(string progId)
            {
                // Convert the prog id into a class id
                string classId = ConvertProgIdToClassId(progId);

                IRunningObjectTable prot = null;
                IEnumMoniker pMonkEnum = null;
                try
                {
                    IntPtr Fetched = IntPtr.Zero;
                    // Open the running objects table.
                    GetRunningObjectTable(0, out prot);
                    prot.EnumRunning(out pMonkEnum);
                    pMonkEnum.Reset();
                    IMoniker[] pmon = new IMoniker[1];

                    // Iterate through the results
                    while (pMonkEnum.Next(1, pmon, Fetched) == 0)
                    {
                        IBindCtx pCtx;
                        CreateBindCtx(0, out pCtx);
                        string displayName;
                        pmon[0].GetDisplayName(pCtx, null, out displayName);
                        Marshal.ReleaseComObject(pCtx);
                        if (displayName.IndexOf(classId) != -1)
                        {
                            // Return the matching object
                            object objReturnObject;
                            prot.GetObject(pmon[0], out objReturnObject);
                            return objReturnObject;
                        }
                    }
                    return null;
                }
                finally
                {
                    // Free resources
                    if (prot != null)
                        Marshal.ReleaseComObject(prot);
                    if (pMonkEnum != null)
                        Marshal.ReleaseComObject(pMonkEnum);
                }
            }
            public static Hashtable GetRunningObjectTable()
            {
                IRunningObjectTable prot;
                IEnumMoniker ppenumMoniker;
                IntPtr pceltFetched = IntPtr.Zero;
                Hashtable hashtable = new Hashtable();
                IMoniker[] rgelt = new IMoniker[1];
                GetRunningObjectTable(0, out prot);
                prot.EnumRunning(out ppenumMoniker);
                ppenumMoniker.Reset();
                while (ppenumMoniker.Next(1, rgelt, pceltFetched) == 0)
                {
                    IBindCtx ppbc;
                    string ppszDisplayName;
                    object ppunkObject;
                    CreateBindCtx(0, out ppbc);
                    rgelt[0].GetDisplayName(ppbc, null, out ppszDisplayName);
                    prot.GetObject(rgelt[0], out ppunkObject);
                    hashtable[ppszDisplayName] = ppunkObject;
                }
                return hashtable;
            }
            [DllImport("ole32.dll", PreserveSig = false)]
            private static extern void CLSIDFromProgIDEx(
                [MarshalAs(UnmanagedType.LPWStr)] string progId, out Guid clsid);

            [DllImport("ole32.dll", PreserveSig = false)]
            private static extern void CLSIDFromProgID(
                [MarshalAs(UnmanagedType.LPWStr)] string progId, out Guid clsid);
            public static string ConvertProgIdToClassId(string progID)
            {
                Guid testGuid;
                try
                {
                    CLSIDFromProgIDEx(progID, out testGuid);
                }
                catch
                {
                    try
                    {
                        CLSIDFromProgID(progID, out testGuid);
                    }
                    catch
                    {
                        return progID;
                    }
                }
                return testGuid.ToString().ToUpper();
            }

            [DllImport("ole32.dll")]
            private static extern int ProgIDFromCLSID([In()]ref Guid clsid,
                [MarshalAs(UnmanagedType.LPWStr)]out string lplpszProgID);
            public static string ConvertClassIdToProgId(string classID)
            {
                Guid testGuid = new Guid(classID.Replace("!", ""));
                string progId = null;
                try
                {
                    ProgIDFromCLSID(ref testGuid, out progId);
                }
                catch (Exception)
                {
                    return null;
                }
                return progId;
            }
            [DllImport("ole32.dll")]
            public static extern void GetRunningObjectTable(int reserved,
                out IRunningObjectTable prot);
            public string GetServerName()
            {
                string serverName;
                int num = this._objectDesigner.GetServerName(out serverName);
                if (serverName != null)
                    return serverName;
                else
                    return string.Empty;
            }
            private void ProcessResult(int result)
            {
                if (result != 0)
                {
                    IErrorInfo ppIErrorInfo = null;
                    GetErrorInfo(0, out ppIErrorInfo);
                    string pBstrDescription = string.Empty;
                    if (ppIErrorInfo != null)
                    {
                        ppIErrorInfo.GetDescription(out pBstrDescription);
                    }
                    string message = string.Format(CultureInfo.CurrentCulture,
                        "Method returned an error. HRESULT = 0x{0:X8}",
                        new object[] { result });
                    if (pBstrDescription != string.Empty)
                    {
                        message = message + " : " + pBstrDescription;
                    }
                    throw new Exception(message);
                }
            }
            public MemoryStream ReadObjectToStream(NavObjectType navObjectType,
                int objectId)
            {
                IStream pOutStm = null;
                CreateStreamOnHGlobal(0, true, out pOutStm);
                int result = this._objectDesigner.ReadObject((int) navObjectType,
                     objectId, pOutStm);
                this.ProcessResult(result);
                return this.ToMemoryStream(pOutStm);
            }
            private unsafe IStream ToIStream(Stream stream)
            {
                byte[] buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);
                uint num = 0;
                IntPtr pcbWritten = new IntPtr((void*) &num);
                IStream pOutStm = null;
                CreateStreamOnHGlobal(0, true, out pOutStm);
                pOutStm.Write(buffer, buffer.Length, pcbWritten);
                pOutStm.Seek((long) 0, 0, IntPtr.Zero);
                return pOutStm;
            }
            private unsafe MemoryStream ToMemoryStream(IStream comStream)
            {
                MemoryStream stream = new MemoryStream();
                byte[] pv = new byte[100];
                uint num = 0;
                IntPtr pcbRead = new IntPtr((void*) &num);
                comStream.Seek((long) 0, 0, IntPtr.Zero);
                do
                {
                    num = 0;
                    comStream.Read(pv, pv.Length, pcbRead);
                    stream.Write(pv, 0, (int) num);
                }
                while (num > 0);
                return stream;
            }
            public void WriteObjectFromStream(Stream stream)
            {
                IStream source = this.ToIStream(stream);
                int result = this._objectDesigner.WriteObjects(source);
                this.ProcessResult(result);
            }
            [ComImport, SuppressUnmanagedCodeSecurity, Guid(
                  "1CF2B120-547D-101B-8E65-08002B2BD119"),
                  InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            internal interface IErrorInfo
            {
                [PreserveSig]
                int GetGUID();
                [PreserveSig]
                int GetSource([MarshalAs(UnmanagedType.BStr)] out string pBstrSource);
                [PreserveSig]
                int GetDescription(
                    [MarshalAs(UnmanagedType.BStr)] out string pBstrDescription);
            }
        }
    }

In the above class, the various functions are created to get the connection for running the CSIDE object. After establishing the connection, it acquires the Microsoft Dynamics Navision Object Designer. The CompileObject function is created to compile the imported Navision FOB.

Step D

Now, we will declare an enum which will contain the list for the type of objects in Navision that needs to be imported.

C#
Namespace IMPORTFOB.NAV
{
    using System;

    public enum NavObjectType
    {
        Codeunit = 5,
        Dataport = 4,
        Form = 2,
        Report = 3,
        Table = 1

    }
}

We have finished the creation of the “ImportFob” class Library. We will now build the solution.

Step 2: Create the sample application which will call “ImportFOB.dll”

Let's call the sample application FobNameID. Create a C# Windows project, FobNameID. Name the namespace “FobNameID”.

Step A

Add a reference to “ImportFOB.dll” to this project. Go to References in Solution Explorer and select Add Reference upon right click. Browse the path for “ImportFOB.dll” and add it to the FobNameID project.

After adding the DLL, declare the following:

C#
using IMPORTFOB.NAV;

Step B

Rename the Program class to FOBImport and create the function ImportFobtoNav with three parameters, as follows:

C#
String FobName, int objecttype, int objid

Create the “ImportFobtoNav” function as follows:

C#
public void ImportFobtoNav(String FobName, int objecttype, int objid)
{
    ObjectDesigner nav = new ObjectDesigner();
    MemoryStream memStream = new MemoryStream();
    // Create the data to write to the stream.
    FileStream fs = File.OpenRead(FobName);
    byte[] firstString = new byte[fs.Length];
    fs.Read(firstString, 0, firstString.Length);
    memStream.Write(firstString, 0, firstString.Length);
    memStream.Seek(0, SeekOrigin.Begin);
    nav.WriteObjectFromStream(memStream);

    if ((objecttype) == 2)
    {
        nav.CompileObject(NavObjectType.Form, objid);
    }
    if ((objecttype) == 5)
    {
        nav.CompileObject(NavObjectType.Codeunit, objid);
    }
    if ((objecttype) == 3)
    {
        nav.CompileObject(NavObjectType.Report, objid);
    }
    fs.Close();
    memStream.Close();
}

This function accepts three parameters: the FOB name, object type (CodeUnit, Form, Report) and the object ID. Inside the function, an instance of ObjectDesigner is created as nav to call the WriteObjectFromStream method from “ImportFOB.DLL”.

The CompileObject method is also called from ImportFOB.DLL to compile the FOB in Navision after importing it. Stream handling is done to read and write the FOB.

Note: To import FOBS to Navision, it is requires that FOBS should be available in the Debug folder of the sample Windows application.

Step C

Create a form “ImportFOB”. Create the following controls in the form:

  1. Label control titled FOB Name and Text control named txtfobname.
  2. Label control titled Object ID and Text control named txtobjid.
  3. Label control titled Object Type and ListBox control named lstobjtype.
  4. Create the following items in the ListBox control:

    1. CodeUnit
    2. Form
    3. Report
  5. Button control captioned Import and named btnImport.
  6. Button control captioned Close and named btnclose.

Step D

Write the following code on the Click event of the Import button:

C#
private void btnImport_Click(object sender, EventArgs e)
{
    FobImport fobimp = new FobImport();
    try
    {
        if (lstobjtype.Text == "Codeunit")
        {
            fobimp.ImportFobtoNav(txtfobname.Text + ".txt", 5,
                Convert.ToInt32(txtobjid.Text));
        }

        if (lstobjtype.Text == "Form")
        {
            fobimp.ImportFobtoNav(txtfobname.Text + ".txt", 2,
                Convert.ToInt32(txtobjid.Text));
        }
        if (lstobjtype.Text == "Report")
        {
            fobimp.ImportFobtoNav(txtfobname.Text + ".txt", 3,
                Convert.ToInt32(txtobjid.Text));
        }
        MessageBox.Show("Fob Imported Successfully");
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Create an object of the FOBImport class created in this Windows application. Please note that “Lstobjtype” is as ListBox with the Items CodeUnit, Form, and Report. Depending on the enum values for the object in “ImportFOB.dll”, we call the “ImportFobNav” function to import FOB to Navision. The ImportFobNav function is created on Step B under Step 2.

Finally, run it and enjoy!

c_windowapplication.JPG

Run the sample Windows application “FobNameID”. Type in the FOB name, object type, and object ID. Please note that the FOB name should be the name of the FOB file which is located in the Debug directory of the Windows application “FobNameID”.

History

  • 1.0.0.0
    • First release version.

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication