3

I am trying to get my app create a shortcut on the desktop. The reason is because my app has some dependencies such ass external dlls and other and I prefer to have it in a folder and simply have a shortcut on my desktop rather than having all the files on my desktop or a folder containing everything.

It's the first time I am trying this. I believed it was simple and indeed it is so sorry if my question is a bit nooby. My simple code looks like this:

string checkDesktopDir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
if (!File.Exists(checkDesktopDir + "\\My app.url"))
    {
        ShortCutWithDependencies("My app");
    }   
private void ShortCutWithDependencies(string sAppName)
    {
        string deskDir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

        using (StreamWriter writer = new StreamWriter(deskDir + "\\" + sAppName + ".url"))
        {
            string app = Assembly.GetExecutingAssembly().Location;
            MessageBox.Show(app);
            writer.WriteLine("[InternetShortcut]");
            writer.WriteLine("URL=" + app);
            writer.WriteLine("IconIndex=0");
            string icon = app.Replace('\\', '/');
            writer.WriteLine("IconFile=" + icon);
            writer.Flush();
        }
    }

However my app will never work. As soon as it get to the part it will need the dependencies to continue it will crash. More specific, when I use the methods imported via DLLImport such as bass.dll methods, it will simply crash. Of course I can't see anything in my output since the shortcut is a compiled .exe.

So my question is this; how do I create a full shortcut of my application?

Edit: updating example of dllimport

        [DllImport("bass.dll")]
        public static extern bool BASS_Start();
        [DllImport("bass.dll")]
        public static extern bool BASS_Init(int device, uint freq, uint flag,
             IntPtr hParent, uint guid);

        if (mp3ToPlay != string.Empty)
                            {
                                BASS_Start();
                                BASS_Init(-1, 44100, 0, IntPtr.Zero, 0);
                                BassHandle = BASS_StreamCreateFile(false, mp3ToPlay, 0, 0, 0x20000);
                                BASS_ChannelPlay(BassHandle, false);
                                PlayBackLength = BASS_ChannelGetLength(BassHandle, 0);
                                PlayBack = true;
                            }

Now I believe this is the problem. I am not sure though. The external dlls (bass.dll, Newtonsoft.Json.dll and Spotify.dll) have Copy to output directory set as Copy always and they are copied. The .exe will run fine and a shortcut created and sent to desktop manually will run fine as well.

Edit: Update 2 with Federico's example Now this will work:

private void CreateShortcut()
        {
            object shDesktop = "Desktop";
            WshShell shell = new WshShell();
            string shortcutAddress = (string)shell.SpecialFolders.Item(ref shDesktop) + @"\iBlock.lnk";
            IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutAddress);
            shortcut.Description = "New shortcut for a iBlock";
            shortcut.Hotkey = "Ctrl+Shift+N";
            shortcut.TargetPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + @"\iBlock\iBlock.exe";
            shortcut.Save();
        }

However there is a glitch here. This part of my code

public string mp3Path = Directory.GetCurrentDirectory() + "\\mp3Directory";

if (!System.IO.File.Exists(mp3Path))
            {
                Directory.CreateDirectory(mp3Path);
            }

Changing it to AppDomain.CurrentDomain.BaseDirectory will easily fix it.

user2530266
  • 287
  • 3
  • 18
  • It's not clear what the problem is. Where are those dependencies located? How do you load them? – Evk Apr 01 '16 at 20:59
  • They are external dlls. I am calling them via DLLImport. Some are located in the apps location and others in a subfolder of the same location. – user2530266 Apr 02 '16 at 03:18
  • @user2530266 I reckon, if you create shortcut manually and try to run it, you will have the same behaviour. – Valentin Apr 03 '16 at 20:52
  • Can you show exactly how you use DllImport with dependency dll which does not work? – Evk Apr 03 '16 at 20:57
  • 3
    You must stop guessing at the problem. Every .NET programmer eventually discovers that writing an event handler for AppDomain.CurrentDomain.UnhandledException is **not** optional. – Hans Passant Apr 03 '16 at 21:56
  • @HansPassant I always have an event handler on my projects but I never wrote one for C# projects. Don't know why. I'd rather have my .exe crash than have an stupid mbox telling me why. I guess I am lazy. Will keep your tip in mind. – user2530266 Apr 04 '16 at 15:43

2 Answers2

2

Try creating the shortcut using the native COM Windows API, as explained in this answer: https://stackoverflow.com/a/4909475/3670737

At first, Project > Add Reference > COM > Windows Script Host Object Model.

using IWshRuntimeLibrary;

private void CreateShortcut()
{
    object shDesktop = (object)"Desktop";
    WshShell shell = new WshShell();
    string shortcutAddress = (string)shell.SpecialFolders.Item(ref shDesktop) + @"\Notepad.lnk";
    IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutAddress);
    shortcut.Description = "New shortcut for a Notepad";
    shortcut.Hotkey = "Ctrl+Shift+N";
    shortcut.TargetPath = Environment.GetFolderPath(Environment.SpecialFolders.System) + @"\notepad.exe";
    shortcut.Save();
}

[Edit 1] Updated after Directory.GetCurrentDirectory() issue:

From the documentation: The current directory is distinct from the original directory, which is the one from which the process was started.

Your expected directory differs from the one returned by Directory.GetCurrentDirectory() because you actually start your process from a different directory when you use a shortcut (your Desktop). Directory.GetCurrentDirectory() returns the current working directory, which is the same of your assembly if you start it by opening the .exe file, but is the shortcut directory if you start it from the .lnk file.

In your scenario I'd use Assembly.GetExecutingAssembly().Location (check this answer for more info: https://stackoverflow.com/a/837501/3670737 )

Community
  • 1
  • 1
Federico Dipuma
  • 17,655
  • 4
  • 39
  • 56
1

If I understand correctly, it sounds like you might be better off just making an installer for your application. You can do this through Visual Studio, and it pretty much automates the process for you. Additionally, you might could try making your program a ClickOnce application with dependencies. I'd personally take the latter option.

I realize this isn't an especially thorough answer, but I feel like the question is a little unclear.

wisner
  • 523
  • 1
  • 5
  • 18