|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
||||
|
||||
IDE для Ruby (развитие для себя)
Ребят, только не бросайтесь фразами: "А уже дофига всяких IDE, зачем тратить время, силы бла бла бла всё равно лучше не сделаешь"
Я для себя. Просто хочу разобраться как эти программы работают. Значит проблема следующая: как отдать файл компилятору (интерпретатору), и вернуть результат в виде ошибок, если они есть. Я так понимаю командная строка + CreateProcess? Или есть более элегантные решения? Последний раз редактировалось Uniq!, 13.04.2013 в 22:54. |
#2
|
||||
|
||||
Как-то обертку над консольным php.exe делал, результаты через пайпы затягивать приходилось. А рубивский компиль какой?
— Как тебя понимать? — Понимать меня не обязательно. Обязательно меня любить и кормить вовремя. На Delphi, увы, больше не программирую. Рекомендуемая литература по программированию |
#3
|
||||
|
||||
Он не компилер, он интерпретатор.
По факту своя ком строка, которая понимает синтаксис Ruby Сейчас проблема такая: Код:
procedure TForm1.aRunExecute(Sender: TObject); begin aSave.Execute; rLog.Items.Add('[' + TimeToStr(Now) + '] Running ' + rSave.FileName); ShellExecute(0, 'open', 'cmd.exe', PWideChar('/k ruby ' + rSave.FileName), 'C:\Windows\system32\', SW_SHOW); end; если в rSave.FileName лежит строка с пробелами\русскими символами\символами типа !"№;%:?*()_ полный путь к интерпретируемому файлу обрывается Последний раз редактировалось Uniq!, 13.04.2013 в 23:56. |
#4
|
|||
|
|||
если только для руби, и если https://github.com/charliesome/better_errors работает под windows, то можно попробовать создать в той папке временный файл, примерно как тот, что там в секции Usage, но в get запускающий тот файл, который должен выкинуть ошибку, запустить временный файл, и webbrowser.navigate(туда). если выскочит ошибка, то по идее должна отоброзится в webbrowser
>woweook< |
#5
|
||||
|
||||
Цитата:
Код:
...PWideChar('/k ruby "' + rSave.FileName + '"'), ... Цитата:
jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 14.04.2013 в 12:15. |
#6
|
||||
|
||||
Я же написал "символами типа"
Проблема не решена, но... Я за ночь докопался вот до такой процедуры: Код:
procedure ExecConsoleApp(CommandLine: AnsiString; Output: TStringList; Errors: TStringList); var sa: TSECURITYATTRIBUTES; si: TSTARTUPINFO; pi: TPROCESSINFORMATION; hPipeOutputRead: THANDLE; hPipeOutputWrite: THANDLE; hPipeErrorsRead: THANDLE; hPipeErrorsWrite: THANDLE; Res, bTest: Boolean; env: array [0 .. 100] of Char; szBuffer: array [0 .. 256] of Char; dwNumberOfBytesRead: DWORD; Stream: TMemoryStream; begin sa.nLength := sizeof(sa); sa.bInheritHandle := true; sa.lpSecurityDescriptor := nil; CreatePipe(hPipeOutputRead, hPipeOutputWrite, @sa, 0); CreatePipe(hPipeErrorsRead, hPipeErrorsWrite, @sa, 0); ZeroMemory(@env, sizeof(env)); ZeroMemory(@si, sizeof(si)); ZeroMemory(@pi, sizeof(pi)); si.cb := sizeof(si); si.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; si.wShowWindow := SW_HIDE; si.hStdInput := 0; si.hStdOutput := hPipeOutputWrite; si.hStdError := hPipeErrorsWrite; { Если вы хотите запустить процесс без параметров, заnil`те второй параметр и используйте первый } Res := CreateProcess(nil, pchar(CommandLine), nil, nil, true, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, @env, nil, si, pi); // Если не получилось - то выходим if not Res then begin CloseHandle(hPipeOutputRead); CloseHandle(hPipeOutputWrite); CloseHandle(hPipeErrorsRead); CloseHandle(hPipeErrorsWrite); Exit; end; CloseHandle(hPipeOutputWrite); CloseHandle(hPipeErrorsWrite); // Читаем вывод Stream := TMemoryStream.Create; try while true do begin bTest := ReadFile(hPipeOutputRead, szBuffer, 256, dwNumberOfBytesRead, nil); if not bTest then begin break; end; Stream.Write(szBuffer, dwNumberOfBytesRead); end; Stream.Position := 0; Output.LoadFromStream(Stream); finally Stream.Free; end; // Вывод о ошибках Stream := TMemoryStream.Create; try while true do begin bTest := ReadFile(hPipeErrorsRead, szBuffer, 256, dwNumberOfBytesRead, nil); if not bTest then begin break; end; Stream.Write(szBuffer, dwNumberOfBytesRead); end; Stream.Position := 0; Errors.LoadFromStream(Stream); finally Stream.Free; end; WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(hPipeOutputRead); CloseHandle(hPipeErrorsRead); end; При вызове CreateProcess ошибка: (вложения) |
#7
|
||||
|
||||
Ну env тут явно лишний. Но это не ошибка.
Какая делфя? Судя по юзанию AnsiString, скорее что-то после 10й. В таком случае нехорошо преобразовывать AnsiString к PChar. Тогда уж к PAnsiChar, или строку юзать (Wide)String. Но вообще взятие в кавычки должно было все решить. Параметры в кавычках передаются CMD в прогу без изменений как один параметр. jmp $ ; Happy End! The Cake Is A Lie. |
#8
|
||||
|
||||
@env - уже убрал, зачем передавать указатель на левые переменные o.O ?
Ошибка сейчас ( как можно заметить ) не в текстовых преобразованиях, а в доступе к kernel32.dll ибо в неё "записать" не может. Delphi XE3 |
#9
|
||||
|
||||
Ошибка возникает внутри kernel32 (большой адрес), но при попытке записать в маленькие адреса (write of address 5accc0). Так что это не запись В kernel32, это запись по недоступному адресу ИЗ нее.
С МСДНа: Цитата:
jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 14.04.2013 в 12:51. |
Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
Uniq! (14.04.2013)
|
#10
|
||||
|
||||
Вот собственно всё и прояснилось. Действительно ошибки из-за преобразований туда сюда...
Я в этом полный ноль, особенно когда речь идёт о разных версиях Delphi. Сама команда CreateProcess должна принимать PWideChar (по документации), я же ей передаю нечто в одинарных кавычках (это какой тип? ) и как мне от него к PWideChar грамотно перейти. И за одно чего-нибудь почитать дайте, пожалуйста. |
#11
|
||||
|
||||
Нечто в кавычках - это делфовая строка. Преобразование в PChar/PAnsiChar/PWideChar по сути одно и то же - возвращает переданный функции преобразования параметр без изменений (кроме случая строки нулевой длины вроде). Потому что делфийская строка - оригинальный класс, в котором адрес класса есть адрес начала строки (массива байт), а все поля класса отсчитываются в минус от этого адреса. Там 3 поля. Длина, размер выделенного блока и количество использований (для многопоточности, чтобы не снести строку, пока ее кто-то юзает).
Если строка имеет изначальный тип WideString (в XE3 WideString = String), то при записи туда строки 'Hello, world!' она автоматически записывается как Wide. И преобразовывать к PWideChar можно. Если она Ansi, то записывается как Ansi (однобайтовые символы), и преобразовывать к Wide не так просто. Разве что сделать Код:
var s:AnsiString; w:WideString; ... s := '1234'; w := s; PWideChar(w); Почитать - дизассемблированный листинг делфийских программ. Я не видел инфы о внутреннем устройстве делфийских строк в инете. Хотя не особо искал. Но вывод о том, что адрес строки есть адрес именно массива байт можно сделать по исходникам преобразователей в P<чего-нибудь>Char или ручками сделав Код:
for i := 1 to length(s) do wirite(AnsiChar(Pointer(s)^)); jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 14.04.2013 в 13:12. |
Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
Uniq! (14.04.2013)
|
#12
|
||||
|
||||
Для будущих поколений: ссылка к прочтению, и куча инфы о том, как это всё преобразовывать.
Проблема решена. Обязательным условием должно быть то, что lpCommandLine - переменная (write acessable), а не константа. Функцией Код:
UniqueString(CommandLine); Код:
CreateProcessW(nil, PWideChar(CommandLine), nil, nil, false, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, si, pi); Новая проблема: в output и error пусто. Передаю я ей в качестве CommabdLine следующее: C:\Ruby200\bin\ruby.exe c:/Uni1.rb в Unit1.rb лежит Код:
puts 'hello world' Проблема тут: Код:
Stream := TMemoryStream.Create; try while true do if ReadFile(hPipeOutputRead, szBuffer, 256, dwNumberOfBytesRead, nil) then Stream.Write(szBuffer, dwNumberOfBytesRead) else break; Stream.Position := 0; Output.LoadFromStream(Stream); finally Stream.Free; end; Внутрь условия не заходит, т.е. ReadFile возвращает False;причина я так думаю всё в тех же Код:
szBuffer: array [0 .. 256] of Char; GetLastError вернул Код:
ERROR_BROKEN_PIPE 109 (0x6D) The pipe has been ended. Разобрался! Ошибка означает, что приложение уже закрылось Т.е. запускать ruby.exe надо с ключём /K Код:
ExecConsoleApp('cmd /K ruby c:/Unit1.rb', Output, error); Последний раз редактировалось Uniq!, 14.04.2013 в 14:08. |