翻譯《The Old New Thing》- What a drag: Dragging a virtual file (HGLOBAL edition)

What a drag: Dragging a virtual file (HGLOBAL edition) - The Old New Thing (microsoft.com)icon-default.png?t=N7T8https://devblogs.microsoft.com/oldnewthing/20080318-00/?p=23083

Raymond Chen?2008年03月18日


拖拽虛擬文件(HGLOBAL 版本)

????????現在我們已經對簡單的數據對象有所了解,讓我們來做點稍微復雜但極其有用的事情:拖拽一個虛擬文件。實現這一功能的方法有很多,但我將從最簡單的方法開始,即虛擬文件以內存塊的形式表示。

????????記住,這個系列的副標題是“這是你能做的最少”。你可以(甚至應該)做很多可選的事情,但我將從絕對最小化的部分開始。

????????對我們一直在研究的拖拽/放置程序進行以下更改。首先,更改數據類型的枚舉:

enum {DATA_FILEGROUPDESCRIPTOR,DATA_FILECONTENTS,DATA_NUM,DATA_INVALID = -1,
};

????????拖拽虛擬文件的核心剪貼板格式是 FILEGROUPDESCRIPTOR,它描述了正在拖拽的文件數量以及它們的各種信息。對于文件組描述符中的每個文件,你必須提供相關的文件內容,由 CFSTR_FILECONTENTS 剪貼板格式表示。

CTinyDataObject::CTinyDataObject() : m_cRef(1)
{SetFORMATETC(&m_rgfe[DATA_FILEGROUPDESCRIPTOR],RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR));SetFORMATETC(&m_rgfe[DATA_FILECONTENTS],RegisterClipboardFormat(CFSTR_FILECONTENTS),TYMED_HGLOBAL, /* lindex */ 0);
}

????????初始化文件組描述符條目和之前看到的差不多。注意,結構體稱為 FILEGROUPDESCRIPTOR,但剪貼板格式是 CFSTR_FILEDESCRIPTOR 而不是“group”。這可能最初是一個印刷錯誤,但現在我們只能接受它。

????????文件內容條目有一個轉折:lindex 是零,而不是 -1。文件內容剪貼板格式使用 lindex 作為從零開始的索引,選擇調用者所談論的是哪個虛擬文件。由于我們只有一個虛擬文件,它的索引是零。

????????和以前一樣,所有真正的工作都在數據對象的核心,即 IDataObject::GetData 方法中。

HRESULT CTinyDataObject::GetData(FORMATETC *pfe, STGMEDIUM *pmed)
{ZeroMemory(pmed, sizeof(*pmed));switch (GetDataIndex(pfe)) {case DATA_FILEGROUPDESCRIPTOR:{FILEGROUPDESCRIPTOR fgd;ZeroMemory(&fgd, sizeof(fgd));fgd.cItems = 1;StringCchCopy(fgd.fgd[0].cFileName,ARRAYSIZE(fgd.fgd[0].cFileName),TEXT("Dummy"));pmed->tymed = TYMED_HGLOBAL;return CreateHGlobalFromBlob(&fgd, sizeof(fgd),GMEM_MOVEABLE, &pmed->hGlobal);}case DATA_FILECONTENTS:pmed->tymed = TYMED_HGLOBAL;return CreateHGlobalFromBlob("Dummy", 5,GMEM_MOVEABLE, &pmed->hGlobal);}return DV_E_FORMATETC;
}

????????當調用者請求文件組描述符時,我們填寫一個 FILEGROUPDESCRIPTOR 結構體,在填寫之前清零我們不關心的字節,以避免信息泄露漏洞。正如我指出的,我們從做絕對最小的必要事情開始,這在虛擬文件傳輸的情況下僅僅包括指定有多少虛擬文件以及它們的名稱。

當調用者請求文件零(我們唯一擁有的)的內容時,我們生成一個包含“Dummy”這個詞的五字節內存塊。

