mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
[SHELL32][MKSHELLLINK] Support EXP_SPECIAL_FOLDER datablock in shortcuts (#7158)
CORE-19692
This commit is contained in:
parent
751641c2be
commit
7b081be46d
3 changed files with 114 additions and 19 deletions
|
@ -746,6 +746,22 @@ HRESULT STDMETHODCALLTYPE CShellLink::Load(IStream *stm)
|
||||||
if (FAILED(hr)) // FIXME: Should we fail?
|
if (FAILED(hr)) // FIXME: Should we fail?
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
|
LPEXP_SPECIAL_FOLDER pSpecial = (LPEXP_SPECIAL_FOLDER)SHFindDataBlock(m_pDBList, EXP_SPECIAL_FOLDER_SIG);
|
||||||
|
if (pSpecial && pSpecial->cbSize == sizeof(*pSpecial) && ILGetSize(m_pPidl) > pSpecial->cbOffset)
|
||||||
|
{
|
||||||
|
if (LPITEMIDLIST folder = SHCloneSpecialIDList(NULL, pSpecial->idSpecialFolder, FALSE))
|
||||||
|
{
|
||||||
|
LPITEMIDLIST pidl = ILCombine(folder, (LPITEMIDLIST)((char*)m_pPidl + pSpecial->cbOffset));
|
||||||
|
if (pidl)
|
||||||
|
{
|
||||||
|
ILFree(m_pPidl);
|
||||||
|
m_pPidl = pidl;
|
||||||
|
TRACE("Replaced pidl base with CSIDL %u up to %ub.\n", pSpecial->idSpecialFolder, pSpecial->cbOffset);
|
||||||
|
}
|
||||||
|
ILFree(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (TRACE_ON(shell))
|
if (TRACE_ON(shell))
|
||||||
{
|
{
|
||||||
#if (NTDDI_VERSION < NTDDI_LONGHORN)
|
#if (NTDDI_VERSION < NTDDI_LONGHORN)
|
||||||
|
|
|
@ -14,8 +14,20 @@ WINE_DEFAULT_DEBUG_CHANNEL (shell);
|
||||||
|
|
||||||
static HRESULT SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, LPCWSTR KeyName, CLSID* pclsidFolder);
|
static HRESULT SHELL32_GetCLSIDForDirectory(LPCWSTR pwszDir, LPCWSTR KeyName, CLSID* pclsidFolder);
|
||||||
|
|
||||||
|
static LPCWSTR GetItemFileName(PCUITEMID_CHILD pidl, LPWSTR Buf, UINT cchMax)
|
||||||
|
{
|
||||||
|
FileStructW* pDataW = _ILGetFileStructW(pidl);
|
||||||
|
if (pDataW)
|
||||||
|
return pDataW->wszName;
|
||||||
|
LPPIDLDATA pdata = _ILGetDataPointer(pidl);
|
||||||
|
if ((pdata->type & PT_VALUEW) == PT_VALUEW)
|
||||||
|
return (LPWSTR)pdata->u.file.szNames;
|
||||||
|
if (_ILSimpleGetTextW(pidl, Buf, cchMax))
|
||||||
|
return Buf;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
HKEY OpenKeyFromFileType(LPWSTR pExtension, LPCWSTR KeyName)
|
static HKEY OpenKeyFromFileType(LPCWSTR pExtension, LPCWSTR KeyName)
|
||||||
{
|
{
|
||||||
HKEY hkey;
|
HKEY hkey;
|
||||||
|
|
||||||
|
@ -45,7 +57,7 @@ HKEY OpenKeyFromFileType(LPWSTR pExtension, LPCWSTR KeyName)
|
||||||
return hkey;
|
return hkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
LPWSTR ExtensionFromPidl(PCUIDLIST_RELATIVE pidl)
|
static LPCWSTR ExtensionFromPidl(PCUIDLIST_RELATIVE pidl, LPWSTR Buf, UINT cchMax)
|
||||||
{
|
{
|
||||||
if (!_ILIsValue(pidl))
|
if (!_ILIsValue(pidl))
|
||||||
{
|
{
|
||||||
|
@ -53,23 +65,17 @@ LPWSTR ExtensionFromPidl(PCUIDLIST_RELATIVE pidl)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileStructW* pDataW = _ILGetFileStructW(pidl);
|
LPCWSTR name = GetItemFileName(pidl, Buf, cchMax);
|
||||||
if (!pDataW)
|
LPCWSTR pExtension = name ? PathFindExtensionW(name) : NULL;
|
||||||
{
|
|
||||||
ERR("Invalid pidl!\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPWSTR pExtension = PathFindExtensionW(pDataW->wszName);
|
|
||||||
if (!pExtension || *pExtension == UNICODE_NULL)
|
if (!pExtension || *pExtension == UNICODE_NULL)
|
||||||
{
|
{
|
||||||
WARN("No extension for %S!\n", pDataW->wszName);
|
WARN("No extension for %S!\n", name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return pExtension;
|
return pExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT GetCLSIDForFileTypeFromExtension(LPWSTR pExtension, LPCWSTR KeyName, CLSID* pclsid)
|
static HRESULT GetCLSIDForFileTypeFromExtension(LPCWSTR pExtension, LPCWSTR KeyName, CLSID* pclsid)
|
||||||
{
|
{
|
||||||
HKEY hkeyProgId = OpenKeyFromFileType(pExtension, KeyName);
|
HKEY hkeyProgId = OpenKeyFromFileType(pExtension, KeyName);
|
||||||
if (!hkeyProgId)
|
if (!hkeyProgId)
|
||||||
|
@ -126,7 +132,8 @@ HRESULT GetCLSIDForFileTypeFromExtension(LPWSTR pExtension, LPCWSTR KeyName, CLS
|
||||||
|
|
||||||
HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pclsid)
|
HRESULT GetCLSIDForFileType(PCUIDLIST_RELATIVE pidl, LPCWSTR KeyName, CLSID* pclsid)
|
||||||
{
|
{
|
||||||
LPWSTR pExtension = ExtensionFromPidl(pidl);
|
WCHAR buf[256];
|
||||||
|
LPCWSTR pExtension = ExtensionFromPidl(pidl, buf, _countof(buf));
|
||||||
if (!pExtension)
|
if (!pExtension)
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
|
||||||
|
@ -289,7 +296,8 @@ HRESULT CFSExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, RE
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LPWSTR pExtension = ExtensionFromPidl(pidl);
|
WCHAR extbuf[256];
|
||||||
|
LPCWSTR pExtension = ExtensionFromPidl(pidl, extbuf, _countof(extbuf));
|
||||||
HKEY hkey = pExtension ? OpenKeyFromFileType(pExtension, L"DefaultIcon") : NULL;
|
HKEY hkey = pExtension ? OpenKeyFromFileType(pExtension, L"DefaultIcon") : NULL;
|
||||||
if (!hkey)
|
if (!hkey)
|
||||||
WARN("Could not open DefaultIcon key!\n");
|
WARN("Could not open DefaultIcon key!\n");
|
||||||
|
|
|
@ -18,8 +18,14 @@ typedef unsigned __int16 uint16_t;
|
||||||
typedef unsigned __int32 uint32_t;
|
typedef unsigned __int32 uint32_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SW_SHOWNORMAL 1
|
#define SW_SHOWNORMAL 1
|
||||||
#define SW_SHOWMINNOACTIVE 7
|
#define SW_SHOWMINNOACTIVE 7
|
||||||
|
#define CSIDL_WINDOWS 0x24
|
||||||
|
#define CSIDL_SYSTEM 0x25
|
||||||
|
|
||||||
typedef struct _GUID
|
typedef struct _GUID
|
||||||
{
|
{
|
||||||
|
@ -125,17 +131,61 @@ typedef struct _ID_LIST_DRIVE
|
||||||
uint16_t unknown;
|
uint16_t unknown;
|
||||||
} ID_LIST_DRIVE;
|
} ID_LIST_DRIVE;
|
||||||
|
|
||||||
|
#define EXP_SPECIAL_FOLDER_SIG 0xA0000005
|
||||||
|
typedef struct _EXP_SPECIAL_FOLDER
|
||||||
|
{
|
||||||
|
uint32_t cbSize, dwSignature, idSpecialFolder, cbOffset;
|
||||||
|
} EXP_SPECIAL_FOLDER;
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
static const struct SPECIALFOLDER {
|
||||||
|
unsigned char csidl;
|
||||||
|
const char* name;
|
||||||
|
} g_specialfolders[] = {
|
||||||
|
{ CSIDL_WINDOWS, "windows" },
|
||||||
|
{ CSIDL_SYSTEM, "system" },
|
||||||
|
{ 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int is_path_separator(unsigned int c)
|
||||||
|
{
|
||||||
|
return c == '\\' || c == '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct SPECIALFOLDER* get_special_folder(const char *target)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
strncpy(buf, target, sizeof(buf));
|
||||||
|
buf[sizeof("shell:") - 1] = '\0';
|
||||||
|
if (strcasecmp("shell:", buf))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
target += sizeof("shell:") - 1;
|
||||||
|
for (unsigned long i = 0;; ++i)
|
||||||
|
{
|
||||||
|
unsigned long len;
|
||||||
|
const struct SPECIALFOLDER *special = &g_specialfolders[i];
|
||||||
|
if (!special->name)
|
||||||
|
return NULL;
|
||||||
|
len = strlen(special->name);
|
||||||
|
strncpy(buf, target, sizeof(buf));
|
||||||
|
buf[len] = '\0';
|
||||||
|
if (!strcasecmp(special->name, buf) && (is_path_separator(target[len]) || !target[len]))
|
||||||
|
return &g_specialfolders[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
const char *pszOutputPath = "shortcut.lnk";
|
const char *pszOutputPath = "shortcut.lnk";
|
||||||
const char *pszTarget = NULL;
|
const char *pszTarget = NULL;
|
||||||
const char *pszDescription = "Description";
|
const char *pszDescription = NULL;
|
||||||
const char *pszWorkingDir = NULL;
|
const char *pszWorkingDir = NULL;
|
||||||
const char *pszCmdLineArgs = NULL;
|
const char *pszCmdLineArgs = NULL;
|
||||||
const char *pszIcon = NULL;
|
const char *pszIcon = NULL;
|
||||||
|
char targetpath[260];
|
||||||
int IconNr = 0;
|
int IconNr = 0;
|
||||||
GUID Guid = CLSID_MyComputer;
|
GUID Guid = CLSID_MyComputer;
|
||||||
int bHelp = 0, bMinimized = 0;
|
int bHelp = 0, bMinimized = 0;
|
||||||
|
@ -143,6 +193,7 @@ int main(int argc, const char *argv[])
|
||||||
LNK_HEADER Header;
|
LNK_HEADER Header;
|
||||||
uint16_t uhTmp;
|
uint16_t uhTmp;
|
||||||
uint32_t dwTmp;
|
uint32_t dwTmp;
|
||||||
|
EXP_SPECIAL_FOLDER CsidlBlock, *pCsidlBlock = NULL;
|
||||||
|
|
||||||
for (i = 1; i < argc; ++i)
|
for (i = 1; i < argc; ++i)
|
||||||
{
|
{
|
||||||
|
@ -226,14 +277,26 @@ int main(int argc, const char *argv[])
|
||||||
ID_LIST_DRIVE IdListDrive;
|
ID_LIST_DRIVE IdListDrive;
|
||||||
unsigned cbListSize = sizeof(IdListGuid) + sizeof(uint16_t), cchName;
|
unsigned cbListSize = sizeof(IdListGuid) + sizeof(uint16_t), cchName;
|
||||||
const char *pszName = pszTarget;
|
const char *pszName = pszTarget;
|
||||||
|
int index = 1, specialindex = -1;
|
||||||
|
const struct SPECIALFOLDER *special = get_special_folder(pszTarget);
|
||||||
|
|
||||||
// ID list
|
// ID list
|
||||||
// It seems explorer does not accept links without id list. List is relative to desktop.
|
// It seems explorer does not accept links without id list. List is relative to desktop.
|
||||||
|
|
||||||
pszName = pszTarget;
|
if (special)
|
||||||
|
|
||||||
if (pszName[0] && pszName[1] == ':')
|
|
||||||
{
|
{
|
||||||
|
Header.Flags &= ~LINK_RELATIVE_PATH;
|
||||||
|
CsidlBlock.cbSize = sizeof(CsidlBlock);
|
||||||
|
CsidlBlock.dwSignature = EXP_SPECIAL_FOLDER_SIG;
|
||||||
|
CsidlBlock.idSpecialFolder = special->csidl;
|
||||||
|
specialindex = 3; // Skip GUID, drive and fake windows/reactos folder
|
||||||
|
sprintf(targetpath, "x:\\reactos\\%s", pszTarget + sizeof("shell:") + strlen(special->name));
|
||||||
|
pszName = pszTarget = targetpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pszName[0] && pszName[0] != ':' && pszName[1] == ':')
|
||||||
|
{
|
||||||
|
++index;
|
||||||
cbListSize += sizeof(IdListDrive);
|
cbListSize += sizeof(IdListDrive);
|
||||||
pszName += 2;
|
pszName += 2;
|
||||||
while (*pszName == '\\' || *pszName == '/')
|
while (*pszName == '\\' || *pszName == '/')
|
||||||
|
@ -249,6 +312,12 @@ int main(int argc, const char *argv[])
|
||||||
if (cchName != 1 || pszName[0] != '.')
|
if (cchName != 1 || pszName[0] != '.')
|
||||||
cbListSize += sizeof(IdListFile) + 2 * (cchName + 1);
|
cbListSize += sizeof(IdListFile) + 2 * (cchName + 1);
|
||||||
|
|
||||||
|
if (++index == specialindex)
|
||||||
|
{
|
||||||
|
CsidlBlock.cbOffset = cbListSize - sizeof(uint16_t);
|
||||||
|
pCsidlBlock = &CsidlBlock;
|
||||||
|
}
|
||||||
|
|
||||||
pszName += cchName;
|
pszName += cchName;
|
||||||
while (*pszName == '\\' || *pszName == '/')
|
while (*pszName == '\\' || *pszName == '/')
|
||||||
++pszName;
|
++pszName;
|
||||||
|
@ -309,7 +378,7 @@ int main(int argc, const char *argv[])
|
||||||
|
|
||||||
if (Header.Flags & LINK_DESCRIPTION)
|
if (Header.Flags & LINK_DESCRIPTION)
|
||||||
{
|
{
|
||||||
// Dscription
|
// Description
|
||||||
uhTmp = strlen(pszDescription);
|
uhTmp = strlen(pszDescription);
|
||||||
fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
|
fwrite(&uhTmp, sizeof(uhTmp), 1, pFile);
|
||||||
fputs(pszDescription, pFile);
|
fputs(pszDescription, pFile);
|
||||||
|
@ -348,6 +417,8 @@ int main(int argc, const char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra stuff
|
// Extra stuff
|
||||||
|
if (pCsidlBlock)
|
||||||
|
fwrite(pCsidlBlock, sizeof(*pCsidlBlock), 1, pFile);
|
||||||
dwTmp = 0;
|
dwTmp = 0;
|
||||||
fwrite(&dwTmp, sizeof(dwTmp), 1, pFile);
|
fwrite(&dwTmp, sizeof(dwTmp), 1, pFile);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue