EFT, MoveX APIs, More Reflection, Windows, Events and Classes

We’re in the process of going from MoveX V12 Java, SP16 fix pack6, Foundation 7.1, Apps 5.2 to M3 V14, or 10.1 and 10.1 offers us a lot of opportunities through Smart Office and WebServices.

One of the issues that caused a lot of grief has been the APIs in MoveX V12 are very weak, they often get 60% of the way to achieving a goal but then don’t have the other core 40% of functionality there so you end up having to take a hybrid approach of direct SQL reads and APIs and using MoveX Explorer.  Or worse still, you have a situation where the API functionality doesn’t honour all of the rules that the client does so you end up with inconsistent behaviour.

As most of you have no-doubt experienced, ERP solutions though great, often leave these little holes or gaps that your organisation needs to fill – this can’t be solved with MoveX alone.  One of these gaps for us was EFT processing, in short creating a file of payments to suppliers that we upload to our bank for electronic payment.

The Lawson solution was to use MeC, and it is a horrible, horrible solution.  MeC is over complicated and can get so severely screwed up with timing issues when it comes to payments that you have to adjust your process to work around the shortcomings – increasing workload and increasing the chances that your Accounts Payable staff can make a mistake, that’s before we get in to the arcane setup you need to go through and the consulting in-experience in this end of the world.  Don’t get me wrong, I’m sure MeC has its place, but for us, it was like using an industrial power drill to hammer in a tac.

So for us I wrote a little .Net application that did away with the MeC side of the equation, it would use the APIs CRS692MI and APS130MI along with several SQL statements to extract a payment proposal, the payment proposals items and the bank account details and finally handle the deletion of the payment proposal.

In the upgrade it looks like something has changed around the functionality in APS130MI and it proposal deletion function which prevents it from working correctly (takes the proposal to status 4 indefinitely, an issue we are logging with Lawson).  Which prompted me to consider, instead of using an external application, why not just create a jscript within Smart Office – the user will just highlight the proposal and click on the “Generate EFT” button and it will spit out a file which can then be uploaded – no more nonsense with APIs, additional user logins, SQL requirements and additional programs.

A jscript for generating the EFTs?  Conceptually, very straight forward, the EFT program really consists of several loops and a function that spits out a file in the right format, can’t really get much easier.  However, it requires usage of classes, properties, may use a window to display information and need to capture some of the events from the new window; things that I haven’t had any experience with in a jscript world.

So, I decided that I would clean up my earlier code around reflection, have it so it is displayed in a ListView (so I can use binding to make life easier) on a newly opened Window and set it up so you could select a property and then open a new window and show the selected objects info to give me a better idea of design for the EFTs.

Defining Classes

Well, this part is pretty simple, when we use the mforms://jscript editor and go New it creates the package and the class for us, so we have a framework to work with.  But can we just define another class within the one package?  Can we include a class within a class, what happens when we do that?  Yes, yes and not a lot J

To start with I created a very basic class, it has a couple of variables and a constructor.  It is the class that we will be using to store the information about each piece of information we find when we do a discovery on an object.

        public class extMemberInfo
	{
		var Name : String;
		var MemberType : String;
		var DeclaringType : String;
		var Module : String;
		var ReflectedType : String;
		
		var Value : String;

		// this is the constructor for the object, here we set all the values
		function extMemberInfo(aName, aMemberType, aDeclaringType, aModule, aReflectedType, aValue)
		{
			this.Name = aName;
			this.MemberType = aMemberType;
			this.DeclaringType = aDeclaringType;
			this.Module = aModule;
			this.ReflectedType = aReflectedType;
			this.Value = aValue;
		}

	}

 

As you can see, not a lot to it, for the sake of experimentation and I do like type safety, I’ve set the data type of the variables, I defined a constructor so we could easily create and initialise the object in a single hit.  After spending a lot of time in a type safe world and my unconditional love of properties I wondered if properties were supported within jscript, this little project was going to need properties that I could bind the ListView columns too.

      public class extMemberInfo
       {
              private var pri_Name : String;
              private var pri_MemberType : String;
              private var pri_DeclaringType : String;
              private var pri_Module : String;
              private var pri_ReflectedType : String;

              private var pri_Value : String;

              // this effectively presents itself as a Property
              // Binding will only work on properties

              // retrieve the MemberType
              function get MemberType() : String
              {
                     return this.pri_MemberType;
              }

              // retrieve the DeclaringType
              function get DeclaringType() : String
              {
                     return this.pri_DeclaringType;
              }

              // retrieve the Module
              function get Module() : String
              {
                     return this.pri_Module;
              }

              // retrieve the ReflectedType
              function get ReflectedType() : String
              {
                     return this.pri_ReflectedType;
              }

              // retrieve the Value
              function get Value() : String
              {
                     return this.pri_Value;
              }

              // retrieve the Name
              function get Name() : String
              {
                     return this.pri_Name;
              }             

              // this is the constructor for the object, here we set all the values
              function extMemberInfo(aName, aMemberType, aDeclaringType, aModule, aReflectedType, aValue)
              {
                     this.pri_Name = aName;
                     this.pri_MemberType = aMemberType;
                     this.pri_DeclaringType = aDeclaringType;
                     this.pri_Module = aModule;
                     this.pri_ReflectedType = aReflectedType;
                     this.pri_Value = aValue;
              }
       }

Here we set our variables to private, so no functions outside of this class should be able to change their values.  The only way for the values to change is when you construct the object, and this will suit our purposes quite nicely.

The new parts that we have are is:

function get Name() : String

Quite simply, it is defining a function which is presented as a property, using the keyword get or set allows you to get or set a value as if it were a property.  Name() is the name of the property, and : String says that this is going to return a String.

return this.pri_Name;

Will then return the value stored in pri_Name

Given we are effectively replicating many of the values in the MemberInfo class that we use to populate this object, we could have probably looked at inheritance, but that’s for another day to look in to.

Ok, so now we have a class which will store our values and supports properties so we can bind our columns to it.

Assemblies

In order to use reflection and some of the methods that I use we need to include other assemblies.

import System;       // Environment class, allows us to use Environment.NewLine
import System.ComponentModel;
import System.Windows.Input;
// we need System.Reflection so we can inspect the objects
import System.Reflection;
import System.Windows;
import System.Windows.Controls;
import MForms;
import Mango.UI.Core;
import Mango.UI.Core.Util;
import Mango.UI.Services;

Most of these are already defined when you create a new jscript within the Smart Office editor.

Incidently, if you want to take a look at the assembles that Lawson provide, then you can use the Visual Studio Object Browser.  The filename of the assemblies typically is the name of the Assembly with a .dll appended to the end (eg. Mango.UI.Core.dll), these are stored in the directory that the ClickOnce deployment dropped Smart Office in to, usually <user profile>\AppData\Local\2.0\<random name>\<random name>\<crytic GUID>\, basically I do a search in the AppData directory for Mango and it will show up the assemblies, in my case:

“C:\Users\Scott\AppData\Local\Apps\2.0\LQK5EE90.NZQ\9P7DMX0R.92Q\http..tion_3eefdc12643b7dbb_0009.0001_0654d9605bc969c8\Mango.Core.dll”
“C:\Users\Scott\AppData\Local\Apps\2.0\LQK5EE90.NZQ\9P7DMX0R.92Q\http..tion_3eefdc12643b7dbb_0009.0001_0654d9605bc969c8\Mango.Skin.dll”
“C:\Users\Scott\AppData\Local\Apps\2.0\LQK5EE90.NZQ\9P7DMX0R.92Q\http..tion_3eefdc12643b7dbb_0009.0001_0654d9605bc969c8\Mango.UI.dll”
“C:\Users\Scott\AppData\Local\Apps\2.0\LQK5EE90.NZQ\9P7DMX0R.92Q\http..tion_3eefdc12643b7dbb_0009.0001_0654d9605bc969c8\MangoChart.Core.dll”
“C:\Users\Scott\AppData\Local\Apps\2.0\LQK5EE90.NZQ\9P7DMX0R.92Q\mang..core_9759cb56e4efc0a2_0009.0001_none_1ff9594031846a9b\MangoChart.Core.dll”

Events

Now events caused me a lot of problems within this little project, you look at the Lawson provided examples and it makes event handling look so much more simpler than in the big boy programming languages J

Events cannot be created within jscript L, however you can subscribe to existing events.  You need to find out what the event is called for an object and then call <object>.add_<eventname>(<event handling function>) and a call will need to be made later to unsubscribe from the event, this follows a similar format <object>.remove_<eventname>(<event handling function>)

Turns out that they can be very challenging, especially within Smart Office.  I found that timing can be everything between hoses your Smart Office instance and it working flawlessly, that you have be pay very special attention to cleaning up resources and getting handlers of events arguments 100% correct – even then, I couldn’t for the life of my get the MouseDoubleClick event to fire in my ListView so resorted to SelectionChanged events.

In my situation I ended up adding event handlers that would listen for the closing of our window and the loaded event.  Within the loaded event I would then add a handler to listen for SelectionChanged events against the ListView.  Because this was such a problematic area I ended up leaving the event registration within the loaded event.

public function OnReflectionWindowLoaded(sender: Object, e: RoutedEventArgs)
{
	try
	{
		// ensure that we have a ListView object to attach to
		if(null != wndReflectionWindow.lvListView)
		{
			// do the actual attach
			wndReflectionWindow.lvListView.add_SelectionChanged(OnSelectionChange);
			// if no exception was generated, then set a
			// flag so we know we did infact attach and will
// need to eventually dispose of the attachment
			wndReflectionWindow.bListViewMouseDoubleClickAdded = true;
		}
	}
	catch(ex)
	{
		MessageBox.Show("Exception adding MouseDoubleClick to ListView: " + ex.Message + Environment.NewLine + ex.StackTrace);
	}
}

public function OnSelectionChange(sender: Object, e:  SelectionChangedEventArgs)
{
	// do something really fancy
}

So when our Windows Loaded event is fired (basically once everything has been initialised), we attach a handler to our ListView looking for any SelectionChanged events, if there is one then the OnSelectionChange function will be called.  It is absolutely critical to get the type correct for the EventArgs, odd things happen within Smart Office ranging from cryptic compile errors to bizzare crashes if you don’t.

It helps to refer to the library at http://msdn.microsoft.com has a lot of information on events and the args types, unfortunately the jscript examples are almost non-existant.

The Code

The moment you’ve been waiting for, the code.  I was testing this against BUS100, so if you want to test this directly in your TEST environment, in Smart Office run BUS100 and then load the jscript editor and paste in the code.  I’ve added a lot of comments in here to explain what is happening.  In my example I use the Lawson ListView as the object I will examine.

There is a lot of ways that this could be expanded.  I’ve created a ReflectionWindow class to hold some common values and in the knowledge that one day I will add code to allow us to open multiple windows at a time and recurse through objects.

If you want to get information on property from the first opened ListView, then hold down the Alt key and then select the property you want to inspect.  A new window will open (oddly UNDER the main listview window).

Also NOTE that when-ever I selected any of the Lawson objects the script would get in to a mess, not sure why but it basically meant a restart of Smart Office to get things running again.

import System;	// Environment class
import System.ComponentModel;
import System.Windows.Input;
// we need System.Reflection so we can inspect the objects
import System.Reflection;
import System.Windows;
import System.Windows.Controls;

import MForms;
import Mango.UI.Core;
import Mango.UI.Core.Util;
import Mango.UI.Services;

package MForms.JScript {
   class bus100s
   {
		var debug, button, content, lv, listControl;
		
		var wndReflectionWindow : ReflectionWindow;
		
		public function Init(element: Object, args: Object,controller : Object, debug : Object) 
		{
			content = controller.RenderEngine.Content;
			listControl = controller.RenderEngine.ListControl;
			lv = listControl.ListView;
			
			button = new Button();
			button.Content = "Inspect";

			Grid.SetColumnSpan(button, 10);
			Grid.SetColumn(button, 0);
			Grid.SetRow(button, 1);
			content.Children.Add(button);
			button.add_Click(OnClick);
			button.add_Unloaded(OnUnloaded);
			wndReflectionWindow = null;
		}
		
		public function OnClick(sender: Object, e: RoutedEventArgs) 
		{
			try
			{
				if(null != wndReflectionWindow)
				{
					MessageBox.Show("wndReflectionWindow not null");
				}
				// we are just going to inspect the listview
				// you can point this at any object to take a look
				addWindow(lv, false);
			}
			catch(ex)
			{
				MessageBox.Show("Exception: " + ex.Message + Environment.NewLine + ex.StackTrace);
			}
		}

		public function OnUnloaded(sender: Object, e: RoutedEventArgs) 
		{
			// the window has been unloaded, time to clean up
			try
			{
				// if we have the wndReflectionWindow
				// look at closing it so we are totally
				// cleaned up
				if(null != wndReflectionWindow)
				{
					if(null != wndReflectionWindow.wndWindow)
					{
						wndReflectionWindow.wndWindow.Close();
					}
				}
				
				// remove the event handlers that we added
				button.remove_Click(OnClick);
				button.remove_Unloaded(OnUnloaded);
			}
			catch(ex)
			{
				MessageBox.Show("Exception: " + ex.Message + Environment.NewLine + ex.StackTrace);
			}
		}

		public function OnReflectionWindowLoaded(sender: Object, e: RoutedEventArgs)
		{
			try
			{
				if(null != wndReflectionWindow.lvListView)
				{
					// subscribe to the SelectionChanged event, call OnSelectionChange()
					wndReflectionWindow.lvListView.add_SelectionChanged(OnSelectionChange);
					wndReflectionWindow.bListViewMouseDoubleClickAdded = true;
				}
			}
			catch(ex)
			{
				MessageBox.Show("Exception adding MouseDoubleClick to ListView: " + ex.Message + Environment.NewLine + ex.StackTrace);
			}
		}

		public function OnReflectionWindowClose(sender: Object, e: CancelEventArgs)
		{
			try
			{
				if(null != wndReflectionWindow)
				{
					if(null != wndReflectionWindow.lvListView)
					{
						if(true == wndReflectionWindow.bListViewMouseDoubleClickAdded)
						{
							// remove our subscription to the SelectionChanged
							// event
							wndReflectionWindow.lvListView.remove_SelectionChanged(OnSelectionChange);
						}
					}
					if(null != wndReflectionWindow.wndWindow)
					{
						// remove other subscribed events
						wndReflectionWindow.wndWindow.remove_Loaded(OnReflectionWindowLoaded);
						wndReflectionWindow.wndWindow.remove_Closing(OnReflectionWindowClose);
					}
					
				}
			}
			catch(ex)
			{
				MessageBox.Show("Exception: " + ex.Message + Environment.NewLine + ex.StackTrace);
			}
			// set to null so by rights the garbage collector
			// will see there are no more objects connected and clean up
			wndReflectionWindow = null;
		}

		public function OnSelectionChange(sender: Object, e:  SelectionChangedEventArgs) 
		{
			try
			{
				// if the user holds down the Alt key when the change their
// selection on a property we will open a new window displaying
// that objects properties
				if(Keyboard.Modifiers == ModifierKeys.Alt)
				{
// only look at the first selected object
					if(e.AddedItems.Count &gt;= 1)
					{
						var emiExtendedMemberInfo = e.AddedItems[0];
						if(null != emiExtendedMemberInfo)
						{
// we can only examine properties
							if(String.Compare("Property", emiExtendedMemberInfo.MemberType) == 0)
							{
								var piPropertyInfo = wndReflectionWindow.wndWindow.Tag.GetType().GetProperty(emiExtendedMemberInfo.Name);
								if(null != piPropertyInfo)
								{
									var objPropertyValue = piPropertyInfo.GetValue(wndReflectionWindow.wndWindow.Tag, null);
									if(null != objPropertyValue)
									{
// call a new window with the value of the selected
										// object
										addWindow(objPropertyValue, true);
									}
								}
							}
						}
					}
				}
			}
			catch(ex)
			{
				MessageBox.Show("Exception: " + ex.Message + Environment.NewLine + ex.StackTrace);
			}
		}
		
		// addWindow - this function will use reflect to look at
		//  an object and maybe give us some clues about that the
		//  object does.   It will open a new window with information
		//  about the various properties, methods etc that are
		//  exposed
		// objCurr = the object that we want to inspect
		private function addWindow(objCurr: Object, bNoEvents: boolean)
		{
			// wrap the function in a try...catch(), let us handle
			// the errors rather than having Smart Office get upset
			try
			{
				// create a new window which we will show to the user
				var wndWindow = new Window();
				if(null != wndWindow)
				{

					if(false == bNoEvents)
					{
						wndReflectionWindow = new ReflectionWindow();
						wndReflectionWindow.wndWindow = wndWindow;
						
						wndReflectionWindow.wndWindow.add_Loaded(OnReflectionWindowLoaded);
						wndReflectionWindow.wndWindow.add_Closing(OnReflectionWindowClose);
					}

					// store the object that we are looking at so we can do further analysis if the user desires
					wndWindow.Tag = objCurr;
					// set the Window Height to 600
					wndWindow.Height = 600;
					// create a StackPanel, this makes it a little easier
					// with control placement in the window
					var spStackPanel = new StackPanel();
					if(null != spStackPanel)
					{
						// StackPanel should be vertical!
						spStackPanel.Orientation = System.Windows.Controls.Orientation.Vertical;
						
						// Create a Textbox that we will use to display
						// the type of the object that we are inspecting
						var tbTextBox = new TextBox();
						if(null != tbTextBox)
						{
							// it is set to ReadOnly
							tbTextBox.IsReadOnly = true;
							
							// add TextBox to the StackPanel
							spStackPanel.Children.Add(tbTextBox);
							
							// set the type of the object
							// we are inspecting to the TextBox
							tbTextBox.Text = objCurr.GetType().ToString();
							
							// finally go out and create the ListView
							// that will display everything
							var lvListView : ListView = createListView();
							if(null != lvListView)
							{
								if(false == bNoEvents)
								{
									wndReflectionWindow.lvListView = lvListView;
								}
								
								var miMemberInfo;
								var mtType;
								mtType = objCurr.GetType();
								// retrieve the members from the object type
								// it is this list that we will iterate through
								// and display
								miMemberInfo = mtType.GetMembers();
								
								// for some reason the for(var miCurrentMember in miMemberInfo) didn't work, resorted to a more traditional loop
								for(var i = 0; i &lt; miMemberInfo.Length-1;i++)
								{
									var miCurrentMember = miMemberInfo[i];
									var emiNewMember;
									var strPropertyValue : String = &quot;N/A&quot;;	// only Properties will have values, everything else we will display as &quot;N/A&quot;
									var piPropertyInfo : PropertyInfo;

									// if we are a property then we should look at getting the value										
									if(MemberTypes.Property == miCurrentMember.MemberType)
									{
										piPropertyInfo = objCurr.GetType().GetProperty(miCurrentMember.Name);
										if(null != piPropertyInfo)
										{
											strPropertyValue = piPropertyInfo.GetValue(objCurr, null);
										}
									}
									
									// create a new extMemberInfo object, this object effectively stores the pertinent information we want to look at
									emiNewMember = new extMemberInfo(miCurrentMember.Name, miCurrentMember.MemberType, miCurrentMember.DeclaringType, miCurrentMember.Module, miCurrentMember.ReflectedType, strPropertyValue);

									if(null != emiNewMember)
									{
										// add our entry to the ListView
										lvListView.Items.Add(emiNewMember);
									}

								}
								// add the ListView to the StackPanel
								spStackPanel.Children.Add(lvListView);

							}
						}
						// add the StackPanel to the Window
						wndWindow.Content = spStackPanel;
												
						// and last but not least, show the Window
						wndWindow.Show();
					}
				}
			}
			catch(ex)
			{
				MessageBox.Show(&quot;Exception: &quot; + ex.Message + &quot; &quot; + ex.StackTrace);
			}
		}
		

		
		// create our ListView with specific columns
		private function createListView() : ListView
		{
			var result : ListView = null;
			try
			{
				var lvListView = new ListView();
				if(null != lvListView)
				{
					var gvGridView = new GridView();
					lvListView.Height = 500;

					if(null != gvGridView)
					{
						lvListView.View = gvGridView;
						
				// create a new column and bind it to 
				// the Name property
		            	var gvcName = new GridViewColumn();
		            	gvcName.DisplayMemberBinding = new System.Windows.Data.Binding(&quot;Name&quot;);
		            	gvcName.Header = &quot;Name&quot;;
		            	gvcName.Width = 100;
		            	gvGridView.Columns.Add(gvcName);
		
				// create a new column and bind it to 
				// the MemberType property
		            	var gvcMemberType = new GridViewColumn();
		            	gvcMemberType.DisplayMemberBinding = new System.Windows.Data.Binding(&quot;MemberType&quot;);
		            	gvcMemberType.Header = &quot;MemberType&quot;;
		            	gvcMemberType.Width = 100;
		            	gvGridView.Columns.Add(gvcMemberType);

		            	var gvcDeclaringType = new GridViewColumn();
		            	gvcDeclaringType.DisplayMemberBinding = new System.Windows.Data.Binding(&quot;DeclaringType&quot;);
		            	gvcDeclaringType.Header = &quot;DeclaringType&quot;;
		            	gvcDeclaringType.Width = 100;
		            	gvGridView.Columns.Add(gvcDeclaringType);

		            	var gvcModule = new GridViewColumn();
		            	gvcModule.DisplayMemberBinding = new System.Windows.Data.Binding(&quot;Module&quot;);
		            	gvcModule.Header = &quot;Module&quot;;
		            	gvcModule.Width = 100;
		            	gvGridView.Columns.Add(gvcModule);
														
		            	var gvcReflectedType = new GridViewColumn();
		            	gvcReflectedType.DisplayMemberBinding = new System.Windows.Data.Binding(&quot;ReflectedType&quot;);
		            	gvcReflectedType.Header = &quot;ReflectedType&quot;;
		            	gvcReflectedType.Width = 100;
		            	gvGridView.Columns.Add(gvcReflectedType);

		            	var gvcValue = new GridViewColumn();
		            	gvcValue.DisplayMemberBinding = new System.Windows.Data.Binding(&quot;Value&quot;);
		            	gvcValue.Header = &quot;Value&quot;;
		            	gvcValue.Width = 100;
		            	gvGridView.Columns.Add(gvcValue);
		            	
		            	result = lvListView;
	            	}
            	}
			}
			catch(ex)
			{
				MessageBox.Show(&quot;Exception: &quot; + ex.Message + Environment.NewLine + ex.StackTrace);
			}
			return result;
		}
	}
		
	// this is a new class that we will store information that will be displayed by the
	// ListView
	// this could probably be done through inheritance, but
	// this is for the purposes of exploring what is supported
	// by the Lawson implementation of jscript
	// - there were a number of issues around this, effectively managing
	//   to get things presented as properties
   	public class extMemberInfo
	{
		private var pri_Name : String;
		private var pri_MemberType : String;
		private var pri_DeclaringType : String;
		private var pri_Module : String;
		private var pri_ReflectedType : String;
		
		private var pri_Value : String;

		// this effectively presents itself as a Property
		// Binding will only work on properties
		
		// retrieve the MemberType
		function get MemberType() : String
		{
			return this.pri_MemberType;
		}
		
		// retrieve the DeclaringType
		function get DeclaringType() : String
		{
			return this.pri_DeclaringType;
		}
		
		// retrieve the Module
		function get Module() : String
		{
			return this.pri_Module;
		}
		
		// retrieve the ReflectedType
		function get ReflectedType() : String
		{
			return this.pri_ReflectedType;
		}
		
		// retrieve the Value
		function get Value() : String
		{
			return this.pri_Value;
		}
		
		// retrieve the Name
		function get Name() : String
		{
			return this.pri_Name;
		}		
						
		// this is the constructor for the object, here we set all the values
		function extMemberInfo(aName, aMemberType, aDeclaringType, aModule, aReflectedType, aValue)
		{
			this.pri_Name = aName;
			this.pri_MemberType = aMemberType;
			this.pri_DeclaringType = aDeclaringType;
			this.pri_Module = aModule;
			this.pri_ReflectedType = aReflectedType;
			this.pri_Value = aValue;
		}
	}
		
	// this class is a common place holder
	// we can look at supporting deeper recursion
	// and multiple window support in the futre
	public class ReflectionWindow
	{
		var wndWindow;
		var lvListView;
		
		var bListViewMouseDoubleClickAdded = false;
	}
  
}

