LINUX.ORG.RU

Злостный оффтоп

 offtop,


1

2

ну не на винфак (кстати, где он) мне же идти :-)

ситуация такая : есть софт, который динамически, через a-la dlopen тягает разные библиотеки (gtk, но только к примеру, он классический любитель «срать» в stderr). Всё замечательно абсолютно везде кроме Win GUI.

там (в gui офтопике) потоки stdin, stdout, stderr и соотв. 0,1,2 закрыты. Малейшая попытка write чревата. Повезёт если просто не упадёт. Я загружаю библиотеку и она может ругаться в stderr но работает, и не должна валиться от write(2,..) где-то внутри.

я вот помню что ранее давно-давно находил нужные заклинания аналогов dup2, какие необходимо произнести в виндовс ДО ТОГО и чтобы всё сложилось верно.

Проблема: я не могу повторить это на офтопике :-( открыть аналог /dev/null и dup2 его в стандартный вывод процесса.

максимум что вспомнилось

void ReopenStd()
{
	HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
	if (h==INVALID_HANDLE_VALUE) {
		// stdout закрыт, надо открыть новый и задать его в STD_OUTPUT_HANDLE
		int out=_open("NUL:",_O_WRONLY|_O_TEXT);
		if (out>=0) {
			_dup2(out,1/*STD_OUTPUT_HANDLE*/);
			_close(out);
		}
	}
	h = GetStdHandle(STD_ERROR_HANDLE);
	if (h==INVALID_HANDLE_VALUE) {
		// stderr закрыт, надо открыть новый и задать его в STD_ERROR_HANDLE
		int out=_open("NUL:",_O_WRONLY|_O_TEXT);
		if (out>=0) {
			_dup2(out,2/*STD_ERROR_HANDLE*/);
			_close(out);
		}
	}
	h = GetStdHandle(STD_INPUT_HANDLE);
	if (h==INVALID_HANDLE_VALUE) {
		// stdin закрыт, надо открыть новый и задать его в STD_INPUT_HANDLE
		int in=_open("NUL:",_O_RDONLY|_O_TEXT);
		if (in>=0) {
			_dup2(in,0/*STD_ERROR_HANDLE*/);
			_close(in);
		}
	}
}

но это неверно.

PS/ если ЧЁ: компилятор gcc, окружение msys2/mingw64

★★★★★

А проблема точно есть?

Насколько я помню, классический I/O API (без всяких асинхронностей) хоть в Windows, хоть в Linux вещь очень дубовая и если просто игнорировать ошибки (не проверять) единственным эффектом будет потеря данных (данные никуда не запишуться). А так, и read, и write отлично работают с невалидными файловыми дескрипторами, просто возвращают либо нули, либо коды ошибок.

Может быть, программа падает от чего-то другого?

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 2)

там (в gui офтопике) потоки stdin, stdout, stderr и соотв. 0,1,2 закрыты.

Они всегда закрыты если не приаттачена консоль (эмулятор терминала виндовый) или эти потоки не перенаправлены. Консоль можно приаттачить даже если приложение запускается с GUI подсистемой.

Малейшая попытка write чревата.

Чем это?

Повезёт если просто не упадёт.

Ниче там не упадет, просто вернет код ошибки.

Использовать сишный stdlib на винде я бы вообще не рекомендовал - он не умеет в юникод итд. Надо использовать WinAPI. И работать с хэндлами ОС. Которые могут и в DuplicateHandle и прочее.

То что опенсорсные приложения за редким исключением в это не могут, это печально. Не хватает мозгов понять что винда другая система и там другое API, видимо.

Я загружаю библиотеку и она может ругаться в stderr но работает, и не должна валиться от write(2,..) где-то внутри. Если она падает то от чего-то другого.

Манки-патчить CRT действительно можно(как FILE* потоки так и псевдо-unix-like-целочисленные значения дескрипторов), но не рекомендуется.

Потому что, главным образом, проблема с манки-патчингом crt в основном в том, что, неизвестно какую CRT использует библиотека которую ты загружаешь, может быть legacy msvcrt из system32, а может более новую версию из SxS. А может вообще статически влинкованную, хотя это и не рекомендуется для DLL. Они все в принципе могут одновременно существовать в одном процессе, потому что линковщик в винде так работает, в отличие от юнипсов, в которых возможны хаки с LD_PRELOAD и прочими извращениями у которых уши растут из кривой worse-is-better архитектуры так и не выросшей из 70х.

lovesan ★★
()
Ответ на: комментарий от lovesan

Ниче там не упадет, просто вернет код ошибки.

там где должно работать там падает. У меня не вполне отдельная программа, скажем так плагин/расширение в чужом приложении.

и действительно падает при записи в stdout/stderr. А если приаттачить консоль то работает как часы. Вот и ищется способ похожий на «приаттачить консоль» но без консоли, перенаправить stdout stderr в NUL: (он-же там аналог /dev/null) для всего процесса.

MKuznetsov ★★★★★
() автор топика