调用windows复制对话框复制文件
命令行调用windows复制对话框复制文件,C#版可能有些Bug报错, 请测试使用!
一:结果演示
1). 复制演示
2). 提示覆盖
3). 不提示覆盖
二. C#源代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices;
namespace CopyX
{
class Program
{
public enum FO_Func : uint
{
FO_MOVE = 0x0001,
FO_COPY = 0x0002,
FO_DELETE = 0x0003,
FO_RENAME = 0x0004,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 2)]
struct SHFILEOPSTRUCT
{
public IntPtr hwnd;
public FO_Func wFunc;
[MarshalAs(UnmanagedType.LPWStr)]
public string pFrom;
[MarshalAs(UnmanagedType.LPWStr)]
public string pTo;
public ushort fFlags;
[MarshalAs(UnmanagedType.Bool)]
public bool fAnyOperationsAborted;
public IntPtr hNameMappings;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpszProgressTitle;
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
static extern int SHFileOperation([In, Out] ref SHFILEOPSTRUCT lpFileOp);
static string usage = "调用Windows自带的复制文件对话框来复制文件。\n" +
"\n CopyX [/Y] source destination\n\n" +
"\t/Y \t不提示直接覆盖目标文件。\n" +
"\tsource \t指定要复制的文件。\n" +
"\tdestination\t为新文件指定目录和/或文件名。";
static int Main(string[] args)
{
bool bOverWrite = false;
string srcPath = null, dstPath = null;
foreach (string arg in args)
{
if (arg == "/y" || arg == "/Y")
{
bOverWrite = true;
}
else if (srcPath == null)
{
srcPath = arg;
}
else if (dstPath == null)
{
dstPath = arg;
}
}
if (args.Contains("/?") || srcPath == null || dstPath == null)
{
Console.WriteLine(usage);
return -1;
}
if ((!File.Exists(srcPath)) && (!Directory.Exists(srcPath)))
{
Console.WriteLine("复制失败, 源文件不存在!");
return -1;
}
SHFILEOPSTRUCT lpFileOp = new SHFILEOPSTRUCT();
lpFileOp.hwnd = IntPtr.Zero;
lpFileOp.wFunc = FO_Func.FO_COPY;
lpFileOp.pFrom = srcPath + '\0';
lpFileOp.pTo = dstPath + '\0';
/*
FOF_MULTIDESTFILES = 0x0001
FOF_CONFIRMMOUSE = 0x0002
FOF_SILENT = 0x0004 // don't create progress/report
FOF_RENAMEONCOLLISION = 0x0008
FOF_NOCONFIRMATION = 0x0010 // Don't prompt the user.
FOF_WANTMAPPINGHANDLE = 0x0020 // Fill in SHFILEOPSTRUCT.hNameMappings
FOF_ALLOWUNDO = 0x0040
FOF_FILESONLY = 0x0080 // on *.* do only files
FOF_SIMPLEPROGRESS = 0x0100 // means don't show names of files
FOF_NOCONFIRMMKDIR = 0x0200 // don't confirm making any needed dirs
FOF_NOERRORUI = 0x0400 // don't put up error UI
FOF_NOCOPYSECURITYATTRIBS = 0x0800 // dont copy NT file Security Attributes
FOF_NORECURSION = 0x1000 // don't recurse into directories.
FOF_NO_CONNECTED_ELEMENTS = 0x2000 // don't operate on connected elements.
FOF_WANTNUKEWARNING = 0x4000 // during delete operation warn if nuking instead of recycling (partially overrides FOF_NOCONFIRMATION)
FOF_NORECURSEREPARSE = 0x8000 // treat reparse points as objects not containers
*/
lpFileOp.fFlags = bOverWrite ? (ushort)(0x0010 | 0x0200) : (ushort)0x0100;
lpFileOp.hNameMappings = IntPtr.Zero;
lpFileOp.fAnyOperationsAborted = false;
int ret = SHFileOperation(ref lpFileOp);
switch (ret)
{
case 0x00: return 0; // 拷贝成功
case 0x71: Console.WriteLine("The source and destination files are the same file."); break;
case 0x72: Console.WriteLine("Multiple file paths were specified in the source buffer, but only one destination file path."); break;
case 0x73: Console.WriteLine("Rename operation was specified but the destination path is a different directory. Use the move operation instead."); break;
case 0x74: Console.WriteLine("The source is a root directory, which cannot be moved or renamed."); break;
case 0x75: Console.WriteLine("The operation was canceled by the user, or silently canceled if the appropriate flags were supplied to SHFileOperation."); break;
case 0x76: Console.WriteLine("The destination is a subtree of the source."); break;
case 0x78: Console.WriteLine("Security settings denied access to the source."); break;
case 0x79: Console.WriteLine("The source or destination path exceeded or would exceed MAX_PATH."); break;
case 0x7A: Console.WriteLine("The operation involved multiple destination paths, which can fail in the case of a move operation."); break;
case 0x7C: Console.WriteLine("The path in the source or destination or both was invalid."); break;
case 0x7D: Console.WriteLine("The source and destination have the same parent folder."); break;
case 0x7E: Console.WriteLine("The destination path is an existing file."); break;
case 0x80: Console.WriteLine("The destination path is an existing folder."); break;
case 0x81: Console.WriteLine("The name of the file exceeds MAX_PATH."); break;
case 0x82: Console.WriteLine("The destination is a read-only CD-ROM, possibly unformatted."); break;
case 0x83: Console.WriteLine("The destination is a read-only DVD, possibly unformatted."); break;
case 0x84: Console.WriteLine("The destination is a writable CD-ROM, possibly unformatted."); break;
case 0x85: Console.WriteLine("The file involved in the operation is too large for the destination media or file system."); break;
case 0x86: Console.WriteLine("The source is a read-only CD-ROM, possibly unformatted."); break;
case 0x87: Console.WriteLine("The source is a read-only DVD, possibly unformatted."); break;
case 0x88: Console.WriteLine("The source is a writable CD-ROM, possibly unformatted."); break;
case 0xB7: Console.WriteLine("MAX_PATH was exceeded during the operation."); break;
case 0x402: Console.WriteLine("An unknown error occurred. This is typically due to an invalid path in the source or destination. This error does not occur on Windows Vista and later."); break;
default: Console.WriteLine("复制失败, 未知错误代码【" + ret + "】,参考: https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa"); break;
}
return ret;
}
}
}
三. AutoIt 源代码
#NoTrayIcon
#pragma compile(FileDescription, '简单调用Windows自带复制对话框复制文件或文件夹')
#pragma compile(FileVersion, 1.0.0.0)
#pragma compile(ProductName, Leo)
#pragma compile(ProductVersion, 1.0.0.0)
#pragma compile(LegalCopyright, Copyright © 2020)
#pragma compile(x64, false)
#pragma compile(UPX, true)
#pragma compile(Compression, 9)
#pragma compile(Console, true)
#include <APIShellExConstants.au3>
#include <WinAPIFiles.au3>
#include <WinAPIShellEx.au3>
Global $bOverWrite = False, $bHelp = False
Global $srcPath = '', $dstPath = ''
For $i = 1 To $CmdLine[0]
If $CmdLine[$i] = '/y' Then
$bOverWrite = True
ElseIf $CmdLine[$i] = '/?' Then
$bHelp = True
ElseIf $srcPath = '' Then
$srcPath = $CmdLine[$i]
ElseIf $dstPath = '' Then
$dstPath = $CmdLine[$i]
EndIf
Next
If $bHelp Or $srcPath = '' Or $dstPath = '' Then
ConsoleWrite("调用Windows自带的复制文件对话框来复制文件。" & @CRLF & @CRLF & _
"CopyX [/Y] source destination" & @CRLF & @CRLF & @TAB & _
"/Y 不提示直接覆盖目标文件。" & @CRLF & @TAB & _
"source 指定要复制的文件。" & @CRLF & @TAB & _
"destination 为新文件指定目录和/或文件名。" & @CRLF)
Exit -1
EndIf
If FileExists($srcPath) <> 1 Then
ConsoleWriteError('复制失败, 源文件不存在!')
Exit -1
EndIf
If $bOverWrite Then
_WinAPI_ShellFileOperation($srcPath, $dstPath, $FO_COPY, BitOR($FOF_NOCONFIRMATION, $FOF_NOCONFIRMMKDIR))
Global $ret = @extended
Else
_WinAPI_ShellFileOperation($srcPath, $dstPath, $FO_COPY, $FOF_SIMPLEPROGRESS)
Global $ret = @extended
EndIf
If $ret <> 0 Then
ConsoleWriteError("复制失败,错误代码: " & $ret & " 参考: https://www.autoitscript.com/autoit3/docs/libfunctions/_WinAPI_ShellFileOperation.htm")
Exit $ret
Else
Exit 0
EndIf
四. 文件说明及下载
C#版编译为DoNet4.5,Win7需安装4.5框架
AutoIt版默认支持Win7 ~ Win10 比较稳定
可自行编译