OberonCore https://forum.oberoncore.ru/ |
|
Перенаправление stdout в лог https://forum.oberoncore.ru/viewtopic.php?f=2&t=1266 |
Страница 1 из 2 |
Автор: | QWERTYProgrammer [ Воскресенье, 30 Ноябрь, 2008 16:15 ] |
Заголовок сообщения: | Перенаправление stdout в лог |
Еще один вопрос по-поводу использования dll: если в Блэкбоксе вызывается функция из dll, которая пишет какие-нибудь сообщения в stdout, можно ли как-то перенаправить вывод в StdLog? |
Автор: | Илья Ермаков [ Воскресенье, 30 Ноябрь, 2008 16:41 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
Вообще говоря, DLL наследует handle файла stdout от всего процесса. Значит, это хэндл получить можно. Можно и перехватить как-то (до начала работы с ДЛЛ открыть этот файл вместо консоли на куда-то ещё). |
Автор: | Илья Ермаков [ Воскресенье, 30 Ноябрь, 2008 16:42 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
Копать в сторону WinApi-функций CreateFile и AllocConsole. |
Автор: | Евгений Темиргалеев [ Понедельник, 01 Декабрь, 2008 12:34 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
Мне кажется, копать надо в сторону pipe и SetStdHandle. Идея такая: - сделать трубу, хендл записи назначить на STD_OUTPUT_HANDLE. - dll пишет в трубу, в ББ из неё периодически читается и выводится в лог. |
Автор: | Евгений Темиргалеев [ Понедельник, 01 Декабрь, 2008 12:39 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
Неименованные трубы, как я понял, поддерживают только блокирующие операции, что со стороны ББ не допустимо. Попробовал сделать с именованными, но застрял в трубе при открытии её на запись. Кто подскажет? Код: MODULE TestStdToLog;
IMPORT WinApi, Dialog, Strings; CONST INVALID_HANDLE_VALUE = -1; pipeName = "\\.\pipe\stdoutToBBLog"; VAR read, write: WinApi.HANDLE; ovrl: WinApi.OVERLAPPED; PROCEDURE ShowWinErr (IN act: ARRAY OF CHAR); VAR msg: ARRAY 512 OF CHAR; err, res: INTEGER; BEGIN err := WinApi.GetLastError(); res := WinApi.FormatMessageW( WinApi.FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, msg, LEN(msg), NIL ); IF res = 0 THEN (* Описание ошибки не получено *) Strings.IntToString(err, msg); msg := msg + " (WinAPI-код ошибки)" END; Dialog.ShowParamMsg("Ошибка при ^0: ^1", act, msg, "") END ShowWinErr; PROCEDURE Uninstall; VAR res: INTEGER; BEGIN IF write # INVALID_HANDLE_VALUE THEN res := WinApi.CloseHandle(write); write := INVALID_HANDLE_VALUE; IF res = 0 THEN ShowWinErr("CloseHandle(write)") END END; IF read # INVALID_HANDLE_VALUE THEN res := WinApi.CloseHandle(read); read := INVALID_HANDLE_VALUE; IF res = 0 THEN ShowWinErr("CloseHandle(read)") END END; (* An instance of a named pipe is always deleted when the last handle to the instance of the named pipe is closed. *) IF ovrl.hEvent # INVALID_HANDLE_VALUE THEN res := WinApi.CloseHandle(ovrl.hEvent); ovrl.hEvent := INVALID_HANDLE_VALUE; IF res = 0 THEN ShowWinErr("CloseHandle(ovrl.hEvent)") END END END Uninstall; PROCEDURE CreatePipe; VAR res: INTEGER; BEGIN res := WinApi.CreateNamedPipe( pipeName, ORD({WinApi.PIPE_ACCESS_INBOUND} + WinApi.FILE_FLAG_OVERLAPPED), WinApi.PIPE_TYPE_BYTE + WinApi.PIPE_READMODE_BYTE + WinApi.PIPE_WAIT, 1, 1024, (* ? *) 1024, (* ? *) 1, (* ? *) NIL); IF res # INVALID_HANDLE_VALUE THEN read := res ELSE ShowWinErr("CreateNamedPipe") END END CreatePipe; PROCEDURE ConnectPipe; VAR res: INTEGER; ovrl: WinApi.OVERLAPPED; BEGIN (* If hNamedPipe was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must not be NULL. It must point to a valid OVERLAPPED structure. If hNamedPipe was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function can incorrectly report that the connect operation is complete. If hNamedPipe was created with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the OVERLAPPED structure pointed to by lpOverlapped must contain a handle to a manual-reset event object (which the server can create by using the CreateEvent function). *) ovrl.hEvent := WinApi.CreateEvent(NIL, WinApi.TRUE, WinApi.FALSE, NIL); IF ovrl.hEvent # 0 THEN res := WinApi.ConnectNamedPipe(read, ovrl); IF res = 0 THEN ShowWinErr("ConnectNamedPipe") END ELSE ShowWinErr("CreateEvent") END END ConnectPipe; PROCEDURE Install; VAR res: INTEGER; BEGIN read := INVALID_HANDLE_VALUE; write := INVALID_HANDLE_VALUE; CreatePipe; IF read # INVALID_HANDLE_VALUE THEN ConnectPipe; res := WinApi.CreateFile( pipeName, WinApi.GENERIC_WRITE, {}, NIL, WinApi.OPEN_EXISTING, (* ? *) WinApi.FILE_ATTRIBUTE_NORMAL, (* ? *) 0 ); IF res = INVALID_HANDLE_VALUE THEN ShowWinErr("CreateFile") ELSE (* res # INVALID_HANDLE_VALUE *) write := res END END END Install; BEGIN Install CLOSE Uninstall END TestStdToLog. ^Q "Kernel.LoadMod('TestStdToLog')" |
Автор: | Trurl [ Понедельник, 01 Декабрь, 2008 15:42 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
Евгений Темиргалеев писал(а): Неименованные трубы, как я понял, поддерживают только блокирующие операции, что со стороны ББ не допустимо. Нам ведь только почитать, так что допустимо. PeekNamedPipe, вопреки названию, работает и с анонимными каналами. |
Автор: | QWERTYProgrammer [ Понедельник, 01 Декабрь, 2008 16:49 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
Действительно, msdn говорит http://msdn.microsoft.com/en-us/library/aa365779(VS.85).aspx, что PeekNamedPipe Function Copies data from a named or anonymous pipe into a buffer without removing it from the pipe. It also returns information about data in the pipe. Надо бы попробовать. |
Автор: | Евгений Темиргалеев [ Понедельник, 01 Декабрь, 2008 23:20 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
Trurl, спасибо, получилось. QWERTYProgrammer, осталось посмотреть в какой stdout будет писать dll ![]() Код: MODULE TestStdToLog; IMPORT WinApi, Dialog, Strings, Log, Services, SYSTEM; CONST INVALID_HANDLE_VALUE = -1; TYPE Action = POINTER TO RECORD (Services.Action) END; VAR a: Action; read, write: WinApi.HANDLE; PROCEDURE ShowWinErr (IN act: ARRAY OF CHAR); VAR msg: ARRAY 512 OF CHAR; err, res: INTEGER; BEGIN err := WinApi.GetLastError(); res := WinApi.FormatMessageW( WinApi.FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, msg, LEN(msg), NIL ); IF res = 0 THEN (* Описание ошибки не получено *) Strings.IntToString(err, msg); msg := msg + " (WinAPI-код ошибки)" END; Dialog.ShowParamMsg("Ошибка при ^0: ^1", act, msg, "") END ShowWinErr; PROCEDURE WriteChar (c: SHORTCHAR); BEGIN CASE c OF | 09X: Log.Tab | 0AX, 0DX: Log.Ln ELSE Log.Char(c) END END WriteChar; PROCEDURE (a: Action) Do; VAR res, avail, n: INTEGER; c: SHORTCHAR; BEGIN res := WinApi.PeekNamedPipe(read, 0, 0, NIL, avail, NIL); (*IF (res = 0) THEN ShowWinErr("PeekNamedPipe") END;*) IF (res # 0) & (avail > 0) THEN (*Log.Int(avail); Log.Ln;*) res := WinApi.ReadFile(read, SYSTEM.ADR(c), 1, n, NIL); (*IF (res = 0) THEN ShowWinErr("ReadFile") END;*) WHILE (res # 0) & (n = 1) & (avail > 0) DO WriteChar(c); DEC(avail); IF avail > 0 THEN res := WinApi.ReadFile(read, SYSTEM.ADR(c), 1, n, NIL); (*IF (res = 0) THEN ShowWinErr("ReadFile") END;*) END END END; Services.DoLater(a, Services.Ticks() + Services.resolution) END Do; PROCEDURE Install; VAR res: INTEGER; BEGIN read := INVALID_HANDLE_VALUE; write := INVALID_HANDLE_VALUE; res := WinApi.CreatePipe(read, write, NIL, 0); IF res # 0 THEN res := WinApi.SetStdHandle(WinApi.STD_OUTPUT_HANDLE, write); IF res # 0 THEN NEW(a); Services.DoLater(a, Services.Ticks() + Services.resolution) ELSE ShowWinErr("SetStdHandle") END ELSE ShowWinErr("CreatePipe") END END Install; PROCEDURE Uninstall; VAR res: INTEGER; BEGIN IF write # INVALID_HANDLE_VALUE THEN res := WinApi.CloseHandle(write); write := INVALID_HANDLE_VALUE; IF res = 0 THEN ShowWinErr("CloseHandle(write)") END END; IF read # INVALID_HANDLE_VALUE THEN res := WinApi.CloseHandle(read); read := INVALID_HANDLE_VALUE; IF res = 0 THEN ShowWinErr("CloseHandle(read)") END END END Uninstall; PROCEDURE Do*; VAR str: ARRAY 1024 OF SHORTCHAR; res, wr: INTEGER; BEGIN str := "Тест" + 09X + "Test" + 09X + "***" + 0AX; res := WinApi.WriteFile(write, SYSTEM.ADR(str), LEN(str$), wr, NIL); IF wr # LEN(str$) THEN ShowWinErr("WriteFile") END END Do; BEGIN Install CLOSE Uninstall END TestStdToLog. ^Q TestStdToLog.Do P.S. Сонным работать не айс... Получилось не сразу ![]() - сначала "не печаталось", из-за Services.DoLater(a, Services.Ticks() + Services.resolution * 1000) - потом печатался мусор из-за res := WinApi.WriteFile(write, SYSTEM.ADR(str), LEN(str), wr, NIL); - и повторно "не печаталось" из-за скопированного в начале ... Services.resolution * 1000 |
Автор: | Trurl [ Вторник, 02 Декабрь, 2008 10:33 ] |
Заголовок сообщения: | Re: Перенаправление stdout в лог |
надо ещё добится того, чтобы SetStdHandle выполнилось раньше, чем dll-ка сделает GetStdHandle. |
Автор: | QWERTYProgrammer [ Среда, 03 Декабрь, 2008 01:06 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
Евгений Темиргалеев писал(а): Trurl, спасибо, получилось. QWERTYProgrammer, осталось посмотреть в какой stdout будет писать dll ![]() Что то на ночь глядя не соображу, что нужно сделать кроме импорта TestStdToLog, чтобы перехватить перехватить печать в stdout при вызове в ББ функции, определенной в dll? ![]() |
Автор: | Евгений Темиргалеев [ Среда, 03 Декабрь, 2008 12:09 ] |
Заголовок сообщения: | Re: Перенаправление stdout в лог |
Задумывалось, что: - для включения перенаправления нужно загрузить модуль Kernel.LoadMod("TestStdToLog") - для выключения - выгрузить Kernel.UnloadMod("TestStdToLog"). Trurl писал(а): надо ещё добится того, чтобы SetStdHandle выполнилось раньше, чем dll-ка сделает GetStdHandle. Для этого, мне кажется, достаточно грузить модуль до модуля с dll-м интерфейсом.
|
Автор: | Евгений Темиргалеев [ Среда, 03 Декабрь, 2008 13:08 ] |
Заголовок сообщения: | Re: Перенаправление stdout в лог |
Евгений Темиргалеев писал(а): - для выключения - выгрузить Kernel.UnloadMod("TestStdToLog"). Ошибся. Так не выгрузить. Для тестов DevDebug.UnloadThis; программно - можно экспортировать Install/Uninstall, подправив:Код: PROCEDURE Install; ... >> IF a = NIL THEN NEW(a) END; Services.DoLater(a, Services.Ticks() + Services.resolution) PROCEDURE Uninstall; VAR res: INTEGER; BEGIN >> IF a # NIL THEN Services.RemoveAction(a) END; Проба с дельфовой dll - вывод не пошёл. Код: MODULE TestStdToLogDll ["Project1.dll"];
PROCEDURE Test*; END TestStdToLogDll. MODULE TestTemp; IMPORT TestStdToLogDll, Log; PROCEDURE Do*; BEGIN Log.String("TestStdToLogDll.Test:"); Log.Ln; TestStdToLogDll.Test END Do; END TestTemp. "Kernel.LoadMod('TestStdToLog')" TestTemp.Do DevDebug.UnloadThis TestStdToLog (* Delphi dll *) library Project1; uses SysUtils, Classes; {$R *.res} procedure Test; begin writeln('x'#9'='#9, 1); end; exports Test; begin end. |
Автор: | Edward Ivanov [ Среда, 03 Декабрь, 2008 14:33 ] |
Заголовок сообщения: | Re: Перенаправление stdout в лог |
IMHO, для dll (Delphi) нужно указать консольный режим. {$APPTYPE CONSOLE} |
Автор: | Евгений Темиргалеев [ Среда, 03 Декабрь, 2008 15:00 ] |
Заголовок сообщения: | Re: Перенаправление stdout в лог |
Спасибо, что обратили внимание. Но это, кажется, не то. Delphi Help писал(а): The $APPTYPE directive controls whether to generate a Win32 console or graphical UI application...
|
Автор: | Edward Ivanov [ Среда, 03 Декабрь, 2008 15:38 ] |
Заголовок сообщения: | Re: Перенаправление stdout в лог |
Write(ln) работает при этой включенной директиве. Иначе AV. |
Автор: | Евгений Темиргалеев [ Среда, 03 Декабрь, 2008 15:42 ] |
Заголовок сообщения: | Re: Перенаправление stdout в лог |
Delphi Help писал(а): The $APPTYPE directive is meaningful only in a program. It should not be used in a library, unit, or package. Как для library, пока не понятно. Пробовал напрямую WriteFile(GetStdHandle(STD_OUTPUT_HANDLE)... из dll - печатает.
... In Delphi code, Write writes one or more values to a text file. F, if specified, is a text file variable. If F is omitted, the standard file variable Output is assumed. ... var Output: Text; In Delphi, the Output variable is a write-only Text file associated with the process's standard output file. On Windows, most processes don't have a standard output file, and writing to Output raises an error. Delphi programs have a standard output file if they are linked as console applications. |
Автор: | Евгений Темиргалеев [ Среда, 03 Декабрь, 2008 15:58 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
QWERTYProgrammer писал(а): Что то на ночь глядя не соображу, что нужно сделать кроме импорта TestStdToLog, чтобы перехватить перехватить печать в stdout при вызове в ББ функции, определенной в dll? Кроме загрузки TestStdToLog ничего не требуется. У Вас сишный длл? Тоже не работает?
![]() |
Автор: | Trurl [ Среда, 03 Декабрь, 2008 16:15 ] |
Заголовок сообщения: | Re: Перенаправление stdout в лог |
Евгений Темиргалеев писал(а): Trurl писал(а): надо ещё добится того, чтобы SetStdHandle выполнилось раньше, чем dll-ка сделает GetStdHandle. Для этого, мне кажется, достаточно грузить модуль до модуля с dll-м интерфейсом.Начнем с того, что модуль с dll-м интерфейсом вообще не загружается. А если модуль использует dll, то она будет загружена и проинициализирована раньше модуля. Если dll выполнит GetStdHandle во время нициализации, а потом сохранит полученный дескриптор и будет использовать его, то все манипуляции со SetStdHandle будут бесполезными. |
Автор: | Евгений Темиргалеев [ Среда, 03 Декабрь, 2008 17:42 ] |
Заголовок сообщения: | Re: Перенаправление stdout в лог |
Имелось ввиду грузить модуль TestStdToLog, который при инициализации вып. SetStdHandle. До загрузки некоторго другого модуля, который использует dll. |
Автор: | QWERTYProgrammer [ Четверг, 04 Декабрь, 2008 00:52 ] |
Заголовок сообщения: | Re: трансляция структуры из h файла |
Евгений Темиргалеев писал(а): QWERTYProgrammer писал(а): Что то на ночь глядя не соображу, что нужно сделать кроме импорта TestStdToLog, чтобы перехватить перехватить печать в stdout при вызове в ББ функции, определенной в dll? Кроме загрузки TestStdToLog ничего не требуется. У Вас сишный длл? Тоже не работает?![]() Да, dll - сишный. И увы тоже не работает. |
Страница 1 из 2 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |