| /* |
| * IShellDispatch implementation |
| * |
| * Copyright 2010 Alexander Morozov for Etersoft |
| * |
| * 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 |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <stdarg.h> |
| |
| #define COBJMACROS |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winreg.h" |
| #include "winsvc.h" |
| #include "shlwapi.h" |
| #include "shlobj.h" |
| #include "shldisp.h" |
| #include "debughlp.h" |
| |
| #include "shell32_main.h" |
| #include "pidl.h" |
| |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(shell); |
| |
| static ITypeLib *typelib; |
| static const IID * const tid_ids[] = |
| { |
| &IID_NULL, |
| &IID_IShellDispatch6, |
| &IID_IShellFolderViewDual3, |
| &IID_Folder3, |
| &IID_FolderItem2, |
| &IID_FolderItems3, |
| &IID_FolderItemVerb, |
| &IID_FolderItemVerbs |
| }; |
| static ITypeInfo *typeinfos[LAST_tid]; |
| |
| typedef struct { |
| IShellDispatch6 IShellDispatch6_iface; |
| LONG ref; |
| } ShellDispatch; |
| |
| typedef struct { |
| Folder3 Folder3_iface; |
| LONG ref; |
| IDispatch *application; |
| IShellFolder2 *folder; |
| PIDLIST_ABSOLUTE pidl; |
| BSTR path; |
| } FolderImpl; |
| |
| typedef struct { |
| FolderItems3 FolderItems3_iface; |
| LONG ref; |
| FolderImpl *folder; |
| BSTR *item_names; |
| LONG item_count; |
| } FolderItemsImpl; |
| |
| typedef struct { |
| FolderItem2 FolderItem2_iface; |
| LONG ref; |
| FolderImpl *folder; |
| WCHAR *path; /* if NULL, folder path is used */ |
| DWORD attributes; |
| } FolderItemImpl; |
| |
| typedef struct { |
| FolderItemVerbs FolderItemVerbs_iface; |
| LONG ref; |
| |
| IContextMenu *contextmenu; |
| HMENU hMenu; |
| LONG count; |
| } FolderItemVerbsImpl; |
| |
| typedef struct { |
| FolderItemVerb FolderItemVerb_iface; |
| LONG ref; |
| |
| IContextMenu *contextmenu; |
| BSTR name; |
| } FolderItemVerbImpl; |
| |
| static inline ShellDispatch *impl_from_IShellDispatch6(IShellDispatch6 *iface) |
| { |
| return CONTAINING_RECORD(iface, ShellDispatch, IShellDispatch6_iface); |
| } |
| |
| static inline FolderImpl *impl_from_Folder(Folder3 *iface) |
| { |
| return CONTAINING_RECORD(iface, FolderImpl, Folder3_iface); |
| } |
| |
| static inline FolderItemsImpl *impl_from_FolderItems(FolderItems3 *iface) |
| { |
| return CONTAINING_RECORD(iface, FolderItemsImpl, FolderItems3_iface); |
| } |
| |
| static inline FolderItemImpl *impl_from_FolderItem(FolderItem2 *iface) |
| { |
| return CONTAINING_RECORD(iface, FolderItemImpl, FolderItem2_iface); |
| } |
| |
| static inline FolderItemVerbsImpl *impl_from_FolderItemVerbs(FolderItemVerbs *iface) |
| { |
| return CONTAINING_RECORD(iface, FolderItemVerbsImpl, FolderItemVerbs_iface); |
| } |
| |
| static inline FolderItemVerbImpl *impl_from_FolderItemVerb(FolderItemVerb *iface) |
| { |
| return CONTAINING_RECORD(iface, FolderItemVerbImpl, FolderItemVerb_iface); |
| } |
| |
| static HRESULT load_typelib(void) |
| { |
| ITypeLib *tl; |
| HRESULT hr; |
| |
| hr = LoadRegTypeLib(&LIBID_Shell32, 1, 0, LOCALE_SYSTEM_DEFAULT, &tl); |
| if (FAILED(hr)) { |
| ERR("LoadRegTypeLib failed: %08x\n", hr); |
| return hr; |
| } |
| |
| if (InterlockedCompareExchangePointer((void**)&typelib, tl, NULL)) |
| ITypeLib_Release(tl); |
| return hr; |
| } |
| |
| void release_typelib(void) |
| { |
| unsigned i; |
| |
| if (!typelib) |
| return; |
| |
| for (i = 0; i < sizeof(typeinfos)/sizeof(*typeinfos); i++) |
| if (typeinfos[i]) |
| ITypeInfo_Release(typeinfos[i]); |
| |
| ITypeLib_Release(typelib); |
| } |
| |
| HRESULT get_typeinfo(enum tid_t tid, ITypeInfo **typeinfo) |
| { |
| HRESULT hr; |
| |
| if (!typelib) |
| hr = load_typelib(); |
| if (!typelib) |
| return hr; |
| |
| if (!typeinfos[tid]) |
| { |
| ITypeInfo *ti; |
| |
| hr = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti); |
| if (FAILED(hr)) |
| { |
| ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hr); |
| return hr; |
| } |
| |
| if (InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL)) |
| ITypeInfo_Release(ti); |
| } |
| |
| *typeinfo = typeinfos[tid]; |
| return S_OK; |
| } |
| |
| /* FolderItemVerb */ |
| static HRESULT WINAPI FolderItemVerbImpl_QueryInterface(FolderItemVerb *iface, |
| REFIID riid, void **ppv) |
| { |
| FolderItemVerbImpl *This = impl_from_FolderItemVerb(iface); |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv); |
| |
| if (IsEqualIID(&IID_IUnknown, riid) || |
| IsEqualIID(&IID_IDispatch, riid) || |
| IsEqualIID(&IID_FolderItemVerb, riid)) |
| *ppv = &This->FolderItemVerb_iface; |
| else |
| { |
| WARN("not implemented for %s\n", debugstr_guid(riid)); |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI FolderItemVerbImpl_AddRef(FolderItemVerb *iface) |
| { |
| FolderItemVerbImpl *This = impl_from_FolderItemVerb(iface); |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI FolderItemVerbImpl_Release(FolderItemVerb *iface) |
| { |
| FolderItemVerbImpl *This = impl_from_FolderItemVerb(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| if (!ref) |
| { |
| IContextMenu_Release(This->contextmenu); |
| SysFreeString(This->name); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbImpl_GetTypeInfoCount(FolderItemVerb *iface, UINT *pctinfo) |
| { |
| TRACE("(%p,%p)\n", iface, pctinfo); |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbImpl_GetTypeInfo(FolderItemVerb *iface, UINT iTInfo, |
| LCID lcid, ITypeInfo **ppTInfo) |
| { |
| HRESULT hr; |
| |
| TRACE("(%p,%u,%d,%p)\n", iface, iTInfo, lcid, ppTInfo); |
| |
| hr = get_typeinfo(FolderItemVerb_tid, ppTInfo); |
| if (SUCCEEDED(hr)) |
| ITypeInfo_AddRef(*ppTInfo); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbImpl_GetIDsOfNames(FolderItemVerb *iface, |
| REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) |
| { |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%s,%p,%u,%d,%p)\n", iface, shdebugstr_guid(riid), rgszNames, cNames, lcid, |
| rgDispId); |
| |
| hr = get_typeinfo(FolderItemVerb_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbImpl_Invoke(FolderItemVerb *iface, |
| DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, |
| DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, |
| UINT *puArgErr) |
| { |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%d,%s,%d,%u,%p,%p,%p,%p)\n", iface, dispIdMember, shdebugstr_guid(riid), lcid, |
| wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(FolderItemVerb_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_Invoke(ti, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbImpl_get_Application(FolderItemVerb *iface, IDispatch **disp) |
| { |
| TRACE("(%p, %p)\n", iface, disp); |
| |
| if (disp) |
| *disp = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbImpl_get_Parent(FolderItemVerb *iface, IDispatch **disp) |
| { |
| TRACE("(%p, %p)\n", iface, disp); |
| |
| if (disp) |
| *disp = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbImpl_get_Name(FolderItemVerb *iface, BSTR *name) |
| { |
| FolderItemVerbImpl *This = impl_from_FolderItemVerb(iface); |
| |
| TRACE("(%p, %p)\n", iface, name); |
| |
| *name = SysAllocString(This->name); |
| return *name ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbImpl_DoIt(FolderItemVerb *iface) |
| { |
| FIXME("(%p)\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static FolderItemVerbVtbl folderitemverbvtbl = { |
| FolderItemVerbImpl_QueryInterface, |
| FolderItemVerbImpl_AddRef, |
| FolderItemVerbImpl_Release, |
| FolderItemVerbImpl_GetTypeInfoCount, |
| FolderItemVerbImpl_GetTypeInfo, |
| FolderItemVerbImpl_GetIDsOfNames, |
| FolderItemVerbImpl_Invoke, |
| FolderItemVerbImpl_get_Application, |
| FolderItemVerbImpl_get_Parent, |
| FolderItemVerbImpl_get_Name, |
| FolderItemVerbImpl_DoIt |
| }; |
| |
| static HRESULT FolderItemVerb_Constructor(IContextMenu *contextmenu, BSTR name, FolderItemVerb **verb) |
| { |
| FolderItemVerbImpl *This; |
| |
| TRACE("%p, %s\n", contextmenu, debugstr_w(name)); |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(FolderItemVerbImpl)); |
| if (!This) |
| return E_OUTOFMEMORY; |
| |
| This->FolderItemVerb_iface.lpVtbl = &folderitemverbvtbl; |
| This->ref = 1; |
| This->contextmenu = contextmenu; |
| IContextMenu_AddRef(contextmenu); |
| This->name = name; |
| |
| *verb = &This->FolderItemVerb_iface; |
| return S_OK; |
| } |
| |
| /* FolderItemVerbs */ |
| static HRESULT WINAPI FolderItemVerbsImpl_QueryInterface(FolderItemVerbs *iface, |
| REFIID riid, void **ppv) |
| { |
| FolderItemVerbsImpl *This = impl_from_FolderItemVerbs(iface); |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv); |
| |
| if (IsEqualIID(&IID_IUnknown, riid) || |
| IsEqualIID(&IID_IDispatch, riid) || |
| IsEqualIID(&IID_FolderItemVerbs, riid)) |
| *ppv = &This->FolderItemVerbs_iface; |
| else |
| { |
| WARN("not implemented for %s\n", debugstr_guid(riid)); |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IUnknown_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI FolderItemVerbsImpl_AddRef(FolderItemVerbs *iface) |
| { |
| FolderItemVerbsImpl *This = impl_from_FolderItemVerbs(iface); |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI FolderItemVerbsImpl_Release(FolderItemVerbs *iface) |
| { |
| FolderItemVerbsImpl *This = impl_from_FolderItemVerbs(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| if (!ref) |
| { |
| IContextMenu_Release(This->contextmenu); |
| DestroyMenu(This->hMenu); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbsImpl_GetTypeInfoCount(FolderItemVerbs *iface, UINT *pctinfo) |
| { |
| TRACE("(%p,%p)\n", iface, pctinfo); |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbsImpl_GetTypeInfo(FolderItemVerbs *iface, UINT iTInfo, |
| LCID lcid, ITypeInfo **ppTInfo) |
| { |
| HRESULT hr; |
| |
| TRACE("(%p,%u,%d,%p)\n", iface, iTInfo, lcid, ppTInfo); |
| |
| hr = get_typeinfo(FolderItemVerbs_tid, ppTInfo); |
| if (SUCCEEDED(hr)) |
| ITypeInfo_AddRef(*ppTInfo); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbsImpl_GetIDsOfNames(FolderItemVerbs *iface, |
| REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) |
| { |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%s,%p,%u,%d,%p)\n", iface, shdebugstr_guid(riid), rgszNames, cNames, lcid, |
| rgDispId); |
| |
| hr = get_typeinfo(FolderItemVerbs_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbsImpl_Invoke(FolderItemVerbs *iface, |
| DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, |
| DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, |
| UINT *puArgErr) |
| { |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%d,%s,%d,%u,%p,%p,%p,%p)\n", iface, dispIdMember, shdebugstr_guid(riid), lcid, |
| wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(FolderItemVerbs_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_Invoke(ti, iface, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbsImpl_get_Count(FolderItemVerbs *iface, LONG *count) |
| { |
| FolderItemVerbsImpl *This = impl_from_FolderItemVerbs(iface); |
| |
| TRACE("(%p, %p)\n", iface, count); |
| |
| if (!count) |
| return E_INVALIDARG; |
| |
| *count = This->count; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbsImpl_get_Application(FolderItemVerbs *iface, IDispatch **disp) |
| { |
| TRACE("(%p, %p)\n", iface, disp); |
| |
| if (disp) |
| *disp = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbsImpl_get_Parent(FolderItemVerbs *iface, IDispatch **disp) |
| { |
| TRACE("(%p, %p)\n", iface, disp); |
| |
| if (disp) |
| *disp = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemVerbsImpl_Item(FolderItemVerbs *iface, VARIANT index, FolderItemVerb **verb) |
| { |
| FolderItemVerbsImpl *This = impl_from_FolderItemVerbs(iface); |
| MENUITEMINFOW info; |
| HRESULT hr; |
| VARIANT v; |
| BSTR name; |
| |
| TRACE("(%p, %s, %p)\n", iface, debugstr_variant(&index), verb); |
| |
| if (!verb) |
| return E_INVALIDARG; |
| |
| *verb = NULL; |
| |
| VariantInit(&v); |
| VariantCopyInd(&v, &index); |
| |
| hr = VariantChangeType(&v, &v, 0, VT_I4); |
| if (FAILED(hr)) |
| { |
| FIXME("failed to coerce to VT_I4, %s\n", debugstr_variant(&v)); |
| return hr; |
| } |
| |
| if (V_I4(&v) > This->count) |
| return S_OK; |
| |
| if (V_I4(&v) == This->count) |
| name = SysAllocStringLen(NULL, 0); |
| else |
| { |
| /* get item name */ |
| memset(&info, 0, sizeof(info)); |
| info.cbSize = sizeof(info); |
| info.fMask = MIIM_STRING; |
| if (!GetMenuItemInfoW(This->hMenu, V_I4(&v), TRUE, &info)) |
| return E_FAIL; |
| |
| name = SysAllocStringLen(NULL, info.cch); |
| if (name) |
| { |
| info.dwTypeData = name; |
| info.cch++; |
| GetMenuItemInfoW(This->hMenu, V_I4(&v), TRUE, &info); |
| } |
| } |
| |
| if (!name) |
| return E_OUTOFMEMORY; |
| |
| return FolderItemVerb_Constructor(This->contextmenu, name, verb); |
| } |
| |
| static HRESULT WINAPI FolderItemVerbsImpl__NewEnum(FolderItemVerbs *iface, IUnknown **ret) |
| { |
| FIXME("(%p, %p)\n", iface, ret); |
| return E_NOTIMPL; |
| } |
| |
| static FolderItemVerbsVtbl folderitemverbsvtbl = { |
| FolderItemVerbsImpl_QueryInterface, |
| FolderItemVerbsImpl_AddRef, |
| FolderItemVerbsImpl_Release, |
| FolderItemVerbsImpl_GetTypeInfoCount, |
| FolderItemVerbsImpl_GetTypeInfo, |
| FolderItemVerbsImpl_GetIDsOfNames, |
| FolderItemVerbsImpl_Invoke, |
| FolderItemVerbsImpl_get_Count, |
| FolderItemVerbsImpl_get_Application, |
| FolderItemVerbsImpl_get_Parent, |
| FolderItemVerbsImpl_Item, |
| FolderItemVerbsImpl__NewEnum |
| }; |
| |
| static HRESULT FolderItemVerbs_Constructor(BSTR path, FolderItemVerbs **verbs) |
| { |
| FolderItemVerbsImpl *This; |
| IShellFolder *folder; |
| LPCITEMIDLIST child; |
| LPITEMIDLIST pidl; |
| HRESULT hr; |
| |
| *verbs = NULL; |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(FolderItemVerbsImpl)); |
| if (!This) |
| return E_OUTOFMEMORY; |
| |
| This->FolderItemVerbs_iface.lpVtbl = &folderitemverbsvtbl; |
| This->ref = 1; |
| |
| /* build context menu for this path */ |
| hr = SHParseDisplayName(path, NULL, &pidl, 0, NULL); |
| if (FAILED(hr)) |
| goto failed; |
| |
| hr = SHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, &child); |
| CoTaskMemFree(pidl); |
| if (FAILED(hr)) |
| goto failed; |
| |
| hr = IShellFolder_GetUIObjectOf(folder, NULL, 1, &child, &IID_IContextMenu, NULL, (void**)&This->contextmenu); |
| IShellFolder_Release(folder); |
| if (FAILED(hr)) |
| goto failed; |
| |
| This->hMenu = CreatePopupMenu(); |
| hr = IContextMenu_QueryContextMenu(This->contextmenu, This->hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL); |
| if (FAILED(hr)) |
| { |
| FolderItemVerbs_Release(&This->FolderItemVerbs_iface); |
| return hr; |
| } |
| |
| This->count = GetMenuItemCount(This->hMenu); |
| *verbs = &This->FolderItemVerbs_iface; |
| return S_OK; |
| |
| failed: |
| HeapFree(GetProcessHeap(), 0, This); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_QueryInterface(FolderItem2 *iface, |
| REFIID riid, LPVOID *ppv) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, riid) || |
| IsEqualIID(&IID_IDispatch, riid) || |
| IsEqualIID(&IID_FolderItem, riid) || |
| IsEqualIID(&IID_FolderItem2, riid)) |
| *ppv = &This->FolderItem2_iface; |
| else |
| { |
| WARN("not implemented for %s\n", debugstr_guid(riid)); |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| IUnknown_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI FolderItemImpl_AddRef(FolderItem2 *iface) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI FolderItemImpl_Release(FolderItem2 *iface) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| if (!ref) |
| { |
| Folder3_Release(&This->folder->Folder3_iface); |
| HeapFree(GetProcessHeap(), 0, This->path); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| return ref; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_GetTypeInfoCount(FolderItem2 *iface, |
| UINT *pctinfo) |
| { |
| TRACE("(%p,%p)\n", iface, pctinfo); |
| |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_GetTypeInfo(FolderItem2 *iface, UINT iTInfo, |
| LCID lcid, ITypeInfo **ppTInfo) |
| { |
| HRESULT hr; |
| |
| TRACE("(%p,%u,%d,%p)\n", iface, iTInfo, lcid, ppTInfo); |
| |
| hr = get_typeinfo(FolderItem2_tid, ppTInfo); |
| if (SUCCEEDED(hr)) |
| ITypeInfo_AddRef(*ppTInfo); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_GetIDsOfNames(FolderItem2 *iface, |
| REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, |
| DISPID *rgDispId) |
| { |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%s,%p,%u,%d,%p)\n", iface, shdebugstr_guid(riid), rgszNames, cNames, lcid, |
| rgDispId); |
| |
| hr = get_typeinfo(FolderItem2_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_Invoke(FolderItem2 *iface, |
| DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, |
| DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, |
| UINT *puArgErr) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%d,%s,%d,%u,%p,%p,%p,%p)\n", iface, dispIdMember, shdebugstr_guid(riid), lcid, |
| wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(FolderItem2_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_Invoke(ti, This, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_Application(FolderItem2 *iface, IDispatch **disp) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| |
| TRACE("(%p,%p)\n", iface, disp); |
| |
| return Folder3_get_Application(&This->folder->Folder3_iface, disp); |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_Parent(FolderItem2 *iface, IDispatch **disp) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| |
| TRACE("(%p,%p)\n", iface, disp); |
| |
| if (disp) |
| { |
| *disp = (IDispatch *)&This->folder->Folder3_iface; |
| IDispatch_AddRef(*disp); |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_Name(FolderItem2 *iface, BSTR *name) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| LPCITEMIDLIST last_part; |
| IShellFolder2 *parent; |
| HRESULT hr = S_OK; |
| LPITEMIDLIST pidl; |
| STRRET strret; |
| |
| TRACE("(%p,%p)\n", iface, name); |
| |
| *name = NULL; |
| |
| if (This->path) |
| hr = SHParseDisplayName(This->path, NULL, &pidl, 0, NULL); |
| else |
| pidl = This->folder->pidl; |
| |
| if (FAILED(hr)) |
| return S_FALSE; |
| |
| hr = SHBindToParent(pidl, &IID_IShellFolder2, (void **)&parent, &last_part); |
| if (hr == S_OK) |
| hr = IShellFolder2_GetDisplayNameOf(parent, last_part, SHGDN_INFOLDER, &strret); |
| |
| IShellFolder2_Release(parent); |
| |
| if (hr == S_OK) |
| hr = StrRetToBSTR(&strret, last_part, name); |
| |
| if (This->path) |
| ILFree(pidl); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_put_Name(FolderItem2 *iface, BSTR bs) |
| { |
| FIXME("(%p,%s)\n", iface, debugstr_w(bs)); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_Path(FolderItem2 *iface, BSTR *path) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| |
| TRACE("(%p,%p)\n", iface, path); |
| |
| *path = SysAllocString(This->path ? This->path : This->folder->path); |
| return *path ? S_OK : E_OUTOFMEMORY; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_GetLink(FolderItem2 *iface, |
| IDispatch **ppid) |
| { |
| FIXME("(%p,%p)\n", iface, ppid); |
| |
| *ppid = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_GetFolder(FolderItem2 *iface, |
| IDispatch **ppid) |
| { |
| FIXME("(%p,%p)\n", iface, ppid); |
| |
| *ppid = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_IsLink(FolderItem2 *iface, VARIANT_BOOL *b) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| |
| TRACE("(%p,%p)\n", iface, b); |
| |
| *b = This->attributes & SFGAO_LINK ? VARIANT_TRUE : VARIANT_FALSE; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_IsFolder(FolderItem2 *iface, VARIANT_BOOL *b) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| |
| TRACE("(%p,%p)\n", iface, b); |
| |
| *b = This->attributes & SFGAO_FOLDER ? VARIANT_TRUE : VARIANT_FALSE; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_IsFileSystem(FolderItem2 *iface, VARIANT_BOOL *b) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| |
| TRACE("(%p,%p)\n", iface, b); |
| |
| *b = This->attributes & SFGAO_FILESYSTEM ? VARIANT_TRUE : VARIANT_FALSE; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_IsBrowsable(FolderItem2 *iface, VARIANT_BOOL *b) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| |
| TRACE("(%p,%p)\n", iface, b); |
| |
| *b = This->attributes & SFGAO_BROWSABLE ? VARIANT_TRUE : VARIANT_FALSE; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_ModifyDate(FolderItem2 *iface, |
| DATE *pdt) |
| { |
| FIXME("(%p,%p)\n", iface, pdt); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_put_ModifyDate(FolderItem2 *iface, DATE dt) |
| { |
| FIXME("(%p,%f)\n", iface, dt); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_Size(FolderItem2 *iface, LONG *pul) |
| { |
| FIXME("(%p,%p)\n", iface, pul); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_get_Type(FolderItem2 *iface, BSTR *pbs) |
| { |
| FIXME("(%p,%p)\n", iface, pbs); |
| |
| *pbs = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_Verbs(FolderItem2 *iface, FolderItemVerbs **verbs) |
| { |
| FolderItemImpl *This = impl_from_FolderItem(iface); |
| |
| TRACE("(%p, %p)\n", iface, verbs); |
| |
| if (!verbs) |
| return E_INVALIDARG; |
| |
| return FolderItemVerbs_Constructor(This->path ? This->path : This->folder->path, verbs); |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_InvokeVerb(FolderItem2 *iface, |
| VARIANT vVerb) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_InvokeVerbEx(FolderItem2 *iface, VARIANT verb, VARIANT args) |
| { |
| FIXME("(%p): stub\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemImpl_ExtendedProperty(FolderItem2 *iface, BSTR propname, VARIANT *ret) |
| { |
| FIXME("(%p)->(%s %p): stub\n", iface, debugstr_w(propname), ret); |
| |
| return E_NOTIMPL; |
| } |
| |
| static const FolderItem2Vtbl FolderItemImpl_Vtbl = { |
| FolderItemImpl_QueryInterface, |
| FolderItemImpl_AddRef, |
| FolderItemImpl_Release, |
| FolderItemImpl_GetTypeInfoCount, |
| FolderItemImpl_GetTypeInfo, |
| FolderItemImpl_GetIDsOfNames, |
| FolderItemImpl_Invoke, |
| FolderItemImpl_get_Application, |
| FolderItemImpl_get_Parent, |
| FolderItemImpl_get_Name, |
| FolderItemImpl_put_Name, |
| FolderItemImpl_get_Path, |
| FolderItemImpl_get_GetLink, |
| FolderItemImpl_get_GetFolder, |
| FolderItemImpl_get_IsLink, |
| FolderItemImpl_get_IsFolder, |
| FolderItemImpl_get_IsFileSystem, |
| FolderItemImpl_get_IsBrowsable, |
| FolderItemImpl_get_ModifyDate, |
| FolderItemImpl_put_ModifyDate, |
| FolderItemImpl_get_Size, |
| FolderItemImpl_get_Type, |
| FolderItemImpl_Verbs, |
| FolderItemImpl_InvokeVerb, |
| FolderItemImpl_InvokeVerbEx, |
| FolderItemImpl_ExtendedProperty |
| }; |
| |
| static HRESULT FolderItem_Constructor(FolderImpl *folder, const WCHAR *path, FolderItem **item) |
| { |
| PIDLIST_ABSOLUTE pidl; |
| FolderItemImpl *This; |
| |
| TRACE("%s\n", debugstr_w(path)); |
| |
| *item = NULL; |
| |
| This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); |
| if (!This) |
| return E_OUTOFMEMORY; |
| |
| This->FolderItem2_iface.lpVtbl = &FolderItemImpl_Vtbl; |
| This->ref = 1; |
| if (path) |
| This->path = strdupW(path); |
| |
| This->folder = folder; |
| Folder3_AddRef(&folder->Folder3_iface); |
| |
| if (SHParseDisplayName(This->path, NULL, &pidl, ~0u, &This->attributes) == S_OK) |
| ILFree(pidl); |
| |
| *item = (FolderItem *)&This->FolderItem2_iface; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_QueryInterface(FolderItems3 *iface, |
| REFIID riid, LPVOID *ppv) |
| { |
| FolderItemsImpl *This = impl_from_FolderItems(iface); |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, riid) || |
| IsEqualIID(&IID_IDispatch, riid) || |
| IsEqualIID(&IID_FolderItems, riid) || |
| IsEqualIID(&IID_FolderItems2, riid) || |
| IsEqualIID(&IID_FolderItems3, riid)) |
| *ppv = &This->FolderItems3_iface; |
| else |
| { |
| WARN("not implemented for %s\n", debugstr_guid(riid)); |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| IUnknown_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI FolderItemsImpl_AddRef(FolderItems3 *iface) |
| { |
| FolderItemsImpl *This = impl_from_FolderItems(iface); |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI FolderItemsImpl_Release(FolderItems3 *iface) |
| { |
| FolderItemsImpl *This = impl_from_FolderItems(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| LONG i; |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| if (!ref) |
| { |
| Folder3_Release(&This->folder->Folder3_iface); |
| for (i = 0; i < This->item_count; i++) |
| SysFreeString(This->item_names[i]); |
| HeapFree(GetProcessHeap(), 0, This->item_names); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| return ref; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_GetTypeInfoCount(FolderItems3 *iface, |
| UINT *count) |
| { |
| TRACE("(%p,%p)\n", iface, count); |
| |
| *count = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_GetTypeInfo(FolderItems3 *iface, |
| UINT type, LCID lcid, ITypeInfo **ppti) |
| { |
| HRESULT hr; |
| |
| TRACE("(%p,%u,%d,%p)\n", iface, type, lcid, ppti); |
| |
| hr = get_typeinfo(FolderItems3_tid, ppti); |
| if (SUCCEEDED(hr)) |
| ITypeInfo_AddRef(*ppti); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_GetIDsOfNames(FolderItems3 *iface, |
| REFIID riid, LPOLESTR *names, UINT count, LCID lcid, DISPID *dispid) |
| { |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%s,%p,%u,%d,%p)\n", iface, shdebugstr_guid(riid), names, count, lcid, dispid); |
| |
| hr = get_typeinfo(FolderItems3_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_GetIDsOfNames(ti, names, count, dispid); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_Invoke(FolderItems3 *iface, |
| DISPID dispid, REFIID riid, LCID lcid, WORD flags, DISPPARAMS *params, |
| VARIANT *result, EXCEPINFO *ei, UINT *err) |
| { |
| FolderItemsImpl *This = impl_from_FolderItems(iface); |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%d,%s,%d,%u,%p,%p,%p,%p)\n", iface, dispid, shdebugstr_guid(riid), lcid, flags, params, result, ei, err); |
| |
| hr = get_typeinfo(FolderItems3_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_Invoke(ti, This, dispid, flags, params, result, ei, err); |
| return hr; |
| } |
| |
| static BOOL shellfolder_exists(const WCHAR *path) |
| { |
| PIDLIST_ABSOLUTE pidl = NULL; |
| HRESULT hr; |
| |
| hr = SHParseDisplayName(path, NULL, &pidl, 0, NULL); |
| ILFree(pidl); |
| |
| return SUCCEEDED(hr); |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_get_Count(FolderItems3 *iface, LONG *count) |
| { |
| FolderItemsImpl *This = impl_from_FolderItems(iface); |
| |
| TRACE("(%p,%p)\n", iface, count); |
| |
| *count = shellfolder_exists(This->folder->path) ? This->item_count : 0; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_get_Application(FolderItems3 *iface, IDispatch **disp) |
| { |
| FolderItemsImpl *This = impl_from_FolderItems(iface); |
| |
| TRACE("(%p,%p)\n", iface, disp); |
| |
| return Folder3_get_Application(&This->folder->Folder3_iface, disp); |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_get_Parent(FolderItems3 *iface, IDispatch **ppid) |
| { |
| TRACE("(%p,%p)\n", iface, ppid); |
| |
| if (ppid) |
| *ppid = NULL; |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_Item(FolderItems3 *iface, VARIANT index, FolderItem **item) |
| { |
| FolderItemsImpl *This = impl_from_FolderItems(iface); |
| BSTR display_name = NULL; |
| HRESULT hr; |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&index), item); |
| |
| *item = NULL; |
| |
| if (!shellfolder_exists(This->folder->path)) |
| return S_FALSE; |
| |
| switch (V_VT(&index)) |
| { |
| case VT_I2: |
| VariantChangeType(&index, &index, 0, VT_I4); |
| /* fall through */ |
| |
| case VT_I4: |
| if (V_I4(&index) >= This->item_count || V_I4(&index) < 0) |
| return S_FALSE; |
| |
| display_name = SysAllocString(This->item_names[V_I4(&index)]); |
| break; |
| |
| case VT_BSTR: |
| { |
| LPITEMIDLIST pidl; |
| STRRET strret; |
| |
| if (!V_BSTR(&index)) |
| return S_FALSE; |
| |
| if (FAILED(hr = IShellFolder2_ParseDisplayName(This->folder->folder, NULL, NULL, V_BSTR(&index), |
| NULL, &pidl, NULL))) |
| return S_FALSE; |
| |
| if (IShellFolder2_GetDisplayNameOf(This->folder->folder, pidl, SHGDN_FORPARSING, &strret) == S_OK) |
| StrRetToBSTR(&strret, pidl, &display_name); |
| ILFree(pidl); |
| break; |
| } |
| case VT_ERROR: |
| break; |
| |
| default: |
| FIXME("Index type %d not handled.\n", V_VT(&index)); |
| /* fall through */ |
| case VT_EMPTY: |
| return E_NOTIMPL; |
| } |
| |
| hr = FolderItem_Constructor(This->folder, display_name, item); |
| SysFreeString(display_name); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl__NewEnum(FolderItems3 *iface, IUnknown **ppunk) |
| { |
| FIXME("(%p,%p)\n", iface, ppunk); |
| |
| if (!ppunk) |
| return E_INVALIDARG; |
| |
| *ppunk = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_InvokeVerbEx(FolderItems3 *iface, VARIANT verb, VARIANT args) |
| { |
| FIXME("(%p,%s,%s)\n", iface, debugstr_variant(&verb), debugstr_variant(&args)); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_Filter(FolderItems3 *iface, LONG flags, BSTR spec) |
| { |
| FIXME("(%p,%d,%s)\n", iface, flags, wine_dbgstr_w(spec)); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderItemsImpl_get_Verbs(FolderItems3 *iface, FolderItemVerbs **ppfic) |
| { |
| FIXME("(%p,%p)\n", iface, ppfic); |
| |
| if (!ppfic) |
| return E_INVALIDARG; |
| |
| *ppfic = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static const FolderItems3Vtbl FolderItemsImpl_Vtbl = { |
| FolderItemsImpl_QueryInterface, |
| FolderItemsImpl_AddRef, |
| FolderItemsImpl_Release, |
| FolderItemsImpl_GetTypeInfoCount, |
| FolderItemsImpl_GetTypeInfo, |
| FolderItemsImpl_GetIDsOfNames, |
| FolderItemsImpl_Invoke, |
| FolderItemsImpl_get_Count, |
| FolderItemsImpl_get_Application, |
| FolderItemsImpl_get_Parent, |
| FolderItemsImpl_Item, |
| FolderItemsImpl__NewEnum, |
| FolderItemsImpl_InvokeVerbEx, |
| FolderItemsImpl_Filter, |
| FolderItemsImpl_get_Verbs |
| }; |
| |
| static void idlist_sort(LPITEMIDLIST *idlist, unsigned int l, unsigned int r, IShellFolder2 *folder) |
| { |
| unsigned int m; |
| |
| if (l == r) |
| return; |
| |
| if (r < l) |
| { |
| idlist_sort(idlist, r, l, folder); |
| return; |
| } |
| |
| m = (l + r) / 2; |
| idlist_sort(idlist, l, m, folder); |
| idlist_sort(idlist, m + 1, r, folder); |
| |
| /* join the two sides */ |
| while (l <= m && m < r) |
| { |
| if ((short)IShellFolder2_CompareIDs(folder, 0, idlist[l], idlist[m + 1]) > 0) |
| { |
| LPITEMIDLIST t = idlist[m + 1]; |
| memmove(&idlist[l + 1], &idlist[l], (m - l + 1) * sizeof(idlist[l])); |
| idlist[l] = t; |
| |
| m++; |
| } |
| l++; |
| } |
| } |
| |
| static HRESULT FolderItems_Constructor(FolderImpl *folder, FolderItems **ret) |
| { |
| IEnumIDList *enumidlist; |
| FolderItemsImpl *This; |
| LPITEMIDLIST pidl; |
| unsigned int i; |
| HRESULT hr; |
| |
| TRACE("(%s,%p)\n", debugstr_w(folder->path), ret); |
| |
| *ret = NULL; |
| |
| This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); |
| if (!This) |
| return E_OUTOFMEMORY; |
| |
| This->FolderItems3_iface.lpVtbl = &FolderItemsImpl_Vtbl; |
| This->ref = 1; |
| This->folder = folder; |
| Folder3_AddRef(&folder->Folder3_iface); |
| |
| enumidlist = NULL; |
| if (FAILED(hr = IShellFolder2_EnumObjects(folder->folder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, |
| &enumidlist))) |
| { |
| goto failed; |
| } |
| |
| while (IEnumIDList_Next(enumidlist, 1, &pidl, NULL) == S_OK) |
| { |
| This->item_count++; |
| ILFree(pidl); |
| } |
| |
| if (This->item_count) |
| { |
| LPITEMIDLIST *pidls; |
| ULONG fetched; |
| |
| pidls = HeapAlloc(GetProcessHeap(), 0, This->item_count * sizeof(*pidls)); |
| This->item_names = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->item_count * sizeof(*This->item_names)); |
| |
| if (!pidls || !This->item_names) |
| { |
| HeapFree(GetProcessHeap(), 0, pidls); |
| HeapFree(GetProcessHeap(), 0, This->item_names); |
| hr = E_OUTOFMEMORY; |
| goto failed; |
| } |
| |
| IEnumIDList_Reset(enumidlist); |
| if (IEnumIDList_Next(enumidlist, This->item_count, pidls, &fetched) == S_OK) |
| idlist_sort(pidls, 0, This->item_count - 1, folder->folder); |
| |
| for (i = 0; i < This->item_count; i++) |
| { |
| STRRET strret; |
| |
| if (IShellFolder2_GetDisplayNameOf(folder->folder, pidls[i], SHGDN_FORPARSING, &strret) == S_OK) |
| StrRetToBSTR(&strret, pidls[i], &This->item_names[i]); |
| |
| ILFree(pidls[i]); |
| } |
| HeapFree(GetProcessHeap(), 0, pidls); |
| } |
| IEnumIDList_Release(enumidlist); |
| |
| *ret = (FolderItems *)&This->FolderItems3_iface; |
| return S_OK; |
| |
| failed: |
| if (enumidlist) |
| IEnumIDList_Release(enumidlist); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderImpl_QueryInterface(Folder3 *iface, REFIID riid, |
| LPVOID *ppv) |
| { |
| FolderImpl *This = impl_from_Folder(iface); |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, riid) || |
| IsEqualIID(&IID_IDispatch, riid) || |
| IsEqualIID(&IID_Folder, riid) || |
| IsEqualIID(&IID_Folder2, riid) || |
| IsEqualIID(&IID_Folder3, riid)) |
| *ppv = &This->Folder3_iface; |
| else |
| { |
| WARN("not implemented for %s\n", debugstr_guid(riid)); |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| IUnknown_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI FolderImpl_AddRef(Folder3 *iface) |
| { |
| FolderImpl *This = impl_from_Folder(iface); |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI FolderImpl_Release(Folder3 *iface) |
| { |
| FolderImpl *This = impl_from_Folder(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| if (!ref) |
| { |
| ILFree(This->pidl); |
| SysFreeString(This->path); |
| IShellFolder2_Release(This->folder); |
| IDispatch_Release(This->application); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| return ref; |
| } |
| |
| static HRESULT WINAPI FolderImpl_GetTypeInfoCount(Folder3 *iface, UINT *pctinfo) |
| { |
| TRACE("(%p,%p)\n", iface, pctinfo); |
| |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderImpl_GetTypeInfo(Folder3 *iface, UINT iTInfo, |
| LCID lcid, ITypeInfo **ppTInfo) |
| { |
| HRESULT hr; |
| |
| TRACE("(%p,%u,%d,%p)\n", iface, iTInfo, lcid, ppTInfo); |
| |
| hr = get_typeinfo(Folder3_tid, ppTInfo); |
| if (SUCCEEDED(hr)) |
| ITypeInfo_AddRef(*ppTInfo); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderImpl_GetIDsOfNames(Folder3 *iface, REFIID riid, |
| LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) |
| { |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%s,%p,%u,%d,%p)\n", iface, shdebugstr_guid(riid), rgszNames, cNames, lcid, |
| rgDispId); |
| |
| hr = get_typeinfo(Folder3_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderImpl_Invoke(Folder3 *iface, DISPID dispIdMember, |
| REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, |
| VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) |
| { |
| FolderImpl *This = impl_from_Folder(iface); |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%d,%s,%d,%u,%p,%p,%p,%p)\n", iface, dispIdMember, shdebugstr_guid(riid), lcid, |
| wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(Folder3_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_Invoke(ti, This, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderImpl_get_Title(Folder3 *iface, BSTR *title) |
| { |
| FolderImpl *This = impl_from_Folder(iface); |
| PCUITEMID_CHILD last_part; |
| IShellFolder2 *parent; |
| SHELLDETAILS sd; |
| HRESULT hr; |
| |
| TRACE("(%p,%p)\n", iface, title); |
| |
| *title = NULL; |
| |
| if (FAILED(hr = SHBindToParent(This->pidl, &IID_IShellFolder2, (void **)&parent, &last_part))) |
| return hr; |
| |
| hr = IShellFolder2_GetDetailsOf(parent, last_part, 0, &sd); |
| IShellFolder2_Release(parent); |
| if (FAILED(hr)) |
| return hr; |
| |
| return StrRetToBSTR(&sd.str, last_part, title); |
| } |
| |
| static HRESULT WINAPI FolderImpl_get_Application(Folder3 *iface, IDispatch **disp) |
| { |
| FolderImpl *This = impl_from_Folder(iface); |
| |
| TRACE("(%p,%p)\n", iface, disp); |
| |
| if (!disp) |
| return E_INVALIDARG; |
| |
| *disp = This->application; |
| IDispatch_AddRef(*disp); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI FolderImpl_get_Parent(Folder3 *iface, IDispatch **disp) |
| { |
| TRACE("(%p,%p)\n", iface, disp); |
| |
| if (disp) |
| *disp = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_get_ParentFolder(Folder3 *iface, Folder **ppsf) |
| { |
| FIXME("(%p,%p)\n", iface, ppsf); |
| |
| *ppsf = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_Items(Folder3 *iface, FolderItems **ppid) |
| { |
| FolderImpl *This = impl_from_Folder(iface); |
| |
| TRACE("(%p,%p)\n", iface, ppid); |
| |
| return FolderItems_Constructor(This, ppid); |
| } |
| |
| static HRESULT WINAPI FolderImpl_ParseName(Folder3 *iface, BSTR name, FolderItem **item) |
| { |
| FolderImpl *This = impl_from_Folder(iface); |
| LPITEMIDLIST pidl; |
| STRRET strret; |
| HRESULT hr; |
| BSTR path; |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_w(name), item); |
| |
| *item = NULL; |
| |
| if (FAILED(IShellFolder2_ParseDisplayName(This->folder, NULL, NULL, name, NULL, &pidl, NULL))) |
| return S_FALSE; |
| |
| if ((hr = IShellFolder2_GetDisplayNameOf(This->folder, pidl, SHGDN_FORPARSING, &strret)) == S_OK) |
| hr = StrRetToBSTR(&strret, pidl, &path); |
| |
| ILFree(pidl); |
| if (hr != S_OK) |
| return S_FALSE; |
| |
| hr = FolderItem_Constructor(This, path, item); |
| SysFreeString(path); |
| return hr; |
| } |
| |
| static HRESULT WINAPI FolderImpl_NewFolder(Folder3 *iface, BSTR name, VARIANT options) |
| { |
| FIXME("(%p,%s,%s)\n", iface, debugstr_w(name), debugstr_variant(&options)); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_MoveHere(Folder3 *iface, VARIANT item, VARIANT options) |
| { |
| FIXME("(%p,%s,%s)\n", iface, debugstr_variant(&item), debugstr_variant(&options)); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_CopyHere(Folder3 *iface, VARIANT item, VARIANT options) |
| { |
| FIXME("(%p,%s,%s)\n", iface, debugstr_variant(&item), debugstr_variant(&options)); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_GetDetailsOf(Folder3 *iface, VARIANT item, int column, BSTR *str) |
| { |
| FIXME("(%p,%s,%d,%p)\n", iface, debugstr_variant(&item), column, str); |
| |
| *str = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_get_Self(Folder3 *iface, FolderItem **item) |
| { |
| FolderImpl *This = impl_from_Folder(iface); |
| |
| TRACE("(%p,%p)\n", iface, item); |
| |
| return FolderItem_Constructor(This, NULL, item); |
| } |
| |
| static HRESULT WINAPI FolderImpl_get_OfflineStatus(Folder3 *iface, LONG *pul) |
| { |
| FIXME("(%p,%p)\n", iface, pul); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_Synchronize(Folder3 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_get_HaveToShowWebViewBarricade(Folder3 *iface, |
| VARIANT_BOOL *pbHaveToShowWebViewBarricade) |
| { |
| FIXME("(%p,%p)\n", iface, pbHaveToShowWebViewBarricade); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_DismissedWebViewBarricade(Folder3 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_get_ShowWebViewBarricade(Folder3 *iface, |
| VARIANT_BOOL *pbShowWebViewBarricade) |
| { |
| FIXME("(%p,%p)\n", iface, pbShowWebViewBarricade); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI FolderImpl_put_ShowWebViewBarricade(Folder3 *iface, |
| VARIANT_BOOL bShowWebViewBarricade) |
| { |
| FIXME("(%p,%d)\n", iface, bShowWebViewBarricade); |
| |
| return E_NOTIMPL; |
| } |
| |
| static const Folder3Vtbl FolderImpl_Vtbl = { |
| FolderImpl_QueryInterface, |
| FolderImpl_AddRef, |
| FolderImpl_Release, |
| FolderImpl_GetTypeInfoCount, |
| FolderImpl_GetTypeInfo, |
| FolderImpl_GetIDsOfNames, |
| FolderImpl_Invoke, |
| FolderImpl_get_Title, |
| FolderImpl_get_Application, |
| FolderImpl_get_Parent, |
| FolderImpl_get_ParentFolder, |
| FolderImpl_Items, |
| FolderImpl_ParseName, |
| FolderImpl_NewFolder, |
| FolderImpl_MoveHere, |
| FolderImpl_CopyHere, |
| FolderImpl_GetDetailsOf, |
| FolderImpl_get_Self, |
| FolderImpl_get_OfflineStatus, |
| FolderImpl_Synchronize, |
| FolderImpl_get_HaveToShowWebViewBarricade, |
| FolderImpl_DismissedWebViewBarricade, |
| FolderImpl_get_ShowWebViewBarricade, |
| FolderImpl_put_ShowWebViewBarricade |
| }; |
| |
| static HRESULT Folder_Constructor(IShellFolder2 *folder, LPITEMIDLIST pidl, Folder **ret) |
| { |
| PCUITEMID_CHILD last_part; |
| IShellFolder2 *parent; |
| FolderImpl *This; |
| STRRET strret; |
| HRESULT hr; |
| |
| *ret = NULL; |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); |
| if (!This) |
| return E_OUTOFMEMORY; |
| |
| This->Folder3_iface.lpVtbl = &FolderImpl_Vtbl; |
| This->ref = 1; |
| This->folder = folder; |
| This->pidl = pidl; |
| |
| hr = SHBindToParent(pidl, &IID_IShellFolder2, (void **)&parent, &last_part); |
| IShellFolder2_GetDisplayNameOf(parent, last_part, SHGDN_FORPARSING, &strret); |
| StrRetToBSTR(&strret, last_part, &This->path); |
| IShellFolder2_Release(parent); |
| |
| IShellDispatch_Constructor(NULL, &IID_IDispatch, (void **)&This->application); |
| |
| *ret = (Folder *)&This->Folder3_iface; |
| return hr; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_QueryInterface(IShellDispatch6 *iface, |
| REFIID riid, LPVOID *ppv) |
| { |
| ShellDispatch *This = impl_from_IShellDispatch6(iface); |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, riid) || |
| IsEqualIID(&IID_IDispatch, riid) || |
| IsEqualIID(&IID_IShellDispatch, riid) || |
| IsEqualIID(&IID_IShellDispatch2, riid) || |
| IsEqualIID(&IID_IShellDispatch3, riid) || |
| IsEqualIID(&IID_IShellDispatch4, riid) || |
| IsEqualIID(&IID_IShellDispatch5, riid) || |
| IsEqualIID(&IID_IShellDispatch6, riid)) |
| *ppv = &This->IShellDispatch6_iface; |
| else |
| { |
| WARN("not implemented for %s\n", debugstr_guid(riid)); |
| *ppv = NULL; |
| return E_NOINTERFACE; |
| } |
| |
| IShellDispatch6_AddRef(iface); |
| return S_OK; |
| } |
| |
| static ULONG WINAPI ShellDispatch_AddRef(IShellDispatch6 *iface) |
| { |
| ShellDispatch *This = impl_from_IShellDispatch6(iface); |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI ShellDispatch_Release(IShellDispatch6 *iface) |
| { |
| ShellDispatch *This = impl_from_IShellDispatch6(iface); |
| ULONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| if (!ref) |
| HeapFree(GetProcessHeap(), 0, This); |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_GetTypeInfoCount(IShellDispatch6 *iface, |
| UINT *pctinfo) |
| { |
| TRACE("(%p,%p)\n", iface, pctinfo); |
| |
| *pctinfo = 1; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_GetTypeInfo(IShellDispatch6 *iface, |
| UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) |
| { |
| HRESULT hr; |
| |
| TRACE("(%p,%u,%d,%p)\n", iface, iTInfo, lcid, ppTInfo); |
| |
| hr = get_typeinfo(IShellDispatch6_tid, ppTInfo); |
| if (SUCCEEDED(hr)) |
| ITypeInfo_AddRef(*ppTInfo); |
| return hr; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_GetIDsOfNames(IShellDispatch6 *iface, |
| REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) |
| { |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%s,%p,%u,%d,%p)\n", iface, shdebugstr_guid(riid), rgszNames, cNames, lcid, |
| rgDispId); |
| |
| hr = get_typeinfo(IShellDispatch6_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId); |
| return hr; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_Invoke(IShellDispatch6 *iface, |
| DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, |
| DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, |
| UINT *puArgErr) |
| { |
| ShellDispatch *This = impl_from_IShellDispatch6(iface); |
| ITypeInfo *ti; |
| HRESULT hr; |
| |
| TRACE("(%p,%d,%s,%d,%u,%p,%p,%p,%p)\n", iface, dispIdMember, shdebugstr_guid(riid), lcid, |
| wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); |
| |
| hr = get_typeinfo(IShellDispatch6_tid, &ti); |
| if (SUCCEEDED(hr)) |
| hr = ITypeInfo_Invoke(ti, &This->IShellDispatch6_iface, dispIdMember, wFlags, pDispParams, |
| pVarResult, pExcepInfo, puArgErr); |
| return hr; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_get_Application(IShellDispatch6 *iface, IDispatch **disp) |
| { |
| TRACE("(%p,%p)\n", iface, disp); |
| |
| if (!disp) |
| return E_INVALIDARG; |
| |
| *disp = (IDispatch *)iface; |
| IDispatch_AddRef(*disp); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_get_Parent(IShellDispatch6 *iface, IDispatch **disp) |
| { |
| TRACE("(%p,%p)\n", iface, disp); |
| |
| if (disp) |
| { |
| *disp = (IDispatch *)iface; |
| IDispatch_AddRef(*disp); |
| } |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_NameSpace(IShellDispatch6 *iface, |
| VARIANT dir, Folder **ret) |
| { |
| IShellFolder2 *folder; |
| IShellFolder *desktop; |
| LPITEMIDLIST pidl; |
| HRESULT hr; |
| |
| TRACE("(%p,%s,%p)\n", iface, debugstr_variant(&dir), ret); |
| |
| *ret = NULL; |
| |
| switch (V_VT(&dir)) |
| { |
| case VT_I2: |
| if (FAILED(hr = VariantChangeType(&dir, &dir, 0, VT_I4))) |
| return hr; |
| |
| /* fallthrough */ |
| case VT_I4: |
| if (FAILED(hr = SHGetFolderLocation(NULL, V_I4(&dir), NULL, 0, &pidl))) |
| return S_FALSE; |
| |
| break; |
| case VT_BSTR: |
| if (FAILED(hr = SHParseDisplayName(V_BSTR(&dir), NULL, &pidl, 0, NULL))) |
| return S_FALSE; |
| |
| break; |
| default: |
| WARN("Ignoring directory value %s\n", debugstr_variant(&dir)); |
| return S_FALSE; |
| } |
| |
| if (FAILED(hr = SHGetDesktopFolder(&desktop))) |
| return hr; |
| |
| if (_ILIsDesktop(pidl)) |
| hr = IShellFolder_QueryInterface(desktop, &IID_IShellFolder2, (void **)&folder); |
| else |
| hr = IShellFolder_BindToObject(desktop, pidl, NULL, &IID_IShellFolder2, (void **)&folder); |
| |
| IShellFolder_Release(desktop); |
| |
| if (FAILED(hr)) |
| return S_FALSE; |
| |
| return Folder_Constructor(folder, pidl, ret); |
| } |
| |
| static HRESULT WINAPI ShellDispatch_BrowseForFolder(IShellDispatch6 *iface, |
| LONG Hwnd, BSTR Title, LONG Options, VARIANT RootFolder, Folder **ppsdf) |
| { |
| FIXME("(%p,%x,%s,%x,%s,%p)\n", iface, Hwnd, debugstr_w(Title), Options, debugstr_variant(&RootFolder), ppsdf); |
| |
| *ppsdf = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_Windows(IShellDispatch6 *iface, |
| IDispatch **ppid) |
| { |
| FIXME("(%p,%p)\n", iface, ppid); |
| |
| *ppid = NULL; |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_Open(IShellDispatch6 *iface, VARIANT dir) |
| { |
| FIXME("(%p,%s)\n", iface, debugstr_variant(&dir)); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_Explore(IShellDispatch6 *iface, VARIANT dir) |
| { |
| FIXME("(%p,%s)\n", iface, debugstr_variant(&dir)); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_MinimizeAll(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_UndoMinimizeALL(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_FileRun(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_CascadeWindows(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_TileVertically(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_TileHorizontally(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_ShutdownWindows(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_Suspend(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_EjectPC(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_SetTime(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_TrayProperties(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_Help(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_FindFiles(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_FindComputer(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_RefreshMenu(IShellDispatch6 *iface) |
| { |
| FIXME("(%p)\n", iface); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_ControlPanelItem(IShellDispatch6 *iface, |
| BSTR szDir) |
| { |
| FIXME("(%p,%s)\n", iface, debugstr_w(szDir)); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_IsRestricted(IShellDispatch6 *iface, BSTR group, BSTR restriction, LONG *value) |
| { |
| FIXME("(%s, %s, %p): stub\n", debugstr_w(group), debugstr_w(restriction), value); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_ShellExecute(IShellDispatch6 *iface, |
| BSTR file, VARIANT v_args, VARIANT v_dir, VARIANT v_op, VARIANT v_show) |
| { |
| VARIANT 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)); |
| |
| VariantInit(&args_str); |
| VariantChangeType(&args_str, &v_args, 0, VT_BSTR); |
| if (V_VT(&args_str) == VT_BSTR) |
| args = V_BSTR(&args_str); |
| |
| VariantInit(&dir_str); |
| VariantChangeType(&dir_str, &v_dir, 0, VT_BSTR); |
| if (V_VT(&dir_str) == VT_BSTR) |
| dir = V_BSTR(&dir_str); |
| |
| VariantInit(&op_str); |
| VariantChangeType(&op_str, &v_op, 0, VT_BSTR); |
| if (V_VT(&op_str) == VT_BSTR) |
| op = V_BSTR(&op_str); |
| |
| VariantInit(&show_int); |
| VariantChangeType(&show_int, &v_show, 0, VT_I4); |
| if (V_VT(&show_int) == VT_I4) |
| show = V_I4(&show_int); |
| |
| ret = ShellExecuteW(NULL, op, file, args, dir, show); |
| |
| VariantClear(&args_str); |
| VariantClear(&dir_str); |
| VariantClear(&op_str); |
| VariantClear(&show_int); |
| |
| return (ULONG_PTR)ret > 32 ? S_OK : S_FALSE; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_FindPrinter(IShellDispatch6 *iface, BSTR name, BSTR location, BSTR model) |
| { |
| FIXME("(%s, %s, %s): stub\n", debugstr_w(name), debugstr_w(location), debugstr_w(model)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_GetSystemInformation(IShellDispatch6 *iface, BSTR name, VARIANT *ret) |
| { |
| FIXME("(%s, %p): stub\n", debugstr_w(name), ret); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_ServiceStart(IShellDispatch6 *iface, BSTR service, VARIANT persistent, VARIANT *ret) |
| { |
| FIXME("(%s, %s, %p): stub\n", debugstr_w(service), debugstr_variant(&persistent), ret); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_ServiceStop(IShellDispatch6 *iface, BSTR service, VARIANT persistent, VARIANT *ret) |
| { |
| FIXME("(%s, %s, %p): stub\n", debugstr_w(service), debugstr_variant(&persistent), ret); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_IsServiceRunning(IShellDispatch6 *iface, BSTR name, VARIANT *running) |
| { |
| 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; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_CanStartStopService(IShellDispatch6 *iface, BSTR service, VARIANT *ret) |
| { |
| FIXME("(%s, %p): stub\n", debugstr_w(service), ret); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_ShowBrowserBar(IShellDispatch6 *iface, BSTR clsid, VARIANT show, VARIANT *ret) |
| { |
| FIXME("(%s, %s, %p): stub\n", debugstr_w(clsid), debugstr_variant(&show), ret); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_AddToRecent(IShellDispatch6 *iface, VARIANT file, BSTR category) |
| { |
| FIXME("(%s, %s): stub\n", debugstr_variant(&file), debugstr_w(category)); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_WindowsSecurity(IShellDispatch6 *iface) |
| { |
| FIXME("stub\n"); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_ToggleDesktop(IShellDispatch6 *iface) |
| { |
| FIXME("stub\n"); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_ExplorerPolicy(IShellDispatch6 *iface, BSTR policy, VARIANT *value) |
| { |
| FIXME("(%s, %p): stub\n", debugstr_w(policy), value); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_GetSetting(IShellDispatch6 *iface, LONG setting, VARIANT_BOOL *result) |
| { |
| FIXME("(%d %p): stub\n", setting, result); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_WindowSwitcher(IShellDispatch6 *iface) |
| { |
| FIXME("stub\n"); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellDispatch_SearchCommand(IShellDispatch6 *iface) |
| { |
| FIXME("stub\n"); |
| return E_NOTIMPL; |
| } |
| |
| static const IShellDispatch6Vtbl ShellDispatchVtbl = { |
| ShellDispatch_QueryInterface, |
| ShellDispatch_AddRef, |
| ShellDispatch_Release, |
| ShellDispatch_GetTypeInfoCount, |
| ShellDispatch_GetTypeInfo, |
| ShellDispatch_GetIDsOfNames, |
| ShellDispatch_Invoke, |
| ShellDispatch_get_Application, |
| ShellDispatch_get_Parent, |
| ShellDispatch_NameSpace, |
| ShellDispatch_BrowseForFolder, |
| ShellDispatch_Windows, |
| ShellDispatch_Open, |
| ShellDispatch_Explore, |
| ShellDispatch_MinimizeAll, |
| ShellDispatch_UndoMinimizeALL, |
| ShellDispatch_FileRun, |
| ShellDispatch_CascadeWindows, |
| ShellDispatch_TileVertically, |
| ShellDispatch_TileHorizontally, |
| ShellDispatch_ShutdownWindows, |
| ShellDispatch_Suspend, |
| ShellDispatch_EjectPC, |
| ShellDispatch_SetTime, |
| ShellDispatch_TrayProperties, |
| ShellDispatch_Help, |
| ShellDispatch_FindFiles, |
| ShellDispatch_FindComputer, |
| ShellDispatch_RefreshMenu, |
| ShellDispatch_ControlPanelItem, |
| ShellDispatch_IsRestricted, |
| ShellDispatch_ShellExecute, |
| ShellDispatch_FindPrinter, |
| ShellDispatch_GetSystemInformation, |
| ShellDispatch_ServiceStart, |
| ShellDispatch_ServiceStop, |
| ShellDispatch_IsServiceRunning, |
| ShellDispatch_CanStartStopService, |
| ShellDispatch_ShowBrowserBar, |
| ShellDispatch_AddToRecent, |
| ShellDispatch_WindowsSecurity, |
| ShellDispatch_ToggleDesktop, |
| ShellDispatch_ExplorerPolicy, |
| ShellDispatch_GetSetting, |
| ShellDispatch_WindowSwitcher, |
| ShellDispatch_SearchCommand |
| }; |
| |
| HRESULT WINAPI IShellDispatch_Constructor(IUnknown *outer, REFIID riid, void **ppv) |
| { |
| ShellDispatch *This; |
| HRESULT ret; |
| |
| TRACE("(%p, %s)\n", outer, debugstr_guid(riid)); |
| |
| *ppv = NULL; |
| |
| if (outer) return CLASS_E_NOAGGREGATION; |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(ShellDispatch)); |
| if (!This) return E_OUTOFMEMORY; |
| This->IShellDispatch6_iface.lpVtbl = &ShellDispatchVtbl; |
| This->ref = 1; |
| |
| ret = IShellDispatch6_QueryInterface(&This->IShellDispatch6_iface, riid, ppv); |
| IShellDispatch6_Release(&This->IShellDispatch6_iface); |
| return ret; |
| } |