Shortcut with a relative path breaks my program

I am not sure that this is a programming problem so much as a Windows problem, but figure it cannot hurt to ask.

My program uses Qt and as far as I can tell I cannot use static linking to distribute it. As an alternative I planned to add a shortcut in the root folder so the user does not have to dig around looking for the .exe. I can change the shortcut to use a relative path easy enough and it starts up fine. This appears to break the path to files though.

Case in point; File>open opens a dialog that has a combobox that is populated from a file, however the file does not open and the combobox therefor does not get filled. Because this is only a problem using the shortcut, I cannot run it in a debugger. Any ideas or suggestions would be appreciated.
The first thing I would check would be that the shortcut has the "starting folder", or whatever it's called, is set correctly. This field sets the initial working directory for the new process, so it can affect hard-coded relative paths, DLL loading, etc.
I had a feeling that was the problem. I have the target set to

%windir%\explorer.exe "..\..\mpgBuddy 1.0b\release\mpgBuddy_3.exe"

and the "start in" location set to nothing. If I change the "start in" location "relative" to target, which would be

%windir%\explorer.exe "..\..\mpgBuddy 1.0b\release

if I follow what is in the original shortcut, I still have the same problem. I never looked into how processes function very much, if at all so it sounds like that is where I need to at least, thanks.
Why the shortcut contains "%windir%\explorer.exe" ? This is very unusual as shortcut files (.lnk) are already understand only by windows explorer, there is no need to spawn another explorer.exe process which in turn launch your desired EXE.
When I first create the shortcut the target is

"H:\mpgBuddy 1.0b\release\mpgBuddy_3.exe"

which is an absolute path and will not work if I move the .exe to another location on the same computer let alone to another computer as would be the case with distributing the program or running it from a thumb drive. The only other alternative I found was to use cmd.exe instead of explorer.exe, but I do not see that making a difference in solving my issue.
will not work if I move the .exe to another location on the same computer
Nothing will help in that case.

let alone to another computer as would be the case with distributing the program or running it from a thumb drive
In the first case, the only solution is to make an installer. In the second case, the shortcut would have to use a rooted path with no unit ("\*", not "?:\*").
Last edited on
I am not sure I understand that? I tried creating a new file (which a new use would have to do before the program could be used) and it works fine. The problem is that the new files are created in C:\Windows\SysWOW64 which is not acceptable and still would not allow it to be portable anyway.

Just to clarify a couple things, when I said move the .exe I meant the folder not just the .exe and using an installer would not allow it to be portable.

I might try using the cmd.exe approach as described here:
http://answers.microsoft.com/en-us/windows/forum/windows_vista-files/how-to-create-a-shortcut-with-relative-path/3e1b0ede-1e18-4ecd-937b-66756d3409d3
but that looks like I will still have the same problem with "start in". The only other solution I have found is this: http://www.csparks.com/Relative/
but once again that looks like it will not work for making it portable.
Portability and shortcuts are very often mutually exclusive.
So in other words, I am out of luck without compiling statically.
As far as DLLs are concerned. If the program uses other resources that are also found relative to itself, you're still going to have problems, although <edit>once</edit> main() has been called it's possible to move the working directory to the path that contains the main executable. But that's only after main() has been called. A possibility might be to use a bootstrapping program that sets the working directory relative to itself and then runs the main program.
Last edited on
Sorry to come to this late. Windows shortcuts only work with absolute pathnames. So your program's installer will have to create the correct shortcut, as helios suggested.

Hope this helps.
Last edited on
Thanks guys, I am not so sure that you understood my intent after reading those last replies. I do not want to use an installer, all I wanted was a way for the user to be able to start the program from the root folder instead of having to go into release and find the .exe among all the files there.
My suggestion doesn't imply an installer.
Use a simple wrapper called launcher.exe that is the only EXE the user sees in root directory compiled statically, very small and which launches automatically your main Qt program calling CreatingProcess and detecting automatically in which directory is running.

This is a sample code for your launcher.exe program:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <tchar.h>
#include <windows.h>
#include <shlwapi.h>

BOOL PathRemoveFileSpecNew(LPTSTR path)
{
    LPTSTR newPath = PathFindFileName(path);
    if( (newPath) && (newPath != path) ) {
        newPath[0] = TEXT('\0');
        return 1;
    }
    return 0;
}

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{

    TCHAR exePath [MAX_PATH + 1];
    GetModuleFileName (GetModuleHandle (NULL), exePath, MAX_PATH);
    PathRemoveFileSpecNew ( exePath );
    TCHAR exeFullPath [MAX_PATH + 100]; // be carefully here
    strcpy (exeFullPath, exePath);
    strcat (exeFullPath, TEXT ("Release\\MyProgram.exe"));
    strcat (exePath, TEXT ("Release"));
    DWORD dwCreationFlags = 0;
    #if defined (UNICODE)
    dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
    #endif // defined

    STARTUPINFO si = {0};
    si.cb = sizeof (STARTUPINFO);
    PROCESS_INFORMATION pi;

    if (!CreateProcess (exeFullPath, NULL, NULL, NULL, FALSE, dwCreationFlags, NULL, exePath, &si, &pi)) {
        MessageBox (NULL, TEXT ("CreateProcess Failed!"), TEXT ("Error"), MB_OK);
    }

    // Close process and thread handles.
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );


    return 0;
}

@helios
No, but I did not understand it either unless it was similar to what modoran posted.

I am not familiar with winapi at all so it is likely to take me a while to figure that out, but it looks promising.
Yeah, that's basically what I had in mind.
Cool, I am trying to figure out where to start looking to understand it. This is a busy week for me so like I said, I probably will not get very far until next week.
Topic archived. No new replies allowed.