Конференция "Основная" » Дельфийский интерфейс для Сишных прог [D7, WinXP]
 
  • andreil © (09.06.08 00:11) [0]
    Значит так. Пишу ДЛЛку на Дельфи, в которой присутствуют интерфейсы.
    Эта библиотека юзается сторонними программами с участием интерфейсов.
    Есть часть исходников этой же ДЛЛки на С++. Вот куски, касающиеся интерфейсов:
    class CSteamInterface006 : public CSteamInterface005
    {
    public:
    CSteamInterface006();
    ~CSteamInterface006();

    virtual int FindServersNumServers(unsigned int arg1);
    virtual int FindServersIterateServer(int arg1, int arg2, char *szServerAddress, unsigned int uServerAddressChars);
    virtual int FindServersGetErrorString();
    }
    ;


    unsigned int _f
    {
    static CSteamInterface006 SteamInterface006;
    return (unsigned int)&SteamInterface006;
    }



    Вопрос - как это переделать на Дельфи? Просто я в интерфейсах - нуб, а тут еще вопрос - получится ли солвместить Си с Дельфи?
  • DrPass © (09.06.08 01:22) [1]
    Что-то я не увидел тут никаких интерфейсов. Обычный сишный класс, разве что слово Interface в названии присутствует
  • andreil © (09.06.08 10:10) [2]
    Я в Си нуб, о чем и сказал, но мне на инглиш форуме сказали, что там именно интерфейс и в этом коде:
    unsigned int _f
    {
    static CSteamInterface006 SteamInterface006;
    return (unsigned int)&SteamInterface006;
    }


    идет передача Сишной программе интерфейса.
    Если делать в Дельфи CSteamInterface006 классом, то нифига не работает, поскольку компилер показывает, что процедуры этого класса не собраны в ДДЛку. + если все-таки оставить его, то при вызове этого интерфейса вылазит ошибка чтения памяти :( в том районе, где ничего нету
    Если же сделать именно интерфейс, то ошибка памяти есть, но в районе, где находится неизвестный код (судя по всему - основной программы)
  • Loginov Dmitry © (09.06.08 10:47) [3]
    > но мне на инглиш форуме сказали, что там именно интерфейс
    > и в этом коде:
    > unsigned int _f
    > {
    > static CSteamInterface006 SteamInterface006;
    > return (unsigned int)&SteamInterface006;
    > }
    > идет передача Сишной программе интерфейса.


    Тут передается просто ссылка на созданный (причем static) объект. Причем здесь интерфейсы?

    Переписать - не проблема (наверно:). Один в один переписывай весь код на дельфи.
    В ЕХЕ тебе нужно создать аналогичный класс, только абстрактный. Например:

    TSteamInterface006 = class(TSteamInterface005)
    public  
     function FindServersNumServers(arg1: Cardinal): Integer; virtual; stdcall; abstract;
     function FindServersIterateServer(arg1, arg2: Integer; szServerAddress: PChar; uServerAddressChars: Integer): Integer; virtual; stdcall; abstract;
     function FindServersGetErrorString(): Integer; virtual; stdcall; abstract;
    end;



    Далее объявляешь переменную
    var
     ASteamInterface: TSteamInterface006;



    Получаешь ссылку на объект:
    Cardinal(ASteamInterface) := _f();



    И работаешь с объектом через абстрактные методы. В рельности же будут вызваны функции из DLL.

    Не уверен на 100%, что удасться совместить код С++ и Дельфи, однако предполагаю, что получится. Виртуальные и абстрактные методы во всех языках, поддерживающих интерфейсы, реализованы одинаково (таблица виртуальных методов имеет везде одинаковое смещение и т.д.) (это имхо, т.к. все - по памяти).

    Однако я не понял, нужно ли тебе совмещать С++ и Дельфи, или же просто переписать все на Дельфи?
  • Игорь Шевченко © (09.06.08 11:10) [4]

    > public CSteamInterface005


    описание в студию
  • jack128_ (09.06.08 11:25) [5]

    > > public CSteamInterface005
    >
    >
    > описание в студию
    >


    Зуб даю, что примерно так начинается:
    class CSteamInterface005 : public CSteamInterface004

    :-))
    > Что-то я не увидел тут никаких интерфейсов.

    насколько я понимаю бинарная структура интерфейсов и дельфийских и сишных классов - совпадает.  главное чтоб первые три элемента VMT базового предка классов имели ссылки на AddRef/Release/QueryInterface
  • palva © (09.06.08 11:58) [6]
    На самом деле (сужу по старым версиям, новых версий не знаю) в языке С++ нет интерфейсов. Слово interface является синонимом слова class, а интерфейсом называется класс, который не содержит полей, а только виртуальные абстрактные методы. Чтобы класс вел себя как интерфейс требуется писать дополнительный код.
  • jack128_ (09.06.08 13:16) [7]

    > На самом деле (сужу по старым версиям, новых версий не знаю)
    > в языке С++ нет интерфейсов.

    естественно нет. они не нужны так как

    > бинарная структура интерфейсов и дельфийских и сишных классов

    А вот в дельфи интерфейсы нуны, так как классы не поддерживают множественное наследование..
  • Dimka Maslov © (09.06.08 13:38) [8]
    Есть такая штука, называется COM

    Сишная библиотека делается COM-сервером, в котором реализован интерфейс. Программа на дельфе - клиент, обращающийся к серверу и получающий указатель на интерфейс. И всё. Не надо использовать никаких кривых абстрактных классов и прочей мути. Если нет желания прописывать длл в реестр, то можно обойтись и без этого. Тогда сервер должен экспортировать одну нестандартную функцию создания объекта.
  • DrPass © (09.06.08 15:16) [9]
    Я ж так понимаю, у него хостовая часть приложения уже "дана свыше" и на Ц++ (собственно, и догадаться несложно, о каком приложении идет речь -Steam). А он, читая прилагаемые к ней Цплюсплюсные хедеры, пытается сочинить клиента на Delphi.
  • andreil © (09.06.08 17:21) [10]
    Я вообщето не сочиняю клиента Стима, а делаю обертку к эмулятору, что требуют несколько проектов. Протсо без этого надо изучать кучу форматов файлов, а так - все нихтяк :)
    И все-бы хорошо, но игры, в которых этот эмуль рабоает, взаимодействуют только через эти интерфейсы. Если бы были просто вызовы, я бы сюда не обращался, тк заголовки всех 156функций уже переведены :)
    Но эти интерфейсы.... :( Никак не могу заставить работать и все тут :(
  • andreil © (09.06.08 17:24) [11]

    > Сишная библиотека делается COM-сервером, в котором реализован
    > интерфейс. Программа на дельфе - клиент

    Я вообщето пишу Дельфийскую библиотеку для Сишной проги, а не наоборот ;)
    Я просто говорои, что есть часть исходников этой библиотеки на Си
  • andreil © (09.06.08 21:17) [12]
    Итак, вроде как со всем разобрался.
    Но вот вопрос - как передать интерфейс?
    В Сишной ДЛЛке:
    return (unsigned int)&SteamInterface006;


    В моей ДЛЛке:
    SteamInterface006:=CSteamInterface006.Create;
         result:=uint(@SteamInterface006);


    Правильно, или надо както по-другому?
  • Loginov Dmitry © (09.06.08 22:30) [13]
    > Правильно, или надо както по-другому?


    Собаку убери.

    Еще: конструкции получились неравноценны. В С++ у тебя объект создается только 1 раз. А в Дельфи - при каждом вызове экспортируемой функции.
  • Dimka Maslov © (10.06.08 10:57) [14]

    > Я вообщето пишу Дельфийскую библиотеку для Сишной проги,
    >  а не наоборот ;)


    Тогда тем более надо библиотеку делать COM-сервером. Кстати на Delphi это сделать немного проще.
  • andreil © (10.06.08 15:18) [15]

    > Собаку убери.

    ОК

    > Тогда тем более надо библиотеку делать COM-сервером. Кстати
    > на Delphi это сделать немного проще.

    Тыкни в место, где рассказывается об этом, а то я СОМ не изучал :(

    > Еще: конструкции получились неравноценны. В С++ у тебя объект
    > создается только 1 раз. А в Дельфи - при каждом вызове экспортируемой
    > функции.

    Может так?:
    if SteamInterface006=nil then
     SteamInterface006:=CSteamInterface006.Create;
         result:=uint(SteamInterface006);

  • andreil © (10.06.08 15:21) [16]
    Хм, все-равно ЕРРОР :(
    Посмотрите, может я объявил не правильно?:
    CSteamInterface006 = class (CSteamInterface005)
    ...
    CSteamInterface005 = class (CSteamInterface004)
    ...
    CSteamInterface004 = class (CSteamInterface003)
    ...
    CSteamInterface003 = class (TInterfacedObject)


    ?
  • DrPass © (10.06.08 16:15) [17]

    > CSteamInterface003 = class (TInterfacedObject)

    Скорее всего CSteamInterface003 = class (TObject)
    Чего ты за слово "интерфейс" уцепился? Нет там никаких интерфейсов, не лепи их. Это просто ссылки на классы.
  • andreil © (10.06.08 17:07) [18]

    > Скорее всего CSteamInterface003 = class (TObject)

    Сделал. Эффекта 0.
    Скинул полные исходники того, что наработал, может кто поможет :(
    http://ifolder.ru/6925349
  • andreil © (10.06.08 17:11) [19]
    Забыл сказать. Проблемный код находится в Steam_Interface.pas (функция "function _f(cszSteamInterfaceVersion: pChar): uint; export; cdecl;").
  • Сергей М. © (10.06.08 19:43) [20]

    >  Эффекта 0


    Тебе ж русским языком говорят - нет в коде в [0] никаких интерфейсов !
    Там фигурирует декларация некоего С-шного класса и ф-ция, возвращающая результатом объект этого класса. Никакими "интерфейсами" там не пахнет.
  • Amoeba © (11.06.08 00:13) [21]

    > Тыкни в место, где рассказывается об этом, а то я СОМ не
    > изучал :(
    >

    http://www.delphikingdom.com/lyceum/seminar.asp?ID=5
  • andreil © (11.06.08 18:12) [22]

    > Тебе ж русским языком говорят - нет в коде в [0] никаких
    > интерфейсов !

    Я сделал без интерфейсов - не работает.

    > http://www.delphikingdom.com/lyceum/seminar.asp?ID=5

    Ёпть, этож сколько надо учить :(
  • Сергей М. © (11.06.08 20:48) [23]

    > сделал без интерфейсов - не работает


    А кто тебе вообще сказал, что "это" должно работать ?

    Ты пойми - COM/OLE-технология на то и существует, чтобы могли взаимодействовать между собой программные модули, созданные в разных средах разработки. И эти модули действительно взаимодействуют при посредстве механизма интерфейсов. Но в приведенном тобой коде нет ничего, что могло бы хоть как-то подтвердить, что интересующая библиотека действительно использует этот механизм.
  • andreil © (12.06.08 20:21) [24]
    Вот, как объявляется в Сишном коде:
    class CSteamInterface006 : public CSteamInterface005
    {..}
    .....
    class CSteamInterface005 : public CSteamInterface004
    {..}
    .....
    class CSteamInterface004 : public CSteamInterface003
    {..}
    .....
    class CSteamInterface003
    {..}


    Я объявляю:
    CSteamInterface006 = class (CSteamInterface005)
    ..
    end;
    .....
    CSteamInterface005 = class (CSteamInterface004)
    ..
    end;
    .....
    CSteamInterface004 = class (CSteamInterface003)
    ..
    end;
    .....
    CSteamInterface003 = class (TInterfacedObject)
    ..
    end;


    В Сишном коде я там ничего про СОМ не нашел!
  • Loginov Dmitry. (12.06.08 20:37) [25]
    Ты хоть [3] читал? Пробовал?
  • andreil © (12.06.08 21:49) [26]

    > Ты хоть [3] читал? Пробовал?

    Пробывал.
    Мне нужен реальный обработчик событий, те:
    function CSteamInterface006.FindServersNumServers(arg1: uint): int;
    begin
     result:=SteamFindServersNumServers(arg1);
    end;


    Еслиже ставить abstract, то ругается, что нельзя это писать. Как же тогда сделать обработчик?
  • andreil © (12.06.08 21:54) [27]
    Хм, сделал без
    SteamInterface006:=CSteamInterface006.Create;


    , а просто
    result:=uint(SteamInterface006);  


    все ОК. Только вот сама программа теперь ругается:
    CFileSystem_Steam::Init()Failed: failed to find steam interface


    + компиллер показывает, что обработчики событий интефейсов (не в прямом смысле слова) не вомпилируются. Судя по все му, из-за этого и ошибка.
  • Vga © (13.06.08 03:11) [28]
    Ну во первых, это таки интерфейсы, причем бинарно идентичные COM, собственно COM-интерфейсы в плюсах так и объявляются. Но с двумя отличиями:
    1) Нету стандартных COM методов QueryInterface, AddRef, Release (в С++ их нужно явно объявлять)
    2) Соглашение о вызове - cdecl.
    Первый пункт не дает воспользоваться дельфовыми COM-интерфейсами - избавиться от трех стандартных методов невозможно (AFAIK). Поэтому делается несколько извращенно.
    Применительно к этим сорцам:
    1) Необходимо в CSteamInterface* (в Delphi кстати все-таки принято вместо C использовать префикс T) и CSteamDLLAppsystem все методы объявить как virtual; cdecl;
    2) Немного изменить Steam_Interface.pas:
    unit Steam_Interface;

    interface

    uses
     Windows, KOL,
       utils, SteamTypes, Steam_Interface_1, Steam_Interface_2, Steam_Interface_3,
       Steam_Interface_4, Steam_DLLAppsystem, Steam_Misc;

    function CreateInterface(cszSteamDLLAppsystemInterfaceVersion: pChar;
                            pError: PSteamError): Pointer; export; cdecl;
    function _f(cszSteamInterfaceVersion: pChar): Pointer; cdecl;

    var
     SteamDLLAppsystem: CSteamDLLAppsystem001;
     SteamInterface003: CSteamInterface003;
     SteamInterface004: CSteamInterface004;
     SteamInterface005: CSteamInterface005;
     SteamInterface006: CSteamInterface006;

    implementation

    function CreateInterface(cszSteamDLLAppsystemInterfaceVersion: pChar;
                            pError: PSteamError): Pointer; export; cdecl;
    begin
     Log('CreateInterface SteamDLLAppsystem version:' +cszSteamDLLAppsystemInterfaceVersion+#13#10);

     result:=nil;
       if cszSteamDLLAppsystemInterfaceVersion='SteamDLLAppsystem001' then
       begin
         SteamClearError(pError);
         result:=SteamDLLAppsystem;
       end;
    end;

    function _f(cszSteamInterfaceVersion: pChar): Pointer; export; cdecl;
    begin
     Log('_f SteamInterface version: '+cszSteamInterfaceVersion+#13#10);
     //
     result:=nil;
     if cszSteamInterfaceVersion='Steam003' then Result:=SteamInterface003
     else if cszSteamInterfaceVersion='Steam004' then Result:=SteamInterface004
     else if cszSteamInterfaceVersion='Steam005' then Result:=SteamInterface005
     else if cszSteamInterfaceVersion='Steam006' then Result:=SteamInterface006
    end;

    initialization

     SteamDLLAppsystem:=CSteamDLLAppsystem001.Create;
     SteamInterface003:=CSteamInterface003.Create;
     SteamInterface004:=CSteamInterface004.Create;
     SteamInterface005:=CSteamInterface005.Create;
     SteamInterface006:=CSteamInterface006.Create;

    finalization

     SteamDLLAppsystem.Free;
     SteamInterface003.Free;
     SteamInterface004.Free;
     SteamInterface005.Free;
     SteamInterface006.Free;

    end.


    3) Там, где ругнется компилер (один из методов ...Appsystem...) - привести к int.
    После этого компилится и даже позволяет запустить распакованный Sin.
  • Vga © (13.06.08 03:15) [29]
    Ах да, совсем забыл. CSteamInterface003 и CSteamDLLAppsystem001 нужно наследовать от TObject, а не TInterfacedObject. Последний как раз реализует те самые методы COM, отсутствующие в интерфейсах стима.
  • andreil © (13.06.08 17:30) [30]

    > Применительно к этим сорцам:

    Спасибо, интерфейс заработал :)
    Насчет СИНа - он не юзает интерфейсы, а просто смотрит, приобрете на ли игра, а это у меня уже давно реализованно ;)
    Да и тем болле те сырцы - это самостоятельная ДЛЛка, а я сейчас пишу врапер к SteamEmu для перехвата обращения к файлам (как минимум).
  • Vga © (13.06.08 17:49) [31]
    Ну он не только смотрит на купленность, но и использует SteamFS. Но в целом да, я его потому и выбрал, что он имеет минимум требований к длл-ке.
 
Конференция "Основная" » Дельфийский интерфейс для Сишных прог [D7, WinXP]
Есть новые Нет новых   [134491   +8][b:0][p:0.003]