OberonCore https://forum.oberoncore.ru/ |
|
Динамический вызов процедур, Meta https://forum.oberoncore.ru/viewtopic.php?f=2&t=2819 |
Страница 1 из 1 |
Автор: | Роман М. [ Вторник, 31 Август, 2010 19:43 ] |
Заголовок сообщения: | Динамический вызов процедур, Meta |
Пишу компонент для вызова процедур посредством динамической загрузки модулей - в некотором роде аналог привычных многим исполняемых файлов C/C++, у которых есть процедура main с параметрами командной строки argc, argv. Зачем? Это такой аналог майкрософтовского RunDll32, который умеет вызывать процедуры из библиотек. Для вызова процедур не требуется наличие BlackBox, нужен лишь загрузчик этих модулей. А далее за работу отвечает загруженный компонент, как типичная исполняемая программа. У меня возникли проблемы с использованием модуля Meta. Подробности (и сам вопрос) - ниже. Цепочка вызова такова:
Вот в таком модуле мы объявляем для экспорта процедуру main, в которую извне будут передаваться Код: MODULE TestExeModule; IMPORT WinApi, Dynamics; PROCEDURE ShowMessage (msg, title: ARRAY OF CHAR); VAR res: INTEGER; BEGIN res := WinApi.MessageBoxW(0, msg, title, {}); END ShowMessage; PROCEDURE main* (argc: INTEGER; argv: Dynamics.ArgList); BEGIN ShowMessage("Hello from ExeModule!", "Exe"); END main; END TestExeModule. Код: MODULE Dynamics; TYPE String* = POINTER TO ARRAY OF CHAR; ArgList* = POINTER TO ARRAY OF String; END Dynamics. Код: MODULE TestLoader; IMPORT WinApi, Dynamics, Loader, StdLog; PROCEDURE ShowMessage (msg, title: ARRAY OF CHAR); VAR res: INTEGER; BEGIN res := WinApi.MessageBoxW(0, msg, title, {}); END ShowMessage; PROCEDURE ReportError (e: Loader.TLoaderError); BEGIN StdLog.String("===Error #"); StdLog.Int(e.n); StdLog.Ln; StdLog.String(e.msg); StdLog.Ln; StdLog.String(e.par0); StdLog.Ln; StdLog.String(e.par1); StdLog.Ln; StdLog.Ln END ReportError; PROCEDURE Run*; VAR mod, proc: Dynamics.String; BEGIN NEW(mod, 64); NEW(proc, 256); mod^ := "TestExeModule"; proc^ := "main"; Loader.Run(mod, proc, 0, NIL); IF Loader.loaderError.n # 0 THEN ReportError(Loader.loaderError) END; END Run; END TestLoader. ![]() Код: MODULE Loader; IMPORT WinApi, SYSTEM, Kernel, Meta, Strings, Dynamics, Dialog; CONST modNotFound = 10; procNotFound = 11; identExpected = 12; unknownIdent = 13; depositExpected = 14; noDepositExpected = 15; syntaxError = 16; lparenExpected = 17; rparenExpected = 18; containerExpected = 19; quoteExpected = 20; fileNotFound = 21; noController = 22; noDialog = 23; cannotUnload = 24; commaExpected = 25; incompParList = 26; TYPE IntValue = POINTER TO RECORD (Meta.Value) int: INTEGER; END; StrValue = POINTER TO RECORD (Meta.Value) str: Dialog.String; END; TLoaderError* = POINTER TO RECORD n*: INTEGER; errorMsg*, msg*, par0*, par1*: POINTER TO ARRAY OF CHAR END; VAR loaderError*: TLoaderError; errorMsg: ARRAY 256 OF CHAR; par: ARRAY 100 OF POINTER TO Meta.Value; PROCEDURE ShowMessage (msg, title: ARRAY OF CHAR); VAR res: INTEGER; BEGIN res := WinApi.MessageBoxW(0, msg, title, {}); END ShowMessage; PROCEDURE FillChar (VAR s: ARRAY OF CHAR; c: CHAR); VAR i: INTEGER; BEGIN i := 0; WHILE s[i] # 0X DO s[i] := c; INC(i) END; END FillChar; PROCEDURE Init; BEGIN NEW(loaderError); loaderError.n := 0; NEW(loaderError.errorMsg, 256); NEW(loaderError.msg, 256); NEW(loaderError.par0, 256); NEW(loaderError.par1, 256); END Init; PROCEDURE Error (res: INTEGER; msg, par0, par1: ARRAY OF CHAR); VAR e, f: ARRAY 256 OF CHAR; BEGIN IF res # 0 THEN loaderError.n := res; IF errorMsg # "" THEN loaderError.errorMsg^ := errorMsg$ ELSE loaderError.errorMsg^ := "#System:CommandError" END; loaderError.msg^ := msg$; loaderError.par0^ := par0$; loaderError.par1^ := par1$; (* IF errorMsg # "" THEN Dialog.MapString(errorMsg, e); Dialog.MapParamString(msg, par0, par1, "", f); IF e # " " THEN f := e$ + ' ' + f$ (*Concat(e, f, f);*) ELSE Dialog.MapString("#System:CommandError", f) END; ShowMessage(f, "Error") END *) END END Error; PROCEDURE Run* (_module, _proc: Dynamics.String; argc: INTEGER; argv: Dynamics.ArgList); VAR res, numPar: INTEGER; errmsg: Dialog.String; PROCEDURE ShowLoaderResult (IN mod: ARRAY OF CHAR); VAR res: INTEGER; importing, imported, object: ARRAY 256 OF CHAR; BEGIN Kernel.GetLoaderResult(res, importing, imported, object); CASE res OF | Kernel.fileNotFound: Error(res, "#System:CodeFileNotFound", imported, "") | Kernel.syntaxError: Error(res, "#System:CorruptedCodeFileFor", imported, "") | Kernel.objNotFound: Error(res, "#System:ObjNotFoundImpFrom", imported, importing) | Kernel.illegalFPrint: Error(res, "#System:ObjInconsImpFrom", imported, importing) | Kernel.cyclicImport: Error(res, "#System:CyclicImpFrom", imported, importing) | Kernel.noMem: Error(res, "#System:NotEnoughMemoryFor", imported, "") ELSE Error(res, "#System:CannotLoadModule", mod, "") END END ShowLoaderResult; PROCEDURE CallProc (IN mod, proc: ARRAY OF CHAR); VAR i, t: Meta.Item; ok: BOOLEAN; BEGIN ok := FALSE; Meta.Lookup(mod, i); IF i.obj = Meta.modObj THEN i.Lookup(proc, i); IF i.obj = Meta.procObj THEN i.GetReturnType(t); ok := (t.typ = 0) & (i.NumParam() = numPar); IF ok THEN i.ParamCallVal(par, t, ok) ELSE Error(incompParList, "#System:IncompatibleParList", mod, proc) END ELSE Error(Kernel.commNotFound, "#System:CommandNotFoundIn", proc, mod) END ELSE ShowLoaderResult(mod) END; IF ~ok THEN ShowMessage("CallProc error", "Error") END END CallProc; PROCEDURE ParamList (); VAR iv: IntValue; sv: StrValue; BEGIN numPar := 0; NEW(iv); iv.int := argc; par[numPar] := iv; INC(numPar); NEW(iv); iv.int := SYSTEM.ADR(argv); par[numPar] := iv; INC(numPar); END ParamList; BEGIN Init; errmsg := "~"; ParamList (); CallProc(_module, _proc (*"main"*)) END Run; END Loader. В принципе, частично уже работает: запускается процедура некоторого модуля, у которой нет параметров. Допустим, если процедура main не имеет параметров и numPar = 0, то всё замечательно запускается. но как только я указываю параметры для передачи аргументов, тут начинаются проблемы. Судя по всему, проблема заключается в подготовке параметров для передаче их процедуре ParamCallVal. На строке i.ParamCallVal(par, t, ok) я получаю ok = FALSE (неудача). Единственное подозрение у меня вызывает строка Код: iv.int := SYSTEM.ADR(argv); Подскажите. |
Автор: | Александр Ильин [ Среда, 01 Сентябрь, 2010 04:36 ] |
Заголовок сообщения: | Re: Динамический вызов процедур, Meta |
Роман М. писал(а): Единственное подозрение у меня вызывает строка Совершенно правильное подозрение. Вот так будет работать:Код: iv.int := SYSTEM.ADR(argv); Подскажите. Код: PROCEDURE ParamList (); В процедуре Meta.PutParam не проходила следующая проверка: IF aTyp # ptrTyp THEN RETURN END;TYPE ArgValue = POINTER TO RECORD (Meta.Value) arg: PrivDynamics.ArgList END; VAR iv: IntValue; av: ArgValue; BEGIN numPar := 0; NEW(iv); iv.int := argc; par[numPar] := iv; INC(numPar); NEW(av); av.arg := argv; par[numPar] := av; INC(numPar); END ParamList; Актуальный параметр должен быть указателем, если формальный является указателем (выше по тексту установлено, что fType = ptrTyp). PS: Наконец-то в какой-то теме есть исходный текст, а то чего только не обсуждают. И компонент интересный. |
Автор: | Роман М. [ Среда, 01 Сентябрь, 2010 09:34 ] |
Заголовок сообщения: | Re: Динамический вызов процедур, Meta |
Работает. Спасибо! |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |