windows read the target of shortcut file in c++ - c++

How to read the target of shortcut file on windows. Tried using boost::read_symlink which throws exception saying "the file or directory is not a reparse point" message.
int main(int argc, _TCHAR* argv[])
{
try {
boost::filesystem::path target = boost::filesystem::read_symlink("c:\\tmp\\blobstore_2.lnk");
cout<<target.string();
} catch(const boost::filesystem::filesystem_error& ex)
{
cout<<"in catch"<<ex.what(); // prints "the file or directory is not a reparse point"
}
std::ifstream smbConfStream("c:\\tmp\\sym_file_2.lnk");
string ss((std::istreambuf_iterator<char>(smbConfStream)),
std::istreambuf_iterator<char>());
cout <<endl<<" ss: "<<ss; // From the output of the "ss" it looks like the information of the target is present inside ss along with other binary data. How to cleanly get the target out.
int i;
cin>>i;
return 0;
}

A Windows .lnk file is not a symbolic link. It is a shortcut file. You use the IShellLink interface to manipulate it.
The documentation contains the following example demonstrating how to resolve a shortcut file.
// ResolveIt - Uses the Shell's IShellLink and IPersistFile interfaces
// to retrieve the path and description from an existing shortcut.
//
// Returns the result of calling the member functions of the interfaces.
//
// Parameters:
// hwnd - A handle to the parent window. The Shell uses this window to
// display a dialog box if it needs to prompt the user for more
// information while resolving the link.
// lpszLinkFile - Address of a buffer that contains the path of the link,
// including the file name.
// lpszPath - Address of a buffer that receives the path of the link
// target, including the file name.
// lpszDesc - Address of a buffer that receives the description of the
// Shell link, stored in the Comment field of the link
// properties.
#include "stdafx.h"
#include "windows.h"
#include "shobjidl.h"
#include "shlguid.h"
#include "strsafe.h"
HRESULT ResolveIt(HWND hwnd, LPCSTR lpszLinkFile, LPWSTR lpszPath, int iPathBufferSize)
{
HRESULT hres;
IShellLink* psl;
WCHAR szGotPath[MAX_PATH];
WCHAR szDescription[MAX_PATH];
WIN32_FIND_DATA wfd;
*lpszPath = 0; // Assume failure
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Get a pointer to the IPersistFile interface.
hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Load the shortcut.
hres = ppf->Load(wsz, STGM_READ);
if (SUCCEEDED(hres))
{
// Resolve the link.
hres = psl->Resolve(hwnd, 0);
if (SUCCEEDED(hres))
{
// Get the path to the link target.
hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATA*)&wfd, SLGP_SHORTPATH);
if (SUCCEEDED(hres))
{
// Get the description of the target.
hres = psl->GetDescription(szDescription, MAX_PATH);
if (SUCCEEDED(hres))
{
hres = StringCbCopy(lpszPath, iPathBufferSize, szGotPath);
if (SUCCEEDED(hres))
{
// Handle success
}
else
{
// Handle the error
}
}
}
}
}
// Release the pointer to the IPersistFile interface.
ppf->Release();
}
// Release the pointer to the IShellLink interface.
psl->Release();
}
return hres;
}

Here's more compact version of David's code, with ATL (included with Visual Studio).
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <ShObjIdl_core.h>
#include <atlstr.h>
#define CHECK( hr ) { const HRESULT __hr = ( hr ); if( FAILED( __hr ) ) return __hr; }
HRESULT resolveShortcutTarget( HWND wnd, const CString& lnk, CString& target )
{
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize has already been called.
CComPtr<IShellLink> psl;
CHECK( psl.CoCreateInstance( CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER ) );
// Get a pointer to the IPersistFile interface.
CComPtr<IPersistFile> ppf;
CHECK( psl->QueryInterface( IID_PPV_ARGS( &ppf ) ) );
// Load the shortcut.
CHECK( ppf->Load( lnk, STGM_READ ) );
// Resolve the link.
CHECK( psl->Resolve( wnd, 0 ) );
// Get the path to the link target.
const HRESULT hr = psl->GetPath( target.GetBufferSetLength( MAX_PATH ), MAX_PATH, nullptr, 0 );
target.ReleaseBuffer();
return hr;
}

