Make some shell32 files compile in MSVC.
[wine/multimedia.git] / dlls / shell32 / shlfileop.c
blobfe9236a04e16a2fd0ea25c77e8908db4595e4e75
1 /*
2 * SHFileOperation
4 * Copyright 2000 Juergen Schmied
5 * Copyright 2002 Andriy Palamarchuk
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <string.h>
27 #include "winreg.h"
28 #include "shellapi.h"
29 #include "shlobj.h"
30 #include "shresdef.h"
31 #include "shell32_main.h"
32 #include "undocshell.h"
33 #include "shlwapi.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(shell);
38 BOOL SHELL_WarnItemDelete (int nKindOfDialog, LPCSTR szDir)
40 char szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
42 if(nKindOfDialog == ASK_DELETE_FILE)
44 LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText,
45 sizeof(szText));
46 LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION,
47 szCaption, sizeof(szCaption));
49 else if(nKindOfDialog == ASK_DELETE_FOLDER)
51 LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText,
52 sizeof(szText));
53 LoadStringA(shell32_hInstance, IDS_DELETEFOLDER_CAPTION,
54 szCaption, sizeof(szCaption));
56 else if(nKindOfDialog == ASK_DELETE_MULTIPLE_ITEM)
58 LoadStringA(shell32_hInstance, IDS_DELETEMULTIPLE_TEXT, szText,
59 sizeof(szText));
60 LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION,
61 szCaption, sizeof(szCaption));
63 else {
64 FIXME("Called without a valid nKindOfDialog specified!\n");
65 LoadStringA(shell32_hInstance, IDS_DELETEITEM_TEXT, szText,
66 sizeof(szText));
67 LoadStringA(shell32_hInstance, IDS_DELETEITEM_CAPTION,
68 szCaption, sizeof(szCaption));
71 FormatMessageA(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
72 szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)&szDir);
74 return (IDOK == MessageBoxA(GetActiveWindow(), szBuffer, szCaption, MB_OKCANCEL | MB_ICONEXCLAMATION));
77 /**************************************************************************
78 * SHELL_DeleteDirectoryA()
80 * like rm -r
83 BOOL SHELL_DeleteDirectoryA(LPCSTR pszDir, BOOL bShowUI)
85 BOOL ret = FALSE;
86 HANDLE hFind;
87 WIN32_FIND_DATAA wfd;
88 char szTemp[MAX_PATH];
90 strcpy(szTemp, pszDir);
91 PathAddBackslashA(szTemp);
92 strcat(szTemp, "*.*");
94 if (bShowUI && !SHELL_WarnItemDelete(ASK_DELETE_FOLDER, pszDir))
95 return FALSE;
97 if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(szTemp, &wfd)))
101 if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
103 strcpy(szTemp, pszDir);
104 PathAddBackslashA(szTemp);
105 strcat(szTemp, wfd.cFileName);
107 if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
108 SHELL_DeleteDirectoryA(szTemp, FALSE);
109 else
110 DeleteFileA(szTemp);
112 } while(FindNextFileA(hFind, &wfd));
114 FindClose(hFind);
115 ret = RemoveDirectoryA(pszDir);
118 return ret;
121 /**************************************************************************
122 * SHELL_DeleteFileA()
125 BOOL SHELL_DeleteFileA(LPCSTR pszFile, BOOL bShowUI)
127 if (bShowUI && !SHELL_WarnItemDelete(ASK_DELETE_FILE, pszFile))
128 return FALSE;
130 return DeleteFileA(pszFile);
133 /*************************************************************************
134 * SHCreateDirectory [SHELL32.165]
136 * NOTES
137 * exported by ordinal
138 * not sure about LPSECURITY_ATTRIBUTES
140 DWORD WINAPI SHCreateDirectory(LPSECURITY_ATTRIBUTES sec,LPCSTR path)
142 DWORD ret;
143 TRACE("(%p,%s)\n",sec,path);
144 if ((ret = CreateDirectoryA(path,sec)))
146 SHChangeNotifyA(SHCNE_MKDIR, SHCNF_PATHA, path, NULL);
148 return ret;
151 /************************************************************************
152 * Win32DeleteFile [SHELL32.164]
154 * Deletes a file. Also triggers a change notify if one exists.
156 * FIXME:
157 * Verified on Win98 / IE 5 (SHELL32 4.72, March 1999 build) to be
158 * ANSI. Is this Unicode on NT?
162 BOOL WINAPI Win32DeleteFile(LPSTR fName)
164 TRACE("%p(%s)\n", fName, fName);
166 DeleteFileA(fName);
167 SHChangeNotifyA(SHCNE_DELETE, SHCNF_PATHA, fName, NULL);
168 return TRUE;
171 /**************************************************************************
172 * SHELL_FileNamesMatch()
174 * Accepts two \0 delimited lists of the file names. Checks whether number of
175 * files in the both lists is the same.
177 BOOL SHELL_FileNamesMatch(LPCSTR pszFiles1, LPCSTR pszFiles2)
179 while ((pszFiles1[strlen(pszFiles1) + 1] != '\0') &&
180 (pszFiles2[strlen(pszFiles2) + 1] != '\0'))
182 pszFiles1 += strlen(pszFiles1) + 1;
183 pszFiles2 += strlen(pszFiles2) + 1;
186 return
187 ((pszFiles1[strlen(pszFiles1) + 1] == '\0') &&
188 (pszFiles2[strlen(pszFiles2) + 1] == '\0')) ||
189 ((pszFiles1[strlen(pszFiles1) + 1] != '\0') &&
190 (pszFiles2[strlen(pszFiles2) + 1] != '\0'));
193 /*************************************************************************
194 * SHFileOperationA [SHELL32.@]
196 * NOTES
197 * exported by name
199 DWORD WINAPI SHFileOperationA (LPSHFILEOPSTRUCTA lpFileOp)
201 LPSTR pFrom = (LPSTR)lpFileOp->pFrom;
202 LPSTR pTo = (LPSTR)lpFileOp->pTo;
203 LPSTR pTempTo;
204 TRACE("flags (0x%04x) : %s%s%s%s%s%s%s%s%s%s%s%s \n", lpFileOp->fFlags,
205 lpFileOp->fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
206 lpFileOp->fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
207 lpFileOp->fFlags & FOF_SILENT ? "FOF_SILENT " : "",
208 lpFileOp->fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
209 lpFileOp->fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
210 lpFileOp->fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
211 lpFileOp->fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
212 lpFileOp->fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
213 lpFileOp->fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
214 lpFileOp->fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
215 lpFileOp->fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
216 lpFileOp->fFlags & 0xf800 ? "MORE-UNKNOWN-Flags" : "");
217 switch(lpFileOp->wFunc) {
218 case FO_COPY:
219 case FO_MOVE:
221 /* establish when pTo is interpreted as the name of the destination file
222 * or the directory where the Fromfile should be copied to.
223 * This depends on:
224 * (1) pTo points to the name of an existing directory;
225 * (2) the flag FOF_MULTIDESTFILES is present;
226 * (3) whether pFrom point to multiple filenames.
228 * Some experiments:
230 * destisdir 1 1 1 1 0 0 0 0
231 * FOF_MULTIDESTFILES 1 1 0 0 1 1 0 0
232 * multiple from filenames 1 0 1 0 1 0 1 0
233 * ---------------
234 * copy files to dir 1 0 1 1 0 0 1 0
235 * create dir 0 0 0 0 0 0 1 0
237 int multifrom = pFrom[strlen(pFrom) + 1] != '\0';
238 int destisdir = PathIsDirectoryA( pTo );
239 int todir = 0;
241 if (lpFileOp->wFunc == FO_COPY)
242 TRACE("File Copy:\n");
243 else
244 TRACE("File Move:\n");
246 if( destisdir ) {
247 if ( !((lpFileOp->fFlags & FOF_MULTIDESTFILES) && !multifrom))
248 todir = 1;
249 } else {
250 if ( !(lpFileOp->fFlags & FOF_MULTIDESTFILES) && multifrom)
251 todir = 1;
254 if ((pTo[strlen(pTo) + 1] != '\0') &&
255 !(lpFileOp->fFlags & FOF_MULTIDESTFILES))
257 WARN("Attempt to use multiple file names as a destination "
258 "without specifying FOF_MULTIDESTFILES\n");
259 return 1;
262 if ((lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
263 !SHELL_FileNamesMatch(pTo, pFrom))
265 WARN("Attempt to use multiple file names as a destination "
266 "with mismatching number of files in the source and "
267 "destination lists\n");
268 return 1;
271 if ( todir ) {
272 char szTempFrom[MAX_PATH];
273 char *fromfile;
274 int lenPTo;
275 if ( ! destisdir) {
276 TRACE(" creating directory %s\n",pTo);
277 SHCreateDirectory(NULL,pTo);
279 lenPTo = strlen(pTo);
280 while(1) {
281 HANDLE hFind;
282 WIN32_FIND_DATAA wfd;
284 if(!pFrom[0]) break;
285 TRACE(" From Pattern='%s'\n", pFrom);
286 if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(pFrom, &wfd)))
290 if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
292 strcpy(szTempFrom, pFrom);
294 pTempTo = HeapAlloc(GetProcessHeap(), 0,
295 lenPTo + strlen(wfd.cFileName) + 5);
296 if (pTempTo) {
297 strcpy(pTempTo,pTo);
298 PathAddBackslashA(pTempTo);
299 strcat(pTempTo,wfd.cFileName);
301 fromfile = PathFindFileNameA(szTempFrom);
302 fromfile[0] = '\0';
303 PathAddBackslashA(szTempFrom);
304 strcat(szTempFrom, wfd.cFileName);
305 TRACE(" From='%s' To='%s'\n", szTempFrom, pTempTo);
306 if(lpFileOp->wFunc == FO_COPY)
308 if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
310 /* copy recursively */
311 if(!(lpFileOp->fFlags & FOF_FILESONLY))
313 SHFILEOPSTRUCTA shfo;
315 SHCreateDirectory(NULL,pTempTo);
316 PathAddBackslashA(szTempFrom);
317 strcat(szTempFrom, "*.*");
318 szTempFrom[strlen(szTempFrom) + 1] = '\0';
319 pTempTo[strlen(pTempTo) + 1] = '\0';
320 memcpy(&shfo, lpFileOp, sizeof(shfo));
321 shfo.pFrom = szTempFrom;
322 shfo.pTo = pTempTo;
323 SHFileOperationA(&shfo);
325 szTempFrom[strlen(szTempFrom) - 4] = '\0';
328 else
329 CopyFileA(szTempFrom, pTempTo, FALSE);
331 else
333 /* move file/directory */
334 MoveFileA(szTempFrom, pTempTo);
336 HeapFree(GetProcessHeap(), 0, pTempTo);
339 } while(FindNextFileA(hFind, &wfd));
340 FindClose(hFind);
342 else
344 /* can't find file with specified name */
345 break;
347 pFrom += strlen(pFrom) + 1;
349 } else {
350 while(1) {
351 if(!pFrom[0]) break;
352 if(!pTo[0]) break;
353 TRACE(" From='%s' To='%s'\n", pFrom, pTo);
355 pTempTo = HeapAlloc(GetProcessHeap(), 0, strlen(pTo)+1);
356 if (pTempTo)
358 strcpy( pTempTo, pTo );
359 PathRemoveFileSpecA(pTempTo);
360 TRACE(" Creating Directory '%s'\n", pTempTo);
361 SHCreateDirectory(NULL,pTempTo);
362 HeapFree(GetProcessHeap(), 0, pTempTo);
364 if (lpFileOp->wFunc == FO_COPY)
365 CopyFileA(pFrom, pTo, FALSE);
366 else
367 MoveFileA(pFrom, pTo);
369 pFrom += strlen(pFrom) + 1;
370 pTo += strlen(pTo) + 1;
373 TRACE("Setting AnyOpsAborted=FALSE\n");
374 lpFileOp->fAnyOperationsAborted=FALSE;
375 return 0;
378 case FO_DELETE:
380 HANDLE hFind;
381 WIN32_FIND_DATAA wfd;
382 char szTemp[MAX_PATH];
383 char *file_name;
385 TRACE("File Delete:\n");
386 while(1) {
387 if(!pFrom[0]) break;
388 TRACE(" Pattern='%s'\n", pFrom);
389 if(INVALID_HANDLE_VALUE != (hFind = FindFirstFileA(pFrom, &wfd)))
393 if(strcasecmp(wfd.cFileName, ".") && strcasecmp(wfd.cFileName, ".."))
395 strcpy(szTemp, pFrom);
396 file_name = PathFindFileNameA(szTemp);
397 file_name[0] = '\0';
398 PathAddBackslashA(szTemp);
399 strcat(szTemp, wfd.cFileName);
401 TRACE(" File='%s'\n", szTemp);
402 if(FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
404 if(!(lpFileOp->fFlags & FOF_FILESONLY))
405 SHELL_DeleteDirectoryA(szTemp, FALSE);
407 else
408 DeleteFileA(szTemp);
410 } while(FindNextFileA(hFind, &wfd));
412 FindClose(hFind);
414 pFrom += strlen(pFrom) + 1;
416 TRACE("Setting AnyOpsAborted=FALSE\n");
417 lpFileOp->fAnyOperationsAborted=FALSE;
418 return 0;
421 case FO_RENAME:
422 TRACE("File Rename:\n");
423 if (pFrom[strlen(pFrom) + 1] != '\0')
425 WARN("Attempt to rename more than one file\n");
426 return 1;
428 lpFileOp->fAnyOperationsAborted = FALSE;
429 TRACE("From %s, To %s\n", pFrom, pTo);
430 return !MoveFileA(pFrom, pTo);
432 default:
433 FIXME("Unhandled shell file operation %d\n", lpFileOp->wFunc);
436 return 1;
439 /*************************************************************************
440 * SHFileOperationW [SHELL32.@]
442 * NOTES
443 * exported by name
445 DWORD WINAPI SHFileOperationW (LPSHFILEOPSTRUCTW lpFileOp)
447 FIXME("(%p):stub.\n", lpFileOp);
448 return 1;
451 /*************************************************************************
452 * SHFileOperation [SHELL32.@]
455 DWORD WINAPI SHFileOperationAW(LPVOID lpFileOp)
457 if (SHELL_OsIsUnicode())
458 return SHFileOperationW(lpFileOp);
459 return SHFileOperationA(lpFileOp);
462 /*************************************************************************
463 * SheGetDirW [SHELL32.281]
466 HRESULT WINAPI SheGetDirW(LPWSTR u, LPWSTR v)
467 { FIXME("%p %p stub\n",u,v);
468 return 0;
471 /*************************************************************************
472 * SheChangeDirW [SHELL32.274]
475 HRESULT WINAPI SheChangeDirW(LPWSTR u)
476 { FIXME("(%s),stub\n",debugstr_w(u));
477 return 0;
480 /*************************************************************************
481 * IsNetDrive [SHELL32.66]
483 BOOL WINAPI IsNetDrive(DWORD drive)
485 char root[4];
486 strcpy(root, "A:\\");
487 root[0] += drive;
488 return (GetDriveTypeA(root) == DRIVE_REMOTE);