【问题标题】:Windows Explorer Paste: Hook or etcWindows 资源管理器粘贴:Hook 等
【发布时间】:2022-10-23 14:06:23
【问题描述】:

我想挂钩/把手Windows资源管理器粘贴。

描述:提议是远程复制/粘贴。像团队查看器或远程桌面。在一台计算机上按 Ctrl+C 文件,在另一台计算机上按 Ctrl+V...

有什么建议(赞赏 c++ 或 c# 示例)?

【问题讨论】:

  • 当您在一台计算机上复制时,将 FILEGROUPDESCRIPTOR 放在另一台计算机上。然后,您可以在粘贴过程中动态生成数据。您将获得一个免费的复制进度对话框。

标签: c++ hook paste remote-desktop windows-explorer


【解决方案1】:

好吧,让我们把这个问题分成 3 个部分:

1.检测剪贴板更改:

这很简单,通过使用SetClipboardViewer 注册一个钩子,Windows 会很好地向我们发送WM_DRAWCLIPBOARD 消息:

HWND nextClipboardViewer = nullptr;

void HandleClipboardChanges()
{

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_CREATE:
            nextClipboardViewer = SetClipboardViewer(hwnd);
            break;

        case WM_CHANGECBCHAIN:
            if (reinterpret_cast<HWND>(wParam) == nextClipboardViewer)
            {
                nextClipboardViewer = reinterpret_cast<HWND>(lParam);
            }
            else if (nextClipboardViewer != nullptr)
            {
                SendMessage(nextClipboardViewer, msg, wParam, lParam);
            }
            break;

        case WM_DRAWCLIPBOARD:
            HandleClipboardChanges();
            SendMessage(nextClipboardViewer, msg, wParam, lParam);
            break;
    }
}

2. 获取活动的 Windows Explorer 目录

在上面的 HandleClipboardChanges 函数中,我们应该遍历所有打开的 Windows 资源管理器,检查其中是否有焦点,并获取它们的当前目录,感谢 zett42's answer,我们可以很容易地做到这一点:

HWND hWndExplorer = nullptr;
HWND hWndFocused = GetActiveWindow();
std::wstring explorerDir;

for (const auto& info : GetCurrentExplorerFolders())
{
    if (hWndFocused == info.hwnd)
    {
        CComHeapPtr<wchar_t> pPath;
        if (SUCCEEDED(::SHGetNameFromIDList(info.pidl.get(), SIGDN_FILESYSPATH, &pPath)))
        {
            hWndExplorer = info.hwnd;
            explorerDir = pPath;
        }

        break;
    }
}

3.处理复制操作并显示进度对话框

对于进度对话框,我们会使用IProgressDialog,虽然IOperationsProgressDialog的功能比较多,但是也比较难用,可以考虑换用。

传递给IProgressDialog::StartProgressDialoghWndParent 可以是nullptr,但我们将使用资源管理器的hWnd 以保持一致性。

下面的代码不检查可读性错误。

// don't forget the include and CoInitialize
#include <atlbase.h>
#include <shlobj_core.h>

CoInitializeEx(nullptr, COINIT_MULTITHREADED);

CComPtr<IProgressDialog> pDialog;

pDialog.CoCreateInstance(CLSID_ProgressDialog);

pDialog->StartProgressDialog(hWndExplorer, nullptr, PROGDLG_AUTOTIME, nullptr);

pDialog->SetTitle(L"Copying from network");
pDialog->SetLine(1, L"Copying 69 files", false, nullptr);

// Do your copy operation here
for (DWORD i = 0; i < 1'000'000; i++)
{
    pDialog->SetProgress(i, 1'000'000);
    pDialog->SetLine(2, L"Copying file_a.txt", false, nullptr);

    // Check if the user had cancelled the operation
    // See also: pDialog->SetCancelMsg()
    // BOOL isUserCancelled = pDialog->HasUserCancelled();
}

pDialog->StopProgressDialog();

【讨论】:

    【解决方案2】:

    没有必要为此挂钩任何东西。至少从 Windows 3.0 开始,复制/粘贴一直是 Windows 功能的主要内容。 Windows 资源管理器不是很特别;它也会在您复制时将项目放在 Windows 剪贴板上,并在您粘贴时从 Windows 剪贴板中获取项目。

    【讨论】:

    • 我认为这个想法是显示进度对话框
    • 您在不了解问题和场景的情况下让法官禁食。想象一下远程连接到另一台计算机。然后您将 Ctrl-C 用于 100mb 的大文件。它不聪明,也不用于通过网络立即复制到本地剪贴板。也许用户也想在远程机器上粘贴,而不是通过网络传输......但是当用户严格执行粘贴时,此时有网络调用传输这么大的文件。所以 PASTE 需要是钩子。请删除不赞成票
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    相关资源
    最近更新 更多