https://git.reactos.org/?p=reactos.git;a=commitdiff;h=358f947975f9d185558bab496b614e5ed4ced289
commit 358f947975f9d185558bab496b614e5ed4ced289 Author: Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com> AuthorDate: Fri Feb 14 11:05:21 2020 +0900 Commit: GitHub <nore...@github.com> CommitDate: Fri Feb 14 11:05:21 2020 +0900 [SHELL32] Rewrite SHAddToRecentDocs (#2333) Rewrite shell32!SHAddToRecentDocs and use it in some applications. Wine's SHAddToRecentDocs was not Unicode supported and unusable. I will dare to rewrite. CORE-3588 --- base/applications/mspaint/registry.cpp | 7 +- base/applications/notepad/main.c | 5 + base/applications/wordpad/wordpad.c | 7 + dll/win32/shell32/wine/shellord.c | 343 ++++++++++++++++++++++++++++++--- dll/win32/shimgvw/CMakeLists.txt | 2 +- dll/win32/shimgvw/shimgvw.c | 5 + 6 files changed, 342 insertions(+), 27 deletions(-) diff --git a/base/applications/mspaint/registry.cpp b/base/applications/mspaint/registry.cpp index cd1250b2397..369d8eaf45c 100644 --- a/base/applications/mspaint/registry.cpp +++ b/base/applications/mspaint/registry.cpp @@ -4,13 +4,15 @@ * FILE: base/applications/mspaint/registry.cpp * PURPOSE: Offering functions dealing with registry values * PROGRAMMERS: Benedikt Freisen + * Katayama Hirofumi MZ */ /* INCLUDES *********************************************************/ #include "precomp.h" - #include <winreg.h> +#include <wincon.h> +#include <shlobj.h> /* FUNCTIONS ********************************************************/ static DWORD ReadDWORD(CRegKey &key, LPCTSTR lpName, DWORD &dwValue, BOOL bCheckForDef) @@ -143,6 +145,9 @@ void RegistrySettings::Store() void RegistrySettings::SetMostRecentFile(LPCTSTR szPathName) { + if (szPathName && szPathName[0]) + SHAddToRecentDocs(SHARD_PATHW, szPathName); + if (strFile1 == szPathName) { // do nothing diff --git a/base/applications/notepad/main.c b/base/applications/notepad/main.c index c424449a33c..dee27770697 100644 --- a/base/applications/notepad/main.c +++ b/base/applications/notepad/main.c @@ -5,6 +5,7 @@ * Copyright 1997,98 Marcel Baur <mb...@g26.ethz.ch> * Copyright 2002 Sylvain Petreolle <spetreo...@yahoo.fr> * Copyright 2002 Andriy Palamarchuk + * Copyright 2020 Katayama Hirofumi MZ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,6 +25,7 @@ #include "notepad.h" +#include <shlobj.h> #include <strsafe.h> NOTEPAD_GLOBALS Globals; @@ -48,6 +50,9 @@ VOID SetFileName(LPCTSTR szFileName) StringCchCopy(Globals.szFileName, ARRAY_SIZE(Globals.szFileName), szFileName); Globals.szFileTitle[0] = 0; GetFileTitle(szFileName, Globals.szFileTitle, ARRAY_SIZE(Globals.szFileTitle)); + + if (szFileName && szFileName[0]) + SHAddToRecentDocs(SHARD_PATHW, szFileName); } /*********************************************************************** diff --git a/base/applications/wordpad/wordpad.c b/base/applications/wordpad/wordpad.c index acc8aa08b82..ba4cf537889 100644 --- a/base/applications/wordpad/wordpad.c +++ b/base/applications/wordpad/wordpad.c @@ -3,6 +3,7 @@ * * Copyright 2004 by Krzysztof Foltman * Copyright 2007-2008 by Alexander N. Sørnes <a...@thehandofagony.com> + * Copyright 2020 Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,6 +33,7 @@ #include <commctrl.h> #include <commdlg.h> #include <shellapi.h> +#include <shlobj.h> #include <wine/unicode.h> #include "wordpad.h" @@ -811,6 +813,8 @@ static void DoOpenFile(LPCWSTR szOpenFileName) SetFocus(hEditorWnd); set_caption(szOpenFileName); + if (szOpenFileName[0]) + SHAddToRecentDocs(SHARD_PATHW, szOpenFileName); lstrcpyW(wszFileName, szOpenFileName); SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0); @@ -883,6 +887,9 @@ static BOOL DoSaveFile(LPCWSTR wszSaveFileName, WPARAM format) lstrcpyW(wszFileName, wszSaveFileName); set_caption(wszFileName); + if (wszFileName[0]) + SHAddToRecentDocs(SHARD_PATHW, wszFileName); + SendMessageW(hEditorWnd, EM_SETMODIFY, FALSE, 0); set_fileformat(format); diff --git a/dll/win32/shell32/wine/shellord.c b/dll/win32/shell32/wine/shellord.c index 9b4c6ab9eba..f634c33665d 100644 --- a/dll/win32/shell32/wine/shellord.c +++ b/dll/win32/shell32/wine/shellord.c @@ -45,6 +45,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); WINE_DECLARE_DEBUG_CHANNEL(pidl); +#ifdef __REACTOS__ +#include <comctl32_undoc.h> +#else /* FIXME: !!! move CREATEMRULIST and flags to header file !!! */ /* !!! it is in both here and comctl32undoc.c !!! */ typedef struct tagCREATEMRULIST @@ -67,7 +70,7 @@ extern VOID WINAPI FreeMRUList(HANDLE hMRUList); extern INT WINAPI AddMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData); extern INT WINAPI FindMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum); extern INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize); - +#endif /************************************************************************* * ParseFieldA [internal] @@ -596,9 +599,59 @@ static INT SHADD_get_policy(LPCSTR policy, LPDWORD type, LPVOID buffer, LPDWORD */ static INT CALLBACK SHADD_compare_mru(LPCVOID data1, LPCVOID data2, DWORD cbData) { +#ifdef __REACTOS__ + LPCWSTR psz1, psz2; + INT iCmp = lstrcmpiW(data1, data2); + if (iCmp != 0) + return iCmp; + psz1 = data1; + psz2 = data2; + psz1 += lstrlenW(psz1) + 1; + psz2 += lstrlenW(psz2) + 1; + return lstrcmpiW(psz1, psz2); +#else return lstrcmpiA(data1, data2); +#endif } +#ifdef __REACTOS__ +static BOOL +DoStoreMRUData(LPBYTE pbBuffer, LPDWORD pcbBuffer, + LPCWSTR pszTargetTitle, LPCWSTR pszTargetPath, LPCWSTR pszLinkTitle) +{ + DWORD ib = 0, cb; + INT cchTargetTitle = lstrlenW(pszTargetTitle); + INT cchTargetPath = lstrlenW(pszTargetPath); + INT cchLinkTitle = lstrlenW(pszLinkTitle); + + cb = (cchTargetTitle + 1 + cchTargetPath + 1 + cchLinkTitle + 2) * sizeof(WCHAR); + if (cb > *pcbBuffer) + return FALSE; + + ZeroMemory(pbBuffer, *pcbBuffer); + + cb = (cchTargetTitle + 1) * sizeof(WCHAR); + if (ib + cb > *pcbBuffer) + return FALSE; + CopyMemory(&pbBuffer[ib], pszTargetTitle, cb); + ib += cb; + + cb = (cchTargetPath + 1) * sizeof(WCHAR); + if (ib + cb > *pcbBuffer) + return FALSE; + CopyMemory(&pbBuffer[ib], pszTargetPath, cb); + ib += cb; + + cb = (cchLinkTitle + 1) * sizeof(WCHAR); + if (ib + cb > *pcbBuffer) + return FALSE; + CopyMemory(&pbBuffer[ib], pszLinkTitle, cb); + ib += cb; + + *pcbBuffer = ib; + return TRUE; +} +#else /************************************************************************* * SHADD_create_add_mru_data - helper function for SHAddToRecentDocs * @@ -650,6 +703,7 @@ static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR n */ return AddMRUData(mruhandle, buffer, *len); } +#endif /************************************************************************* * SHAddToRecentDocs [SHELL32.@] @@ -668,6 +722,268 @@ static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR n */ void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv) { +#ifdef __REACTOS__ + static const WCHAR szExplorerKey[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer"; + INT ret; + WCHAR szTargetPath[MAX_PATH], szLinkDir[MAX_PATH], szLinkFile[MAX_PATH], szDescription[80]; + WCHAR szPath[MAX_PATH]; + DWORD cbBuffer, data[64], datalen, type; + HANDLE hFind; + WIN32_FIND_DATAW find; + HKEY hExplorerKey; + LONG error; + LPWSTR pchDotExt, pchTargetTitle, pchLinkTitle; + MRUINFOW mru; + HANDLE hMRUList = NULL; + IShellLinkW *psl = NULL; + IPersistFile *pPf = NULL; + HRESULT hr; + BYTE Buffer[(MAX_PATH + 64) * sizeof(WCHAR)]; + + TRACE("%04x %p\n", uFlags, pv); + + /* check policy */ + ret = SHADD_get_policy("NoRecentDocsHistory", &type, data, &datalen); + if (ret > 0 && ret != ERROR_FILE_NOT_FOUND) + { + ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret); + } + else if (ret == ERROR_SUCCESS) + { + if (!(type == REG_DWORD || (type == REG_BINARY && datalen == 4))) + { + ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n", + type, datalen); + return; + } + + TRACE("policy value for NoRecentDocsHistory = %08x\n", data[0]); + /* now test the actual policy value */ + if (data[0] != 0) + return; + } + + /* store to szTargetPath */ + szTargetPath[0] = 0; + if (pv) + { + switch (uFlags) + { + case SHARD_PATHA: + MultiByteToWideChar(CP_ACP, 0, pv, -1, szLinkDir, ARRAYSIZE(szLinkDir)); + GetFullPathNameW(szLinkDir, ARRAYSIZE(szTargetPath), szTargetPath, NULL); + break; + + case SHARD_PATHW: + GetFullPathNameW(pv, ARRAYSIZE(szTargetPath), szTargetPath, NULL); + break; + + case SHARD_PIDL: + SHGetPathFromIDListW(pv, szLinkDir); + GetFullPathNameW(szLinkDir, ARRAYSIZE(szTargetPath), szTargetPath, NULL); + break; + + default: + FIXME("Unsupported flags: %u\n", uFlags); + return; + } + } + + /* get recent folder */ + if (!SHGetSpecialFolderPathW(NULL, szLinkDir, CSIDL_RECENT, FALSE)) + { + ERR("serious issues 1\n"); + return; + } + TRACE("Users Recent dir %S\n", szLinkDir); + + /* open Explorer key */ + error = RegCreateKeyExW(HKEY_CURRENT_USER, szExplorerKey, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &hExplorerKey, NULL); + if (error) + { + ERR("Failed to RegCreateKeyExW: 0x%08X\n", error); + return; + } + + if (!pv) + { + TRACE("pv is NULL, so delete all shortcut files in %S\n", szLinkDir); + + lstrcpynW(szLinkFile, szLinkDir, ARRAYSIZE(szLinkFile)); + PathAppendW(szLinkFile, L"*.lnk"); + + hFind = FindFirstFileW(szLinkFile, &find); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + lstrcpynW(szLinkFile, szLinkDir, ARRAYSIZE(szLinkFile)); + PathAppendW(szLinkFile, find.cFileName); + DeleteFileW(szLinkFile); + } while (FindNextFile(hFind, &find)); + FindClose(hFind); + } + + SHDeleteKeyW(hExplorerKey, L"RecentDocs"); + RegCloseKey(hExplorerKey); + return; + } + + if (szTargetPath[0] == 0 || !PathFileExistsW(szTargetPath) || + PathIsDirectoryW(szTargetPath)) + { + /* path is not normal file */ + RegCloseKey(hExplorerKey); + return; + } + + hr = CoInitialize(NULL); + if (FAILED(hr)) + { + ERR("CoInitialize: %08X\n", hr); + RegCloseKey(hExplorerKey); + return; + } + + /* check if file is a shortcut */ + ret = 0; + pchDotExt = PathFindExtensionW(szTargetPath); + while (lstrcmpiW(pchDotExt, L".lnk") == 0) + { + hr = IShellLink_ConstructFromPath(szTargetPath, &IID_IShellLinkW, (LPVOID*)&psl); + if (FAILED(hr)) + { + ERR("IShellLink_ConstructFromPath: 0x%08X\n", hr); + goto Quit; + } + + IShellLinkW_GetPath(psl, szPath, ARRAYSIZE(szPath), NULL, 0); + IShellLinkW_Release(psl); + psl = NULL; + + lstrcpynW(szTargetPath, szPath, ARRAYSIZE(szTargetPath)); + pchDotExt = PathFindExtensionW(szTargetPath); + + if (++ret >= 8) + { + ERR("Link loop?\n"); + goto Quit; + } + } + if (!lstrcmpiW(pchDotExt, L".exe")) + { + /* executables are not added */ + goto Quit; + } + + /* *** JOB 0: Build strings *** */ + + pchTargetTitle = PathFindFileNameW(szTargetPath); + + lstrcpyW(szDescription, L"Shortcut to "); + StrCatBuffW(szDescription, pchTargetTitle, ARRAYSIZE(szDescription)); + + lstrcpynW(szLinkFile, szLinkDir, ARRAYSIZE(szLinkFile)); + PathAppendW(szLinkFile, pchTargetTitle); + StrCatBuffW(szLinkFile, L".lnk", ARRAYSIZE(szLinkFile)); + pchLinkTitle = PathFindFileNameW(szLinkFile); + + /* *** JOB 1: Update registry for ...\Explorer\RecentDocs list *** */ + + /* store MRU data */ + cbBuffer = sizeof(Buffer); + ret = DoStoreMRUData(Buffer, &cbBuffer, pchTargetTitle, szTargetPath, pchLinkTitle); + if (!ret) + { + ERR("DoStoreMRUData failed: %d\n", ret); + goto Quit; + } + + /* create MRU list */ + mru.cbSize = sizeof(mru); + mru.uMax = 16; + mru.fFlags = MRU_BINARY | MRU_CACHEWRITE; + mru.hKey = hExplorerKey; + mru.lpszSubKey = L"RecentDocs"; + mru.lpfnCompare = (MRUCMPPROCW)SHADD_compare_mru; + hMRUList = CreateMRUListW(&mru); + if (!hMRUList) + { + ERR("CreateMRUListW failed\n"); + goto Quit; + } + + /* already exists? */ + ret = FindMRUData(hMRUList, Buffer, cbBuffer, NULL); + if (ret >= 0) + { + /* Just touch for speed */ + HANDLE hFile; + hFile = CreateFileW(szLinkFile, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + TRACE("Just touch file '%S'.\n", szLinkFile); + CloseHandle(hFile); + goto Quit; + } + } + + /* add MRU data */ + ret = AddMRUData(hMRUList, Buffer, cbBuffer); + if (ret < 0) + { + ERR("AddMRUData failed: %d\n", ret); + goto Quit; + } + + /* *** JOB 2: Create shortcut in user's "Recent" directory *** */ + + hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + &IID_IShellLinkW, (LPVOID *)&psl); + if (FAILED(hr)) + { + ERR("CoInitialize for IID_IShellLinkW: %08X\n", hr); + goto Quit; + } + + hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID *)&pPf); + if (FAILED(hr)) + { + ERR("IShellLinkW_QueryInterface: %08X\n", hr); + goto Quit; + } + + if (uFlags == SHARD_PIDL) + hr = IShellLinkW_SetIDList(psl, pv); + else + hr = IShellLinkW_SetPath(psl, pv); + + IShellLinkW_SetDescription(psl, szDescription); + + hr = IPersistFile_Save(pPf, szLinkFile, TRUE); + if (FAILED(hr)) + { + ERR("IPersistFile_Save: 0x%08X\n", hr); + } + + hr = IPersistFile_SaveCompleted(pPf, szLinkFile); + if (FAILED(hr)) + { + ERR("IPersistFile_SaveCompleted: 0x%08X\n", hr); + } + +Quit: + if (hMRUList) + FreeMRUList(hMRUList); + if (pPf) + IPersistFile_Release(pPf); + if (psl) + IShellLinkW_Release(psl); + CoUninitialize(); + RegCloseKey(hExplorerKey); +#else /* If list is a string list lpfnCompare has the following prototype * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2) * for binary lists the prototype is @@ -822,30 +1138,6 @@ void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv) TRACE("full document name %s\n", debugstr_a(doc_name)); -#ifdef __REACTOS__ - /* check if file is a shortcut */ - ext = strrchr(doc_name, '.'); - if (!lstrcmpiA(ext, ".lnk")) - { - WCHAR doc_nameW[MAX_PATH]; - IShellLinkA* ShellLink; - int nLength = MultiByteToWideChar(CP_ACP, 0, doc_name, -1, doc_nameW, MAX_PATH); - if (nLength == 0) - return; - - IShellLink_ConstructFromPath(doc_nameW, &IID_IShellLinkA, (LPVOID*)&ShellLink); - IShellLinkA_GetPath(ShellLink, doc_name, MAX_PATH, NULL, 0); - IShellLinkA_Release(ShellLink); - } - - ext = strrchr(doc_name, '.'); - if (!lstrcmpiA(ext, ".exe")) - { - /* executables are not added */ - return; - } -#endif - PathStripPathA(doc_name); TRACE("stripped document name %s\n", debugstr_a(doc_name)); @@ -1032,6 +1324,7 @@ void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv) /* all done */ RegCloseKey(HCUbasekey); return; +#endif } /************************************************************************* diff --git a/dll/win32/shimgvw/CMakeLists.txt b/dll/win32/shimgvw/CMakeLists.txt index e26d54f73be..fefd3d1ca02 100644 --- a/dll/win32/shimgvw/CMakeLists.txt +++ b/dll/win32/shimgvw/CMakeLists.txt @@ -11,5 +11,5 @@ list(APPEND SOURCE add_library(shimgvw MODULE ${SOURCE}) set_module_type(shimgvw win32dll) target_link_libraries(shimgvw wine) -add_importlibs(shimgvw advapi32 comctl32 user32 gdi32 gdiplus comdlg32 shlwapi msvcrt kernel32 ntdll) +add_importlibs(shimgvw advapi32 comctl32 user32 gdi32 shell32 gdiplus comdlg32 shlwapi msvcrt kernel32 ntdll) add_cd_file(TARGET shimgvw DESTINATION reactos/system32 FOR all) diff --git a/dll/win32/shimgvw/shimgvw.c b/dll/win32/shimgvw/shimgvw.c index 7f2d0393a71..de8dc0e0238 100644 --- a/dll/win32/shimgvw/shimgvw.c +++ b/dll/win32/shimgvw/shimgvw.c @@ -18,12 +18,14 @@ #include <winnls.h> #include <winreg.h> #include <wingdi.h> +#include <wincon.h> #include <windowsx.h> #include <objbase.h> #include <commctrl.h> #include <commdlg.h> #include <gdiplus.h> #include <tchar.h> +#include <shlobj.h> #include <strsafe.h> #include <shlwapi.h> @@ -304,6 +306,9 @@ static void pLoadImage(LPWSTR szOpenFileName) } Anime_LoadInfo(); + if (szOpenFileName && szOpenFileName[0]) + SHAddToRecentDocs(SHARD_PATHW, szOpenFileName); + /* reset zoom */ ResetZoom();