AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 78750285
Accepted
Thomas Weller
Thomas Weller
Asked: 2024-07-15 22:02:31 +0800 CST2024-07-15 22:02:31 +0800 CST 2024-07-15 22:02:31 +0800 CST

Renderizando a área de transferência repetidamente

  • 772

Tenho um aplicativo que usa renderização atrasada da área de transferência para colar a hora atual. Mas: quando a hora for renderizada uma vez, sempre irá colar a mesma hora, e não a hora atualizada.

Acho que precisaria ligar SetClipboardData(CF_TEXT, nullptr);novamente, para restaurar outro caso de renderização atrasada, mas não sei quando ou onde devo fazer isso. Posso detectar quando o aplicativo de destino retirou os dados da área de transferência?

Como posso colar a hora atual cada vez que o usuário pressiona Ctrl+V?

#include <windows.h>
#include <thread>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>

// Get current time with milliseconds (HH:MM:SS.xxx)
void GetTime(std::string& time_str)
{
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);
    auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
    std::tm bt{};
    localtime_s(&bt, &in_time_t);
    std::ostringstream oss;
    oss << std::put_time(&bt, "%H:%M:%S") << '.' << std::setfill('0') << std::setw(3) << milliseconds.count();
    time_str = oss.str();
}

void RenderClipboardData(HWND hwnd) {
    std::string time_str;
    GetTime(time_str);

    EmptyClipboard();

    // Allocate global memory for the clipboard data
    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, time_str.size() + 1);
    if (hGlobal) {
        // Lock the global memory and copy the string into it
        void* pGlobal = GlobalLock(hGlobal);
        if (pGlobal) {
            memcpy(pGlobal, time_str.c_str(), time_str.size() + 1);
            GlobalUnlock(hGlobal);
            SetClipboardData(CF_TEXT, hGlobal);
        }
        else
        {
            // Free the global memory if it wasn't successfully set
            GlobalFree(hGlobal); 
        }
    }
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    switch (uMsg) {
    case WM_RENDERFORMAT:
        if (wParam == CF_TEXT) {
            RenderClipboardData(hwnd);
        }
        break;
    case WM_CREATE:
         CreateWindow(
            L"STATIC",
            L"This application pastes the current time on Ctrl+V. ",
            WS_VISIBLE | WS_CHILD,
            10, 10, 600, 100,
            hwnd,
            nullptr,
            reinterpret_cast<LPCREATESTRUCT>(lParam)->hInstance,
            nullptr);

        if (OpenClipboard(hwnd)) {
            EmptyClipboard();
            SetClipboardData(CF_TEXT, nullptr); // Delayed rendering to get the current time
            CloseClipboard();
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {

    constexpr wchar_t CLASS_NAME[] = L"SampleWindowClass";

    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        L"Delayed Clipboard Rendering", // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, 640, 120,

        nullptr,       // Parent window    
        nullptr,       // Menu
        hInstance,     // Instance handle
        nullptr        // Additional application data
    );

    if (hwnd == nullptr) {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);

    MSG msg = {};
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

Eu tentei:

  • processar a WM_DESTROYCLIPBOARDmensagem e redefinir a área de transferência para renderização atrasada.
c++
  • 1 1 respostas
  • 50 Views

1 respostas

  • Voted
  1. Best Answer
    Remy Lebeau
    2024-07-16T01:47:51+08:002024-07-16T01:47:51+08:00

    Em primeiro lugar, você NÃO deve ligar EmptyClipboard()ao renderizar o texto. Outro aplicativo que deseja o texto já abriu a área de transferência, então basta colocar o texto na área de transferência e não fazer mais nada.

    Agora, para realizar o que deseja, você pode fazer com que seu WM_RENDERFORMATmanipulador poste uma mensagem personalizada em sua janela após renderizar os dados e, em seguida, emitir uma nova renderização de atraso a partir desse manipulador de mensagens, por exemplo:

    bool SetClipboardDataDelayRendered(HWND hwnd) {
        if (!OpenClipboard(hwnd)) return false;
        EmptyClipboard();
        SetClipboardData(CF_TEXT, nullptr); // Delayed rendering to get the current time
        CloseClipboard();
        return true;
    }
    
    void RenderClipboardData(HWND hwnd) {
        ...
        // DO NOT DO THIS HERE!
        // EmptyClipboard();
        ...
    }
    
    static const UINT WM_SET_CB_DELAY_RENDERED = WM_USER + 100;
    
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    
        switch (uMsg) {
        case WM_CREATE:
            ...
            SendMessage(hwnd, WM_SET_CB_DELAY_RENDERED, 0, 0);
            break;
        case WM_SET_CB_DELAY_RENDERED:
            // keep trying until the clipboard can be opened...
            if (!SetClipboardDataDelayRendered(hwnd))
                PostMessage(hwnd, WM_SET_CB_DELAY_RENDERED, 0, 0);
            break;
        case WM_RENDERFORMAT:
            if (wParam == CF_TEXT) {
                RenderClipboardData(hwnd);
                // the other app has the clipboard open,
                // wait for it to close before resetting it...
                PostMessage(hwnd, WM_SET_CB_DELAY_RENDERED, 0, 0);
            }
            break;
        ...
        }
        return 0;
    }
    

    Dito isso, lembre-se de que depois de solicitar a renderização atrasada de seus dados, outro aplicativo poderá aparecer e substituir o conteúdo da área de transferência por seus próprios dados, portanto, sua renderização atrasada irá parar de funcionar. Você pode detectar essa condição manipulando WM_DESTROYCLIPBOARDe/ou usando GetClipboardOwner()para ter certeza de que você HWNDainda é o proprietário. Talvez seja necessário usar um cronômetro ou outro mecanismo para reiniciar a renderização atrasada se isso acontecer.

    • 1

relate perguntas

  • Por que os compiladores perdem a vetorização aqui?

  • Erro de compilação usando CMake com biblioteca [fechada]

  • Erro lançado toda vez que tento executar o premake

  • Como criar um tipo de octeto semelhante a std::byte em C++?

  • Somente operações bit a bit para std::byte em C++ 17?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve