ReactOS  0.4.15-dev-5452-g3c95c95
shlfileop.cpp
Go to the documentation of this file.
1 /*
2  * SHFileOperation
3  *
4  * Copyright 2000 Juergen Schmied
5  * Copyright 2002 Andriy Palamarchuk
6  * Copyright 2004 Dietrich Teickner (from Odin)
7  * Copyright 2004 Rolf Kalbermatter
8  * Copyright 2019 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include "precomp.h"
26 
28 
29 #define IsAttrib(x, y) ((INVALID_FILE_ATTRIBUTES != (x)) && ((x) & (y)))
30 #define IsAttribFile(x) (!((x) & FILE_ATTRIBUTE_DIRECTORY))
31 #define IsAttribDir(x) IsAttrib(x, FILE_ATTRIBUTE_DIRECTORY)
32 #define IsDotDir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
33 
34 #define FO_MASK 0xF
35 
36 #define NEW_FILENAME_ON_COPY_TRIES 100
37 
38 typedef struct
39 {
44  IProgressDialog *progress;
47  WCHAR szBuilderString[50];
49 
50 #define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026
51 
52 typedef struct
53 {
61 } FILE_ENTRY;
62 
63 typedef struct
64 {
71 } FILE_LIST;
72 
78 static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly);
79 static HRESULT copy_files(FILE_OPERATION *op, BOOL multiDest, const FILE_LIST *flFrom, FILE_LIST *flTo);
80 static DWORD move_files(FILE_OPERATION *op, BOOL multiDest, const FILE_LIST *flFrom, const FILE_LIST *flTo);
81 
83 static BOOL _FileOpCount(FILE_OPERATION *op, LPWSTR pwszBuf, BOOL bFolder, DWORD *ticks);
84 
85 /* Confirm dialogs with an optional "Yes To All" as used in file operations confirmations
86  */
88 {
93 };
94 
95 /* as some buttons may be hidden and the dialog height may change we may need
96  * to move the controls */
97 static void confirm_msg_move_button(HWND hDlg, INT iId, INT *xPos, INT yOffset, BOOL bShow)
98 {
99  HWND hButton = GetDlgItem(hDlg, iId);
100  RECT r;
101 
102  if (bShow)
103  {
104  POINT pt;
105  int width;
106 
107  GetWindowRect(hButton, &r);
108  width = r.right - r.left;
109  pt.x = r.left;
110  pt.y = r.top;
111  ScreenToClient(hDlg, &pt);
112  MoveWindow(hButton, *xPos - width, pt.y - yOffset, width, r.bottom - r.top, FALSE);
113  *xPos -= width + 5;
114  }
115  else
116  ShowWindow(hButton, SW_HIDE);
117 }
118 
119 /* Note: we paint the text manually and don't use the static control to make
120  * sure the text has the same height as the one computed in WM_INITDIALOG
121  */
123 {
124  PAINTSTRUCT ps;
125  HFONT hOldFont;
126  RECT r;
127  HDC hdc;
128 
129  BeginPaint(hDlg, &ps);
130  hdc = ps.hdc;
132 
134  /* this will remap the rect to dialog coords */
137  DrawTextW(hdc, (LPWSTR)GetPropW(hDlg, L"WINE_CONFIRM"), -1, &r, DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_WORDBREAK);
138  SelectObject(hdc, hOldFont);
139  EndPaint(hDlg, &ps);
140 
141  return TRUE;
142 }
143 
145 {
146  struct confirm_msg_info *info = (struct confirm_msg_info *)lParam;
147  INT xPos, yOffset;
148  int width, height;
149  HFONT hOldFont;
150  HDC hdc;
151  RECT r;
152 
153  SetWindowTextW(hDlg, info->lpszCaption);
155  SetPropW(hDlg, L"WINE_CONFIRM", info->lpszText);
157 
158  /* compute the text height and resize the dialog */
160  hdc = GetDC(hDlg);
161  yOffset = r.bottom;
164  SelectObject(hdc, hOldFont);
165  yOffset -= r.bottom;
166  yOffset = min(yOffset, 35); /* don't make the dialog too small */
167  ReleaseDC(hDlg, hdc);
168 
169  GetClientRect(hDlg, &r);
170  xPos = r.right - 7;
171  GetWindowRect(hDlg, &r);
172  width = r.right - r.left;
173  height = r.bottom - r.top - yOffset;
176 
177  confirm_msg_move_button(hDlg, IDCANCEL, &xPos, yOffset, info->bYesToAll);
178  confirm_msg_move_button(hDlg, IDNO, &xPos, yOffset, TRUE);
179  confirm_msg_move_button(hDlg, IDC_YESTOALL, &xPos, yOffset, info->bYesToAll);
180  confirm_msg_move_button(hDlg, IDYES, &xPos, yOffset, TRUE);
181 
182  return TRUE;
183 }
184 
186 {
187  switch (uMsg)
188  {
189  case WM_INITDIALOG:
190  return ConfirmMsgBox_Init(hDlg, lParam);
191  case WM_PAINT:
192  return ConfirmMsgBox_Paint(hDlg);
193  case WM_COMMAND:
194  EndDialog(hDlg, wParam);
195  break;
196  case WM_CLOSE:
197  EndDialog(hDlg, IDCANCEL);
198  break;
199  }
200  return FALSE;
201 }
202 
204 {
205  struct confirm_msg_info info;
206 
207  info.lpszText = lpszText;
208  info.lpszCaption = lpszCaption;
209  info.hIcon = hIcon;
210  info.bYesToAll = bYesToAll;
212 }
213 
214 /* confirmation dialogs content */
215 typedef struct
216 {
219  UINT caption_resource_id, text_resource_id;
221 
222 static BOOL SHELL_ConfirmIDs(int nKindOfDialog, SHELL_ConfirmIDstruc *ids)
223 {
224  ids->hIconInstance = shell32_hInstance;
225  switch (nKindOfDialog)
226  {
227  case ASK_DELETE_FILE:
228  ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
229  ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
230  ids->text_resource_id = IDS_DELETEITEM_TEXT;
231  return TRUE;
232 
233  case ASK_DELETE_FOLDER:
234  ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
235  ids->caption_resource_id = IDS_DELETEFOLDER_CAPTION;
236  ids->text_resource_id = IDS_DELETEITEM_TEXT;
237  return TRUE;
238 
240  ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
241  ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
242  ids->text_resource_id = IDS_DELETEMULTIPLE_TEXT;
243  return TRUE;
244 
245  case ASK_TRASH_FILE:
246  ids->icon_resource_id = IDI_SHELL_TRASH_FILE;
247  ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
248  ids->text_resource_id = IDS_TRASHITEM_TEXT;
249  return TRUE;
250 
251  case ASK_TRASH_FOLDER:
252  ids->icon_resource_id = IDI_SHELL_TRASH_FILE;
253  ids->caption_resource_id = IDS_DELETEFOLDER_CAPTION;
254  ids->text_resource_id = IDS_TRASHFOLDER_TEXT;
255  return TRUE;
256 
258  ids->icon_resource_id = IDI_SHELL_TRASH_FILE;
259  ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
260  ids->text_resource_id = IDS_TRASHMULTIPLE_TEXT;
261  return TRUE;
262 
263  case ASK_CANT_TRASH_ITEM:
264  ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
265  ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
266  ids->text_resource_id = IDS_CANTTRASH_TEXT;
267  return TRUE;
268 
269  case ASK_DELETE_SELECTED:
270  ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
271  ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
272  ids->text_resource_id = IDS_DELETESELECTED_TEXT;
273  return TRUE;
274 
275  case ASK_OVERWRITE_FILE:
276  ids->icon_resource_id = IDI_SHELL_FOLDER_MOVE2;
277  ids->caption_resource_id = IDS_OVERWRITEFILE_CAPTION;
278  ids->text_resource_id = IDS_OVERWRITEFILE_TEXT;
279  return TRUE;
280 
282  ids->icon_resource_id = IDI_SHELL_FOLDER_MOVE2;
283  ids->caption_resource_id = IDS_OVERWRITEFILE_CAPTION;
284  ids->text_resource_id = IDS_OVERWRITEFOLDER_TEXT;
285  return TRUE;
286 
287  default:
288  FIXME(" Unhandled nKindOfDialog %d stub\n", nKindOfDialog);
289  }
290  return FALSE;
291 }
292 
293 static BOOL SHELL_ConfirmDialogW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir, FILE_OPERATION *op)
294 {
295  WCHAR szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
297  DWORD_PTR args[1];
298  HICON hIcon;
299  int ret;
300 
301  assert(nKindOfDialog >= 0 && nKindOfDialog < 32);
302  if (op && (op->dwYesToAllMask & (1 << nKindOfDialog)))
303  return TRUE;
304 
305  if (!SHELL_ConfirmIDs(nKindOfDialog, &ids)) return FALSE;
306 
307  LoadStringW(shell32_hInstance, ids.caption_resource_id, szCaption, sizeof(szCaption)/sizeof(WCHAR));
308  LoadStringW(shell32_hInstance, ids.text_resource_id, szText, sizeof(szText)/sizeof(WCHAR));
309 
310  args[0] = (DWORD_PTR)szDir;
312  szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)args);
313  hIcon = LoadIconW(ids.hIconInstance, (LPWSTR)MAKEINTRESOURCE(ids.icon_resource_id));
314 
315  ret = SHELL_ConfirmMsgBox(hWnd, szBuffer, szCaption, hIcon, op && op->bManyItems);
316  if (op)
317  {
318  if (ret == IDC_YESTOALL)
319  {
320  op->dwYesToAllMask |= (1 << nKindOfDialog);
321  ret = IDYES;
322  }
323  if (ret == IDCANCEL)
324  op->bCancelled = TRUE;
325  if (ret != IDYES)
326  op->req->fAnyOperationsAborted = TRUE;
327  }
328  return ret == IDYES;
329 }
330 
331 BOOL SHELL_ConfirmYesNoW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir)
332 {
333  return SHELL_ConfirmDialogW(hWnd, nKindOfDialog, szDir, NULL);
334 }
335 
336 static DWORD SHELL32_AnsiToUnicodeBuf(LPCSTR aPath, LPWSTR *wPath, DWORD minChars)
337 {
338  DWORD len = MultiByteToWideChar(CP_ACP, 0, aPath, -1, NULL, 0);
339 
340  if (len < minChars)
341  len = minChars;
342 
343  *wPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
344  if (*wPath)
345  {
346  MultiByteToWideChar(CP_ACP, 0, aPath, -1, *wPath, len);
347  return NO_ERROR;
348  }
349  return E_OUTOFMEMORY;
350 }
351 
352 static void SHELL32_FreeUnicodeBuf(LPWSTR wPath)
353 {
354  HeapFree(GetProcessHeap(), 0, wPath);
355 }
356 
358 {
359  FIXME("(%s, %p) stub\n", debugstr_w(path), status);
360  return E_FAIL;
361 }
362 
363 /**************************************************************************
364  * SHELL_DeleteDirectory() [internal]
365  *
366  * Asks for confirmation when bShowUI is true and deletes the directory and
367  * all its subdirectories and files if necessary.
368  */
370 {
371  BOOL ret = TRUE;
372  HANDLE hFind;
373  WIN32_FIND_DATAW wfd;
374  WCHAR szTemp[MAX_PATH];
375 
376  /* Make sure the directory exists before eventually prompting the user */
377  PathCombineW(szTemp, pszDir, L"*");
378  hFind = FindFirstFileW(szTemp, &wfd);
379  if (hFind == INVALID_HANDLE_VALUE)
380  return FALSE;
381 
382  if (!bShowUI || (ret = SHELL_ConfirmDialogW(op->req->hwnd, ASK_DELETE_FOLDER, pszDir, NULL)))
383  {
384  do
385  {
386  if (IsDotDir(wfd.cFileName))
387  continue;
388  PathCombineW(szTemp, pszDir, wfd.cFileName);
389  if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
390  ret = SHELL_DeleteDirectoryW(op, szTemp, FALSE);
391  else
392  ret = (SHNotifyDeleteFileW(op, szTemp) == ERROR_SUCCESS);
393 
394  if (op->progress != NULL)
395  op->bCancelled |= op->progress->HasUserCancelled();
396  } while (ret && FindNextFileW(hFind, &wfd) && !op->bCancelled);
397  }
398  FindClose(hFind);
399  if (ret)
401  return ret;
402 }
403 
404 /**************************************************************************
405  * Win32CreateDirectory [SHELL32.93]
406  *
407  * Creates a directory. Also triggers a change notify if one exists.
408  *
409  * PARAMS
410  * path [I] path to directory to create
411  *
412  * RETURNS
413  * TRUE if successful, FALSE otherwise
414  */
415 
417 {
418  TRACE("(%s, %p)\n", debugstr_w(path), sec);
419 
420  if (CreateDirectoryW(path, sec))
421  {
423  return ERROR_SUCCESS;
424  }
425  return GetLastError();
426 }
427 
428 /**********************************************************************/
429 
431 {
432  return (SHNotifyCreateDirectoryW(path, sec) == ERROR_SUCCESS);
433 }
434 
435 /************************************************************************
436  * Win32RemoveDirectory [SHELL32.94]
437  *
438  * Deletes a directory. Also triggers a change notify if one exists.
439  *
440  * PARAMS
441  * path [I] path to directory to delete
442  *
443  * RETURNS
444  * TRUE if successful, FALSE otherwise
445  */
447 {
448  BOOL ret;
449  TRACE("(%s)\n", debugstr_w(path));
450 
452  if (!ret)
453  {
454  /* Directory may be write protected */
455  DWORD dwAttr = GetFileAttributesW(path);
456  if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY))
459  }
460  if (ret)
461  {
463  return ERROR_SUCCESS;
464  }
465  return GetLastError();
466 }
467 
468 /***********************************************************************/
469 
471 {
473 }
474 
476  if (op->progress == NULL)
477  return;
478  WCHAR szTitle[50], szPreflight[50];
479  UINT animation_id = NULL;
480 
481  switch (op->req->wFunc)
482  {
483  case FO_COPY:
485  LoadStringW(shell32_hInstance, IDS_FILEOOP_FROM_TO, op->szBuilderString, sizeof( op->szBuilderString)/sizeof(WCHAR));
486  animation_id = IDA_SHELL_COPY;
487  break;
488  case FO_DELETE:
490  LoadStringW(shell32_hInstance, IDS_FILEOOP_FROM, op->szBuilderString, sizeof( op->szBuilderString)/sizeof(WCHAR));
491  animation_id = IDA_SHELL_DELETE;
492  break;
493  case FO_MOVE:
495  LoadStringW(shell32_hInstance, IDS_FILEOOP_FROM_TO, op->szBuilderString, sizeof( op->szBuilderString)/sizeof(WCHAR));
496  animation_id = IDA_SHELL_COPY;
497  break;
498  default:
499  return;
500  }
501  LoadStringW(shell32_hInstance, IDS_FILEOOP_PREFLIGHT, szPreflight, sizeof(szPreflight)/sizeof(WCHAR));
502 
503  op->progress->SetTitle(szTitle);
504  op->progress->SetLine(1, szPreflight, false, NULL);
505  op->progress->SetAnimation(shell32_hInstance, animation_id);
506 }
507 
509  if (op->progress == NULL || src == NULL)
510  return;
511  LPWSTR fileSpecS, pathSpecS, fileSpecD, pathSpecD;
512  WCHAR szFolderS[50], szFolderD[50], szFinalString[260];
513 
514  DWORD_PTR args[2];
515 
516  fileSpecS = (pathSpecS = (LPWSTR) src);
517  fileSpecD = (pathSpecD = (LPWSTR) dest);
518 
519  // March across the string to get the file path and it's parent dir.
520  for (LPWSTR ptr = (LPWSTR) src; *ptr; ptr++) {
521  if (*ptr == '\\') {
522  pathSpecS = fileSpecS;
523  fileSpecS = ptr+1;
524  }
525  }
526  lstrcpynW(szFolderS, pathSpecS, min(50, fileSpecS - pathSpecS));
527  args[0] = (DWORD_PTR) szFolderS;
528 
529  switch (op->req->wFunc)
530  {
531  case FO_COPY:
532  case FO_MOVE:
533  if (dest == NULL)
534  return;
535  for (LPWSTR ptr = (LPWSTR) dest; *ptr; ptr++) {
536  if (*ptr == '\\') {
537  pathSpecD = fileSpecD;
538  fileSpecD = ptr + 1;
539  }
540  }
541  lstrcpynW(szFolderD, pathSpecD, min(50, fileSpecD - pathSpecD));
542  args[1] = (DWORD_PTR) szFolderD;
543  break;
544  case FO_DELETE:
545  break;
546  default:
547  return;
548  }
549 
551  op->szBuilderString, 0, 0, szFinalString, sizeof(szFinalString), (va_list*)args);
552 
553  op->progress->SetLine(1, fileSpecS, false, NULL);
554  op->progress->SetLine(2, szFinalString, false, NULL);
555 }
556 
557 
559  LARGE_INTEGER TotalFileSize,
560  LARGE_INTEGER TotalBytesTransferred,
561  LARGE_INTEGER StreamSize,
562  LARGE_INTEGER StreamBytesTransferred,
563  DWORD dwStreamNumber,
564  DWORD dwCallbackReason,
565  HANDLE hSourceFile,
566  HANDLE hDestinationFile,
567  LPVOID lpData
568 ) {
569  FILE_OPERATION *op = (FILE_OPERATION *) lpData;
570 
571  if (op->progress) {
572  /*
573  * This is called at the start of each file. To keop less state,
574  * I'm adding the file to the completed size here, and the re-subtracting
575  * it when drawing the progress bar.
576  */
577  if (dwCallbackReason & CALLBACK_STREAM_SWITCH)
578  op->completedSize.QuadPart += TotalFileSize.QuadPart;
579 
580  op->progress->SetProgress64(op->completedSize.QuadPart -
581  TotalFileSize.QuadPart +
582  TotalBytesTransferred.QuadPart
583  , op->totalSize.QuadPart);
584 
585 
586  op->bCancelled = op->progress->HasUserCancelled();
587  }
588 
589  return 0;
590 }
591 
592 
593 /************************************************************************
594  * SHNotifyDeleteFileW [internal]
595  *
596  * Deletes a file. Also triggers a change notify if one exists.
597  *
598  * PARAMS
599  * op [I] File Operation context
600  * path [I] path to source file to move
601  *
602  * RETURNS
603  * ERORR_SUCCESS if successful
604  */
606 {
607  BOOL ret;
608 
609  TRACE("(%s)\n", debugstr_w(path));
610 
612 
614  FileSize.QuadPart = 0;
615 
616  WIN32_FIND_DATAW wfd;
617  HANDLE hFile = FindFirstFileW(path, &wfd);
618  if (hFile != INVALID_HANDLE_VALUE && IsAttribFile(wfd.dwFileAttributes)) {
619  ULARGE_INTEGER tmp;
620  tmp.u.LowPart = wfd.nFileSizeLow;
621  tmp.u.HighPart = wfd.nFileSizeHigh;
622  FileSize.QuadPart = tmp.QuadPart;
623  }
624  FindClose(hFile);
625 
626  ret = DeleteFileW(path);
627  if (!ret)
628  {
629  /* File may be write protected or a system file */
630  DWORD dwAttr = GetFileAttributesW(path);
633  ret = DeleteFileW(path);
634  }
635  if (ret)
636  {
637  // Bit of a hack to make the progress bar move. We don't have progress inside the file, so inform when done.
640  return ERROR_SUCCESS;
641  }
642  return GetLastError();
643 }
644 
645 /************************************************************************
646  * Win32DeleteFile [SHELL32.164]
647  *
648  * Deletes a file. Also triggers a change notify if one exists.
649  *
650  * PARAMS
651  * path [I] path to file to delete
652  *
653  * RETURNS
654  * TRUE if successful, FALSE otherwise
655  */
657 {
659 }
660 
661 #ifdef __REACTOS__
662 /************************************************************************
663  * CheckForError [internal]
664  *
665  * Show message box if operation failed
666  *
667  * PARAMS
668  * op [I] File Operation context
669  * error [I] Error code
670  * src [I] Source file full name
671  *
672  */
673 static DWORD CheckForError(FILE_OPERATION *op, DWORD error, LPCWSTR src)
674 {
675  CStringW strTitle, strMask, strText;
676  LPWSTR lpMsgBuffer;
677 
678  if (error == ERROR_SUCCESS || (op->req->fFlags & (FOF_NOERRORUI | FOF_SILENT)))
679  goto exit;
680 
681  strTitle.LoadStringW(op->req->wFunc == FO_COPY ? IDS_COPYERRORTITLE : IDS_MOVEERRORTITLE);
682 
684  NULL,
685  error,
687  (LPWSTR)&lpMsgBuffer,
688  0,
689  NULL);
690 
691  strText.Format(op->req->wFunc == FO_COPY ? IDS_COPYERROR : IDS_MOVEERROR,
693  lpMsgBuffer);
694 
695  MessageBoxW(op->req->hwnd, strText, strTitle, MB_ICONERROR);
696  LocalFree(lpMsgBuffer);
697 
698 exit:
699  return error;
700 }
701 #endif
702 
703 /************************************************************************
704  * SHNotifyMoveFile [internal]
705  *
706  * Moves a file. Also triggers a change notify if one exists.
707  *
708  * PARAMS
709  * op [I] File Operation context
710  * src [I] path to source file to move
711  * dest [I] path to target file to move to
712  *
713  * RETURNS
714  * ERROR_SUCCESS if successful
715  */
717 {
718  BOOL ret;
719 
720  TRACE("(%s %s)\n", debugstr_w(src), debugstr_w(dest));
721 
723 
725 
726  /* MOVEFILE_REPLACE_EXISTING fails with dirs, so try MoveFile */
727  if (!ret)
728  ret = MoveFileW(src, dest);
729 
730  if (!ret)
731  {
732  DWORD dwAttr;
733 
734  dwAttr = SHFindAttrW(dest, FALSE);
735  if (INVALID_FILE_ATTRIBUTES == dwAttr)
736  {
737  /* Source file may be write protected or a system file */
738  dwAttr = GetFileAttributesW(src);
741  ret = MoveFileW(src, dest);
742  }
743  }
744  if (ret)
745  {
748  return ERROR_SUCCESS;
749  }
750 
751 #ifdef __REACTOS__
752  return CheckForError(op, GetLastError(), src);
753 #else
754  return GetLastError();
755 #endif
756 }
757 
759 {
760  WCHAR tmp[] = { L"A:\\" };
761 
762  if (!path || !path[0])
763  return FALSE;
764 
765  if (path[1] != UNICODE_NULL && path[1] != ':')
766  return FALSE;
767 
768  tmp[0] = path[0];
769 
770  return GetDriveTypeW(tmp) == DRIVE_CDROM;
771 }
772 
773 /************************************************************************
774  * SHNotifyCopyFile [internal]
775  *
776  * Copies a file. Also triggers a change notify if one exists.
777  *
778  * PARAMS
779  * src [I] path to source file to move
780  * dest [I] path to target file to move to
781  * bFailIfExists [I] if TRUE, the target file will not be overwritten if
782  * a file with this name already exists
783  *
784  * RETURNS
785  * ERROR_SUCCESS if successful
786  */
788 {
789  BOOL ret;
790  DWORD attribs;
791 
792  TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : "");
793 
795 
796  /* Destination file may already exist with read only attribute */
800 
802  {
805  {
806  TRACE("[shell32, SHNotifyCopyFileW] STILL SHIT\n");
807  }
808  }
809 
810  ret = CopyFileExW(src, dest, SHCopyProgressRoutine, op, &op->bCancelled, bFailIfExists);
811  if (ret)
812  {
813  // We are copying from a CD-ROM volume, which is readonly
814  if (SHIsCdRom(src))
815  {
819  }
820 
822  return ERROR_SUCCESS;
823  }
824 
825 #ifdef __REACTOS__
826  return CheckForError(op, GetLastError(), src);
827 #else
828  return GetLastError();
829 #endif
830 }
831 
832 /*************************************************************************
833  * SHCreateDirectory [SHELL32.165]
834  *
835  * This function creates a file system folder whose fully qualified path is
836  * given by path. If one or more of the intermediate folders do not exist,
837  * they will be created as well.
838  *
839  * PARAMS
840  * hWnd [I]
841  * path [I] path of directory to create
842  *
843  * RETURNS
844  * ERROR_SUCCESS or one of the following values:
845  * ERROR_BAD_PATHNAME if the path is relative
846  * ERROR_FILE_EXISTS when a file with that name exists
847  * ERROR_PATH_NOT_FOUND can't find the path, probably invalid
848  * ERROR_INVALID_NAME if the path contains invalid chars
849  * ERROR_ALREADY_EXISTS when the directory already exists
850  * ERROR_FILENAME_EXCED_RANGE if the filename was to long to process
851  *
852  * NOTES
853  * exported by ordinal
854  * Win9x exports ANSI
855  * WinNT/2000 exports Unicode
856  */
858 {
860 }
861 
862 /*************************************************************************
863  * SHCreateDirectoryExA [SHELL32.@]
864  *
865  * This function creates a file system folder whose fully qualified path is
866  * given by path. If one or more of the intermediate folders do not exist,
867  * they will be created as well.
868  *
869  * PARAMS
870  * hWnd [I]
871  * path [I] path of directory to create
872  * sec [I] security attributes to use or NULL
873  *
874  * RETURNS
875  * ERROR_SUCCESS or one of the following values:
876  * ERROR_BAD_PATHNAME or ERROR_PATH_NOT_FOUND if the path is relative
877  * ERROR_INVALID_NAME if the path contains invalid chars
878  * ERROR_FILE_EXISTS when a file with that name exists
879  * ERROR_ALREADY_EXISTS when the directory already exists
880  * ERROR_FILENAME_EXCED_RANGE if the filename was too long to process
881  *
882  * FIXME: Not implemented yet;
883  * SHCreateDirectoryEx also verifies that the files in the directory will be visible
884  * if the path is a network path to deal with network drivers which might have a limited
885  * but unknown maximum path length. If not:
886  *
887  * If hWnd is set to a valid window handle, a message box is displayed warning
888  * the user that the files may not be accessible. If the user chooses not to
889  * proceed, the function returns ERROR_CANCELLED.
890  *
891  * If hWnd is set to NULL, no user interface is displayed and the function
892  * returns ERROR_CANCELLED.
893  */
895 {
896  LPWSTR wPath;
897  DWORD retCode;
898 
899  TRACE("(%s, %p)\n", debugstr_a(path), sec);
900 
901  retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0);
902  if (!retCode)
903  {
904  retCode = SHCreateDirectoryExW(hWnd, wPath, sec);
905  SHELL32_FreeUnicodeBuf(wPath);
906  }
907  return retCode;
908 }
909 
910 /*************************************************************************
911  * SHCreateDirectoryExW [SHELL32.@]
912  *
913  * See SHCreateDirectoryExA.
914  */
916 {
917  int ret = ERROR_BAD_PATHNAME;
918  TRACE("(%p, %s, %p)\n", hWnd, debugstr_w(path), sec);
919 
920  if (PathIsRelativeW(path))
921  {
922  SetLastError(ret);
923  }
924  else
925  {
927  /* Refuse to work on certain error codes before trying to create directories recursively */
928  if (ret != ERROR_SUCCESS &&
929  ret != ERROR_FILE_EXISTS &&
932  {
933  WCHAR *pEnd, *pSlash, szTemp[MAX_PATH + 1]; /* extra for PathAddBackslash() */
934 
935  lstrcpynW(szTemp, path, MAX_PATH);
936  pEnd = PathAddBackslashW(szTemp);
937  pSlash = szTemp + 3;
938 
939  while (*pSlash)
940  {
941  while (*pSlash && *pSlash != '\\') pSlash++;
942  if (*pSlash)
943  {
944  *pSlash = 0; /* terminate path at separator */
945 
946  ret = SHNotifyCreateDirectoryW(szTemp, pSlash + 1 == pEnd ? sec : NULL);
947  }
948  *pSlash++ = '\\'; /* put the separator back */
949  }
950  }
951 
952  if (ret && hWnd && (ERROR_CANCELLED != ret && ERROR_ALREADY_EXISTS != ret))
953  {
957  }
958  }
959 
960  return ret;
961 }
962 
963 /*************************************************************************
964  * SHFindAttrW [internal]
965  *
966  * Get the Attributes for a file or directory. The difference to GetAttributes()
967  * is that this function will also work for paths containing wildcard characters
968  * in its filename.
969 
970  * PARAMS
971  * path [I] path of directory or file to check
972  * fileOnly [I] TRUE if only files should be found
973  *
974  * RETURNS
975  * INVALID_FILE_ATTRIBUTES if the path does not exist, the actual attributes of
976  * the first file or directory found otherwise
977  */
978 static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly)
979 {
980  WIN32_FIND_DATAW wfd;
981  BOOL b_FileMask = fileOnly && (NULL != StrPBrkW(pName, L"*?"));
983  HANDLE hFind = FindFirstFileW(pName, &wfd);
984 
985  TRACE("%s %d\n", debugstr_w(pName), fileOnly);
986  if (INVALID_HANDLE_VALUE != hFind)
987  {
988  do
989  {
990  if (b_FileMask && IsAttribDir(wfd.dwFileAttributes))
991  continue;
992  dwAttr = wfd.dwFileAttributes;
993  break;
994  } while (FindNextFileW(hFind, &wfd));
995 
996  FindClose(hFind);
997  }
998  return dwAttr;
999 }
1000 
1001 /*************************************************************************
1002  *
1003  * _ConvertAtoW helper function for SHFileOperationA
1004  *
1005  * Converts a string or string-list to unicode.
1006  */
1007 static DWORD _ConvertAtoW(PCSTR strSrc, PCWSTR* pStrDest, BOOL isList)
1008 {
1009  *pStrDest = NULL;
1010 
1011  // If the input is null, nothing to convert.
1012  if (!strSrc)
1013  return 0;
1014 
1015  // Measure the total size, depending on if it's a zero-terminated list.
1016  int sizeA = 0;
1017  if (isList)
1018  {
1019  PCSTR tmpSrc = strSrc;
1020  int size;
1021  do
1022  {
1023  size = lstrlenA(tmpSrc) + 1;
1024  sizeA += size;
1025  tmpSrc += size;
1026  } while (size != 1);
1027  }
1028  else
1029  {
1030  sizeA = lstrlenA(strSrc) + 1;
1031  }
1032 
1033  // Measure the needed allocation size.
1034  int sizeW = MultiByteToWideChar(CP_ACP, 0, strSrc, sizeA, NULL, 0);
1035  if (!sizeW)
1036  return GetLastError();
1037 
1038  PWSTR strDest = (PWSTR) HeapAlloc(GetProcessHeap(), 0, sizeW * sizeof(WCHAR));
1039  if (!strDest)
1040  return ERROR_OUTOFMEMORY;
1041 
1042  int err = MultiByteToWideChar(CP_ACP, 0, strSrc, sizeA, strDest, sizeW);
1043  if (!err)
1044  {
1045  HeapFree(GetProcessHeap(), 0, strDest);
1046  return GetLastError();
1047  }
1048 
1049  *pStrDest = strDest;
1050  return 0;
1051 }
1052 
1053 /*************************************************************************
1054  * SHFileOperationA [SHELL32.@]
1055  *
1056  * Function to copy, move, delete and create one or more files with optional
1057  * user prompts.
1058  *
1059  * PARAMS
1060  * lpFileOp [I/O] pointer to a structure containing all the necessary information
1061  *
1062  * RETURNS
1063  * Success: ERROR_SUCCESS.
1064  * Failure: ERROR_CANCELLED.
1065  *
1066  * NOTES
1067  * exported by name
1068  */
1070 {
1071  int errCode, retCode;
1072  SHFILEOPSTRUCTW nFileOp = { 0 };
1073 
1074  // Convert A information to W
1075  nFileOp.hwnd = lpFileOp->hwnd;
1076  nFileOp.wFunc = lpFileOp->wFunc;
1077  nFileOp.fFlags = lpFileOp->fFlags;
1078 
1079  errCode = _ConvertAtoW(lpFileOp->pFrom, &nFileOp.pFrom, TRUE);
1080  if (errCode != 0)
1081  goto cleanup;
1082 
1083  if (FO_DELETE != (nFileOp.wFunc & FO_MASK))
1084  {
1085  errCode = _ConvertAtoW(lpFileOp->pTo, &nFileOp.pTo, TRUE);
1086  if (errCode != 0)
1087  goto cleanup;
1088  }
1089 
1090  if (nFileOp.fFlags & FOF_SIMPLEPROGRESS)
1091  {
1092  errCode = _ConvertAtoW(lpFileOp->lpszProgressTitle, &nFileOp.lpszProgressTitle, FALSE);
1093  if (errCode != 0)
1094  goto cleanup;
1095  }
1096 
1097  // Call the actual function
1098  retCode = SHFileOperationW(&nFileOp);
1099  if (retCode)
1100  {
1101  ERR("SHFileOperationW failed with 0x%x\n", retCode);
1102  }
1103 
1104  // Cleanup
1105 cleanup:
1106  if (nFileOp.pFrom)
1107  HeapFree(GetProcessHeap(), 0, (PVOID) nFileOp.pFrom);
1108  if (nFileOp.pTo)
1109  HeapFree(GetProcessHeap(), 0, (PVOID) nFileOp.pTo);
1110  if (nFileOp.lpszProgressTitle)
1112 
1113  if (errCode != 0)
1114  {
1115  lpFileOp->fAnyOperationsAborted = TRUE;
1116  SetLastError(errCode);
1117 
1118  return errCode;
1119  }
1120 
1121  // Thankfully, starting with NT4 the name mappings are always unicode, so no need to convert.
1122  lpFileOp->hNameMappings = nFileOp.hNameMappings;
1123  lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
1124  return retCode;
1125 }
1126 
1127 static void __inline grow_list(FILE_LIST *list)
1128 {
1130  list->num_alloc * 2 * sizeof(*newx) );
1131  list->feFiles = newx;
1132  list->num_alloc *= 2;
1133 }
1134 
1135 /* adds a file to the FILE_ENTRY struct
1136  */
1137 static void add_file_to_entry(FILE_ENTRY *feFile, LPCWSTR szFile)
1138 {
1139  DWORD dwLen = lstrlenW(szFile) + 1;
1140  LPCWSTR ptr;
1141  LPCWSTR ptr2;
1142 
1143  feFile->szFullPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
1144  lstrcpyW(feFile->szFullPath, szFile);
1145 
1146  ptr = StrRChrW(szFile, NULL, '\\');
1147  ptr2 = StrRChrW(szFile, NULL, '/');
1148  if (!ptr || ptr < ptr2)
1149  ptr = ptr2;
1150  if (ptr)
1151  {
1152  dwLen = ptr - szFile + 1;
1153  feFile->szDirectory = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
1154  lstrcpynW(feFile->szDirectory, szFile, dwLen);
1155 
1156  dwLen = lstrlenW(feFile->szFullPath) - dwLen + 1;
1157  feFile->szFilename = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
1158  lstrcpyW(feFile->szFilename, ptr + 1); /* skip over backslash */
1159  }
1160  feFile->bFromWildcard = FALSE;
1161 }
1162 
1163 static LPWSTR wildcard_to_file(LPCWSTR szWildCard, LPCWSTR szFileName)
1164 {
1165  LPCWSTR ptr;
1166  LPCWSTR ptr2;
1167  LPWSTR szFullPath;
1168  DWORD dwDirLen, dwFullLen;
1169 
1170  ptr = StrRChrW(szWildCard, NULL, '\\');
1171  ptr2 = StrRChrW(szWildCard, NULL, '/');
1172  if (!ptr || ptr < ptr2)
1173  ptr = ptr2;
1174  dwDirLen = ptr - szWildCard + 1;
1175 
1176  dwFullLen = dwDirLen + lstrlenW(szFileName) + 1;
1177  szFullPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwFullLen * sizeof(WCHAR));
1178 
1179  lstrcpynW(szFullPath, szWildCard, dwDirLen + 1);
1180  lstrcatW(szFullPath, szFileName);
1181 
1182  return szFullPath;
1183 }
1184 
1185 static void parse_wildcard_files(FILE_LIST *flList, LPCWSTR szFile, LPDWORD pdwListIndex)
1186 {
1187  WIN32_FIND_DATAW wfd;
1188  HANDLE hFile = FindFirstFileW(szFile, &wfd);
1189  FILE_ENTRY *file;
1190  LPWSTR szFullPath;
1191  BOOL res;
1192 
1193  if (hFile == INVALID_HANDLE_VALUE) return;
1194 
1195  for (res = TRUE; res; res = FindNextFileW(hFile, &wfd))
1196  {
1197  if (IsDotDir(wfd.cFileName))
1198  continue;
1199 
1200  if (*pdwListIndex >= flList->num_alloc)
1201  grow_list( flList );
1202 
1203  szFullPath = wildcard_to_file(szFile, wfd.cFileName);
1204  file = &flList->feFiles[(*pdwListIndex)++];
1205  add_file_to_entry(file, szFullPath);
1206  file->bFromWildcard = TRUE;
1207  file->attributes = wfd.dwFileAttributes;
1208 
1209  if (IsAttribDir(file->attributes))
1210  flList->bAnyDirectories = TRUE;
1211 
1212  HeapFree(GetProcessHeap(), 0, szFullPath);
1213  }
1214 
1215  FindClose(hFile);
1216 }
1217 
1218 /* takes the null-separated file list and fills out the FILE_LIST */
1220 {
1221  LPCWSTR ptr = szFiles;
1222  WCHAR szCurFile[MAX_PATH];
1223  DWORD i = 0;
1224 
1225  if (!szFiles)
1226  return ERROR_INVALID_PARAMETER;
1227 
1228  flList->bAnyFromWildcard = FALSE;
1229  flList->bAnyDirectories = FALSE;
1230  flList->bAnyDontExist = FALSE;
1231  flList->num_alloc = 32;
1232  flList->dwNumFiles = 0;
1233 
1234  /* empty list */
1235  if (!szFiles[0])
1236  return ERROR_ACCESS_DENIED;
1237 
1239  flList->num_alloc * sizeof(FILE_ENTRY));
1240 
1241  while (*ptr)
1242  {
1243  if (i >= flList->num_alloc) grow_list( flList );
1244 
1245  /* change relative to absolute path */
1246  if (PathIsRelativeW(ptr))
1247  {
1248  GetCurrentDirectoryW(MAX_PATH, szCurFile);
1249  PathCombineW(szCurFile, szCurFile, ptr);
1250  flList->feFiles[i].bFromRelative = TRUE;
1251  }
1252  else
1253  {
1254  lstrcpyW(szCurFile, ptr);
1255  flList->feFiles[i].bFromRelative = FALSE;
1256  }
1257 
1258  /* parse wildcard files if they are in the filename */
1259  if (StrPBrkW(szCurFile, L"*?"))
1260  {
1261  parse_wildcard_files(flList, szCurFile, &i);
1262  flList->bAnyFromWildcard = TRUE;
1263  i--;
1264  }
1265  else
1266  {
1267  FILE_ENTRY *file = &flList->feFiles[i];
1268  add_file_to_entry(file, szCurFile);
1269  file->attributes = GetFileAttributesW( file->szFullPath );
1270  file->bExists = (file->attributes != INVALID_FILE_ATTRIBUTES);
1271 
1272  if (!file->bExists)
1273  flList->bAnyDontExist = TRUE;
1274 
1275  if (IsAttribDir(file->attributes))
1276  flList->bAnyDirectories = TRUE;
1277  }
1278 
1279  /* advance to the next string */
1280  ptr += lstrlenW(ptr) + 1;
1281  i++;
1282  }
1283  flList->dwNumFiles = i;
1284 
1285  return S_OK;
1286 }
1287 
1288 /* free the FILE_LIST */
1289 static void destroy_file_list(FILE_LIST *flList)
1290 {
1291  DWORD i;
1292 
1293  if (!flList || !flList->feFiles)
1294  return;
1295 
1296  for (i = 0; i < flList->dwNumFiles; i++)
1297  {
1298  HeapFree(GetProcessHeap(), 0, flList->feFiles[i].szDirectory);
1299  HeapFree(GetProcessHeap(), 0, flList->feFiles[i].szFilename);
1300  HeapFree(GetProcessHeap(), 0, flList->feFiles[i].szFullPath);
1301  }
1302 
1303  HeapFree(GetProcessHeap(), 0, flList->feFiles);
1304 }
1305 
1307 {
1308  CStringW mask(szDestPath);
1309  CStringW ext(PathFindExtensionW(szDestPath));
1310 
1311  // cut off extension before inserting a "new file" mask
1312  if (!ext.IsEmpty())
1313  {
1314  mask = mask.Left(mask.GetLength() - ext.GetLength());
1315  }
1316  mask += L" (%d)" + ext;
1317 
1318  CStringW newName;
1319 
1320  // trying to find new file name
1321  for (int i = 1; i < NEW_FILENAME_ON_COPY_TRIES; i++)
1322  {
1323  newName.Format(mask, i);
1324 
1325  if (!PathFileExistsW(newName))
1326  {
1327  return newName;
1328  }
1329  }
1330 
1331  return CStringW();
1332 }
1333 
1334 static void copy_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWSTR szDestPath)
1335 {
1336  WCHAR szFrom[MAX_PATH], szTo[MAX_PATH];
1337  FILE_LIST flFromNew, flToNew;
1338 
1339  if (IsDotDir(feFrom->szFilename))
1340  return;
1341 
1342  if (PathFileExistsW(szDestPath))
1343  PathCombineW(szTo, szDestPath, feFrom->szFilename);
1344  else
1345  lstrcpyW(szTo, szDestPath);
1346 
1347 #ifdef __REACTOS__
1348  if (PathFileExistsW(szTo))
1349  {
1350  if (op->req->fFlags & FOF_RENAMEONCOLLISION)
1351  {
1352  CStringW newPath = try_find_new_name(szTo);
1353  if (!newPath.IsEmpty())
1354  {
1355  StringCchCopyW(szTo, _countof(szTo), newPath);
1356  }
1357  }
1358  else if (!(op->req->fFlags & FOF_NOCONFIRMATION))
1359 #else
1360  if (!(op->req->fFlags & FOF_NOCONFIRMATION) && PathFileExistsW(szTo))
1361  {
1362  CStringW newPath;
1363  if (lstrcmp(feFrom->szDirectory, szDestPath) == 0 && !(newPath = try_find_new_name(szTo)).IsEmpty())
1364  {
1365  StringCchCopyW(szTo, _countof(szTo), newPath);
1366  }
1367  else
1368 #endif
1369  {
1370  if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FOLDER, feFrom->szFilename, op))
1371  {
1372  /* Vista returns an ERROR_CANCELLED even if user pressed "No" */
1373  if (!op->bManyItems)
1374  op->bCancelled = TRUE;
1375  return;
1376  }
1377  }
1378  }
1379 
1380  szTo[lstrlenW(szTo) + 1] = '\0';
1382 
1383  PathCombineW(szFrom, feFrom->szFullPath, L"*.*");
1384  szFrom[lstrlenW(szFrom) + 1] = '\0';
1385 
1386  ZeroMemory(&flFromNew, sizeof(FILE_LIST));
1387  ZeroMemory(&flToNew, sizeof(FILE_LIST));
1388  parse_file_list(&flFromNew, szFrom);
1389  parse_file_list(&flToNew, szTo);
1390 
1391  copy_files(op, FALSE, &flFromNew, &flToNew);
1392 
1393  destroy_file_list(&flFromNew);
1394  destroy_file_list(&flToNew);
1395 }
1396 
1397 static BOOL copy_file_to_file(FILE_OPERATION *op, const WCHAR *szFrom, const WCHAR *szTo)
1398 {
1399 #ifdef __REACTOS__
1400  if (PathFileExistsW(szTo))
1401  {
1402  if (op->req->fFlags & FOF_RENAMEONCOLLISION)
1403  {
1404  CStringW newPath = try_find_new_name(szTo);
1405  if (!newPath.IsEmpty())
1406  {
1407  return SHNotifyCopyFileW(op, szFrom, newPath, FALSE) == 0;
1408  }
1409  }
1410  else if (!(op->req->fFlags & FOF_NOCONFIRMATION))
1411  {
1413  return FALSE;
1414  }
1415 #else
1416  if (!(op->req->fFlags & FOF_NOCONFIRMATION) && PathFileExistsW(szTo))
1417  {
1418  CStringW newPath;
1419  if (lstrcmp(szFrom, szTo) == 0 && !(newPath = try_find_new_name(szTo)).IsEmpty())
1420  {
1421  return SHNotifyCopyFileW(op, szFrom, newPath, FALSE) == 0;
1422  }
1423 
1425  return FALSE;
1426 #endif
1427  }
1428 
1429  return SHNotifyCopyFileW(op, szFrom, szTo, FALSE) == 0;
1430 }
1431 
1432 /* copy a file or directory to another directory */
1433 static void copy_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo)
1434 {
1435  if (!PathFileExistsW(feTo->szFullPath))
1437 
1438  if (IsAttribFile(feFrom->attributes))
1439  {
1440  WCHAR szDestPath[MAX_PATH];
1441 
1442  PathCombineW(szDestPath, feTo->szFullPath, feFrom->szFilename);
1443  copy_file_to_file(op, feFrom->szFullPath, szDestPath);
1444  }
1445  else if (!(op->req->fFlags & FOF_FILESONLY && feFrom->bFromWildcard))
1446  copy_dir_to_dir(op, feFrom, feTo->szFullPath);
1447 }
1448 
1449 static void create_dest_dirs(LPCWSTR szDestDir)
1450 {
1451  WCHAR dir[MAX_PATH];
1452  LPCWSTR ptr = StrChrW(szDestDir, '\\');
1453 
1454  /* make sure all directories up to last one are created */
1455  while (ptr && (ptr = StrChrW(ptr + 1, '\\')))
1456  {
1457  lstrcpynW(dir, szDestDir, ptr - szDestDir + 1);
1458 
1459  if (!PathFileExistsW(dir))
1461  }
1462 
1463  /* create last directory */
1464  if (!PathFileExistsW(szDestDir))
1465  SHNotifyCreateDirectoryW(szDestDir, NULL);
1466 }
1467 
1468 /* the FO_COPY operation */
1469 static HRESULT copy_files(FILE_OPERATION *op, BOOL multiDest, const FILE_LIST *flFrom, FILE_LIST *flTo)
1470 {
1471  DWORD i;
1472  const FILE_ENTRY *entryToCopy;
1473  const FILE_ENTRY *fileDest = &flTo->feFiles[0];
1474 
1475  if (flFrom->bAnyDontExist)
1477 
1478  if (flTo->dwNumFiles == 0)
1479  {
1480  /* If the destination is empty, SHFileOperation should use the current directory */
1481  WCHAR curdir[MAX_PATH+1];
1482 
1483  GetCurrentDirectoryW(MAX_PATH, curdir);
1484  curdir[lstrlenW(curdir)+1] = 0;
1485 
1486  destroy_file_list(flTo);
1487  ZeroMemory(flTo, sizeof(FILE_LIST));
1488  parse_file_list(flTo, curdir);
1489  fileDest = &flTo->feFiles[0];
1490  }
1491 
1492  if (multiDest)
1493  {
1494  if (flFrom->bAnyFromWildcard)
1495  return ERROR_CANCELLED;
1496 
1497  if (flFrom->dwNumFiles != flTo->dwNumFiles)
1498  {
1499  if (flFrom->dwNumFiles != 1 && !IsAttribDir(fileDest->attributes))
1500  return ERROR_CANCELLED;
1501 
1502  /* Free all but the first entry. */
1503  for (i = 1; i < flTo->dwNumFiles; i++)
1504  {
1506  HeapFree(GetProcessHeap(), 0, flTo->feFiles[i].szFilename);
1507  HeapFree(GetProcessHeap(), 0, flTo->feFiles[i].szFullPath);
1508  }
1509 
1510  flTo->dwNumFiles = 1;
1511  }
1512  else if (IsAttribDir(fileDest->attributes))
1513  {
1514  for (i = 1; i < flTo->dwNumFiles; i++)
1515  if (!IsAttribDir(flTo->feFiles[i].attributes) ||
1516  !IsAttribDir(flFrom->feFiles[i].attributes))
1517  {
1518  return ERROR_CANCELLED;
1519  }
1520  }
1521  }
1522  else if (flFrom->dwNumFiles != 1)
1523  {
1524  if (flTo->dwNumFiles != 1 && !IsAttribDir(fileDest->attributes))
1525  return ERROR_CANCELLED;
1526 
1527  if (PathFileExistsW(fileDest->szFullPath) &&
1528  IsAttribFile(fileDest->attributes))
1529  {
1530  return ERROR_CANCELLED;
1531  }
1532 
1533  if (flTo->dwNumFiles == 1 && fileDest->bFromRelative &&
1534  !PathFileExistsW(fileDest->szFullPath))
1535  {
1536  return ERROR_CANCELLED;
1537  }
1538  }
1539 
1540  for (i = 0; i < flFrom->dwNumFiles; i++)
1541  {
1542  entryToCopy = &flFrom->feFiles[i];
1543 
1544  if ((multiDest) &&
1545  flTo->dwNumFiles > 1)
1546  {
1547  fileDest = &flTo->feFiles[i];
1548  }
1549 
1550  if (IsAttribDir(entryToCopy->attributes) &&
1551  !lstrcmpiW(entryToCopy->szFullPath, fileDest->szDirectory))
1552  {
1553  return ERROR_SUCCESS;
1554  }
1555 
1556  create_dest_dirs(fileDest->szDirectory);
1557 
1558  if (!lstrcmpiW(entryToCopy->szFullPath, fileDest->szFullPath))
1559  {
1560  if (IsAttribFile(entryToCopy->attributes))
1562  else
1563  return ERROR_SUCCESS;
1564  }
1565 
1566  if ((flFrom->dwNumFiles > 1 && flTo->dwNumFiles == 1) ||
1567  IsAttribDir(fileDest->attributes))
1568  {
1569  copy_to_dir(op, entryToCopy, fileDest);
1570  }
1571  else if (IsAttribDir(entryToCopy->attributes))
1572  {
1573  copy_dir_to_dir(op, entryToCopy, fileDest->szFullPath);
1574  }
1575  else
1576  {
1577  if (!copy_file_to_file(op, entryToCopy->szFullPath, fileDest->szFullPath))
1578  {
1579  op->req->fAnyOperationsAborted = TRUE;
1580  return ERROR_CANCELLED;
1581  }
1582  }
1583 
1584  if (op->progress != NULL)
1585  op->bCancelled |= op->progress->HasUserCancelled();
1586  /* Vista return code. XP would return e.g. ERROR_FILE_NOT_FOUND, ERROR_ALREADY_EXISTS */
1587  if (op->bCancelled)
1588  return ERROR_CANCELLED;
1589  }
1590 
1591  /* Vista return code. On XP if the used pressed "No" for the last item,
1592  * ERROR_ARENA_TRASHED would be returned */
1593  return ERROR_SUCCESS;
1594 }
1595 
1596 static BOOL confirm_delete_list(HWND hWnd, DWORD fFlags, BOOL fTrash, const FILE_LIST *flFrom)
1597 {
1598  if (flFrom->dwNumFiles > 1)
1599  {
1600  WCHAR tmp[8];
1601 
1602  wnsprintfW(tmp, sizeof(tmp)/sizeof(tmp[0]), L"%d", flFrom->dwNumFiles);
1604  }
1605  else
1606  {
1607  const FILE_ENTRY *fileEntry = &flFrom->feFiles[0];
1608 
1609  if (IsAttribFile(fileEntry->attributes))
1610  return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_FILE:ASK_DELETE_FILE), fileEntry->szFullPath, NULL);
1611  else if (!(fFlags & FOF_FILESONLY && fileEntry->bFromWildcard))
1613  }
1614  return TRUE;
1615 }
1616 
1617 /* the FO_DELETE operation */
1619 {
1620  const FILE_ENTRY *fileEntry;
1621  DWORD i;
1622  BOOL bPathExists;
1623  BOOL bTrash;
1624 
1625  if (!flFrom->dwNumFiles)
1626  return ERROR_SUCCESS;
1627 
1628  /* Windows also checks only the first item */
1629  bTrash = (op->req->fFlags & FOF_ALLOWUNDO)
1630  && TRASH_CanTrashFile(flFrom->feFiles[0].szFullPath);
1631 
1632  if (!(op->req->fFlags & FOF_NOCONFIRMATION) || (!bTrash && op->req->fFlags & FOF_WANTNUKEWARNING))
1633  if (!confirm_delete_list(op->req->hwnd, op->req->fFlags, bTrash, flFrom))
1634  {
1635  op->req->fAnyOperationsAborted = TRUE;
1636  return 0;
1637  }
1638 
1639  /* Check files. Do not delete one if one file does not exists */
1640  for (i = 0; i < flFrom->dwNumFiles; i++)
1641  {
1642  fileEntry = &flFrom->feFiles[i];
1643 
1644  if (fileEntry->attributes == (ULONG)-1)
1645  {
1646  // This is a windows 2003 server specific value which has been removed.
1647  // Later versions of windows return ERROR_FILE_NOT_FOUND.
1649  }
1650  }
1651 
1652  for (i = 0; i < flFrom->dwNumFiles; i++)
1653  {
1654  bPathExists = TRUE;
1655  fileEntry = &flFrom->feFiles[i];
1656 
1657  if (!IsAttribFile(fileEntry->attributes) &&
1658  (op->req->fFlags & FOF_FILESONLY && fileEntry->bFromWildcard))
1659  continue;
1660 
1661  if (bTrash)
1662  {
1663  BOOL bDelete;
1664  if (TRASH_TrashFile(fileEntry->szFullPath))
1665  {
1667  continue;
1668  }
1669 
1670  /* Note: Windows silently deletes the file in such a situation, we show a dialog */
1671  if (!(op->req->fFlags & FOF_NOCONFIRMATION) || (op->req->fFlags & FOF_WANTNUKEWARNING))
1672  bDelete = SHELL_ConfirmDialogW(op->req->hwnd, ASK_CANT_TRASH_ITEM, fileEntry->szFullPath, NULL);
1673  else
1674  bDelete = TRUE;
1675 
1676  if (!bDelete)
1677  {
1678  op->req->fAnyOperationsAborted = TRUE;
1679  break;
1680  }
1681  }
1682 
1683  /* delete the file or directory */
1684  if (IsAttribFile(fileEntry->attributes))
1685  {
1686  bPathExists = (ERROR_SUCCESS == SHNotifyDeleteFileW(op, fileEntry->szFullPath));
1687  }
1688  else
1689  bPathExists = SHELL_DeleteDirectoryW(op, fileEntry->szFullPath, FALSE);
1690 
1691  if (!bPathExists)
1692  {
1693  DWORD err = GetLastError();
1694 
1695  if (ERROR_FILE_NOT_FOUND == err)
1696  {
1697  // This is a windows 2003 server specific value which ahs been removed.
1698  // Later versions of windows return ERROR_FILE_NOT_FOUND.
1700  }
1701  else
1702  {
1703  return err;
1704  }
1705  }
1706 
1707  if (op->progress != NULL)
1708  op->bCancelled |= op->progress->HasUserCancelled();
1709  /* Should fire on progress dialog only */
1710  if (op->bCancelled)
1711  return ERROR_CANCELLED;
1712  }
1713 
1714  return ERROR_SUCCESS;
1715 }
1716 
1717 static void move_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWSTR szDestPath)
1718 {
1719  WCHAR szFrom[MAX_PATH], szTo[MAX_PATH];
1720  FILE_LIST flFromNew, flToNew;
1721 
1722  if (IsDotDir(feFrom->szFilename))
1723  return;
1724 
1725  SHNotifyCreateDirectoryW(szDestPath, NULL);
1726 
1727  PathCombineW(szFrom, feFrom->szFullPath, L"*.*");
1728  szFrom[lstrlenW(szFrom) + 1] = '\0';
1729 
1730  lstrcpyW(szTo, szDestPath);
1731  szTo[lstrlenW(szDestPath) + 1] = '\0';
1732 
1733  ZeroMemory(&flFromNew, sizeof(FILE_LIST));
1734  ZeroMemory(&flToNew, sizeof(FILE_LIST));
1735  parse_file_list(&flFromNew, szFrom);
1736  parse_file_list(&flToNew, szTo);
1737 
1738  move_files(op, FALSE, &flFromNew, &flToNew);
1739 
1740  destroy_file_list(&flFromNew);
1741  destroy_file_list(&flToNew);
1742 
1743  if (PathIsDirectoryEmptyW(feFrom->szFullPath))
1745 }
1746 
1747 /* moves a file or directory to another directory */
1748 static void move_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo)
1749 {
1750  WCHAR szDestPath[MAX_PATH];
1751 
1752  PathCombineW(szDestPath, feTo->szFullPath, feFrom->szFilename);
1753 
1754  if (IsAttribFile(feFrom->attributes))
1755  SHNotifyMoveFileW(op, feFrom->szFullPath, szDestPath, FALSE);
1756  else if (!(op->req->fFlags & FOF_FILESONLY && feFrom->bFromWildcard))
1757  move_dir_to_dir(op, feFrom, szDestPath);
1758 }
1759 
1760 /* the FO_MOVE operation */
1761 static DWORD move_files(FILE_OPERATION *op, BOOL multiDest, const FILE_LIST *flFrom, const FILE_LIST *flTo)
1762 {
1763  DWORD i;
1764  INT mismatched = 0;
1765 
1766  const FILE_ENTRY *entryToMove;
1767  const FILE_ENTRY *fileDest;
1768 
1769  if (!flFrom->dwNumFiles)
1770  return ERROR_SUCCESS;
1771 
1772  if (!flTo->dwNumFiles)
1773  return ERROR_FILE_NOT_FOUND;
1774 
1775  if (!(multiDest) &&
1776  flTo->dwNumFiles > 1 && flFrom->dwNumFiles > 1)
1777  {
1778  return ERROR_CANCELLED;
1779  }
1780 
1781  if (!(multiDest) &&
1782  !flFrom->bAnyDirectories &&
1783  flFrom->dwNumFiles > flTo->dwNumFiles &&
1784  !(flTo->bAnyDirectories && flTo->dwNumFiles == 1))
1785  {
1786  return ERROR_CANCELLED;
1787  }
1788 
1789  if (!PathFileExistsW(flTo->feFiles[0].szDirectory))
1790  return ERROR_CANCELLED;
1791 
1792  if (multiDest)
1793  mismatched = flFrom->dwNumFiles - flTo->dwNumFiles;
1794 
1795  fileDest = &flTo->feFiles[0];
1796  for (i = 0; i < flFrom->dwNumFiles; i++)
1797  {
1798  entryToMove = &flFrom->feFiles[i];
1799 
1800  if (!PathFileExistsW(fileDest->szDirectory))
1801  return ERROR_CANCELLED;
1802 
1803  if (multiDest)
1804  {
1805  if (i >= flTo->dwNumFiles)
1806  break;
1807  fileDest = &flTo->feFiles[i];
1808  if (mismatched && !fileDest->bExists)
1809  {
1811  flTo->feFiles[i].bExists = TRUE;
1813  }
1814  }
1815 
1816  if (fileDest->bExists && IsAttribDir(fileDest->attributes))
1817  move_to_dir(op, entryToMove, fileDest);
1818  else
1819  SHNotifyMoveFileW(op, entryToMove->szFullPath, fileDest->szFullPath, IsAttribDir(entryToMove->attributes));
1820 
1821  if (op->progress != NULL)
1822  op->bCancelled |= op->progress->HasUserCancelled();
1823  /* Should fire on progress dialog only */
1824  if (op->bCancelled)
1825  return ERROR_CANCELLED;
1826 
1827  }
1828 
1829  if (mismatched > 0)
1830  {
1831  if (flFrom->bAnyDirectories)
1832  return DE_DESTSAMETREE;
1833  else
1834  return DE_SAMEFILE;
1835  }
1836 
1837  return ERROR_SUCCESS;
1838 }
1839 
1840 /* the FO_RENAME files */
1841 static HRESULT rename_files(FILE_OPERATION *op, const FILE_LIST *flFrom, const FILE_LIST *flTo)
1842 {
1843  const FILE_ENTRY *feFrom;
1844  const FILE_ENTRY *feTo;
1845 
1846  if (flFrom->dwNumFiles != 1)
1847  return ERROR_GEN_FAILURE;
1848 
1849  if (flTo->dwNumFiles != 1)
1850  return ERROR_CANCELLED;
1851 
1852  feFrom = &flFrom->feFiles[0];
1853  feTo= &flTo->feFiles[0];
1854 
1855  /* fail if destination doesn't exist */
1856  if (!feFrom->bExists)
1858 
1859  /* fail if destination already exists */
1860  if (feTo->bExists)
1861  return ERROR_ALREADY_EXISTS;
1862 
1863  return SHNotifyMoveFileW(op, feFrom->szFullPath, feTo->szFullPath, IsAttribDir(feFrom->attributes));
1864 }
1865 
1866 /* alert the user if an unsupported flag is used */
1867 static void check_flags(FILEOP_FLAGS fFlags)
1868 {
1869  WORD wUnsupportedFlags = FOF_NO_CONNECTED_ELEMENTS |
1871 #ifdef __REACTOS__
1873 #else
1875 #endif
1876 
1877  if (fFlags & wUnsupportedFlags)
1878  FIXME("Unsupported flags: %04x\n", fFlags);
1879 }
1880 
1881 #ifdef __REACTOS__
1882 
1883 static DWORD
1884 validate_operation(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LIST *flTo)
1885 {
1886  DWORD i, k, dwNumDest;
1887  WCHAR szFrom[MAX_PATH], szTo[MAX_PATH];
1888  CStringW strTitle, strText;
1889  const FILE_ENTRY *feFrom;
1890  const FILE_ENTRY *feTo;
1891  UINT wFunc = lpFileOp->wFunc;
1892  HWND hwnd = lpFileOp->hwnd;
1893 
1894  dwNumDest = flTo->dwNumFiles;
1895 
1896  if (wFunc != FO_COPY && wFunc != FO_MOVE)
1897  return ERROR_SUCCESS;
1898 
1899  for (k = 0; k < dwNumDest; ++k)
1900  {
1901  feTo = &flTo->feFiles[k];
1902  for (i = 0; i < flFrom->dwNumFiles; ++i)
1903  {
1904  feFrom = &flFrom->feFiles[i];
1905  StringCbCopyW(szFrom, sizeof(szFrom), feFrom->szFullPath);
1906  StringCbCopyW(szTo, sizeof(szTo), feTo->szFullPath);
1907  if (IsAttribDir(feTo->attributes))
1908  {
1909  PathAppendW(szTo, feFrom->szFilename);
1910  }
1911 
1912  // same path?
1913  if (lstrcmpiW(szFrom, szTo) == 0 &&
1914  (wFunc == FO_MOVE || !(lpFileOp->fFlags & FOF_RENAMEONCOLLISION)))
1915  {
1916  if (!(lpFileOp->fFlags & (FOF_NOERRORUI | FOF_SILENT)))
1917  {
1918  if (wFunc == FO_MOVE)
1919  {
1920  strTitle.LoadStringW(IDS_MOVEERRORTITLE);
1921  if (IsAttribDir(feFrom->attributes))
1922  strText.Format(IDS_MOVEERRORSAMEFOLDER, feFrom->szFilename);
1923  else
1924  strText.Format(IDS_MOVEERRORSAME, feFrom->szFilename);
1925  }
1926  else
1927  {
1928  strTitle.LoadStringW(IDS_COPYERRORTITLE);
1929  strText.Format(IDS_COPYERRORSAME, feFrom->szFilename);
1930  return ERROR_SUCCESS;
1931  }
1932  MessageBoxW(hwnd, strText, strTitle, MB_ICONERROR);
1933  return DE_SAMEFILE;
1934  }
1935  return DE_OPCANCELLED;
1936  }
1937 
1938  // subfolder?
1939  if (IsAttribDir(feFrom->attributes))
1940  {
1941  size_t cchFrom = PathAddBackslashW(szFrom) - szFrom;
1942  size_t cchTo = PathAddBackslashW(szTo) - szTo;
1943  if (cchFrom <= cchTo)
1944  {
1945  WCHAR ch = szTo[cchFrom];
1946  szTo[cchFrom] = 0;
1947  int compare = lstrcmpiW(szFrom, szTo);
1948  szTo[cchFrom] = ch;
1949 
1950  if (compare == 0)
1951  {
1952  if (!(lpFileOp->fFlags & (FOF_NOERRORUI | FOF_SILENT)))
1953  {
1954  if (wFunc == FO_MOVE)
1955  {
1956  strTitle.LoadStringW(IDS_MOVEERRORTITLE);
1957  strText.Format(IDS_MOVEERRORSUBFOLDER, feFrom->szFilename);
1958  }
1959  else
1960  {
1961  strTitle.LoadStringW(IDS_COPYERRORTITLE);
1962  strText.Format(IDS_COPYERRORSUBFOLDER, feFrom->szFilename);
1963  }
1964  MessageBoxW(hwnd, strText, strTitle, MB_ICONERROR);
1965  return DE_DESTSUBTREE;
1966  }
1967  return DE_OPCANCELLED;
1968  }
1969  }
1970  }
1971  }
1972  }
1973 
1974  return ERROR_SUCCESS;
1975 }
1976 #endif
1977 /*************************************************************************
1978  * SHFileOperationW [SHELL32.@]
1979  *
1980  * See SHFileOperationA
1981  */
1983 {
1985  FILE_LIST flFrom, flTo;
1986  int ret = 0;
1987 
1988  if (!lpFileOp)
1989  return ERROR_INVALID_PARAMETER;
1990 
1991  ret = CoInitialize(NULL);
1992  if (FAILED(ret))
1993  return ret;
1994 
1995  lpFileOp->fAnyOperationsAborted = FALSE;
1996  check_flags(lpFileOp->fFlags);
1997 
1998  ZeroMemory(&flFrom, sizeof(FILE_LIST));
1999  ZeroMemory(&flTo, sizeof(FILE_LIST));
2000 
2001  if ((ret = parse_file_list(&flFrom, lpFileOp->pFrom)))
2002  return ret;
2003 
2004  if (lpFileOp->wFunc != FO_DELETE)
2005  parse_file_list(&flTo, lpFileOp->pTo);
2006 
2007  ZeroMemory(&op, sizeof(op));
2008  op.req = lpFileOp;
2009  op.totalSize.QuadPart = 0ull;
2010  op.completedSize.QuadPart = 0ull;
2011  op.bManyItems = (flFrom.dwNumFiles > 1);
2012 
2013 #ifdef __REACTOS__
2014  ret = validate_operation(lpFileOp, &flFrom, &flTo);
2015  if (ret)
2016  goto cleanup;
2017 #endif
2018  if (lpFileOp->wFunc != FO_RENAME && !(lpFileOp->fFlags & FOF_SILENT)) {
2019  ret = CoCreateInstance(CLSID_ProgressDialog,
2020  NULL,
2021  CLSCTX_INPROC_SERVER,
2022  IID_PPV_ARG(IProgressDialog, &op.progress));
2023  if (FAILED(ret))
2024  goto cleanup;
2025 
2026  op.progress->StartProgressDialog(op.req->hwnd, NULL, PROGDLG_NORMAL & PROGDLG_AUTOTIME, NULL);
2028  _FileOpCountManager(&op, &flFrom);
2029  }
2030 
2031  switch (lpFileOp->wFunc)
2032  {
2033  case FO_COPY:
2034  ret = copy_files(&op, op.req->fFlags & FOF_MULTIDESTFILES, &flFrom, &flTo);
2035  break;
2036  case FO_DELETE:
2037  ret = delete_files(&op, &flFrom);
2038  break;
2039  case FO_MOVE:
2040  ret = move_files(&op, op.req->fFlags & FOF_MULTIDESTFILES, &flFrom, &flTo);
2041  break;
2042  case FO_RENAME:
2043  ret = rename_files(&op, &flFrom, &flTo);
2044  break;
2045  default:
2047  break;
2048  }
2049 
2050  if (op.progress) {
2051  op.progress->StopProgressDialog();
2052  op.progress->Release();
2053  }
2054 
2055 cleanup:
2056  destroy_file_list(&flFrom);
2057 
2058  if (lpFileOp->wFunc != FO_DELETE)
2059  destroy_file_list(&flTo);
2060 
2061  if (ret == ERROR_CANCELLED)
2062  lpFileOp->fAnyOperationsAborted = TRUE;
2063 
2064  CoUninitialize();
2065 
2066  return ret;
2067 }
2068 
2069 // Used by SHFreeNameMappings
2070 static int CALLBACK _DestroyCallback(void *p, void *pData)
2071 {
2073 
2074  SHFree(lp->pszOldPath);
2075  SHFree(lp->pszNewPath);
2076 
2077  return TRUE;
2078 }
2079 
2080 /*************************************************************************
2081  * SHFreeNameMappings [shell32.246]
2082  *
2083  * Free the mapping handle returned by SHFileOperation if FOF_WANTSMAPPINGHANDLE
2084  * was specified.
2085  *
2086  * PARAMS
2087  * hNameMapping [I] handle to the name mappings used during renaming of files
2088  *
2089  * RETURNS
2090  * Nothing
2091  */
2093 {
2094  if (hNameMapping)
2095  {
2096  DSA_DestroyCallback((HDSA) hNameMapping, _DestroyCallback, NULL);
2097  }
2098 }
2099 
2100 /*************************************************************************
2101  * SheGetDirA [SHELL32.@]
2102  *
2103  * drive = 0: returns the current directory path
2104  * drive > 0: returns the current directory path of the specified drive
2105  * drive=1 -> A: drive=2 -> B: ...
2106  * returns 0 if successful
2107 */
2109 {
2110  WCHAR org_path[MAX_PATH];
2111  DWORD ret;
2112  char drv_path[3];
2113 
2114  /* change current directory to the specified drive */
2115  if (drive) {
2116  strcpy(drv_path, "A:");
2117  drv_path[0] += (char)drive-1;
2118 
2119  GetCurrentDirectoryW(MAX_PATH, org_path);
2120 
2121  SetCurrentDirectoryA(drv_path);
2122  }
2123 
2124  /* query current directory path of the specified drive */
2126 
2127  /* back to the original drive */
2128  if (drive)
2129  SetCurrentDirectoryW(org_path);
2130 
2131  if (!ret)
2132  return GetLastError();
2133 
2134  return 0;
2135 }
2136 
2137 /*************************************************************************
2138  * SheGetDirW [SHELL32.@]
2139  *
2140  * drive = 0: returns the current directory path
2141  * drive > 0: returns the current directory path of the specified drive
2142  * drive=1 -> A: drive=2 -> B: ...
2143  * returns 0 if successful
2144  */
2146 {
2147  WCHAR org_path[MAX_PATH];
2148  DWORD ret;
2149  char drv_path[3];
2150 
2151  /* change current directory to the specified drive */
2152  if (drive)
2153  {
2154  strcpy(drv_path, "A:");
2155  drv_path[0] += (char)drive-1;
2156 
2157  GetCurrentDirectoryW(MAX_PATH, org_path);
2158 
2159  SetCurrentDirectoryA(drv_path);
2160  }
2161 
2162  /* query current directory path of the specified drive */
2164 
2165  /* back to the original drive */
2166  if (drive)
2167  SetCurrentDirectoryW(org_path);
2168 
2169  if (!ret)
2170  return GetLastError();
2171 
2172  return 0;
2173 }
2174 
2175 /*************************************************************************
2176  * SheChangeDirA [SHELL32.@]
2177  *
2178  * changes the current directory to the specified path
2179  * and returns 0 if successful
2180  */
2182 {
2184  return 0;
2185  else
2186  return GetLastError();
2187 }
2188 
2189 /*************************************************************************
2190  * SheChangeDirW [SHELL32.@]
2191  *
2192  * changes the current directory to the specified path
2193  * and returns 0 if successful
2194  */
2196 {
2198  return 0;
2199  else
2200  return GetLastError();
2201 }
2202 
2203 /*************************************************************************
2204  * IsNetDrive [SHELL32.66]
2205  */
2207 {
2208  char root[4];
2209  strcpy(root, "A:\\");
2210  root[0] += (char)drive;
2211  return (GetDriveTypeA(root) == DRIVE_REMOTE);
2212 }
2213 
2214 
2215 /*************************************************************************
2216  * RealDriveType [SHELL32.524]
2217  */
2219 {
2220  char root[] = "A:\\";
2221  root[0] += (char)drive;
2222  return GetDriveTypeA(root);
2223 }
2224 
2225 /***********************************************************************
2226  * SHPathPrepareForWriteW (SHELL32.@)
2227  */
2229 {
2230  DWORD res;
2231  DWORD err;
2232  LPCWSTR realpath;
2233  int len;
2234  WCHAR* last_slash;
2235  WCHAR* temppath=NULL;
2236 
2237  TRACE("%p %p %s 0x%08x\n", hwnd, modless, debugstr_w(path), flags);
2238 
2240  FIXME("unimplemented flags 0x%08x\n", flags);
2241 
2242  /* cut off filename if necessary */
2244  {
2245  last_slash = StrRChrW(path, NULL, '\\');
2246  if (last_slash == NULL)
2247  len = 1;
2248  else
2249  len = last_slash - path + 1;
2250  temppath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2251  if (!temppath)
2252  return E_OUTOFMEMORY;
2253  StrCpyNW(temppath, path, len);
2254  realpath = temppath;
2255  }
2256  else
2257  {
2258  realpath = path;
2259  }
2260 
2261  /* try to create the directory if asked to */
2263  {
2264  if (flags & SHPPFW_ASKDIRCREATE)
2265  FIXME("treating SHPPFW_ASKDIRCREATE as SHPPFW_DIRCREATE\n");
2266 
2267  SHCreateDirectoryExW(0, realpath, NULL);
2268  }
2269 
2270  /* check if we can access the directory */
2271  res = GetFileAttributesW(realpath);
2272 
2273  HeapFree(GetProcessHeap(), 0, temppath);
2274 
2276  {
2277  err = GetLastError();
2278  if (err == ERROR_FILE_NOT_FOUND)
2280  return HRESULT_FROM_WIN32(err);
2281  }
2282  else if (res & FILE_ATTRIBUTE_DIRECTORY)
2283  return S_OK;
2284  else
2286 }
2287 
2288 /***********************************************************************
2289  * SHPathPrepareForWriteA (SHELL32.@)
2290  */
2292 {
2293  WCHAR wpath[MAX_PATH];
2294  MultiByteToWideChar( CP_ACP, 0, path, -1, wpath, MAX_PATH);
2295  return SHPathPrepareForWriteW(hwnd, modless, wpath, flags);
2296 }
2297 
2298 
2299 /*
2300  * The two following background operations were modified from filedefext.cpp
2301  * They use an inordinate amount of mutable state across the string functions,
2302  * so are not easy to follow and care is required when modifying.
2303  */
2304 
2305 DWORD WINAPI
2307 {
2308  DWORD ticks = GetTickCount();
2309  FILE_ENTRY *entryToCount;
2310 
2311  for (UINT i = 0; i < from->dwNumFiles; i++)
2312  {
2313  entryToCount = &from->feFiles[i];
2314 
2315  WCHAR theFileName[MAX_PATH];
2316  StringCchCopyW(theFileName, MAX_PATH, entryToCount->szFullPath);
2317  _FileOpCount(op, theFileName, IsAttribDir(entryToCount->attributes), &ticks);
2318  }
2319  return 0;
2320 }
2321 
2322 // All path manipulations, even when this function is nested, occur on the one buffer.
2323 static BOOL
2324 _FileOpCount(FILE_OPERATION *op, LPWSTR pwszBuf, BOOL bFolder, DWORD *ticks)
2325 {
2326  /* Find filename position */
2327  UINT cchBuf = wcslen(pwszBuf);
2328  WCHAR *pwszFilename = pwszBuf + cchBuf;
2329  size_t cchFilenameMax = MAX_PATH - cchBuf;
2330  if (!cchFilenameMax)
2331  return FALSE;
2332 
2333  if (bFolder) {
2334  *(pwszFilename++) = '\\';
2335  --cchFilenameMax;
2336  /* Find all files, FIXME: shouldn't be "*"? */
2337  StringCchCopyW(pwszFilename, cchFilenameMax, L"*");
2338  }
2339 
2340  WIN32_FIND_DATAW wfd;
2341  HANDLE hFind = FindFirstFileW(pwszBuf, &wfd);
2342  if (hFind == INVALID_HANDLE_VALUE)
2343  {
2344  ERR("FindFirstFileW %ls failed\n", pwszBuf);
2345  return FALSE;
2346  }
2347 
2348  do
2349  {
2350  if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2351  {
2352  /* Don't process "." and ".." items */
2353  if (!wcscmp(wfd.cFileName, L".") || !wcscmp(wfd.cFileName, L".."))
2354  continue;
2355 
2356  StringCchCopyW(pwszFilename, cchFilenameMax, wfd.cFileName);
2357  _FileOpCount(op, pwszBuf, TRUE, ticks);
2358  }
2359  else
2360  {
2362  FileSize.u.LowPart = wfd.nFileSizeLow;
2363  FileSize.u.HighPart = wfd.nFileSizeHigh;
2364  op->totalSize.QuadPart += FileSize.QuadPart;
2365  }
2366  if (GetTickCount() - *ticks > (DWORD) 500)
2367  {
2368  // Check if the dialog has ended. If it has, we'll spin down.
2369  if (op->progress != NULL)
2370  op->bCancelled = op->progress->HasUserCancelled();
2371 
2372  if (op->bCancelled)
2373  break;
2374  *ticks = GetTickCount();
2375  }
2376  } while(FindNextFileW(hFind, &wfd));
2377 
2378  FindClose(hFind);
2379  return TRUE;
2380 }
static HRESULT parse_file_list(FILE_LIST *flList, LPCWSTR szFiles)
Definition: shlfileop.cpp:1219
struct _LARGE_INTEGER::@2253 u
HINSTANCE hIconInstance
Definition: shlfileop.cpp:217
#define SHCNE_MKDIR
Definition: shlobj.h:1745
BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
Definition: fileinfo.c:794
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
BOOL WINAPI CreateDirectoryW(IN LPCWSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:90
#define IDS_FILEOOP_MOVING
Definition: shresdef.h:234
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
Definition: bug.cpp:7
#define ASK_CANT_TRASH_ITEM
Definition: shell32_main.h:121
#define STM_SETICON
Definition: winuser.h:2082
static HRESULT rename_files(FILE_OPERATION *op, const FILE_LIST *flFrom, const FILE_LIST *flTo)
Definition: shlfileop.cpp:1841
#define MAKEINTRESOURCE
Definition: winuser.h:591
static void SHELL32_FreeUnicodeBuf(LPWSTR wPath)
Definition: shlfileop.cpp:352
const uint16_t * PCWSTR
Definition: typedefs.h:57
LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
Definition: string.c:1276
GLint GLint GLsizei width
Definition: gl.h:1546
#define ERROR_FILE_EXISTS
Definition: winerror.h:165
#define FOF_NOCOPYSECURITYATTRIBS
Definition: shellapi.h:149
static HICON
Definition: imagelist.c:84
#define FOF_NO_CONNECTED_ELEMENTS
Definition: shellapi.h:151
#define SHCNE_RMDIR
Definition: shlobj.h:1746
BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
Definition: path.c:1578
#define IDS_MOVEERRORSAMEFOLDER
Definition: shresdef.h:248
#define HRESULT_FROM_WIN32(x)
Definition: winerror.h:92
UINT WINAPI GetDriveTypeA(IN LPCSTR lpRootPathName)
Definition: disk.c:468
#define IDI_SHELL_CONFIRM_DELETE
Definition: shresdef.h:603
INT_PTR WINAPI DialogBoxParamW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_opt_ HWND, _In_opt_ DLGPROC, _In_ LPARAM)
DWORD WINAPI _FileOpCountManager(FILE_OPERATION *op, const FILE_LIST *flFrom)
Definition: shlfileop.cpp:2306
SHFILEOPSTRUCTW * req
Definition: shlfileop.cpp:40
#define ERROR_SUCCESS
Definition: deptool.c:10
int WINAPI MapWindowPoints(_In_opt_ HWND hWndFrom, _In_opt_ HWND hWndTo, _Inout_updates_(cPoints) LPPOINT lpPoints, _In_ UINT cPoints)
#define DWORD_PTR
Definition: treelist.c:76
#define error(str)
Definition: mkdosfs.c:1605
#define IDYES
Definition: winuser.h:829
ULARGE_INTEGER totalSize
Definition: shlfileop.cpp:46
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
static INT_PTR ConfirmMsgBox_Paint(HWND hDlg)
Definition: shlfileop.cpp:122
#define DE_OPCANCELLED
Definition: shlfileop.c:45
#define MOVEFILE_REPLACE_EXISTING
Definition: filesup.h:28
PVOID hNameMappings
Definition: shellapi.h:359
HDC WINAPI GetDC(_In_opt_ HWND)
LPWSTR szFullPath
Definition: shlfileop.cpp:57
#define TRUE
Definition: types.h:120
#define pt(x, y)
Definition: drawing.c:79
#define IDS_FILEOOP_FROM
Definition: shresdef.h:237
GLsizei const GLchar ** path
Definition: glext.h:7234
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
#define SW_HIDE
Definition: winuser.h:762
static INT_PTR ConfirmMsgBox_Init(HWND hDlg, LPARAM lParam)
Definition: shlfileop.cpp:144
FILEOP_FLAGS fFlags
Definition: shellapi.h:347
uint16_t * PWSTR
Definition: typedefs.h:56
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
#define FO_COPY
Definition: shellapi.h:134
static DWORD SHELL32_AnsiToUnicodeBuf(LPCSTR aPath, LPWSTR *wPath, DWORD minChars)
Definition: shlfileop.cpp:336
#define ASK_DELETE_FILE
Definition: shell32_main.h:112
#define FOF_SILENT
Definition: shellapi.h:140
#define IDD_YESTOALL_MSGBOX
Definition: shresdef.h:404
#define LANG_NEUTRAL
Definition: nls.h:22
#define CP_ACP
Definition: compat.h:109
const GLint * attribs
Definition: glext.h:10538
#define FORMAT_MESSAGE_ARGUMENT_ARRAY
Definition: winbase.h:424
#define FORMAT_MESSAGE_FROM_STRING
Definition: winbase.h:421
#define IDS_OVERWRITEFILE_CAPTION
Definition: shresdef.h:126
#define ASK_TRASH_FILE
Definition: shell32_main.h:118
#define DT_WORDBREAK
Definition: winuser.h:544
#define IDS_DELETEITEM_CAPTION
Definition: shresdef.h:122
LPWSTR WINAPI StrCpyNW(LPWSTR dst, LPCWSTR src, int count)
Definition: string.c:536
#define SUBLANG_DEFAULT
Definition: nls.h:168
static void confirm_msg_move_button(HWND hDlg, INT iId, INT *xPos, INT yOffset, BOOL bShow)
Definition: shlfileop.cpp:97
static HDC
Definition: imagelist.c:92
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:756
#define CALLBACK
Definition: compat.h:35
#define ASK_DELETE_SELECTED
Definition: shell32_main.h:117
HWND hWnd
Definition: settings.c:17
#define ERROR_NO_MORE_SEARCH_HANDLES
Definition: winerror.h:187
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
static CStringW try_find_new_name(LPCWSTR szDestPath)
Definition: shlfileop.cpp:1306
#define FO_MASK
Definition: shlfileop.cpp:34
#define FOF_ALLOWUNDO
Definition: shellapi.h:144
static HRESULT delete_files(FILE_OPERATION *op, const FILE_LIST *flFrom)
Definition: shlfileop.cpp:1618
#define IDS_OVERWRITEFOLDER_TEXT
Definition: shresdef.h:133
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1539
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define ASK_TRASH_FOLDER
Definition: shell32_main.h:119
#define FOF_WANTNUKEWARNING
Definition: shellapi.h:152
#define CALLBACK_STREAM_SWITCH
Definition: winbase.h:151
#define assert(x)
Definition: debug.h:53
#define IDS_COPYERRORSAME
Definition: shresdef.h:250
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1040
BOOL bAnyFromWildcard
Definition: shlfileop.cpp:68
#define ZeroMemory
Definition: winbase.h:1670
EXTERN_C DWORD WINAPI SheGetDirW(DWORD drive, LPWSTR buffer)
Definition: shlfileop.cpp:2145
void __cdecl Format(UINT nFormatID,...)
Definition: cstringt.h:753
GLuint buffer
Definition: glext.h:5915
BOOL SHELL_ConfirmYesNoW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir)
Definition: shlfileop.cpp:331
DWORD attributes
Definition: shlfileop.cpp:54
BOOL WINAPI SetWindowTextW(_In_ HWND, _In_opt_ LPCWSTR)
UINT_PTR WPARAM
Definition: windef.h:207
int WINAPI MessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType)
#define ASK_TRASH_MULTIPLE_ITEM
Definition: shell32_main.h:120
const TCHAR * szFiles[]
Definition: CImage.cpp:17
void WINAPI SHFreeNameMappings(HANDLE hNameMapping)
Definition: shlfileop.cpp:2092
static DWORD SHNotifyMoveFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BOOL isdir)
Definition: shlfileop.cpp:716
EXTERN_C INT WINAPI RealDriveType(INT drive, BOOL bQueryNet)
Definition: shlfileop.cpp:2218
BOOL bFromRelative
Definition: shlfileop.cpp:59
BOOL WINAPI ShowWindow(_In_ HWND, _In_ int)
BOOL WINAPI EndPaint(_In_ HWND, _In_ const PAINTSTRUCT *)
static HRESULT copy_files(FILE_OPERATION *op, BOOL multiDest, const FILE_LIST *flFrom, FILE_LIST *flTo)
Definition: shlfileop.cpp:1469
ULARGE_INTEGER completedSize
Definition: shlfileop.cpp:45
int32_t INT_PTR
Definition: typedefs.h:64
char * LPSTR
Definition: xmlstorage.h:182
DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:583
FILEOP_FLAGS fFlags
Definition: shellapi.h:357
#define FO_RENAME
Definition: shellapi.h:136
#define NO_ERROR
Definition: dderror.h:5
#define ERROR_DIRECTORY
Definition: winerror.h:295
#define DT_NOPREFIX
Definition: winuser.h:537
#define lstrlenW
Definition: compat.h:750
#define IID_PPV_ARG(Itype, ppType)
#define E_FAIL
Definition: ddrawi.h:102
static void _SetOperationTitle(FILE_OPERATION *op)
Definition: shlfileop.cpp:475
Definition: match.c:390
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
int32_t INT
Definition: typedefs.h:58
int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
Definition: shlfileop.cpp:1982
#define IDI_SHELL_FOLDER_MOVE2
Definition: shresdef.h:676
BOOL WINAPI EndDialog(_In_ HWND, _In_ INT_PTR)
WPARAM wParam
Definition: combotst.c:138
EXTERN_C int WINAPI IsNetDrive(int drive)
Definition: shlfileop.cpp:2206
#define lstrcpynW
Definition: compat.h:738
BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend)
Definition: path.c:126
int WINAPI lstrcmpiW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:194
BOOL bExists
Definition: shlfileop.cpp:60
#define IDS_MOVEERRORTITLE
Definition: shresdef.h:246
#define FO_MOVE
Definition: shellapi.h:133
EXTERN_C HRESULT WINAPI SHPathPrepareForWriteW(HWND hwnd, IUnknown *modless, LPCWSTR path, DWORD flags)
Definition: shlfileop.cpp:2228
#define MB_ICONEXCLAMATION
Definition: winuser.h:779
#define IDS_DELETEFOLDER_CAPTION
Definition: shresdef.h:123
#define DT_PATH_ELLIPSIS
Definition: winuser.h:530
IProgressDialog * progress
Definition: shlfileop.cpp:44
GLuint * ids
Definition: glext.h:5907
BOOL fAnyOperationsAborted
Definition: shellapi.h:358
#define IDS_MOVEERROR
Definition: shresdef.h:253
static BOOL _FileOpCount(FILE_OPERATION *op, LPWSTR pwszBuf, BOOL bFolder, DWORD *ticks)
Definition: shlfileop.cpp:2324
int WINAPI SetBkMode(_In_ HDC, _In_ int)
Definition: dc.c:1056
#define SM_CXSCREEN
Definition: winuser.h:953
#define L(x)
Definition: ntvdm.h:50
static void check_flags(FILEOP_FLAGS fFlags)
Definition: shlfileop.cpp:1867
#define DRIVE_REMOTE
Definition: winbase.h:253
#define IDC_YESTOALL_MESSAGE
Definition: shresdef.h:407
#define IDS_CREATEFOLDER_DENIED
Definition: shresdef.h:120
GLenum GLint GLuint mask
Definition: glext.h:6028
#define IDS_MOVEERRORSAME
Definition: shresdef.h:249
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
Definition: dsa.c:44
#define DRIVE_CDROM
Definition: machpc98.h:115
static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
Definition: shlfileop.cpp:416
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
#define DT_CALCRECT
Definition: winuser.h:526
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
Definition: path.c:294
#define SHPPFW_DIRCREATE
Definition: shlobj.h:303
unsigned int BOOL
Definition: ntddk_ex.h:94
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
HDC WINAPI BeginPaint(_In_ HWND, _Out_ LPPAINTSTRUCT)
DWORD num_alloc
Definition: shlfileop.cpp:66
EXTERN_C BOOL WINAPI Win32RemoveDirectoryW(LPCWSTR path)
Definition: shlfileop.cpp:470
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
#define debugstr_w
Definition: kernel32.h:32
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
#define FIXME(fmt,...)
Definition: debug.h:111
BOOL WINAPI MoveFileW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName)
Definition: move.c:1104
BOOL bAnyDirectories
Definition: shlfileop.cpp:69
static PVOID ptr
Definition: dispmode.c:27
#define FORMAT_MESSAGE_ALLOCATE_BUFFER
Definition: winbase.h:419
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
LPCSTR lpszProgressTitle
Definition: shellapi.h:350
DWORD dwNumFiles
Definition: shlfileop.cpp:67
#define TRANSPARENT
Definition: wingdi.h:950
static void destroy_file_list(FILE_LIST *flList)
Definition: shlfileop.cpp:1289
#define FOF_NOERRORUI
Definition: shellapi.h:148
static DWORD move_files(FILE_OPERATION *op, BOOL multiDest, const FILE_LIST *flFrom, const FILE_LIST *flTo)
Definition: shlfileop.cpp:1761
#define FOF_NOCONFIRMATION
Definition: shellapi.h:142
#define IDA_SHELL_DELETE
Definition: shresdef.h:784
#define WM_GETFONT
Definition: winuser.h:1641
char ext[3]
Definition: mkdosfs.c:358
LPCWSTR lpszProgressTitle
Definition: shellapi.h:360
unsigned char
Definition: typeof.h:29
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:394
LONG_PTR LPARAM
Definition: windef.h:208
char * va_list
Definition: acmsvcex.h:78
static BOOL SHIsCdRom(LPCWSTR path)
Definition: shlfileop.cpp:758
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1776
#define IDS_FILEOOP_DELETING
Definition: shresdef.h:235
static INT_PTR CALLBACK ConfirmMsgBoxProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: shlfileop.cpp:185
static const WCHAR sizeW[]
Definition: editor.c:79
static void copy_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo)
Definition: shlfileop.cpp:1433
DWORD dwYesToAllMask
Definition: shlfileop.cpp:41
unsigned int dir
Definition: maze.c:112
const char * LPCSTR
Definition: xmlstorage.h:183
static BOOL SHELL_ConfirmIDs(int nKindOfDialog, SHELL_ConfirmIDstruc *ids)
Definition: shlfileop.cpp:222
LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath)
Definition: path.c:447
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
static void parse_wildcard_files(FILE_LIST *flList, LPCWSTR szFile, LPDWORD pdwListIndex)
Definition: shlfileop.cpp:1185
BOOL WINAPI RemoveDirectoryW(IN LPCWSTR lpPathName)
Definition: dir.c:732
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:423
#define ASK_DELETE_FOLDER
Definition: shell32_main.h:113
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define IDS_DELETEITEM_TEXT
Definition: shresdef.h:124
static void __inline grow_list(FILE_LIST *list)
Definition: shlfileop.cpp:1127
#define FOF_WANTMAPPINGHANDLE
Definition: shellapi.h:143
static int CALLBACK _DestroyCallback(void *p, void *pData)
Definition: shlfileop.cpp:2070
#define SM_CYSCREEN
Definition: winuser.h:954
LPWSTR szFilename
Definition: shlfileop.cpp:56
#define TRACE(s)
Definition: solgame.cpp:4
static LPSTR pName
Definition: security.c:75
GLsizeiptr size
Definition: glext.h:5919
#define GetProcessHeap()
Definition: compat.h:736
LPWSTR pszNewPath
Definition: shellapi.h:389
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
BOOL WINAPI SetPropW(_In_ HWND, _In_ LPCWSTR, _In_opt_ HANDLE)
static void add_file_to_entry(FILE_ENTRY *feFile, LPCWSTR szFile)
Definition: shlfileop.cpp:1137
HWND WINAPI GetDlgItem(_In_opt_ HWND, _In_ int)
__wchar_t WCHAR
Definition: xmlstorage.h:180
WINE_DEFAULT_DEBUG_CHANNEL(shell)
#define debugstr_a
Definition: kernel32.h:31
LONG HRESULT
Definition: typedefs.h:79
#define _countof(array)
Definition: sndvol32.h:68
#define ASK_DELETE_MULTIPLE_ITEM
Definition: shell32_main.h:114
#define WM_CLOSE
Definition: winuser.h:1611
#define FOF_FILESONLY
Definition: shellapi.h:145
_In_ LPCSTR pszDir
Definition: shellapi.h:582
#define IDI_SHELL_TRASH_FILE
Definition: shresdef.h:588
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
const char file[]
Definition: icontest.c:11
#define SHPPFW_ASKDIRCREATE
Definition: shlobj.h:305
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
unsigned short WORD
Definition: ntddk_ex.h:93
int WINAPI GetSystemMetrics(_In_ int)
unsigned long DWORD
Definition: ntddk_ex.h:95
UINT op
Definition: effect.c:236
int WINAPI SHCreateDirectoryExA(HWND hWnd, LPCSTR path, LPSECURITY_ATTRIBUTES sec)
Definition: shlfileop.cpp:894
#define SetLastError(x)
Definition: compat.h:752
LRESULT WINAPI SendDlgItemMessageW(_In_ HWND, _In_ int, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define PROGDLG_AUTOTIME
Definition: shlobj.h:893
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
#define PROGDLG_NORMAL
Definition: shlobj.h:891
static BOOL SHELL_ConfirmDialogW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir, FILE_OPERATION *op)
Definition: shlfileop.cpp:293
#define IDS_TRASHFOLDER_TEXT
Definition: shresdef.h:129
TCHAR szTitle[MAX_LOADSTRING]
Definition: magnifier.c:35
static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path)
Definition: shlfileop.cpp:446
GLbitfield flags
Definition: glext.h:7161
static BOOL copy_file_to_file(FILE_OPERATION *op, const WCHAR *szFrom, const WCHAR *szTo)
Definition: shlfileop.cpp:1397
#define WM_PAINT
Definition: winuser.h:1610
#define DE_DESTSAMETREE
Definition: shlfileop.c:48
BOOL bFromWildcard
Definition: shlfileop.cpp:58
#define IDS_FILEOOP_COPYING
Definition: shresdef.h:233
#define FOF_SIMPLEPROGRESS
Definition: shellapi.h:146
BOOL fAnyOperationsAborted
Definition: shellapi.h:348
static void create_dest_dirs(LPCWSTR szDestDir)
Definition: shlfileop.cpp:1449
static void move_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWSTR szDestPath)
Definition: shlfileop.cpp:1717
PVOID hNameMappings
Definition: shellapi.h:349
LPCWSTR pFrom
Definition: shellapi.h:355
int ret
EXTERN_C void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
EXTERN_C DWORD WINAPI SheChangeDirA(LPSTR path)
Definition: shlfileop.cpp:2181
static DWORD SHNotifyCopyFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists)
Definition: shlfileop.cpp:787
HDC hdc
Definition: main.c:9
#define ASK_OVERWRITE_FILE
Definition: shell32_main.h:116
#define MB_ICONERROR
Definition: winuser.h:781
#define IDA_SHELL_COPY
Definition: shresdef.h:780
BOOL WINAPI SetCurrentDirectoryA(IN LPCSTR lpPathName)
Definition: path.c:2206
#define IDS_OVERWRITEFILE_TEXT
Definition: resource.h:67
#define IDS_CREATEFOLDER_CAPTION
Definition: shresdef.h:121
GLenum GLsizei len
Definition: glext.h:6722
#define IDS_COPYERRORSUBFOLDER
Definition: shresdef.h:252
#define IDS_DELETEMULTIPLE_TEXT
Definition: shresdef.h:125
_Must_inspect_result_ _Out_ PLARGE_INTEGER FileSize
Definition: fsrtlfuncs.h:108
EXTERN_C DWORD WINAPI SheChangeDirW(LPWSTR path)
Definition: shlfileop.cpp:2195
BOOL WINAPI CopyFileExW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, IN LPVOID lpData OPTIONAL, IN LPBOOL pbCancel OPTIONAL, IN DWORD dwCopyFlags)
Definition: copy.c:318
#define FOF_NORECURSEREPARSE
Definition: shellapi.h:154
#define IDS_FILEOOP_PREFLIGHT
Definition: shresdef.h:238
GLenum src
Definition: glext.h:6340
#define err(...)
#define WM_COMMAND
Definition: winuser.h:1730
#define IDC_YESTOALL_ICON
Definition: shresdef.h:406
UINT WINAPI GetDriveTypeW(IN LPCWSTR lpRootPathName)
Definition: disk.c:497
int WINAPIV wnsprintfW(LPWSTR lpOut, int cchLimitIn, LPCWSTR lpFmt,...)
Definition: wsprintf.c:564
uint32_t DWORD_PTR
Definition: typedefs.h:65
_In_ HANDLE hFile
Definition: mswsock.h:90
BOOL WINAPI MoveWindow(_In_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ BOOL)
static DWORD SHNotifyDeleteFileW(FILE_OPERATION *op, LPCWSTR path)
Definition: shlfileop.cpp:605
EXTERN_C BOOL WINAPI Win32CreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
Definition: shlfileop.cpp:430
Definition: shlfileop.cpp:52
#define lstrcmp
Definition: winbase.h:3743
EXTERN_C DWORD WINAPI Win32DeleteFileW(LPCWSTR path)
Definition: shlfileop.cpp:656
EXTERN_C HRESULT WINAPI SHPathPrepareForWriteA(HWND hwnd, IUnknown *modless, LPCSTR path, DWORD flags)
Definition: shlfileop.cpp:2291
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
DWORD CALLBACK SHCopyProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData)
Definition: shlfileop.cpp:558
LPWSTR szDirectory
Definition: shlfileop.cpp:55
#define SHCNF_PATHW
Definition: shlobj.h:1777
#define FOF_RENAMEONCOLLISION
Definition: shellapi.h:141
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv)
Definition: compobj.c:3325
#define ERR(fmt,...)
Definition: debug.h:110
int WINAPI SHCreateDirectory(HWND hWnd, LPCWSTR path)
Definition: shlfileop.cpp:857
void WINAPI DSA_DestroyCallback(HDSA hdsa, PFNDSAENUMCALLBACK enumProc, LPVOID lParam)
Definition: dsa.c:432
static BOOL confirm_delete_list(HWND hWnd, DWORD fFlags, BOOL fTrash, const FILE_LIST *flFrom)
Definition: shlfileop.cpp:1596
bool IsEmpty() const
Definition: atlsimpstr.h:379
#define IsAttribDir(x)
Definition: shlfileop.cpp:31
static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly)
Definition: shlfileop.cpp:978
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define IDS_COPYERRORTITLE
Definition: shresdef.h:247
#define IDS_MOVEERRORSUBFOLDER
Definition: shresdef.h:251
#define S_OK
Definition: intsafe.h:52
BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath)
Definition: path.c:3930
#define shell32_hInstance
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
#define IDC_YESTOALL
Definition: shresdef.h:405
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define lstrcpyW
Definition: compat.h:749
#define ERROR_CANCELLED
Definition: winerror.h:726
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
HICON hIcon
Definition: msconfig.c:44
void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
Definition: compobj.c:2067
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1577
int WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
Definition: shlfileop.cpp:915
#define SHCNE_DELETE
Definition: shlobj.h:1744
BOOL TRASH_TrashFile(LPCWSTR wszPath)
BOOL WINAPI SetCurrentDirectoryW(IN LPCWSTR lpPathName)
Definition: path.c:2249
#define NEW_FILENAME_ON_COPY_TRIES
Definition: shlfileop.cpp:36
#define HeapReAlloc
Definition: compat.h:734
DWORD WINAPI GetCurrentDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2146
#define list
Definition: rosglue.h:35
#define ShellMessageBoxW
Definition: precomp.h:59
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
Definition: string.c:468
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
#define IDS_DELETESELECTED_TEXT
Definition: shresdef.h:128
#define NULL
Definition: types.h:112
#define MB_OK
Definition: winuser.h:784
HANDLE WINAPI GetPropW(_In_ HWND, _In_ LPCWSTR)
BOOL WINAPI MoveFileWithProgressW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName, IN LPPROGRESS_ROUTINE lpProgressRoutine, IN LPVOID lpData, IN DWORD dwFlags)
Definition: move.c:718
#define IsAttrib(x, y)
Definition: shlfileop.cpp:29
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
struct _ULARGE_INTEGER::@3912 u
#define ASK_OVERWRITE_FOLDER
Definition: shell32_main.h:122
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define MultiByteToWideChar
Definition: compat.h:110
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp)
Definition: shlfileop.cpp:1069
void WINAPI SHFree(LPVOID pv)
Definition: shellole.c:326
static DWORD _ConvertAtoW(PCSTR strSrc, PCWSTR *pStrDest, BOOL isList)
Definition: shlfileop.cpp:1007
HRESULT WINAPI CoInitialize(LPVOID lpReserved)
Definition: compobj.c:1964
#define DE_DESTSUBTREE
Definition: shlfileop.c:46
#define IsDotDir(x)
Definition: shlfileop.cpp:32
EXTERN_C HRESULT WINAPI SHIsFileAvailableOffline(LPCWSTR path, LPDWORD status)
Definition: shlfileop.cpp:357
BOOL SHELL_DeleteDirectoryW(FILE_OPERATION *op, LPCWSTR pszDir, BOOL bShowUI)
Definition: shlfileop.cpp:369
GLuint res
Definition: glext.h:9613
LPWSTR pszOldPath
Definition: shellapi.h:388
uint32_t * LPDWORD
Definition: typedefs.h:59
#define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND
Definition: shlfileop.cpp:50
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
unsigned int ULONG
Definition: retypes.h:1
#define MAKELANGID(p, s)
Definition: nls.h:15
HICON WINAPI LoadIconW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2044
#define IDS_TRASHMULTIPLE_TEXT
Definition: shresdef.h:131
WORD FILEOP_FLAGS
Definition: shellapi.h:211
char * cleanup(char *str)
Definition: wpickclick.c:99
CAtlStringW CStringW
Definition: atlstr.h:130
#define DE_SAMEFILE
Definition: shlfileop.c:42
#define SHPPFW_IGNOREFILENAME
Definition: shlobj.h:306
BOOL TRASH_CanTrashFile(LPCWSTR wszPath)
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
static char * dest
Definition: rtl.c:135
#define IDS_COPYERROR
Definition: shresdef.h:254
#define ERROR_PATH_NOT_FOUND
Definition: winerror.h:106
static LPWSTR wildcard_to_file(LPCWSTR szWildCard, LPCWSTR szFileName)
Definition: shlfileop.cpp:1163
#define IDS_TRASHITEM_TEXT
Definition: shresdef.h:130
const char * PCSTR
Definition: typedefs.h:52
int yOffset
Definition: appswitch.c:59
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
#define SHCNE_CREATE
Definition: shlobj.h:1743
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
#define FOF_MULTIDESTFILES
Definition: shellapi.h:138
#define IDNO
Definition: winuser.h:830
#define ERROR_GEN_FAILURE
Definition: winerror.h:134
static void _SetOperationTexts(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest)
Definition: shlfileop.cpp:508
LPWSTR lpszCaption
Definition: shlfileop.cpp:90
void exit(int exitcode)
Definition: _exit.c:33
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define IDCANCEL
Definition: winuser.h:825
BOOL WINAPI ScreenToClient(_In_ HWND, _Inout_ LPPOINT)
#define IsAttribFile(x)
Definition: shlfileop.cpp:30
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1827
CardRegion * from
Definition: spigame.cpp:19
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4022
LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
Definition: string.c:556
#define EXTERN_C
Definition: basetyps.h:12
STRSAFEAPI StringCbCopyW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:166
LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile)
Definition: path.c:194
int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll)
Definition: shlfileop.cpp:203
#define FO_DELETE
Definition: shellapi.h:135
#define ERROR_BAD_PATHNAME
Definition: winerror.h:233
#define WM_INITDIALOG
Definition: winuser.h:1729
LPARAM lParam
Definition: combotst.c:139
int k
Definition: mpi.c:3369
#define IDS_CANTTRASH_TEXT
Definition: shresdef.h:132
static void copy_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWSTR szDestPath)
Definition: shlfileop.cpp:1334
static void move_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo)
Definition: shlfileop.cpp:1748
#define HeapFree(x, y, z)
Definition: compat.h:735
BOOL bAnyDontExist
Definition: shlfileop.cpp:70
#define IDS_FILEOOP_FROM_TO
Definition: shresdef.h:236
EXTERN_C DWORD WINAPI SheGetDirA(DWORD drive, LPSTR buffer)
Definition: shlfileop.cpp:2108
LONGLONG QuadPart
Definition: typedefs.h:114
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
INT WINAPI DrawTextW(HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags)
Definition: defwnd.c:17
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
#define ERROR_FILENAME_EXCED_RANGE
Definition: winerror.h:263
Definition: fci.c:126
struct _FILE_ENTRY FILE_ENTRY
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
FILE_ENTRY * feFiles
Definition: shlfileop.cpp:65
Definition: ps.c:97