mirror of
https://github.com/reactos/reactos.git
synced 2024-08-21 10:53:15 +00:00
![Jose Carlos Jesus](/assets/img/avatar_default.png)
* [SHELL32] Fix issue when creating a new file or folder. No chance to rename the displayed name. The CNewMenu::SelectNewItem method starts with a request to notify the View object about a new item by calling SHChangeNotify. After creating and obtaining the new PIDL by calling ILFindLastID, the CDefView::SelectItem method is called. This method fails right from the start when calling LV_FindItemByPidl which returns -1, thus preventing the user from being given the opportunity to change the name displayed by default. This failure is due to the fact that this object has not yet been added to the CDefView::m_ListView list. This is caused by the asynchronous nature of SHChangeNotify. Thanks to Giannis Adamopoulos for the big help.
781 lines
21 KiB
C++
781 lines
21 KiB
C++
/*
|
|
* provides new shell item service
|
|
*
|
|
* Copyright 2007 Johannes Anderwald (johannes.anderwald@reactos.org)
|
|
* Copyright 2009 Andrew Hill
|
|
* Copyright 2012 Rafal Harabien
|
|
* Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(shell);
|
|
|
|
CNewMenu::CNewMenu() :
|
|
m_pidlFolder(NULL),
|
|
m_pItems(NULL),
|
|
m_pLinkItem(NULL),
|
|
m_pSite(NULL),
|
|
m_idCmdFirst(0),
|
|
m_idCmdFolder(-1),
|
|
m_idCmdLink(-1),
|
|
m_hIconFolder(NULL),
|
|
m_hIconLink(NULL)
|
|
{
|
|
}
|
|
|
|
CNewMenu::~CNewMenu()
|
|
{
|
|
UnloadAllItems();
|
|
|
|
if (m_pidlFolder)
|
|
ILFree(m_pidlFolder);
|
|
}
|
|
|
|
void CNewMenu::UnloadItem(SHELLNEW_ITEM *pItem)
|
|
{
|
|
/* Note: free allows NULL as argument */
|
|
free(pItem->pData);
|
|
free(pItem->pwszDesc);
|
|
free(pItem->pwszExt);
|
|
|
|
if (pItem->hIcon)
|
|
DestroyIcon(pItem->hIcon);
|
|
|
|
HeapFree(GetProcessHeap(), 0, pItem);
|
|
}
|
|
|
|
void CNewMenu::UnloadAllItems()
|
|
{
|
|
SHELLNEW_ITEM *pCurItem;
|
|
|
|
/* Unload the handler items, including the link item */
|
|
while (m_pItems)
|
|
{
|
|
pCurItem = m_pItems;
|
|
m_pItems = m_pItems->pNext;
|
|
UnloadItem(pCurItem);
|
|
}
|
|
m_pItems = NULL;
|
|
m_pLinkItem = NULL;
|
|
}
|
|
|
|
CNewMenu::SHELLNEW_ITEM *CNewMenu::LoadItem(LPCWSTR pwszExt)
|
|
{
|
|
HKEY hKey;
|
|
WCHAR wszBuf[MAX_PATH];
|
|
PBYTE pData = NULL;
|
|
DWORD cbData;
|
|
|
|
StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s\\ShellNew", pwszExt);
|
|
|
|
TRACE("LoadItem Keyname %s Name %s\n", debugstr_w(pwszExt), debugstr_w(wszBuf));
|
|
|
|
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
|
{
|
|
TRACE("Failed to open key\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* Find first valid value */
|
|
struct
|
|
{
|
|
LPCWSTR pszName;
|
|
SHELLNEW_TYPE Type;
|
|
BOOL bNeedData;
|
|
BOOL bStr;
|
|
} Types[] = {
|
|
{L"FileName", SHELLNEW_TYPE_FILENAME, TRUE, TRUE},
|
|
{L"Command", SHELLNEW_TYPE_COMMAND, TRUE, TRUE},
|
|
{L"Data", SHELLNEW_TYPE_DATA, TRUE, FALSE},
|
|
{L"NullFile", SHELLNEW_TYPE_NULLFILE, FALSE},
|
|
{NULL}
|
|
};
|
|
UINT i;
|
|
|
|
for (i = 0; Types[i].pszName; ++i)
|
|
{
|
|
/* Note: We are using ANSI function because strings can be treated as data */
|
|
cbData = 0;
|
|
DWORD dwFlags = Types[i].bStr ? RRF_RT_REG_SZ : RRF_RT_ANY;
|
|
DWORD dwType;
|
|
if (RegGetValueW(hKey, NULL, Types[i].pszName, dwFlags, NULL, NULL, &cbData) == ERROR_SUCCESS)
|
|
{
|
|
if (Types[i].bNeedData && cbData > 0)
|
|
{
|
|
pData = (PBYTE)malloc(cbData);
|
|
RegGetValueW(hKey, NULL, Types[i].pszName, dwFlags, &dwType, pData, &cbData);
|
|
if (!Types[i].bStr && (dwType == REG_SZ || dwType == REG_EXPAND_SZ))
|
|
{
|
|
PBYTE pData2 = (PBYTE)malloc(cbData);
|
|
cbData = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pData, -1, (LPSTR)pData2, cbData, NULL, NULL);
|
|
free(pData);
|
|
pData = pData2;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
|
|
/* Was any key found? */
|
|
if (!Types[i].pszName)
|
|
{
|
|
free(pData);
|
|
return NULL;
|
|
}
|
|
|
|
SHFILEINFOW fi;
|
|
if (!SHGetFileInfoW(pwszExt, FILE_ATTRIBUTE_NORMAL, &fi, sizeof(fi), SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME | SHGFI_ICON | SHGFI_SMALLICON))
|
|
{
|
|
free(pData);
|
|
return NULL;
|
|
}
|
|
|
|
/* Create new item */
|
|
SHELLNEW_ITEM *pNewItem = static_cast<SHELLNEW_ITEM *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SHELLNEW_ITEM)));
|
|
if (!pNewItem)
|
|
{
|
|
free(pData);
|
|
return NULL;
|
|
}
|
|
|
|
TRACE("new item %ls\n", fi.szTypeName);
|
|
pNewItem->Type = Types[i].Type;
|
|
pNewItem->pData = pData;
|
|
pNewItem->cbData = pData ? cbData : 0;
|
|
pNewItem->pwszExt = _wcsdup(pwszExt);
|
|
pNewItem->pwszDesc = _wcsdup(fi.szTypeName);
|
|
if (fi.hIcon)
|
|
pNewItem->hIcon = fi.hIcon;
|
|
|
|
return pNewItem;
|
|
}
|
|
|
|
BOOL
|
|
CNewMenu::CacheItems()
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwSize = 0;
|
|
DWORD dwIndex = 0;
|
|
LPWSTR lpValue;
|
|
LPWSTR lpValues;
|
|
WCHAR wszName[MAX_PATH];
|
|
SHELLNEW_ITEM *pNewItem;
|
|
SHELLNEW_ITEM *pCurItem = NULL;
|
|
|
|
/* Enumerate all extensions */
|
|
while (RegEnumKeyW(HKEY_CLASSES_ROOT, dwIndex++, wszName, _countof(wszName)) == ERROR_SUCCESS)
|
|
{
|
|
if (wszName[0] != L'.')
|
|
continue;
|
|
|
|
pNewItem = LoadItem(wszName);
|
|
if (pNewItem)
|
|
{
|
|
dwSize += wcslen(wszName) + 1;
|
|
if (!m_pLinkItem && wcsicmp(pNewItem->pwszExt, L".lnk") == 0)
|
|
{
|
|
/* The unique link handler */
|
|
m_pLinkItem = pNewItem;
|
|
}
|
|
|
|
/* Add at the end of the list */
|
|
if (pCurItem)
|
|
{
|
|
pCurItem->pNext = pNewItem;
|
|
pCurItem = pNewItem;
|
|
}
|
|
else
|
|
{
|
|
pCurItem = m_pItems = pNewItem;
|
|
}
|
|
}
|
|
}
|
|
|
|
dwSize++;
|
|
|
|
lpValues = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize * sizeof(WCHAR));
|
|
if (!lpValues)
|
|
return FALSE;
|
|
|
|
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;
|
|
}
|
|
|
|
if (RegCreateKeyEx(HKEY_CURRENT_USER, ShellNewKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, lpValues);
|
|
return FALSE;
|
|
}
|
|
|
|
if (RegSetValueExW(hKey, L"Classes", NULL, REG_MULTI_SZ, (LPBYTE)lpValues, dwSize * sizeof(WCHAR)) != ERROR_SUCCESS)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, lpValues);
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpValues);
|
|
RegCloseKey(hKey);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CNewMenu::LoadCachedItems()
|
|
{
|
|
LPWSTR wszName;
|
|
LPWSTR lpValues;
|
|
DWORD dwSize;
|
|
HKEY hKey;
|
|
SHELLNEW_ITEM *pNewItem;
|
|
SHELLNEW_ITEM *pCurItem = NULL;
|
|
|
|
if (RegOpenKeyExW(HKEY_CURRENT_USER, ShellNewKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
if (RegQueryValueExW(hKey, L"Classes", NULL, NULL, NULL, &dwSize) != ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
lpValues = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, dwSize);
|
|
if (!lpValues)
|
|
return FALSE;
|
|
|
|
if (RegQueryValueExW(hKey, L"Classes", NULL, NULL, (LPBYTE)lpValues, &dwSize) != ERROR_SUCCESS)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, lpValues);
|
|
return FALSE;
|
|
}
|
|
|
|
wszName = lpValues;
|
|
|
|
for (; *wszName != '\0'; wszName += wcslen(wszName) + 1)
|
|
{
|
|
pNewItem = LoadItem(wszName);
|
|
if (pNewItem)
|
|
{
|
|
if (!m_pLinkItem && wcsicmp(pNewItem->pwszExt, L".lnk") == 0)
|
|
{
|
|
/* The unique link handler */
|
|
m_pLinkItem = pNewItem;
|
|
}
|
|
|
|
/* Add at the end of the list */
|
|
if (pCurItem)
|
|
{
|
|
pCurItem->pNext = pNewItem;
|
|
pCurItem = pNewItem;
|
|
}
|
|
else
|
|
{
|
|
pCurItem = m_pItems = pNewItem;
|
|
}
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpValues);
|
|
RegCloseKey(hKey);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CNewMenu::LoadAllItems()
|
|
{
|
|
// TODO: We need to find a way to refresh the cache from time to time, when
|
|
// e.g. new extensions with ShellNew handlers have been added or removed.
|
|
|
|
/* If there are any unload them */
|
|
UnloadAllItems();
|
|
|
|
if (!LoadCachedItems())
|
|
{
|
|
CacheItems();
|
|
}
|
|
|
|
return (m_pItems != NULL);
|
|
}
|
|
|
|
UINT
|
|
CNewMenu::InsertShellNewItems(HMENU hMenu, UINT idCmdFirst, UINT Pos)
|
|
{
|
|
MENUITEMINFOW mii;
|
|
UINT idCmd = idCmdFirst;
|
|
WCHAR wszBuf[256];
|
|
|
|
if (m_pItems == NULL)
|
|
{
|
|
if (!LoadAllItems())
|
|
return 0;
|
|
}
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
mii.cbSize = sizeof(mii);
|
|
|
|
m_idCmdFirst = idCmd;
|
|
|
|
/* Insert the new folder action */
|
|
if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEWFOLDER, wszBuf, _countof(wszBuf)))
|
|
wszBuf[0] = 0;
|
|
mii.fMask = MIIM_ID | MIIM_BITMAP | MIIM_STRING;
|
|
mii.dwTypeData = wszBuf;
|
|
mii.cch = wcslen(mii.dwTypeData);
|
|
mii.wID = idCmd;
|
|
mii.hbmpItem = HBMMENU_CALLBACK;
|
|
if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii))
|
|
m_idCmdFolder = 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))
|
|
m_idCmdLink = idCmd++;
|
|
}
|
|
|
|
/* Insert a seperator for the custom new action */
|
|
mii.fMask = MIIM_TYPE | MIIM_ID;
|
|
mii.fType = MFT_SEPARATOR;
|
|
mii.wID = -1;
|
|
InsertMenuItemW(hMenu, Pos++, TRUE, &mii);
|
|
|
|
/* Insert the rest of the items */
|
|
mii.fMask = MIIM_ID | MIIM_BITMAP | MIIM_STRING | MIIM_DATA;
|
|
mii.fType = 0;
|
|
|
|
for (SHELLNEW_ITEM *pCurItem = m_pItems; pCurItem; pCurItem = pCurItem->pNext)
|
|
{
|
|
/* Skip shortcut item */
|
|
if (pCurItem == m_pLinkItem)
|
|
continue;
|
|
|
|
TRACE("szDesc %s\n", debugstr_w(pCurItem->pwszDesc));
|
|
mii.dwItemData = (ULONG_PTR)pCurItem;
|
|
mii.dwTypeData = pCurItem->pwszDesc;
|
|
mii.cch = wcslen(mii.dwTypeData);
|
|
mii.wID = idCmd;
|
|
if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii))
|
|
++idCmd;
|
|
}
|
|
|
|
return idCmd - idCmdFirst;
|
|
}
|
|
|
|
CNewMenu::SHELLNEW_ITEM *CNewMenu::FindItemFromIdOffset(UINT IdOffset)
|
|
{
|
|
/* Folder */
|
|
if (m_idCmdFirst + IdOffset == m_idCmdFolder)
|
|
return NULL;
|
|
|
|
/* Shortcut */
|
|
if (m_idCmdFirst + IdOffset == m_idCmdLink)
|
|
return m_pLinkItem;
|
|
|
|
/* Find shell new item - Retrieve menu item info */
|
|
MENUITEMINFOW mii;
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_DATA;
|
|
|
|
if (GetMenuItemInfoW(m_hSubMenu, m_idCmdFirst + IdOffset, FALSE, &mii) && mii.dwItemData)
|
|
return (SHELLNEW_ITEM *)mii.dwItemData;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
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 | SHCNF_FLUSH, (LPCVOID)pszName, NULL);
|
|
|
|
if (!m_pSite)
|
|
return S_OK;
|
|
|
|
/* Get a pointer to the shell view */
|
|
hr = IUnknown_QueryService(m_pSite, SID_IFolderView, IID_PPV_ARG(IShellView, &lpSV));
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
return S_OK;
|
|
|
|
/* Attempt to get the pidl of the new item */
|
|
hr = SHILCreateFromPathW(pszName, &pidl, NULL);
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
return hr;
|
|
|
|
pidlNewItem = ILFindLastID(pidl);
|
|
|
|
hr = lpSV->SelectItem(pidlNewItem, dwSelectFlags);
|
|
|
|
SHFree(pidl);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Code is duplicated in CDefaultContextMenu
|
|
HRESULT CNewMenu::CreateNewFolder(LPCMINVOKECOMMANDINFO lpici)
|
|
{
|
|
WCHAR wszPath[MAX_PATH];
|
|
WCHAR wszName[MAX_PATH];
|
|
WCHAR wszNewFolder[25];
|
|
HRESULT hr;
|
|
|
|
/* Get folder path */
|
|
hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
return hr;
|
|
|
|
if (!LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, _countof(wszNewFolder)))
|
|
return E_FAIL;
|
|
|
|
/* Create the name of the new directory */
|
|
if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFolder))
|
|
return E_FAIL;
|
|
|
|
/* Create the new directory and show the appropriate dialog in case of error */
|
|
if (SHCreateDirectory(lpici->hwnd, wszName) != ERROR_SUCCESS)
|
|
return E_FAIL;
|
|
|
|
/* Show and select the new item in the def view */
|
|
SelectNewItem(SHCNE_MKDIR, SHCNF_PATHW, wszName, TRUE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CNewMenu::NewItemByCommand(SHELLNEW_ITEM *pItem, LPCWSTR wszPath)
|
|
{
|
|
WCHAR wszBuf[MAX_PATH];
|
|
LPWSTR Ptr, pwszCmd;
|
|
WCHAR wszTemp[MAX_PATH];
|
|
STARTUPINFOW si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
if (!ExpandEnvironmentStringsW((LPWSTR)pItem->pData, wszBuf, _countof(wszBuf)))
|
|
{
|
|
TRACE("ExpandEnvironmentStrings failed\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;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
|
|
HRESULT CNewMenu::NewItemByNonCommand(SHELLNEW_ITEM *pItem, LPWSTR wszName,
|
|
DWORD cchNameMax, LPCWSTR wszPath)
|
|
{
|
|
WCHAR wszBuf[MAX_PATH];
|
|
WCHAR wszNewFile[MAX_PATH];
|
|
BOOL bSuccess = TRUE;
|
|
|
|
if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszBuf, _countof(wszBuf)))
|
|
return E_FAIL;
|
|
|
|
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)
|
|
{
|
|
/* Write a content */
|
|
DWORD cbWritten;
|
|
WriteFile(hFile, pItem->pData, pItem->cbData, &cbWritten, NULL);
|
|
}
|
|
|
|
/* Close file now */
|
|
CloseHandle(hFile);
|
|
}
|
|
else
|
|
{
|
|
bSuccess = FALSE;
|
|
}
|
|
|
|
if (pItem->Type == SHELLNEW_TYPE_FILENAME)
|
|
{
|
|
/* Copy file */
|
|
if (!CopyFileW((LPWSTR)pItem->pData, wszName, FALSE))
|
|
ERR("Copy file failed: %ls\n", (LPWSTR)pItem->pData);
|
|
}
|
|
|
|
/* 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
|
|
{
|
|
CStringW Caption(MAKEINTRESOURCEW(IDS_CREATEFILE_CAPTION));
|
|
CStringW Message(MAKEINTRESOURCEW(IDS_CREATEFILE_DENIED));
|
|
Message.FormatMessage(Message.GetString(), wszName);
|
|
MessageBoxW(0, Message, Caption, MB_ICONEXCLAMATION | MB_OK);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CNewMenu::CreateNewItem(SHELLNEW_ITEM *pItem, LPCMINVOKECOMMANDINFO lpcmi)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR wszPath[MAX_PATH], wszName[MAX_PATH];
|
|
|
|
/* Get folder path */
|
|
hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
return hr;
|
|
|
|
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");
|
|
break;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CNewMenu::SetSite(IUnknown *pUnkSite)
|
|
{
|
|
m_pSite = pUnkSite;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CNewMenu::GetSite(REFIID riid, void **ppvSite)
|
|
{
|
|
return m_pSite->QueryInterface(riid, ppvSite);
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CNewMenu::QueryContextMenu(HMENU hMenu,
|
|
UINT indexMenu,
|
|
UINT idCmdFirst,
|
|
UINT idCmdLast,
|
|
UINT uFlags)
|
|
{
|
|
MENUITEMINFOW mii;
|
|
UINT cItems = 0;
|
|
WCHAR wszNew[200];
|
|
|
|
TRACE("%p %p %u %u %u %u\n", this,
|
|
hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
|
|
|
|
if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszNew, _countof(wszNew)))
|
|
return E_FAIL;
|
|
|
|
m_hSubMenu = CreateMenu();
|
|
if (!m_hSubMenu)
|
|
return E_FAIL;
|
|
|
|
cItems = InsertShellNewItems(m_hSubMenu, idCmdFirst, 0);
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE | MIIM_SUBMENU;
|
|
mii.fType = MFT_STRING;
|
|
mii.wID = -1;
|
|
mii.dwTypeData = wszNew;
|
|
mii.cch = wcslen(mii.dwTypeData);
|
|
mii.fState = MFS_ENABLED;
|
|
mii.hSubMenu = m_hSubMenu;
|
|
|
|
if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
|
|
return E_FAIL;
|
|
|
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cItems);
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CNewMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdFolder)
|
|
{
|
|
hr = CreateNewFolder(lpici);
|
|
}
|
|
else
|
|
{
|
|
SHELLNEW_ITEM *pItem = FindItemFromIdOffset(LOWORD(lpici->lpVerb));
|
|
if (pItem)
|
|
hr = CreateNewItem(pItem, lpici);
|
|
}
|
|
|
|
TRACE("CNewMenu::InvokeCommand %x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CNewMenu::GetCommandString(UINT_PTR idCmd,
|
|
UINT uType,
|
|
UINT *pwReserved,
|
|
LPSTR pszName,
|
|
UINT cchMax)
|
|
{
|
|
FIXME("%p %lu %u %p %p %u\n", this,
|
|
idCmd, uType, pwReserved, pszName, cchMax );
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CNewMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CNewMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_MEASUREITEM:
|
|
{
|
|
MEASUREITEMSTRUCT* lpmis = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam);
|
|
if (!lpmis || lpmis->CtlType != ODT_MENU)
|
|
break;
|
|
|
|
if (lpmis->itemWidth < (UINT)GetSystemMetrics(SM_CXMENUCHECK))
|
|
lpmis->itemWidth = GetSystemMetrics(SM_CXMENUCHECK);
|
|
if (lpmis->itemHeight < 16)
|
|
lpmis->itemHeight = 16;
|
|
|
|
if (plResult)
|
|
*plResult = TRUE;
|
|
break;
|
|
}
|
|
case WM_DRAWITEM:
|
|
{
|
|
DRAWITEMSTRUCT* lpdis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
|
|
if (!lpdis || lpdis->CtlType != ODT_MENU)
|
|
break;
|
|
|
|
DWORD id = LOWORD(lpdis->itemID);
|
|
HICON hIcon = NULL;
|
|
if (m_idCmdFirst + id == m_idCmdFolder)
|
|
{
|
|
hIcon = m_hIconFolder;
|
|
}
|
|
else if (m_idCmdFirst + id == m_idCmdLink)
|
|
{
|
|
hIcon = m_hIconLink;
|
|
}
|
|
else
|
|
{
|
|
SHELLNEW_ITEM *pItem = FindItemFromIdOffset(id);
|
|
if (pItem)
|
|
hIcon = pItem->hIcon;
|
|
}
|
|
|
|
if (!hIcon)
|
|
break;
|
|
|
|
DrawIconEx(lpdis->hDC,
|
|
2,
|
|
lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top - 16) / 2,
|
|
hIcon,
|
|
16,
|
|
16,
|
|
0, NULL, DI_NORMAL);
|
|
|
|
if(plResult)
|
|
*plResult = TRUE;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WINAPI
|
|
CNewMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder,
|
|
IDataObject *pdtobj, HKEY hkeyProgID)
|
|
{
|
|
m_pidlFolder = ILClone(pidlFolder);
|
|
|
|
/* Load folder and shortcut icons */
|
|
m_hIconFolder = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_FOLDER), IMAGE_ICON, 16, 16, LR_SHARED);
|
|
m_hIconLink = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), IMAGE_ICON, 16, 16, LR_SHARED);
|
|
return S_OK;
|
|
}
|