????????運行這個程序,并將不可見的對象拖出客戶端區域并將其放置到桌面上。哇,你的虛擬文件已經被復制到桌面上,并變成了一個真實的文件。(你甚至可以將它拖放到Outlook郵件撰寫窗口中,它將作為附件出現!)

????????這里還有一些問題,但我們已經至少完成了拖拽由內存塊表示的虛擬文件的絕對最小必要事項。讓我們看看其中一些可選特性,其中一些對您和最終用戶都有重大影響。

????????首先,您可能已經注意到創建的 Dummy 文件在末尾可能有一些垃圾字節。我說“可能”,因為這些垃圾字節的存在取決于堆管理器的感受。如果您只提供 HGLOBAL,則內存塊大小的唯一指示是 GlobalSize 函數的輸出。但 GlobalSize 函數返回的大小不需要等于傳遞給 GlobalAlloc 的大小;唯一的保證是它至少和請求的大小一樣大。它可能更大,這是由于內部堆管理,例如將所有分配舍入到最近的16字節的倍數。如果進行了這樣的舍入,那么創建的 Dummy 文件將包含那些額外的垃圾字節。

????????為了避免這個問題,在 FILEGROUPDESCRIPTOR 中設置 FD_FILESIZE 標志,并在 nFileSizeLownFileSizeHigh 成員中指定確切的文件大小:

????????在 FILEGROUPDESCRIPTOR 中指定文件大小也有利于最終用戶,因為它為文件復制進度條提供了它應該接收多少字節的信息。沒有它,進度條不知道那個虛擬文件中有多少字節。它最終在請求文件內容時找到,但它是從每個文件復制時逐個學習的。進度對話框沒有機會預先收集這些信息,以提供有意義的進度反饋。

????????另一個可選細節,您可能希望利用的是,在 FILEGROUPDESCRIPTOR 中指定文件屬性和修改時間。例如,您可能希望在復制時使文件隱藏,或者您可能希望自定義最后修改時間。

????????我們來做一些事情。我們將在文件組描述符中指定文件大小以避免垃圾并改善進度反饋,并將最后修改時間設置為特定日期。

case DATA_FILEGROUPDESCRIPTOR:
{FILEGROUPDESCRIPTOR fgd;ZeroMemory(&fgd, sizeof(fgd));fgd.cItems = 1;fgd.fgd[0].dwFlags = FD_FILESIZE | FD_WRITESTIME;fgd.fgd[0].nFileSizeLow = 5;fgd.fgd[0].ftLastWriteTime.dwLowDateTime = 0x256d4000;fgd.fgd[0].ftLastWriteTime.dwHighDateTime = 0x01bf53eb;StringCchCopy(fgd.fgd[0].cFileName,ARRAYSIZE(fgd.fgd[0].cFileName),TEXT("Dummy"));pmed->tymed = TYMED_HGLOBAL;return CreateHGlobalFromBlob(&fgd, sizeof(fgd),GMEM_MOVEABLE, &pmed->hGlobal);
}

????????現在,當您放置文件時,它在末尾將沒有任何垃圾字節,時間戳將是2000年1月1日午夜UTC。(由于文件太小,您不會注意到進度條有任何改進。)

????????盡管我們沒有做很多,但這對許多人來說可能已經足夠了,尤其是那些只想允許用戶從他們的程序中拖拽一個對象并將其放入資源管理器窗口以創建相應文件的人,只要 HGLOBAL 是文件內容的方便格式。這對于小文件是合適的,但隨著文件變大,您必須一次性生成整個文件的事實可能變得昂貴。下次我們將看看一個替代方案。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20065.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20065.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20065.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據庫(13)——DQL分組查詢

語法 SELECT 字段列表 FROM 表名 [WHERE 條件] GROUP BY 分組字段名 [HAVING 分組后過濾條件] 示例 原始表: 根據性別分組并統計人數 select sex,count(*) from information group by sex; 根據性別分組,并求年齡的平均值:

vue iframe src規則

iframe 元素的 src 屬性規則與常規的網頁鏈接規則相似&#xff0c;可以是以下幾種形式&#xff1a; 1、相對路徑&#xff1a;相對于當前頁面的路徑。例如&#xff0c;如果你想加載當前域名下的一個頁面&#xff0c;可以簡單地指定其相對路徑&#xff1a; <iframe src"…

工廠數字化!數據治理是基礎

數據治理是基礎 在當今的工業生產中&#xff0c;數字化轉型已成為企業提升競爭力的必由之路。然而&#xff0c;數字化轉型并非一蹴而就&#xff0c;它需要戰略驅動、數據治理和數據智能的協同發展。本文將圍繞如何進行數字化、數據治理的內涵以及數據治理作為數字化轉型基礎的原…

QT系列教程(7) QLineEdit介紹

簡介 QLineEdit屬于輸入插件&#xff0c;用來實現單行錄入。支持幾種錄入模式。 Normal表示正常錄入,錄入的信息會顯示在QLineEdit上。 Password表示密碼錄入的方式&#xff0c;錄入的信息不顯示QLineEdit&#xff0c;只是通過黑色圓點顯示。 NoEcho 表示不顯示錄入信息&am…

通過SpringCloudGateway中的GlobalFilter實現鑒權過濾

1.pom.xml中加入gateway jar包 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency> 2.創建權限過濾器 SecurityFilter /*** 鑒權過濾***/ Slf4j Component …

第 11 章 排序

第 11 章 排序 Abstract 排序猶如一把將混亂變為秩序的魔法鑰匙&#xff0c;使我們能以更高效的方式理解與處理數據。 無論是簡單的升序&#xff0c;還是復雜的分類排列&#xff0c;排序都向我們展示了數據的和諧美感。 本章內容 11.1 排序算法11.2 選擇排序11.3 冒…

Ps:調整畫筆工具

調整畫筆工具 Adjustment Brush Tool可以將選區、創建蒙版和應用調整的傳統工作流程合并為一個步驟&#xff0c;簡化了對圖像進行非破壞性局部調整的操作。 快捷鍵&#xff1a;B 調整畫筆工具是 Photoshop 2024 年 5 月版&#xff08;25.9 版&#xff09;新增的工具。 ◆ ◆ …

【STM32】定時器與PWM的LED控制

目錄 一、定時器控制LED周期性亮滅&#xff08;一&#xff09;定時器1.STM32F103定時器分類及區別2.通用定時器主要功能3.通用定時器工作過程 &#xff08;二&#xff09;STM32CubeMX創建工程&#xff08;三&#xff09;代碼實現&#xff08;四&#xff09;實驗結果 二、PWM模式…

gin接收圖片文件,websocet持續返回響應,解決多任務排隊問題

背景 有一個需求是這樣的&#xff0c;前端需要通過http請求的form-data上傳圖片文件&#xff0c;后端接收圖片后調用AI接口執行命令&#xff0c;由于命令執行時間較長&#xff0c;需要持續返回當前任務在全局任務列表中的位置&#xff0c;以便前端即時更新排隊信息。 思考 如…

【源碼】Spring Data JPA原理解析之Repository自定義方法命名規則執行原理(二)

Spring Data JPA系列 1、SpringBoot集成JPA及基本使用 2、Spring Data JPA Criteria查詢、部分字段查詢 3、Spring Data JPA數據批量插入、批量更新真的用對了嗎 4、Spring Data JPA的一對一、LazyInitializationException異常、一對多、多對多操作 5、Spring Data JPA自定…

Oracle中TAF與SCANIP全面解析

TAF (Transparent Application Failover) 概念&#xff1a; TAF是Oracle數據庫提供的一個高級特性&#xff0c;旨在實現應用程序在數據庫連接中斷時的透明重連。它允許應用程序在數據庫故障發生時&#xff0c;無需修改代碼或手動干預&#xff0c;就能自動連接到新的數據庫實例…

Java垃圾回收_1

一、垃圾回收 1.如何判斷對象可以回收 &#xff08;1&#xff09;引用計數法 存在循環引用問題&#xff0c; Java未使用這種算法 在引用計數法中&#xff0c;每個對象都有一個引用計數器&#xff0c;記錄著指向該對象的引用數量。當引用計數器為零時&#xff0c;表示沒有任…

JavaSE:SE知識整體總結

1、引言 歷時一個多月的學習&#xff0c;已經掌握了JavaSE的知識&#xff0c;這篇博客就來做一下SE知識的總結~ 2、數據類型和變量 Java中的數據類型分為基本數據類型和引用數據類型。 2.1 基本數據類型 基本數據類型共有四類八種&#xff1a; 四類&#xff1a;整形、浮點…

在phpstorm2024版里如何使用Jetbrains ai assistant 插件 ?

ai assistant激活成功后&#xff0c;如圖 ai assistant渠道&#xff1a;https://web.52shizhan.cn/activity/ai-assistant 在去年五月份的 Google I/O 2023 上&#xff0c;Google 為 Android Studio 推出了 Studio Bot 功能&#xff0c;使用了谷歌編碼基礎模型 Codey,Codey 是…

SpringBoot HelloWorld 之 實現注冊功能

SpringBoot HelloWorld 之 實現注冊功能 一.配置 創建數據庫big_event CREATE TABLE user (id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT ID,username varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT 用戶名,password varchar(32) COLLATE utf8_unicode_ci …

Vue3項目練習詳細步驟(第五部分:用戶模塊的功能)

頂部導航欄個人信息顯示 接口文檔 接口請求與綁定 導航欄下拉菜單功能 路由實現 退出登錄和路由跳轉實現 基本資料修改 頁面結構 接口文檔 接口請求與綁定 修改頭像 頁面結構 頭像回顯 頭像上傳 接口文檔 重置密碼 頁面結構 接口文檔 接口請求與綁定 頂部導航…

自然語言處理學習路線

學習目標 NLP 系統知識&#xff08;從入門到入土&#xff09; 學習內容 NLP的基本流程&#xff1a;&#xff08;待更&#xff09;文本預處理&#xff08;標點符號處理、繁體轉簡體、分詞Tokenizer&#xff09;&#xff1a;&#xff08;待更&#xff09;詞袋模型&#xff08;TF…

【T+】暢捷通T+軟件固定資產模塊反啟用

【問題描述】 暢捷通T軟件&#xff0c;固定資產模塊反啟用。 【解決方法】 針對賬套庫執行如下腳本清除資產的所有數據&#xff0c; 執行前請與客戶確認資產的所有數據都不要了&#xff0c;確認后備份賬套再執行腳本&#xff0c;切記&#xff01;&#xff01;&#xff01; 然后…

Flutter 中的 ChipTheme 小部件:全面指南

Flutter 中的 ChipTheme 小部件&#xff1a;全面指南 Flutter 是一個由 Google 開發的跨平臺 UI 框架&#xff0c;它提供了一套豐富的組件集合&#xff0c;用于構建現代化的、響應式的移動和 Web 應用。ChipTheme 是 Flutter 中一個專門用于統一設置應用中所有 Chip 組件樣式的…

紅外熱成像觀驅一體儀,夜間驅鳥新利器

夜間驅鳥是機場鳥防工作的重點和難點&#xff0c;但紅外熱成像觀驅一體儀的出現解決了這個問題&#xff0c;它結合了紅外熱成像技術和激光驅鳥技術&#xff0c;極大地提升了夜間驅鳥工作的效率和安全性。 驅鳥技術詳解&#xff1a; 在夜晚低能見度的環境下&#xff0c;紅外熱成…