Добрый день, спрашиваю тут, т.к. сам решения вопроса не вижу.
Задача:
Запустить через критпроцесс консольное приложение, перенаправив потоки ввода вывода в родительскую программу, далее кинуть в поток ввода число, далее прочитать поток вывода.
Вроде задача не сложная, делаем так:
Переменные:
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa;
LPSECURITY_ATTRIBUTES lpsa = NULL;
Ну и собственно критпроцесс:
if(!CreateProcess(NULL,filename, NULL, NULL, TRUE, 0, 0, 0, &si, &pi))
{
dialog_send("Could not open file (error %d)\r\n", GetLastError());
return;
}
Работает нормально, однако запуская приложение написанное на Assembler'е я получаю Краш дочерней проги без каких либо объяснений, ошибку критпроцесс не возвращает, опытным путем выяснил, что без использования перенаправления stdin/stdout(STARTF_USESTDHANDLES) запускается нормально.
В чем проблема непонятно, может есть какие-то ньюансы работы потоковых перенаправлений с ASM программами?
После детальных исследований было выявлено место краша:
00401063 mov bl,byte ptr [esi]
Дизасм запускаемой ассемблеровской проги прилагается: http://paste.org/pastebin/view/20366
Похоже ошибка доступа к памяти гдето в дочерней проге.
Немного смущает наличие вызова AllocConsole. Оно что, собирается без опции /SUBSYSTEM:CONSOLE? Не уверен, что в этом случае поля si.hStdOutput и si.hStdInput будут использованы, хотя не проверял. И ещё, вряд-ли стоит наследовать оба конца пайпов, лучше, по-моему, воспользоваться DuplicateHandle для получения ненаследуемых хёндлов.
По сабжу — почему бы не подключиться отладчиком, воспользовавшись, к примеру, CREATE_SUSPENDED или даже просто sleep'ом?
Здравствуйте, Jolly Roger, Вы писали:
JR>Здравствуйте, Selestin, Вы писали:
AllocConsole вызывается в асм проге для инициализации консоли, компилится она masm32 вроде.
Вот кусок кода:
invoke AllocConsole
invoke GetStdHandle,-11
mov stdout,eax
invoke GetStdHandle,STD_INPUT_HANDLE
mov stdin,eax
Вроде как-то так работает.
Про дубликат хендл пишут, что копировать ввод вывод можно только в пределах процесса:
Консольный ввод данных (Console input):
Дескриптор возвращается функцией CreateFile, когда установлен CONIN$, или функцией GetStdHandle, когда установлен флажок STD_INPUT_HANDLE. Консольные дескрипторы могут быть дублированы для использования только в том же самом процессе.
Экранный буфер консоли (Console screen buffer):
Дескриптор возвращается функцией CreateFile, когда установлен CONOUT$, или функцией GetStdHandle, когда установлен флажок STD_OUTPUT_HANDLE. Консольные дескрипторы могут быть продублированы для использования только в том же самом процессе.
Здравствуйте, Selestin, Вы писали:
S>AllocConsole вызывается в асм проге для инициализации консоли, компилится она masm32 вроде.
С masm32 поставляется линкер Link.exe, который знает опцию /SUBSYSTEM:CONSOLE. Посмотрите в папке masm32\bin, там должен быть файл BUILDC.BAT. Я просто далеко не уверен, что унаследованные хёндлы будут использованы для консоли, созданной вызовом AllocConsole.
S>Про дубликат хендл пишут, что копировать ввод вывод можно только в пределах процесса: S>Консольный ввод данных (Console input): S>Дескриптор возвращается функцией CreateFile, когда установлен CONIN$, или функцией GetStdHandle, когда установлен флажок STD_INPUT_HANDLE. Консольные дескрипторы могут быть дублированы для использования только в том же самом процессе.
Ну вот и оставьте себе ненаследуемые продублированные "концы", а наследуемые закройте. В запускаемом приложении должно быть по одному хёндлу из каждой пара, зачем ему все четыре?
JR>С masm32 поставляется линкер Link.exe, который знает опцию /SUBSYSTEM:CONSOLE. Посмотрите в папке masm32\bin, там должен быть файл BUILDC.BAT. Я просто далеко не уверен, что унаследованные хёндлы будут использованы для консоли, созданной вызовом AllocConsole.
Дело в том что задача моей программы запускать любые приложения написанные не мной, а студентами, поэтому вся задача осложняется тем, что я не могу проконтролировать процесс сборки.
JR>Ну вот и оставьте себе ненаследуемые продублированные "концы", а наследуемые закройте. В запускаемом приложении должно быть по одному хёндлу из каждой пара, зачем ему все четыре?
Теперь понял, спасибо.
Всетаки не получилось сделать через пайпы, из-за того что дочерняя прога вызывает AllocConsole.
Появился вариант сделать через AttachConsole, темболее что хендл дочернего процесса я знаю, т.к. сам его создаю.
Функция
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"1\r\n ",2,&BytesBuffer,NULL);
Работает на ура, буфер вывода легко читаем и записываем.
Проблемы возникли с STD_INPUT_HANDLE, пробовал сделать WriteFile туда, ничего не происходит, однако через пайпы этой функцией отправляло все нормально, может нужно эмулировать нажатие enter? Хотя мне кажется врядли, мож я что не так делаю?
S>Проблемы возникли с STD_INPUT_HANDLE, пробовал сделать WriteFile туда, ничего не происходит, однако через пайпы этой функцией отправляло все нормально, может нужно эмулировать нажатие enter? Хотя мне кажется врядли, мож я что не так делаю?
Похоже что stdin открыт только для чтения, но какже тогда работает клавиатура? Она же записывает туда как-то?
Пробовал открывать для записи так:
hCrt = _open_osfhandle((long) GetStdHandle(STD_INPUT_HANDLE), _O_TEXT);
hf = _fdopen( hCrt, "w" );
*stdin = *hf;
Здравствуйте, Selestin, Вы писали:
S>Проблемы возникли с STD_INPUT_HANDLE, пробовал сделать WriteFile туда, ничего не происходит, однако через пайпы этой функцией отправляло все нормально, может нужно эмулировать нажатие enter? Хотя мне кажется врядли, мож я что не так делаю?