Solved

Create shortcut on desktop

Posted on 2000-04-18
29
1,315 Views
Last Modified: 2013-11-20
Here's another "how to create a shortcut" question.
I've seen a lot of them in EE and I found a good site at codeguru:
http://www.codeguru.com/shell/filelinks.shtml

Though, I'd like to have the code modified so I can use it (almost) without any changes ;)

Here's what it should do:
My exe will be downloaded from the internet.
The first time it is started on the client's machine (WIN), a shortcut will be created on the desktop.
Of course the current path of the exe must be retrieved, since I don't know where the client saved it on the HD.

I'd like to get source code instead of pointing me to "helpful" resources.
Let me know if you need more details.

Best regards and thanks beforehand
-Stavi-
0
Comment
Question by:mitrakis
  • 14
  • 12
  • 2
  • +1
29 Comments
 
LVL 11

Expert Comment

by:mikeblas
ID: 2728025

This code does what you ask for, though it'll do it every time your app is run. You can call it only once--just set a flag in your registry hive, or in an INI file, or something.


-- begin file linky.cpp --


// compile with
//    cl /W4 linky.cpp

#include <windows.h>

#include <shellapi.h>
#include <shlguid.h>
#include <shlobj.h>

#include <stdio.h>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "shell32.lib")

void main()
{
   // get the name and path to our executable.
   char szExecutable[_MAX_PATH];
   GetModuleFileName(NULL, szExecutable, _MAX_PATH);

   // get the location of the desktop folder path
   char szLinkTarget[_MAX_PATH * 2];
   if (!SHGetSpecialFolderPath(NULL, szLinkTarget, CSIDL_DESKTOP, FALSE))
   {
      printf("Couldn't get desktop folder location!\n");
      return;
   }

   // after the path name, add a real file name
   strcat(szLinkTarget, "\\MyFile.lnk");

   printf("%s\n", szLinkTarget);

   CoInitialize(NULL);

   // get the shell manager's link object

   IShellLink* pShellLink = NULL;
   HRESULT hRes = CoCreateInstance(CLSID_ShellLink, NULL,
      CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*) &pShellLink);

   if (SUCCEEDED(hRes) && pShellLink != NULL)
   {
      // set the path and description on that object
      pShellLink->SetPath(szExecutable);
      pShellLink->SetDescription("Sample Description!");

      // then, ask that object to save itself into the desktop
      // folder with the name we built before

      IPersistFile* pPersistFile = NULL;
      hRes = pShellLink->QueryInterface(IID_IPersistFile,
         (LPVOID*) &pPersistFile);

      if (SUCCEEDED(hRes) && pPersistFile != NULL)
      {
         // Save needs the name as wide characters

         WCHAR wszDesktopPath[_MAX_PATH * 2];
         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szLinkTarget, -1,
            wszDesktopPath, _MAX_PATH * 2);

         printf("%S\n", wszDesktopPath);

         // dot the save!
         hRes = pPersistFile->Save(wszDesktopPath, TRUE);
         if (FAILED(hRes))
            printf("PersistFile::Save failed!\n");
         pPersistFile->Release();
      }
     
      pShellLink->Release();
   }
   else
   {
      printf("Couldn't create shell link object!\n");
   }

   CoUninitialize();
}

-- end file linky.cpp --

..B ekiM
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2729698
Should this work under NT ?
I get a whole bunch of errors in "shlguid.h" as soon as "shlguid.h" is included.
All the other headers are included flawlessly.

Regards
-Stavi-
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2729737
Sorry...had to include "objbase.h", too...now it compiles without errors.
I'll let you kow how it goes.

-Stavi-
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2729801
Well, compiled w/o errors but not executable.
The following error occurs when executing my app:

**Couldn't find entry point "SHGetSpecialFolderA" in DLL "Shell32.dll"**

after confirmation, another error occurs:

**Not executable: Path not found (Win32-error 3)**

Any ideas ?

-Stavi-

P.S.:
App should work on WIN9x, NT, 2000
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2729856
Hmm...it seems that I need shell32.dll version 4.71 or higher (requires MSIE4 desktop update).
I cannot assume that all my clients will have this version installed...

Any other workarounds to get this thing working would be greatly appreciated.

Best regards
-Stavi-
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2729907
It's me again, sorry.
How about forcing the EXE to create a new folder and copy itself therein.

This way, I don't have to retrieve the current path, but I can copy it to my defined location and create a shortcut to the now known path ?
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2731496

I don't know why the program didn't build for you. From the command line, building the file as-is, I had no problems. I'm using VC++ 6.0 with no SP's installed.

Indeed, SHGetSpecialFolderPath() is a helper function that's only available after a full install of IE 4 (or newer). It's possible that a target system won't have it. But, it's possible to recreate the functionality of the API with other APIs that are always available. I've done that for you and shown the code below--note the #else side of the #ifdef.

Your other alternative is to find SHFOLDER.EXE in the latest Platform SDK and use it to distribute SHFOLDER.DLL. SHFOLDER.DLL contains a shell version independent implementation of SHGetSpecialFolerPath. The Platform SDK has the header and LIB for the API and and the import library for it, too.

Here's the code:

-- begin file linky2.cpp --

// compile with
//    cl /W4 linky2.cpp

#include <windows.h>

#include <shellapi.h>
#include <shlguid.h>
#include <shlobj.h>

#include <stdio.h>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "shell32.lib")

void main()
{
   // get the name and path to our executable.
   char szExecutable[_MAX_PATH];
   GetModuleFileName(NULL, szExecutable, _MAX_PATH);

   char szLinkTarget[_MAX_PATH * 2];

#ifdef AGGRESSIVE
   // get the location of the desktop folder path
   if (!SHGetSpecialFolderPath(NULL, szLinkTarget, CSIDL_DESKTOP, FALSE))
   {
      printf("Couldn't get desktop folder location!\n");
      return;
   }
#else
   LPMALLOC pMalloc;
   if (FAILED(SHGetMalloc(&pMalloc)))
   {
      printf("Can't continue: no SHMalloc available!\n");
      return;
   }

   ITEMIDLIST* itemIDList;
   if (SUCCEEDED(SHGetSpecialFolderLocation(NULL,
      CSIDL_DESKTOP, &itemIDList)))
   {
      SHGetPathFromIDList(itemIDList, szLinkTarget);
      pMalloc->Free(itemIDList);
   }
   else
   {
      pMalloc->Release();
      printf("Couldn't get desktop folder location!\n");
      return;
   }

   pMalloc->Release();
#endif

   // after the path name, add a real file name
   strcat(szLinkTarget, "\\MyFile.lnk");

   printf("%s\n", szLinkTarget);

   CoInitialize(NULL);

   // get the shell manager's link object

   IShellLink* pShellLink = NULL;
   HRESULT hRes = CoCreateInstance(CLSID_ShellLink, NULL,
      CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*) &pShellLink);

   if (SUCCEEDED(hRes) && pShellLink != NULL)
   {
      // set the path and description on that object
      pShellLink->SetPath(szExecutable);
      pShellLink->SetDescription("Sample Description!");

      // then, ask that object to save itself into the desktop
      // folder with the name we built before

      IPersistFile* pPersistFile = NULL;
      hRes = pShellLink->QueryInterface(IID_IPersistFile,
         (LPVOID*) &pPersistFile);

      if (SUCCEEDED(hRes) && pPersistFile != NULL)
      {
         // Save needs the name as wide characters

         WCHAR wszDesktopPath[_MAX_PATH * 2];
         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szLinkTarget, -1,
            wszDesktopPath, _MAX_PATH * 2);

         printf("%S\n", wszDesktopPath);

         // dot the save!
         hRes = pPersistFile->Save(wszDesktopPath, TRUE);
         if (FAILED(hRes))
            printf("PersistFile::Save failed!\n");
         pPersistFile->Release();
      }
     
      pShellLink->Release();
   }
   else
   {
      printf("Couldn't create shell link object!\n");
   }

   CoUninitialize();
}

-- end file linky2.cpp --

..B ekiM
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2731502
> How about forcing the EXE to create a new folder and copy itself therein.

If you want, you can do that.  But that's a different question than the one I've answered for you.

 > This way, I don't have to retrieve the current path, but I can copy it to
 > my defined location and create a shortcut to the now known path ?

Sure, you could. The shortcut creation code is exactly the same--just pass a folder name in for the path instead of an executable name when you call pShellLink->SetPath().

..B ekiM
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2733578
I get the same error as already posted before.
Why do I get the error "Cannot find SHGetSpecialFolderPathA in DLL" although I don't use this func in my app at all ?

Mike, I don't know why it works for you and not for me...as I said, it builds without problems, but execution fails due to the outdated shell32.dll (missing entry point).

I just copied your code and pasted it into a new function called "CreateShortCut()" so this cannot be a problem.

Best regards
-Stavi-

P.S.:
Yes, you're right. I should post a new Q when requesting "new" things, but if this one doesn't work, I need an alternative, definitely.
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2734910
> Why do I get the error "Cannot find SHGetSpecialFolderPathA in DLL"  > although I don't use this func in my app at all ?

Obviously, your app really does reference the function even though, for some reason, you think it doesn't.  The code I show doesn't reference it, and I am certain of that.

 > I don't know why it works for you and not for me

Me, either. Obviously, you're making some mistake. Maybe you're running the wrong EXE, or your build failed and you didn't notice and you're running an old EXE.  It's impossible for me to tell exactly what's happening to you without seeing your machine.

 > I just copied your code and pasted it into a new
 > function called "CreateShortCut()" so this cannot be a problem.

Since you're running lots of other code besides what I gave you (that is, I have no idea what's going on in the rest of your app), I can't help you unless you give me the whole project.  The code I gave you is completely self-contained an can be run as a standalone program. You should try doing that, as that was the intent of providing such a complete example.

..B ekiM

0
 
LVL 3

Author Comment

by:mitrakis
ID: 2739778
Mike,

my app does nothing than an automatic RAS dialup to a RAS server, opens the default browser and shows a given HTML file.

I never included shellapi.h, shlguid.h, shlobj.h or objbase.h before so the fault is not on my side.
Have no idea why "SHGetSpecialFolderPathA" is causing an error although I don't use it.

If it works on your side, it seems you have the right shell32 version installed, regardless if you use it as standalone program or as function (like I do).
As I said, I cannot assume that all potential clients (which use my app) will have shell32.dll (>= v4.71) installed.

I really appreciate your help but I need to get it to work.
Let me know if the Q is getting "hard" to increase credits for you...

Best regards and happy eastern
-Stavi-
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2740321

 > Have no idea why "SHGetSpecialFolderPathA" is causing an error although I don't use it.

Then, how can you blame my code? Your stubborness is becoming insulting.