Related

How to resolve shortcut to it's target path using windows API [duplicate]

How to read the target of shortcut file on windows. Tried using boost::read_symlink which throws exception saying "the file or directory is not a reparse point" message.
int main(int argc, _TCHAR* argv[])
{
try {
boost::filesystem::path target = boost::filesystem::read_symlink("c:\\tmp\\blobstore_2.lnk");
cout<<target.string();
} catch(const boost::filesystem::filesystem_error& ex)
{
cout<<"in catch"<<ex.what(); // prints "the file or directory is not a reparse point"
}
std::ifstream smbConfStream("c:\\tmp\\sym_file_2.lnk");
string ss((std::istreambuf_iterator<char>(smbConfStream)),
std::istreambuf_iterator<char>());
cout <<endl<<" ss: "<<ss; // From the output of the "ss" it looks like the information of the target is present inside ss along with other binary data. How to cleanly get the target out.
int i;
cin>>i;
return 0;
}
A Windows .lnk file is not a symbolic link. It is a shortcut file. You use the IShellLink interface to manipulate it.
The documentation contains the following example demonstrating how to resolve a shortcut file.
// ResolveIt - Uses the Shell's IShellLink and IPersistFile interfaces
// to retrieve the path and description from an existing shortcut.
//
// Returns the result of calling the member functions of the interfaces.
//
// Parameters:
// hwnd - A handle to the parent window. The Shell uses this window to
// display a dialog box if it needs to prompt the user for more
// information while resolving the link.
// lpszLinkFile - Address of a buffer that contains the path of the link,
// including the file name.
// lpszPath - Address of a buffer that receives the path of the link
// target, including the file name.
// lpszDesc - Address of a buffer that receives the description of the
// Shell link, stored in the Comment field of the link
// properties.
#include "stdafx.h"
#include "windows.h"
#include "shobjidl.h"
#include "shlguid.h"
#include "strsafe.h"
HRESULT ResolveIt(HWND hwnd, LPCSTR lpszLinkFile, LPWSTR lpszPath, int iPathBufferSize)
{
HRESULT hres;
IShellLink* psl;
WCHAR szGotPath[MAX_PATH];
WCHAR szDescription[MAX_PATH];
WIN32_FIND_DATA wfd;
*lpszPath = 0; // Assume failure
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Get a pointer to the IPersistFile interface.
hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Load the shortcut.
hres = ppf->Load(wsz, STGM_READ);
if (SUCCEEDED(hres))
{
// Resolve the link.
hres = psl->Resolve(hwnd, 0);
if (SUCCEEDED(hres))
{
// Get the path to the link target.
hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATA*)&wfd, SLGP_SHORTPATH);
if (SUCCEEDED(hres))
{
// Get the description of the target.
hres = psl->GetDescription(szDescription, MAX_PATH);
if (SUCCEEDED(hres))
{
hres = StringCbCopy(lpszPath, iPathBufferSize, szGotPath);
if (SUCCEEDED(hres))
{
// Handle success
}
else
{
// Handle the error
}
}
}
}
}
// Release the pointer to the IPersistFile interface.
ppf->Release();
}
// Release the pointer to the IShellLink interface.
psl->Release();
}
return hres;
}
Here's more compact version of David's code, with ATL (included with Visual Studio).
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <ShObjIdl_core.h>
#include <atlstr.h>
#define CHECK( hr ) { const HRESULT __hr = ( hr ); if( FAILED( __hr ) ) return __hr; }
HRESULT resolveShortcutTarget( HWND wnd, const CString& lnk, CString& target )
{
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize has already been called.
CComPtr<IShellLink> psl;
CHECK( psl.CoCreateInstance( CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER ) );
// Get a pointer to the IPersistFile interface.
CComPtr<IPersistFile> ppf;
CHECK( psl->QueryInterface( IID_PPV_ARGS( &ppf ) ) );
// Load the shortcut.
CHECK( ppf->Load( lnk, STGM_READ ) );
// Resolve the link.
CHECK( psl->Resolve( wnd, 0 ) );
// Get the path to the link target.
const HRESULT hr = psl->GetPath( target.GetBufferSetLength( MAX_PATH ), MAX_PATH, nullptr, 0 );
target.ReleaseBuffer();
return hr;
}

