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!

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


oxffff   (2008-09-14 23:23:00) [81]


> Anatoly Podgoretsky ©   (14.09.08 23:09) [9]


-1.

:)

И cdecl и stdcall использует указатель на слот для результата размером >4

The following conventions are used for returning function result values.

Ordinal results are returned, when possible, in a CPU register. Bytes are returned in AL, words are returned in AX, and double-words are returned in EAX.
Real results are returned in the floating-point coprocessor's top-of-stack register (ST(0)). For function results of type Currency, the value in ST(0) is scaled by 10000. For example, the Currency value 1.234 is returned in ST(0) as 12340.
For a string, dynamic array, method pointer, or variant result, the effects are the same as if the function result were declared as an additional var parameter following the declared parameters. In other words, the caller passes an additional 32-bit pointer that points to a variable in which to return the function result.

Int64 is returned in EDX:EAX.
Pointer, class, class-reference, and procedure-pointer results are returned in EAX.
For static-array, record, and set results, if the value occupies one byte it is returned in AL; if the value occupies two bytes it is returned in AX; and if the value occupies four bytes it is returned in EAX. Otherwise, the result is returned in an additional var parameter that is passed to the function after the declared parameters..


Anatoly Podgoretsky   (2008-09-14 23:09:00) [82]

> Сергей М.  (14.09.2008 22:14:06)  [6]

Вообще то об этом говорит "mov         eax,dword ptr [ebp+8]", а не "ret 4"


oxffff   (2008-09-14 22:44:00) [83]


> либо бросить затею скрестить ежа с ужом - об этом тебе,
> кстати, уже неоднократоно говорили.


The cdecl convention is useful when you call functions from shared libraries written in C or C++.

Скрещивать можно все. Нужно только немного знаний. Самую малость.


oxffff   (2008-09-14 22:42:00) [84]


> Сергей М. ©   (14.09.08 22:14) [6]


Уже лучше.


Сергей М.   (2008-09-14 22:14:00) [85]


> return sid;
> mov         eax,dword ptr [ebp+8]
> mov         ecx,dword ptr [sid (0D2CF734h)]
> mov         dword ptr [eax],ecx
> mov         edx,dword ptr [sid+4 (0D2CF738h)]
> mov         dword ptr [eax+4],edx
> mov         eax,dword ptr [ebp+8]
>  }
> pop         edi  
> pop         esi  
> pop         ebx  
> mov         esp,ebp
> pop         ebp  
> ret         4    
>


Это говорит о том, что на вершину стека перед вызовом ф-ции компилятором был положен параметр - адрес структуры, которую ф-ция должна заполнить, фактически скопировать.
Он же, этот адрес, возвращается в кач-ве рез-та в EAX.

RET 4 говорит об stdcall - стек балансируется вызываемой ф-цией.


> Как быть?


Либо извращаться на BASM'е либо бросить затею скрестить ежа с ужом - об этом тебе, кстати, уже неоднократоно говорили.


Сергей М.   (2008-09-14 21:18:00) [86]


> после возврата из ClassID()


Ну а где у тебя реализация этой функции ?


Сергей М.   (2008-09-14 21:16:00) [87]


> нет у него параметров. self разве что


У кого "у него" ?

Покажи конкретную строчку дельфийского кода, при исполнении которой происходит эта самая "аномалия" ..


ПЗ   (2008-09-14 20:29:00) [88]

Да вроде и нет у него параметров. self разве что....
На всякий случай, попробовал stdcallв Delphi-реализации.
После возврата указатель стека перебрасывается аж в $0012DD3C. А надо, чтобы был $0012DD38.
safecall и pascal дают AV. Как быть?


Сергей М.   (2008-09-13 22:49:00) [89]


> Перед вызовом
> ESP = 0х0012DD34
> После вызова
> ESP = 0х0012DD38


Это говорит о том, что соглашение о вызове однозначноне cdecl.


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


Это говорит о том, что вызываемой cdecl-подпрограмме небыл передан ни один входной параметр.


ПЗ   (2008-09-13 22:00:00) [90]

На всякий случай, скомпилированный вид данного метода на обоих языках:
С++

 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

return sid;
mov         eax,dword ptr [ebp+8]
mov         ecx,dword ptr [sid (0D2CF734h)]
mov         dword ptr [eax],ecx
mov         edx,dword ptr [sid+4 (0D2CF738h)]
mov         dword ptr [eax+4],edx
mov         eax,dword ptr [ebp+8]
 }
pop         edi  
pop         esi  
pop         ebx  
mov         esp,ebp
pop         ebp  
ret         4    


Delphi

ClassDesc.pas.244: begin
push ebp
mov ebp,esp

mov eax,[ebp+$08]
mov edx,[m_id]    <=== адрес возвращаемой структуры (m_id.a)
mov [eax],edx
mov edx,[m_id+$4] <=== m_id.b
mov [eax+$04],edx

ClassDesc.pas.244: end;
pop ebp
ret

Настораживают разночтения у скомпилированных функций. Что означает sub esp,0CCh в С++ - варианте?


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

Наверх

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