Your program is causing an error because something in your code is using that API, either directly or indirectly. These errors don't happen for random reasons. They happen for very deterministic reasons. If you dumpbin -imports on your executable, you'll find that it really does reference that function.

Please, I'm begging you now. Build the code that I gave you, exactly as I've given it to you. Just copy it to a file and run the compiler on it from the command-line. It works around the issue of SHGetSpecialFolderPath() not being available on some systems, and won't cause the "SHGetSpecialFolderPathA" error no matter where it is run. That's simply because the code _doesn't reference that API_, period!

How can you possibly conclude that the problem is on my end when you're not even running the code that I gave you?  The problem is on your end, with the code you're running. I can't even _see_ that code.

On Windows NT, the code I originally supplied would fail; I don't have the updated shell DLL on my test machine, either. If you dumpbin -imports (or run Depends) on the executable that my second source file products, you'll find it no longer references SHGetSpecialFolderPath().

I can't tell you why your code references the API because I haven't seen your code. My code works, your code doesn't. How can the problem be on my end, then?

..B ekiM
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2740342
.. or do you want to send me your project so I can figure it out for you?

..B ekiM
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2785620
Never had the intention to jump on you !

Though, in my opinion it's not always fair to state "it's your fault" without accepting any other point of views.

I'd appreciate if you have a look at my project.
Don't be surprised...much things are coded quite "unusal" ;-)

Get it from here:
http://www.mitrakis.de/uploads/dialer.zip

The code you'll get is without any desktop or shell stuff.
So, this is the version I had *before* posting this question herein.

I'd love it to see this app generating a shortcut on my desktop. Note, that I don't know where the user will save the EXE to.

Best regards
-Stavi-
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 3

Author Comment

by:mitrakis
ID: 2788733
Sorry...not solved yet.

Regards
-Stavi-
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2854594
I don't see any code to generate a desktop shortcut in the project you've posted at that URL.

When I build the applications, they don't import SHGetSpecialFolderLocationA().

..B ekiM
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2855095
Hello Mike,

My comment from May 07:
>>The code you'll get is without any desktop or shell stuff.
>>So, this is the version I had *before* posting this question herein.

I never fiddled around with shortcuts in my app before posting this question herein.
After getting your shell code above I simply cut'n pasted it into my project.
Calling the now new function CreateShortCut() should do what I've requested.
....but it didn't.

If you want me to give you my project *with* your code added let me know and I'll do so.

Best regards and thanks for getting back to me
-Stavi-
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2866104
I'm lost. What's the problem?

..B ekiM
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2866849
In other words:

I asked for code to be able to create a shortcut on the desktop programmatically, as soon as my app is executed by the user.

Right before, my app did nothing than creating a phone book entry (DUN), dial a predefined number (calling a RAS server), start the user's standard browser and load a default website.

I want to offer this app on internet, so newbies can just download this app, double-click it, a shortcut will be created on their desktop, and they're connected to the specified site directly.

When you gave me the above code for shortcut creation, I added this code to my project and it didn't work (see my previous comments).

You told me that the code worked for you when using at as a stand-alone project.
Since I had to put it in my project, I created a new function named "CreateShortCut()" and cut'n pasted your code therein.
I called this function in OnInit() but I got errors when executing it (see my comments).

So I decided to send you my project without the shortcut stuff and hoped you can have a look at it or maybe you could add your code into my project so it will work as expected (-> create a desktop shortcut on first execution).

Using your code always resulted in "Cannot find SHGetSpecialFolderPathA in DLL" although this func is not referenced in your code example at all.

Since you asked for my project, I've sent it to you.
Thanks for your patience
-Stavi-
0
 
LVL 1

Accepted Solution

by:
TimB earned 100 total points
ID: 2913702
Here's a .cpp file:






// Shortcut.cpp : implementation file
//

#include "stdafx.h"
#include "Shortcut.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CShortcut
CShortcut::CShortcut()
{
    // Initialize data members
    m_bDirty           = FALSE;
    m_strPath          = _T("");
    m_strTarget        = _T("");
    m_strStartDir      = _T("");
    m_strDescription   = _T("");
    m_strIconLocation  = _T("");
    m_strArgs          = _T("");
    m_nIconIndex       = 0;
    m_wHotkey          = MAKEWORD((BYTE) 0, (BYTE) 0);
    m_nShowCmd         = 0;
    HICON m_hLargeIcon = NULL;
    HICON m_hSmallIcon = NULL;
}

CShortcut::CShortcut(LPCTSTR lpsz, BOOL bFill)
{
    // Initialize data members
    m_bDirty           = FALSE;
    m_strPath          = lpsz;
    m_strTarget        = _T("");
    m_strStartDir      = _T("");
    m_strDescription   = _T("");
    m_strIconLocation  = _T("");
    m_strArgs          = _T("");
    m_nIconIndex       = 0;
    m_nShowCmd         = 0;
    m_wHotkey          = MAKEWORD((BYTE) 0, (BYTE) 0);
    HICON m_hLargeIcon = NULL;
    HICON m_hSmallIcon = NULL;

    // Fill data
    if (bFill)
    {
        FillData();
    }
}

CShortcut::~CShortcut()
{
    ASSERT(m_bDirty == FALSE);
}

#ifdef _DEBUG
void CShortcut::Dump(CDumpContext& dc)
{
    CObject::Dump(dc);

    dc << _T("\nm_bDirty = ")          << m_bDirty
       << _T("\nm_strPath = ")         << m_strPath
       << _T("\nm_strTarget = ")       << m_strTarget
       << _T("\nm_strStartDir = ")     << m_strStartDir
       << _T("\nm_strDescription = ")  << m_strDescription
       << _T("\nm_strIconLocation = ") << m_strIconLocation
       << _T("\nm_strArgs = ")         << m_strArgs
       << _T("\nm_nIconIndex = ")      << m_nIconIndex
       << _T("\nm_wHotkey = ")         << m_wHotkey
       << _T("\nm_nShowCmd = ")        << m_nShowCmd
       << _T("\nm_hLargeIcon = ")      << m_hLargeIcon
       << _T("\nm_hSmallIcon = ")      << m_hSmallIcon
       << _T("\n");
}
#endif // _DEBUG

/////////////////////////////////////////////////////////////////////////////
// Create
// Remarks: Creates a shortcut and saves it
// Inputs:  LPCTSTRs containing full path to file name, full path to target,
//          start directory, description, arguments, icon location, an int
//          containing icon index, a WORD containing hot key, and an int
//          containing show command
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::Create(LPCTSTR lpszPath,     LPCTSTR lpszTarget,
                       LPCTSTR lpszStartDir, LPCTSTR lpszDescription,
                       LPCTSTR lpszArgs,     LPCTSTR lpszIconLocation,
                       int nIconIndex,       WORD    wHotkey,
                       int nShowCmd)
{
    m_bDirty          = TRUE;// Checks an object for changes since it was last saved to its current file. - used in IPersistFile
    m_strPath         = lpszPath;      // the full path and filename of the .lnk file
    m_strTarget       = lpszTarget;// the name of the file the shortcut is aimed at
    m_strStartDir     = lpszStartDir;// Sets the name of the working directory for a shell link object.
    m_strDescription  = lpszDescription;// Sets the description string for a shell link object. The description can be any application-defined string.
    m_strArgs         = lpszArgs;// Command line arguments passed to the app when the shortcut is double clicked
    m_strIconLocation = lpszIconLocation;// Address of a buffer to contain the path of the file containing the icon.
    m_nIconIndex      = nIconIndex; // index of that icon in the binary image
    m_wHotkey         = wHotkey; // Keycode for the hotkey - Setting a hot key allows the user to activate the object by pressing a particular combination of keys.
    m_nShowCmd        = nShowCmd; // whether to start maximized, minimiezd or normal - SW_SHOWMAXIMIZED SW_SHOWMINIMIZED SW_SHOWNORMAL

    return Save();
}

/////////////////////////////////////////////////////////////////////////////
// CreateEx
// Remarks: Creates a shortcut and saves it
// Inputs:  A pointer to a SHORTCUTSTRUCT structure containing initialization
//          data
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::CreateEx(const LPSHORTCUTSTRUCT s)
{
    m_bDirty          = TRUE;
    m_strPath         = s->strPath;
    m_strTarget       = s->strTarget;
    m_strStartDir     = s->strStartDir;
    m_strDescription  = s->strDescription;
    m_strArgs         = s->strArgs;
    m_strIconLocation = s->strIconLocation;
    m_nIconIndex      = s->nIconIndex;
    m_wHotkey         = s->wHotkey;
    m_nShowCmd        = s->nShowCmd;

    return Save();
}

/////////////////////////////////////////////////////////////////////////////
// FileExists
// Remarks: Determines whether a file exists
// Inputs:  LPCTSTR containing full path to file name
// Returns: BOOL; TRUE if file exists, FALSE if file does not exist
BOOL CShortcut::FileExists(LPCTSTR lpsz)
{
    ASSERT(lpsz != NULL);

    WIN32_FIND_DATA wfd;
    HANDLE hFind = ::FindFirstFile(lpsz, &wfd);
    ::FindClose(hFind);

    // Make sure file exists, and that it's not a directory
    return (hFind != INVALID_HANDLE_VALUE &&
        !(wfd.dwFileAttributes && FILE_ATTRIBUTE_DIRECTORY));
}

/////////////////////////////////////////////////////////////////////////////
// TargetExists
// Remarks: Determines whether the target of the link exists
// Inputs:  None
// Returns: BOOL; TRUE if file exists, FALSE if file does not exist
BOOL CShortcut::TargetExists()
{
    // If we have the target, see whether it exists
    return (m_strTarget == _T("") ? FALSE : FileExists((LPCTSTR) m_strTarget));
}

/////////////////////////////////////////////////////////////////////////////
// FillData
// Remarks: Fills all the data members for the shortcut
// Inputs:  None
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::FillData()
{
    BOOL bRet = FALSE;

    // Make sure we have a path
    ASSERT(m_strPath != _T(""));

    IShellLink* psl;
    HRESULT hres;
    LPTSTR lpsz = m_strPath.GetBuffer(MAX_PATH);

    // Create instance for shell link
    hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
        IID_IShellLink, (LPVOID*) &psl);
    if (SUCCEEDED(hres))
    {
        // Get a pointer to the persist file interface
        IPersistFile* ppf;
        hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*) &ppf);
        if (SUCCEEDED(hres))
        {
            // Make sure it's ANSI
            WORD wsz[MAX_PATH];
            ::MultiByteToWideChar(CP_ACP, 0, lpsz, -1, wsz, MAX_PATH);

            // Load shortcut
            hres = ppf->Load(wsz, STGM_READ);
            if (SUCCEEDED(hres))
            {
                // Fill data members
                bRet = (FillTarget(psl)      &&
                        FillStartDir(psl)    &&
                        FillDescription(psl) &&
                        FillArguments(psl)   &&
                        FillIcons(psl)       &&
                        FillHotkey(psl)      &&
                        FillShowCmd(psl));
            }
            ppf->Release();
        }
        psl->Release();
    }
    return bRet;
}

