Как вызвать процедуру или функцию, когда мы не знаем о параметрах? - PullRequest
5 голосов
/ 19 марта 2011

Мое приложение должно обеспечивать возможность вызова различных функций и процедур из внешних библиотек DLL.Поэтому мы не знаем количество параметров и их типы.Что я должен сделать, чтобы сделать это?

Позвольте мне объяснить это подробнее.Мое приложение представляет собой инструмент RAD, и у него есть собственный сценарий и синтаксис ... Я хочу позволить пользователям использовать файл ANY dll и вызывать любые функции или процедуры, которые они хотят.Я не могу использовать простой метод вызова dll (LoadLibrary, а затем GetProcAddress), потому что я не знаю, к какому типу относится GetProcAddress (var Proc:procedure (A:??;B:??;...)).

Ответы [ 4 ]

5 голосов
/ 19 марта 2011

У меня есть реализация Delphi в скриптовой функциональности моего ZGameEditor-проекта, поиск «TExpExternalFuncCall.Execute» в файле ниже:

http://code.google.com/p/zgameeditor/source/browse/trunk/ZExpressions.pas

Протестировано и работает под Windows(x86 и x64), Linux, Android (ARM) и OS X (x86).Обрабатывает соглашения о вызовах stdcall и cdecl.

Но libFFI, вероятно, является более общим, чем моя реализация, поэтому я рекомендовал бы такой подход.

4 голосов
/ 19 марта 2011

Это простой пример, который работает на моей машине, но я не специалист по этому вопросу.

procedure TForm4.Button1Click(Sender: TObject);
var
  hmod: HMODULE;
  paddr: pointer;         
  c1, c2, ret: cardinal;
begin
  c1 := 400; //frequency
  c2 := 2000; // duration

  hmod := LoadLibrary('kernel32'); // Of course, the name of the DLL is taken from the script
  if hmod <> 0 then
    try
      paddr := GetProcAddress(hmod, 'Beep'); // ...as is the name of the exported function
      if paddr <> nil then
      begin
        // The script is told that this function requires two cardinals as
        // arguments. Let's call them c1 and c2. We will assume stdcall
        // calling convention. We will assume a 32-bit return value; this
        // we will store in ret.
        asm
          push c2
          push c1
          call [paddr]
          mov ret, eax
        end;
      end;
    finally
      FreeLibrary(hmod);
    end;
end;
3 голосов
/ 19 марта 2011

Как говорит Дэвид Х. о FFI, это вряд ли для слабонервных.

Однако вы можете использовать исходный код, например, для модулей расширения ctypes Python для FFI, в качестве источника информации о том, как libFFI (ctypes) связан с конкретным синтаксисом (в данном случае python). Исходный код python и его стандартные модули очень удобочитаемы.

Вот пример использования библиотек, которые Дэвид упоминает в Python:

http://code.activestate.com/recipes/146847/

Поскольку исходные коды для python (в C) доступны, а сам Python может быть расширением в Delphi, вы можете использовать его для начала. Если вы хотите написать свой собственный полный динамический язык (как часть вашего инструмента RAD), то вы также справитесь с задачей FFI.

Я лично не готов к тому, чтобы изобрести полный, работоспособный язык программирования и все его библиотеки с нуля, поэтому я предпочитаю гибридизировать то, что я знаю, вместе. Нативный код на C или Delphi и динамические скрипты на Python. При необходимости вы можете легко объединить все три в одно приложение.

3 голосов
/ 19 марта 2011

То, что вы описываете, известно как Интерфейс внешней функции (FFI) и не для чутья сердца.

Я бы не рекомендовал вам пытаться разработать свою собственную FFIс нуля.Очень распространенный выбор FFI - libffi .

На странице Википедии для libffi перечислены следующие проекты как пользователи libffi:

Python, Dalvik, F-Script, PyPy, PyObjC, RubyCocoa, JRuby, Rubinius, MacRuby, gcj, GNU Smalltalk, IcedTea, Cycript, Pawn, Squeak, собственный доступ к Java, схема PLT, встраиваемый общий Lisp и Mozilla.1015 *

Лично я широко использую libffi через интерфейс Python / ctypes для моей DLL-библиотеки Delphi, хотя, к счастью, Python / ctypes оборачивает ее на довольно высоком уровне.

Если бы я выключалмаршрут, который вы описываете, я бы настоятельно рекомендовал использовать libffi.Если вы выберете этот путь, вам придется проделать определенную работу, чтобы использовать его из Delphi, поскольку он написан на C / asm.

...