https://git.reactos.org/?p=reactos.git;a=commitdiff;h=358f947975f9d185558ba…
commit 358f947975f9d185558bab496b614e5ed4ced289
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Fri Feb 14 11:05:21 2020 +0900
Commit: GitHub <noreply(a)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 <mbaur(a)g26.ethz.ch>
* Copyright 2002 Sylvain Petreolle <spetreolle(a)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 <alex(a)thehandofagony.com>
+ * Copyright 2020 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
@@ -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();