📄 shortcut.cpp
字号:
//*******************************************************************
//
// FILE: Shortcut.cpp
//
// AUTHOR: Thomas Latuske <CobUser@GMX.de>
//
// COMPONENT: CShortcut
//
// DATE: 04.05.2004
//
// COMMENTS: Update 11.05.2004:
// - added ResolveLink
// - added GetSpecialFolder (split off)
//
//*******************************************************************
// Includes
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "stdafx.h"
#include "Shortcut.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Konstruktion/Destruktion
//////////////////////////////////////////////////////////////////////
CShortcut::CShortcut()
{
m_sCmdArg.Empty();
}
CShortcut::~CShortcut()
{
}
/*!
***************************************************************
\param LnkTarget - The File/Folder the link belongs to
\param LnkName - The name of the ShortCut
\param SpecialFolder - where to put the shortcut (See #defines below)
\param LnkDescription - an application can use it to store\n
any text information and can retrieve\n
it with "IShellLink::GetDescription"\n
\param IconLocation - path to the file where the icon is located\n
that should be used. Can be an empty string\n
\param IconIndex - the # of the icon in the file\n
\return BOOL - ShortCut created or not\n
Defines for Special Folders:
SendTo Menu/Folder: CSIDL_SENDTO
Desktop for current User CSIDL_DESKTOP
Desktop: CSIDL_COMMON_DESKTOPDIRECTORY
Autostart for current User: CSIDL_STARTUP
Autostart: CSIDL_COMMON_STARTUP
Start-menu for current User: CSIDL_STARTMENU
Start-menu: CSIDL_STARTMENU
Programms-menu for current User:CSIDL_COMMON_STARTMENU
and some more.....
*****************************************************************/
BOOL CShortcut::CreateShortCut(CString LnkTarget, CString LnkName, UINT SpecialFolder, CString LnkDescription, CString IconLocation, UINT IconIndex)
{
HRESULT hr;
CFile cfFull;
CString sExePath, sExe, sSpecialFolder;
char *chTmp = sExePath.GetBuffer(MAX_PATH);
GetModuleFileName(NULL, chTmp, MAX_PATH);
sExePath.ReleaseBuffer();
// Find the Special Folder:
if(!GetSpecialFolder(SpecialFolder, sSpecialFolder))
return FALSE;
sSpecialFolder += LnkName + "." + "lnk";
if(LnkTarget == "_this")
{
cfFull.SetFilePath(sExePath);
sExe = cfFull.GetFileName();
sExe.Delete(sExe.Find(".") + 1, 3);
}
else
{
sExePath = LnkTarget;
}
// Create the ShortCut:
CoInitialize(NULL);
BOOL bRet = FALSE;
IShellLink* psl;
if (SUCCEEDED( CoCreateInstance(CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellLink,
(LPVOID*) &psl)))
{
IPersistFile* ppf;
//
psl->SetPath(sExePath);
psl->SetDescription(LnkDescription);
if(!m_sCmdArg.IsEmpty())
psl->SetArguments(m_sCmdArg);
if (SUCCEEDED(psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf)))
{
WORD wsz[MAX_PATH];
MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
sSpecialFolder,
-1,
wsz,
MAX_PATH);
/* Call IShellLink::SetIconLocation with the file containing
the icon and the index of the icon */
if(!IconLocation.IsEmpty())
{
hr = psl->SetIconLocation(IconLocation, IconIndex);
#ifdef _DEBUG
if(FAILED(hr))
TRACE("IconLocation not changed!\n");
#endif
}
if(SUCCEEDED(ppf->Save(wsz, TRUE)))
{
bRet = TRUE;
}
ppf->Release();
}
psl->Release();
}
if(bRet)
{
TRACE("Lnk Written!\n");
}
else
{
TRACE("Lnk NOT Written! CreateShortCut(...) failed!\n");
}
return bRet;
}
/*!
***************************************************************
\param LnkName - The name of the ShortCut
\param SpecialFolder - Location of the shortcut (See #defines below)
\return void
Defines for Special Folders:
SendTo Menu/Folder: CSIDL_SENDTO
Desktop for current User CSIDL_DESKTOP
Desktop: CSIDL_COMMON_DESKTOPDIRECTORY
Autostart for current User: CSIDL_STARTUP
Autostart: CSIDL_COMMON_STARTUP
Start-menu for current User: CSIDL_STARTMENU
Start-menu: CSIDL_STARTMENU
Programms-menu for current User:CSIDL_COMMON_STARTMENU
and some more.....
*****************************************************************/
BOOL CShortcut::DeleteShortCut(CString LnkName, UINT SpecialFolder)
{
CFile cfFull;
CString sExePath, sExe, sSpecialFolder;
char *chTmp = sExePath.GetBuffer(MAX_PATH);
GetModuleFileName(NULL, chTmp, MAX_PATH);
sExePath.ReleaseBuffer();
if(!GetSpecialFolder(SpecialFolder, sSpecialFolder))
return FALSE;
// Work with the special folder's path (contained in szPath)
cfFull.SetFilePath(sExePath);
sExe = cfFull.GetFileName();
sExe.Delete(sExe.Find(".") + 1, 3);
sSpecialFolder += LnkName + "." + "lnk";
// DELETE THE LINK:
SHFILEOPSTRUCT FIO;
memset(&FIO, 0, sizeof SHFILEOPSTRUCT);
// FIO.pTo=NULL; // MUST be NULL
FIO.wFunc=FO_DELETE;
FIO.fFlags=FOF_NOERRORUI|FOF_NOCONFIRMATION;
if(sSpecialFolder.Find('\0')!=sSpecialFolder.GetLength())
{
FIO.fFlags|=FOF_MULTIDESTFILES;
}
if(sSpecialFolder.Right(1))
{
sSpecialFolder+='\0';
}
FIO.pFrom=&*sSpecialFolder;
int bD = SHFileOperation(&FIO);
if(!bD)
{
TRACE("Lnk Deleted!\n");
return TRUE;
}
else
{
TRACE("Lnk NOT Deleted! DeleteShortCut(...) FAILED!\n");
return FALSE;
}
}
/*********************************************
This is useful when creating a link to an
application that takes command-line arguments:
*********************************************/
void CShortcut::SetCmdArguments(CString sArg)
{
m_sCmdArg = sArg;
}
/*********************************************
This routine tests if a link already existits:
*********************************************/
BOOL CShortcut::isLinkAvailable(CString LnkName, UINT SpecialFolder)
{
CFileStatus cfStatus;
CString sSpecialFolder;
// Find the Special Folder:
if(!GetSpecialFolder(SpecialFolder, sSpecialFolder))
return FALSE;
// Work with the special folder's path (contained in szPath)
sSpecialFolder += "\\";
sSpecialFolder += LnkName + "." + "lnk";
if(CFile::GetStatus(sSpecialFolder, cfStatus))
{
#ifdef _DEBUG
afxDump << "Full file name = " << cfStatus.m_szFullName << "\n";
#endif
return TRUE;
}
else
{
#ifdef _DEBUG
afxDump << "File NOT available = " << cfStatus.m_szFullName << "\n";
#endif
return FALSE;
}
}
/*********************************************
This routine resolves the lnk destination:
\param LnkName - The name of the ShortCut\n
\param SpecialFolder - where to put the shortcut (See #defines above (MSDN))\n
\param hwnd - handle of the parent window for MessageBoxes\n
the shell may need to display\n
\param LnkPath - Reference to a CString that receives the linkpath if\n
routine is successful else the string will be empty\n
\param LnkDescription - Reference to a CString that receives the Description\n
of the link else the string will be empty\n
\returns a HRESULT \n
*********************************************/
HRESULT CShortcut::ResolveLink(CString LnkName, UINT SpecialFolder, HWND hwnd, CString &LnkPath, CString &LnkDescription)
{
HRESULT hres;
IShellLink* psl;
char *szGotPath = LnkPath.GetBuffer(MAX_PATH);
char *szDescription = LnkDescription.GetBuffer(MAX_PATH);
CString sLnkFile, sSpecialFolder;
CString sLong;
WIN32_FIND_DATA wfd;
// get the path to the special folder:
if(!GetSpecialFolder(SpecialFolder, sSpecialFolder))
return 1; // return ERROR
// build a linkfile:
sLnkFile = sSpecialFolder + LnkName + ".lnk";
// Get a pointer to the IShellLink interface.
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, (LPVOID *)&ppf);
if (SUCCEEDED(hres))
{
WORD wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP,
0,
sLnkFile,//lpszLinkFile,
-1,
wsz,
MAX_PATH); // Load the shortcut.
hres = ppf->Load(wsz, STGM_READ);
if (SUCCEEDED(hres))
{ // Resolve the link.
hres = psl->Resolve(hwnd, SLR_ANY_MATCH);
if (SUCCEEDED(hres))
{
// Get the path to the link target.
hres = psl->GetPath(szGotPath,
MAX_PATH,
(WIN32_FIND_DATA *)&wfd,
SLGP_SHORTPATH );
LnkPath.ReleaseBuffer();
if (!SUCCEEDED(hres))
{
LnkDescription.ReleaseBuffer();
return hres; // application-defined function
}
// Get the description of the target:
hres = psl->GetDescription(szDescription, MAX_PATH);
LnkDescription.ReleaseBuffer();
if (!SUCCEEDED(hres))
return hres;
}
}
// Release the pointer to the IPersistFile interface.
ppf->Release();
}
// Release the pointer to the IShellLink interface.
psl->Release();
}
// whether OS is <= NT4 or not... use this helper:
if(ShortToLongPathName(LnkPath, sLong) > LnkPath.GetLength())
LnkPath = sLong;
return hres;
}
/*********************************************
This routine is a helper that finds\n
the path to the special folder:\n
\param SpecialFolder - an UINT-define (See #defines above or (MSDN))\n
\param SpecialFolderString - Reference to a CString that receives the\n
path to the special folder
\returns a BOOL - Found or not \n
*********************************************/
BOOL CShortcut::GetSpecialFolder(UINT SpecialFolder, CString &SpecialFolderString)
{
HRESULT hr;
// Find the Special Folder:
// Allocate a pointer to an Item ID list
LPITEMIDLIST pidl;
// Get a pointer to an item ID list that
// represents the path of a special folder
hr = SHGetSpecialFolderLocation(NULL, SpecialFolder, &pidl);
if(SUCCEEDED(hr))
{ // Convert the item ID list's binary
// representation into a file system path
char szPath[_MAX_PATH];
if(SHGetPathFromIDList(pidl, szPath))
{
// Allocate a pointer to an IMalloc interface
LPMALLOC pMalloc;
// Get the address of our task allocator's IMalloc interface
hr = SHGetMalloc(&pMalloc);
// Free the item ID list allocated by SHGetSpecialFolderLocation
pMalloc->Free(pidl);
// Free our task allocator
pMalloc->Release();
// Work with the special folder's path (contained in szPath)
SpecialFolderString = szPath;
SpecialFolderString += "\\";
return TRUE;
}
}
return FALSE;
}
/*********************************************
This routine is a helper that builds a long\n
path of a short (8+3) path:\n
\param sShortPath - short path to convert\n
\param sLongPath - string that receives the long path\n
\returns a BOOL - Found or not \n
*********************************************/
// if the extension contains '~', replace it with '*'!!!!!!!!!!!!!!!
int CShortcut::ShortToLongPathName(CString sShortPath, CString &sLongPath)
{
// Catch null pointers.
if (sShortPath.IsEmpty()) return 0;
// Check whether the input path is valid.
if (0xffffffff == GetFileAttributes(sShortPath)) return 0;
// Special characters.
CString sep = "\\";
CString colon = ":";
CString sDrive, sCutPath, sTmpShort;
int npos = sShortPath.GetLength();
// Copy the short path into the work buffer and convert forward
// slashes to backslashes.
CString path = sShortPath;
path.Replace("/", sep);
// We need a couple of markers for stepping through the path.
int left = 0;
int right = 0;
// Parse the first bit of the path.
if (path.GetLength() >= 2 && isalpha(path[0]) && colon == path[1]) // Drive letter?
{
if (2 == path.GetLength()) // 抌are
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -