#include <stdio.h>
#include <shlobj.h>
#include <shlwapi.h>

bool __fastcall CreateShortCut(LPWSTR pwzShortCutFileName,  LPCITEMIDLIST pidl,
                               LPTSTR pszWorkingDirectory, WORD wHotKey, int iCmdShow);
int short_cut_startup(char *connection_name, LPWSTR link_name);
LPITEMIDLIST GetNextItemID(LPCITEMIDLIST pidl);
UINT GetSize(LPCITEMIDLIST pidl);
LPITEMIDLIST Append(LPCITEMIDLIST pidlBase, LPCITEMIDLIST pidlAdd);

LPMALLOC pMalloc;

int main(void)
{
    if(short_cut_startup("demo", L"demo - connection.lnk"))
        printf("Success!\n");
    else printf("Can't create shortcut!\n");
    return 0;
}

/* Main function which creating shortcut on desktop */
int short_cut_startup(char *connection_name, LPWSTR link_name)
{
    LPITEMIDLIST pidConnections = NULL;
    LPITEMIDLIST pidlItems = NULL;
    LPITEMIDLIST pidlDesk = NULL;
    IShellFolder *psfFirstFolder = NULL;
    IShellFolder *psfDeskTop = NULL;
    IShellFolder *pConnections = NULL;
    LPENUMIDLIST ppenum = NULL;
    ULONG celtFetched;
    HRESULT hr;
    STRRET str_curr_connection_name;
    TCHAR curr_connection_name[MAX_PATH] = "";    /* Connection point name */
    TCHAR desktop_path[MAX_PATH]="";            /* Path to desktop */
    TCHAR full_link_name[MAX_PATH]="";            /* Full shortcut name */
    LPITEMIDLIST full_pid;                        /* Full shortcut pid */

   
    CoInitialize( NULL );
    /* Allocating memory for Namespace objects */
    hr = SHGetMalloc(&pMalloc);
    hr = SHGetFolderLocation(NULL, CSIDL_CONNECTIONS, NULL, NULL, &pidConnections);

    /* Get full path to desktop */
    SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktop_path);

    hr = SHGetDesktopFolder(&psfDeskTop);
    hr = psfDeskTop->BindToObject(pidConnections, NULL, IID_IShellFolder, (LPVOID *) &pConnections);
    hr = pConnections->EnumObjects(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &ppenum);

    /* Loop for searching our connection */
    while(hr = ppenum->Next(1,&pidlItems, &celtFetched) == S_OK && (celtFetched) == 1)
    {
        pConnections->GetDisplayNameOf(pidlItems, SHGDN_INFOLDER, &str_curr_connection_name);
        StrRetToBuf(&str_curr_connection_name, pidlItems, curr_connection_name, MAX_PATH);
        if(!strcmp(curr_connection_name,connection_name))
            goto found;
    }
    printf("Connection not found in \"Network connections\" folder.\n");
    return 0;
found:
    /* Append PIDLs */
    full_pid=Append(pidConnections,pidlItems);
    SetCurrentDirectory(desktop_path);
    if(!CreateShortCut(link_name, full_pid, "C:\\windows", 0, SW_SHOWNORMAL))
        return 0;

    ppenum->Release();
    pMalloc->Free(pidlItems);
    pMalloc->Free(pidConnections);
    pMalloc->Release();
    pConnections->Release();
    CoUninitialize();
    return 1;
}

bool __fastcall CreateShortCut(LPWSTR pwzShortCutFileName,  LPCITEMIDLIST pidl,
                               LPTSTR pszWorkingDirectory, WORD wHotKey, int iCmdShow)
{ 
    IShellLink * pSL; 
    IPersistFile * pPF; 
    HRESULT hRes; 
    hRes = CoCreateInstance(CLSID_ShellLink, 0,CLSCTX_INPROC_SERVER, 
                            IID_IShellLink, (LPVOID *)&pSL); 
    if( SUCCEEDED(hRes) ) 
    { 
        hRes=pSL->SetIDList(pidl);
        if(SUCCEEDED(hRes))
        { 
            hRes = pSL->SetHotkey(wHotKey); 
            if( SUCCEEDED(hRes) ) 
            { 
                hRes = pSL->SetShowCmd(iCmdShow); 
                if( SUCCEEDED(hRes) ) 
                { 
                    hRes = pSL->QueryInterface(IID_IPersistFile,(LPVOID *)&pPF); 
                    if( SUCCEEDED(hRes) ) 
                    { 
                        hRes = pPF->Save(pwzShortCutFileName,TRUE); 
                        pPF->Release(); 
                    }
                }
            }
        }
        pSL->Release(); 
    }
    return SUCCEEDED(hRes); 
}

/******************************************************************************/
/* Functions copied from http://msdn.microsoft.com */

LPITEMIDLIST GetNextItemID(LPCITEMIDLIST pidl) 
{ 
   // Check for valid pidl.
   if(pidl == NULL)
      return NULL;

   // Get the size of the specified item identifier. 
   int cb = pidl->mkid.cb; 

   // If the size is zero, it is the end of the list. 

   if (cb == 0) 
      return NULL; 

   // Add cb to pidl (casting to increment by bytes). 
   pidl = (LPITEMIDLIST) (((LPBYTE) pidl) + cb); 

   // Return NULL if it is null-terminating, or a pidl otherwise. 
   return (pidl->mkid.cb == 0) ? NULL : (LPITEMIDLIST) pidl; 
} 

/* Get size of PIDL */
UINT GetSize(LPCITEMIDLIST pidl)
{
    UINT cbTotal = 0;
    if (pidl)
    {
        cbTotal += sizeof(pidl->mkid.cb);    // Terminating null character
        while (pidl)
        {
            cbTotal += pidl->mkid.cb;
            pidl = GetNextItemID(pidl);
        }
    }
    return cbTotal;
}

/* Appending PIDLs */
LPITEMIDLIST Append(LPCITEMIDLIST pidlBase, LPCITEMIDLIST pidlAdd)
{
    if(pidlBase == NULL)
        return NULL;
    if(pidlAdd == NULL)
        return (LPITEMIDLIST)pidlBase;
    
    LPITEMIDLIST pidlNew;

    UINT cb1 = GetSize(pidlBase) - sizeof(pidlBase->mkid.cb);
    UINT cb2 = GetSize(pidlAdd);

    pidlNew = (LPITEMIDLIST)pMalloc->Alloc(cb1 + cb2);
    if (pidlNew)
    {
        CopyMemory(pidlNew, pidlBase, cb1);
        CopyMemory(((LPSTR)pidlNew) + cb1, pidlAdd, cb2);
    }
    return pidlNew;
}