shell32: read in freedesktop's recently used document list (try 2)

Damjan Jovanovic damjan.jov at gmail.com
Wed Apr 28 13:42:19 CDT 2010


Changelog:
* shell32: read in freedesktop's recently used document list

Try 2 is a subpart of try 1 with CP_UTF8 instead of CP_ACP and better
MultiByte<->WideChar conversion.

Damjan Jovanovic
-------------- next part --------------
diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in
index 5e4a0c8..5b94116 100644
--- a/dlls/shell32/Makefile.in
+++ b/dlls/shell32/Makefile.in
@@ -5,7 +5,7 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = shell32.dll
 IMPORTLIB = shell32
-IMPORTS   = uuid shlwapi comctl32 user32 gdi32 advapi32 kernel32 ntdll
+IMPORTS   = uuid shlwapi comctl32 user32 gdi32 advapi32 kernel32 ntdll wininet
 DELAYIMPORTS = ole32 oleaut32 shdocvw version
 
 C_SRCS = \
diff --git a/dlls/shell32/shellord.c b/dlls/shell32/shellord.c
index fac7a7a..3eff1f7 100644
--- a/dlls/shell32/shellord.c
+++ b/dlls/shell32/shellord.c
@@ -21,9 +21,15 @@
  */
 #include "config.h"
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <time.h>
 
 #define COBJMACROS
 
@@ -47,6 +53,8 @@
 #include "shlwapi.h"
 #include "commdlg.h"
 #include "commoncontrols.h"
+#include "wininet.h"
+#include "xmldom.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
 WINE_DECLARE_DEBUG_CHANNEL(pidl);
@@ -732,6 +740,90 @@ static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR n
     return AddMRUData(mruhandle, buffer, *len);
 }
 
+static WCHAR* get_file_contents(int fd)
+{
+    WCHAR *bufferW = NULL;
+    struct stat fileinfo;
+    if (fstat(fd, &fileinfo) == 0)
+    {
+        char *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, fileinfo.st_size + 1);
+        if (buffer)
+        {
+            size_t pos = 0;
+            ssize_t ret;
+            do
+            {
+                ret = read(fd, &buffer[pos], fileinfo.st_size - pos);
+                if (ret > 0)
+                    pos += ret;
+            } while ((ret > 0 || errno == EINTR) && pos < fileinfo.st_size);
+
+            if (ret >= 0)
+            {
+                INT wsize = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, NULL, 0);
+                bufferW = HeapAlloc(GetProcessHeap(), 0, wsize * sizeof(WCHAR));
+                if (bufferW)
+                    MultiByteToWideChar(CP_UTF8, 0, buffer, -1, bufferW, wsize);
+            }
+            HeapFree(GetProcessHeap(), 0, buffer);
+        }
+    }
+    return bufferW;
+}
+
+/* http://standards.freedesktop.org/recent-file-spec/recent-file-spec-0.2.html */
+static void update_freedesktop_recently_used(WCHAR *filename, char *recently_used)
+{
+    int fd = -1;
+    BOOL need_unlock = FALSE;
+    WCHAR *xml = NULL;
+    IXMLDOMDocument *document = NULL;
+    HRESULT hr;
+
+    fd = open(recently_used, O_CREAT | O_RDWR, 0x600);
+    if (fd < 0)
+        goto done;
+    if (lockf(fd, F_LOCK, 0) != 0)
+        goto done;
+    need_unlock = TRUE;
+    xml = get_file_contents(fd);
+    if (xml == NULL)
+        goto done;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IXMLDOMDocument, (LPVOID*)&document);
+    if (FAILED(hr))
+        goto done;
+    if (strlenW(xml) > 0)
+    {
+        BSTR xmlBstr = SysAllocString(xml);
+        if (xmlBstr)
+        {
+            VARIANT_BOOL variantBool = VARIANT_TRUE;
+            hr = IXMLDOMDocument_loadXML(document, xmlBstr, &variantBool);
+            SysFreeString(xmlBstr);
+            if (FAILED(hr) || variantBool == VARIANT_FALSE)
+            {
+                TRACE("couldn't load recently used xml\n");
+                goto done;
+            }
+        }
+        else
+            goto done;
+    }
+
+done:
+    if (fd >= 0)
+    {
+        if (need_unlock)
+            lockf(fd, F_ULOCK, 0);
+        close(fd);
+    }
+    HeapFree(GetProcessHeap(), 0, xml);
+    if (document)
+        IXMLDOMDocument_Release(document);
+}
+
 /*************************************************************************
  * SHAddToRecentDocs				[SHELL32.@]
  *
@@ -760,6 +852,7 @@ void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
 
     UINT olderrormode;
     HKEY HCUbasekey;
+    WCHAR *fullpath = NULL;
     CHAR doc_name[MAX_PATH];
     CHAR link_dir[MAX_PATH];
     CHAR new_lnk_filepath[MAX_PATH];
@@ -880,15 +973,33 @@ void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
     switch (uFlags)
     {
     case SHARD_PIDL:
-        SHGetPathFromIDListA(pv, doc_name);
+        fullpath = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
+        if (fullpath == NULL)
+            goto fail;
+        if (!SHGetPathFromIDListA(pv, doc_name))
+            goto fail;
+        if (!SHGetPathFromIDListW(pv, fullpath))
+            goto fail;
         break;
 
     case SHARD_PATHA:
+    {
+        int size;
         lstrcpynA(doc_name, pv, MAX_PATH);
+        size = MultiByteToWideChar(CP_ACP, 0, doc_name, -1, NULL, 0);
+        fullpath = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
+        if (fullpath == NULL)
+            goto fail;
+        MultiByteToWideChar(CP_ACP, 0, doc_name, -1, fullpath, size);
         break;
+    }
 
     case SHARD_PATHW:
         WideCharToMultiByte(CP_ACP, 0, pv, -1, doc_name, MAX_PATH, NULL, NULL);
+        fullpath = HeapAlloc(GetProcessHeap(), 0, (strlenW((WCHAR*)pv) + 1) * sizeof(WCHAR));
+        if (fullpath == NULL)
+            goto fail;
+        strcpyW(fullpath, (WCHAR*)pv);
         break;
 
     default:
@@ -932,6 +1043,7 @@ void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
 	if (!mruhandle) {
 	    /* MRU failed */
 	    ERR("MRU processing failed, handle zero\n");
+	    HeapFree(GetProcessHeap(), 0, fullpath);
 	    RegCloseKey(HCUbasekey);
 	    return;
 	}
@@ -1077,10 +1189,29 @@ void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv)
 	}
     }
 
+    /* ***  JOB 3: Add a shortcut to freedesktop.org's recent documents  *** */
+
+    {
+        char *home;
+        char *recently_used;
+
+        home = getenv("HOME");
+        if (home == NULL)
+            goto fail;
+        recently_used = HeapAlloc(GetProcessHeap(), 0, strlen(home) + 1 + 14 + 1);
+        if (recently_used)
+        {
+            sprintf(recently_used, "%s/.recently-used", home);
+            update_freedesktop_recently_used(fullpath, recently_used);
+            HeapFree(GetProcessHeap(), 0, recently_used);
+        }
+    }
+
  fail:
     CoUninitialize();
 
     /* all done */
+    HeapFree(GetProcessHeap(), 0, fullpath);
     RegCloseKey(HCUbasekey);
     return;
 }


More information about the wine-patches mailing list