Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.55/11: Рейтинг темы: голосов - 11, средняя оценка - 4.55
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2871 / 1042
Регистрация: 01.06.2021
Сообщений: 10,508

Эксперты по Pipes заходите

28.12.2023, 18:53. Показов 2340. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Решил изучить Pipes и возникла следующая проблема.

Имею десктопное приложение, которое получает и отправляет данные с консольного приложения. Само консольное приложение не видно. Т.е. я создаю дочерний процесс консольного приложения, который запускается фоново, к которому подключаю анонимные каналы через CreatePipe.
Всё работает. Т.е. у меня получается отправить или принять данные с консольного приложения.

Вот только после записи в канал (отправки текста к консольному приложению), я больше не могу читать из канала (получать данные из консольного приложения). Проблема в том, что моя функция, которая записывает в канал, закрывает дескриптор (handle) для записи в канал, чтобы дочерний процесс прекратил читать. Но вот этот дескриптор нужен для следующей записи, а он уже закрыт. Т.е. получается так, что я не могу отправить текст от десктопного приложения к консольному более одного раза.

Что посоветуете?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
28.12.2023, 18:53
Ответы с готовыми решениями:

Человеки не пролистывайте, заходите
Измените код Только напишите что вы изменили #include <iostream> #include <ctime> using namespace std; int main() { ...

Вычисление определенного интеграла.ЗАХОДИТЕ!
Вычисление определенного интеграла методом трапеций и методом парабол На языке python..желательно простым языком работа для 1-ого курса

Все, кто знают о сайтостроении.Заходите
Всем привет)Ребята, кто знают что нибудь про сайтостроении или даже не знают (научимся командно) читайте дальше:)Есть идея создать...

12
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2871 / 1042
Регистрация: 01.06.2021
Сообщений: 10,508
29.12.2023, 01:57  [ТС]
Может я плохо объясняю. Попробую иначе.

Есть родительский процесс, который создает дочерний процесс. Между двумя процессами должен идти двусторонний обмен информацией.
Для этого я устанавливаю две трубы (канала). Трубы направленные, поэтому для двусторонней связи нужно иметь две трубы: одна от родителя к потомку, вторая - от потомка к родителю. У каждого конца трубы есть дескриптор (handle). Итого есть 4 дескриптора. Схематически это выглядит так:

IN_WRITE (родитель) >>> OUT_WRITE (потомок)
OUT_READ (родитель) <<< IN_READ (потомок)

Дескрипторы труб со стороны потомка (OUT_WRITE и IN_READ) закрываются сразу же после создания процесса, ибо они не нужны.

Действие Write to Pipe
Дескриптор IN_WRITE используется для функции WriteFile, с помощью которой я отправляю данные от родителя к потомку.
Действие Read from Pipe
Дескриптор OUT_READ используется для функции ReadFile, с помощью которой я читаю данные от потомка к родителю.

Действие Read from Pipe я могу повторить много раз.
Проблема с действием Write to Pipe. Дело в том, что после WriteFile я закрываю дескриптор IN_WRITE (без этого у меня не получается больше Read from Pipe и так советуют в документации). Но, как вы понимаете, после закрытия дескриптора одна труба становится непригодной. Я могу дальше использовать вторую трубу для Read from Pipe, но я больше не могу отправить данные от родителя к потомку (действие Write to Pipe), ибо не имею валидного дескриптора для WriteFile.

Таким образом, с помощью анонимных двух труб я могу получить сколько угодно данных от потомка к родителю, но у меня получается только один раз отправить данные от родителя к потомку. Но мне нужно, чтобы я имел такую возможность много раз.
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
29.12.2023, 11:50
Цитата Сообщение от Royal_X Посмотреть сообщение
Что посоветуете
вариант "не закрывать" - не подходит?
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2871 / 1042
Регистрация: 01.06.2021
Сообщений: 10,508
29.12.2023, 11:51  [ТС]
Алексей1153, если не закрывать, то почему-то больше не могу читать

Даже в доку сказано, что нужно закрывать

// Close the pipe handle so the child process stops reading.
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
29.12.2023, 11:54
Royal_X, надо поразбираться с кодами ошибок. Может, флажок ошибки какой-то скидывать надо

Добавлено через 1 минуту
Цитата Сообщение от Royal_X Посмотреть сообщение
Даже в доку сказано, что нужно закрывать
// Close the pipe handle so the child process stops reading.
это же не обязательно. Это не в доке, а в примере кода - им так захотелось
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2871 / 1042
Регистрация: 01.06.2021
Сообщений: 10,508
29.12.2023, 11:56  [ТС]
Алексей1153, если не закрывать, то после WriteFile зависает. В коде на сайте майкрософт тоже закрывают. И вот получается, что для чтения ничего закрывать не нужно, поэтому я могу получить данные от дочернего процесса к родителю сколько угодно. Но вот для записи я закрываю и соответственно только раз могу отправить от родителя к потомку
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
29.12.2023, 11:59
Royal_X, думаю, нужно прицепить проект с примером, в котором кто-то смог бы поковыряться
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2871 / 1042
Регистрация: 01.06.2021
Сообщений: 10,508
29.12.2023, 12:08  [ТС]
Алексей1153, ок

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#ifndef UNICODE
#define UNICODE
#endif
 
#include <windows.h>
#include <string>
#include <stdio.h>
 
void OnCreate(HWND);
void CreateChildProcess();
void ReadFromPipe();
void WriteToPipe();
 
HWND g_edit;
 
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
 
/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
 
/*  Make the class name into a global variable  */
WCHAR szClassName[] = L"CodeBlocksWindowsApp";
 
INT WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE, LPSTR, int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */
 
    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);
 
    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
 
    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;
 
    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           L"UCI Chess Engine Test",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );
 
    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);
 
    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }
 
    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}
 
 
/*  This function is called by the Windows function DispatchMessage()  */
 
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            OnCreate(hwnd);
            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }
 
    return 0;
}
 
void OnCreate(HWND hwnd)
{
    g_edit = CreateWindow(
        L"EDIT",
        NULL,
        WS_CHILD | WS_BORDER | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE,
        10,10,
        500,200,
        hwnd,
        NULL,
        (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE),
        NULL
    );
 
    SECURITY_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    // Set the bInheritHandle flag so pipe handles are inherited.
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;
 
    // Create a pipe for the child process's STDIN.
    if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
    {
        printf("STDIN CreatePipe failed (%lu).\n", GetLastError());
        return;
    }
 
    // Ensure the write handle to the pipe for STDIN is not inherited.
    if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
    {
        printf("STDIN SetHandleInformation\n");
        return;
    }
 
    // Create a pipe for the child process's STDOUT.
    if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
    {
        printf("STDOUT CreatePipe failed (%lu).\n", GetLastError());
        return;
    }
 
    // Ensure the read handle to the pipe for STDOUT is not inherited.
    if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
    {
        printf("STDOUT SetHandleInformation\n");
        return;
    }
/*
    ╔══════════════════╗                ╔══════════════════╗
    ║  Parent Process  ║                ║  Child Process   ║
    ╠══════════════════╣                ╠══════════════════╣
    ║                  ║                ║                  ║
    ║ g_hChildStd_IN_Wr╟─────────────>>>║g_hChildStd_IN_Rd ║
    ║                  ║                ║                  ║
    ║g_hChildStd_OUT_Rd║<<<─────────────╢g_hChildStd_OUT_Wr║
    ║                  ║                ║                  ║
    ╚══════════════════╝                ╚══════════════════╝
*/
    // Create the child process.
    CreateChildProcess();
 
    Sleep(1000);
    ReadFromPipe();
    Sleep(1000);
    WriteToPipe();
    Sleep(1000);
    ReadFromPipe();
//    Sleep(1000);
//    WriteToPipe();
//    Sleep(1000);
//    ReadFromPipe();
}
 
void CreateChildProcess()
{
    // Create a child process that uses the previously created pipes for STDIN and STDOUT.
 
    // Set up members of the PROCESS_INFORMATION structure.
    PROCESS_INFORMATION pi;
    ZeroMemory( &pi, sizeof(pi) );
 
    // Set up members of the STARTUPINFO structure.
    // This structure specifies the STDIN and STDOUT handles for redirection.
    STARTUPINFO si;
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    si.hStdError = g_hChildStd_OUT_Wr;
    si.hStdOutput = g_hChildStd_OUT_Wr;
    si.hStdInput = g_hChildStd_IN_Rd;
    si.dwFlags |= STARTF_USESTDHANDLES;
 
    WCHAR szCmdline[] = L"stockfish.exe";
 
    // Create the child process.
    if( !CreateProcess(
                NULL,
                szCmdline,      // command line
                NULL,           // Process handle not inheritable
                NULL,           // Thread handle not inheritable
                TRUE,           // Handles are inherited
                NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, // Creation flags
                NULL,           // Use parent's environment block
                NULL,           // Use parent's starting directory
                &si,            // Pointer to STARTUPINFO structure
                &pi )           // Pointer to PROCESS_INFORMATION structure
            )
    {
        // If an error occurs, exit the application.
        printf( "CreateProcess failed (%lu).\n", GetLastError() );
        return;
    }
 
    // Close handles to the child process and its primary thread.
    // Some applications might keep these handles to monitor the status
    // of the child process, for example.
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
 
    // Close handles to the stdin and stdout pipes no longer needed by the child process.
    // If they are not explicitly closed, there is no way to recognize that the child process has ended.
    CloseHandle(g_hChildStd_OUT_Wr);
    CloseHandle(g_hChildStd_IN_Rd);
 
    printf( "Child process created\n");
}
 
void WriteToPipe()
{
    DWORD dwWritten;
 
    CHAR text[] = "uci";
 
    WriteFile(g_hChildStd_IN_Wr, text, 3, &dwWritten, NULL);
 
    printf( "Chars written: %lu\n", dwWritten);
 
    // Close the pipe handle so the child process stops reading.
    if ( !CloseHandle(g_hChildStd_IN_Wr) )
        printf("Error: CloseHandle hStdinWrite (%lu)\n", GetLastError());
}
 
void ReadFromPipe()
{
    DWORD dwRead;
    CHAR chBuf[4096];
 
    ReadFile(g_hChildStd_OUT_Rd, chBuf, 4096, &dwRead, NULL);
 
    printf( "Chars read: %lu\n", dwRead);
 
    std::wstring text(chBuf, chBuf + dwRead);
    SetWindowText(g_edit, text.c_str());
}


Алексей1153, в коде я использую Sleep, но это временное решение, потом поставлю таймеры, чтобы не блокировать главный процесс.

Добавлено через 4 минуты
Алексей1153, на 243 я закрываю и отсюда проблема
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
29.12.2023, 12:30
Цитата Сообщение от Royal_X Посмотреть сообщение
stockfish.exe
а он всё вычитывает?
remarks

pipes

Pipes (Interprocess Communications)
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2871 / 1042
Регистрация: 01.06.2021
Сообщений: 10,508
29.12.2023, 12:39  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
а он всё вычитывает?
хз, но один раз успешно отправляет текст "uci"
Миниатюры
Эксперты по Pipes заходите  
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2871 / 1042
Регистрация: 01.06.2021
Сообщений: 10,508
29.12.2023, 15:49  [ТС]
Алексей1153, кстати, на скриншоте результат чтения после успешной отправки команды "uci".

Т.е. сперва мы прочли 61 символ с дочернего процесса (их на скриншоте нет, т.к. второе чтение их уже удалило. Там была одна строка - приветствие шахматного движка)
Потом мы отправили текст "uci" - 3 символа. Эта команда просит движку вывести все доступные опции движка.
И далее мы получили 1242 символа, которые видны на скриншоте. Раз получили этот текст, то команда uci была успешно отправлена и отработана дочерним процессом.


Upd

Алексей1153, проблема решена
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
29.12.2023, 15:53
Royal_X, что было?
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6178 / 2871 / 1042
Регистрация: 01.06.2021
Сообщений: 10,508
29.12.2023, 21:39  [ТС]
Связь с движком работает, всё получилось



Кто хочет, может тестировать. Рядом с программой должен лежать файл "stockfish.exe". Хотя, вы можете использовать любой движок с таким именем...
Движок скачать можно отсюда. Не забудьте переименовать файл на "stockfish.exe" и положить рядом с программой.
В архиве также есть текстовый файл с описанием команд UCI-протокола.
Вложения
Тип файла: 7z Chess engine GUI.7z (80.1 Кб, 5 просмотров)
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
29.12.2023, 21:39
Помогаю со студенческими работами здесь

Ищу крутую и динамическую музыку! Заходите, не стесняйтесь!
Недавно услышал трек Subkulture feat. Klayton of Celldweller – Erasus и мне просто сорвало крышу... Пишите, может вы знаете музыку(такую...

Создаем тест Векслера. Кто готов поучаствовать заходите
Расклад такой я создал более-менее годную к использования delphi форму теста, точнее не форму, а формы(1- где инструкция и тест, 3-...

Платный хостинг Можно получить БЕСПЛАТНО заходите халява
Теперь платный хостинг без рекламы можно получить бесплатно на сайте много функций и доменов заходите...

Фраза 'Заходите сюда' в теге title. Есть ли санкции?
В контекстной рекламе за такие призывы по рукам бьют (объявления блокируют). А в поиске что с ними делают?

Эксперты обобщенного программирования
Прошу подсказать в чем тут ошибка ? Вот часть когда куда указывают ошибки: template &lt; class ArrayList&lt;T&gt;&gt; class Iterator ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru