https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8e60c2efeefbb2a4d9389…
commit 8e60c2efeefbb2a4d93894c8300c0244bf54fea6
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Tue Apr 23 10:48:34 2019 +0900
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Wed Apr 24 03:28:17 2019 +0200
[SHELL32] Implement 'New Link' (Retrial of #1510), CORE-15511 (#1518)
Correctly create cache about ".lnk" and handling in the member functions.
Co-authored-by: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
---
dll/win32/shell32/CNewMenu.cpp | 309 +++++++++++++++++++++--------------------
dll/win32/shell32/CNewMenu.h | 7 +-
2 files changed, 164 insertions(+), 152 deletions(-)
diff --git a/dll/win32/shell32/CNewMenu.cpp b/dll/win32/shell32/CNewMenu.cpp
index 4a17e9b58b..d4b86863f3 100644
--- a/dll/win32/shell32/CNewMenu.cpp
+++ b/dll/win32/shell32/CNewMenu.cpp
@@ -4,6 +4,7 @@
* Copyright 2007 Johannes Anderwald (johannes.anderwald(a)reactos.org)
* Copyright 2009 Andrew Hill
* Copyright 2012 Rafal Harabien
+ * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -60,18 +61,14 @@ void CNewMenu::UnloadAllItems()
{
SHELLNEW_ITEM *pCurItem;
- /* Unload normal items */
+ /* Unload the handler items, including the link item */
while (m_pItems)
{
pCurItem = m_pItems;
m_pItems = m_pItems->pNext;
-
UnloadItem(pCurItem);
}
-
- /* Unload link item */
- if (m_pLinkItem)
- UnloadItem(m_pLinkItem);
+ m_pItems = NULL;
m_pLinkItem = NULL;
}
@@ -183,21 +180,21 @@ CNewMenu::CacheItems()
if (pNewItem)
{
dwSize += wcslen(wszName) + 1;
- if (wcsicmp(pNewItem->pwszExt, L".lnk") == 0)
+ if (!m_pLinkItem && wcsicmp(pNewItem->pwszExt, L".lnk")
== 0)
{
- /* Link handler */
+ /* The unique link handler */
m_pLinkItem = pNewItem;
}
+
+ /* Add at the end of the list */
+ if (pCurItem)
+ {
+ pCurItem->pNext = pNewItem;
+ pCurItem = pNewItem;
+ }
else
{
- /* Add at the end of list */
- if (pCurItem)
- {
- pCurItem->pNext = pNewItem;
- pCurItem = pNewItem;
- }
- else
- pCurItem = m_pItems = pNewItem;
+ pCurItem = m_pItems = pNewItem;
}
}
}
@@ -208,13 +205,10 @@ CNewMenu::CacheItems()
if (!lpValues)
return FALSE;
- lpValue = lpValues;
- pCurItem = m_pItems;
- while (pCurItem)
+ for (pCurItem = m_pItems, lpValue = lpValues; pCurItem; pCurItem =
pCurItem->pNext)
{
memcpy(lpValue, pCurItem->pwszExt, (wcslen(pCurItem->pwszExt) + 1) *
sizeof(WCHAR));
lpValue += wcslen(pCurItem->pwszExt) + 1;
- pCurItem = pCurItem->pNext;
}
if (RegCreateKeyEx(HKEY_CURRENT_USER, ShellNewKey, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
@@ -269,21 +263,21 @@ CNewMenu::LoadCachedItems()
pNewItem = LoadItem(wszName);
if (pNewItem)
{
- if (wcsicmp(pNewItem->pwszExt, L".lnk") == 0)
+ if (!m_pLinkItem && wcsicmp(pNewItem->pwszExt, L".lnk")
== 0)
{
- /* Link handler */
+ /* The unique link handler */
m_pLinkItem = pNewItem;
}
+
+ /* Add at the end of the list */
+ if (pCurItem)
+ {
+ pCurItem->pNext = pNewItem;
+ pCurItem = pNewItem;
+ }
else
{
- /* Add at the end of list */
- if (pCurItem)
- {
- pCurItem->pNext = pNewItem;
- pCurItem = pNewItem;
- }
- else
- pCurItem = m_pItems = pNewItem;
+ pCurItem = m_pItems = pNewItem;
}
}
}
@@ -299,27 +293,13 @@ CNewMenu::LoadAllItems()
{
/* If there are any unload them */
UnloadAllItems();
-
+
if (!LoadCachedItems())
{
CacheItems();
}
-
- if (!m_pLinkItem)
- {
- m_pLinkItem = static_cast<SHELLNEW_ITEM *>(HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, sizeof(SHELLNEW_ITEM)));
- if (m_pLinkItem)
- {
- m_pLinkItem->Type = SHELLNEW_TYPE_NULLFILE;
- m_pLinkItem->pwszDesc = _wcsdup(L"Link");
- m_pLinkItem->pwszExt = _wcsdup(L".lnk");
- }
- }
- if (m_pItems == NULL)
- return FALSE;
- else
- return TRUE;
+ return (m_pItems != NULL);
}
UINT
@@ -349,14 +329,17 @@ CNewMenu::InsertShellNewItems(HMENU hMenu, UINT idCmdFirst, UINT
Pos)
if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii))
++idCmd;
- /* Insert new shortcut action */
- if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEWLINK, wszBuf, _countof(wszBuf)))
- wszBuf[0] = 0;
- mii.dwTypeData = wszBuf;
- mii.cch = wcslen(mii.dwTypeData);
- mii.wID = idCmd;
- if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii))
- ++idCmd;
+ /* Insert the new shortcut action */
+ if (m_pLinkItem)
+ {
+ if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEWLINK, wszBuf,
_countof(wszBuf)))
+ wszBuf[0] = 0;
+ mii.dwTypeData = wszBuf;
+ mii.cch = wcslen(mii.dwTypeData);
+ mii.wID = idCmd;
+ if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii))
+ ++idCmd;
+ }
/* Insert seperator for custom new action */
mii.fMask = MIIM_TYPE | MIIM_ID;
@@ -371,6 +354,10 @@ CNewMenu::InsertShellNewItems(HMENU hMenu, UINT idCmdFirst, UINT
Pos)
SHELLNEW_ITEM *pCurItem = m_pItems;
while (pCurItem)
{
+ /* Skip shortcut item */
+ if (pCurItem == m_pLinkItem)
+ continue;
+
TRACE("szDesc %s\n", debugstr_w(pCurItem->pwszDesc));
mii.dwTypeData = pCurItem->pwszDesc;
mii.cch = wcslen(mii.dwTypeData);
@@ -404,13 +391,18 @@ CNewMenu::SHELLNEW_ITEM *CNewMenu::FindItemFromIdOffset(UINT
IdOffset)
return pItem;
}
-HRESULT CNewMenu::SelectNewItem(LONG wEventId, UINT uFlags, LPWSTR pszName)
+HRESULT CNewMenu::SelectNewItem(LONG wEventId, UINT uFlags, LPWSTR pszName, BOOL
bRename)
{
CComPtr<IShellBrowser> lpSB;
CComPtr<IShellView> lpSV;
HRESULT hr = E_FAIL;
LPITEMIDLIST pidl;
PITEMID_CHILD pidlNewItem;
+ DWORD dwSelectFlags;
+
+ dwSelectFlags = SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED |
SVSI_SELECT;
+ if (bRename)
+ dwSelectFlags |= SVSI_EDIT;
/* Notify the view object about the new item */
SHChangeNotify(wEventId, uFlags, (LPCVOID) pszName, NULL);
@@ -430,8 +422,7 @@ HRESULT CNewMenu::SelectNewItem(LONG wEventId, UINT uFlags, LPWSTR
pszName)
pidlNewItem = ILFindLastID(pidl);
- hr = lpSV->SelectItem(pidlNewItem, SVSI_DESELECTOTHERS | SVSI_EDIT |
SVSI_ENSUREVISIBLE |
- SVSI_FOCUSED | SVSI_SELECT);
+ hr = lpSV->SelectItem(pidlNewItem, dwSelectFlags);
SHFree(pidl);
@@ -463,121 +454,139 @@ HRESULT CNewMenu::CreateNewFolder(LPCMINVOKECOMMANDINFO lpici)
return E_FAIL;
/* Show and select the new item in the def view */
- SelectNewItem(SHCNE_MKDIR, SHCNF_PATHW, wszName);
+ SelectNewItem(SHCNE_MKDIR, SHCNF_PATHW, wszName, TRUE);
return S_OK;
}
-HRESULT CNewMenu::CreateNewItem(SHELLNEW_ITEM *pItem, LPCMINVOKECOMMANDINFO lpcmi)
+HRESULT CNewMenu::NewItemByCommand(SHELLNEW_ITEM *pItem, LPCWSTR wszPath)
{
WCHAR wszBuf[MAX_PATH];
- WCHAR wszPath[MAX_PATH];
- HRESULT hr;
+ LPWSTR Ptr, pwszCmd;
+ WCHAR wszTemp[MAX_PATH];
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
- /* Get folder path */
- hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
- if (FAILED_UNEXPECTEDLY(hr))
- return hr;
+ if (!ExpandEnvironmentStringsW((LPWSTR)pItem->pData, wszBuf, _countof(wszBuf)))
+ {
+ TRACE("ExpandEnvironmentStrings failed\n");
+ return E_FAIL;
+ }
- switch (pItem->Type)
+ /* Expand command parameter, FIXME: there can be more modifiers */
+ Ptr = wcsstr(wszBuf, L"%1");
+ if (Ptr)
{
- case SHELLNEW_TYPE_COMMAND:
- {
- LPWSTR Ptr, pwszCmd;
- WCHAR wszTemp[MAX_PATH];
- STARTUPINFOW si;
- PROCESS_INFORMATION pi;
+ Ptr[1] = L's';
+ StringCbPrintfW(wszTemp, sizeof(wszTemp), wszBuf, wszPath);
+ pwszCmd = wszTemp;
+ }
+ else
+ {
+ pwszCmd = wszBuf;
+ }
- if (!ExpandEnvironmentStringsW((LPWSTR)pItem->pData, wszBuf,
_countof(wszBuf)))
- {
- TRACE("ExpandEnvironmentStrings failed\n");
- break;
- }
+ /* Create process */
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ if (CreateProcessW(NULL, pwszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si,
&pi))
+ {
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return S_OK;
+ }
+ else
+ {
+ ERR("Failed to create process\n");
+ return E_FAIL;
+ }
+}
- /* Expand command parameter, FIXME: there can be more modifiers */
- Ptr = wcsstr(wszBuf, L"%1");
- if (Ptr)
- {
- Ptr[1] = L's';
- StringCbPrintfW(wszTemp, sizeof(wszTemp), wszBuf, wszPath);
- pwszCmd = wszTemp;
- }
- else
- {
- pwszCmd = wszBuf;
- }
+HRESULT CNewMenu::NewItemByNonCommand(SHELLNEW_ITEM *pItem, LPWSTR wszName,
+ DWORD cchNameMax, LPCWSTR wszPath)
+{
+ WCHAR wszBuf[MAX_PATH];
+ WCHAR wszNewFile[MAX_PATH];
+ BOOL bSuccess = TRUE;
- /* Create process */
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- if (CreateProcessW(NULL, pwszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si,
&pi))
- {
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- }
- else
- {
- ERR("Failed to create process\n");
- }
- break;
- }
+ if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszBuf, _countof(wszBuf)))
+ return E_FAIL;
- case SHELLNEW_TYPE_DATA:
- case SHELLNEW_TYPE_FILENAME:
- case SHELLNEW_TYPE_NULLFILE:
+ StringCchPrintfW(wszNewFile, _countof(wszNewFile), L"%s %s%s", wszBuf,
pItem->pwszDesc, pItem->pwszExt);
+
+ /* Create the name of the new file */
+ if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFile))
+ return E_FAIL;
+
+ /* Create new file */
+ HANDLE hFile = CreateFileW(wszName, GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ if (pItem->Type == SHELLNEW_TYPE_DATA)
{
- BOOL bSuccess = TRUE;
- WCHAR wszName[MAX_PATH];
- WCHAR wszNewFile[MAX_PATH];
+ /* Write a content */
+ DWORD cbWritten;
+ WriteFile(hFile, pItem->pData, pItem->cbData, &cbWritten, NULL);
+ }
- if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszBuf,
_countof(wszBuf)))
- return E_FAIL;
+ /* Close file now */
+ CloseHandle(hFile);
+ }
+ else
+ {
+ bSuccess = FALSE;
+ }
- StringCchPrintfW(wszNewFile, _countof(wszNewFile), L"%s %s%s",
wszBuf, pItem->pwszDesc, pItem->pwszExt);
+ if (pItem->Type == SHELLNEW_TYPE_FILENAME)
+ {
+ /* Copy file */
+ if (!CopyFileW((LPWSTR)pItem->pData, wszName, FALSE))
+ ERR("Copy file failed: %ls\n", (LPWSTR)pItem->pData);
+ }
- /* Create the name of the new file */
- if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFile))
- return E_FAIL;
+ /* Show message if we failed */
+ if (bSuccess)
+ {
+ TRACE("Notifying fs %s\n", debugstr_w(wszName));
+ SelectNewItem(SHCNE_CREATE, SHCNF_PATHW, wszName, pItem != m_pLinkItem);
+ }
+ else
+ {
+ StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Cannot create file: %s",
wszName);
+ MessageBoxW(NULL, wszBuf, L"Cannot create file", MB_OK|MB_ICONERROR);
// FIXME load localized error msg
+ }
- /* Create new file */
- HANDLE hFile = CreateFileW(wszName, GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile != INVALID_HANDLE_VALUE)
- {
- if (pItem->Type == SHELLNEW_TYPE_DATA)
- {
- /* Write a content */
- DWORD cbWritten;
- WriteFile(hFile, pItem->pData, pItem->cbData, &cbWritten,
NULL);
- }
+ return S_OK;
+}
- /* Close file now */
- CloseHandle(hFile);
- }
- else
- {
- bSuccess = FALSE;
- }
+HRESULT CNewMenu::CreateNewItem(SHELLNEW_ITEM *pItem, LPCMINVOKECOMMANDINFO lpcmi)
+{
+ HRESULT hr;
+ WCHAR wszPath[MAX_PATH], wszName[MAX_PATH];
- if (pItem->Type == SHELLNEW_TYPE_FILENAME)
- {
- /* Copy file */
- if (!CopyFileW((LPWSTR)pItem->pData, wszName, FALSE))
- ERR("Copy file failed: %ls\n", (LPWSTR)pItem->pData);
- }
+ /* Get folder path */
+ hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
- /* Show message if we failed */
- if (bSuccess)
- {
- TRACE("Notifying fs %s\n", debugstr_w(wszName));
- SelectNewItem(SHCNE_CREATE, SHCNF_PATHW, wszName);
- }
- else
- {
- StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Cannot create file:
%s", wszName);
- MessageBoxW(NULL, wszBuf, L"Cannot create file",
MB_OK|MB_ICONERROR); // FIXME load localized error msg
- }
+ if (pItem == m_pLinkItem)
+ {
+ NewItemByNonCommand(pItem, wszName, _countof(wszName), wszPath);
+ NewItemByCommand(pItem, wszName);
+ return S_OK;
+ }
+
+ switch (pItem->Type)
+ {
+ case SHELLNEW_TYPE_COMMAND:
+ NewItemByCommand(pItem, wszPath);
+ break;
+
+ case SHELLNEW_TYPE_DATA:
+ case SHELLNEW_TYPE_FILENAME:
+ case SHELLNEW_TYPE_NULLFILE:
+ NewItemByNonCommand(pItem, wszName, _countof(wszName), wszPath);
break;
- }
case SHELLNEW_TYPE_INVALID:
ERR("Invalid type\n");
diff --git a/dll/win32/shell32/CNewMenu.h b/dll/win32/shell32/CNewMenu.h
index 2475e725a9..a0c62eb86e 100644
--- a/dll/win32/shell32/CNewMenu.h
+++ b/dll/win32/shell32/CNewMenu.h
@@ -56,7 +56,7 @@ private:
LPITEMIDLIST m_pidlFolder;
LPWSTR m_wszPath;
SHELLNEW_ITEM *m_pItems;
- SHELLNEW_ITEM *m_pLinkItem;
+ SHELLNEW_ITEM *m_pLinkItem; // Points to the link handler item in the m_pItems list.
CComPtr<IUnknown> m_pSite;
HMENU m_hSubMenu;
HICON m_hiconFolder, m_hiconLink;
@@ -71,7 +71,10 @@ private:
SHELLNEW_ITEM *FindItemFromIdOffset(UINT IdOffset);
HRESULT CreateNewFolder(LPCMINVOKECOMMANDINFO lpici);
HRESULT CreateNewItem(SHELLNEW_ITEM *pItem, LPCMINVOKECOMMANDINFO lpcmi);
- HRESULT SelectNewItem(LONG wEventId, UINT uFlags, LPWSTR pszName);
+ HRESULT SelectNewItem(LONG wEventId, UINT uFlags, LPWSTR pszName, BOOL bRename);
+ HRESULT NewItemByCommand(SHELLNEW_ITEM *pItem, LPCWSTR wszPath);
+ HRESULT NewItemByNonCommand(SHELLNEW_ITEM *pItem, LPWSTR wszName,
+ DWORD cchNameMax, LPCWSTR wszPath);
public:
CNewMenu();