private void OnClick( InfoStorageAttribute storage, dynamic item, List<string> filesList )
		{
			string action = Util.IsJsonProperty( item, "action" ) ? (string)item.action : "";
			string cmd = Util.IsJsonProperty( item, "cmd" ) ? (string)item.cmd : "";

			if ( action.Length > 0 || cmd.Length > 0 )
			{
				if ( filesList.Count > 0 )
				{
					string[] args = Util.IsJsonProperty( item, "args" ) ? Util.ObjectToStringArray( (object[])item.args ) : new string[ 0 ];
					var style = Util.IsJsonProperty( item, "style" ) ? (string)item.style : "remain";

					string type = style == "remain" ? "/K" : "/C";
					string argsString = args.Length > 0 ? JoinWithQuotes( args ) : "";
					string filesString = filesList.Count > 0 ? JoinWithQuotes( filesList.ToArray() ) : "";
					string fullArgs = "";
					if ( action.Length > 0 )
					{
						fullArgs = type + @" node """ + action + @""" " + argsString + " " + filesString;
					}
					else if ( cmd.Length > 0 )
					{
						fullArgs = type + @"""" + cmd + @""" " + argsString + " " + filesString;
					}

					System.Diagnostics.Process process = new System.Diagnostics.Process();
					System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
					startInfo.WindowStyle = style == "hidden" ? System.Diagnostics.ProcessWindowStyle.Hidden : System.Diagnostics.ProcessWindowStyle.Normal;
					startInfo.FileName = "cmd.exe";
					startInfo.Arguments = fullArgs;
					startInfo.WorkingDirectory = storage.ActionPath;
					process.StartInfo = startInfo;
					process.Start();
				}
			}
		}
        private void OnClick(InfoStorageAttribute storage, dynamic item, List <string> filesList)
        {
            string action = Util.IsJsonProperty(item, "action") ? (string)item.action : "";
            string cmd    = Util.IsJsonProperty(item, "cmd") ? (string)item.cmd : "";

            if (action.Length > 0 || cmd.Length > 0)
            {
                if (filesList.Count > 0)
                {
                    string[] args  = Util.IsJsonProperty(item, "args") ? Util.ObjectToStringArray((object[])item.args) : new string[0];
                    var      style = Util.IsJsonProperty(item, "style") ? (string)item.style : "remain";

                    string type        = style == "remain" ? "/K" : "/C";
                    string argsString  = args.Length > 0 ? JoinWithQuotes(args) : "";
                    string filesString = filesList.Count > 0 ? JoinWithQuotes(filesList.ToArray()) : "";
                    string fullArgs    = "";
                    if (action.Length > 0)
                    {
                        fullArgs = type + @" node """ + action + @""" " + argsString + " " + filesString;
                    }
                    else if (cmd.Length > 0)
                    {
                        fullArgs = type + @"""" + cmd + @""" " + argsString + " " + filesString;
                    }

                    System.Diagnostics.Process          process   = new System.Diagnostics.Process();
                    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
                    startInfo.WindowStyle      = style == "hidden" ? System.Diagnostics.ProcessWindowStyle.Hidden : System.Diagnostics.ProcessWindowStyle.Normal;
                    startInfo.FileName         = "cmd.exe";
                    startInfo.Arguments        = fullArgs;
                    startInfo.WorkingDirectory = storage.ActionPath;
                    process.StartInfo          = startInfo;
                    process.Start();
                }
            }
        }
        static void AddChildren(Assembly assem, Platform.ShellRightClickContextMenuClass menuClass, InfoStorageAttribute storage, IntPtr menu, dynamic children, List <string> selectedFiles, bool isRoot, MenuClick onClick)
        {
            for (var i = 0; i < children.Length; ++i)
            {
                dynamic item = children[i];
                string  name = Util.IsJsonProperty(item, "name") ? (string)item.name : "New Menu Item";

                // embed image into assembly and reference that
                System.Drawing.Bitmap bmp = null;
                IntPtr subMenu            = IntPtr.Zero;

                if (Util.IsJsonProperty(item, "imageResource"))
                {
                    var    resources = assem.GetManifestResourceStream((string)item.imageResource + ".resources");
                    var    rr        = new System.Resources.ResourceReader(resources);
                    string resourceType;
                    byte[] resourceData;
                    rr.GetResourceData("image.bmp", out resourceType, out resourceData);
                    // For some reason the resource compiler adds 4 bytes to the start of our data.
                    bmp = new System.Drawing.Bitmap(new System.IO.MemoryStream(resourceData, 4, resourceData.Length - 4));
                }
                if (Util.IsJsonProperty(item, "children"))
                {
                    subMenu = menuClass.CreateSubMenu();
                    AddChildren(assem, menuClass, storage, subMenu, item.children, selectedFiles, false, onClick);
                }

                int position = i + 1;
                if (isRoot)
                {
                    position = Util.IsJsonProperty(item, "position") ? (int)item.position : position;
                }
                if (menu == IntPtr.Zero)
                {
                    // root element
                    if (subMenu == IntPtr.Zero)
                    {
                        uint id = menuClass.InsertMenuItem(name, position, (List <string> s) => { onClick(item, selectedFiles); });
                        if (bmp != null)
                        {
                            menuClass.SetMenuItemBitmap(id, bmp);
                        }
                    }
                    else
                    {
                        menuClass.InsertSubMenu(subMenu, name, position, bmp);
                    }
                }
                else
                {
                    // sub menu
                    if (subMenu == IntPtr.Zero)
                    {
                        menuClass.InsertMenuItemIntoSubMenu(menu, name, position, bmp, (List <string> s) => { onClick(item, selectedFiles); });
                    }
                    else
                    {
                        uint id = menuClass.InsertSubMenuIntoSubMenu(menu, subMenu, name, position);
                        if (bmp != null)
                        {
                            menuClass.SetMenuItemBitmap(id, bmp);
                        }
                    }
                }
            }
        }
        public static void BuildMenu(Assembly assem, Platform.ShellRightClickContextMenuClass menuClass, InfoStorageAttribute storage, List <string> list, MenuClick onClick)
        {
            try
            {
                // filter file extensions if required
                var filter    = new List <string>(storage.FileExtensionFilter);
                var filesList = storage.ExpandFileNames ? BuildFileList(filter, list) : list;

                if (filesList.Count > 0)
                {
                    string menuFormatJson = storage.MenuFormat;

                    var     jsonReader               = new JsonFx.Json.JsonReader();
                    dynamic menuFormatObject         = jsonReader.Read <dynamic>(menuFormatJson);
                    dynamic menuFormatObjectChildren = menuFormatObject.children;

                    AddChildren(assem, menuClass, storage, IntPtr.Zero, menuFormatObjectChildren, filesList, true, onClick);
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message + "\r\n\r\n" + e.StackTrace, "Error whilst creating menu");
            }
        }
		static void AddChildren( Assembly assem, Platform.ShellRightClickContextMenuClass menuClass, InfoStorageAttribute storage, IntPtr menu, dynamic children, List<string> selectedFiles, bool isRoot, MenuClick onClick )
		{
			for ( var i=0; i<children.Length; ++i )
			{
				dynamic item = children[ i ];
				string name = Util.IsJsonProperty( item, "name" ) ? (string)item.name : "New Menu Item";
				
				// embed image into assembly and reference that
				System.Drawing.Bitmap bmp = null;
				IntPtr subMenu = IntPtr.Zero;

				if ( Util.IsJsonProperty( item, "imageResource" ) )
				{
					var resources = assem.GetManifestResourceStream( (string)item.imageResource + ".resources" );
					var rr = new System.Resources.ResourceReader( resources );
					string resourceType;
					byte[] resourceData;
					rr.GetResourceData( "image.bmp", out resourceType, out resourceData );
					// For some reason the resource compiler adds 4 bytes to the start of our data.
					bmp = new System.Drawing.Bitmap( new System.IO.MemoryStream( resourceData, 4, resourceData.Length-4 ) );
				}
				if ( Util.IsJsonProperty( item, "children" ) )
				{
					subMenu = menuClass.CreateSubMenu();
					AddChildren( assem, menuClass, storage, subMenu, item.children, selectedFiles, false, onClick );
				}

				int position = i+1;
				if ( isRoot )
				{
					position = Util.IsJsonProperty( item, "position" ) ? (int)item.position : position;
				}
				if ( menu == IntPtr.Zero )
				{
					// root element
					if ( subMenu == IntPtr.Zero )
					{
						uint id = menuClass.InsertMenuItem( name, position, ( List<string> s ) => { onClick( item, selectedFiles ); } );
						if ( bmp != null )
						{
							menuClass.SetMenuItemBitmap( id, bmp );
						}
					}
					else
					{
						menuClass.InsertSubMenu( subMenu, name, position, bmp );
					}
				}
				else
				{
					// sub menu
					if ( subMenu == IntPtr.Zero )
					{
						menuClass.InsertMenuItemIntoSubMenu( menu, name, position, bmp, ( List<string> s ) => { onClick( item, selectedFiles ); } );
					}
					else
					{
						uint id = menuClass.InsertSubMenuIntoSubMenu( menu, subMenu, name, position );
						if ( bmp != null )
						{
							menuClass.SetMenuItemBitmap( id, bmp );
						}
					}
				}
			}
		}
		public static void BuildMenu( Assembly assem, Platform.ShellRightClickContextMenuClass menuClass, InfoStorageAttribute storage, List<string> list, MenuClick onClick )
		{
			try
			{
				// filter file extensions if required
				var filter = new List<string>( storage.FileExtensionFilter );
				var filesList = storage.ExpandFileNames ? BuildFileList( filter, list ) : list;

				if ( filesList.Count > 0 )
				{
					string menuFormatJson = storage.MenuFormat;

					var jsonReader = new JsonFx.Json.JsonReader();
					dynamic menuFormatObject = jsonReader.Read<dynamic>( menuFormatJson );
					dynamic menuFormatObjectChildren = menuFormatObject.children;

					AddChildren( assem, menuClass, storage, IntPtr.Zero, menuFormatObjectChildren, filesList, true, onClick );
				}
			}
			catch ( Exception e )
			{
				MessageBox.Show( e.Message + "\r\n\r\n" + e.StackTrace, "Error whilst creating menu" );
			}
		}