Sync to Wine-0_9_3: Michael Jung mjung@iss.tu-darmstadt.de - Use the ANSI codepage in IShellFolder::GetDisplayNameOf. - Implemented scrolling during drag&drop for the shellview class. - Use GetUIObjectOf instead of BindToObject to get a IDropTarget object. - Register the shell view itself as the drop target, not it's parent folder. Forward drag&drop method calls to the folder currently under the cursor. - Initialize OLE instead of just COM, in order to enable Drag & Drop. - Modified KeyStateToDropEffect macro to match native shellview's behaviour. - Also scan HKEY_CURRENT_USER for shell namespace extensions in Desktop folder. Fixed a handle leak in case of failing AddToEnumList call. - Also scan HKEY_CURRENT_USER for shell namespace extensions in MyComputer. - Enhanced UnixFolder's IDropTarget implementation. Use STATIC_CAST macro more consistently. - Initial stubbed implementation of UnixFolder's IDropTarget interface. Francois Gouget fgouget@free.fr - Assorted spelling fixes. Ge van Geldorp gvg@reactos.org - Load shortcut icon by resource id instead of by icon index. - Other code in shlexec.c (e.g. the extension handling code in ShellExecute_GetClassKey) expects sei->lpFile to not be enclosed in quotes. Martin Fuchs martin-fuchs@gmx.net - Correctly call HCR_GetFolderAttributes() in SHELL32_GetItemAttributes(). Directly return the correct "My Computer" attributes in ISF_Desktop_fnGetAttributesOf(). Remove "todo_wine" from the "My Computer" attributes test case. Add test case for retrieving the file system path from the CSIDL_PROGRAM_FILES PIDL using SHGetPathFromIDListW(). - Fix context menu handling for more than one entry in order to repair .lnk-file execution: Don't break at the first non-matching entry. Markus Gömmel m.goemmel@compulab.de - Added CSIDL_MYVIDEO|MYPICTURES|MYMUSIC to _SHRegisterUserShellFolders. Modified: trunk/reactos/lib/shell32/iconcache.c Modified: trunk/reactos/lib/shell32/shell32_main.h Modified: trunk/reactos/lib/shell32/shellpath.c Modified: trunk/reactos/lib/shell32/shfldr_desktop.c Modified: trunk/reactos/lib/shell32/shlexec.c Modified: trunk/reactos/lib/shell32/shlview.c _____
Modified: trunk/reactos/lib/shell32/iconcache.c --- trunk/reactos/lib/shell32/iconcache.c 2005-12-14 19:02:42 UTC (rev 20167) +++ trunk/reactos/lib/shell32/iconcache.c 2005-12-14 19:09:44 UTC (rev 20168) @@ -129,7 +129,10 @@
/* search for the shortcut icon only once */ if (s_imgListIdx == -1) - s_imgListIdx = SIC_LoadOverlayIcon(-IDI_SHELL_SHORTCUT); + s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT); + /* FIXME should use icon index 29 instead of the + resource id, but not all icons are present yet + so we can't use icon indices */
if (s_imgListIdx != -1) { _____
Modified: trunk/reactos/lib/shell32/shell32_main.h --- trunk/reactos/lib/shell32/shell32_main.h 2005-12-14 19:02:42 UTC (rev 20167) +++ trunk/reactos/lib/shell32/shell32_main.h 2005-12-14 19:09:44 UTC (rev 20168) @@ -121,9 +121,9 @@
};
#define KeyStateToDropEffect(kst)\ - (((kst) & MK_CONTROL) ?\ - (((kst) & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY):\ - DROPEFFECT_MOVE) + ((((kst)&(MK_CONTROL|MK_SHIFT))==(MK_CONTROL|MK_SHIFT)) ? DROPEFFECT_LINK :\ + (((kst)&(MK_CONTROL|MK_SHIFT)) ? DROPEFFECT_COPY :\ + DROPEFFECT_MOVE))
HGLOBAL RenderHDROP(LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl); HGLOBAL RenderSHELLIDLIST (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl); _____
Modified: trunk/reactos/lib/shell32/shellpath.c --- trunk/reactos/lib/shell32/shellpath.c 2005-12-14 19:02:42 UTC (rev 20167) +++ trunk/reactos/lib/shell32/shellpath.c 2005-12-14 19:09:44 UTC (rev 20168) @@ -1808,12 +1808,15 @@
CSIDL_RECENT, CSIDL_SENDTO, CSIDL_STARTMENU, + CSIDL_MYMUSIC, + CSIDL_MYVIDEO, CSIDL_DESKTOPDIRECTORY, CSIDL_NETHOOD, CSIDL_TEMPLATES, CSIDL_PRINTHOOD, CSIDL_COOKIES, CSIDL_HISTORY, + CSIDL_MYPICTURES }; WCHAR userShellFolderPath[MAX_PATH], shellFolderPath[MAX_PATH]; LPCWSTR pUserShellFolderPath, pShellFolderPath; _____
Modified: trunk/reactos/lib/shell32/shfldr_desktop.c --- trunk/reactos/lib/shell32/shfldr_desktop.c 2005-12-14 19:02:42 UTC (rev 20167) +++ trunk/reactos/lib/shell32/shfldr_desktop.c 2005-12-14 19:09:44 UTC (rev 20168) @@ -428,6 +428,9 @@
static const DWORD dwDesktopAttributes = SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER; + static const DWORD dwMyComputerAttributes = + SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | + SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08lx))\n", This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0); @@ -447,6 +450,8 @@ pdump (*apidl); if (_ILIsDesktop(*apidl)) { *rgfInOut &= dwDesktopAttributes; + } else if (_ILIsMyComputer(*apidl)) { + *rgfInOut &= dwMyComputerAttributes; } else { SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut); } _____
Modified: trunk/reactos/lib/shell32/shlexec.c --- trunk/reactos/lib/shell32/shlexec.c 2005-12-14 19:02:42 UTC (rev 20167) +++ trunk/reactos/lib/shell32/shlexec.c 2005-12-14 19:09:44 UTC (rev 20168) @@ -1156,15 +1156,15 @@
r = RegEnumKeyW( hkeycm, i++, szguid, 39 ); if ( r != ERROR_SUCCESS ) break; - r = ERROR_FUNCTION_FAILED; + hr = CLSIDFromString( szguid, &guid ); - if ( FAILED( hr ) ) - break; - r = ERROR_SUCCESS; - /* stop at the first one that succeeds in running */ - hr = shellex_load_object_and_run( hkey, &guid, sei ); - if ( SUCCEEDED( hr ) ) - break; + if (SUCCEEDED(hr)) + { + /* stop at the first one that succeeds in running */ + hr = shellex_load_object_and_run( hkey, &guid, sei ); + if ( SUCCEEDED( hr ) ) + break; + } } RegCloseKey( hkeycm ); } _____
Modified: trunk/reactos/lib/shell32/shlview.c --- trunk/reactos/lib/shell32/shlview.c 2005-12-14 19:02:42 UTC (rev 20167) +++ trunk/reactos/lib/shell32/shlview.c 2005-12-14 19:09:44 UTC (rev 20168) @@ -100,6 +100,10 @@
DWORD dwAspects; DWORD dwAdvf; IAdviseSink *pAdvSink; + IDropTarget* pCurDropTarget; /* The sub-item, which is currently dragged over */ + IDataObject* pCurDataObject; /* The dragged data-object */ + LONG iDragOverItem; /* Dragged over item's index, iff pCurDropTarget != NULL */ + UINT iActiveTimersMask; /* Bookkeeping of activated timers for drag scrolling */ } IShellViewImpl;
static const IShellViewVtbl svvt; @@ -190,6 +194,11 @@ if(pFolder) IShellFolder_AddRef(pFolder); IShellFolder_QueryInterface(sv->pSFParent, &IID_IShellFolder2, (LPVOID*)&sv->pSF2Parent);
+ sv->pCurDropTarget = NULL; + sv->pCurDataObject = NULL; + sv->iDragOverItem = 0; + sv->iActiveTimersMask = 0; + TRACE("(%p)->(%p)\n",sv, pFolder); return (IShellView *) sv; } @@ -671,7 +680,7 @@ } }
- if (SUCCEEDED(IShellFolder_CreateViewObject(This->pSFParent, This->hWnd, &IID_IDropTarget, (LPVOID*)&pdt))) + if (SUCCEEDED(IUnknown_QueryInterface((IUnknown*)&This->lpVtbl, &IID_IDropTarget, (LPVOID*)&pdt))) { RegisterDragDrop(This->hWnd, pdt); IDropTarget_Release(pdt); @@ -2169,56 +2178,176 @@ return IShellFolder_Release((IShellFolder*)This); }
-static HRESULT WINAPI ISVDropTarget_DragEnter( - IDropTarget *iface, - IDataObject *pDataObject, - DWORD grfKeyState, - POINTL pt, - DWORD *pdwEffect) +/********************************************************************** ******** + * scroll_timer_proc [Internal] + * + * Timer callback function for drag&drop scrolling + */ + +#define IDT_UP 0x1u +#define IDT_DOWN 0x2u +#define IDT_LEFT 0x4u +#define IDT_RIGHT 0x8u + +VOID CALLBACK scroll_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idTimer, DWORD dwTimer) { + switch (idTimer) { + case IDT_UP: + SendMessageW(hwnd, WM_VSCROLL, SB_LINEUP, 0); + break; + case IDT_DOWN: + SendMessageW(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); + break; + case IDT_LEFT: + SendMessageW(hwnd, WM_HSCROLL, SB_LINEUP, 0); + break; + case IDT_RIGHT: + SendMessageW(hwnd, WM_HSCROLL, SB_LINEDOWN, 0); + break; + } +} + +/********************************************************************** ******** + * start_stop_timer [Internal] + */ +static inline void start_stop_timer(IShellViewImpl *This, UINT_PTR idTimer, BOOL fStart) { + if (fStart && !(This->iActiveTimersMask & idTimer)) { + SetTimer(This->hWndList, idTimer, 200, scroll_timer_proc); + This->iActiveTimersMask |= idTimer; + } + if (!fStart && This->iActiveTimersMask & idTimer) { + KillTimer(This->hWndList, idTimer); + This->iActiveTimersMask &= ~idTimer; + } +} + +/********************************************************************** ******** + * drag_notify_subitem [Internal] + * + * Figure out the shellfolder object, which is currently under the mouse cursor + * and notify it via the IDropTarget interface. + */ + +#define SCROLLAREAWIDTH 20 + +static HRESULT drag_notify_subitem(IShellViewImpl *This, DWORD grfKeyState, POINTL pt, + DWORD *pdwEffect) { + LVHITTESTINFO htinfo; + LVITEMA lvItem; + LONG lResult; + HRESULT hr; + RECT clientRect;
- IShellViewImpl *This = impl_from_IDropTarget(iface); + /* Map from global to client coordinates and query the index of the listview-item, which is + * currently under the mouse cursor. */ + htinfo.pt.x = pt.x; + htinfo.pt.y = pt.y; + htinfo.flags = LVHT_ONITEM; + ScreenToClient(This->hWndList, &htinfo.pt); + lResult = SendMessageW(This->hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
- FIXME("Stub: This=%p, DataObject=%p\n",This,pDataObject); + /* Start or stop the drag scrolling timers */ + GetClientRect(This->hWndList, &clientRect); + start_stop_timer(This, IDT_LEFT, htinfo.pt.x < SCROLLAREAWIDTH); + start_stop_timer(This, IDT_RIGHT, htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH); + start_stop_timer(This, IDT_UP, htinfo.pt.y < SCROLLAREAWIDTH); + start_stop_timer(This, IDT_DOWN, htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH);
- return E_NOTIMPL; + /* If we are still over the previous sub-item, notify it via DragOver and return. */ + if (This->pCurDropTarget && lResult == This->iDragOverItem) + return IDropTarget_DragOver(This->pCurDropTarget, grfKeyState, pt, pdwEffect); + + /* We've left the previous sub-item, notify it via DragLeave and Release it. */ + if (This->pCurDropTarget) { + IDropTarget_DragLeave(This->pCurDropTarget); + IDropTarget_Release(This->pCurDropTarget); + This->pCurDropTarget = NULL; + } + + This->iDragOverItem = lResult; + if (lResult == -1) { + /* We are not above one of the listview's subitems. Bind to the parent folder's + * DropTarget interface. */ + hr = IShellFolder_QueryInterface(This->pSFParent, &IID_IDropTarget, + (LPVOID*)&This->pCurDropTarget); + } else { + /* Query the relative PIDL of the shellfolder object represented by the currently + * dragged over listview-item ... */ + ZeroMemory(&lvItem, sizeof(lvItem)); + lvItem.mask = LVIF_PARAM; + lvItem.iItem = lResult; + ListView_GetItemA(This->hWndList, &lvItem); + + /* ... and bind pCurDropTarget to the IDropTarget interface of an UIObject of this object */ + hr = IShellFolder_GetUIObjectOf(This->pSFParent, This->hWndList, 1, + (LPCITEMIDLIST*)&lvItem.lParam, &IID_IDropTarget, NULL, (LPVOID*)&This->pCurDropTarget); + } + + /* If anything failed, pCurDropTarget should be NULL now, which ought to be a save state. */ + if (FAILED(hr)) + return hr; + + /* Notify the item just entered via DragEnter. */ + return IDropTarget_DragEnter(This->pCurDropTarget, This->pCurDataObject, grfKeyState, pt, pdwEffect); }
-static HRESULT WINAPI ISVDropTarget_DragOver( - IDropTarget *iface, - DWORD grfKeyState, - POINTL pt, - DWORD *pdwEffect) +static HRESULT WINAPI ISVDropTarget_DragEnter(IDropTarget *iface, IDataObject *pDataObject, + DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { - IShellViewImpl *This = impl_from_IDropTarget(iface); + IShellViewImpl *This = impl_from_IDropTarget(iface);
- FIXME("Stub: This=%p\n",This); + /* Get a hold on the data object for later calls to DragEnter on the sub-folders */ + This->pCurDataObject = pDataObject; + IDataObject_AddRef(pDataObject);
- return E_NOTIMPL; + return drag_notify_subitem(This, grfKeyState, pt, pdwEffect); }
-static HRESULT WINAPI ISVDropTarget_DragLeave( - IDropTarget *iface) +static HRESULT WINAPI ISVDropTarget_DragOver(IDropTarget *iface, DWORD grfKeyState, POINTL pt, + DWORD *pdwEffect) { - IShellViewImpl *This = impl_from_IDropTarget(iface); + IShellViewImpl *This = impl_from_IDropTarget(iface); + return drag_notify_subitem(This, grfKeyState, pt, pdwEffect); +}
- FIXME("Stub: This=%p\n",This); +static HRESULT WINAPI ISVDropTarget_DragLeave(IDropTarget *iface) { + IShellViewImpl *This = impl_from_IDropTarget(iface);
- return E_NOTIMPL; + IDropTarget_DragLeave(This->pCurDropTarget); + + IDropTarget_Release(This->pCurDropTarget); + IDataObject_Release(This->pCurDataObject); + This->pCurDataObject = NULL; + This->pCurDropTarget = NULL; + This->iDragOverItem = 0; + + start_stop_timer(This, IDT_LEFT, FALSE); + start_stop_timer(This, IDT_RIGHT, FALSE); + start_stop_timer(This, IDT_UP, FALSE); + start_stop_timer(This, IDT_DOWN, FALSE); + + return S_OK; }
-static HRESULT WINAPI ISVDropTarget_Drop( - IDropTarget *iface, - IDataObject* pDataObject, - DWORD grfKeyState, - POINTL pt, - DWORD *pdwEffect) +static HRESULT WINAPI ISVDropTarget_Drop(IDropTarget *iface, IDataObject* pDataObject, + DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { - IShellViewImpl *This = impl_from_IDropTarget(iface); + IShellViewImpl *This = impl_from_IDropTarget(iface);
- FIXME("Stub: This=%p\n",This); + IDropTarget_Drop(This->pCurDropTarget, pDataObject, grfKeyState, pt, pdwEffect);
- return E_NOTIMPL; + IDropTarget_Release(This->pCurDropTarget); + IDataObject_Release(This->pCurDataObject); + This->pCurDataObject = NULL; + This->pCurDropTarget = NULL; + This->iDragOverItem = 0; + + start_stop_timer(This, IDT_LEFT, FALSE); + start_stop_timer(This, IDT_RIGHT, FALSE); + start_stop_timer(This, IDT_UP, FALSE); + start_stop_timer(This, IDT_DOWN, FALSE); + + return S_OK; }
static const IDropTargetVtbl dtvt =