Recently I investigated the INSApplication interface and discovered some nice possiblities. Through the INSRec interface you can retrieve the value of any field of the record, which is shown in the client's currently active form (may be with INSEnumCallback it is possible to step through all open forms, but I 've got no idea how...). As there is no typelib information available, you have to implement the interfaces in the usual way (be aware that the names of the methods are not official in any way) - here is the declaration for C#:
[ComImport, Guid("50000004-0000-1000-0001-0000836BD2D2"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface INSObjectDesigner
{
int ReadObject([In] int objectType, [In] int objectId, [In] IStream destination);
int ReadObjects([In] String filter, [In] IStream destination);
int WriteObjects([In] IStream source);
int CompileObject([In] int objectType, [In] int objectId);
int CompileObjects([In] String filter);
int GetServerName(out String serverName);
int GetDatabaseName(out String databaseName); // gets database folder and name
int GetServerType(out int serverType); // 1=SQL, 2=Classic
int GetCSIDEVersion(out String csideVersion); // "DE 5.0 SP1", "DE 6.00", etc.
int GetApplicationVersion(out String applicationVersion); // "DE Dynamics NAV 5.0 SP1", "DE Dynamics NAV 6.0", etc.
int GetCompanyName(out String companyName);
}
[ComImport, Guid("50000004-0000-1000-0011-0000836BD2D2"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface INSCallbackEnum
{
int proc3([In,MarshalAs(UnmanagedType.Interface)] INSRec a);
int proc4([In] int a, [In] string b, [In] string c);
int proc5([In] int a, [In] string b);
int proc6([In] int a, [In] string b);
int proc7([In] int a, [In] string b, [In] string c, [In] string d, [In] int e, [In] int f);
}
[ComImport, Guid("50000004-0000-1000-0007-0000836BD2D2"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface INSRec
{
int proc3([In] int a, [In] String b, [In] int c);
int GetFieldValue([In] int a, out String b);
int proc5([In,MarshalAs(UnmanagedType.Interface)] INSCallbackEnum a);
}
[ComImport, Guid("50000004-0000-1000-0006-0000836BD2D2"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface INSTable
{
int proc3([In, MarshalAs(UnmanagedType.Interface)] INSRec a);
int proc4([In, MarshalAs(UnmanagedType.Interface)] INSRec a);
int proc5([In, MarshalAs(UnmanagedType.Interface)] INSRec a);
int proc6([Out, MarshalAs(UnmanagedType.Interface)] out INSRec a);
int proc7([In] int a, [In] string b);
int proc8([In,MarshalAs(UnmanagedType.Interface)] INSCallbackEnum a);
int proc9([In,MarshalAs(UnmanagedType.Interface)] INSCallbackEnum a);
int proc10([In,MarshalAs(UnmanagedType.Interface)] INSCallbackEnum a, [In] int b);
int proc11([In,MarshalAs(UnmanagedType.Interface)] INSRec a);
int GetID(out int a);
int proc13(out int a);
}
[ComImport, Guid("50000004-0000-1000-0010-0000836BD2D2"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface INSAppBase
{
int GetTable([In] int a, [Out,MarshalAs(UnmanagedType.Interface)] out INSTable b);
int GetInfos(out string a, out string databasename, out string company, out string d);
int proc5();
int proc6([In] int a);
int proc7([In] string a);
int proc8([In, MarshalAs(UnmanagedType.Interface)] INSCallbackEnum a, [In] int b);
}
[ComImport, Guid("50000004-0000-1000-0000-0000836BD2D2"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface INSHyperlink
{
int Open([In] string link);
int proc4(out int a);
}
[ComImport, Guid("50000004-0000-1000-0008-0000836BD2D2"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface INSMenuButton
{
int proc3([In] string a);
int proc4([In] int a, [In] string b, [In] string c);
}
[ComImport, Guid("50000004-0000-1000-0003-0000836BD2D2"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface INSForm
{
int GetHyperlink(out String a); // gets Hyperlink with Fieldcaptions
int GetID(out String a); // gets active object's type (Form) and ID
int GetRec([Out,MarshalAs(UnmanagedType.Interface)] out INSRec a);
int GetTable([Out, MarshalAs(UnmanagedType.Interface)] out INSTable a);
int GetLanguageID(out int a); // gets Language ID of application (1033, etc.)
int proc8([Out, MarshalAs(UnmanagedType.Interface)] out INSMenuButton a);
int proc9();
}
[ComImport, Guid("50000004-0000-1000-0002-0000836BD2D2"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface INSApplication
{
int GetForm([Out,MarshalAs(UnmanagedType.Interface)] out INSForm form);
}
A new concept in the whole discussion is the MarshalAs directive, which permits the use of complex data types within COM Interop.
Note also that the declaration of the interfaces is sufficient. We don't have to declare any COM coclasses because we are not creating new objects (NAV client must be already running).
Here is a (minimal) sample C#-code-snippet which retrieves the value of field no. 2 (Name) for the open Customer Card. Note that the customer card has to be opened and should be activated.
INSApplication IA = (INSApplication)RunningObjectTable.GetRunningCOMObjectByName("!C/SIDE!navision://client/run?");
INSForm IF;
IA.GetForm(out IF);
INSRec IR;
IF.GetRec(out IR);
String str;
IR.GetFieldValue(2, out str);
System.Console.WriteLine(str);
The RunningObjectTable.GetRunnigCOMObjectByName function can be found here:
http://www.mycsharp.de/wbb2/thread.php?threadid=36340During my tests, I had a problem that every now and then the customer card was not the active form. In this case IF == null is returned and you will encounter a System.NullReferenceExeption in the above code. To get the customer card the active form, just switch to the NAV client and move the customer card around (do not work in full screen modus) in order to make it the active form (it is not sufficient to just click into the card form).