How do I manipulate the icon for an existing desktop shortcut using Win32?

I want to be able to get the current .ico file being used for a shortcut and then change it to a different .ico file temporarily. I was planning on parsing the .lnk files manually, but I thought I might ask for an easier way here first.
Use the IShellLink interface. Here are examples from MSDN:
Shell Links
// CreateLink - Uses the Shell's IShellLink and IPersistFile interfaces
// to create and store a shortcut to the specified object.
//
// Returns the result of calling the member functions of the interfaces.
//
// Parameters:
// lpszPathObj - Address of a buffer that contains the path of the object,
// including the file name.
// lpszPathLink - Address of a buffer that contains the path where the
// Shell link is to be stored, including the file name.
// lpszDesc - Address of a buffer that contains a description of the
// Shell link, stored in the Comment field of the link
// properties.
#include "stdafx.h"
#include "windows.h"
#include "winnls.h"
#include "shobjidl.h"
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc)
{
HRESULT hres;
IShellLink* psl;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
// ResolveIt - Uses the Shell's IShellLink and IPersistFile interfaces
// to retrieve the path and description from an existing shortcut.
//
// Returns the result of calling the member functions of the interfaces.
//
// Parameters:
// hwnd - A handle to the parent window. The Shell uses this window to
// display a dialog box if it needs to prompt the user for more
// information while resolving the link.
// lpszLinkFile - Address of a buffer that contains the path of the link,
// including the file name.
// lpszPath - Address of a buffer that receives the path of the link
target, including the file name.
// lpszDesc - Address of a buffer that receives the description of the
// Shell link, stored in the Comment field of the link
// properties.
#include "stdafx.h"
#include "windows.h"
#include "shobjidl.h"
#include "shlguid.h"
#include "strsafe.h"
HRESULT ResolveIt(HWND hwnd, LPCSTR lpszLinkFile, LPWSTR lpszPath, int iPathBufferSize)
{
HRESULT hres;
IShellLink* psl;
WCHAR szGotPath[MAX_PATH];
WCHAR szDescription[MAX_PATH];
WIN32_FIND_DATA wfd;
*lpszPath = 0; // Assume failure
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Get a pointer to the IPersistFile interface.
hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Load the shortcut.
hres = ppf->Load(wsz, STGM_READ);
if (SUCCEEDED(hres))
{
// Resolve the link.
hres = psl->Resolve(hwnd, 0);
if (SUCCEEDED(hres))
{
// Get the path to the link target.
hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATA*)&wfd, SLGP_SHORTPATH);
if (SUCCEEDED(hres))
{
// Get the description of the target.
hres = psl->GetDescription(szDescription, MAX_PATH);
if (SUCCEEDED(hres))
{
hres = StringCbCopy(lpszPath, iPathBufferSize, szGotPath);
if (SUCCEEDED(hres))
{
// Handle success
}
else
{
// Handle the error
}
}
}
}
}
// Release the pointer to the IPersistFile interface.
ppf->Release();
}
// Release the pointer to the IShellLink interface.
psl->Release();
}
return hres;
}
In your case, you would:
Create an instance of IShellLink
query it for IPersistFile()
call IPersistFile.Load() to set the .lnk filename
call IShellLink.Resolve() to load the file
call IShellLink.SetIconLocation() to set a new .ico filename
Call IPersistFile.Save() to save the new .lnk file.

