[CORE-7737]
authorZiliang Guo <drakekaizer666@gmail.com>
Thu, 11 Dec 2014 19:52:47 +0000 (19:52 +0000)
committerZiliang Guo <drakekaizer666@gmail.com>
Thu, 11 Dec 2014 19:52:47 +0000 (19:52 +0000)
Implement browsing with the shell image viewer. Patch by Ricardo Hanke.

svn path=/trunk/; revision=65608

reactos/dll/win32/shimgvw/CMakeLists.txt
reactos/dll/win32/shimgvw/shimgvw.c
reactos/dll/win32/shimgvw/shimgvw.h

index c923f33..be17acc 100644 (file)
@@ -10,5 +10,5 @@ list(APPEND SOURCE
 add_library(shimgvw SHARED ${SOURCE})
 set_module_type(shimgvw win32dll)
 target_link_libraries(shimgvw wine)
-add_importlibs(shimgvw advapi32 comctl32 user32 gdi32 gdiplus comdlg32 msvcrt kernel32 ntdll)
+add_importlibs(shimgvw advapi32 comctl32 user32 gdi32 gdiplus comdlg32 shlwapi msvcrt kernel32 ntdll)
 add_cd_file(TARGET shimgvw DESTINATION reactos/system32 FOR all)
index 65f48c3..b6e10d3 100644 (file)
@@ -26,6 +26,7 @@
 #include <gdiplus.h>
 #include <tchar.h>
 #include <strsafe.h>
+#include <shlwapi.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -35,6 +36,7 @@
 
 HINSTANCE hInstance;
 SHIMGVW_SETTINGS shiSettings;
+SHIMGVW_FILENODE *currentFile;
 GpImage *image;
 WNDPROC PrevProc = NULL;
 
@@ -159,6 +161,166 @@ static void pSaveImageAs(HWND hwnd)
     free(codecInfo);
 }
 
