C++读取系统剪贴板数据(windows)

本文档展示了如何使用C++在Windows环境下读取剪贴板中的文件列表、图片(位图和DIB格式)以及文本数据。通过`GetClipboardData`和`EnumClipboardFormats`等API函数,可以获取剪贴板的各种格式数据,如CF_HDROP(文件列表)、CF_BITMAP(位图)、CF_DIB(设备无关位图)和CF_UNICODETEXT(Unicode文本)。

// 显示剪贴板的文本
#include <comdef.h>
#include <iostream>
#include <oleidl.h>
#include <string>
#include <vector>
#include <windows.h>
using namespace std;

std::vector<std::string> GetPaths() {
  std::vector<std::string> path_list;

  HDROP hDrop =
      HDROP(::GetClipboardData(CF_HDROP)); // 获取剪切板中复制的文件列表相关句柄

  if (hDrop != NULL) {
    WCHAR szFilePathName[MAX_PATH + 1] = {0};

    UINT nNumOfFiles =
        DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); // 得到文件个数

    // 考虑到用户可能同时选中了多个对象(可能既包含文件也包含文件夹),所以要循环处理
    for (UINT nIndex = 0; nIndex < nNumOfFiles; ++nIndex) {
      memset(szFilePathName, 0, MAX_PATH + 1);
      DragQueryFile(hDrop, nIndex, szFilePathName, MAX_PATH); // 得到文件名

      _bstr_t path(szFilePathName);
      std::string ss = (LPCSTR)path;

      path_list.push_back(ss);
    }
  }

  return path_list;
}

int GetBitmapSize() {
  int nSize = 0;
  // 打开剪切板,并且剪切板里存在图片
  if (IsClipboardFormatAvailable(CF_BITMAP)) {
    // 取得剪切板中的图片数据
    HGLOBAL hClipBoard = GetClipboardData(CF_BITMAP);
    if (hClipBoard) {
      //从剪贴板中取出一个内存的句柄
      // 获取内存大小
      // nSize = GlobalSize(hClipBoard);
      //对内存块进行加锁,将内存句柄值转化为一个指针,并将内存块的引用计数器加一,内存中的数据也返回到指针型变量中
      // char &data = new char[nSize];
      // memcpy(data, GlobalLock(hClipBoard), nSize);
      // 将数据存储
      //将内存块的引用计数器减一
      GlobalUnlock(hClipBoard);
      //关闭剪贴板,释放剪贴板资源的占用权
      CloseClipboard();
    }
  }
  return nSize;
}

//返回值:
// 0 - 存储bmp文件成功
// 1 - 剪贴板内容非DIB格式
// 2 - 打开剪贴板失败
// 3 - 存储bmp文件失败
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int SaveBmpFileFromClipboard(const char *file_name = "capture.bmp") {
  HANDLE hDib;
  LPVOID lpDib;
  BITMAPFILEHEADER bfBuf;

  if (IsClipboardFormatAvailable(CF_DIB)) //检查剪贴板内容是否为DIB类型的数据
  {
    hDib = GetClipboardData(CF_DIB); //获取剪贴板内容并存入hDib句柄
    lpDib = GlobalLock(
        hDib); //利用GlobalLock锁住hDib占用的内存,并返回内存块的首字节指针

    printf("%s", "Getting data...\n");
    int iData = GlobalSize(
        lpDib); //利用GlobalSize获取上述锁住的内存块的大小
                // bfBuf是BITMAPFILEHEADER结构体类型,下面手动指定BMP文件头参数
    bfBuf.bfType = 0x4d42; //"BM"的ASCII码的hex值
    bfBuf.bfSize =
        iData + sizeof(BITMAPFILEHEADER); // BMP文件大小=数据大小+文件头大小
    bfBuf.bfReserved1 = 0;                //固定值
    bfBuf.bfReserved2 = 0;                //固定值
    bfBuf.bfOffBits =
        sizeof(BITMAPFILEHEADER) +
        sizeof(BITMAPINFOHEADER); //文件数据写入时的偏移量=文件头大小+信息头大小

    printf("%s", "Writing files...\n");
    //下面是创建文件并写入文件头和写入文件数据,即生成了BMP文件
    DWORD dwWriten;
    HANDLE hf = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
                            FILE_ATTRIBUTE_NORMAL, NULL);
    WriteFile(hf, &bfBuf, sizeof(BITMAPFILEHEADER), &dwWriten,
              NULL);                              //写入文件头
    WriteFile(hf, lpDib, iData, &dwWriten, NULL); //写入图片数据
    CloseHandle(hf);

    if (!_access(file_name, 0)) {
      printf("%s", "Bmp file saved!\n");
    } else {
      printf("%s", "Bmp file not saved!\n");
      return 3;
    }

    GlobalUnlock(hDib); //解锁被锁住的内存块
    GlobalFree(hDib);   //彻底释放hDib
  } else {
    printf("%s", "Not DIB format!\n");
    return 1;
  }

  return 0;
}

// 遍历当前剪贴板可用的格式数据
int ShowAllFormats() {

  // 由于设置了VX在复制时带上文字颜色,所以从VS2008中拷贝文本时,数据格式不为CF_UNICODETEXT
  /*
   * EnumClipboardFormats
   * 若要启动剪贴板格式的枚举,请将 格式 设置为零。 当 格式
   * 为零时,该函数将检索第一个可用的剪贴板格式。 对于枚举期间的后续调用,请将
   * 格式 设置为上一 个 EnumClipboardFormats 调用的结果
   */
  UINT clipboard_format = 0;
  char szFormatName[1024] = {0};
  while (clipboard_format = EnumClipboardFormats(clipboard_format)) {
    int nameLength =
        GetClipboardFormatNameA(clipboard_format, szFormatName, 1024);
    printf("Clipboard Data Format = %d,   name = %s\n", clipboard_format,
           szFormatName);
    HGLOBAL global_memory = GetClipboardData(clipboard_format);
    LPCSTR clipboard_data = (LPCSTR)GlobalLock(global_memory);
    /* 暂时用不到这些
    if (clipboard_data != NULL) {
      // 剪切板上数据的地址
      printf("Clipboard Data Address = 0x%x\n", global_memory);

      // 剪切板上数据大小
      DWORD data_size = GlobalSize(global_memory);
      printf("Data Size = %d\n", data_size);

      // 16进制输出数据
      printf("Data: ");
      for (DWORD i = 0; i < data_size; i++) {
        if (i % 8 == 0)
          putchar(' ');
        if (i % 16 == 0)
          putchar('\n');
        printf("%02x ", (UCHAR)clipboard_data[i]);
      }
      putchar('\n');

      // 输出部分数据
      switch (clipboard_format) {
      case CF_TEXT:
        printf(" 数据格式:CF_TEXT   数据内容:\n%s\n", clipboard_data);
        break;
      case CF_UNICODETEXT:
        printf(" 数据格式:CF_UNICODETEXT 数据内容:\n%ls\n",
               (LPCWSTR)clipboard_data);
        break;
      }
      GlobalUnlock(global_memory);
    }*/
  }

  return 0;
}

int main() {
  HWND hWnd = NULL;
  BOOL result = OpenClipboard(hWnd); //打开剪切板
  DWORD errCode = GetLastError();
  if (FALSE == result) {
    cout << "剪贴板打开失败!" << endl;
    return -1;
  }

  //检索剪贴板上当前不同数据格式的数量。
  int formatSize = CountClipboardFormats();
  cout << "剪贴板上当前不同数据格式的数量:" << formatSize << endl;
  // 文件格式
  if (IsClipboardFormatAvailable(CF_HDROP)) {

    cout << "文件格式:" << endl;
    cout << "=========================>" << endl << endl;
    ;
    std::vector<std::string> path_list = GetPaths();
    for (auto path : path_list) {
      cout << path << endl;
    }

    cout << endl << "<=========================" << endl << endl;
  }

  /* 用最下面的 CF_DIB 作为图片格式判断
  // 图片格式
  if (IsClipboardFormatAvailable(CF_BITMAP)) {
    HBITMAP h = (HBITMAP)GetClipboardData(CF_BITMAP); //获取剪切板数据
    char *p = (char *)GlobalLock(h);
    cout << "图片格式:" << endl;
    cout << "=========================>" << endl << endl;
    int bitmapSize = GetBitmapSize();
    cout << "图片大小:" << bitmapSize << endl;
    cout << endl << "<=========================" << endl << endl;
    GlobalUnlock(h);
    CloseClipboard();
  }
  */

  // 文本格式 // 使用  CF_TEXT  还是会中文乱码
  if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
    HANDLE h = GetClipboardData(CF_UNICODETEXT); //获取剪切板数据
    LPTSTR p = (LPTSTR)GlobalLock(h);
    DWORD text_size = GlobalSize(h);
    wchar_t *sBuf = new wchar_t[text_size + 1];
    wmemset(sBuf, 0, text_size);
    wcscpy_s(sBuf, text_size, p);
    cout << "文本格式:" << endl;
    cout << "=========================>" << endl << endl;

    // setlocale(LC_CTYPE, "");

    //获取转换所需的目标缓存大小
    DWORD dBufSize =
        WideCharToMultiByte(CP_ACP, 0, sBuf, -1, NULL, 0, NULL, FALSE);

    //分配目标缓存
    char *dBuf = new char[dBufSize];
    memset(dBuf, 0, dBufSize);

    //转换
    int nRet =
        WideCharToMultiByte(CP_ACP, 0, sBuf, -1, dBuf, dBufSize, NULL, FALSE);

    if (nRet <= 0) {
      printf("转换失败\n");
    } else {
      // printf("转换成功\n");
    }
    string copyText = dBuf;
    cout << copyText << endl;

    cout << endl << "<=========================" << endl << endl;
    GlobalUnlock(h);
    delete[] dBuf;
    delete[] sBuf;
  }

  // 图片DIB格式
  if (IsClipboardFormatAvailable(CF_DIB)) {
    cout << "图片DIB格式:" << endl;
    cout << "=========================>" << endl << endl;

    SaveBmpFileFromClipboard("testPicture.bmp");
    system("explorer .");
    cout << endl << "<=========================" << endl << endl;
  }

  // HTML Format  49344 自定义的格式 可以由 RegisterClipboardFormatA 函数注册
  if (IsClipboardFormatAvailable(49344)) {
    cout << "HTML 49344 格式:" << endl;
    cout << "=========================>" << endl << endl;

    HGLOBAL global_memory = GetClipboardData(49344);
    LPCSTR clipboard_data = (LPCSTR)GlobalLock(global_memory);
    DWORD data_size = GlobalSize(global_memory);
    printf("Data Size = %d\n", data_size);
    /*
    // 16进制输出数据
    printf("Data: ");
    for (DWORD i = 0; i < data_size; i++) {
      if (i % 8 == 0)
        putchar(' ');
      if (i % 16 == 0)
        putchar('\n');
      printf("%02x ", (UCHAR)clipboard_data[i]);
    }
    putchar('\n');
    */
    GlobalUnlock(global_memory);
    cout << endl << "<=========================" << endl << endl;
  }

  // 显示所有可用的数据格式
  ShowAllFormats();

  CloseClipboard();
  getchar();
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程经验随笔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值