На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> class, abstract, virtual - что не так в коде?
    Доброй ночи!

    Есть код на C++, запускается. Нужно то же только на Delphi, вроде все один в один но access violation. Что я делаю не так с вызовом абстрактных классов и как нужно?

    ExpandedWrap disabled
      typedef char* (*CrIntFunc) (const char *Name);
       
      class CSomeClass
      {
      public:
          virtual void Dummy1(void) = 0;
          virtual void Method1(void) = 0;
          virtual void Method2(void) = 0;
          virtual int Method3(const char *param1, const char *param2 = NULL) = 0;
      };
       
      void main()
      {
          HMODULE hDLL = LoadLibrary("MYDLL.dll");
          if(!hDLL)
          {
              MessageBox(NULL, "hDLL=0", "ERROR", MB_OK);
              return 1;
          }
          CrIntFunc Func = (CrIntFunc)GetProcAddress(hDLL,"CreateInterface");
          CSomeClass* pSomeClass = (CSomeClass*)Func("String_ident");
          pSomeClass->Method1();
      }


    ExpandedWrap disabled
      type
          TCrIntFunc = function(cszname: pChar): Pointer; cdecl;
          TSomeClass = class
              procedure Dummy1; virtual; abstract;
              procedure Method1; virtual; abstract;
              procedure Method2; virtual; abstract;
              function Method3(param1, param2: PChar):integer; virtual; abstract;
         end;
       
      begin
           hDLL := LoadLibrary('MYDLL.dll');
           CrIntFunc := GetProcAddress(hDLL, 'CreateInterface');
           addr := CrIntFunc('String_ident');
           SomeClass := TSomeClass(addr);
           SomeClass.Method1; //тут вылетает
      end.

    Дебаг вывожу в консоль - и hDLL, и addr имеют правильные значения, не nil.
      Delphi какая версия - юникодная?

      Это что - получение интерфейса?
        По сути да, в DLL (C++) описан интерфейс со всеми методами, экспортируется единственная функция CreateInterface.
        В представленном коде на С++ ошибок не возникает. Delphi 7, но тут ничего на языках отличных от английского не будет потому не принципиально. Я не думаю что CreateInterface нужно вызывать с параметром типа PWideChar, DLL писалась 10 лет назад.

        hDLL имеет значение 10000000
        Ошибка Access violation at address 100052C8 in module 'MYDLL.dll' - судя по адресу ошибка возникает в DLL, но судя по тому что из C++ кода все работает - это результат моих кривых рук либо какой-то несовместимости Delphi и C++. В одной статье видел подсказку по поводу stdcall но тут метод без параметров, и результат с ним такой же, вплоть до тех же адресов.
        Сообщение отредактировано: Виталь -
          работать не будет по многим причинам.
          * реализация классов и vtable у паскаля и с++ разная
          * ты не говоришь на каком языке написана MYDLL.dll.
          пс. подозреваю то из за чего работает первый вариант, так это то что библиотека написана на этих самых плюсах

          что бы код работал кросс-языково нужно уйти от vtable или заменить класс интерфейсом.
          * ты можешь заменить класс структурой с методами

          ExpandedWrap disabled
            typedef void (*TMyMethod1) ();
            typedef int (*TMyMethod3) (const char *param1, const char *param2);
             
            struct CSomeClass {
                TMyMethod1 Dummy1;
                TMyMethod1 Method1;
                TMyMethod1 Method2;
                TMyMethod3Method3;
            };


          это ровно также будет работать и в делфи

          * ты можешь перейти на интерфейсы. тогда не надо будет парится по поводу self
          это не значит что нужно работать через com, просто объявить, реализовать и возвращать его через библиотеку.
          тогда паскаль при вызове интерфейса не будет опираться на свой vtable, а не посредственно вызывать методы интерфейса

          Добавлено
          пс. я понимаю что структура и класс для c++ одно и тоже (почти), но отсутствие виртуальных методов как раз не будет создавать vtable
          Сообщение отредактировано: ViktorXP -
            Цитата ViktorXP @
            * реализация классов и vtable у паскаля и с++ разная

            А в чем же различие (применительно к текущему случаю)? AFAIK и там и там - одно и тоже. объект указывает на VMT, VMT - указывает на массив указателей методов. Первый (нулевой) указатель - это и есть указатель на метод Dummy. В дельфи все вирт методы TObject - имеют отрицательное смещение, поэтому ни на что не влияют




            Цитата Виталь @
            В одной статье видел подсказку по поводу stdcall но тут метод без параметров, и результат с ним такой же, вплоть до тех же адресов.

            у любого экземплярного метода есть скрытый параметр Self (this в плюсах). У тебя в классах не факт что stdcall используется. Попробуй cdecl или thiscall
            Сообщение отредактировано: jack128 -
              Добрый вечер. Спасибо за интерес к теме. Да, библиотека на плюсах.

              Цитата
              что бы код работал кросс-языково нужно уйти от vtable или заменить класс интерфейсом

              Это нужно сделать в вызывающей программе на Delphi или в вызываемой библиотеке тоже?
              Исходников библиотеки нет и не будет, потому если менять надо оба то это сразу не вариант.

              Еще вопрос по теме. Если в самой библиотеке объявлен не класс, а именно интерфейс, и это я по незнанию описал его как класс, при этом в коде на С++ такая штука заработала - может быть такое или нет? На самом деле библиотека очень слабо описана, работаешь почти вслепую.

              Цитата
              Попробуй cdecl или thiscall

              Попробовал явно указать cdecl и stdcall
              ExpandedWrap disabled
                procedure Method1; virtual; cdecl; abstract;

              ошибка вылазит абсолютно одинаковая, а thiscall в Delphi пишут что нет.
              Цитата
              Access violation at address *** in module 'MYDLL.dll'. Write of address ***.
                Виталь, А чем скомпилирована библиотека?
                В Delphi действительно нету thiscall, а именно он и используется в данном случае. Точнее его вариация, зависит от компилятора (gcc, microsoft vs). Если нету исходников, либо других АПИ, то варианта два:
                Простой вариант - можно сделать на С++ библиотеку "враппер", которая будет вызывать нужные классовые функции и иметь простые функции для экспорта.
                И не простой вариант, дергать функции напрямую, при этом изображая thiscall. Довольно муторно, но реально
                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                0 пользователей:


                Рейтинг@Mail.ru
                [ Script execution time: 0,0266 ]   [ 16 queries used ]   [ Generated: 16.04.24, 04:09 GMT ]