首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

C++Builder 將檔案路徑複製到剪貼板(CF_HDROP 格式)

     編輯:VC 教學

前言

將檔案路徑放入剪貼板,讓使用者能在總管中 Ctrl+V 貼上實體檔案,需使用 CF_HDROP 格式配合 DROPFILES 結構。本文提供完整的 C++Builder 實作函式 CopyToClipboard,支援單一檔案路徑複製至剪貼板。

完整實作代碼


bool CopyToClipboard(AnsiString file)
{
    if (file.IsEmpty()) return false;

    // 1. 計算緩衝區大小:DROPFILES 結構(20 bytes) + 路徑字串 + 雙 null 結尾(2 bytes)
    int nLen = 20 + file.Length() + 2;

    // 2. 分配可移動、共享、零初始化的全域記憶體
    HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, nLen);
    if (hMem == NULL) return false;

    // 3. 鎖定記憶體取得指標
    char* Data = (char*)GlobalLock(hMem);
    if (!Data)
    {
        GlobalFree(hMem);
        return false;
    }

    // 4. 填寫 DROPFILES 結構
    // 結構定義:
    // typedef struct _DROPFILES {
    //   DWORD pFiles;   // 檔案清單相對結構起始的位移(固定 20)
    //   POINT pt;       // 點擊座標(拖放用,此處為 0)
    //   BOOL fNC;       // 非客戶區旗標
    //   BOOL fWide;     // 是否為 Unicode 路徑(FALSE=ANSI)
    // } DROPFILES;
    *(DWORD*)Data = 20;                 // pFiles = 20 (sizeof(DROPFILES))
    // pt.x, pt.y, fNC, fWide 已由 GMEM_ZEROINIT 歸零

    // 5. 複製檔案路徑至緩衝區(位移 20 之後)
    strcpy(Data + 20, file.c_str());
    // 結尾已有雙 null(配置時 +2,且 GlobalAlloc 零初始化)

    GlobalUnlock(hMem);

    // 6. 開啟剪貼板、清空、設定資料
    bool success = false;
    if (OpenClipboard(NULL))
    {
        EmptyClipboard();
        if (SetClipboardData(CF_HDROP, hMem) != NULL)
        {
            hMem = NULL; // 所有權轉移給剪貼板,不需自行釋放
            success = true;
        }
        CloseClipboard();
    }

    // 7. 若設定失敗,釋放記憶體
    if (hMem) GlobalFree(hMem);

    return success;
}

// 使用範例
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    CopyToClipboard("C:\\scandisk.log");
}

關鍵技術點深度解析

DROPFILES 結構佈局

Offset  Size  Field
0       4     pFiles  = 20 (檔案清單起始位移)
4       4     pt.x    = 0
8       4     pt.y    = 0
12      4     fNC     = 0 (FALSE)
16      4     fWide   = 0 (FALSE=ANSI, TRUE=Unicode)
20      ...   檔案路徑字串(以單一 null 分隔多檔,末尾雙 null)

總大小 = 20 + Σ(路徑長度+1) + 1(額外結尾 null)。

GlobalAlloc 旗標說明

旗標用途
GMEM_MOVEABLE允許記憶體管理器移動區塊(剪貼板要求)
GMEM_DDESHARE允許 DDE/剪貼板共享(舊版相容)
GMEM_ZEROINIT自動零初始化,省去 memset

所有權轉移規則

  • SetClipboardData 成功(返回非 NULL)→ 記憶體所有權轉移給剪貼板,**不可**呼叫 GlobalFree。
  • SetClipboardData 失敗(返回 NULL)→ 記憶體仍屬呼叫者,**必須**呼叫 GlobalFree 釋放。

擴充:支援多檔案與 Unicode 路徑


bool CopyFilesToClipboard(const std::vector& files, bool useUnicode = false)
{
    if (files.empty()) return false;

    // 計算總大小
    size_t total = 20; // DROPFILES
    for (auto& f : files) total += f.Length() + 1;
    total += 1; // 額外結尾 null

    HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, total);
    if (!hMem) return false;

    char* Data = (char*)GlobalLock(hMem);
    *(DWORD*)Data = 20;
    // fWide 在 ANSI 版保持 0;Unicode 版需設為 1 並用 wchar_t 複製路徑

    char* ptr = Data + 20;
    for (auto& f : files)
    {
        strcpy(ptr, f.c_str());
        ptr += f.Length() + 1;
    }
    *ptr = '\0'; // 雙 null 結尾

    GlobalUnlock(hMem);

    bool success = false;
    if (OpenClipboard(NULL))
    {
        EmptyClipboard();
        UINT fmt = useUnicode ? CF_HDROP : CF_HDROP; // 實際上 CF_HDROP 兩者通用,fWide 決定解讀方式
        if (SetClipboardData(fmt, hMem) != NULL)
        {
            hMem = NULL;
            success = true;
        }
        CloseClipboard();
    }
    if (hMem) GlobalFree(hMem);
    return success;
}

驗證方法

  1. 執行程式呼叫 CopyToClipboard("C:\\test.txt")。
  2. 開啟檔案總管,任意資料夾按 Ctrl+V。
  3. 若 test.txt 被貼上(複製/移動視目的資料夾權限),即成功。

常見失敗原因

現象原因修正
貼上無反應pFiles 位移錯誤(非 20)確認 *(DWORD*)Data = 20
路徑截斷/亂碼緩衝區大小不足或缺雙 null配置 +2 位元組,確保零初始化
OpenClipboard 失敗其他程式佔用剪貼板重試機制或延遲執行
Unicode 路徑失效fWide=1 但資料為 ANSIfWide=1 時必須寫入 wchar_t (UTF-16)

掌握 CF_HDROP 格式,即可讓你的應用程式與 Windows Shell 完美整合,提供原生的檔案拖放/複製體驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved