PDA

View Full Version : فرم اصلی و فرم دوم داخل فایل DLL



spicirmkh
سه شنبه 15 اسفند 1385, 07:49 صبح
سلام

من یک فرم اصلی و فرم دوم دارم که فرم اصلی ، فرم دوم صدا می زند فقط فرم دوم درون یک فایل DLL است

فایل اصلی بدین صورت فایل DLL صدا می زند



procedure TfrmCallDLL.btnCallDLLClick(Sender: TObject);
var
Lib : THandle;
Contact : function ( MForm :Tform): integer;stdcall;
begin

Lib := LoadLibrary('Dcontact.dll');
if Lib = 0 then
Exit;
try
@Contact := GetProcAddress(Lib,'Contact');
if @Contact<>nil then Contact(frmCallDLL);
finally
FreeLibrary(Lib);
end;
end;

و درون فایل DLL بدین صورت نوشتم




function Contact ( MForm :Tform): integer;stdcall;
begin
FormMain := TFormMain.Create(Application);
Mform.Parent := FormMain ;
FormMain.FormStyle := fsMDIChild ;
MForm.FormStyle := fsMDIForm;
try
Result := FormMain.ShowModal;
finally
FormMain.Free;
end;
end;

اما متاسفانه پیغام خطا می دهد اشکال من کجاست

vcldeveloper
سه شنبه 15 اسفند 1385, 08:54 صبح
شما در این کد فرم اصلی را به تابع Contact پاس می دید، بعد یه فرم جدید میسازید (MainForm) و می خواید فرم جدید را Parent فرم اصلی کنید (!!)، بعد همون MainForm را که به عنوان Parent فرم اصلی (frmCallDll) تعریف کردید، بصورت MDI Child تعریف می کنید و فرم فرزند اون، یعنی frmCallDll، را بصورت MDI Form (!!).
مشخص نیست چکار می خواید بکنید. معلوم نیست کدوم فرم اصلی هست، کدوم فرم فرزند.
در ضمن برای فراخوانی فرم ها از DLL یک پارامتر از نوع THandle هم به تابع اضافه کنید و در هنگام فراخوانی تابع در برنامه اصلی مقدار Application.Handle را بهش پاس بدید. در داخل کد تابع در DLL هم مقدار Application.Handle اون DLL را برابر با هندل پاس داده شده بکنید:



function DllFormShowModal(AHandle: THandle);
var
MyForm : TMyForm;
begin
try
//Dll handle
Application.Handle := AHandle;
MyForm := TMyForm.Create;
try
MyForm.ShowModal;
finally
MyForm.Free;
end;
except
on E: Exception do
ShowMessage(E.Msg);
end;
end;
در برنامه فراخوان DLL:


//Caller App handle
DllFormShowModal(Application.Handle);



اما متاسفانه پیغام خطا می دهد اشکال من کجاست
پیغام خطا را بنویسید.

spicirmkh
چهارشنبه 16 اسفند 1385, 11:06 صبح
جناب آقای کشاورز

با سلام

من برنامه و فرم اصلی شامل یک پنل ( Panel ) است حال می خواهم یک فایل DLL صدا بزنم که این فایل DLL داری یک فرم است و این فرم داخل Panel فرم اصلی باز بشود

فرض کنیم یعنی مشخصات فرم و پنل به DLL بدهم شبیه دستور زیر





FormDLL.Parent := FormMain.panle1 ;


باتشکر

vcldeveloper
پنج شنبه 17 اسفند 1385, 10:30 صبح
مثل سورس کدی که پیوست کردم عمل کنید.

spicirmkh
جمعه 18 اسفند 1385, 12:19 عصر
جناب آقای کشاورز

با سلام و تشکر از ارسال جواب و فایل ، چند تا سوال داشتم

1- چرا هر وقت یک فایل DLL صدا می زنید Application.Handle را به فایل DLL می فرستید و در آنجا Application.Handle := AHandle قرار می دهد من قبلا این کار انجام نمی دادم و به خوبی کار می کرد ؟

2 - فرق دستور


DllForm := TDllForm.Create(Application.MainForm);

و


DllForm := TDllForm.Create(Application);


3- آیا می توانم در مثالی که زده اید فایل DLL در برنامه اصلی بصورت دینامیک تعریف کنم


با تشکر فراوان

vcldeveloper
شنبه 19 اسفند 1385, 08:38 صبح
- آیا می توانم در مثالی که زده اید فایل DLL در برنامه اصلی بصورت دینامیک تعریف کنم
منظورتون اینه که فایل DLL بصورت دینامیک لود بشه؟ بله مشکلی نداره، من فقط به خاطر سادگی کار اونو بصورت استاتیک به برنامه لینک کردم.


فرق دستور ...
دو فراخوانی بالا با هم فرق می کنند. در یکی شی Application به عنوان Owner فرم ساخته شده، معرفی شده، در یکی MainForm.
Application شی اصلی برنامه شما ست که بطور معمول Owner تمام فرم های برنامه است. برنامه شما با ایجاد یک شی Application شروع و با اجرای متد Run از TApplication در یک حلقه پیغام هایی که به برنامه میرسه را مدیریت میکنه، تا زمانی که از این حلقه خارج بشید و برنامه بسته بشه.
Owner یک شی هم شی ایی هست که وظیفه آزاد کردن حافظه اختصاص داده شده به شی ساخته شده را داره.
در کدهای بالا، در مثال اول فرم شما در شرایط عادی تا آزاد شدن حافظه MainForm در حافظه باقی می مونه و در اون زمان توسط MainForm آزاد میشه. در برنامه های دارای رابط کاربر گرافیکی با بسته شدن فرم اصلی برنامه، برنامه هم بسته میشه.
در مثال دوم، فرم ساخته شده در شرایط عادی تا زمان آزاد شدن شی Application در حافظه باقی می مونه.


چرا هر وقت یک فایل DLL صدا می زنید Application.Handle را به فایل DLL می فرستید و در آنجا Application.Handle := AHandle قرار می دهد من قبلا این کار انجام نمی دادم و به خوبی کار می کرد ؟
این کار باعث میشه که آیکن پنجره ایجاد شده بصورت جدا از ایکن برنامه در Task Bar ظاهر نشه.

spicirmkh
یک شنبه 20 اسفند 1385, 10:42 صبح
[QUOTE=علی کشاورز;316636]منظورتون اینه که فایل DLL بصورت دینامیک لود بشه؟ بله مشکلی نداره، من فقط به خاطر سادگی کار اونو بصورت استاتیک به برنامه لینک کردم.

با سلام

بصورت استاتیک مشکلی ندارم

اما بصورت دینامیک تعریف می کنم برنامه شما این پیغام می دهد

برنامه فراخوان به یان صورت تعریف کرده ام



procedure TForm1.Button1Click(Sender: TObject);
var
Lib : THandle;
ShowDllForm : function(AppHandle, ParentWnd: THandle): LongInt;stdcall;
begin

Lib := LoadLibrary('FormDll.dll');
if Lib = 0 then
Exit;
try
@ShowDllForm := GetProcAddress(Lib,'ShowDllForm');
if @ShowDllForm<>nil then
FDllForm := ShowDllForm(Application.Handle,Panel1.Handle);
finally
FreeLibrary(Lib);
end;
end;

vcldeveloper
دوشنبه 21 اسفند 1385, 07:51 صبح
ببینید، وقتی DLL را بصورت دینامیک فراخوانی می کنید، DLL باید تا زمانی که فرم در برنامه اصلی نمایش داده میشه در حافظه باقی بمونه. در کد بالا، شما بالافاصله پس از اجرای تابع ShowDllForm، اونو از حافظه خارج می کنید. FreeLibrary را زمانی فراخوانی کنید که کارتون با اون فرم تموم شده. می تونید کد را بصورت زیر تغییر بدید:


function TForm1.ShowDllFormDynamically(ParentWnd: THandle): LongInt;
var
hLib : THandle;
ShowDllForm : function (AppHandle, ParentWnd: THandle): LongInt;stdcall;
begin
hLib := GetModuleHandle('FormDll.dll');
if hLib <= 32 then
hLib := LoadLibrary('FormDll.dll');
if hLib > 32 then
begin
@ShowDllForm := GetProcAddress(hLib,'ShowDllForm');
if @ShowDllForm <> nil then
Result := ShowDllForm(Application.Handle,ParentWnd);
end;
end;

بعدا می تونید یک تابع هم برای آزاد کردن فرم ساخته شده، توسط FreeDllForm بنویسید و DLL را هم در اون تابع آزاد کنید. برای بدست آوردن هندل DLLاایی که قبلا در حافظه پروسه map شده (مثلا LoadLibrary)، می تونید از تابع GetModuleHandle استفاده کنید.

spicirmkh
دوشنبه 21 اسفند 1385, 10:53 صبح
با سلام و تشکر

در برنامه اول وقتی به دستور


DllForm := TDllForm.Create(Application.MainForm);

فرم ساخته می شود و بلافاصله نمایش داده می شود و منتظر دستور show نمی شود . چه کار باید کرد که فرم با دستور show نمایش داده شود

سوال دوم

در برنامه آخری می توانیم وقتی فرم DLL را Close کردیم بلافاصله از حافظه خارج شود

با تشکر

spicirmkh
دوشنبه 21 اسفند 1385, 12:06 عصر
با سلام مجدد

کاری توانستم بکنم این است

فرم DLL را Visible := false کردم وقتی به show می رسید نمایش داده می شود فقط یک مشکل پیش می آورد که سراغ TDllForm.FormActivate نمی رفت تا زمانی که showmessage می گذاشتم کنترل برنامه می رفت سراغ فرم DLL

کاری که من می خواهم بکنم که یک میز کار اصلی داشته باشم و فرم فایل DLL توی Panel فرم اصلی باز بشود

و فرم DLL یک فرم ورود اطلاعات می باشد

با تشکر

spicirmkh
دوشنبه 21 اسفند 1385, 14:28 عصر
سلام دوباره و شرمند از این همه مزاحمت


من فرم دوم بصورت دینامیک صدا زدم حال می خواهم وفتی فرم DLL بستم SetFocus روی فیلد خاصی انجام بدهم آیا می توانم بفهمم که آیا فرم دوم بسته است یا نه یا اینکه panel1 چه فرم درونش هست

با تشکر

spicirmkh
دوشنبه 21 اسفند 1385, 17:13 عصر
سلام

باز هم معذرت می خواهم این 4 سوال که می پرسم امروز

اگر در فرم DLL من یک فرم DataModule داشته باشیم آیا این روش که من ایجاد می کنم درست است



Result := 0;
try
Application.Handle := AppHandle;
FData := TFData.Create(Application.MainForm);
FormMain := TFormMain.Create(Application.MainForm);
if Assigned(FormMain) then


و برای بستن فرم روش این روش صحیح است توی Onclose فرم


Fdata.Free ;

vcldeveloper
سه شنبه 22 اسفند 1385, 09:56 صبح
و برای بستن فرم روش این روش صحیح است توی Onclose فرم
در OnClose بنویسید:
Action := caFree;


اگر در فرم DLL من یک فرم DataModule داشته باشیم آیا این روش که من ایجاد می کنم درست است

وجود یا عدم وجود Data Module مسئله ایی برای کد بالا ایجاد نمیکنه. در ضمن لازم نیست Application.MainForm را Owner فرمهای ساخته شده بگیرید. همون Application بهتره.

spicirmkh
سه شنبه 22 اسفند 1385, 15:14 عصر
سلام

استاد گرامی آقای کشاورز

قبل سوال آخری 3 تا سوال دیگر پرسیدم و امکان دارد لطف کنید جواب آن سوالات بدهید

با تشکر

spicirmkh
سه شنبه 22 اسفند 1385, 16:21 عصر
جناب آقای کشاورز
باسلام

من طبق راهنمائی شما یک برنامه نوشتم که ضمیمه کرده ام

مشکل اینجا است من قبل از اینکه فایل DLL صدا بزنم چک می کنم که توی حافظه map شده است یا نه اگر شده بود آنرا آزاد کند بعد دوباره لود کند بخاطر منظور خواستی

اما برنامه بار دوم صدا می زنم فرم اصلی کوچک می شود ؟

سوال بعدی چرا وقتی فایل در فرم Dll ایجاد می کنیم منتظر show نمی شود و باز می ماند ؟


با تشکر فراوان

