PDA

View Full Version : سوال: دو سوال در مورد dll



Mask
شنبه 12 اسفند 1391, 13:32 عصر
با سلام.
چون این 2 سوال مربوط به dll بود نخاستم 2 پست ایجاد کنم.
سوال اول :
تفاوت دو کد زیر چیست ؟ آیا هر کدام برای منظوری تهیه شده است؟

exports addition name 'addition';

exports addition;
سوال دوم :
چرا در کد زیر وقتی از Stdcall استفاده نکنیم ، جواب اشتباه بر میگردد.
کد Dll :

library Test;

uses
Windows,
SysUtils;

function addition(a, b: Integer): Integer;export;
begin
Result := a + b;
end;

exports addition;

begin

end.
کد بار گزاری در برنامه :

type
TMyAddition = function(a, b: Integer): Integer; stdcall;

procedure TForm1.Button1Click(Sender: TObject);
var
MyAddition: TMyAddition;
FunctionPointer: TFarProc;
hModule: THandle;
begin
hModule := LoadLibrary(PChar('test.dll')); // Dll invite
if hModule = 0 then
begin // Dll can not be loaded will leave the procedure
raise Exception.Create('DLL could not be loaded');
end
else
try
FunctionPointer := GetProcAddress(hModule, 'addition');
// Function address can be determined
if FunctionPointer <> Nil then
begin // If the function was then found
@MyAddition := FunctionPointer; // the code is executed in the function
ShowMessage(IntToStr(MyAddition(StrToInt(Edit1.Tex t),
StrToInt(Edit2.Text)))); // and output
FunctionPointer := Nil;
FreeLibrary(hModule);
end
else
ShowMessage('Function could not be found.');
// release of DLL
FreeLibrary(hModule);
except
on E: Exception do
begin // should still be caught in this error occur except
ShowMessage('Error : ' + E.Message);
FreeLibrary(hModule);
end;
end;
end;
در صورتی که اگر کد به شکل زیر شود ، جواب درست بر میگردد:

library Test;

uses
Windows,
SysUtils;

function addition(a, b: Integer): Integer;export;stdcall;
begin
Result := a + b;
end;

exports addition;

begin

end.

Felony
شنبه 12 اسفند 1391, 13:51 عصر
1- در کدی که شما نوشتید فرقی ندارند ؛ اگر یک export خالی بزنید تابع با نام خودش export میشه ولی ممکنه در یک DLL تابی با نام مثلا GetStudentInfoByStudentID داشته باشیم که نخوایم با این نام طولانی Export ش کنیم ، در این صورت با اون Name میتونیم بگیم که نام تابع خروجی x باشه ولی هر وقت x صدا زده شد تابع اصلی ما Call بشه .

2- اون ها قرادادهای Call کردن توابع هستن : http://en.wikipedia.org/wiki/X86_calling_conventions

Mask
شنبه 12 اسفند 1391, 14:27 عصر
ممنون از پاسختون.
در مورد سوال دوم : منظورم بیشتر قسمت فنی این قضیه بود وگرنه در جریان قرادادهای Call کردن هستم.
با مراجعه به لینکی که قرار دادید :

The stdcall[3] calling convention is a variation on the Pascal calling convention in which the callee is responsible for cleaning up the stack, but the parameters are pushed onto the stack in right-to-left order, as in the _cdecl calling convention. Registers EAX, ECX, and EDX are designated for use within the function. Return values are stored in the EAX register.
stdcall is the standard calling convention for the Microsoft Win32 API and for Open Watcom C++‎.
به نظرم موضوع سر رجیستر EAX هست.چون ما داریم به صورت داینامیک dll رو لود میکنیم ، پس در درجه اول باید با استفاده از stdcall پشته را تمیز کرده تا خروجی که در EAX برگشت میشود به صورت صحیح باشد.
آیا ین استنباط درسته؟

یوسف زالی
دوشنبه 14 اسفند 1391, 05:03 صبح
تمیز کردن لفظ صحیحی نیست.
همه چیز به Parameter هایی بستگی داره که می فرستی.
اگر یک یا هیچ Parameter داشتی تفاوتی در نحوه ی کال کردن نبود. اما در تعداد بالاتر FIFO و LIFO بودن اونها می شه همین داستان.
وقتی Parameter ی ارسال می شه در اصل مقدار یا آدرسش در Stack گذاشته = Push می شه و با کال کردن یک تابع، از اونجا که تابع می دونه چه تعداد Parameter داره، به تعداد اونها Stack رو POP می کنه و در متغیر های محلی = EAX, EBX, .. می ریزه. البته این فرستادن گاهی برای سادگی (مثلا تعداد زیر 4 تا متغیر عددی) از همون اول در رجیستر انجام می شه و اصلا کار به Stack نمی رسه.
استاندارد کال کردن یک تابع این هست. استاندارد به معنای این که همه ملزم به رعایت اون باشند. حالا ممکنه که دلفی بیاد و در اینجا وارد قراردادهای خودش بشه، اما وی بی نشه. واسه این که هردو بفهمن چی دارن می گن و چی دارن به هم می فرستن این استاندارد ها رو وضع کردن.
این استاندارد ها سوای این که بیان می کنن FIFO یا LIFO اطلاعات رو در Stack می ریزن، بیان کننده ی رجیستر های درگیر فرستادن هم هستند.
اون خروجی که از تابع بر می گرده هم در واقع ربطی به Stack نداره.
در واقع به داینامیک بودن لود هم بستگی نداره.
به سادگی قرارداد می گه بعد از فراخوانی یک تابع خروجی اون در چه رجیستری قرار داره.

البته همه ی اینها رو می دونم که می دونی. اگر صورت سوالت رو خوب نگرفتم کمی بیشتر توضیح بده.