[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
This commit is contained in:
Katayama Hirofumi MZ 2020-02-14 11:05:21 +09:00 committed by GitHub
parent b539dd1c5a
commit 358f947975
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 342 additions and 27 deletions

View file

@ -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

View file

@ -5,6 +5,7 @@
* Copyright 1997,98 Marcel Baur <mbaur@g26.ethz.ch>
* Copyright 2002 Sylvain Petreolle <spetreolle@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);
}
/***********************************************************************

View file

@ -3,6 +3,7 @@
*
* Copyright 2004 by Krzysztof Foltman
* Copyright 2007-2008 by Alexander N. Sørnes <alex@thehandofagony.com>
* Copyright 2020 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
@ -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);

View file

@ -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
}
/*************************************************************************

View file

@ -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)

View file

@ -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();