Хитрая dll'ка - может, MFC, может нет :)

Тема в разделе "WASM.RESEARCH", создана пользователем volodya, 27 янв 2005.

  1. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Вопросик возник...

    Есть некая dll. dll экспортирует ряд функций. dll написана на С++/MFC и вызывается также из MFC-приложения.

    Параметры передаются по ссылке (т.е. в функцию передается и поинтер на буфер в числе прочей гадости). На возврате этот буфер наполняется значениями, ессно.

    Прототип очень грубо выглядит так:
    Код (Text):
    1. bool some_func(void *);


    так вот, при "разговоре" exe и dll все протекает нормально.

    однако, если использовать функции dll напрямую, например, из гадского Delphi
    Код (Text):
    1. function NAme(var Buff:array of byte):Boolean;external 'DLLNAME.dll'l;


    то буфер на возврате пустой.

    Почему так?

    Мои мысли - т.к. с MFC я лично дела не имел, может, надо как-то что-то предварительно инициализировать? Какие-то тонкости MFC, которых я не знаю?

    Далее, в dll есть функция ххх_Initialise - ну, тут отдельный разговор - эту штуку в первую очередь ковырять надо...

    Т.о. вопрос сводится к тому, могу ли я отсеять причину MFC на первом этапе? Если да - то, стало быть, дело в функции инициализации.
     
  2. jekyll

    jekyll New Member

    Публикаций:
    0
    Регистрация:
    20 мар 2003
    Сообщения:
    92
    Адрес:
    Russia
    Я конечно далеко не профи, но при таком пространном объяснении достаточно сложно сделать какие-либо выводы. Кинул бы длл сюда, если можешь, или хотя бы порядок вызова функций длл в екзешнике. Хотя бы что-то конкретное.
     
  3. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Код (Text):
    1. 01:19:124  xxx_Initialise() start
    2. 01:19:274  xxx_Initialise() end 0
    3. 01:19:274  xxx_SetPersonalisation() start
    4. 01:29:970  xxx_SetPersonalisation() end 0
    5. 01:29:970  xxx_GetSIMControlKey() start
    6. 01:29:970  xxx_GetSIMControlKey() end 0
    7. 01:29:970  xxx_GetNetworkControlKey() start
    8. 01:29:970  xxx_GetNetworkControlKey() end 0
    9. 01:29:970  xxx_GetNetworkSubsetControlKey() start
    10. 01:29:970  xxx_GetNetworkSubsetControlKey() end 0
    11. 01:29:970  xxx_GetSPControlKey() start
    12. 01:29:970  xxx_GetSPControlKey() end 0
    13. 01:29:970  xxx_GetCorporateControlKey() start
    14. 01:29:970  xxx_GetCorporateControlKey() end 0
    15. 01:29:970  xxx_GetSpecialControlKey() start
    16. 01:29:970  xxx_GetSpecialControlKey() end 0
    17. 01:29:970  xxx_GetMultiControlKey() start
    18. 01:29:970  xxx_GetMultiControlKey() end 0
    19. 01:29:970  xxx_GetShippingControlKey() start
    20. 01:29:970  xxx_GetShippingControlKey() end 0
    21. 01:29:970  xxx_Commit() start




    dll кинуть не могу

    вот тебе лог вызовов ее функций из exe, хотя, не понимаю, чем тебе от этого легче станет...
     
  4. captain cobalt

    captain cobalt New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2003
    Сообщения:
    222
    Адрес:
    /ru/perm
    Может быть, что-нибудь связанное со стеком? ;)
     
  5. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Просто что бы убедиться, что не влияет какой-нить хитрый сборщик мусора, можно из гадского Delphi попробовать передать
    точно такой же как в оригинале.
     
  6. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    volodya

    function NAme(var Buff:array of byte):Boolean;external 'DLLNAME.dll'l;



    А волшебное слово cdecl сказать не забыл? "Без него чалма не работает".
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    > "А волшебное слово cdecl сказать не забыл ?"



    Во-во, типы вызова при объявлении функции в dll и exe должны совпадать. Вот только по правилам хорошего тона в dll обычно используется вызов stdcall. А в "гадском Delphi" по умолчанию используется вызов register, т.е. ссылка на Buff заталкивается в регистр EAX, а не в стек. Поэтому без "волшебного слова" работать не будет.
     
  8. _Juicy

    _Juicy Active Member

    Публикаций:
    0
    Регистрация:
    12 авг 2003
    Сообщения:
    1.159
    Адрес:
    SPb
    <offtopic>Ясно, чтобы за дельфинов не отправили в хельхайм, нужно обозвать их "гадскими". А синонимы, типа "мерзких", "голимых", "хреновых" подойдут?</offtopic>



    Если не совпадают конвенции вызова, то скорее должен быть не пустой буфер, а падение с аксесс виолейшн.

    Замангленые имена - тоже вроде бы не к месту...

    Есть еще две вешчи: во-первых, не СОМовая ли это дллка?

    Во вторых:

    "AppWizard позволяет создавать два вида DLL с поддержкой MFC: DLL-расширения и обычные DLL...

    такая DLL может экспортировать целые классы...

    DLL-расширение динамически связывается с кодом DLL-версии библиотеки MFC, поэтому необходимо, чтобы клиентская программа компоновалась с MFC динамически, и чтобы версии динамических библиотек MFC у клиентской программы и DLL-расширения были одинаковы...

    Если же вам нужна DLL, которую можно загружать в любую среду программирования, включая Visual Basic 6.0, значит, вам нужна обычная DLL."

    Круглински, "Программирование на M$ Visual C++ 6.0"



    Точно не знаю, врать не буду, но может дело еще в этом.
     
  9. ssx

    ssx Member

    Публикаций:
    0
    Регистрация:
    19 авг 2003
    Сообщения:
    336


    он fastcall называется
     
  10. _Juicy

    _Juicy Active Member

    Публикаций:
    0
    Регистрация:
    12 авг 2003
    Сообщения:
    1.159
    Адрес:
    SPb
    Еще я извиняюсь, если что, но хочу напомнить, что в функции типа xxx_DoSomething (...) обычно первым параметром либо в ecx передается указатель на объект класса.
     
  11. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Ясно, чтобы за дельфинов не отправили в хельхайм, нужно обозвать их "гадскими". А синонимы, типа "мерзких", "голимых", "хреновых" подойдут?



    Прикольно. Это, интересно, кто тут меня будет в хельхейм отправлять? :)

    А дельфи использовал не я - я его вообще не знаю. И знать не желаю.



    Что до остальных замечений - вижу, что в MFC тут люди разбираются не особо - оно и правильно - я его тоже не знаю :) В принципе, проблему решим... Всем спасибо за участие.
     
  12. semen

    semen New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2004
    Сообщения:
    334
    Адрес:
    Russia
    volodya

    Хы, как я ненавижу MFC, хотя сталкиваться приходилось...

    Но помойму MFC здесь совершенно не причем, а дело как раз в стыковке MSVS & Delphi. Раз из Си все ОК, а из дельфей нет - то как тут уже было замечено, дело скорее всего в соглашениях вызова функций. Мне например совершенно неочевидно, что

    bool some_func(void *);

    и

    function NAme(var Buff:array of byte):Boolean;external 'DLLNAME.dll'l;

    будут иметь одинаковые соглашения. Если с Си все четко ясно как он это делает(если не стоит опция компилятора, меняющая дефолтное соглашение), то Дельфи ИМХО надо проверить на вшивость - остановиться отладчиком и посмотреть в дизассемблер... Еще конечно, когда стыкуются разные среды, согдашения лучше указывать явно...
     
  13. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    semen



    Угу. Так уже и было предложено - трассировка функций в обоих вариантах. Уберем проблему. Главное, чтобы это никакой фичей MFC не было - там я совсем слабо разбираюсь...
     
  14. semen

    semen New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2004
    Сообщения:
    334
    Адрес:
    Russia
    volodya

    Да - с MFC бывают неочевидные траблы, например при ее совмещении с ATL или DirectShow Base Classes - он они возникают при компиляции си кода, а не совмещения сред на уровне dll...
     
  15. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Это и есть то, что мне надо было услышать.

    Очень хорошо. Еще раз спасибо всем.
     
  16. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Да, ребята, намутили однако. Придется повториться.



    1) В дельфях по умолчанию используется тип вызова register при включенной опции оптимизации (а отключать ее не рекомендуется), или pascal при выключенной.

    Вызов pascal передает параметры через стек в последовательности слева-направо (в отличие от cdecl и stdcall для которых передача идет справа-налево). Вызов register отличается от pascal тем, что первые три параметра, которые можно передать через регистры (т.е. размером до 4 байт), передаются через регистры в последовательности EAX,EDX и ECX, а остальные через стек. Например, при двух объявлениях (Buf:pointer;Count:integer;Dopusk:double)

    и (Buf:pointer;Dopusk:double;Count:integer) получим одинаковые результаты: Buf в EAX, Count в EDX и Dopusk в стеке.

    Примечание: Не уверен, что вызов register идентичен fastcall - последовательность регистров вроде бы другая. Хотя я в Си плаваю также "хорошо", как многие тут в паскале.



    2) Обяъвление function NAme(var Buff:array of byte):Boolean;external 'DLLNAME.dll';

    неверно не только потому, что не указан тип вызова, но и потому, что неверно указан тип параметра Buff.

    Array of X в дельфях это особый тип параметра функции, для которого кроме указателя на массив передается второй скрытый параметр HighIndex = Count-1 при LowIndex = 0 по умолчанию. Я лично с этой фигней стараюсь не связываться и если нужно передать Count, то лучше это делать явно.

    В данном случае, можно просто объявить Buff как нетипированный var-параметр:

    function NAme(var Buff):Boolean;
     
  17. jekyll

    jekyll New Member

    Публикаций:
    0
    Регистрация:
    20 мар 2003
    Сообщения:
    92
    Адрес:
    Russia
    leo

    Не уверен, что вызов register идентичен fastcall



    Мда, я всегда думал, что названия разные, а смысл один. Оказывается при конвеции вызова fastcall первые два DWORD'a или параметры меньшего размера передаются через ECX, EDX. Дальше все на стек.



    Но в MSDN есть такая сноска:

    Note: Future compiler versions may use different registers to store parameters.





    Что по идее не дает никаких гарантий в какой региср что попадет.
     
  18. infern0

    infern0 New Member

    Публикаций:
    0
    Регистрация:
    7 окт 2003
    Сообщения:
    811
    Адрес:
    Russia


    они разные. Спецификации register у мелкомягких и бормана не совпадают. Ни тому ни другому гордость видать не позволяет стандарт сделать :)
     
  19. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Видимо всё таки борланду что-то не позволяет.

    Паскаль "от основателя", например,
    .

    IMHO для компилятора делать _предположения_, что dll будет принимать параметры в регистрах по меньшей мере глупо.
     
  20. diamond

    diamond New Member

    Публикаций:
    0
    Регистрация:
    21 май 2004
    Сообщения:
    507
    Адрес:
    Russia
    По-моему, ключевое слово fastcall есть даже в ANSI C++, где оно означает спецификацию вызова, при которой часть параметров передается в регистрах. Стандарт, естественно, не уточняет, в каких. Microsoft использует ECX:EDX, Borland (в своих компиляторах C++) - EAX:EDX:ECX. Модель вызова register в Delphi - то же самое, что и fastcall в Borland C++/C++ Builder, просто названо по-другому.