C++: How do I create a Shortcut in the Start Menu on Windows

I would like to know how to obtain the path to the start menu folder on Windows and then create a shortcut to a path that might contain non-ASCII characters.
Here is the solution. It uses Qt but it's also possible without. Then just use std::wstring instead of QString. For concatenating the paths and filenames you will then have to use string operations instead of using QDir.
#include <shlobj.h>
bool createStartMenuEntry(QString targetPath) {
targetPath = QDir::toNativeSeparators(targetPath);
WCHAR startMenuPath[MAX_PATH];
HRESULT result = SHGetFolderPathW(NULL, CSIDL_COMMON_PROGRAMS, NULL, 0, startMenuPath);
if (SUCCEEDED(result)) {
QString linkPath = QDir(QString::fromWCharArray(startMenuPath)).absoluteFilePath("Shortcut Name.lnk");
CoInitialize(NULL);
IShellLinkW* shellLink = NULL;
result = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&shellLink);
if (SUCCEEDED(result)) {
shellLink->SetPath(targetPath.toStdWString().c_str());
shellLink->SetDescription(L"Shortcut Description");
shellLink->SetIconLocation(targetPath.toStdWString().c_str(), 0);
IPersistFile* persistFile;
result = shellLink->QueryInterface(IID_IPersistFile, (void**)&persistFile);
if (SUCCEEDED(result)) {
result = persistFile->Save(linkPath.toStdWString().c_str(), TRUE);
persistFile->Release();
} else {
return false;
}
shellLink->Release();
} else {
return false;
}
} else {
return false;
}
return true;
}
Thats the part that obtains the location of the start-menu folder:
WCHAR startMenuPath[MAX_PATH];
HRESULT result = SHGetFolderPathW(NULL, CSIDL_COMMON_PROGRAMS, NULL, 0, startMenuPath);
The rest is then creation of the shortcut. Exchange shortcut name and description for your desired values.
Same idea as accepted answer but Visual Studio method.
Usage:
CString sProgramsPath = getenv("PROGRAMDATA");
CString sShortcutPath = sProgramsPath += "\\Microsoft\\Windows\\Start Menu\\Programs\\SHORTCUT_NAME.lnk";
// (that's .LNK)
CreateLink("C:\\target_file_path\\target_file_name.exe",
"sShortcutPath",
"C:\\target_file_path\\,
"Shortcut Description");
Function:
/*============================================================================*/
// CreateLink - Uses the Shell's IShellLink and IPersistFile interfaces
// to create and store a shortcut to the specified object.
//
// Returns the result of calling the member functions of the interfaces.
//
// Parameters:
// lpszPathObj - Address of a buffer that contains the path of the object,
// including the file name.
// lpszPathLink - Address of a buffer that contains the path where the
// Shell link is to be stored, including the file name.
// lpszPath - Working directory of target Obj file
// lpszDesc - Address of a buffer that contains a description of the
// Shell link, stored in the Comment field of the link
// properties.
HRESULT CreateLink(
LPCSTR lpszPathObj,
LPCSTR lpszPathLink,
LPCSTR lpszPath,
LPCSTR lpszDesc )
/*============================================================================*/
{
IShellLink* psl = NULL;
HRESULT hres = CoInitialize(NULL);
if (!SUCCEEDED(hres))
LOGASSERT(FALSE);
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
psl->SetWorkingDirectory(lpszPath);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(wsz, TRUE);
if (!SUCCEEDED(hres))
LOGASSERT(FALSE);
ppf->Release();
}
psl->Release();
}
CoUninitialize();
return hres;
}

Why in finding target path of shortcut with shell link in c++ it refers to windows\installer folder

