https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e8dcbcc61d52df02fd6bb4abb9af947851df8cd3

commit e8dcbcc61d52df02fd6bb4abb9af947851df8cd3
Author:     Mark Jansen <mark.jan...@reactos.org>
AuthorDate: Fri Apr 13 22:59:04 2018 +0200
Commit:     Mark Jansen <mark.jan...@reactos.org>
CommitDate: Sat Apr 14 15:47:13 2018 +0200

    [SHELL32] Sync CShellDispatch and family with wine.
    Incorporates work from Ivan Rodionov.
    CORE-12955
---
 dll/win32/shell32/CFolder.cpp          |  72 ++++++---------
 dll/win32/shell32/CFolder.h            |  24 ++---
 dll/win32/shell32/CFolderItemVerbs.cpp |  15 ++-
 dll/win32/shell32/CFolderItems.cpp     | 118 ++++++++++++++----------
 dll/win32/shell32/CFolderItems.h       |  28 ++----
 dll/win32/shell32/CShellDispatch.cpp   | 161 ++++++++++++++++++++++++++-------
 dll/win32/shell32/CShellDispatch.h     |  21 +----
 7 files changed, 257 insertions(+), 182 deletions(-)

diff --git a/dll/win32/shell32/CFolder.cpp b/dll/win32/shell32/CFolder.cpp
index 26eea6cfba..3421ecbcc1 100644
--- a/dll/win32/shell32/CFolder.cpp
+++ b/dll/win32/shell32/CFolder.cpp
@@ -1,21 +1,8 @@
 /*
- * Folder implementation
- *
- * Copyright 2015 Mark Jansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     shell32
+ * LICENSE:     LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
+ * PURPOSE:     Folder implementation
+ * COPYRIGHT:   Copyright 2015-2018 Mark Jansen (mark.jan...@reactos.org)
  */
 
 #include "precomp.h"
@@ -31,9 +18,10 @@ CFolder::~CFolder()
 {
 }
 
-void CFolder::Init(LPITEMIDLIST idlist)
+HRESULT CFolder::Initialize(LPITEMIDLIST idlist)
 {
-    m_idlist.Attach(idlist);
+    m_idlist.Attach(ILClone(idlist));
+    return CShellDispatch_Constructor(IID_PPV_ARG(IShellDispatch, 
&m_Application));
 }
 
 HRESULT CFolder::GetShellFolder(CComPtr<IShellFolder>& psfCurrent)
@@ -65,35 +53,39 @@ HRESULT STDMETHODCALLTYPE CFolder::get_Title(BSTR *pbs)
 HRESULT STDMETHODCALLTYPE CFolder::get_Application(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
-    return E_NOTIMPL;
+
+    if (!ppid)
+        return E_INVALIDARG;
+
+    *ppid = m_Application;
+    (*ppid)->AddRef();
+
+    return S_OK;
 }
 
 HRESULT STDMETHODCALLTYPE CFolder::get_Parent(IDispatch **ppid)
 {
     TRACE("(%p %p)\n", this, ppid);
+
+    if (ppid)
+        *ppid = NULL;
+
     return E_NOTIMPL;
 }
 
 HRESULT STDMETHODCALLTYPE CFolder::get_ParentFolder(Folder **ppsf)
 {
     TRACE("(%p, %p)\n", this);
+
+    *ppsf = NULL;
+
     return E_NOTIMPL;
 }
 
 HRESULT STDMETHODCALLTYPE CFolder::Items(FolderItems **ppid)
 {
-    CFolderItems* items = new CComObject<CFolderItems>();
-    items->AddRef();
-
-    HRESULT hr = items->Init(ILClone(m_idlist));
-    if (FAILED_UNEXPECTEDLY(hr))
-    {
-        items->Release();
-        return hr;
-    }
-
-    *ppid = items;
-    return S_OK;
+    /* FolderItems_Constructor */
+    return 
ShellObjectCreatorInit<CFolderItems>(static_cast<LPITEMIDLIST>(m_idlist), this, 
IID_PPV_ARG(FolderItems, ppid));
 }
 
 HRESULT STDMETHODCALLTYPE CFolder::ParseName(BSTR bName, FolderItem **ppid)
@@ -113,11 +105,10 @@ HRESULT STDMETHODCALLTYPE CFolder::ParseName(BSTR bName, 
FolderItem **ppid)
     if (!SUCCEEDED(hr))
         return S_FALSE;
 
-    CFolderItem* item = new CComObject<CFolderItem>();
-    item->AddRef();
-    item->Init(ILCombine(m_idlist, relativePidl));
-    *ppid = item;
-    return S_OK;
+    CComHeapPtr<ITEMIDLIST> combined;
+    combined.Attach(ILCombine(m_idlist, relativePidl));
+
+    return ShellObjectCreatorInit<CFolderItem>(this, 
static_cast<LPITEMIDLIST>(combined), IID_PPV_ARG(FolderItem, ppid));
 }
 
 HRESULT STDMETHODCALLTYPE CFolder::NewFolder(BSTR bName, VARIANT vOptions)
@@ -151,11 +142,8 @@ HRESULT STDMETHODCALLTYPE CFolder::get_Self(FolderItem 
**ppfi)
     TRACE("(%p, %p)\n", this, ppfi);
     if (!ppfi)
         return E_POINTER;
-    CFolderItem* item = new CComObject<CFolderItem>();
-    item->AddRef();
-    item->Init(ILClone(m_idlist));
-    *ppfi = item;
-    return S_OK;
+
+    return ShellObjectCreatorInit<CFolderItem>(this, 
static_cast<LPITEMIDLIST>(m_idlist), IID_PPV_ARG(FolderItem, ppfi));
 }
 
 HRESULT STDMETHODCALLTYPE CFolder::get_OfflineStatus(LONG *pul)
diff --git a/dll/win32/shell32/CFolder.h b/dll/win32/shell32/CFolder.h
index bfd5c9d08d..df0d482b43 100644
--- a/dll/win32/shell32/CFolder.h
+++ b/dll/win32/shell32/CFolder.h
@@ -1,21 +1,8 @@
 /*
- * Folder implementation
- *
- * Copyright 2015 Mark Jansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     shell32
+ * LICENSE:     LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
+ * PURPOSE:     Folder implementation
+ * COPYRIGHT:   Copyright 2015-2018 Mark Jansen (mark.jan...@reactos.org)
  */
 
 #ifndef _FOLDER_H_
@@ -31,12 +18,13 @@ private:
     HRESULT GetShellFolder(CComPtr<IShellFolder>& psfCurrent);
 
     CComHeapPtr<ITEMIDLIST> m_idlist;
+    CComPtr<IShellDispatch> m_Application;
 
 public:
     CFolder();
     ~CFolder();
 
-    void Init(LPITEMIDLIST idlist);
+    HRESULT Initialize(LPITEMIDLIST idlist);
 
     // *** Folder methods ***
     virtual HRESULT STDMETHODCALLTYPE get_Title(BSTR *pbs);
diff --git a/dll/win32/shell32/CFolderItemVerbs.cpp 
b/dll/win32/shell32/CFolderItemVerbs.cpp
index 87866fa786..0397f724f8 100644
--- a/dll/win32/shell32/CFolderItemVerbs.cpp
+++ b/dll/win32/shell32/CFolderItemVerbs.cpp
@@ -107,7 +107,7 @@ HRESULT CFolderItemVerbs::Init(LPITEMIDLIST idlist)
 HRESULT STDMETHODCALLTYPE CFolderItemVerbs::get_Count(LONG *plCount)
 {
     if (!plCount)
-        return E_POINTER;
+        return E_INVALIDARG;
     *plCount = m_count;
     return S_OK;
 }
@@ -115,12 +115,20 @@ HRESULT STDMETHODCALLTYPE 
CFolderItemVerbs::get_Count(LONG *plCount)
 HRESULT STDMETHODCALLTYPE CFolderItemVerbs::get_Application(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
+
+    if (ppid)
+        *ppid = NULL;
+
     return E_NOTIMPL;
 }
 
 HRESULT STDMETHODCALLTYPE CFolderItemVerbs::get_Parent(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
+
+    if (ppid)
+        *ppid = NULL;
+
     return E_NOTIMPL;
 }
 
@@ -130,9 +138,8 @@ HRESULT STDMETHODCALLTYPE CFolderItemVerbs::Item(VARIANT 
indexVar, FolderItemVer
         return E_POINTER;
 
     CComVariant var;
-    VariantCopyInd(&var, &indexVar);
 
-    HRESULT hr = VariantChangeType(&var, &var, 0, VT_I4);
+    HRESULT hr = VariantChangeType(&var, &indexVar, 0, VT_I4);
     if (FAILED_UNEXPECTEDLY(hr))
         return E_INVALIDARG;
 
@@ -144,7 +151,9 @@ HRESULT STDMETHODCALLTYPE CFolderItemVerbs::Item(VARIANT 
indexVar, FolderItemVer
     BSTR name = NULL;
 
     if(index == m_count)
+    {
         name = SysAllocStringLen(NULL, 0);
+    }
     else
     {
         MENUITEMINFOW info = { sizeof(info), 0 };
diff --git a/dll/win32/shell32/CFolderItems.cpp 
b/dll/win32/shell32/CFolderItems.cpp
index 614ead2e8b..9d2e27090b 100644
--- a/dll/win32/shell32/CFolderItems.cpp
+++ b/dll/win32/shell32/CFolderItems.cpp
@@ -1,21 +1,8 @@
 /*
- * FolderItem(s) implementation
- *
- * Copyright 2015,2016 Mark Jansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     shell32
+ * LICENSE:     LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
+ * PURPOSE:     FolderItem(s) implementation
+ * COPYRIGHT:   Copyright 2015-2018 Mark Jansen (mark.jan...@reactos.org)
  */
 
 #include "precomp.h"
@@ -31,28 +18,49 @@ CFolderItem::~CFolderItem()
 {
 }
 
-void CFolderItem::Init(LPITEMIDLIST idlist)
+HRESULT CFolderItem::Initialize(Folder* folder, LPITEMIDLIST idlist)
 {
-    m_idlist.Attach(idlist);
+    m_idlist.Attach(ILClone(idlist));
+    m_Folder = folder;
+    return S_OK;
 }
 
 // *** FolderItem methods ***
 HRESULT STDMETHODCALLTYPE CFolderItem::get_Application(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
-    return E_NOTIMPL;
+    return m_Folder->get_Application(ppid);
 }
 
 HRESULT STDMETHODCALLTYPE CFolderItem::get_Parent(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
+    if (ppid)
+    {
+        *ppid = m_Folder;
+        m_Folder->AddRef();
+    }
     return E_NOTIMPL;
 }
 
 HRESULT STDMETHODCALLTYPE CFolderItem::get_Name(BSTR *pbs)
 {
     TRACE("(%p, %p)\n", this, pbs);
-    return E_NOTIMPL;
+
+    *pbs = NULL;
+
+    CComPtr<IShellFolder2> Parent;
+    LPCITEMIDLIST last_part;
+    HRESULT hr = SHBindToParent(m_idlist, IID_PPV_ARG(IShellFolder2, &Parent), 
&last_part);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    STRRET strret;
+    hr = Parent->GetDisplayNameOf(last_part, SHGDN_INFOLDER, &strret);
+    if (!FAILED_UNEXPECTEDLY(hr))
+        hr = StrRetToBSTR(&strret, last_part, pbs);
+
+    return hr;
 }
 
 HRESULT STDMETHODCALLTYPE CFolderItem::put_Name(BSTR bs)
@@ -170,11 +178,11 @@ CFolderItems::~CFolderItems()
 {
 }
 
-HRESULT CFolderItems::Init(LPITEMIDLIST idlist)
+HRESULT CFolderItems::Initialize(LPITEMIDLIST idlist, Folder* parent)
 {
     CComPtr<IShellFolder> psfDesktop, psfTarget;
 
-    m_idlist.Attach(idlist);
+    m_idlist.Attach(ILClone(idlist));
 
     HRESULT hr = SHGetDesktopFolder(&psfDesktop);
     if (FAILED_UNEXPECTEDLY(hr))
@@ -189,6 +197,7 @@ HRESULT CFolderItems::Init(LPITEMIDLIST idlist)
     if (FAILED_UNEXPECTEDLY(hr))
         return hr;
 
+    m_Folder = parent;
     return S_OK;
 }
 
@@ -210,8 +219,7 @@ HRESULT STDMETHODCALLTYPE CFolderItems::get_Count(long 
*plCount)
             return hr;
 
         CComHeapPtr<ITEMIDLIST> Pidl;
-        hr = m_EnumIDList->Next(1, &Pidl, 0);
-        while (hr != S_FALSE)
+        while ((hr = m_EnumIDList->Next(1, &Pidl, 0)) != S_FALSE)
         {
             count++;
             Pidl.Free();
@@ -226,12 +234,16 @@ HRESULT STDMETHODCALLTYPE CFolderItems::get_Count(long 
*plCount)
 HRESULT STDMETHODCALLTYPE CFolderItems::get_Application(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
-    return E_NOTIMPL;
+    return m_Folder->get_Application(ppid);
 }
 
 HRESULT STDMETHODCALLTYPE CFolderItems::get_Parent(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
+
+    if (ppid)
+        *ppid = NULL;
+
     return E_NOTIMPL;
 }
 
@@ -240,40 +252,48 @@ HRESULT STDMETHODCALLTYPE CFolderItems::Item(VARIANT 
index, FolderItem **ppid)
     if (!m_EnumIDList)
         return E_FAIL;
 
-    if (V_VT(&index) != VT_I4 && V_VT(&index) != VT_UI4)
-        return E_INVALIDARG;
+    if (V_VT(&index) == VT_I2)
+        VariantChangeType(&index, &index, 0, VT_I4);
 
-    ULONG count = V_UI4(&index);
+    if (V_VT(&index) == VT_I4)
+    {
+        ULONG count = V_UI4(&index);
 
-    HRESULT hr = m_EnumIDList->Reset();
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
+        HRESULT hr = m_EnumIDList->Reset();
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
 
-    hr = m_EnumIDList->Skip(count);
+        hr = m_EnumIDList->Skip(count);
 
-    if (FAILED_UNEXPECTEDLY(hr))
-        return hr;
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
 
-    CComHeapPtr<ITEMIDLIST> spPidl;
-    hr = m_EnumIDList->Next(1, &spPidl, 0);
-    if (hr == S_OK)
+        CComHeapPtr<ITEMIDLIST> spPidl;
+        hr = m_EnumIDList->Next(1, &spPidl, 0);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+        hr = ShellObjectCreatorInit<CFolderItem>(m_Folder, 
static_cast<LPITEMIDLIST>(spPidl), IID_PPV_ARG(FolderItem, ppid));
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+        return hr;
+    }
+    else if (V_VT(&index) == VT_BSTR)
     {
-        CFolderItem* item = new CComObject<CFolderItem>();
-        item->AddRef();
-        item->Init(spPidl.Detach());
-        *ppid = item;
-        return S_OK;
+        if (!V_BSTR(&index))
+            return S_FALSE;
+
+        HRESULT hr = m_Folder->ParseName(V_BSTR(&index), ppid);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+        return hr;
     }
 
-    return hr;
+    FIXME("Index type %d not handled.\n", V_VT(&index));
+    return E_NOTIMPL;
 }
 
 HRESULT STDMETHODCALLTYPE CFolderItems::_NewEnum(IUnknown **ppunk)
 {
-    CFolderItems* items = new CComObject<CFolderItems>();
-    items->AddRef();
-    items->Init(ILClone(m_idlist));
-    *ppunk = items;
-    return S_OK;
+    return 
ShellObjectCreatorInit<CFolderItems>(static_cast<LPITEMIDLIST>(m_idlist), 
m_Folder, IID_FolderItems, reinterpret_cast<void**>(ppunk));
 }
 
diff --git a/dll/win32/shell32/CFolderItems.h b/dll/win32/shell32/CFolderItems.h
index ddb62c87e8..ce339646db 100644
--- a/dll/win32/shell32/CFolderItems.h
+++ b/dll/win32/shell32/CFolderItems.h
@@ -1,21 +1,8 @@
 /*
- * FolderItem(s) implementation
- *
- * Copyright 2015 Mark Jansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     shell32
+ * LICENSE:     LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
+ * PURPOSE:     FolderItem(s) implementation
+ * COPYRIGHT:   Copyright 2015-2018 Mark Jansen (mark.jan...@reactos.org)
  */
 
 #ifndef _FOLDERITEM_H_
@@ -29,13 +16,13 @@ class CFolderItem:
 {
 private:
     CComHeapPtr<ITEMIDLIST> m_idlist;
+    CComPtr<Folder> m_Folder;
 
 public:
     CFolderItem();
     ~CFolderItem();
 
-    // Please note: CFolderItem takes ownership of idlist.
-    void Init(LPITEMIDLIST idlist);
+    HRESULT Initialize(Folder* folder, LPITEMIDLIST idlist);
 
 
     // *** FolderItem methods ***
@@ -75,6 +62,7 @@ class CFolderItems:
 private:
     CComHeapPtr<ITEMIDLIST> m_idlist;
     CComPtr<IEnumIDList> m_EnumIDList;
+    CComPtr<Folder> m_Folder;
     long m_Count;
 
 public:
@@ -82,7 +70,7 @@ public:
     ~CFolderItems();
 
     // Please note: CFolderItems takes ownership of idlist.
-    HRESULT Init(LPITEMIDLIST idlist);
+    HRESULT Initialize(LPITEMIDLIST idlist, Folder* parent);
 
     // *** FolderItems methods ***
     virtual HRESULT STDMETHODCALLTYPE get_Count(long *plCount);
diff --git a/dll/win32/shell32/CShellDispatch.cpp 
b/dll/win32/shell32/CShellDispatch.cpp
index 7c98b4ae52..259b891997 100644
--- a/dll/win32/shell32/CShellDispatch.cpp
+++ b/dll/win32/shell32/CShellDispatch.cpp
@@ -1,24 +1,12 @@
 /*
- * IShellDispatch implementation
- *
- * Copyright 2015 Mark Jansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     shell32
+ * LICENSE:     LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
+ * PURPOSE:     IShellDispatch implementation
+ * COPYRIGHT:   Copyright 2015-2018 Mark Jansen (mark.jan...@reactos.org)
  */
 
 #include "precomp.h"
+#include "winsvc.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
 
@@ -40,13 +28,27 @@ HRESULT CShellDispatch::Initialize()
 HRESULT STDMETHODCALLTYPE CShellDispatch::get_Application(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
-    return E_NOTIMPL;
+
+    if (!ppid)
+        return E_INVALIDARG;
+
+    *ppid = this;
+    AddRef();
+
+    return S_OK;
 }
 
 HRESULT STDMETHODCALLTYPE CShellDispatch::get_Parent(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
-    return E_NOTIMPL;
+
+    if (ppid)
+    {
+        *ppid = static_cast<IDispatch*>(this);
+        AddRef();
+    }
+
+    return S_OK;
 }
 
 HRESULT VariantToIdlist(VARIANT* var, LPITEMIDLIST* idlist)
@@ -69,26 +71,56 @@ HRESULT STDMETHODCALLTYPE CShellDispatch::NameSpace(VARIANT 
vDir, Folder **ppsdf
     if (!ppsdf)
         return E_POINTER;
     *ppsdf = NULL;
-    LPITEMIDLIST idlist = NULL;
-    HRESULT hr = VariantToIdlist(&vDir, &idlist);
+    HRESULT hr;
+
+    if (V_VT(&vDir) == VT_I2)
+    {
+        hr = VariantChangeType(&vDir, &vDir, 0, VT_I4);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+    }
+
+    CComHeapPtr<ITEMIDLIST> idlist;
+    hr = VariantToIdlist(&vDir, &idlist);
     if (!SUCCEEDED(hr) || !idlist)
         return S_FALSE;
-    CFolder* fld = new CComObject<CFolder>();
-    fld->Init(idlist);
-    *ppsdf = fld;
-    fld->AddRef();
-    return hr;
+
+    return ShellObjectCreatorInit<CFolder>(static_cast<LPITEMIDLIST>(idlist), 
IID_PPV_ARG(Folder, ppsdf));
+}
+
+static BOOL is_optional_argument(const VARIANT *arg)
+{
+    return V_VT(arg) == VT_ERROR && V_ERROR(arg) == DISP_E_PARAMNOTFOUND;
 }
 
 HRESULT STDMETHODCALLTYPE CShellDispatch::BrowseForFolder(LONG Hwnd, BSTR 
Title, LONG Options, VARIANT RootFolder, Folder **ppsdf)
 {
     TRACE("(%p, %lu, %ls, %lu, %s, %p)\n", this, Hwnd, Title, Options, 
debugstr_variant(&RootFolder), ppsdf);
-    return E_NOTIMPL;
+
+    *ppsdf = NULL;
+
+    if (!is_optional_argument(&RootFolder))
+        FIXME("root folder is ignored\n");
+
+    BROWSEINFOW bi = { 0 };
+    bi.hwndOwner = reinterpret_cast<HWND>(LongToHandle(Hwnd));
+    bi.lpszTitle = Title;
+    bi.ulFlags = Options;
+
+    CComHeapPtr<ITEMIDLIST> selection;
+    selection.Attach(SHBrowseForFolderW(&bi));
+    if (!selection)
+        return S_FALSE;
+
+    return 
ShellObjectCreatorInit<CFolder>(static_cast<LPITEMIDLIST>(selection), 
IID_PPV_ARG(Folder, ppsdf));
 }
 
 HRESULT STDMETHODCALLTYPE CShellDispatch::Windows(IDispatch **ppid)
 {
     TRACE("(%p, %p)\n", this, ppid);
+
+    *ppid = NULL;
+
     return E_NOTIMPL;
 }
 
@@ -208,10 +240,35 @@ HRESULT STDMETHODCALLTYPE 
CShellDispatch::IsRestricted(BSTR group, BSTR restrict
     return E_NOTIMPL;
 }
 
-HRESULT STDMETHODCALLTYPE CShellDispatch::ShellExecute(BSTR file, VARIANT 
args, VARIANT dir, VARIANT op, VARIANT show)
+HRESULT STDMETHODCALLTYPE CShellDispatch::ShellExecute(BSTR file, VARIANT 
v_args, VARIANT v_dir, VARIANT v_op, VARIANT v_show)
 {
-    TRACE("(%p, %ls, %s, %s, %s, %s)\n", this, file, debugstr_variant(&args), 
debugstr_variant(&dir), debugstr_variant(&op), debugstr_variant(&show));
-    return E_NOTIMPL;
+    CComVariant args_str, dir_str, op_str, show_int;
+    WCHAR *args = NULL, *dir = NULL, *op = NULL;
+    INT show = 0;
+    HINSTANCE ret;
+
+    TRACE("(%s, %s, %s, %s, %s)\n", debugstr_w(file), 
debugstr_variant(&v_args),
+            debugstr_variant(&v_dir), debugstr_variant(&v_op), 
debugstr_variant(&v_show));
+
+    args_str.ChangeType(VT_BSTR, &v_args);
+    if (V_VT(&args_str) == VT_BSTR)
+        args = V_BSTR(&args_str);
+
+    dir_str.ChangeType(VT_BSTR, &v_dir);
+    if (V_VT(&dir_str) == VT_BSTR)
+        dir = V_BSTR(&dir_str);
+
+    op_str.ChangeType(VT_BSTR, &v_op);
+    if (V_VT(&op_str) == VT_BSTR)
+        op = V_BSTR(&op_str);
+
+    show_int.ChangeType(VT_I4, &v_show);
+    if (V_VT(&show_int) == VT_I4)
+        show = V_I4(&show_int);
+
+    ret = ShellExecuteW(NULL, op, file, args, dir, show);
+
+    return (ULONG_PTR)ret > 32 ? S_OK : S_FALSE;
 }
 
 HRESULT STDMETHODCALLTYPE CShellDispatch::FindPrinter(BSTR name, BSTR 
location, BSTR model)
@@ -238,10 +295,48 @@ HRESULT STDMETHODCALLTYPE 
CShellDispatch::ServiceStop(BSTR service, VARIANT pers
     return E_NOTIMPL;
 }
 
-HRESULT STDMETHODCALLTYPE CShellDispatch::IsServiceRunning(BSTR service, 
VARIANT *running)
+HRESULT STDMETHODCALLTYPE CShellDispatch::IsServiceRunning(BSTR name, VARIANT 
*running)
 {
-    TRACE("(%p, %ls, %p)\n", this, service, running);
-    return E_NOTIMPL;
+    SERVICE_STATUS_PROCESS status;
+    SC_HANDLE scm, service;
+    DWORD dummy;
+
+    TRACE("(%s, %p)\n", debugstr_w(name), running);
+
+    V_VT(running) = VT_BOOL;
+    V_BOOL(running) = VARIANT_FALSE;
+
+    scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
+    if (!scm)
+    {
+        ERR("failed to connect to service manager\n");
+        return S_OK;
+    }
+
+    service = OpenServiceW(scm, name, SERVICE_QUERY_STATUS);
+    if (!service)
+    {
+        ERR("Failed to open service %s (%u)\n", debugstr_w(name), 
GetLastError());
+        CloseServiceHandle(scm);
+        return S_OK;
+    }
+
+    if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (BYTE *)&status,
+                              sizeof(SERVICE_STATUS_PROCESS), &dummy))
+    {
+        TRACE("failed to query service status (%u)\n", GetLastError());
+        CloseServiceHandle(service);
+        CloseServiceHandle(scm);
+        return S_OK;
+    }
+
+    if (status.dwCurrentState == SERVICE_RUNNING)
+        V_BOOL(running) = VARIANT_TRUE;
+
+    CloseServiceHandle(service);
+    CloseServiceHandle(scm);
+
+    return S_OK;
 }
 
 HRESULT STDMETHODCALLTYPE CShellDispatch::CanStartStopService(BSTR service, 
VARIANT *ret)
diff --git a/dll/win32/shell32/CShellDispatch.h 
b/dll/win32/shell32/CShellDispatch.h
index 539f3cfd29..6c32ecf667 100644
--- a/dll/win32/shell32/CShellDispatch.h
+++ b/dll/win32/shell32/CShellDispatch.h
@@ -1,21 +1,8 @@
 /*
- * IShellDispatch implementation
- *
- * Copyright 2015 Mark Jansen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     shell32
+ * LICENSE:     LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
+ * PURPOSE:     IShellDispatch implementation
+ * COPYRIGHT:   Copyright 2015-2018 Mark Jansen (mark.jan...@reactos.org)
  */
 
 #ifndef _SHELLDISPATCH_H_

Reply via email to