Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Место, где разработчики плагинов могут поделиться своим опытом.
Post Reply
awson
Posts: 26
Joined: Fri 11 Sep, 2009 13:22

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by awson » Thu 29 Dec, 2016 10:12

Предположим, я использую стороннюю библиотеку, которую линкую в плагин, т.е., ее код исполняется непосредственно в процессе Фара.

И вот эта библиотека где-то там у себя внутри вдруг пишет в stdout (и stderr) всякое, и оно, соответственно, прям поверх красивого синего Фара серым цветом изображается.

Кто-нибудь с такой проблемой сталкивался и решал ли? Какие идеи? Тупейшее лобовое закрытие перед вызовом, а потом переоткрытие stdout'а после -- не срабатывает, то есть надо ковыряться. Понятно, что так или иначе проблему решить можно, но, может, в Фаре есть какая-то готовая функциональность для этого?

User avatar
DrKnS
Posts: 4535
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 113 times
Contact:

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by DrKnS » Thu 29 Dec, 2016 10:29

Если вы будете играться с перенаправлением stdout, то поломаете вывод самого фара.
Кроме того, ничто не мешает библиотеке напрямую открывать CONOUT$.
Поэтому или уносить в отдельный процесс, или просить автора библиотеки так не делать.

awson
Posts: 26
Joined: Fri 11 Sep, 2009 13:22

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by awson » Thu 29 Dec, 2016 10:56

А если известно, что код библиотеки использует *только* стандартный fprintf stdout/stderr?

User avatar
DrKnS
Posts: 4535
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 113 times
Contact:

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by DrKnS » Thu 29 Dec, 2016 12:02

Стандартный наверное можно заткнуть каким нибудь freopen("nul","w",stdout).
Только не забудьте потом поставить обратно, т. к. другие могут использовать его для вполне легитимных целей.

awson
Posts: 26
Joined: Fri 11 Sep, 2009 13:22

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by awson » Thu 29 Dec, 2016 13:54

Вот как раз "поставить назад" не получалось. То есть, и полное закрытие и перенаправление работало, а когда потом "ставил назад", фар затихал секунды на 3 и падал.

Я, в общем, не копал, просто решил сначала спросить, чтоб, в случае чего, не ломиться в открытые ворота. Ну, покопаю тогда.

Shmuel
Posts: 5041
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 11 times
Been thanked: 133 times

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by Shmuel » Thu 29 Dec, 2016 14:03

Как вариант может сгодиться обёртка вызовов функций библиотеки парой FCTL_GETUSERSCREEN/FCTL_SETUSERSCREEN.

awson
Posts: 26
Joined: Fri 11 Sep, 2009 13:22

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by awson » Thu 29 Dec, 2016 19:12

В общем, проблему нашел, к ФАРу она отношения не имеет. На всякий случай напишу тут, а то вдруг кто напорется.

Проблемой является откровенный маразм в заголовочных файлах M$.
В corecrt_wstdio.h (это Windows 10 SDK -- у них теперь CRT частично в Windows SDK входит) написано такое:

Code: Select all

    typedef struct _iobuf
    {
        void* _Placeholder;
    } FILE;
Т.е., любой код, который копирует структуру FILE, копирует только sizeof(void*) байтов. И мой код

Code: Select all

*stdout = ...
(это я stdout "на место возвращаю") в том числе.

И если переопределить структуру FILE нормально (как например, в mingw-w64), или скопировать нужное количество байтов руками, то всё начинает работать нормально.

Ну, я, типа, понимаю, что правильные с точки зрения MS разработчики не должны хотеть копировать структуру FILE, а должны воспринимать ее сугубо как opaque и никогда не разыменовывать указатели на нее. Но вообще, это дичь какая-то. Похоже, это у них началось с момента перетряхивания структуры CRT.

User avatar
DrKnS
Posts: 4535
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 113 times
Contact:

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by DrKnS » Thu 29 Dec, 2016 19:55

awson wrote: Но вообще, это дичь какая-то.
Почему дичь? Стандарт явно запрещает разыменовывать и копировать FILE*, содержимое и размер структуры нигде не оговорены и ваше ручное копирование байтов вполне может вычурно отвалиться при первом же апдейте CRT.
Лучше использовать что-то типа _fdopen(_dup(_fileno(stdout)), "w").

awson
Posts: 26
Joined: Fri 11 Sep, 2009 13:22

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by awson » Thu 29 Dec, 2016 20:41

stdout это rvalue, вы не можете ему ничего присвоить.

написать

Code: Select all

stdout = _fdopen(old_stdout, "w")
нельзя.

Вы сначала делаете

Code: Select all

int old_stdout = _dup(1)
потом зовете нужную функцию, а потом "возвращаете" stdout с помощью

Code: Select all

*stdout = * _fdopen(old_stdout, "w")
Но если стандарт запрещает копировать FILE, значит либо подобные вещи в общем случае вообще нельзя делать, либо делать не на уровне CRT.

User avatar
DrKnS
Posts: 4535
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 113 times
Contact:

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by DrKnS » Thu 29 Dec, 2016 20:54

  1. printf("this goes to screen\n");
  2.  
  3. fflush(stdout);
  4.  
  5.  
  6.  
  7. int fd = _dup(_fileno(stdout));
  8.  
  9. freopen("out.txt", "w", stdout);
  10.  
  11.  
  12.  
  13. printf("this goes to file\n");
  14.  
  15. fflush(stdout);
  16.  
  17.  
  18.  
  19. _dup2(fd, _fileno(stdout));
  20.  
  21.  
  22.  
  23. printf("this goes to screen again\n");
  24.  
  25. fflush(stdout);

awson
Posts: 26
Joined: Fri 11 Sep, 2009 13:22

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by awson » Thu 29 Dec, 2016 21:07

Ничо не понял, но не работает :)
Last edited by awson on Thu 29 Dec, 2016 21:21, edited 2 times in total.

Shmuel
Posts: 5041
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 11 times
Been thanked: 133 times

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by Shmuel » Thu 29 Dec, 2016 22:16

awson wrote: Ничо не понял, но не работает :)
У меня почему-то работает.

awson
Posts: 26
Joined: Fri 11 Sep, 2009 13:22

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by awson » Fri 30 Dec, 2016 09:09

Shmuel wrote:У меня почему-то работает.
Чтобы не работало, нужен *новый* Windows 10 SDK, который ставится, например, с VS 2017RC и, возможно, с VS2015. У меня есть гипотеза, что с более старыми студиями (до перетряски CRT) оно тоже работает, как, например, оно прекрасно работает с mingw-w64 gcc.

Под новым Windows 10 SDK код уважаемого DrKnS падает, хотя он, судя по всему, корректнее, поскольку не копирует FILE.

User avatar
DrKnS
Posts: 4535
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 113 times
Contact:

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by DrKnS » Fri 30 Dec, 2016 14:20

У меня на VS2015, SDK v10.0.10240.0 всё работает.
FILE там такой же, как у вас выше.
Если в 2017RC падает - возможно, это баг, есть смысл написать им на https://connect.microsoft.com/VisualStudio

awson
Posts: 26
Joined: Fri 11 Sep, 2009 13:22

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by awson » Fri 30 Dec, 2016 15:14

Ха, у меня оказался немного другой код (там был еще fclose(stdout), а потом _fdopen ...), так вот он падал на 2015 и 2017 и работал на 2012 (откопал ее и проверил) и mingw-w64. Я сейчас в точности воспроизвел ваш и он действительно работает на всех версиях.

Вопросы снимаются.

dmvo
Posts: 4
Joined: Thu 25 May, 2017 09:01

Сторонняя библиотека, *линкуемая* в плагин, пишет в stdout (stderr)

Post by dmvo » Thu 25 May, 2017 09:52

У меня такая ситуация. Мое решение: перед каждой операцией с такой библиотекой делаю PanelControl(FCTL_GETUSERSCREEN), а после, соответственно, FCTL_SETUSERSCREEN. И мирюсь с тем, что не получится сделать диалог прогресса копирования файлов, например.

Post Reply

Return to “Разработка плагинов”

Who is online

Users browsing this forum: No registered users and 4 guests