I want to find target path of a shortcut in startmenu folder ,
I know that should use from shell link component object model ,
But in my test for some shortcuts it shows: "windows\installer\{guid}\x.exe" and does not show program files folder for it , and for other shortcut works fine,
How can i find target path for these products.
this is the function i use:
HRESULT TargetShortcut::ResolveIt(HWND hwnd, LPCTSTR lpszLinkFile, LPTSTR lpszPath, int iPathBufferSize)
{
HRESULT hres;
if (lpszPath == NULL)
return E_INVALIDARG;
*lpszPath = 0;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
IShellLink* __psl = NULL;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
// Get a pointer to the IPersistFile interface.
IPersistFile* ppf = NULL;
hres = __psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
if (SUCCEEDED(hres))
{
// Add code here to check return value from MultiByteWideChar
// for success.
// Load the shortcut.
#ifdef _UNICODE
hres = ppf->Load(lpszLinkFile, STGM_READ);
#else
WCHAR wsz[MAX_PATH] = {0};
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH);
hres = ppf->Load(wsz, STGM_READ);
#endif
if (SUCCEEDED(hres))
{
// Resolve the link.
hres = __psl->Resolve(hwnd, 0);
if (SUCCEEDED(hres))
{
// Get the path to the link target.
TCHAR szGotPath[MAX_PATH] = {0};
hres = __psl->GetPath(szGotPath, _countof(szGotPath), NULL, SLGP_SHORTPATH);
if (SUCCEEDED(hres))
{
hres = StringCbCopy(lpszPath, iPathBufferSize, szGotPath);
}
}
}
// Release the pointer to the IPersistFile interface.
ppf->Release();
}
// Release the pointer to the IShellLink interface.
__psl->Release();
}
return hres;
}
and this an answer for a shortcut :
C:\Windows\Installer{53FA9A9F-3C19-4D43-AD6B-DEF365D469BA}
Try first this code:
#include "msi.h"
#pragma comment (lib, "msi")
...
TCHAR Path[MAX_PATH];
Path[0] = '\0';
TCHAR pszComponentCode[MAX_FEATURE_CHARS+1];
TCHAR pszProductCode[MAX_FEATURE_CHARS+1];
pszComponentCode[0] = _T('\0');
pszProductCode[0] = _T('\0');
if ( MsiGetShortcutTarget(pszLinkPathName, pszProductCode, NULL, pszComponentCode) == ERROR_SUCCESS)
{
DWORD dw = MAX_PATH;
UINT ret = MsiGetComponentPath(pszProductCode, pszComponentCode, Path, &dw);
//Path now contains path to EXE
}
else
{
//process regular LNK
}
Then in ELSE part you can call code to resolve regular LNK

How to programmatically create a shortcut using Win32

