主页
Top.Mail.Ru Yandeks.Metrika
论坛:“主要”;
当前存档:2002.07.29;
下载:[xml.tar.bz2];

向下

调用* .dll后看不见的形式 找到类似的分支


VAleksey   (2002-07-16 13:29) [0]

Вызываю из программы длл в которой у меня находится форма. Форма пока пустая и длл ничего кроме создания и разрушения формы не делает, но ! после вызова функции длл которая создает и уничтожает форму главное окно приложения становиться невидимым.
Оно остается невидимым пока не пощелкаещь мышкой по его ярлычку в панели задач несколько раз.
Ощибок не возникает при этом. На всякий случай я даже убрал все обработчики исключительных ситуаций.
Что я делаю неправильно ? Почему окно приложени невидимо ? Как это исправить ?
PS
Немного кода :))
// обьявление функции в главном модуле программы
Type
TEditAnswerGetGuess = function(AHandle:THandle; const NQ:longint):Real;
Var
EditAnswerGetGuess:TEditAnswerGetGuess;
...
// Вызов функции из длл
procedure TfmAdm.EditAnswerExecute(Sender: TObject);
Var HLib:THandle;
begin
hLib:=LoadLibrary(PChar("Answers"+FloatToStr(dm1.tbQ.FieldByName("TypeQ").Value)+".dll"));
if hLib<32 then
begin
MessageDlg("Не найдена необходимая динамическая библиотека !",mtError,[mbOk],0);
System.Exit;
end;
//try
EditAnswerGetGuess:=TEditAnswerGetGuess(GetProcAddress(hLib,"EditAnswerGetGuess"));
(Application.Handle,dm1.tbQ.FieldByName("Id_Q").AsInteger);
dm1.tbQ.Edit;
dm1.tbQ.FieldByName("Guess").Value:=EditAnswerGetGuess(Application.Handle,dm1.tbQ.FieldByName("Id_Q").AsInteger);
dm1.tbQ.Post;
//finally
FreeLibrary(hLib);
//end;
end;

...
// и напоследок код функции в длл
function EditAnswerGetGuess(AHandle:THandle; const NQ:longint):real; Export;
begin
Application.Handle:=AHandle;
fmMain1:=tfmMain1.Create(Application);
fmMain1.ShowModal;
Result:=0.5;
fmMain1.Free;
end;



Skier   (2002-07-16 13:37) [1]

> VAleksey


// обьявление функции в главном модуле программы
Type
TEditAnswerGetGuess = function(AHandle:THandle; const NQ:longint):Real; stdcall;


...
// и напоследок код функции в длл
function EditAnswerGetGuess(AHandle:THandle; const NQ:longint):real; stdcall;
begin
Application.Handle:=AHandle;
fmMain1:=tfmMain1.Create(Application);
fmMain1.ShowModal;
Result:=0.5;
fmMain1.Free;
end;



Fiend   (2002-07-16 13:38) [2]

может корректнее передавать в функцию не хэндл, а указатель на Application вашего приложения, а то что то тёмное получается.

вы можете ответить, что значит Application внутри DLL



Игорь Шевченко   (2002-07-16 13:41) [3]

滑雪者©(16.07.02 13:37)

Зачем нужен stdcall ?



Skier   (2002-07-16 13:42) [4]

>伊戈尔舍甫琴科
!!! ???



VAleksey   (2002-07-16 13:45) [5]


>滑雪者©(16.07.02 13:42)

等等

> function EditAnswerGetGuess(AHandle:THandle; const NQ:longint):real;
> stdcall;

компилятор не пропускает.



Emfi   (2002-07-16 13:46) [6]

Не совсем традиционный подход.
Попробуй вызывать Update для формы, вызывающей функцию dll.



Игорь Шевченко   (2002-07-16 13:47) [7]

作者

而不是
EditAnswerGetGuess:=TEditAnswerGetGuess(GetProcAddress(hLib,"EditAnswerGetGuess"));

尝试

@EditAnswerGetGuess:=GetProcAddress(hLib,"EditAnswerGetGuess");

как-то более канонически ?


滑雪者©(16.07.02 13:42)

Зачем в данном примере нужен stdcall ?



VAleksey   (2002-07-16 13:51) [8]


> Igor Shevchenko©(16.07.02 13:47)

пробовал. Не помогает.
А вот товарищь


>滑雪者©

прав StdCall вылечил эту ерунду.
Может Skier еще и немного теорией ответ разбавим ? Очень хочется узнать причины.



Skier   (2002-07-16 13:55) [9]

> VAleksey
Обратись к Игорь Шевченко © он знает хорошую
ссылку в сети на эту тему.



anatol   (2002-07-16 13:58) [10]

naverno potomu 4to v dll u tebea functsia obyavlena cac export a v v exe ti pitashsea vizvat" cac register(po umol4aniu). a vobshe stcall ato standart dlea windows.



Игорь Шевченко   (2002-07-16 14:09) [11]

About Calling conventions
Author: P. Below
Homepage: http://www.teamb.com/
0 Comments to this tip [Write new comment]
[ Print tip ]

Tip Rating: (3):
技能:
有用:
总体而言:



Calling conventions influence two things:

- how parameters are passed to a function/procedure (=routines)
- how the call stack is cleaned up when the call returns

Delphi routines can use the calling conventions pascal (the
Delphi 1 default), register (the default for Delphi 2-5), cdecl
(the default used by C/C++ compilers), stdcall (the default used
by the Windows API). There is a fifth one: safecall, which
is only used in the context of interface methods. A good
explanation for what it entails can be found in issue 51
(Nov. 99) of The Delphi Magazine, i will not go into it
further here. Lets go through the first four in detail, using a
couple of test functions with the same parameter list but
different calling conventions. For clearity we compile with
stack frames on, so each routine will start with the prologue

push ebp
mov ebp, esp

The stack layouts given below are for the mov line. Each test
function is called with the same parameter values so one can
use the CPU windows stack pane to study the resulting stack
布局。

1. Pascal calling convention

Function Test1( i: Integer; b: Boolean; d: Double ): Integer;
帕斯卡;

Pascal calling convention passes parameters on the stack and
pushes them from left to right in the parameter list. Each
parameter occupies a multiple of 4 bytes. The resulting stack
layout is

ebp + 20 value of i, 4 bytes
ebp + 16 value of b, 4 bytes, only lowbyte significant
ebp + 08 value of d, 8 bytes
ebp + 04 return address, 4 bytes
ebp + 00 old ebp value

The parameters are cleared off the stack by the called function
使用

ret $10

instruction ($10 = 16 is the total size of the parameters on
stack).

2. Register calling convention

Function Test2( i: Integer; b: Boolean; d: Double ): Integer;
注册;

Register calling convention passes parameters in registers
eax, edx, ecx and on the stack and processes them from left to
right in the parameter list. There are rules to decide what
goes into registers and what goes on the stack, as detailed
in the Object Pascal Language guide. The resulting stack layout
is

ebp + 08 value of d, 8 bytes
ebp + 04 return address, 4 bytes
ebp + 00 old ebp value

The value of i is passed in eax, the value of b in edx.

The parameters are cleared off the stack by the called function
使用

ret $8

instruction ($8 = 8 is the total size of the parameters on
stack).

3. cdecl calling convention

Function Test3( i: Integer; b: Boolean; d: Double ): Integer;
CDECL;

Cdecl calling convention passes parameters on the stack and
pushes them from right to left in the parameter list. Each
parameter occupies a multiple of 4 bytes. The resulting stack
layout is

ebp + 16 value of d, 8 bytes
ebp + 12 value of b, 4 bytes, only lowbyte significant
ebp + 08 value of i, 4 bytes
ebp + 04 return address, 4 bytes
ebp + 00 old ebp value

The parameters are cleared off the stack by the calling
function, so the function ends with a

ret 0

and after the call instruction we find a

add esp, $10

instruction ($10 = 16 is the total size of the parameters on
stack).

4. Stdcall calling convention

Function Test4( i: Integer; b: Boolean; d: Double ): Integer;
STDCALL;

Sdtcall calling convention passes parameters on the stack and
pushes them from right to left in the parameter list. Each
parameter occupies a multiple of 4 bytes. The resulting stack
layout is

ebp + 16 value of d, 8 bytes
ebp + 12 value of b, 4 bytes, only lowbyte significant
ebp + 08 value of i, 4 bytes
ebp + 04 return address, 4 bytes
ebp + 00 old ebp value

The parameters are cleared off the stack by the called function
使用

ret $10

instruction ($10 = 16 is the total size of the parameters on
stack).

Продолжениеследует...



Игорь Шевченко   (2002-07-16 14:14) [12]

When writing DLLs that are only be meant to be used from Delphi
programs you will usually use the register calling convention,
since it is the most efficient one. But this really ties the
DLL to Delphi, no program compiled in another language (with
the exception of BC++ Builder perhaps) will be able to use the
DLL unless it uses assembler to call the functions, since the
Register calling convention (like MS VC _fastcall) is
compiler-specific.

When writing DLLs that should be usable by other programs
regardless of language you use the stdcall calling convention
for exported routines. Any language that can call Windows API
routines will be able to call routines from such a DLL, as long
as you stay away from Delphi-specific data types, like String,
Boolean, objects, real48.

Pascal calling convention is Win16 heritage, it was the default
for the Win16 API but is no longer used on Win32.

A topic loosely tied to calling conventions is name decoration
for exported names in DLLs. Delphi (5 at least) does not
decorate names, regardless of calling convention used. The name
appears in the exported names table exactly as you cite it in
the exports clause of the DLL, case and all. Case is
significant for exported functions in Win32!

Other compilers may decorate names. Unless told to do otherwise
a C compiler will prefix all cdecl functions with an underbar
and will decorate stdcall functions in the format _name@x,
where x is the total parameter size, e.g. _Test3@16. C++ is
even worse, unless functions are declared as extern "C" it will
export names in a decorated format that encodes parameter size
and type, in a compiler-specific fashion. For routines exported
with Pascal calling convention the names may be all uppercase,
but as said above you will not usually encouter this convention
on Win32.

Due to these naming issues it is often appropriate to sic TDUMP
on an unknown DLL you want to interface to, to figure out the
actual names of the exported functions. These can then be given
in a name clause for the external statement if they are
decorated.


Demo DLL:

library DemoDLL;

使用
窗口;

function Test1(i: Integer; b: Boolean; d: Double): Integer; pascal;
开始
Result := Round(i * Ord(b) * d);
结束;

function Test2(i: Integer; b: Boolean; d: Double): Integer; register;
开始
Result := Round(i * Ord(b) * d);
结束;

function Test3(i: Integer; b: Boolean; d: Double): Integer; cdecl;
开始
Result := Round(i * Ord(b) * d);
结束;

function Test4(i: Integer; b: Boolean; d: Double): Integer; stdcall;
开始
Result := Round(i * Ord(b) * d);
结束;

出口
Test1 index 1,
Test2 index 2,
Test3 index 3,
Test4 index 4;

开始
结束。


// Example call from test project:

履行

{$ R * .DFM}

function Test1(i: Integer; b: Boolean; d: Double): Integer;
pascal; external "DEMODLL.DLL" Index 1;

function Test2(i: Integer; b: Boolean; d: Double): Integer;
register; external "DEMODLL.DLL" Index 2;

function Test3(i: Integer; b: Boolean; d: Double): Integer;
cdecl; external "DEMODLL.DLL" Index 3;

function Test4(i: Integer; b: Boolean; d: Double): Integer;
stdcall; external "DEMODLL.DLL" Index 4;

过程TForm1.Button1Click(Sender:TObject);
VAR
我:整数;
开始
i := Test1(16, True, 1.0);
i := Test2(16, True, 1.0);
i := Test3(16, True, 1.0);
i := Test4(16, True, 1.0);
结束;



Set breakpoints on the lines and step into the routines with the
CPU window open to see the stack layout.




VAleksey   (2002-07-16 14:19) [13]

О..О...О......О !
Лучще по почте вышли !
> Igor Shevchenko©(16.07.02 14:09)




VAleksey   (2002-07-17 13:18) [14]

Млин, е мое сейчас снова да ладом пропадает форма !!



Страницы: 1 整个分支

论坛:“主要”;
当前存档:2002.07.29;
下载:[xml.tar.bz2];

楼上









内存:0.63 MB
时间:0.041 c
3-95223
PSZ
2002-07-08 13:11
2002.07.29
在DB中搜索


4-95598
诺斯费拉图
2002-05-20 03:33
2002.07.29
睡觉


14-95528
fore_3
2002-06-29 01:21
2002.07.29
人们可以更好地使用搜索?


3-95201
alexvan
2002-07-06 14:36
2002.07.29
就像在dbgrid字段值中一样


14-95566
变态
2002-06-28 16:57
2002.07.29
Enigmatics类型游戏的音乐





南非荷兰语 阿尔巴尼亚人 阿拉伯语 亚美尼亚 阿塞拜疆 巴斯克 白俄罗斯 保加利亚语 加泰罗尼亚 简体中文 中国(繁体) 克罗地亚 捷克 丹麦语 荷兰人 英语 爱沙尼亚语 菲律宾人 芬兰 法文
加利亚西语 格鲁吉亚语 德语 希腊语 海地克里奥尔语 希伯来语 印地语 匈牙利 北日耳曼语 印度尼西亚人 爱尔兰语 意大利语 日本性玩偶 韩语 拉脱维亚 立陶宛 马其顿 马来语 马耳他语 挪威语
波斯语 波兰语 葡萄牙语 罗马尼亚 俄语 塞尔维亚 斯洛伐克 斯洛文尼亚 西班牙语 斯瓦希里 瑞典语 泰国人 土耳其 乌克兰 乌尔都语 越南人 威尔士语 意第绪语 孟加拉 波斯尼亚
宿务 世界语 古吉拉特语 豪萨语 苗族 伊博 爪哇 卡纳达语 高棉 老挝 拉丁语 毛利 马拉 蒙古人 尼泊尔 旁遮普 索马里 泰米尔人 泰卢固语 约鲁巴语
祖鲁
英文 Французский Немецкий Итальянский Португальский 俄文 Испанский