Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Классы в DLL на Delphi и MSVC++ (бой продолжается)...


Страницы:   1 2 3 4 5

ПЗ ©   (2008-09-13 21:58:00) 

Продолжаю исследовать возможности написания плагинов для 3d Studio MAX на Delphi.
Плагин сидит в DLL  в виде класса заданной структуры. 3ds загружает DLL, получает
ссылку на экземпляр класса (не COM) и вызывает его методы. Когда класс написан на MSVC
все ОК, когда на Delphi - есть сбои. Путем сравнения процессов вызова в отладчиках
установил аномалию.
Есть метод класса.
На С++:

class MyUtilityClassDesc
{
...
 virtual SClassID ClassID()
 {
return sid;
 }
}
где
struct SClassID
{
ULONG a,b;
}sid;
...
sid.a=0xFF00FF;
sid.b=0xAABBEE;

То же на Delphi:

ClassDesc=class
...
function ClassID():MClass_ID;virtual;cdecl;
end;
function ClassDesc.ClassID():MClass_ID;cdecl;

begin
 Result:=m_id;
end;
где
MClass_ID=record
 a,b:LongWord;
end;
...
m_id:MClass_ID;
m_id.a:=$FF00FF;
m_id.b:=$AABBEE;

Аномалия в том, что после возврата из ClassID() на С++, указатель стека смщается, а на Delphi - нет!
На С++:
Перед вызовом
ESP = 0х0012DD34
После вызова
ESP = 0х0012DD38

На Delphi
Перед вызовом
ESP = $0012DD34
После вызова
ESP = $0012DD34 <=!!!

Получается, что на С++ вершина стека оказывается непосредственно на возвращенном результате, а на Delphi - ПОСЛЕ результата функции(метода), что потом приводит к AV!

Знатоки, научите, как такое может быть, если вызывающий код один и тот же и результат возвращается корректно?


Anatoly Podgoretsky   (2008-09-15 16:33:00) [61]

> Сергей М.  (15.09.2008 15:44:29)  [29]

Классик сказал, напился, тут помню, а тут нет.


Сергей М.   (2008-09-15 15:44:00) [62]


> но компилятор не знает


Та к не бывает - тут знаю, а тут не знаю)


oxffff   (2008-09-15 14:33:00) [63]


> Slym ©   (15.09.08 11:20) [19]


Интерфейс - это просто указатель на абстрактный класс с самантикой подсчета ссылок и запроса других абстрактных классов.


oxffff   (2008-09-15 14:20:00) [64]


> Либо они есть , либо их нет - разве компилятор об этом не
> знает ?


В данном случае их нет, но компилятор не знает.
:O)


Slym   (2008-09-15 13:06:00) [65]

попробуй так:
type
 TClassID=packed record
   a,b:LongWord;
 end;

 TClassDesc=packed record
   IsPublic: function:LongBool;stdcall;
   Create: function(const Loading:LongBool):pointer;stdcall;
   ClassName:function :PChar;stdcall;
   SuperClassID:function:TClassID;stdcall;
   ClassID:function:TClassID;stdcall;
   Category:function :PChar;stdcall;
 end;

const m_id:TClassID=(a:$FF00FF;b:$AABBEE);

function ClassID:TClassID;stdcall;
begin
 result:=m_id;
end;

function LibClassDesc(const i:integer):TClassDesc;
begin
 ZeroMemory(@result,SizeOf(result));
 result.ClassID:=@ClassID;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 ClassDesc:TClassDesc;
 ClassID:TClassID;
begin
 ClassDesc:=LibClassDesc(1);
 ClassID:=ClassDesc.ClassID;
end;


Slym   (2008-09-15 12:41:00) [66]

Метод Передача параметров Кто чистит стек Где применяется
__cdecl В стек, справа налево Вызывающий По умолчанию в C и C++
__stdcall В стек, справа налево Сама функция Вызовы почти всех системных функций, а также по умолчанию внутренние функции Visual Basic
__fastcall Два первых параметра  в регистрах ECX и EDX, остальные  в стек, справа налево Сама функция По умолчанию в Borland Delphi
thiscall Указатель this передается в регистре ECX, параметры  в стек, справа налево. Сама функция Функциями-методами классов без списка аргументов переменной длины. Не может быть задан явно.
похоже на то


Сергей М.   (2008-09-15 12:37:00) [67]


> oxffff ©   (15.09.08 12:01) [23]


> проверки доступа к неинициализированным локальным переменным


Зачем их "проверять" ? Не понятно ..
Либо они есть , либо их нет - разве компилятор об этом не знает ?


oxffff   (2008-09-15 12:01:00) [68]


> Сергей М. ©   (15.09.08 11:41) [21]


VС++ использует эту технику для проверки доступа к неинициализированным локальным переменным(те самые которые по отрицательным смещениям от ebp). В данном случае инициализация в 0CCCCCCCCh.

Но поскольку локальных переменных здесь нет, то следующий код - это шняга

push        ecx  
lea         edi,[ebp-0CCh]
mov         ecx,33h
mov         eax,0CCCCCCCCh
rep stos    dword ptr [edi]
pop         ecx  
mov         dword ptr [ebp-8],ecx


Slym   (2008-09-15 11:46:00) [69]

например так может?
type
 TMClass_ID=packed record
   a,b:LongWord;
 end;

 IClassDesc = interface
 ['{9275252B-2D15-4C04-8317-158591B1EE85}']
   function ClassID():TMClass_ID;cdecl;
 end;

 TClassDesc=class(TObject, IClassDesc);
   function ClassID():TMClass_ID;cdecl;
 end;
var ClassDesc:TClassDesc;

function LibClassDesc(const i:integer):TClassDesc
begin
 ClassDesc.GetInterface(IClassDesc,result);
end;


Сергей М.   (2008-09-15 11:41:00) [70]


> oxffff ©   (15.09.08 11:10) [18]


> Для проверки инициализированности


Инициализированности чего?


Anatoly Podgoretsky   (2008-09-15 11:26:00) [71]


> Сергей М. ©   (15.09.08 11:01) [17]

Видимо так, поскольку в последней строчке используется ECX, а инициализации не видать, в связи с этим перед этим сохраняется ECX в последней строчке. Но для точного диагноза надо знать соглашения о вызовах.


Slym   (2008-09-15 11:20:00) [72]

А мне кажется что здесь не объекты, а интерфейсы... ибо как MAX находит точку входа в методы? по VMT чтоли? дак она у всех разная...


oxffff   (2008-09-15 11:10:00) [73]


> Сергей М. ©   (15.09.08 11:01) [17]
>
> > Anatoly Podgoretsky ©   (15.09.08 10:09) [15]
>
>
> Бесспорно.
> Но если этот код не "шняга", значит, в ECX передается один
> из вх.параметров ..


Неа. Этот код

push        ecx  
lea         edi,[ebp-0CCh]
mov         ecx,33h
mov         eax,0CCCCCCCCh
rep stos    dword ptr [edi]
pop         ecx  
mov         dword ptr [ebp-8],ecx

Эта муть. Вставляется в VS в debug версии.
Отношения к коду не имеет.
Для проверки инициализированности перед использованием __RTC_UninitUse


Сергей М.   (2008-09-15 11:01:00) [74]


> Anatoly Podgoretsky ©   (15.09.08 10:09) [15]


Бесспорно.
Но если этот код не "шняга", значит, в ECX передается один из вх.параметров ..


Anatoly Podgoretsky   (2008-09-15 10:10:00) [75]

> Сергей М.  (15.09.2008 9:01:12)  [12]

esi, edi сохраняются в соответствии с соглашением по использованию регистров.


Anatoly Podgoretsky   (2008-09-15 10:09:00) [76]

> Сергей М.  (15.09.2008 9:01:12)  [12]

Из отмеченого жирным, регистр ECX сохраняется в стеке поскольку он нужен неиспорченым в последеней строке.


Сергей М.   (2008-09-15 09:43:00) [77]


> oxffff ©   (15.09.08 09:09) [13]


Я тоже не понимаю, с какой луны он свалился)
Автор что-то напутал, наверно ..


oxffff   (2008-09-15 09:09:00) [78]


> Сергей М. ©   (15.09.08 09:01) [12]
>
> > Anatoly Podgoretsky ©   (15.09.08 00:09) [11]
>
>
> > но не register
>
>
> Конечно, не register, но как объяснить


Это вообще код-шняга. Он делает ровным счетом ничего.
Рабочий код начинается с return sid;


Сергей М.   (2008-09-15 09:01:00) [79]


> Anatoly Podgoretsky ©   (15.09.08 00:09) [11]


> но не register


Конечно, не register, но как объяснить

virtual SClassID ClassID()
{
push        ebp  
mov         ebp,esp
sub         esp,0CCh
push        ebx  
push        esi  
push        edi  
push        ecx 
lea         edi,[ebp-0CCh]
mov         ecx,33h
mov         eax,0CCCCCCCCh
rep stos    dword ptr [edi]
pop         ecx  
mov         dword ptr [ebp-8],ecx


??


> После возврата указатель стека перебрасывается аж в $0012DD3C.
>  А надо, чтобы был $0012DD38.


Это из-за self'а - он первым заталкивается в стек, следом заталкивается указатель на результат.

Соотв-но на выходе ты увидишь RET 8 вместо ожидаемых RET 4


Anatoly Podgoretsky   (2008-09-15 00:09:00) [80]

> oxffff  (14.09.2008 23:23:10)  [10]

По другому более точно - ret 4 говорит, что это не cdecl, а вот что одначно решить нельзя, толи это stdcall, толи pascal, толи safecal, но не register, тема в справке Calling conventions.


Страницы:   1 2 3 4 5

Наверх

Титульная страница Поиск, карта сайта Написать письмо