I need to programmatically create a shortcut using C++.
How can I do this using Win32 SDK?
What API function can be used for this purpose?
Try Windows Shell Links. This page also contains a C++ example. Descriptive Snippet:
Using Shell Links
This section contains examples that
demonstrate how to create and resolve
shortcuts from within a Win32-based
application. This section assumes you
are familiar with Win32, C++, and OLE
COM programming.
EDIT: Adding the code sample in case the link dies (and MSDN links do die often.)
// CreateLink - Uses the Shell's IShellLink and IPersistFile interfaces
// to create and store a shortcut to the specified object.
//
// Returns the result of calling the member functions of the interfaces.
//
// Parameters:
// lpszPathObj - Address of a buffer that contains the path of the object,
// including the file name.
// lpszPathLink - Address of a buffer that contains the path where the
// Shell link is to be stored, including the file name.
// lpszDesc - Address of a buffer that contains a description of the
// Shell link, stored in the Comment field of the link
// properties.
#include "stdafx.h"
#include "windows.h"
#include "winnls.h"
#include "shobjidl.h"
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc)
{
HRESULT hres;
IShellLink* psl;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
Here is a c++ sample code based on William Rayer code on codeproject.com
header file (ShortcutProvider.h):
#include <Windows.h>
class ShortcutProvider
{
public:
/*
-------------------------------------------------------------------
Description:
Creates the actual 'lnk' file (assumes COM has been initialized).
Parameters:
pszTargetfile - File name of the link's target.
pszTargetargs - Command line arguments passed to link's target.
pszLinkfile - File name of the actual link file being created.
pszDescription - Description of the linked item.
iShowmode - ShowWindow() constant for the link's target.
pszCurdir - Working directory of the active link.
pszIconfile - File name of the icon file used for the link.
iIconindex - Index of the icon in the icon file.
Returns:
HRESULT value >= 0 for success, < 0 for failure.
--------------------------------------------------------------------
*/
HRESULT Create(LPSTR pszTargetfile, LPSTR pszTargetargs,
LPSTR pszLinkfile, LPSTR pszDescription,
int iShowmode, LPSTR pszCurdir,
LPSTR pszIconfile, int iIconindex);
};
Source File (ShortcutProvide.cpp):
#include "ShortcutProvider.h"
#include <Windows.h>
#include <shlobj.h>
#include <winnls.h>
#include <shobjidl.h>
#include <objbase.h>
#include <objidl.h>
#include <shlguid.h>
HRESULT ShortcutProvider::Create(LPSTR pszTargetfile, LPSTR pszTargetargs,
LPSTR pszLinkfile, LPSTR pszDescription,
int iShowmode, LPSTR pszCurdir,
LPSTR pszIconfile, int iIconindex)
{
HRESULT hRes; /* Returned COM result code */
IShellLink* pShellLink; /* IShellLink object pointer */
IPersistFile* pPersistFile; /* IPersistFile object pointer */
WCHAR wszLinkfile[MAX_PATH]; /* pszLinkfile as Unicode
string */
int iWideCharsWritten; /* Number of wide characters
written */
CoInitialize(NULL);
hRes = E_INVALIDARG;
if (
(pszTargetfile != NULL) && (strlen(pszTargetfile) > 0) &&
(pszTargetargs != NULL) &&
(pszLinkfile != NULL) && (strlen(pszLinkfile) > 0) &&
(pszDescription != NULL) &&
(iShowmode >= 0) &&
(pszCurdir != NULL) &&
(pszIconfile != NULL) &&
(iIconindex >= 0)
)
{
hRes = CoCreateInstance(
CLSID_ShellLink, /* pre-defined CLSID of the IShellLink
object */
NULL, /* pointer to parent interface if part of
aggregate */
CLSCTX_INPROC_SERVER, /* caller and called code are in same
process */
IID_IShellLink, /* pre-defined interface of the
IShellLink object */
(LPVOID*)&pShellLink); /* Returns a pointer to the IShellLink
object */
if (SUCCEEDED(hRes))
{
/* Set the fields in the IShellLink object */
hRes = pShellLink->SetPath(pszTargetfile);
hRes = pShellLink->SetArguments(pszTargetargs);
if (strlen(pszDescription) > 0)
{
hRes = pShellLink->SetDescription(pszDescription);
}
if (iShowmode > 0)
{
hRes = pShellLink->SetShowCmd(iShowmode);
}
if (strlen(pszCurdir) > 0)
{
hRes = pShellLink->SetWorkingDirectory(pszCurdir);
}
if (strlen(pszIconfile) > 0 && iIconindex >= 0)
{
hRes = pShellLink->SetIconLocation(pszIconfile, iIconindex);
}
/* Use the IPersistFile object to save the shell link */
hRes = pShellLink->QueryInterface(
IID_IPersistFile, /* pre-defined interface of the
IPersistFile object */
(LPVOID*)&pPersistFile); /* returns a pointer to the
IPersistFile object */
if (SUCCEEDED(hRes))
{
iWideCharsWritten = MultiByteToWideChar(CP_ACP, 0,
pszLinkfile, -1,
wszLinkfile, MAX_PATH);
hRes = pPersistFile->Save(wszLinkfile, TRUE);
pPersistFile->Release();
}
pShellLink->Release();
}
}
CoUninitialize();
return (hRes);
}
This MSDN artice, Shell Links, provide a comprehensive tutorial about the subject with code example.
You can use system function to execute mklink command.
system("mklink /d shortcut_name Target_file");