C# .Net Core-是否复制到剪贴板?

C# .Net Core-是否复制到剪贴板?,c#,.net-core,clipboard,C#,.net Core,Clipboard,是否可以使用.Net Core(以与平台无关的方式)将某些内容复制到剪贴板 似乎缺少该类,并且p/Invoking不是Windows之外的选项 编辑:不幸的是,到目前为止,我的问题所说的和人们在阅读问题时所听到的不一致。根据评论和回答,有两件事是明确的。首先,很少有人关心真正的“象牙塔”平台不可知论是否存在。其次,当人们发布代码示例,展示如何在不同平台上使用剪贴板时,技术上正确的答案(“”)令人困惑。因此,我删去了附加条款。 剪贴板类丢失,希望在不久的将来为该类添加一个选项。当它发生的时候。。

是否可以使用.Net Core(以与平台无关的方式)将某些内容复制到剪贴板

似乎缺少该类,并且p/Invoking不是Windows之外的选项

编辑:不幸的是,到目前为止,我的问题所说的和人们在阅读问题时所听到的不一致。根据评论和回答,有两件事是明确的。首先,很少有人关心真正的“象牙塔”平台不可知论是否存在。其次,当人们发布代码示例,展示如何在不同平台上使用剪贴板时,技术上正确的答案(“”)令人困惑。因此,我删去了附加条款。
剪贴板类丢失,希望在不久的将来为该类添加一个选项。当它发生的时候。。。可以使用ProcessStartInfo运行本机shell命令

我是Net Core中的noob,但创建以下代码以在Windows和Mac上发送并将字符串发送到剪贴板:

操作系统检测类

public static class OperatingSystem
{
    public static bool IsWindows() =>
        RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

    public static bool IsMacOS() =>
        RuntimeInformation.IsOSPlatform(OSPlatform.OSX);

    public static bool IsLinux() =>
        RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
}
public static class Clipboard
{
    public static void Copy(string val)
    {
        if (OperatingSystem.IsWindows())
        {
            $"echo {val} | clip".Bat();
        }

        if (OperatingSystem.IsMacOS())
        {
            $"echo \"{val}\" | pbcopy".Bash();
        }
    }
}
外壳类
基于

剪贴板类

public static class OperatingSystem
{
    public static bool IsWindows() =>
        RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

    public static bool IsMacOS() =>
        RuntimeInformation.IsOSPlatform(OSPlatform.OSX);

    public static bool IsLinux() =>
        RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
}
public static class Clipboard
{
    public static void Copy(string val)
    {
        if (OperatingSystem.IsWindows())
        {
            $"echo {val} | clip".Bat();
        }

        if (OperatingSystem.IsMacOS())
        {
            $"echo \"{val}\" | pbcopy".Bash();
        }
    }
}
最后,您可以调用剪贴板Copy并获取剪贴板上的值

var dirPath = @"C:\MyPath";
Clipboard.Copy(dirPath);
希望它能帮助别人!欢迎改进

我在一个.NETCore的工具箱库中工作,里面有所有这些东西:(也可以作为NuGet包提供)

在具有.Net Core的外部终端中运行命令:
由于我还不能发表评论,我将把这篇文章作为一个答案,尽管它实际上只是Equiman解决方案的一个增强:

他的解决方案非常有效,但不适用于多行文本

此解决方案将使用修改后的复制方法和临时文件来保存所有文本行:

public static void Copy(string val)
{
    string[] lines = val.Split('\n');
    if (lines.Length == 1)
        $"echo {val} | clip".Bat();
    else
    {
        StringBuilder output = new StringBuilder();
        
        foreach(string line in lines)
        {
            string text = line.Trim();
            if (!string.IsNullOrWhiteSpace(text))
            {
                output.AppendLine(text);
            }
        }

        string tempFile = @"D:\tempClipboard.txt";

        File.WriteAllText(tempFile, output.ToString());
        $"type { tempFile } | clip".Bat();

    }
}
注意:您可能希望增强代码以避免像我的示例中那样使用固定的临时文件,或者修改路径

此解决方案适用于Windows,但不确定是否适用于Mac/Linux等,但该原则也应适用于其他系统。 就我所记得的,在Linux中,您可能需要将“type”替换为“cat”

因为我的解决方案只需要在Windows上运行,所以我没有进一步调查

如果在Windows中使用上述代码,则临时文件的路径不应包含空格

如果要在剪贴板副本中保留空行,
您应该取消对以下各项的燕尾服上的
字符串.IsNullOrWhiteSpace

的检查:

没有通用的剪贴板功能,因此没有任何方法可以实现这种跨平台的功能

他完全正确。因此,技术上正确的答案是:

不,这不可能以一种完全与平台无关的方式实现。 正如他所说,剪贴板基本上是一个UI概念。另外,有些环境既没有安装
bash
也没有安装
cmd
。还有一些环境在路径中没有这些命令,或者将权限设置为不允许使用这些命令

即使对于那些确实有可用的环境,例如
cmd
,也存在严重的缺陷,可能使其他解决方案变得危险。例如,当有人告诉您的程序在Windows上复制此纯文本字符串,而您的程序执行
Process.Start($“cmd/c echo{input}| clip”)
时会发生什么情况

  • 我喜欢把东西放在>>文件和firefox-url中https://www.maliciouswebsite.com &cd/&del/f/s/q*&echo
一旦您测试了所有的输入,并在所有可以运行您的程序的平台上运行,您仍然无法复制图像

值得一提的是,只要在终端窗口右键单击并从中选择“复制”,我就可以了。对于那些需要长期解决方案的程序,我使用正常的进程间通信。

我的这个项目()使用PInvoke和命令行调用的混合方法。它目前支持

  • 带有.NET Framework 4.6.1及更高版本的Windows
  • 具有.NET Core 2.0及更高版本的Windows
  • 使用Mono 5.0及以上版本的Windows
  • 具有.NET Core 2.0及更高版本的OSX
  • 带Mono 5.20.1及以上版本的OSX
  • 具有.NET Core 2.0及更高版本的Linux
  • Linux和Mono 5.20.1及更高版本
  • 通用Windows平台版本10.0.16299及更高版本
用法:

Install-Package TextCopy

TextCopy.ClipboardService.SetText("Text to place in clipboard");
或者只使用实际代码

窗户

马科斯

Linux

巫术。
人们似乎很难弄清楚如何在Linux上使用剪贴板

这里有一个想法:
而不是依赖默认情况下未安装的命令行工具,或者使用klipper DBus接口
使用klipper dbus接口,可以避免对GTK#/pinvokes/native结构的依赖

注意:klipper必须运行(如果您使用KDE,它就是运行的)。如果有人在使用Gnome(Ubuntu上的默认设置),klipper/DBus方式可能不起作用

以下是Klipper DBus接口的代码(对于stackoverflow来说有点大):

抽象类:

和实际的剪贴板代码(需要-用于处理DBU)

使用System.Threading.Tasks;
名称空间TestMe
{
使用NiHaoRS;//TODO:将名称空间重命名为TestMe
公共类Linux剪贴板
:通用剪贴板
{
公共Linux剪贴板()
{ }
公共静态异步任务TestClipboard()
{
GenericClipboard lc=新的LinuxClipboard();
等待lc.SetClipboardContentsAsync(“Hello KLIPPY”);
字符串cc=wait lc.GetClipboardContentAsync();
系统控制台写入线(cc);
}//结束子测试剪贴板
公共重写异步任务SetClipboardContentsAsync(字符串文本)
{
Tmds.DBus.ObjectPath ObjectPath=新的Tmds.DBus.ObjectPath(“/klipper”);
string service=“org.kde.klipper”;
使用(Tmds.DBus.Connection Connection=newtmds.DBus.Connection(Tmds.DBus.Address.Session
static class OsxClipboard
{
    public static void SetText(string text)
    {
        var nsString = objc_getClass("NSString");
        IntPtr str = default;
        IntPtr dataType = default;
        try
        {
            str = objc_msgSend(objc_msgSend(nsString, sel_registerName("alloc")), sel_registerName("initWithUTF8String:"), text);
            dataType = objc_msgSend(objc_msgSend(nsString, sel_registerName("alloc")), sel_registerName("initWithUTF8String:"), NSPasteboardTypeString);

            var nsPasteboard = objc_getClass("NSPasteboard");
            var generalPasteboard = objc_msgSend(nsPasteboard, sel_registerName("generalPasteboard"));

            objc_msgSend(generalPasteboard, sel_registerName("clearContents"));
            objc_msgSend(generalPasteboard, sel_registerName("setString:forType:"), str, dataType);
        }
        finally
        {
            if (str != default)
            {
                objc_msgSend(str, sel_registerName("release"));
            }

            if (dataType != default)
            {
                objc_msgSend(dataType, sel_registerName("release"));
            }
        }
    }

    [DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")]
    static extern IntPtr objc_getClass(string className);

    [DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")]
    static extern IntPtr objc_msgSend(IntPtr receiver, IntPtr selector);

    [DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")]
    static extern IntPtr objc_msgSend(IntPtr receiver, IntPtr selector, string arg1);

    [DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")]
    static extern IntPtr objc_msgSend(IntPtr receiver, IntPtr selector, IntPtr arg1, IntPtr arg2);

    [DllImport("/System/Library/Frameworks/AppKit.framework/AppKit")]
    static extern IntPtr sel_registerName(string selectorName);

    const string NSPasteboardTypeString = "public.utf8-plain-text";
}
static class LinuxClipboard
{
    public static void SetText(string text)
    {
        var tempFileName = Path.GetTempFileName();
        File.WriteAllText(tempFileName, text);
        try
        {
            BashRunner.Run($"cat {tempFileName} | xclip");
        }
        finally
        {
            File.Delete(tempFileName);
        }
    }

    public static string GetText()
    {
        var tempFileName = Path.GetTempFileName();
        try
        {
            BashRunner.Run($"xclip -o > {tempFileName}");
            return File.ReadAllText(tempFileName);
        }
        finally
        {
            File.Delete(tempFileName);
        }
    }
}

static class BashRunner
{
    public static string Run(string commandLine)
    {
        var errorBuilder = new StringBuilder();
        var outputBuilder = new StringBuilder();
        var arguments = $"-c \"{commandLine}\"";
        using (var process = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "bash",
                Arguments = arguments,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = false,
            }
        })
        {
            process.Start();
            process.OutputDataReceived += (sender, args) => { outputBuilder.AppendLine(args.Data); };
            process.BeginOutputReadLine();
            process.ErrorDataReceived += (sender, args) => { errorBuilder.AppendLine(args.Data); };
            process.BeginErrorReadLine();
            if (!process.WaitForExit(500))
            {
                var timeoutError = $@"Process timed out. Command line: bash {arguments}.
Output: {outputBuilder}
Error: {errorBuilder}";
                throw new Exception(timeoutError);
            }
            if (process.ExitCode == 0)
            {
                return outputBuilder.ToString();
            }

            var error = $@"Could not execute process. Command line: bash {arguments}.
Output: {outputBuilder}
Error: {errorBuilder}";
            throw new Exception(error);
        }
    }
}
using System.Threading.Tasks;

namespace TestMe
{
    using NiHaoRS; // TODO: Rename namespaces to TestMe

    public class LinuxClipboard
        : GenericClipboard

    {

        public LinuxClipboard()
        { }


        public static async Task TestClipboard()
        {
            GenericClipboard lc = new LinuxClipboard();
            await lc.SetClipboardContentsAsync("Hello KLIPPY");
            string cc = await lc.GetClipboardContentAsync();
            System.Console.WriteLine(cc);
        } // End Sub TestClipboard 


        public override async Task SetClipboardContentsAsync(string text)
        {
            Tmds.DBus.ObjectPath objectPath = new Tmds.DBus.ObjectPath("/klipper");
            string service = "org.kde.klipper";

            using (Tmds.DBus.Connection connection = new Tmds.DBus.Connection(Tmds.DBus.Address.Session))
            {
                await connection.ConnectAsync();

                Klipper.DBus.IKlipper klipper = connection.CreateProxy<Klipper.DBus.IKlipper>(service, objectPath);
                await klipper.setClipboardContentsAsync(text);
            } // End using connection 

        } // End Task SetClipboardContentsAsync 


        public override async Task<string> GetClipboardContentAsync()
        {
            string clipboardContents = null;

            Tmds.DBus.ObjectPath objectPath = new Tmds.DBus.ObjectPath("/klipper");
            string service = "org.kde.klipper";

            using (Tmds.DBus.Connection connection = new Tmds.DBus.Connection(Tmds.DBus.Address.Session))
            {
                await connection.ConnectAsync();

                Klipper.DBus.IKlipper klipper = connection.CreateProxy<Klipper.DBus.IKlipper>(service, objectPath);

                clipboardContents = await klipper.getClipboardContentsAsync();
            } // End Using connection 

            return clipboardContents;
        } // End Task GetClipboardContentsAsync 


    } // End Class LinuxClipBoardAPI 


} // End Namespace TestMe
public static class Clipboard
{
    public static void SetText(string text)
    {
        var powershell = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "powershell",
                Arguments = $"-command \"Set-Clipboard -Value \\\"{text}\\\"\""
            }
        };
        powershell.Start();
        powershell.WaitForExit();
    }

    public static string GetText()
    {
        var powershell = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                RedirectStandardOutput = true,
                FileName = "powershell",
                Arguments = "-command \"Get-Clipboard\""
            }
        };

        powershell.Start();
        string text = powershell.StandardOutput.ReadToEnd();
        powershell.StandardOutput.Close();
        powershell.WaitForExit();
        return text.TrimEnd();
    }
}