And that’s it.  Given the code above runs through almost all of the concepts I need with the EFTs (except for writing to files and web-services), then I hope to convert my EFT code in to jscript over the next couple of weekends and post it here.

Update 20101122 As it turns out, the priority of the source code has been reduced as Lawson provided a fix before we went live on 10.1, see fix JT-185102

This entry was posted in Development, How Far is Too Far?, M3 / MoveX. Bookmark the permalink.

6 Responses to EFT, MoveX APIs, More Reflection, Windows, Events and Classes

  1. Renato Ribeiro says:

    hi,

    excellent site, and excellent post. i am initiate in JScript and Ibrix development and this is a excellent help.
    Hope that we can change knowledgement about these issues in future

    • potatoit says:

      Thank you. I’m all for the sharing of knowledge.

      Smart Client / Office are truly great products (which is part of the reason why I’ve been tinkering with reflection) and I think that the information needs to be there for people to take advantage of – if even to know that something is possible – or they aren’t the only ones to stumble across something that just don’t quite seem right 🙂

  2. patrick Weiss says:

    Your site and ideas are very good. I have also a question: Is it still possible to start an API directly in a Jscript ?

    • potatoit says:

      Hi Patrick, thank you for the comment 🙂

      I believe that you can directly call the APIs from the jscript, that will of-course mean that you have to distribute the mvxAPI toolset to each computer that is going to run the jscript in question. IIRC the mvxsock*.dll is a COM object and you can use something similar to what I did with getting Excel access in my other blog postings – so something like:
      var mvxSocket = new ActiveXObject();

      I’d tend to recommend that you wrap the API in a webservice and call the webservice. While we’re on the subject, be aware that the API field positions can move between versions of M3, check out my posting “APIs – don’t forget to read the fine print!”

      Cheers,
      Scott

  3. patrick Weiss says:

    Thanks for your suggestion, but habe you such an example of a Jscript calling a WebService ?
    🙂

    • potatoit says:

      Ah, not at the moment. I’ve created webservices in M3 but haven’t tried calling one from jscript. It is on my list of things to do and post about soon 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s