[SHELL32] Improve and fix SendTo (#2122)
authorKatayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
Sun, 1 Dec 2019 19:06:20 +0000 (04:06 +0900)
committerGitHub <noreply@github.com>
Sun, 1 Dec 2019 19:06:20 +0000 (04:06 +0900)
Because of timing of SendTo folder initialization, SendTo My Documents didn't work well.
Now My Documents item is working well. CORE-12562

dll/win32/shell32/CSendToMenu.cpp
dll/win32/shell32/CSendToMenu.h
dll/win32/shell32/wine/shellpath.c

index 9e9fbe8..8a7e1bc 100644 (file)
@@ -156,10 +156,169 @@ void CSendToMenu::UnloadAllItems()
     }
 }
 
+BOOL CSendToMenu::FolderHasAnyItems() const
+{
+    WCHAR szPath[MAX_PATH];
+    SHGetSpecialFolderPathW(NULL, szPath, CSIDL_SENDTO, FALSE);
+
+    PathAppendW(szPath, L"*");
+
+    WIN32_FIND_DATAW find;
+    HANDLE hFind = FindFirstFileW(szPath, &find);
+    if (hFind == INVALID_HANDLE_VALUE)
+        return FALSE;
+
+    BOOL bFound = FALSE;
+    do
+    {
+        if (wcscmp(find.cFileName, L".") == 0 ||
+            wcscmp(find.cFileName, L"..") == 0 ||
+            _wcsicmp(find.cFileName, L"desktop.ini") == 0)
+        {
+            continue;
+        }
+
+        bFound = TRUE;
+        break;
+    } while (FindNextFileW(hFind, &find));
+
+    FindClose(hFind);
+    return bFound;
+}
+
+static BOOL CreateEmptyFile(LPCWSTR pszFile)
+{
+    HANDLE hFile;
+    hFile = CreateFileW(pszFile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    CloseHandle(hFile);
+    return hFile != INVALID_HANDLE_VALUE;
+}
+
+static HRESULT
+CreateShellLink(
+    LPCWSTR pszLinkPath,
+    LPCWSTR pszTargetPath OPTIONAL,
+    LPCITEMIDLIST pidlTarget OPTIONAL,
+    LPCWSTR pszArg OPTIONAL,
+    LPCWSTR pszDir OPTIONAL,
+    LPCWSTR pszIconPath OPTIONAL,
+    INT iIconNr OPTIONAL,
+    LPCWSTR pszComment OPTIONAL)
+{
+    CComPtr<IShellLinkW> psl;
+    HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL,
+                                  CLSCTX_INPROC_SERVER,
+                                  IID_PPV_ARG(IShellLinkW, &psl));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    if (pszTargetPath)
+    {
+        hr = psl->SetPath(pszTargetPath);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+    }
+    else if (pidlTarget)
+    {
+        hr = psl->SetIDList(pidlTarget);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+    }
+    else
+    {
+        ERR("invalid argument\n");
+        return E_INVALIDARG;
+    }
+
+    if (pszArg)
+        hr = psl->SetArguments(pszArg);
+
+    if (pszDir)
+        hr = psl->SetWorkingDirectory(pszDir);
+
+    if (pszIconPath)
+        hr = psl->SetIconLocation(pszIconPath, iIconNr);
+
+    if (pszComment)
+        hr = psl->SetDescription(pszComment);
+
+    CComPtr<IPersistFile> ppf;
+    hr = psl->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    hr = ppf->Save(pszLinkPath, TRUE);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    return hr;
+}
+
+HRESULT CSendToMenu::CreateSendToFiles(LPCWSTR pszSendTo)
+{
+    WCHAR szTarget[MAX_PATH];
+    WCHAR szSendToFile[MAX_PATH];
+    WCHAR szShell32[MAX_PATH];
+    HRESULT hr;
+
+    /* create my documents */
+    SHGetSpecialFolderPathW(NULL, szTarget, CSIDL_MYDOCUMENTS, FALSE);
+
+    StringCbCopyW(szSendToFile, sizeof(szSendToFile), pszSendTo);
+    PathAppendW(szSendToFile, PathFindFileNameW(szTarget));
+    StringCbCatW(szSendToFile, sizeof(szSendToFile), L".lnk");
+
+    GetSystemDirectoryW(szShell32, ARRAY_SIZE(szShell32));
+    PathAppendW(szShell32, L"shell32.dll");
+    hr = CreateShellLink(szSendToFile, szTarget, NULL, NULL, NULL,
+                         szShell32, -IDI_SHELL_MY_DOCUMENTS, NULL);
+    if (FAILED_UNEXPECTEDLY(hr))
+        ;
+
+    /* create desklink */
+    StringCbCopyW(szSendToFile, sizeof(szSendToFile), pszSendTo);
+    LoadStringW(shell32_hInstance, IDS_DESKLINK, szTarget, _countof(szTarget));
+    StringCbCatW(szTarget, sizeof(szTarget), L".DeskLink");
+    PathAppendW(szSendToFile, szTarget);
+    if (!CreateEmptyFile(szSendToFile))
+    {
+        ERR("CreateEmptyFile\n");
+    }
+
+    /* create zipped compressed folder */
+    HINSTANCE hZipFldr =
+        LoadLibraryExW(L"zipfldr.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
+    if (hZipFldr)
+    {
+#define IDS_FRIENDLYNAME 10195
+        LoadStringW(hZipFldr, IDS_FRIENDLYNAME, szTarget, _countof(szTarget));
+#undef IDS_FRIENDLYNAME
+        FreeLibrary(hZipFldr);
+
+        StringCbCopyW(szSendToFile, sizeof(szSendToFile), pszSendTo);
+        PathAppendW(szSendToFile, szTarget);
+        StringCbCatW(szSendToFile, sizeof(szSendToFile), L".ZFSendToTarget");
+        if (!CreateEmptyFile(szSendToFile))
+        {
+            ERR("CreateEmptyFile\n");
+        }
+    }
+
+    return S_OK;
+}
+
 HRESULT CSendToMenu::LoadAllItems(HWND hwnd)
 {
     UnloadAllItems();
 
+    if (!FolderHasAnyItems())
+    {
+        WCHAR szPath[MAX_PATH];
+        SHGetSpecialFolderPathW(NULL, szPath, CSIDL_SENDTO, FALSE);
+        CreateSendToFiles(szPath);
+    }
+
     CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlSendTo;
 
     m_pSendTo.Release();
index 2f59319..2156f1e 100644 (file)
@@ -69,6 +69,9 @@ private:
     HRESULT LoadAllItems(HWND hwnd);
     void UnloadAllItems();
 
+    BOOL FolderHasAnyItems() const;
+    HRESULT CreateSendToFiles(LPCWSTR pszSendTo);
+
     UINT InsertSendToItems(HMENU hMenu, UINT idFirst, UINT idMenu);
 
     SENDTO_ITEM *FindItemFromIdOffset(UINT IdOffset);
index 984116f..9ca628f 100644 (file)
@@ -2146,129 +2146,6 @@ cleanup:
     return hr;
 }
 
-static HRESULT
-CreateShellLink(
-    LPCWSTR pszLinkPath,
-    LPCWSTR pszCmd,
-    LPCWSTR pszArg OPTIONAL,
-    LPCWSTR pszDir OPTIONAL,
-    LPCWSTR pszIconPath OPTIONAL,
-    INT iIconNr OPTIONAL,
-    LPCWSTR pszComment OPTIONAL)
-{
-    IShellLinkW *psl;
-    IPersistFile *ppf;
-
-    HRESULT hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID*)&psl);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
-
-    hr = IShellLinkW_SetPath(psl, pszCmd);
-    if (FAILED_UNEXPECTEDLY(hr))
-    {
-        IShellLinkW_Release(psl);
-        return hr;
-    }
-
-    if (pszArg)
-        hr = IShellLinkW_SetArguments(psl, pszArg);
-
-    if (pszDir)
-        hr = IShellLinkW_SetWorkingDirectory(psl, pszDir);
-
-    if (pszIconPath)
-        hr = IShellLinkW_SetIconLocation(psl, pszIconPath, iIconNr);
-
-    if (pszComment)
-        hr = IShellLinkW_SetDescription(psl, pszComment);
-
-    hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
-
-    if (SUCCEEDED(hr))
-    {
-        hr = IPersistFile_Save(ppf, pszLinkPath, TRUE);
-        IPersistFile_Release(ppf);
-    }
-
-    IShellLinkW_Release(psl);
-
-    return hr;
-}
-
-static HRESULT
-CreateShellLinkCoInit(
-    LPCWSTR pszLinkPath,
-    LPCWSTR pszCmd,
-    LPCWSTR pszArg OPTIONAL,
-    LPCWSTR pszDir OPTIONAL,
-    LPCWSTR pszIconPath OPTIONAL,
-    INT iIconNr OPTIONAL,
-    LPCWSTR pszComment OPTIONAL)
-{
-    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
-    BOOL bCoInit = (hr == S_OK);
-
-    hr = CreateShellLink(pszLinkPath, pszCmd, pszArg, pszDir,
-                         pszIconPath, iIconNr, pszComment);
-
-    if (bCoInit)
-        CoUninitialize();
-
-    return hr;
-}
-
-HRESULT DoCreateSendToFiles(LPCWSTR pszSendTo)
-{
-    WCHAR szTarget[MAX_PATH];
-    WCHAR szSendToFile[MAX_PATH];
-    WCHAR szShell32[MAX_PATH];
-    HRESULT hr;
-    HANDLE hFile;
-    HINSTANCE hZipFldr;
-
-    /* create my documents */
-    SHGetSpecialFolderPathW(NULL, szTarget, CSIDL_MYDOCUMENTS, TRUE);
-
-    StringCbCopyW(szSendToFile, sizeof(szSendToFile), pszSendTo);
-    PathAppendW(szSendToFile, PathFindFileNameW(szTarget));
-    StringCbCatW(szSendToFile, sizeof(szSendToFile), L".lnk");
-
-    GetSystemDirectoryW(szShell32, ARRAY_SIZE(szShell32));
-    PathAppendW(szShell32, L"shell32.dll");
-    hr = CreateShellLinkCoInit(szSendToFile, szTarget, NULL, NULL,
-                               szShell32, -IDI_SHELL_MY_DOCUMENTS, NULL);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
-
-    /* create desklink */
-    StringCbCopyW(szSendToFile, sizeof(szSendToFile), pszSendTo);
-    LoadStringW(shell32_hInstance, IDS_DESKLINK, szTarget, _countof(szTarget));
-    StringCbCatW(szTarget, sizeof(szTarget), L".DeskLink");
-    PathAppendW(szSendToFile, szTarget);
-    hFile = CreateFileW(szSendToFile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
-                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-    CloseHandle(hFile);
-
-    /* create zipped compressed folder */
-    hZipFldr = LoadLibraryW(L"zipfldr.dll");
-    if (hZipFldr)
-    {
-#define IDS_FRIENDLYNAME 10195
-        LoadStringW(hZipFldr, IDS_FRIENDLYNAME, szTarget, _countof(szTarget));
-#undef IDS_FRIENDLYNAME
-        FreeLibrary(hZipFldr);
-
-        StringCbCopyW(szSendToFile, sizeof(szSendToFile), pszSendTo);
-        PathAppendW(szSendToFile, szTarget);
-        StringCbCatW(szSendToFile, sizeof(szSendToFile), L".ZFSendToTarget");
-        hFile = CreateFileW(szSendToFile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
-                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-        CloseHandle(hFile);
-    }
-
-    return S_OK;
-}
-
 /*************************************************************************
  * SHGetFolderPathAndSubDirW           [SHELL32.@]
  */
@@ -2408,11 +2285,6 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW(
     TRACE("Created missing system directory %s\n", debugstr_w(szBuildPath));
 
 end:
-    if ((nFolder & CSIDL_FLAG_CREATE) && folder == CSIDL_SENDTO)
-    {
-        DoCreateSendToFiles(szBuildPath);
-    }
-
     /* create desktop.ini for custom icon */
     if ((nFolder & CSIDL_FLAG_CREATE) &&
         CSIDL_Data[folder].nShell32IconIndex)