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

2024-06-01 07:04

本文主要是介绍翻译《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 是文件内容的方便格式。这对于小文件是合适的,但随着文件变大,您必须一次性生成整个文件的事实可能变得昂贵。下次我们将看看一个替代方案。

这篇关于翻译《The Old New Thing》- What a drag: Dragging a virtual file (HGLOBAL edition)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1020305

相关文章

解决JavaWeb-file.isDirectory()遇到的坑问题

《解决JavaWeb-file.isDirectory()遇到的坑问题》JavaWeb开发中,使用`file.isDirectory()`判断路径是否为文件夹时,需要特别注意:该方法只能判断已存在的文... 目录Jahttp://www.chinasem.cnvaWeb-file.isDirectory()遇

Golan中 new() 、 make() 和简短声明符的区别和使用

《Golan中new()、make()和简短声明符的区别和使用》Go语言中的new()、make()和简短声明符的区别和使用,new()用于分配内存并返回指针,make()用于初始化切片、映射... 详细介绍golang的new() 、 make() 和简短声明符的区别和使用。文章目录 `new()`

VMWare报错“指定的文件不是虚拟磁盘“或“The file specified is not a virtual disk”问题

《VMWare报错“指定的文件不是虚拟磁盘“或“Thefilespecifiedisnotavirtualdisk”问题》文章描述了如何修复VMware虚拟机中出现的“指定的文件不是虚拟... 目录VMWare报错“指定的文件不是虚拟磁盘“或“The file specified is not a virt

提示:Decompiled.class file,bytecode version如何解决

《提示:Decompiled.classfile,bytecodeversion如何解决》在处理Decompiled.classfile和bytecodeversion问题时,通过修改Maven配... 目录问题原因总结问题1、提示:Decompiled .class file,China编程 bytecode

论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey

Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染:一项综述 文章目录 大规模语言模型的基准数据污染:一项综述摘要1 引言 摘要 大规模语言模型(LLMs),如GPT-4、Claude-3和Gemini的快

论文翻译:ICLR-2024 PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS

PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS https://openreview.net/forum?id=KS8mIvetg2 验证测试集污染在黑盒语言模型中 文章目录 验证测试集污染在黑盒语言模型中摘要1 引言 摘要 大型语言模型是在大量互联网数据上训练的,这引发了人们的担忧和猜测,即它们可能已

java线程深度解析(一)——java new 接口?匿名内部类给你答案

http://blog.csdn.net/daybreak1209/article/details/51305477 一、内部类 1、内部类初识 一般,一个类里主要包含类的方法和属性,但在Java中还提出在类中继续定义类(内部类)的概念。 内部类的定义:类的内部定义类 先来看一个实例 [html]  view plain copy pu

string字符会调用new分配堆内存吗

gcc的string默认大小是32个字节,字符串小于等于15直接保存在栈上,超过之后才会使用new分配。

excel翻译软件有哪些?如何高效提翻译?

你是否曾在面对满屏的英文Excel表格时感到头疼?项目报告、数据分析、财务报表... 当这些重要的信息被语言壁垒阻挡时,效率和理解度都会大打折扣。别担心,只需3分钟,我将带你轻松解锁excel翻译成中文的秘籍。 无论是职场新人还是老手,这一技巧都将是你的得力助手,让你在信息的海洋中畅游无阻。 方法一:使用同声传译王软件 同声传译王是一款专业的翻译软件,它支持多种语言翻译,可以excel

Open a folder or workspace... (File -> Open Folder)

问题:vscode Open with Live Server 时 显示Open a folder or workspace... (File -> Open Folder)报错 解决:不可以单独打开文件1.html ; 需要在文件夹里打开 像这样