/////////////////////////////////////////////////////////////////////////////
// FillTarget
// Remarks: Fills the m_strTarget data member
// Inputs:  IShellLink*
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::FillTarget(IShellLink* psl)
{
    ASSERT(psl != NULL);
    WIN32_FIND_DATA wfd;
    HRESULT hres = psl->GetPath(m_strTarget.GetBuffer(MAX_PATH), MAX_PATH,
        &wfd, SLGP_UNCPRIORITY);
    m_strTarget.ReleaseBuffer();
    return SUCCEEDED(hres);
}

/////////////////////////////////////////////////////////////////////////////
// FillStartDir
// Remarks: Fills the m_strStartDir data member
// Inputs:  IShellLink*
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::FillStartDir(IShellLink* psl)
{
    ASSERT(psl != NULL);
    HRESULT hres = psl->GetWorkingDirectory(m_strStartDir.GetBuffer(MAX_PATH),
        MAX_PATH);
    m_strStartDir.ReleaseBuffer();
    return SUCCEEDED(hres);
}

/////////////////////////////////////////////////////////////////////////////
// FillDescription
// Remarks: Fills the m_strDescription data member
// Inputs:  IShellLink*
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::FillDescription(IShellLink* psl)
{
    ASSERT(psl != NULL);
    HRESULT hres = psl->GetDescription(m_strDescription.GetBuffer(MAX_PATH),
        MAX_PATH);
    m_strDescription.ReleaseBuffer();
    return SUCCEEDED(hres);
}

/////////////////////////////////////////////////////////////////////////////
// FillArguments
// Remarks: Fills the m_strArgs data member
// Inputs:  IShellLink*
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::FillArguments(IShellLink* psl)
{
    ASSERT(psl != NULL);
    HRESULT hres = psl->GetArguments(m_strArgs.GetBuffer(MAX_PATH), MAX_PATH);
    m_strArgs.ReleaseBuffer();
    return SUCCEEDED(hres);
}

/////////////////////////////////////////////////////////////////////////////
// FillIcons
// Remarks: Fills the m_hLargeIcon & m_hSmallIcon data members.  It also fills
//          the m_strIconLocation and m_nIconIndex data members, but the
//          m_nIconIndex member doesn't always get the correct icon index.
//          If someone can explain this better to me, I'd appreciate it.
// Inputs:  IShellLink*
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::FillIcons(IShellLink* psl)
{
    ASSERT(psl != NULL);

    IExtractIcon* pei;
    UINT nFlags;
    BOOL bRet = FALSE;

    HRESULT hres = psl->QueryInterface(IID_IExtractIcon, (LPVOID*) &pei);
    if (SUCCEEDED(hres))
    {
        hres = pei->GetIconLocation(GIL_FORSHELL,
            m_strIconLocation.GetBuffer(MAX_PATH), MAX_PATH, &m_nIconIndex,
            &nFlags);
        m_strIconLocation.ReleaseBuffer();
        if (hres == NOERROR)
        {
            // Try to extract it through the interface
            hres = pei->Extract(m_strIconLocation.GetBuffer(MAX_PATH),
                m_nIconIndex, &m_hLargeIcon, &m_hSmallIcon, 0);
            m_strIconLocation.ReleaseBuffer();
            if (hres == S_FALSE)
            {
                ExtractIcons();
                bRet = (m_hLargeIcon != NULL && m_hSmallIcon != NULL);
            }
            else
            {
                bRet = TRUE;
            }
        }
        pei->Release();
    }
    return bRet;
}

/////////////////////////////////////////////////////////////////////////////
// ExtractIcons
// Remarks: Extracts the large and small icons using the ::ExtractIcon API
// Inputs:  None
// Returns: void
void CShortcut::ExtractIcons()
{
    // Extract icons
    m_hLargeIcon = ::ExtractIcon(AfxGetInstanceHandle(),
        (LPCTSTR) m_strIconLocation, m_nIconIndex);
    m_hSmallIcon = ::ExtractIcon(AfxGetInstanceHandle(),
        (LPCTSTR) m_strIconLocation, m_nIconIndex);
}

/////////////////////////////////////////////////////////////////////////////
// FillHotkey
// Remarks: Fills the m_wHotkey data member
// Inputs:  IShellLink*
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::FillHotkey(IShellLink* psl)
{
    ASSERT(psl != NULL);
    HRESULT hres = psl->GetHotkey(&m_wHotkey);
    return SUCCEEDED(hres);
}

/////////////////////////////////////////////////////////////////////////////
// FillShowCmd
// Remarks: Fills the m_nShowCmd data member
// Inputs:  IShellLink*
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::FillShowCmd(IShellLink* psl)
{
    ASSERT(psl != NULL);
    HRESULT hres = psl->GetShowCmd(&m_nShowCmd);
    return SUCCEEDED(hres);
}

