From 38bee199b726a21dba2b488ecab1431c2fc2124c Mon Sep 17 00:00:00 2001 From: Pablo Borobia Date: Wed, 30 Aug 2006 19:35:54 +0000 Subject: [PATCH] shel32.dll part: * Clipboard implemtation in win32k and user32 * Added a clipboard system for each Window Station * GetLastInputInfo implementation * GetLayout in win32k Stubs * Shell32 changes to cut/copy & paste link/paste * Implemented ALT+PrintScreen to clipboard svn path=/trunk/; revision=23811 --- reactos/dll/win32/shell32/shell32_main.h | 2 + reactos/dll/win32/shell32/shfldr_fs.c | 53 ++++- reactos/dll/win32/shell32/shlfileop.c | 81 +++++++ reactos/dll/win32/shell32/shv_bg_cmenu.c | 251 ++++++++++++++++++--- reactos/dll/win32/shell32/shv_item_cmenu.c | 11 +- 5 files changed, 355 insertions(+), 43 deletions(-) diff --git a/reactos/dll/win32/shell32/shell32_main.h b/reactos/dll/win32/shell32/shell32_main.h index 3d8be2542fc..49ad4f24856 100644 --- a/reactos/dll/win32/shell32/shell32_main.h +++ b/reactos/dll/win32/shell32/shell32_main.h @@ -148,6 +148,8 @@ void FreeChangeNotifications(void); BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI); BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI); BOOL SHELL_ConfirmDialog(int nKindOfDialog, LPCSTR szDir); +DWORD SHNotifyMoveFileA(LPCSTR src, LPCSTR dest); +DWORD SHNotifyCopyFileA(LPCSTR src, LPCSTR dest, BOOL bFailIfExists); /* 16-bit functions */ void WINAPI DragAcceptFiles16(HWND16 hWnd, BOOL16 b); diff --git a/reactos/dll/win32/shell32/shfldr_fs.c b/reactos/dll/win32/shell32/shfldr_fs.c index 53d823147e9..6d57372cd5b 100644 --- a/reactos/dll/win32/shell32/shfldr_fs.c +++ b/reactos/dll/win32/shell32/shfldr_fs.c @@ -1154,6 +1154,8 @@ ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCSTR lpName, return hres; } +extern BOOL fileMoving; + /**************************************************************************** * ISFHelper_fnDeleteItems * @@ -1168,7 +1170,7 @@ ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl) BOOL bConfirm = TRUE; TRACE ("(%p)(%u %p)\n", This, cidl, apidl); - + /* deleting multiple items so give a slightly different warning */ if (cidl != 1) { char tmp[8]; @@ -1178,7 +1180,7 @@ ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl) return E_FAIL; bConfirm = FALSE; } - + for (i = 0; i < cidl; i++) { strcpy (szPath, This->sPathTarget); PathAddBackslashA (szPath); @@ -1236,7 +1238,8 @@ ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl, LPITEMIDLIST pidl; if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl))) { - for (i = 0; i < cidl; i++) { + for (i = 0; i < cidl; i++) + { SHGetPathFromIDListA (pidl, szSrcPath); PathAddBackslashA (szSrcPath); _ILSimpleGetText (apidl[i], szSrcPath + strlen (szSrcPath), @@ -1244,9 +1247,43 @@ ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl, strcpy (szDstPath, This->sPathTarget); PathAddBackslashA (szDstPath); - _ILSimpleGetText (apidl[i], szDstPath + strlen (szDstPath), - MAX_PATH); - MESSAGE ("would copy %s to %s\n", szSrcPath, szDstPath); + _ILSimpleGetText (apidl[i], szDstPath + strlen (szDstPath), MAX_PATH); + DPRINT1 ("copy %s to %s\n", szSrcPath, szDstPath); + + if (fileMoving) + { + fileMoving = FALSE; + SHNotifyMoveFileA(szSrcPath, szDstPath); + } + else + { + SHNotifyCopyFileA(szSrcPath, szDstPath, TRUE); + } + + /* + SHFILEOPSTRUCTA op; + + if (fileMoving) + { + op.wFunc = FO_MOVE; + fileMoving = FALSE; + } + else + { + op.wFunc = FO_COPY; + } + + op.pTo = szDstPath; + op.pFrom = szSrcPath; + op.fFlags = FOF_SIMPLEPROGRESS; + op.hwnd = NULL; + op.hNameMappings = NULL; + op.lpszProgressTitle = NULL; + + UINT bRes = SHFileOperationA(&op); + DbgPrint("CopyItems SHFileOperationA 0x%08x\n", bRes); + */ + } SHFree (pidl); } @@ -1558,9 +1595,11 @@ static HRESULT WINAPI ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject, DWORD dwKeyState, POINTL pt, DWORD * pdwEffect) { + DWORD dwEffect = *pdwEffect; + IGenericSFImpl *This = impl_from_IDropTarget(iface); - FIXME ("(%p) object dropped\n", This); + FIXME ("(%p) object dropped(%d)\n", This, dwKeyState); return E_NOTIMPL; } diff --git a/reactos/dll/win32/shell32/shlfileop.c b/reactos/dll/win32/shell32/shlfileop.c index b6139b8696e..46ac0fe7130 100644 --- a/reactos/dll/win32/shell32/shlfileop.c +++ b/reactos/dll/win32/shell32/shlfileop.c @@ -478,6 +478,65 @@ static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists) return GetLastError(); } +DWORD SHNotifyMoveFileA(LPCSTR src, LPCSTR dest) +{ + BOOL ret; + LPWSTR destW; + + ret = MoveFileA(src, dest); + if (!ret) + { + DWORD dwAttr; + + SHELL32_AnsiToUnicodeBuf(dest, &destW, 0); + dwAttr = SHFindAttrW(destW, FALSE); + SHELL32_FreeUnicodeBuf(destW); + if (INVALID_FILE_ATTRIBUTES == dwAttr) + { + /* Source file may be write protected or a system file */ + dwAttr = GetFileAttributesA(src); + if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)) + if (SetFileAttributesA(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))) + ret = MoveFileA(src, dest); + } + } + if (ret) + { + //SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATHA, src, dest); + SHChangeNotify(SHCNE_CREATE, SHCNF_PATHA, dest, NULL); + SHChangeNotify(SHCNE_DELETE, SHCNF_PATHA, src, NULL); + return ERROR_SUCCESS; + } + return GetLastError(); +} + +/************************************************************************ + * SHNotifyCopyFile [internal] + * + * Copies a file. Also triggers a change notify if one exists. + * + * PARAMS + * src [I] path to source file to move + * dest [I] path to target file to move to + * bFailIfExists [I] if TRUE, the target file will not be overwritten if + * a file with this name already exists + * + * RETURNS + * ERROR_SUCCESS if successful + */ +DWORD SHNotifyCopyFileA(LPCSTR src, LPCSTR dest, BOOL bFailIfExists) +{ + BOOL ret; + + ret = CopyFileA(src, dest, bFailIfExists); + if (ret) + { + SHChangeNotify(SHCNE_CREATE, SHCNF_PATHA, dest, NULL); + return ERROR_SUCCESS; + } + return GetLastError(); +} + /************************************************************************* * SHCreateDirectory [SHELL32.165] * @@ -649,7 +708,29 @@ static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly) } return dwAttr; } +/* +DWORD SHFindAttrA(LPSTR pName, BOOL fileOnly) +{ + WIN32_FIND_DATAA wfd; + BOOL b_FileMask = fileOnly && (NULL != StrPBrkA(pName, wWildcardChars)); + DWORD dwAttr = INVALID_FILE_ATTRIBUTES; + HANDLE hFind = FindFirstFileA(pName, &wfd); + if (INVALID_HANDLE_VALUE != hFind) + { + do + { + if (b_FileMask && IsAttribDir(wfd.dwFileAttributes)) + continue; + dwAttr = wfd.dwFileAttributes; + break; + } + while (FindNextFileA(hFind, &wfd)); + FindClose(hFind); + } + return dwAttr; +} +*/ /************************************************************************* * * SHFileStrICmp HelperFunction for SHFileOperationW diff --git a/reactos/dll/win32/shell32/shv_bg_cmenu.c b/reactos/dll/win32/shell32/shv_bg_cmenu.c index 669d080156e..f83622113f2 100644 --- a/reactos/dll/win32/shell32/shv_bg_cmenu.c +++ b/reactos/dll/win32/shell32/shv_bg_cmenu.c @@ -38,6 +38,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); +extern BOOL fileMoving; + /************************************************************************** * IContextMenu Implementation */ @@ -215,6 +217,198 @@ static void DoNewFolder( } } +/***************************************************************************/ +static BOOL DoLink(LPCSTR pSrcFile, LPCSTR pDstFile) +{ + IShellLinkA *psl = NULL; + IPersistFile *pPf = NULL; + HRESULT hres; + WCHAR widelink[MAX_PATH]; + BOOL ret = FALSE; + + CoInitialize(0); + + hres = CoCreateInstance( &CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IShellLinkA, + (LPVOID )&psl); + + if(SUCCEEDED(hres)) { + + hres = IShellLinkA_QueryInterface(psl, &IID_IPersistFile, + (LPVOID *)&pPf); + if(FAILED(hres)) + { + ERR("failed QueryInterface for IPersistFile %08lx\n", hres); + goto fail; + } + + DPRINT1("shortcut point to %s\n", pSrcFile); + + hres = IShellLinkA_SetPath(psl, pSrcFile); + + if(FAILED(hres)) + { + ERR("failed Set{IDList|Path} %08lx\n", hres); + goto fail; + } + + MultiByteToWideChar(CP_ACP, 0, pDstFile, -1, + widelink, MAX_PATH); + + /* create the short cut */ + hres = IPersistFile_Save(pPf, widelink, TRUE); + + if(FAILED(hres)) + { + ERR("failed IPersistFile::Save %08lx\n", hres); + IPersistFile_Release(pPf); + IShellLinkA_Release(psl); + goto fail; + } + + hres = IPersistFile_SaveCompleted(pPf, widelink); + IPersistFile_Release(pPf); + IShellLinkA_Release(psl); + DPRINT1("shortcut %s has been created, result=%08lx\n", + pDstFile, hres); + ret = TRUE; + } + else { + DPRINT1("CoCreateInstance failed, hres=%08lx\n", hres); + } + + fail: + CoUninitialize(); + return ret; +} + +static BOOL MakeLink( + IContextMenu2 *iface) +{ + BgCmImpl *This = (BgCmImpl *)iface; + BOOL bSuccess = FALSE; + IDataObject * pda; + + TRACE("\n"); + + if(SUCCEEDED(OleGetClipboard(&pda))) + { + STGMEDIUM medium; + FORMATETC formatetc; + + TRACE("pda=%p\n", pda); + + /* Set the FORMATETC structure*/ + InitFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL); + + /* Get the pidls from IDataObject */ + if(SUCCEEDED(IDataObject_GetData(pda, &formatetc, &medium))) + { + LPITEMIDLIST * apidl; + LPITEMIDLIST pidl; + IShellFolder *psfFrom = NULL, *psfDesktop; + + LPIDA lpcida = GlobalLock(medium.u.hGlobal); + TRACE("cida=%p\n", lpcida); + + apidl = _ILCopyCidaToaPidl(&pidl, lpcida); + + /* bind to the source shellfolder */ + SHGetDesktopFolder(&psfDesktop); + if(psfDesktop) + { + IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom); + IShellFolder_Release(psfDesktop); + } + + if (psfFrom) + { + /* get source and destination shellfolder */ + IPersistFolder2 *ppfdst = NULL; + IPersistFolder2 *ppfsrc = NULL; + IShellFolder_QueryInterface(This->pSFParent, &IID_IPersistFolder2, (LPVOID*)&ppfdst); + IShellFolder_QueryInterface(psfFrom, &IID_IPersistFolder2, (LPVOID*)&ppfsrc); + + + DPRINT1("[%p,%p]\n",ppfdst,ppfsrc); + + /* do the link/s */ + /* hack to get desktop path */ + if ( (ppfdst && ppfsrc) || (This->bDesktop && ppfsrc) ) + { + + int i; + char szSrcPath[MAX_PATH]; + char szDstPath[MAX_PATH]; + BOOL ret = FALSE; + LPITEMIDLIST pidl2; + char filename[MAX_PATH]; + char linkFilename[MAX_PATH]; + char srcFilename[MAX_PATH]; + + DbgPrint("&&&"); + IPersistFolder2_GetCurFolder(ppfsrc, &pidl2); + SHGetPathFromIDListA (pidl2, szSrcPath); + + if (This->bDesktop) + { + SHGetSpecialFolderLocation(0, CSIDL_DESKTOPDIRECTORY, &pidl2); + SHGetPathFromIDListA (pidl2, szDstPath); + } + else + { + IPersistFolder2_GetCurFolder(ppfdst, &pidl2); + SHGetPathFromIDListA (pidl2, szDstPath); + } + + + for (i = 0; i < lpcida->cidl; i++) + { + _ILSimpleGetText (apidl[i], filename, MAX_PATH); + + DbgPrint("filename %s\n", filename); + + lstrcpyA(linkFilename, szDstPath); + PathAddBackslashA(linkFilename); + //lstrcatA(linkFilename, "Shortcut to "); + lstrcatA(linkFilename, filename); + lstrcatA(linkFilename, ".lnk"); + + DbgPrint("linkFilename %s\n", linkFilename); + + lstrcpyA(srcFilename, szSrcPath); + PathAddBackslashA(srcFilename); + lstrcatA(srcFilename, filename); + + DbgPrint("srcFilename %s\n", srcFilename); + + ret = DoLink(srcFilename, linkFilename); + + if (ret) + { + SHChangeNotify(SHCNE_CREATE, SHCNF_PATHA, linkFilename, NULL); + } + } + + } + if(ppfdst) IPersistFolder2_Release(ppfdst); + if(ppfsrc) IPersistFolder2_Release(ppfsrc); + IShellFolder_Release(psfFrom); + } + + _ILFreeaPidl(apidl, lpcida->cidl); + SHFree(pidl); + + /* release the medium*/ + ReleaseStgMedium(&medium); + } + IDataObject_Release(pda); + } + return bSuccess; + +} /************************************************************************** * DoPaste */ @@ -226,19 +420,19 @@ static BOOL DoPaste( IDataObject * pda; TRACE("\n"); - + if(SUCCEEDED(OleGetClipboard(&pda))) { STGMEDIUM medium; FORMATETC formatetc; TRACE("pda=%p\n", pda); - + /* Set the FORMATETC structure*/ InitFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL); /* Get the pidls from IDataObject */ - if(SUCCEEDED(IDataObject_GetData(pda,&formatetc,&medium))) + if(SUCCEEDED(IDataObject_GetData(pda, &formatetc, &medium))) { LPITEMIDLIST * apidl; LPITEMIDLIST pidl; @@ -248,7 +442,7 @@ static BOOL DoPaste( TRACE("cida=%p\n", lpcida); apidl = _ILCopyCidaToaPidl(&pidl, lpcida); - + /* bind to the source shellfolder */ SHGetDesktopFolder(&psfDesktop); if(psfDesktop) @@ -261,17 +455,28 @@ static BOOL DoPaste( { /* get source and destination shellfolder */ ISFHelper *psfhlpdst, *psfhlpsrc; - IShellFolder_QueryInterface(This->pSFParent, &IID_ISFHelper, (LPVOID*)&psfhlpdst); + if (This->bDesktop) + { + /* unimplemented*/ + SHGetDesktopFolder(&psfDesktop); + IFSFolder_Constructor(psfDesktop, &IID_ISFHelper, (LPVOID*)&psfhlpdst); + IShellFolder_QueryInterface(psfhlpdst, &IID_ISFHelper, (LPVOID*)&psfhlpdst); + } + else + { + IShellFolder_QueryInterface(This->pSFParent, &IID_ISFHelper, (LPVOID*)&psfhlpdst); + } + IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (LPVOID*)&psfhlpsrc); - + + DPRINT1("[%p,%p]\n",psfhlpdst,psfhlpsrc); + /* do the copy/move */ if (psfhlpdst && psfhlpsrc) { ISFHelper_CopyItems(psfhlpdst, psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl); - /* FIXME handle move - ISFHelper_DeleteItems(psfhlpsrc, lpcida->cidl, apidl); - */ } + if(psfhlpdst) ISFHelper_Release(psfhlpdst); if(psfhlpsrc) ISFHelper_Release(psfhlpsrc); IShellFolder_Release(psfFrom); @@ -285,30 +490,7 @@ static BOOL DoPaste( } IDataObject_Release(pda); } -#if 0 - HGLOBAL hMem; - OpenClipboard(NULL); - hMem = GetClipboardData(CF_HDROP); - - if(hMem) - { - char * pDropFiles = (char *)GlobalLock(hMem); - if(pDropFiles) - { - int len, offset = sizeof(DROPFILESTRUCT); - - while( pDropFiles[offset] != 0) - { - len = strlen(pDropFiles + offset); - TRACE("%s\n", pDropFiles + offset); - offset += len+1; - } - } - GlobalUnlock(hMem); - } - CloseClipboard(); -#endif return bSuccess; } @@ -335,7 +517,6 @@ static HRESULT WINAPI ISVBgCm_fnInvokeCommand( IShellView_GetWindow(lpSV, &hWndSV); } } - if(HIWORD(lpcmi->lpVerb)) { TRACE("%s\n",lpcmi->lpVerb); @@ -373,6 +554,10 @@ static HRESULT WINAPI ISVBgCm_fnInvokeCommand( DoPaste(iface); break; + case FCIDM_SHVIEW_INSERTLINK: + MakeLink(iface); + break; + case FCIDM_SHVIEW_PROPERTIES: if (This->bDesktop) { ShellExecuteA(lpcmi->hwnd, "open", "rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL); diff --git a/reactos/dll/win32/shell32/shv_item_cmenu.c b/reactos/dll/win32/shell32/shv_item_cmenu.c index 43f76fd8181..60ae91263d1 100644 --- a/reactos/dll/win32/shell32/shv_item_cmenu.c +++ b/reactos/dll/win32/shell32/shv_item_cmenu.c @@ -39,6 +39,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); +/* ugly hack for cut&psate files */ +BOOL fileMoving = FALSE; + + /************************************************************************** * IContextMenu Implementation */ @@ -98,7 +102,7 @@ IContextMenu2 *ISvItemCm_Constructor(LPSHELLFOLDER pSFParent, LPCITEMIDLIST pidl { cm->bAllValues &= (_ILIsValue(apidl[u]) ? 1 : 0); } - + TRACE("(%p)->()\n",cm); return (IContextMenu2*)cm; @@ -374,9 +378,10 @@ static BOOL DoCopyOrCut( LPDATAOBJECT lpDo; TRACE("(%p)->(wnd=%p,bCut=0x%08x)\n",This, hwnd, bCut); - + fileMoving = bCut; + /* get the active IShellView */ - if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER,0,0))) + if ((lpSB = (LPSHELLBROWSER)SendMessageA(hwnd, CWM_GETISHELLBROWSER, 0, 0))) { if (SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV))) {