add to start menu

How do I add an group / icon to the startmenu of windows?
Who is Participating?
40 points refunded, solution posted by Asker earlier in the thread.  Moved to PAQ at zero points.
Moondancer - EE Moderator
Igor BazarnyCommented:

Are you writing installer? Just use installAnywhere or installShield. You need to add shortcut to your program or folder to correspondent directory (depending on OS/settings). It may be C:\Windows\Profiles\<user>\Start Menu\Programs. I guess, there should be a shell function to do that, if you aren't afraid of JNI

Igor Bazarny,
Brainbench MVP for Java 1
calvinrsmithAuthor Commented:
yes the shell function is what i'm looking for
Cloud Class® Course: CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

Igor BazarnyCommented:
Then I believe it's not the best place to ask. It's not java question.
Do you reallize that the start menu is simply a directory structure under c:\windows\Start Menu?

Just add a directory under c:\windows\Start Menu to groups and file shortcuts to create icons...
calvinrsmithAuthor Commented:
yes it is, however it is not always windows it could be winnt or just about anything else.  Also there are global icons and per user icons.  Plus I don't know the file format :(  Anyway I've figured this out thx for your help
At the risk of telling you something you already know, Windows NT is the same way.  It's just that Windows NT throws the user profile in the directory mix as well.  So you have to ask yourself, do you want the user to install your program under their own directory start menu, or under the directory start menu for the "All Users" menu, or maybe you want the "Default User".  The registry also tells you the prefix whethor it be "c:\documents and settings" (Windows 2000) or "c:\The place where I decided to put my user settings" some custom config.  If this isn't what you want, you will have to explain in a little more detail what you need...
calvinrsmithAuthor Commented:
yep I got it all figured out now.  Must hit the registry to figure out where the link goes then hit a com control to create the link.  works pretty good

I've had the same problem. Because I couldn't find any solution in java to add a Shortcut, I've used Windows Script to solve this problem. The problem with java was that you are able to add a folder or a file to about anywhere you want (according your the user's wishes), but you can't set the properties of the shortcut-file (e.g. icon-index).

If you need I can send you the script-file that is able to add a shortcut.
Igor BazarnyCommented:

Post it here, otherwise when question will turn onto PAQ entry it will be misguiding--people will give points to see an answer, but there is no answer here, as far as I understand.

Igor Bazarny
    Good I'm glad you got it working, I hope I helped some.  I suppose there might be a Windows API call to create a shortcut in the startmenu, I don't know what it would be though.

    If you want, you could create the pif/lnk dynamically.  This would give you highest level access to the file.  Here is a C program that I got off of  Just convert it to java and your on your way...

/* link95.c

Following DOS 16 bit code more or less parses a *.lnk
file as generated by Win9x.  I post it cause someone
asked about the format of *.lnk files, and I haven't
seen anything about this anywhere before.  Likely someone
has done a more complete job and I just don't know about
it!  Please let me know if this is useful, or you know
the complete solution.

2/24/99 revisite, rename previous version link95a.c
   Note see win95\resource.lzh:shortcut.exe, got somewhere
   (probably Microsoft) dumps shortcuts

16 bit code for parsing win95 *.lnk files
    Used MSC 6.0  (ie WORD => unsigned short => 2 bytes)

Much of data in file still unknown, of initial 0x4C bytes in
*.lnk file, much is constant but there is variability from
one file to the next.  Can parse to the descriptive strings
at the end of the file with following:

On my machine, a dump at the beginning of the file always looks
the same up through offset 0x13:
   00000: 4C 00 00 00  01 14 02 00  00 00 00 00  C0 00 00 00
   00010: 00 00 00 46  
Next byte in file varies, probably a bitmap per below.

Following the header at offset 0x4C in file is a two byte word
which is the length of 1st variable length block.
This length is # bytes to skip to reach next block or 0.
If zero block is empty?  Skip bytes read to next length.
The block length includes the two bytes in the length word!

CAUTION, following seems to be true but always?
There are 3 such blocks (including zeros for empty blocks).

Then a string space starts (its organized slightly differently).
Each two byte (word) length is the number of bytes in string
which follows the word.  There are no NUL terminators, if
desired you must add them.  It appears this region is always
terminated by two words, both equal to zero.  I think one
could read till found first string block of zero length.
This is the end of the useable data in the file.

The byte at offset 0x14 in file seems to identify
the individual blocks and strings included in file.
I define the following bitmaps, each bit indicates
a different function and associated block or string.

Look at low nibble for blocks of data as follows (probably):
1 => ?  occurs but meaning escapes me, see com114~1.lnk
2 => target program, see compus~1.lnk with above
4 => ?  have never even seen this
8 => path componets, see notepad.lnk & cdplay~1.lnk
     note also forces an extra string!

In addition to bit 4 (mask value 8) of low nibble
Look at the high nibble for strings.  It is a bitmap
of which strings are expected in the order shown below.
looking at magic # byte at 0x14

0x10 => working directory
0x20 => arguments for program
0x40 => icon file name
per above if low nibble & 8, 1st string is
    The path to *.exe relative to current location of *.lnk

One expects any combination of bits above with 1 to 4
strings possible.
Interesting in that strings do not appear to be in unicode!

Now it gets pretty vague.  I don't fully understand
the various blocks, and almost nothing in the header.
Not clear why strings should be arranged differently than
data blocks.  In particular why do block length differently
and why have empty block if bit map tells us which ones
are there?  The bit map concept is just a guess for the
data blocks, but seems to work for the strings so logical.
Maybe one is supposed to use bitmap info also, only thing
I've done for verification is:

If ( (low nibble of byte at 0x14) & 0x2)
    shortcut.exe says there is a target, otherwise none

In general each block is made up from a number of sub
blocks.  Each two byte word at the begining of a block defines
the sub block length.  The blocks do NOT seem to occur in order
of their bit map value, target type 2 always last:
Type     description
8       1st sub block is 0xE unknown bytes
        Each additional sub block is one level in path spec.
        ie 2nd is drive, remainder are nodes in path
        or file name at end of block.  Per above if this
        exists, 1st string below seems to be relative path to
        program from location of *.lnk file.

2       This contains the full path to the target program.
        Starts with 0x2D unknown bytes, followed by a
        null terminated path to the program at offset 0x2d.
        WARNING in general above is true, but a couple of my
        shortcuts just had "C:\" at this offset,
        then another sub block, then the rest of the path
        in a third sub block.
        This occurs if the fifth word in block is 0x3
        rather than 0x1.  Seems to give local path and
        network path.  See code below.

I'd like this to be a little cleaner, I don't love Microsoft,
but to have two different methods of storing data in the same
little file seems odd.  Likely I overcomplicated things somewhere,
but don't see it.  If you do let me know!

#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>

#define BUFSZ 512    // global working buffer in case needs to be big
char buf[BUFSZ];
#define HEADSZ 0x4c  // don't know what is in here! only identified two bytes

main(int argc, char *argv[])
    unsigned char tndx,tmask,head[HEADSZ];
    long flen,len=0L;
    char *type,*str;
    int i,fp,rd,cnt=0,scnt=0;
    unsigned *uptr,sz=0x4c; /* fixed size of initial region */
    if(argc < 2)
         printf("\nusage: link95 <filename>\ndisplays link info");
         exit (1);
    if((fp = open(argv[1],O_RDONLY|O_BINARY)) == EOF)
         printf("\nfailed to open: %s",argv[1]);
    else if (read(fp,head,HEADSZ) != HEADSZ)
         printf("\nfailed to read a header of length %x (hex) bytes)",
    len = HEADSZ;
    flen = filelength(fp);
    while(cnt < 3 && (rd = read_block(fp,buf,BUFSZ)) >= 0)
         if(rd == 0)
              len+= sizeof(unsigned); // empty block
              len += rd; // size of block, includes unsigned
         str = "None";
         type = NULL;
              /* hopefully I'll know what other blocks are some day...
                 my experience has been that if there is a 3rd data block
                 which isn't empty, its the Target block associated
                 with bit 0x2.  Maybe there is an id embedded in the
                 blocks, but I don't see it...
              case 3:
                 uptr = (unsigned *) &buf[0];
                 // should I be checking for an 0x2 in bitmap?
                 type = "Target";
                 if(rd > 0x2d)  // 0x2d == *(uptr+6)
                    str = buf+0x2d; // display absolute path string
                    // above works for me but could be variable offset ie
                 printf("\n%s: %s",type,str);
                 // CAUTION not always as simple as above
                 if(*(uptr+4) >= 3 && *(uptr+12) < rd)
                 {  // skip over computer name to create local target
                    printf("%s",buf + *(uptr+12));

    if((head[0x14] & 8))
    { /* if bit set then had a data block above and
         first string should be extra relative path.
         Note that shortcut.exe does NOT display this string
        if((rd = read_string(fp,buf,BUFSZ)) <= 0)
            printf("\nNo strings found");
            printf("\nrelative path string: %s",buf);
            len += sizeof(unsigned) + rd; // word + strlen was read

    tmask = head[0x14] >> 4; // high nibble of byte
    // check all three possible states
    for(tndx = 1;len < flen && tndx <= 4;)
         {  // the following match shortcut.exe output
              case 1:
                   type ="Working directory";
              case 2:
                   type ="Arguments";
              case 4:
                   type = "Icon file";
         if(tndx & tmask)
             // there should be another string
             if((rd = read_string(fp,buf,BUFSZ)) <= 0)
                  printf("\nerror reading string");
                  len += sizeof(unsigned) + rd; // word + strlen was read

         tndx = tndx << 1;
         printf("\n%s: %s",type,buf);
    printf("\nread %ld bytes out of %ld in file",len,flen);

/* each block starts with an unsigned word
   may contain nested block
   or word may be zero, in this case block empty, just
   advance 2 bytes for this word
   word read at start of block is returns, ie 0 for empty block
read_block(int fp,unsigned char *buf,unsigned msz)
    int rd,sz;
    unsigned *uptr = (unsigned *)buf;
    if(msz < sizeof(unsigned) ||
       read(fp,buf,sizeof(unsigned)) != sizeof(unsigned))
    else if(*uptr > msz)
    sz = *uptr - sizeof(unsigned); // additional to read in
    if(sz > 0 && read(fp,buf+sizeof(unsigned),sz) != sz)
         return(*uptr);  // bytes read

/* file ends with a series of strings, logic is similar to
   above, but length is # chars in string, and they aren't nul
   terminated, I append a NUL to make printing easier if it fits
   Note I'm NOT putting len in buffer this time, want a string
read_string(int fp,unsigned char *buf,unsigned msz)
    int rd,sz;
    if(read(fp,&sz,sizeof(unsigned)) != sizeof(unsigned))
    else if(sz > msz)
    if(sz > 0 && read(fp,buf,sz) != sz)
         if(sz >= 0 && sz < msz)
              buf[sz] = 0;
         return(sz);  // bytes read into string buffer, ie its length
Hi Igor,

Here is the script-code that I was talking about.

  This scriptfile creates a shortcut in the Start Menu

  // general variables
  var WSHShell = WScript.CreateObject("WScript.Shell");
  var WshSysEnv = WSHShell.Environment("Process");
  var fso =new ActiveXObject("Scripting.FileSystemObject");
  var scName = "Start MyApplication";
  var scFolder=getStartMenuPath()+"\\MyApplication";
  if (!(fso.FolderExists(scFolder)))

  var programPath="C:\\Program Files\\MyApplication";
  var iconIndex = 0;

  var MyShortcut = WSHShell.CreateShortcut(scFolder  +"\\"+ scName + ".lnk");
  MyShortcut.TargetPath = programPath + "\\MyApplication.exe";
  MyShortcut.Arguments = "/arguments";
  MyShortcut.WorkingDirectory = programPath;
  MyShortcut.WindowStyle = 4;
  MyShortcut.IconLocation = programPath + "\\MyApplication.exe, "+ iconIndex;

function getStartMenuPath()
  var StartMenuPath = "";
  if (WshSysEnv("OS") == "Windows_NT")
    StartMenuPath = WSHShell.SpecialFolders("AllUsersPrograms");
  } else
    StartMenuPath = WSHShell.SpecialFolders("Programs");

function End()
ADMINISTRATION WILL BE CONTACTING YOU SHORTLY.  Moderators Computer101 or Netminder will return to finalize these if still open in seven days.  Please post closing recommendations before that time.

Question(s) below appears to have been abandoned. Your options are:
1. Accept a Comment As Answer (use the button next to the Expert's name).
2. Close the question if the information was not useful to you. You must tell the participants why you wish to do this, and allow for Expert response.
3. Ask Community Support to help split points between participating experts, or just comment here with details and we'll respond with the process.
4. Delete the question. Again, please comment to advise the other participants why you wish to do this.

For special handling needs, please post a zero point question in the link below and include the question QID/link(s) that it regards.
Please click the Help Desk link on the left for Member Guidelines, Member Agreement and the Question/Answer process.

Please click you Member Profile to view your question history and keep them all current with updates as the collaboration effort continues, to track all your open and locked questions at this site.  If you are an EE Pro user, use the Power Search option to find them.

To view your open questions, please click the following link(s) and keep them all current with updates.

------------>  EXPERTS:  Please leave any comments regarding your closing recommendations if this item remains inactive another seven (7) days.  Also, if you are interested in the cleanup effort, please click this link
Thank you everyone.
Moderator @ Experts Exchange

P.S.  For any year 2000 questions, special attention is needed to ensure the first correct response is awarded, since they are not in the comment date order, but rather in Member ID order.
calvinrsmithAuthor Commented:
please close as I figured it out by myself
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.