/////////////////////////////////////////////////////////////////////////////
// Save
// Remarks: Saves the shortcut
// Inputs:  None
// Returns: BOOL; TRUE if successful, FALSE if unsuccessful
BOOL CShortcut::Save()
{
    // Save only if we have to
    if (m_bDirty == FALSE)
    {
        return TRUE;
    }

    ASSERT(m_strPath != _T(""));

    IShellLink* psl;
    HRESULT hres;
    BOOL bRet = FALSE;

    // Create shell link instance
    hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
        IID_IShellLink, (LPVOID*) &psl);
    if (SUCCEEDED(hres))
    {
        // Get a pointer to persist file interface
        IPersistFile* ppf;
        hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*) &ppf);
        if (SUCCEEDED(hres))
        {
            // Convert to ANSI
            WORD wsz[MAX_PATH];
            ::MultiByteToWideChar(CP_ACP, 0, (LPCTSTR) m_strPath, -1, wsz,
                MAX_PATH);

            // Set attributes of link
            psl->SetPath((LPCTSTR) m_strTarget);
            psl->SetWorkingDirectory((LPCTSTR) m_strStartDir);
            psl->SetIconLocation((LPCTSTR) m_strIconLocation, m_nIconIndex);
            psl->SetDescription((LPCTSTR) m_strDescription);
            psl->SetArguments((LPCTSTR) m_strArgs);
            psl->SetHotkey(m_wHotkey);
            psl->SetShowCmd(m_nShowCmd);

            // Save the updated link
            hres = ppf->Save(wsz, TRUE);
            if (SUCCEEDED(hres))
            {
                bRet = TRUE;
                m_bDirty = FALSE;
            }
            ppf->Release();
        }
        psl->Release();
    }
    return bRet;
}









*********************************



Here's a header file:



// Shortcut.h : header file
//

// CShortcut
// Written 1996 by Rob Warner
// rhwarner@southeast.net
// http://users.southeast.net/~rhwarner
// Distribute freely, modify to your heart's content <g>
// Let me know if you find it useful, or if you've improved it <vbg>

// To use: You must #include <afxole.h> in your stdafx.h.
//         You must also initialize/uninitialize COM.  One way to do this is
//         in your derived CWinApp::InitInstance(), add the following line:
//
//          ::CoInitialize(NULL);
//
//         And in your derived CWinApp::ExitInstance(), add the following line:
//
//          ::CoUnitialize();
//

/////////////////////////////////////////////////////////////////////////////
// CShortcut

#ifndef _INC_SHORTCUT
#define _INC_SHORTCUT

#include "winnetwk.h"            // TB for using vc 4.0
#include "winnls.h"                  // TB for using vc 4.0
#include <shlobj.h>



typedef struct tagSHORTCUTSTRUCT {
    CString strPath;
    CString strTarget;
    CString strStartDir;
    CString strDescription;
    CString strIconLocation;
    CString strArgs;
    int     nIconIndex;
    WORD    wHotkey;
    int     nShowCmd;
} SHORTCUTSTRUCT, *LPSHORTCUTSTRUCT;

class
#ifdef _AFXEXT
AFX_EXT_CLASS
#endif
CShortcut : public CObject
{
// Constructors
public:
    CShortcut();
    CShortcut(LPCTSTR, BOOL bFill = FALSE);
    BOOL Create(LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR, LPCTSTR, int,
        WORD, int);
    BOOL CreateEx(const LPSHORTCUTSTRUCT);

// Attributes
public:
    // Accessors
    CString GetPath()         { return m_strPath;         }
    CString GetTarget()       { return m_strTarget;       }
    CString GetStartDir()     { return m_strStartDir;     }
    CString GetDescription()  { return m_strDescription;  }
    CString GetArguments()    { return m_strArgs;         }
    CString GetIconLocation() { return m_strIconLocation; }
    int     GetIconIndex()    { return m_nIconIndex;      }
    HICON   GetLargeIcon()    { return m_hLargeIcon;      }
    HICON   GetSmallIcon()    { return m_hSmallIcon;      }
    WORD    GetHotkey()       { return m_wHotkey;         }
    int     GetShowCmd()      { return m_nShowCmd;        }

    // Mutators
    void SetPath(LPCTSTR lpsz)           { m_strPath         = lpsz;  m_bDirty = TRUE; }
    void SetTarget(LPCTSTR lpsz)         { m_strTarget       = lpsz;  m_bDirty = TRUE; }
    void SetStartDir(LPCTSTR lpsz)       { m_strStartDir     = lpsz;  m_bDirty = TRUE; }
    void SetArguments(LPCTSTR lpsz)      { m_strArgs         = lpsz;  m_bDirty = TRUE; }
    void SetIconIndex(const int n)       { m_nIconIndex      = n;     m_bDirty = TRUE; }
    void SetHotkey(const WORD w)         { m_wHotkey         = w;     m_bDirty = TRUE; }
    void SetShowCmd(const int n)         { m_nShowCmd        = n;     m_bDirty = TRUE; }
    void SetDescription(LPCTSTR lpsz)    { m_strDescription  = lpsz;  m_bDirty = TRUE; }
    void SetIconLocation(LPCTSTR lpsz)   { m_strIconLocation = lpsz;  m_bDirty = TRUE; }
    void SetLargeIcon(const HICON hIcon) { m_hLargeIcon      = hIcon; m_bDirty = TRUE; }
    void SetSmallIcon(const HICON hIcon) { m_hSmallIcon      = hIcon; m_bDirty = TRUE; }
   
protected:
    BOOL    m_bDirty;
    CString m_strPath;
    CString m_strTarget;
    CString m_strStartDir;
    CString m_strDescription;
    CString m_strIconLocation;
    CString m_strArgs;
    int     m_nIconIndex;
    HICON   m_hLargeIcon;
    HICON   m_hSmallIcon;
    WORD    m_wHotkey;
    int     m_nShowCmd;

// Operations
public:
    BOOL Save();
    BOOL FillData();

// Overrides

// Implementation
public:
    virtual ~CShortcut();

#ifdef _DEBUG
    virtual void Dump(CDumpContext&);
#endif // _DEBUG

protected:
      void ExtractIcons();
    BOOL FileExists(LPCTSTR);
    BOOL TargetExists();
    BOOL FillTarget      (IShellLink* psl);
    BOOL FillIcons       (IShellLink* psl);
    BOOL FillDescription (IShellLink* psl);
    BOOL FillStartDir    (IShellLink* psl);
    BOOL FillArguments   (IShellLink* psl);
    BOOL FillHotkey      (IShellLink* psl);
    BOOL FillShowCmd     (IShellLink* psl);
};

#endif







I downloaded this class ages ago and found it really usefull.

I hope thi is the sort of thing you're looking for.

TimB
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2916837
> I asked for code to be able to create a shortcut on the desktop programmatically,

And that's what I've given you.

 > I called this function in OnInit() but I got errors when executing it (see my comments).

Right.  And I gave you code that works around the error on OSes where the API I was previously using wasn't available.

 > and hoped you can have a look at it or maybe you could add your code into my project

Oh, I see. So, you're saying the answer wasn't enough and that I need to actually update your application for you? All for 100 points? All because you're too stubborn to try the stand-alone code yourself?

..B ekiM
0
 
LVL 3

Author Comment

by:mitrakis
ID: 2917722
Mike,

this is the second time that you jump on me.
This is quite annoying and just stop it man !

If you think you're the one and only god in programming then I apologize for my stupid, brainless, useless comments herein.

What the hell do you want me to do now ?
Crediting you for code that works for you and not for me ???

You asked me to send you my project so you can have a look at it (since I'm too stupid)...now you got it, and all I hear are offences again.

If points are not enough, just tell me !!!
If you're willing to look at my project let me know and I'll increase points since your code looked quite easy and understandable, if not thanks for your help so far...

And btw, if I had the time to fiddle around with this shortcut stuff I'd try it...but there's *NO TIME*.

Thanks a lot TimB for taking time on this topic.
Although, I think Mike's suggestion is the right way, I'll have a look at it and will try to use it in my project.
But please, please be patient since I'm quite busy right now.

Best regards
-Stavi-
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 3818713
> Crediting you for code that works for you and not for me ???

You don't know if it does work or not: you haven't tried it. The sample code I gave you works. You modified the sample code and put it into your own project. I can't guarantee your modifications because I've never even seen them.

 > You asked me to send you my project so you can have a look at it

The project you posted doesn't include _any_ modifications. I can't look at what you've done to figure out what's wrong with it. Instead, you've asked me to do the work for you.

 > If points are not enough, just tell me !!!

So, yes: if you want me to do the work for you, 100 points isn't enough.

..B ekiM
0
 
LVL 3

Author Comment

by:mitrakis
ID: 3828372
Well, that's a statement I can work with.

a.)
I *tried* it. Maybe I'm not a C++ crack but I *tried* it.
Copy'n pasting the relevant lines didn't do the job, so I got back to you and offered my "shortcut-free" project.

b.)
I suggest two ways:
1) You'll tell me how many points you expect for the job.
2) I'll insert your code into my project again as I've already tried it before and would be glad to troubleshoot it with you.

I'd prefer the first way, but you decide.

Best regards
-Stavi-
0
 

Expert Comment

by:denmead
ID: 4141469
The following code replace SHGetSpecialFolderLocation () with GetSpecialFolder ()  which tries to use SHGetSpecialFolderPathA () if it can load it and uses GetWindowsDirectory () as a fall back if the users has IE < 4.0.

You can check the return code from GetSpecialFolder  () to find out what happened.


Here is the code ...


#include "stdafx.h"

#include <windows.h>

#include <shellapi.h>
#include <objbase.h>

#include <shlguid.h>
#include <shlobj.h>

#include <stdio.h>

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "shell32.lib")

/* ///////////////////////////////////////////////////////////////////////

GetSpecialFolder () replaces SHGetSpecialFolderLocation () to
provide backwards compatibility when IE < 4.0

return values:

      0      failed to get path
      1      success using SHGetSpecialFolderPathA ()
      2      success using GetWindowsDirectory ()
      3      ditto 2 but the path reported by SHGetSpecialFolderPathA () missing
*/

static char *szShell32 = "shell32.dll";
typedef  BOOL (WINAPI* PF_GETFOLDER)(HWND, LPSTR, int, BOOL);

static int GetSpecialFolder (char *PathName, int csid)
{
    PF_GETFOLDER pfnGetFolder;

    HMODULE hModule = LoadLibrary (szShell32);

      int success            = 0;
      int MissingPath      = 0;

    if (hModule) {

          pfnGetFolder = (PF_GETFOLDER) GetProcAddress (hModule, "SHGetSpecialFolderPathA");

            if (pfnGetFolder) {

                  if (!pfnGetFolder (NULL, PathName, csid, FALSE))  {

                        // this could happen if we asked for a common folder
                        // and this is not WinNT/2000

                        MissingPath = 1;

                  } else {

                        success = 1;      // flag we got the path!
                  }
            }

            FreeLibrary (hModule);
      }

    if (success)
            return 1;

      // okay we failed to get it using SHGetSpecialFolderPathA ()
      // so lets try the fallback GetWindowsDirectory ()

      if (GetWindowsDirectory (PathName, _MAX_DIR - 9) == 0)
            return 0; // not having much luck here

      switch (csid) {

            case CSIDL_DESKTOP:
            case CSIDL_COMMON_DESKTOPDIRECTORY:
                  strcat (PathName, "\\Desktop");
            break;

            case CSIDL_STARTMENU:
            case CSIDL_COMMON_STARTMENU:
                  strcat (PathName, "\\Start Menu");
            break;

            case CSIDL_STARTUP:
            case CSIDL_COMMON_STARTUP:
                  strcat (PathName, "\\Startup");
            break;

            default:
                  return 0;
            break;
      }

      return (2 + MissingPath);
}

///////////////////////////////////////////////////////////////////////////

// returns same values as GetSpecialFolder ()

int check_csid (int csid)
{
      char szLinkTarget [_MAX_PATH * 2];

      return GetSpecialFolder (szLinkTarget, csid);
}

///////////////////////////////////////////////////////////////////////////

BOOL AddShortCut (char *LinkName, char *ExePath, char *desc, int csid)
{
      int success = 0;

      // get the location of the desktop folder path
      char szLinkTarget [_MAX_PATH * 2];

      if (GetSpecialFolder (szLinkTarget, csid) == 0)  {
            return 0;      // failed!
      }

      // after the path name, add a real file name

      char *ptmp = szLinkTarget + strlen (szLinkTarget);

      wsprintf (ptmp, "\\%s.lnk", LinkName);

      // Link Target = szLinkTarget

      CoInitialize (NULL);

      // get the shell manager's link object

      IShellLink* pShellLink = NULL;

      HRESULT hRes = CoCreateInstance (
            CLSID_ShellLink,
            NULL,
            CLSCTX_INPROC_SERVER,
            IID_IShellLink,
            (LPVOID*) &pShellLink);

      if (SUCCEEDED (hRes) && pShellLink != NULL)  {

            // set the path and description on that object

            pShellLink->SetPath                  (ExePath);
            pShellLink->SetDescription      (desc);

            // then, ask that object to save itself into the desktop
            // folder with the name we built before

            IPersistFile* pPersistFile = NULL;

            hRes = pShellLink->QueryInterface (IID_IPersistFile, (LPVOID*) &pPersistFile);

            if (SUCCEEDED (hRes) && pPersistFile != NULL) {

                  // Save needs the name as wide characters

                  WCHAR wszDesktopPath [_MAX_PATH * 2];

                  MultiByteToWideChar (
                        CP_ACP,
                        MB_PRECOMPOSED,
                        szLinkTarget,
                        -1,
                        wszDesktopPath,
                        _MAX_PATH * 2);

                  // Unicode Link = wszDesktopPath

                  // dot the save!

                  hRes = pPersistFile->Save (wszDesktopPath, TRUE);

                  if (FAILED (hRes) == 0)
                        success = 1;

                  pPersistFile->Release ();
            }

            pShellLink->Release ();
      }

      CoUninitialize ();

      return success;
}

/////////////////////////////////////////////////////////////////////////

// some code to test the functions ....

static void test_check_csid (int csid)
{
      int check = check_csid (csid);

      printf ("check_csid () return = %d ", check);

      switch (check) {

            case 1:
                  printf ("SHGetSpecialFolderPathA () working (IE >= 4.0?)\n");
            break;

            case 2:
                  printf ("GetWindowsDirectory () working (IE < 4.0?)\n");
            break;

            case 3:
                  printf ("folder missing?\n");
            break;

            default:
                  printf ("check_csid () failed\n");
            break;
      }
}

int main (int argc, char* argv [])
{
      // check to see if SHGetSpecialFolderPathA () working

      printf ("\nTesting for CSIDL_DESKTOPDIRECTORY \n");

      test_check_csid (CSIDL_DESKTOPDIRECTORY);
      
      // check to see if winNT/2000 with common area working

      printf ("\nTesting for CSIDL_COMMON_DESKTOPDIRECTORY \n");

      test_check_csid (CSIDL_COMMON_DESKTOPDIRECTORY);
      
      // get the name and path to our executable.

      char szExecutable [_MAX_PATH];

      GetModuleFileName (NULL, szExecutable, _MAX_PATH);

      // now add to desktop

      int success = AddShortCut ("My Link", szExecutable, "My Description", CSIDL_DESKTOPDIRECTORY);

      printf ("\nAddShortCut () CSIDL_DESKTOPDIRECTORY success = %d \n", success);

      if (!success)
            return 1;

      // now add to start menu

      success = AddShortCut ("My Link", szExecutable, "My Description", CSIDL_STARTMENU);

      printf ("\nAddShortCut () CSIDL_STARTMENU success = %d \n", success);

      int ErrorLevel = (success == 0);

      return ErrorLevel;
}

0
 
LVL 11

Expert Comment

by:mikeblas
ID: 4968059
This question continues to languish. I guess mitrakis never had any intention of accepting any answer.

..B ekiM
0
 
LVL 1

Expert Comment

by:TimB
ID: 4980890
hmmmm......

Tim
0
 
LVL 3

Author Comment

by:mitrakis
ID: 5597159
Well, my apologies to Mike for not checking my emails or EE comments while away on leave...and thanks for your answer on my last question !?

Thanks to all for your patience.

Best regards
-Stavi-
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 5624420
Only seven short months later.

..B ekiM
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now