Программное перемещение текста консоли в буфер обмена на C или C++

Учитывая, что на консоли Windows 11 уже существует текст, как можно скопировать весь текст в буфер обмена с помощью C или C++?

То есть я хочу сделать программный эквивалент перетаскивания мышью по всему тексту, чтобы выделить его, а затем нажать Ctrl-C, чтобы он был захвачен в буфер обмена.

В C и C++ нет понятия ни об окне консоли, ни о том, как с ним взаимодействовать. Мне не известен какой-либо Win32 API для чтения текста консоли, который не является пользовательским вводом, поэтому, если не считать использования Win32 SendInput() для ручной имитации реальных событий мыши и клавиатуры, отправляемых в окно консоли, я не знаю ни одного другой способ сделать то, что вы хотите.

Remy Lebeau 27.08.2024 17:53

Вы задали этот вопрос вчера.

3CxEZiVlQ 27.08.2024 18:06

Вы можете использовать саму консоль, чтобы выделить текст мышкой и скопировать его. Моя утилита, которая копирует весь буфер консоли (включая прокручиваемую часть) в файл, использует GetConsoleScreenBufferInfo() для создания буфера и т. д., а затем ReadConsoleOutputCharacter() для чтения партии. Если вы хотите скопировать его в буфер обмена, вам понадобится OpenClipboard() и т. д.

Weather Vane 27.08.2024 20:30

@gregspears ОП хочет «программный эквивалент» выбора и копирования. Поэтому я сомневаюсь, что они хотят, чтобы пользователь действительно вводил Ctrl-C вручную. Программа должна взять любой текст, который уже есть в консоли, и поместить его в буфер обмена.

Remy Lebeau 27.08.2024 22:04

@RemyLebeau - спасибо, в этом есть смысл. У меня есть код для этого. По вашему опытному мнению, следует ли мне опубликовать решение или этот вопрос будет закрыт сообществом? Я опубликовал множество решений за секунды и минуты до того, как сообщество закрыло вопрос ФП — похоже, что скоро появится еще один… большое спасибо за ваши рекомендации.

greg spears 27.08.2024 22:14

@gregspears Если вы думаете, что у вас есть решение, не стесняйтесь опубликовать его.

Remy Lebeau 27.08.2024 22:22

@catnip, возможно, потому, что это похоже на запрос кода.

Weather Vane 28.08.2024 00:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот решение, как просили. Этот код я только что протестировал в MS Visual Studio и Windows OS 10.

Обратите внимание, что это непереносимый код Windows, поскольку OP запросил решение, конкретно связанное с ОС Windows, и отметил winapi.

Эта программа выводит строку в окно консоли, затем захватывает/удаляет текст из окна экрана/консоли через Windows API ReadConsoleOutputCharacter().

Текстовые данные затем копируются в буфер обмена Windows.

#include <windows.h>
#include <stdio.h>
#include <conio.h>

/*-------------------------------------------------------------------------

  copy_to_clipboard()

  Adapted from https://stackoverflow.com/a/1264179/3130521
  Credits: Judge Maygarden
*--------------------------------------------------------------------------*/
BOOL copy_to_clipboard(char *pBuff)
{
    size_t size = strlen(pBuff)+1;
    if (size > 1)
    {
        HGLOBAL hMem =  GlobalAlloc(GMEM_MOVEABLE, size);
        memcpy(GlobalLock(hMem), pBuff, size);
        GlobalUnlock(hMem);
        OpenClipboard(0);
        EmptyClipboard();
        SetClipboardData(CF_TEXT, hMem);
        CloseClipboard();
        return TRUE;
    }
    return FALSE;
}

int main() 
{
    /* Get the handle to the console window*/
    HANDLE hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO CSBI;
    int win_w,win_h,size;
    char *tbuff;
    DWORD num_chars_read;
    COORD   dwReadCoord = {0,0}; /* Read from screen top, left (0,0) */

    if (hConOut == INVALID_HANDLE_VALUE)
    {
        printf("STDOUT not available.\n");
        return 0;
    }

    /* Put some text to the screen */
    printf("This text should match the contents of the clipboard buffer on completion.\n");

    /* Get console window dims, potential text size, allocate buffer to that size */
    GetConsoleScreenBufferInfo( hConOut, &CSBI );
    win_w=CSBI.srWindow.Right - CSBI.srWindow.Left+1;
    win_h=CSBI.srWindow.Bottom - CSBI.srWindow.Top+1;
    size = win_w*win_h;
    tbuff = malloc(size+1);
    if (!tbuff)
    {
        printf("malloc() failed!\n");
        return 0;
    }

    /* Capture the text from the console window*/
    if (!ReadConsoleOutputCharacter( hConOut, tbuff, size,dwReadCoord, &num_chars_read))
    {
        free(tbuff);
        printf("ReadConsoleOutputCharacter() failed!\n");
        return 0;
    }

    /* Strip trailing whitepace (there should be a lot!)*/
    while(num_chars_read && tbuff[num_chars_read-1] == ' ')
        tbuff[--num_chars_read] = '\0';

    /* Copy text to the clipboard*/
    if (!copy_to_clipboard(tbuff))
    {
        free(tbuff);
        printf("copy_to_clipboard() failed!\n");
        return 0;
    }

    free(tbuff);  /* Always free() */

    /* Notify user done */
    printf("All done. Success. Open notepad and paste from clipboard.\n");
    _getch(); /* wait key press */

    return 0;
}

Ваш код работает. Большое спасибо. Мне пришлось изменить «tbuff = malloc(size+1);» to "tbuff = (char *)malloc(size+1);" Но в остальном это то решение, которое я искал.

Bob Penoyer 28.08.2024 02:20

@BobPenoyer — отличные новости! Очень приветствую и спасибо, что выбрали мой ответ. При добавлении приведения для malloc(): (char *) -- да, некоторые компиляторы этого хотят. Не должны, но некоторые делают, лол. Это тема для другого дня. Удачного...

greg spears 28.08.2024 02:24

@gregspears «да, некоторым компиляторам нужен [приведение для malloc()]» - точнее, каждый компилятор C не заботится об этом, и каждый компилятор C++ требует этого. В C void* неявно преобразуется в любой другой тип указателя, но в C++ это не так.

Remy Lebeau 28.08.2024 02:39

Другие вопросы по теме