You are on page 1of 10

============================

MS3D APPLICATION MENU README


============================

Copyright 2008 Mintec, Inc.


All Rights Reserved

.. Contents:: Table of Contents

--------
OVERVIEW
--------

The APPMENU INI files are used for installing menu entires onto the
"MineSight" application menu of MS3D. You can control what your menu
looks like for all projects or on a project by project basis.

Modifications of this file should only be done if you know what you are
doing, so always MAKE A BACKUP!

--------------
SPECIFICATIONS
--------------

FILE NAMING AND LOCATION


------------------------

The "MS3D_APPMENU_[PRODUCT].ini" files are used to help configure the


contents of the MS3D MineSight menu. The files are named according to
their products, and indicate how they should be sorted on the menu.
Thus, "ms3d_appmenu_product_a.ini" is sorted before
"ms3d_appmenu_product_b.ini".

If you use the project directory a separator will be added to help


distinguish it from the MS3D process directory entries and the
custom compass procedures.

VARIABLE SUBSTITUTIONS
----------------------

At runtime certain items are known, and when the INI file is loaded it
will perform variable substitutions using the $(var) notation. For
example, consider that you want to launch a program, and supply the
project directory,

::

...
program=doozle_drap.exe
args="$(ProjectDir)"
...

If the project directory was, C:\projects\BigGoldMine, then the program


would get spawned with,

::

doozle_drap.exe "C:\projects\BigGoldMine"
VARIABLES
.........

$(Config)

Indicates that we are working with either a "DEBUG" or


"RELEASE" version of MS3D.

$(MEDEXE)

The directory that %MEDEXE% points to.

$(MS3DProcessDir)

Points to the directory that contains the MS3D.EXE.

$(ProjectDir)

Points to the directory that was selected on the MS3D Splash Screen.

$(ResourceDir)

Points to the directory that contains the MSRS (_msresource).

All variables are CASE SENSITIVE.

MENU VERSUS SUBMENU


-------------------

Your application menu may want to either make a single menu entry or it
may want to specify a submenu. You can handle this by specifying more
than one entry in the "menu/list" entry. As in,

::

; Example of a submenu
[menu]
title = Economic Planner (MSEP)
mnemonic = E
requires = any
list = msep_compass, msepc

Where the list will give the full specifications for the menu entry. In
this case there would need to be [msep_compass] and [msepc] sections.

If you just wanted to have a single entry (i.e. no submenu), you would
do the following,

::

; Example of a single entry menu.


[menu]
list = msda

Then there would exist an [msda] section that had the full configuration
options.

COMMON ENTRIES
--------------
**type, required**

This indicates what type of menu entry you have. See the `ENTRIES
BASED ON TYPES`_ section for a list of available types.

**title, required/optional**

This is the name of the menu entry.

**mnemonic, optional**

This is the mnemonic that we will use for the entry.

**requires, required/optional**

This defines what is required to enable/disable the menu entry. This


has zero effect on the actual "usage" of the menu entry contents. If
you are not sure, then you should probably use "any" for this value.

ENTRIES BASED ON TYPES


----------------------

The following specifications are type specific. Any given section needs
to have certain entries defined based on its type.

compass_group
.............

This specifies that you wish to open a specific menu and a specific
group on the Compass Dialog. A compass_group type should have the
following entries,

**mnu, required**

This is the name of the MNU file for searching for a group. If
the MNU file is not found, a warning is posted to the MS3D
Message Box, and MSCOMPASS is "just opened".

**group, required**

This is group to select from the supplied MNU box. This group
will be active when you select this menu entry. The
group name is case sensitive.

**default_group, required**

If the above group is not found, this group is activated. It is


recommended that you use something generic like "All". The
group name is case sensitive.

If the default group can not be found a warning is sent to the


MS3D message window, and MSCOMPASS is "just opened".

**searchdirs, required**

These are the directories that need to be searched. The


general search pattern should be process dir, then MEDEXE dir.
**is_recurse_search, required**

When searching, should we recursively search through a directory


and its sub-directories (sometimes this would be a very slow
operation) or should we just look in the directory. Set to true
if you want to recurse, set to false otherwise.

exe
...

Indicates that you wish to execute a program with arguments.

**program, required**

This is the program EXE that we are too search for.

**args, optional**

These are args that are applied to the given program. Tip, use
the "ini" variables to get interesting results (see "Variable
Substitutions" above).

**searchdirs, required**

These are the directories that need to be searched. The


general search pattern should be process dir, then MEDEXE dir.

**is_recurse_search, required**

When searching, should we recursively search through the


directory and its sub-directories (sometimes this would be a
very slow operation) or should we just look in the directory.
Set to true if you want to recurse, set to false otherwise.

**is_dotnet, optional**

Set to false if the application is a "native" application. Set


to true if it is a .NET application.

**reg, optional**

This is where to go looking for the given reg_key. The registry


search has a lower priority than the directory search. We will
search in both "HKEY_CURRENT_USER" and "HKEY_LOCAL_MACHINE", in
that order.

This is not the recommended way to search for a program, and is


only maintained for some older programs.

**reg_key, optional**

Set this to a registry key that can be used in a last ditch


effort to locate a file.

function
........

This is a special type. It is used to invoke functions from within MS3D,


but still give exterior control to such things as Title, Mnemonic, and
requirements.

**function, required**

The name of an entry in the msappmenu.c's "func_name_to_func"


table. The program will attempt to invoke the given function in
the table.

An example of this type of menu entry would be the


"ms3d_appmenu_mscompass.ini".

msge
....

This will launch a python script as a MineSight(r) Grail Embedded


script (MSGe).

**script, required**

This is the script file name that we are too search for.

**searchdirs, required**

These are the directories that need to be searched. The


general search pattern should be process dir, then MEDEXE dir.

**is_recurse_search, required**

When searching, should we recursively search through the


directory and its sub-directories (sometimes this would be a
very slow operation) or should we just look in the directory.
Set to true if you want to recurse, set to false otherwise.

-------------
ERROR LOGGING
-------------

Errors are reported in a file called :file:`ms3d_appmenu.log` within the


MS3D project directory (if and only if there is read access). Sometimes
you may be missing a product that has a corresponding INI file, in that
case you may see spurious errors in the error log. Those errors are most
likely OK.

--------
EXAMPLES
--------

SUB-MENU
--------

The following is a simple example of setting up a sub-menu to launch two


native exe's.

::

[menu]
title = My Applications
mnemonic = M
requires = any
list = fizzle_wizzle, fuzzle_goozzle

[fizzle_wizzle]
type=exe
title=Fizzle Wizzle
mnemonic=F
requires=any
program=fizzle_wizzle.exe
searchdir=$(MS3DProcessDir)\my_apps, $(MEDEXE)\my_apps
is_rescurse_search=false
is_dotnet=false

[fuzzle_goozzle]
type=exe
title=Fuzzle Goozzle
mnemonic=F
requires=any
program=fuzzle_goozzle.exe
searchdir=$(MS3DProcessDir)\my_apps, $(MEDEXE)\my_apps
is_rescurse_search=false
is_dotnet=false

This will make a menu entry that appears as,

::

My Applications->Fizzle Wizzle
Fuzzle Goozzle

Each of these applications are searched for first under

::

[ms3d.exe dir]\my_apps
[%medexe%]\my_apps

The search is not recursive.

MENU
----

This example illustrates setting up a menu entry to launch a .NET


application,

::

; This is a one-entry menu.


[menu]
list=watcha_ma_callit

[watcha_ma_callit]
type=exe
title=New Watcha Ma Callit
mnemonic=N
requires=watcha
program=watcha.exe
searchdir=$(MS3DProcessDir)\watcha, $(MS3DProcessDir)\watcha_beta,
$(MEDEXE)\watcha, $(MEDEXE)\watcha
is_recurse=false
is_dotnet=true

That will make a new menu entry that looks like,

::

New Watcha Ma Callit

when the user clicks that menu entry, it will find the program in
either,

::

[ms3d.exe dir]\watcha
[ms3d.exe dir]\watcha_beta
[%medexe%]\watcha
[%medexe%]\watcha_beta

The search will not recurse into sub-directories.

LAUNCHING STANDALONE PYTHON SCRIPTS


-----------------------------------

As an interesting aside, you can use these mechanics to launch a python


script. In this example, we will create a script called
:file:`helloworld_project.py` and store it in a sub-directory of a
project at :file:`c:\\myproject`.

First, lets consider what the script will do. In this case the script
will take one parameter -- the project directory -- and print it on a
Tkinter dialog.

.. python::

import sys
import Tkinter
import tkMessageBox

tk = Tkinter.Tk()
tk.withdraw()

# First argument to this script should be the project path, if not,


# post a dialog and say bye, bye.
try:
project_path = sys.argv[1]
except IndexError, e:
tkMessageBox.showerror(
"Error: Missing argument",
"require path to project directory as first argument"
)
sys.exit(-1)

lbl_helloworld = Tkinter.Label(tk, text="Hello World!")


lbl_project = Tkinter.Label(
tk,
text=("The project is: '%s'" % (project_path))
)
lbl_helloworld.pack(padx=10, pady=10)
lbl_project.pack(padx=10, pady=10)

tk.deiconify()
tk.lift()
tk.mainloop()

That's the script to print the dialog. Now lets create a "command file"
run python against this script.

::

SETLOCAL

:: Determine the directory that this script resides in.


SET MYROOT=%~d0%~p0

:: Configure the pythonpath so future imports in the python script also


:: look in the same directory as the helloworld script.
SET PYTHONPATH=%MYROOT%;%PYTHONPATH%

:: Define a full path to the script. Quotes are IMPORTANT!


SET SCRIPTPATH="%MYROOT%helloworld_project.py"

:: Determine how we are going to call PYTHON.EXE, if there is a hint to


:: its location use it, otherwise, just rely on the path to define the
:: location.
IF /I [%PYTHONHOME%] NEQ [] SET CALL_PYTHON="%PYTHONHOME%\python.exe"
IF /I [%PYTHONHOME%] EQU [] SET CALL_PYTHON=python.exe

:: Execute
%CALL_PYTHON% %SCRIPTPATH% %*

ENDLOCAL

There are a few important items in this command script,

1. The ability to locate the directory that the command scripts


resides within via the,

::

SET MYROOT=%~d0%~p0

this lets you,

a. Enhance the %PYTHONPATH% to ensure that when you do an import


in Python, you also look in the same directory as your command
script.

b. This is really helpful if you are writing a script that uses


some third party library, but you want to make sure your script
works with a particular version. For example, consider that you
want to use wxWidgets, you could then install your script as,

::

c:\myproject\python_scripts\my_script.py
\wxWidgets\__init__.py
...other wxWidgets
...files...

Then if you ran this from the my_script.py,

.. python::

import wxWidgets
print wxWidgets.__file__

you would get

::

c:\myproject\python_scripts\wxWidgets\__init__.py

you see, it picked up *your* wxWidgets first, not some global


system one.

2. Ability to control how to run python, and what python to use. In


this case we simply decided to either use the one defined by
PYTHONHOME or default to the one located on the path.

Now that we have all that defined, lets create our appmenu INI file. In
this case we will create a single entry,

::

[menu]
list=helloworld_project

[helloworld_project]
; It is an EXE project, we are launching Python.exe
type=exe
title=Helloworld Project!
mnemonic=H
requires=anykey
; We want to spawn the command file that we created, since that file
; controls how the data is outputted.
program=helloworld_project.cmd
args=$(ProjectDir)
searchdir=$(ProjectDir)\python_scripts
is_recurse=false
is_dotnet=false

You could have put the :file:`python_scripts` sub directory into the same
directory as :file:`MS3D.EXE`, and get a result that runs across all projects at
a particular site.

LAUNCHING MSGe PYTHON SCRIPTS


-----------------------------

This can be best illustrated with an example,

::

[menu]
list=em_info

[em_info]
type=msge
title=Python/MSGRAIL Info
mnemonic=P
requires=anykey
script=em-info.py
searchdirs=$(MS3DProcessDir)\scripts, $(MEDEXE)\scripts
is_recurse=false

This will create a menu entry called "Python/MSGRAIL Info" that when
activated will launch the "em-info.py" script as an "Embedded" script.

---
FAQ
---

1. I HAVE A DISABLED ENTRY? HOW CAN I TO ENABLE IT?


---------------------------------------------------

First you should check the :file:`$(ProjectDir)\\ms3d_appmenu.log` file


for any hints. Second, ensure that your "requires" field is correct --
it is case sensitive.

You might also like