Создайте экземпляр экспортированного класса C ++ из Delphi - PullRequest
3 голосов
/ 01 апреля 2010

Я последовал за прекрасной статьей Руди Велтуиса об использовании классов C ++ в DLL. Все было прекрасно, за исключением того, что мне нужен доступ к некоторым классам, у которых нет соответствующих фабрик в C ++ DLL. Как я могу создать экземпляр класса в DLL? Рассматриваемые классы определены как

class __declspec(dllexport) exampleClass
{
public:
  void foo();
};

Теперь без фабрики у меня нет четкого способа создания экземпляра класса, но я знаю, что это можно сделать, поскольку я видел SWIG-скрипты (файлы .i), которые делают эти классы доступными для Python. Если Python & SWIG могут это сделать, то я предполагаю / надеюсь, что есть какой-то способ сделать это и в Delphi.

Теперь я мало что знаю о SWIG, но похоже, что он генерирует какую-то карту для искаженных имен C ++? Это где-то рядом справа? Глядя на экспорт из DLL, я полагаю, что я мог бы получить доступ к функциям и конструктору / деструктору по индексу или искаженному имени напрямую, но это было бы неприятно; и будет ли это вообще работать? Даже если я могу вызвать конструктор, как я могу сделать эквивалент "new CClass ();" в Delphi?

Ответы [ 4 ]

7 голосов
/ 01 апреля 2010

Способ работы Swig: 1) Он создает плоский API для каждого метода класса и для создания функции фабрики / разрушителя классов. например:

class C { 
      public : 
           C() {...}
           int M1(int P1) {...}
        } 

производит:

       C* New_C();
       Destroy_C(C*self);
       int C_M1(C*self,int P1) {}

Плоский API должен быть скомпилирован в новую DLL

2) выдает для плоского API единицу, содержащую объявление плоского API на паскале 3) плоский Паскаль API может быть дополнительно использован для автоматического создания класса Паскаля, например:

 type TC = class


 private

      FObj : pointer;
 public

      constructor Create();
      destructor Destroy(); override;
      function m1(p1:integer: integer;
    ...

  constructor TC.Create();
  begin
     inherited;
     FObj := New_C();
  end;

  destructor TC.Destroy();
  begin
      Destroy_C(FObj);
      inherited;
  end;

  function TC.M1(P1:integer) : integer;
  begin
      Result := C_M1(FObj, P1);
 end;
5 голосов
/ 01 апреля 2010

Это можно сделать с помощью SWIG. По крайней мере, ДОЛЖНО быть возможно. Я написал SWIG-модуль для ObjectPascal и успешно использую его в своем собственном проекте. Я перевел GEOS и библиотеку GDAL / OGR. У меня также есть ветвь в репозитории SWIG, НО мне еще нужно завершить последние шаги, чтобы построить все наборы тестов и исправить карты типов, чтобы принять модуль.

Кто-то хотел бы помочь?

Стефано Моратто stefano.moratto@gmail.com www.csiat.it

5 голосов
/ 01 апреля 2010

Правильный способ сделать это - написать DLL-оболочку, предоставляющую фабрику для нужного вам класса.

Я не уверен, что SWIG работает, но все, что опирается на обратное проектирование искажения имен, кажется сомнительным подходом.

Кроме того, объект C ++ должен создаваться только в коде C ++. Вы должны оставить семантику создания объекта во время выполнения C ++.

Существует причина, по которой существует COM. Именно для того, чтобы метафора этого межъязыкового объекта работала аккуратно.

Я написал множество COM-объектов, которые вызываются из Delphi, Python и C #

2 голосов
/ 01 апреля 2010

Если Python может, это не обязательно означает, что любой язык может.

Python (или любой другой язык сценариев) может иметь доступ к коду C ++ в том же компиляторе и в той версии, с которой он был скомпилирован.

Лакмусовый тест заключается в том, что код Python может обращаться к классу независимо от того, с каким он скомпилирован (например, одна реализация Python с той же DLL, сгенерированной с помощью msvc и gcc)

В общем, все с искаженными именами зависит от компилятора и версии. Таким образом, единственный способ состоит в том, чтобы скомпилировать тестовую программу с целевым компилятором, разобрать его, найти соответствующие вызовы времени выполнения (для типа класса, конструктора и помощников времени выполнения) и способ их вызова, а также имитировать это с помощью любой функции cdecl или асм в Delphi.

Умелые люди, такие как Руди, могут убрать, что они используют функцию Паскаля в максимально возможной степени и представляют ее как нечто, что выглядит легко, но кросс-компиляторная совместимость HLL - сложная (если не невозможная) тема.

...