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

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

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

Postby awson » Thu 29 Dec, 2016 10:12

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

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

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

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

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

Postby DrKnS » Thu 29 Dec, 2016 10:29

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

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

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

Postby awson » Thu 29 Dec, 2016 10:56

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

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

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

Postby DrKnS » Thu 29 Dec, 2016 12:02

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

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

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

Postby awson » Thu 29 Dec, 2016 13:54

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

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

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

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

Postby Shmuel » Thu 29 Dec, 2016 14:03

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

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

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

Postby 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: 4463
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 105 times
Contact:

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

Postby DrKnS » Thu 29 Dec, 2016 19:55

awson wrote:Source of the post Но вообще, это дичь какая-то.

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

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

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

Postby 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: 4463
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 105 times
Contact:

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

Postby DrKnS » Thu 29 Dec, 2016 20:54

  1. printf("this goes to screen\n");
  2. fflush(stdout);
  3.  
  4. int fd = _dup(_fileno(stdout));
  5. freopen("out.txt", "w", stdout);
  6.  
  7. printf("this goes to file\n");
  8. fflush(stdout);
  9.  
  10. _dup2(fd, _fileno(stdout));
  11.  
  12. printf("this goes to screen again\n");
  13. fflush(stdout);

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

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

Postby 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: 4955
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 11 times
Been thanked: 125 times

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

Postby Shmuel » Thu 29 Dec, 2016 22:16

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

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

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

Postby awson » Fri 30 Dec, 2016 09:09

Shmuel wrote:У меня почему-то работает.

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

Под новым Windows 10 SDK код уважаемого DrKnS падает, хотя он, судя по всему, корректнее, поскольку не копирует FILE.
Last edited by awson on Fri 30 Dec, 2016 09:12, edited 2 times in total.

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

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

Postby DrKnS » Fri 30 Dec, 2016 14:20

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

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

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

Postby awson » Fri 30 Dec, 2016 15:14

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

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


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

Who is online

Users browsing this forum: No registered users and 2 guests