implement copy file content to clipboard on Windows

Linux 有xclip, xsel等程序用来复制内容,我想在Windows也需要,特别是文本内容就行

clipfile.h

c 复制代码
#ifndef CLIPFILE_H
#define CLIPFILE_H

#include <stdbool.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

// 将文本内容复制到剪贴板
bool clipclipfile_copy_text(const char* text);

// 将文件内容复制到剪贴板
bool clipfile_copy_file(const char* filename);

#ifdef __cplusplus
}
#endif

#endif // CLIPFILE_H

#ifdef CLIPFILE_IMPLEMENTATION

#include <stdlib.h>
#include <string.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif

// 内部函数:获取文件大小
static size_t clipfile_get_file_size(const char* filename) {
#ifdef _WIN32
    WIN32_FILE_ATTRIBUTE_DATA file_info;
    if (!GetFileAttributesExA(filename, GetFileExInfoStandard, &file_info)) {
        return 0;
    }
    return (size_t)((file_info.nFileSizeHigh * (MAXDWORD + 1LL)) + file_info.nFileSizeLow);
#else
    struct stat st;
    if (stat(filename, &st) != 0) {
        return 0;
    }
    return (size_t)st.st_size;
#endif
}

// 将文本内容复制到剪贴板
bool clipfile_copy_text(const char* text) {
    if (!text) return false;

#ifdef _WIN32
    // Windows 实现
    if (!OpenClipboard(NULL)) return false;
    if (!EmptyClipboard()) {
        CloseClipboard();
        return false;
    }

    size_t text_len = strlen(text);
    HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, text_len + 1);
    if (!hMem) {
        CloseClipboard();
        return false;
    }

    char* pMem = (char*)GlobalLock(hMem);
    if (pMem) {
        strcpy(pMem, text);
        GlobalUnlock(hMem);
        SetClipboardData(CF_TEXT, hMem);
    } else {
        GlobalFree(hMem);
        hMem = NULL;
    }

    CloseClipboard();
    return hMem != NULL;

#else
    // Unix-like 实现
    const char* cmd;
#ifdef __APPLE__
    cmd = "pbcopy";
#else
    cmd = "xclip -selection clipboard";
#endif

    FILE* pipe = popen(cmd, "w");
    if (!pipe) return false;

    fputs(text, pipe);
    int ret = pclose(pipe);
    return ret == 0;
#endif
}

// 将文件内容复制到剪贴板
bool clipfile_copy_file(const char* filename) {
    if (!filename) return false;

    // 获取文件大小
    size_t file_size = clipfile_get_file_size(filename);
    if (file_size == 0) {
        // 可能是0字节文件或错误,仍尝试读取
        file_size = 1024; // 初始缓冲区大小
    }

    // 分配缓冲区
    char* buffer = (char*)malloc(file_size + 1);
    if (!buffer) return false;

    // 打开文件
    FILE* file = fopen(filename, "rb");
    if (!file) {
        free(buffer);
        return false;
    }

    // 读取文件内容
    size_t bytes_read = fread(buffer, 1, file_size, file);
    fclose(file);

    // 处理实际读取的字节数
    if (bytes_read == 0) {
        free(buffer);
        return false; // 空文件或读取错误
    }

    // 确保字符串以null结尾
    buffer[bytes_read] = '\0';

    // 复制到剪贴板
    bool success = clipfile_copy_text(buffer);
    free(buffer);
    
    return success;
}

#endif // CLIPFILE_IMPLEMENTATION

#ifdef CLIPFILE_MAIN
#include <stdio.h>

static void print_usage(const char* prog_name) {
    fprintf(stderr, "用法: %s [选项] <文件名>\n", prog_name);
    fprintf(stderr, "将指定文件的内容复制到系统剪贴板\n\n");
    fprintf(stderr, "选项:\n");
    fprintf(stderr, "  -h, --help    显示此帮助信息\n");
    fprintf(stderr, "  -v, --version 显示版本信息\n");
}

static void print_version(void) {
    fprintf(stderr, "clipfile 1.0\n");
    fprintf(stderr, "跨平台文件内容复制到剪贴板工具\n");
}

int main(int argc, char* argv[]) {
    // 解析命令行参数
    if (argc < 2) {
        print_usage(argv[0]);
        return 1;
    }

    const char* filename = NULL;
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
            print_usage(argv[0]);
            return 0;
        } else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
            print_version();
            return 0;
        } else if (filename == NULL) {
            filename = argv[i];
        } else {
            fprintf(stderr, "错误: 过多的参数\n");
            print_usage(argv[0]);
            return 1;
        }
    }

    if (!filename) {
        fprintf(stderr, "错误: 未指定文件名\n");
        print_usage(argv[0]);
        return 1;
    }

    // 复制文件内容到剪贴板
    bool success = clipfile_copy_file(filename);
    if (success) {
        printf("成功将文件内容复制到剪贴板: %s\n", filename);
        return 0;
    } else {
        fprintf(stderr, "错误: 无法复制文件内容到剪贴板: %s\n", filename);
        return 1;
    }
}

#endif // CLIPFILE_MAIN

暴露两个api

c 复制代码
// probe.c
#define CLIPFILE_IMPLEMENTATION
#include "clipfile.h"

int main(int argc, char** argv) {
    // 复制文本到剪贴板
    clipfile_copy_text("Hello, World!");
    printf("文本形式成功\n");
    #if 0
    // 复制文件内容到剪贴板
    if (clipfile_copy_file("probe.c")) {
        printf("文件内容已复制到剪贴板\n");
    } else {
        printf("复制失败\n");
    }
    #endif
    return 0;
}

跨平台支持:

  • Windows 系统:使用 Win32 API 直接操作剪贴板
  • macOS 系统:使用 pbcopy 命令(没测试)
  • Linux 系统:使用 xclip 命令(需要系统已安装)(没测试)

作为命令行工具编译和使用

Windows (MinGW)
bash 复制代码
gcc -x c -DCLIPFILE_IMPLEMENTATION -DCLIPFILE_MAIN clipfile.h -o clipfile.exe -luser32
Windows (MSVC)
cmd 复制代码
cl /DCLIPFILE_IMPLEMENTATION /DCLIPFILE_MAIN /Tcclipfile.h /Fe:clipfile.exe user32.lib
相关推荐
阿白的白日梦1 天前
winget基础管理---更新/修改源为国内源
windows
埃博拉酱5 天前
VS Code Remote SSH 连接 Windows 服务器卡在"下载 VS Code 服务器":prcdn DNS 解析失败的诊断与 BITS 断点续传
windows·ssh·visual studio code
唐宋元明清21886 天前
.NET 本地Db数据库-技术方案选型
windows·c#
加号36 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
tryCbest6 天前
Windows环境下配置pip镜像源
windows·pip
呉師傅6 天前
火狐浏览器报错配置文件缺失如何解决#操作技巧#
运维·网络·windows·电脑
百事牛科技6 天前
保护文档安全:PDF限制功能详解与实操
windows·pdf
悠哉悠哉愿意6 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
一个人旅程~6 天前
如何用命令行把win10/win11设置为长期暂停更新?
linux·windows·经验分享·电脑
Lester_11016 天前
STM32霍尔传感器输入口设置为复用功能输入口时,还能用GPIO函数直接读取IO的状态吗
stm32·单片机·嵌入式硬件·电机控制