Creating a shortcut .lnk using Windows API - c++

I'm having a problem with creating a shortcut using C++.
The .lnk file is created, but the target has a nonsense path.
Can you explain why this code is not creating a correct shortcut? Can someone could help me fix my code?
Here is the code
// RepChrome.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
#include "winnls.h"
#include "shobjidl.h"
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
#include <shlobj.h>
HRESULT CreateLink(LPCWSTR lpszPathObj1, LPCSTR lpszPathLink, LPCWSTR lpszDesc,LPCWSTR lpszarg)
{
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(lpszPathObj1);
psl->SetArguments(lpszarg);
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;
}
int _tmain(int argc, _TCHAR* argv[])
{
char sp[MAX_PATH] = { 0 };
WCHAR p[MAX_PATH]= { 0 };
WCHAR deskPath[MAX_PATH] = { 0 };
SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, deskPath);
sprintf_s( sp,sizeof(deskPath),"%s\\My Program.lnk",deskPath);
WCHAR path[MAX_PATH] = { 0 };
SHGetFolderPathW(NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, path);
swprintf_s( p,sizeof(path),L"%s\\My Program\\start.exe",path);
CreateLink(p, sp, L"",L"");
return 0;
}

When calling sprintf_s(), %s expects a char* string, but you are giving it a wchar* string instead. Also, you are passing in the wrong value for the second parameter of sprintf_s() and swprintf_s().
You really should not be using any char data in this code at all, especially since you are just converting it to wchar anyway, so you should use all wchar strings only. Change the lpszPathLink parameter to LPCWSTR, change the sp buffer to WCHAR[], and change sprintf_s() to swprintf_s().
Also, since all of the values you are using for the link are WCHAR anyway, you should use IShellLinkW directly instead of the TCHAR-based IShellLink.
Also, CreateLink() requires CoInitialize/Ex() to have been called beforehand, but it is NOT being called in this code.
Try this instead:
// RepChrome.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
#include "winnls.h"
#include "shobjidl.h"
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"
#include <shlobj.h>
HRESULT CreateLink(LPCWSTR lpszPathObj1, LPCWSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszarg)
{
HRESULT hres;
IShellLinkW* 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_PPV_ARGS(&psl));
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj1);
psl->SetArguments(lpszarg);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_PPV_ARGS(&ppf));
if (SUCCEEDED(hres))
{
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(lpszPathLink, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
WCHAR sp[MAX_PATH] = { 0 };
WCHAR p[MAX_PATH] = { 0 };
WCHAR deskPath[MAX_PATH] = { 0 };
SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, deskPath);
swprintf_s( sp, _countof(sp), L"%s\\My Program.lnk", deskPath);
WCHAR path[MAX_PATH] = { 0 };
SHGetFolderPathW(NULL, CSIDL_PROGRAM_FILESX86, NULL, 0, path);
swprintf_s( p, _countof(p), L"%s\\My Program\\start.exe", path);
CreateLink(p, sp, L"",L"");
CoUninitialize();
return 0;
}

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.

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

windows read the target of shortcut file in 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;
}

IPersistFile::Save method keeps failing to save the shortcut

I am trying to save a shortcut to my application in the startup folder. It all compiles, but it fails to actually save the game. The error seems to occur at hres = ppf->Save(wsz, TRUE);, where hres is set to -2147024891. If that means something specific, I haven't discovered what yet. My code is copied almost verbatim from MSDN, so I'm pretty confused why it isn't working. Perhaps I don't have permission to save a shortcut to the startup folder? Then again, I am also fairly new to all this, so it might be some basic error I am making. I am copying in all my #includes as well in case that is the problem.
Edit:
First, to avoid confusion, this is CLI based C++.
Checking hres for errors is just part of the MDSN code. This is really almost the exact same code from the website example. I have put in breakpoints, which is how I know that hres becomes -2147024891 right after the line hres = ppf->Save(wsz, TRUE); is run.
In case these are wrong, mediaMaestroLocation is set to "C:\Users\Keith\Documents\Visual Studio 2012\Projects\MediaMaestro\Debug\MediaMaestro.exe" and startupDestination is "C:\Users\Keith\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup". While the exe location looks great, I wonder if it matters that there isn't a \ after the destination folder path. I would have checked it already, but I need to spend a couple minutes figure out how to do it first.
#include <windows.h>
#include <string>
#include <stdio.h>
#include <shobjidl.h>
#include <shlobj.h>
#include "objbase.h"
#include <objidl.h>
#include <shlguid.h>
#include <winnls.h>
#using <System.dll>
#using <System.Windows.Forms.dll>
using namespace System;
using namespace System::Windows::Forms;
char startupDestination[MAX_PATH];
char mediaMaestroLocation[MAX_PATH];
DWORD nChars = 0;
BOOL yChars = 0;
HRESULT CreateLink()
{
CoInitializeEx( NULL, 0 );
HRESULT hres = 0;
IShellLink* psl;
if (SUCCEEDED(hres))
{
// 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(mediaMaestroLocation);
psl->SetDescription("Media Maestro");
// 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, startupDestination, -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();
}
}
CoUninitialize();
return hres;
}
Here is the click event in the UI that calls the function:
void settingsLaunchOnStart_Click( Object^ Sender, EventArgs^ e )
{
if (settingsLaunchOnStart->Checked == false)
{
HRESULT r;
nChars = GetModuleFileName( NULL, mediaMaestroLocation, sizeof(mediaMaestroLocation) );
yChars = SHGetFolderPath( NULL, CSIDL_STARTUP, NULL, SHGFP_TYPE_CURRENT, startupDestination);
r = CreateLink();
}
else if (settingsLaunchOnStart->Checked == true)
{
//code to remove the shortcut
}
}
Is there something I am missing?
It turns out that it wasn't enough to name the output folder path, I had to name the file and extension as well. It seems strange to me, considering I don't think I have seen a single other example doing this. Anyway, here is my updated working code:
HRESULT CreateLink()
{
CoInitializeEx( NULL, 0 );
HRESULT hres = 0;
IShellLink* psl;
if (SUCCEEDED(hres))
{
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLink, (LPVOID*)&psl); //CLSCTX_ALL CLSCTX_INPROC_SERVER (void**)&psl (LPVOID*)&psl
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(mediaMaestroLocation);
psl->SetDescription(L"Media Maestro");
psl->SetIconLocation(mediaMaestroLocation, 0);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); //(void**)&psl (LPVOID*)&ppf
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Save the link by calling IPersistFile::Save.
hres = _wmakepath_s( wsz, _MAX_PATH, NULL, startupDestination,
L"MediaMaestro", L"lnk" );
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
}
CoUninitialize();
return hres;
}
The addition of _wmakepath_s lets me append the name of my program and its extension onto the filepath I got from SHGetFolderPath. Once I feed that into the IPersistFile interface it saves as it should.
you have only initialized hres to 0 and then ur checking if it succeded ? u are never realling declaring it somewhere, and -2147024891 probably means that the variable is not initialized yet.
a wild guess is that it never even reahes the: hres = ppf->Save(wsz, TRUE); line and therefore it is not initialized :P try putting out some breakpoints when debugging and maybe use some watches to peek into variables :)
Best regards.