Как создать виртуальный файл в буфере обмена для вставки в проводник?C++

Программы на C++. Форум разработчиков
Anonymous
 Как создать виртуальный файл в буфере обмена для вставки в проводник?

Сообщение Anonymous »

В настоящее время я разрабатываю приложение wxWidgets для Windows 10/11, которое должно генерировать файл. Этот файл чувствителен к безопасности, поэтому лучше всего свести к минимуму его копии на диске. В результате я хочу создать этот файл виртуально в памяти и скопировать его в буфер обмена, чтобы пользователь мог вставить его через подключение к удаленному рабочему столу Microsoft. Я прочитал документацию Microsoft по форматам буфера обмена и попытался реализовать это с помощью wxDataFormat, wxDataObjectSimple и wxDataObjectComposite wxWidget.
Документация Microsoft привела меня к считаю, что мне нужно создать два объекта данных типа CFSTR_FILECONTENTS и CFSTR_FILEDESCRIPTOR, чтобы хранить виртуальный файл в памяти. Из исходного кода реализации MSW wxWidget видно, что wxDataObjectSimple выделяет буфер GlobalAlloc и сохраняет этот буфер в структуре STGMEDIUM, которая ожидается для этих двух форматов. В результате я создал классы VirtualFileContents и VirtualFileDescriptor, производные от wxDataObjectSimple, которые предоставляют содержимое файла и данные структуры FILEGROUPDESCRIPTOR соответственно. Класс VirtualFile является производным от wxDataObjectComposite и объединяет эти два типа вместе.
При такой реализации я мог наблюдать в нескольких программах просмотра буфера обмена Win32, которые у меня были. правильные данные буфера обмена, как описано Microsoft, с «FileContents» и «FileGroupDescriptor» в качестве типов дескрипторов «HGlobal» с ожидаемыми данными и правильным форматом внутри. При открытии контекстного меню в Проводнике доступна опция вставки, однако на несколько кадров появляется вращающийся курсор, а затем звучит системный звонок, указывающий на ошибку. Диалоговое окно с ошибкой не отображается, и файл не вставляется.
Для дальнейшего устранения этой ситуации я открыл копию Microsoft Outlook 2016 и скопировал вложение из электронного письма. Это также реализовано аналогичным образом с помощью CFSTR_FILECONTENTS и CFSTR_FILEDESCRIPTOR, но файл Outlook содержит тип «IStream», а не тип «HGlobal». Это вставлено в Проводник без проблем, и я сравнил расположение структуры FileGroupDescriptor и не обнаружил ошибок в расположении памяти. Я видел, что Outlook включает как FileGroupDescriptorW, так и FileGroupDescriptor при копировании файлов, но моя реализация также не решила проблему. Ниже приведен фрагмент моей текущей реализации:
Заголовок

Код: Выделить всё

namespace Clipboard {

class VirtualFileContents : public wxDataObjectSimple {
private:
std::string m_str;

public:
VirtualFileContents(const std::string &str);

std::size_t GetDataSize() const;
bool GetDataHere(void *buf) const;
};

class VirtualFileDescriptorW : public wxDataObjectSimple {
private:
std::wstring m_fileName;
VirtualFileContents &m_contents;

public:
VirtualFileDescriptorW(const std::wstring &file_name, VirtualFileContents &contents);

std::size_t GetDataSize() const;
bool GetDataHere(void *buf) const;
};

class VirtualFileDescriptorA : public wxDataObjectSimple {
private:
std::string m_fileName;
VirtualFileContents &m_contents;

public:
VirtualFileDescriptorA(const std::string &file_name, VirtualFileContents &contents);

std::size_t GetDataSize() const;
bool GetDataHere(void *buf) const;
};

class VirtualFile : public wxDataObjectComposite {
private:
VirtualFileContents *m_contents;
VirtualFileDescriptorW *m_wDescriptor;
VirtualFileDescriptorA *m_aDescriptor;

public:
VirtualFile(const std::string &str, const std::filesystem::path &file_name);
};

};  // namespace Clipboard
Источник

Код: Выделить всё

Clipboard::VirtualFileContents::VirtualFileContents(const std::string &str)
: wxDataObjectSimple{CFSTR_FILECONTENTS}, m_str(str) {
}

std::size_t Clipboard::VirtualFileContents::GetDataSize() const {
return this->m_str.size();
}

bool Clipboard::VirtualFileContents::GetDataHere(void *buf) const {
std::memcpy(buf, this->m_str.data(), this->m_str.size());
return true;
}

Clipboard::VirtualFileDescriptorW::VirtualFileDescriptorW(const std::wstring &file_name,
VirtualFileContents &contents)
: wxDataObjectSimple{CFSTR_FILEDESCRIPTORW}, m_fileName(file_name), m_contents(contents) {
}

std::size_t Clipboard::VirtualFileDescriptorW::GetDataSize() const {
return sizeof(FILEGROUPDESCRIPTORW);
}

bool Clipboard::VirtualFileDescriptorW::GetDataHere(void *buf) const {
if (this->m_fileName.size() >= MAX_PATH) {
std::runtime_error("File name too long.");
}

FILEGROUPDESCRIPTORW files = {
.cItems = 1,
.fgd = {{.dwFlags = 0,
.clsid = {},
.sizel = {},
.pointl = {},
.dwFileAttributes = 0x0,
.ftCreationTime = {},
.ftLastAccessTime = {},
.ftLastWriteTime = {},
.nFileSizeHigh = 0, //static_cast(this->m_contents.GetDataSize() >> 32),
.nFileSizeLow = 0, //static_cast(this->m_contents.GetDataSize() &  0xFFFFFFFF),
.cFileName = L""}}};
std::memcpy(files.fgd[0].cFileName, this->m_fileName.data(),
this->m_fileName.size() * sizeof(decltype(this->m_fileName)::value_type));

std::memcpy(buf, &files, sizeof(files));
return true;
}

Clipboard::VirtualFileDescriptorA::VirtualFileDescriptorA(const std::string &file_name,
VirtualFileContents &contents)
: wxDataObjectSimple{CFSTR_FILEDESCRIPTORA}, m_fileName(file_name), m_contents(contents) {
}

std::size_t Clipboard::VirtualFileDescriptorA::GetDataSize() const {
return sizeof(FILEGROUPDESCRIPTORA);
}

bool Clipboard::VirtualFileDescriptorA::GetDataHere(void *buf) const {
if (this->m_fileName.size() >= MAX_PATH) {
std::runtime_error("File name too long.");
}

FILEGROUPDESCRIPTORA files = {
.cItems = 1,
.fgd = {{.dwFlags = 0,
.clsid = {},
.sizel = {},
.pointl = {},
.dwFileAttributes = 0x0,
.ftCreationTime = {},
.ftLastAccessTime = {},
.ftLastWriteTime = {},
.nFileSizeHigh = 0,
.nFileSizeLow = 0,
.cFileName = ""}}};
std::memcpy(files.fgd[0].cFileName, this->m_fileName.data(),
this->m_fileName.size() * sizeof(decltype(this->m_fileName)::value_type));

std::memcpy(buf, &files, sizeof(files));
return true;
}

Clipboard::VirtualFile::VirtualFile(const std::string &str, const std::filesystem::path &file_name)
: m_contents(new VirtualFileContents{str}),
m_wDescriptor(new VirtualFileDescriptorW{file_name.wstring(), *this->m_contents}),
m_aDescriptor(new VirtualFileDescriptorA{file_name.string(), *this->m_contents}) {
this->Add(this->m_wDescriptor, true);
this->Add(this->m_aDescriptor);
this->Add(this->m_contents);
}
Копировать код

Код: Выделить всё

if (wxTheClipboard->Open()) {
wxTheClipboard->SetData(new Clipboard::VirtualFile("hello there", "test.txt"));
wxTheClipboard->Close();
}
Знает ли кто-нибудь о каких-либо недостатках в моем подходе или каких-либо инструментах, которые могли бы помочь мне отладить совместимость буфера обмена Windows/Проводника? Это более простая проблема, например, я просто исключаю время создания из структуры?

Подробнее здесь: https://stackoverflow.com/questions/790 ... o-explorer

Вернуться в «C++»