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 ); } } } } }