+static VOID
+pLoadImageFromNode(SHIMGVW_FILENODE *node, HWND hwnd)
+{
+    WCHAR szTitleBuf[800];
+    WCHAR szResStr[512];
+    WCHAR *c;
+
+    if (node)
+    {
+        c = wcsrchr(node->FileName, '\\');
+        if (c)
+        {
+            c++;
+        }
+        
+        LoadStringW(hInstance, IDS_APPTITLE, szResStr, 512);
+        StringCbPrintfExW(szTitleBuf, 800, NULL, NULL, 0, L"%ls%ls%ls", szResStr, L" - ", c);
+        SetWindowTextW(hwnd, szTitleBuf);
+
+        if (image)
+        {
+            GdipDisposeImage(image);
+        }
+
+        pLoadImage(node->FileName);
+        InvalidateRect(hDispWnd, NULL, TRUE);
+        UpdateWindow(hDispWnd);
+    }
+}
+
+static SHIMGVW_FILENODE*
+pBuildFileList(LPWSTR szFirstFile)
+{
+    HANDLE hFindHandle;
+    WCHAR *extension;
+    WCHAR szSearchPath[MAX_PATH];
+    WCHAR szSearchMask[MAX_PATH];
+    WCHAR szFileTypes[MAX_PATH];
+    WIN32_FIND_DATAW findData;
+    SHIMGVW_FILENODE *currentNode;
+    SHIMGVW_FILENODE *root;
+    SHIMGVW_FILENODE *conductor;
+    ImageCodecInfo *codecInfo;
+    UINT num;
+    UINT size;
+    UINT j;
+
+
+    wcscpy(szSearchPath, szFirstFile);
+    PathRemoveFileSpecW(szSearchPath);
+
+    GdipGetImageDecodersSize(&num, &size);
+    codecInfo = malloc(size);
+    if (!codecInfo)
+    {
+        DPRINT1("malloc() failed in pLoadFileList()\n");
+        return NULL;
+    }
+
+    GdipGetImageDecoders(num, size, codecInfo);
+
+    root = malloc(sizeof(SHIMGVW_FILENODE));
+    if (!root)
+    {
+        DPRINT1("malloc() failed in pLoadFileList()\n");
+        free(codecInfo);
+        return NULL;
+    }
+
+    conductor = root;
+
+    for (j = 0; j < num; ++j)
+    {
+        StringCbPrintfExW(szFileTypes, MAX_PATH, NULL, NULL, 0, L"%ls", codecInfo[j].FilenameExtension);
+        
+        extension = wcstok(szFileTypes, L";");
+        while (extension != NULL)
+        {
+            StringCbPrintfExW(szSearchMask, MAX_PATH, NULL, NULL, 0, L"%ls%ls%ls", szSearchPath, L"\\", extension);
+
+            hFindHandle = FindFirstFileW(szSearchMask, &findData);
+            if (hFindHandle != INVALID_HANDLE_VALUE)
+            {
+                do
+                {
+                    StringCbPrintfExW(conductor->FileName, MAX_PATH, NULL, NULL, 0, L"%ls%ls%ls", szSearchPath, L"\\", findData.cFileName);
+
+                    // compare the name of the requested file with the one currently found.
+                    // if the name matches, the current node is returned by the function.
+                    if (wcscmp(szFirstFile, conductor->FileName) == 0)
+                    {
+                        currentNode = conductor;
+                    }
+
+                    conductor->Next = malloc(sizeof(SHIMGVW_FILENODE));
+
+                    // if malloc fails, make circular what we have and return it
+                    if (!conductor->Next)
+                    {
+                        DPRINT1("malloc() failed in pLoadFileList()\n");
+                        
+                        conductor->Next = root;
+                        root->Prev = conductor;
+
+                        FindClose(hFindHandle);
+                        free(codecInfo);
+                        return conductor;
+                    }
+
+                    conductor->Next->Prev = conductor;
+                    conductor = conductor->Next;
+                }
+                while (FindNextFileW(hFindHandle, &findData) != 0);
+
+                FindClose(hFindHandle);
+            }
+
+            extension = wcstok(NULL, L";");
+        }
+    }
+
+    // we now have a node too much in the list. In case the requested file was not found,
+    // we use this node to store the name of it, otherwise we free it.
+    if (currentNode == NULL)
+    {
+        StringCbPrintfExW(conductor->FileName, MAX_PATH, NULL, NULL, 0, L"%ls", szFirstFile);
+        currentNode = conductor;
+    }
+    else
+    {
+        conductor = conductor->Prev;
+        free(conductor->Next);
+    }
+
+    // link the last node with the first one to make the list circular
+    conductor->Next = root;
+    root->Prev = conductor;
+    conductor = currentNode;
+
+    free(codecInfo);
+
+    return conductor;
+}
+
+static VOID
+pFreeFileList(SHIMGVW_FILENODE *root)
+{
+    SHIMGVW_FILENODE *conductor;
+
+    root->Prev->Next = NULL;
+    root->Prev = NULL;
+
+    while (root)
+    {
+        conductor = root;
+        root = conductor->Next;
+        free(conductor);
+    }
+}
+
 static VOID
 ImageView_DrawImage(HWND hwnd)
 {
@@ -410,9 +572,17 @@ ImageView_WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
             switch (wParam)
             {
                 case IDC_PREV:
+                {
+                    currentFile = currentFile->Prev;
+                    pLoadImageFromNode(currentFile, hwnd);
+                }
 
                 break;
                 case IDC_NEXT:
+                {
+                    currentFile = currentFile->Next;
+                    pLoadImageFromNode(currentFile, hwnd);
+                }
 
                 break;
                 case IDC_ZOOMP:
@@ -522,6 +692,7 @@ ImageView_CreateWindow(HWND hwnd, LPWSTR szFileName)
     ULONG_PTR gdiplusToken;
     WNDCLASS WndClass = {0};
     TCHAR szBuf[512];
+    WCHAR szInitialFile[MAX_PATH];
     HWND hMainWnd;
     MSG msg;
 
@@ -560,6 +731,16 @@ ImageView_CreateWindow(HWND hwnd, LPWSTR szFileName)
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             0, 0, NULL, NULL, hInstance, NULL);
 
+    // make sure the path has no quotes on it
+    wcscpy(szInitialFile, szFileName);
+    PathUnquoteSpacesW(szInitialFile);
+
+    currentFile = pBuildFileList(szInitialFile);
+    if (currentFile)
+    {
+        pLoadImageFromNode(currentFile, hMainWnd);
+    }
+
     // Show it
     ShowWindow(hMainWnd, SW_SHOW);
     UpdateWindow(hMainWnd);
@@ -571,6 +752,8 @@ ImageView_CreateWindow(HWND hwnd, LPWSTR szFileName)
         DispatchMessageW(&msg);
     }
 
+    pFreeFileList(currentFile);
+
     if (image)
         GdipDisposeImage(image);
     GdiplusShutdown(gdiplusToken);
index 47135ea..9bce39c 100644 (file)
@@ -13,3 +13,10 @@ typedef struct
     INT Right;
     INT Bottom;
 } SHIMGVW_SETTINGS;
+
+typedef struct SHIMGVW_FILENODE_INTERNAL
+{
+    WCHAR FileName[MAX_PATH];
+    struct SHIMGVW_FILENODE_INTERNAL *Prev;
+    struct SHIMGVW_FILENODE_INTERNAL *Next;
+} SHIMGVW_FILENODE;