vcldeveloper
چهارشنبه 23 اسفند 1385, 08:25 صبح
می خواهم وفتی فرم DLL بستم SetFocus روی فیلد خاصی انجام بدهم آیا می توانم بفهمم که آیا فرم دوم بسته است یا نه یا اینکه panel1 چه فرم درونش هست
می تونید به DLL خودتون توابعی اضافه کنید که مثلا مشخصات فرم جاری را نشان بده یا متد را به OnClose فرم نمایش داده شده نسبت بده. اصول و روش کار همونی هست که قبلا گفتم، فقط محتوای توابع فرق می کنه.

vcldeveloper
چهارشنبه 23 اسفند 1385, 08:29 صبح
فرم ساخته می شود و بلافاصله نمایش داده می شود و منتظر دستور show نمی شود . چه کار باید کرد که فرم با دستور show نمایش داده شود
اینو خودتون در پست بعدی نوشتید که حل کردید؛ با Visible := False.


در برنامه آخری می توانیم وقتی فرم DLL را Close کردیم بلافاصله از حافظه خارج شود
اینو هم جواب دادم؛ در OnClose فرم می تونید بنویسید Action := caFree.

vcldeveloper
چهارشنبه 23 اسفند 1385, 08:51 صبح
یک برنامه نوشتم که ضمیمه کرده ام
چشم، نگاه می کنم، اگه چیزی به ذهنم رسید، اینجا میزارم.

موفق باشید

spicirmkh
چهارشنبه 23 اسفند 1385, 11:53 صبح
سلام

من توی فرم اصلی وقتی می خواهم DLL که صدا زدم آزاد کنم با دستور زیر فرم اصلی می رود توی Task bar پائین صفحه

کد آزاد شدن DLL



hLib := GetModuleHandle('Dmenu.dll');
if hLib > 32 then freelibrary(Hlib);


کد صدا زدن DLL



var
hLib : THandle;
MenuSTD : function (AppHandle, ParentWnd: THandle; Pwidth, Pheight : integer ): LongInt;stdcall;
begin
hLib := GetModuleHandle('Dmenu.dll');
if hLib <= 32 then
hLib := LoadLibrary('Dmenu.dll');
if hLib > 32 then
begin
@MenuSTD := GetProcAddress(hLib,'MenuSTD');
if @MenuSTD <> nil then
MenuSTD(Application.Handle,Panel1.Handle,Panel1.Wi dth,Panel1.Height);
end;
end;


کد فایل DLL


function MenuSTD(AppHandle, ParentWnd: THandle; Pwidth, Pheight : integer ): LongInt;stdcall;
begin
Result := 0;
try
Application.Handle := AppHandle;
FData := TFData.Create(Application);
FormMain := TFormMain.Create(Application);
if Assigned(FormMain) then
with FormMain do
begin
if ParentWnd > 0 then
ParentWindow := ParentWnd;
left := round((Pwidth-FormMain.Width)/2) ;
Top := 0;
height := Pheight ;
Show;
FormMain.Align := alClient ;
Result := LongInt(FormMain);
end; //with

except
on E: Exception do
MessageDlg(E.Message,mtError,[mbOK],0);
end;
end;




با تشکر فراوان

vcldeveloper
پنج شنبه 24 اسفند 1385, 10:39 صبح
من کد شما رو نگاه کردم، اول مشکل مینیمایز شدن داشت، ولی با یکی دو بار Build مشکل برطرف شد و دیگه ندیدمش. در هر حال من یه خورده تغییرات در کد شما دادم:

حرفه ای
شنبه 10 اسفند 1387, 00:58 صبح
آقاي كشاورز سلام

تاپيك شما در خصوص نمايش فرمهاي Midichild در dll را خواندم
بسيار عالي بود
متاسفانه كاربر من دسترسي ساخت تاپيك را ندارد به همين دليل اينگونه مزاحم شدم
مشكل من اينجاست كه
1- مي خواهم خواصيت PageControlآبجكت tabsheet1 داخل dll رابرابر با PageControl1 موجود در فرم اصلي قرار دهم آيا اين امر امكان دارد ؟
2- يك datamadule در برنامه اصلي دارم كه datasource ها داخل آن قراردارند . امكان دارد dbgride بر روي tabsheet1 روي فرم موجود در dll به datamadule فوق وصل كنم ؟
در صورت امكان راهنمايي كنيد

حرفه ای
شنبه 10 اسفند 1387, 22:57 عصر
دوستان كسي نمي تونه به من كمك كنه ؟