OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Воскресенье, 06 Июль, 2025 23:50

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 3 ] 
Автор Сообщение
 Заголовок сообщения: Динамический вызов процедур, Meta
СообщениеДобавлено: Вторник, 31 Август, 2010 19:43 

Зарегистрирован: Пятница, 25 Сентябрь, 2009 13:10
Сообщения: 1177
Откуда: Мариуполь
Пишу компонент для вызова процедур посредством динамической загрузки модулей - в некотором роде аналог привычных многим исполняемых файлов C/C++, у которых есть процедура main с параметрами командной строки argc, argv.

Зачем? Это такой аналог майкрософтовского RunDll32, который умеет вызывать процедуры из библиотек. Для вызова процедур не требуется наличие BlackBox, нужен лишь загрузчик этих модулей. А далее за работу отвечает загруженный компонент, как типичная исполняемая программа.

У меня возникли проблемы с использованием модуля Meta. Подробности (и сам вопрос) - ниже.

Цепочка вызова такова:
  1. TestLoader (загрузчик модулей, исполняемый/EXE) - в него я буду передавать параметры с командной строки. В последствии этот модуль будет вызываться из исполняемого файла на XDS Oberon-2 (Windows/Linux).
  2. Loader (переработанный StdInterpreter) будет запускать соответствующие процедуры по полученным параметрам (имя модуля, имя процедуры, количество аргументов, указатель на массив аргументов).
  3. Исполняемый модуль (у меня это TestExeModule).

Вот в таком модуле мы объявляем для экспорта процедуру 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.

:!: TestLoader.Run

Код:
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 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2461
Откуда: Россия, Томск
Роман М. писал(а):
Единственное подозрение у меня вызывает строка
Код:
iv.int := SYSTEM.ADR(argv);


Подскажите.
Совершенно правильное подозрение. Вот так будет работать:
Код:
      PROCEDURE ParamList ();
        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;
В процедуре Meta.PutParam не проходила следующая проверка: IF aTyp # ptrTyp THEN RETURN END;
Актуальный параметр должен быть указателем, если формальный является указателем (выше по тексту установлено, что fType = ptrTyp).

PS: Наконец-то в какой-то теме есть исходный текст, а то чего только не обсуждают. И компонент интересный.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 01 Сентябрь, 2010 09:34 

Зарегистрирован: Пятница, 25 Сентябрь, 2009 13:10
Сообщения: 1177
Откуда: Мариуполь
Работает. Спасибо!


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 3 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2025, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB