PDA

View Full Version : مخفی کردن WinMain



Aminm_666
چهارشنبه 16 دی 1383, 04:05 صبح
چطوری میشه DLL رو مجبور کرد که WinMain رو exportش کنه؟


---

Inprise
چهارشنبه 16 دی 1383, 10:24 صبح
DLL ها اصولا" WinMain ندارند .

Aminm_666
پنج شنبه 17 دی 1383, 01:08 صبح
خیر سرم دارم application framework میسازم یه چیزی مثل MFC. برای همین لازمه که WinMain رو export کنم تا تو سایر برنامه های مبتنی بر اون دیگه لازم نباشه این تابع که بدنه ثابتی داره. هی تکرار بشه. با static library میشه اینکارو کرد ولی چه فایده ای داره وقتی قراره بدنش تو فایل اجراییم کپی بشه. یک بار برای همیشه اونم فقط با DLL. اما چطوری؟



---

Inprise
پنج شنبه 17 دی 1383, 03:23 صبح
منم مطلقا" نمیفهمم چی داری میگی .

موفق باشی

مرتضی ن.
پنج شنبه 17 دی 1383, 19:07 عصر
Just put it in your EXPORT list in the DLL's .def file
Let me know if it works

Aminm_666
جمعه 18 دی 1383, 03:40 صبح
DLLهای MFC چیکار میکنن. میشه با استفاده از MFC برنامه اجرایی نوشت و WinMain نداشت. چون WinMain تو DLL های MFC مخفی شده. بدنه ثابتی هم داره. پس لازم نیست تو هر برنامه اجرایی مبتنی بر MFC تکرار بشه. منم یه همچین کاری میخام بکنم. یعنی از MFC استفاده نمی کنم بلکه شبیه اون رو دارم میسازم. برای export هم از <span dir=ltr>__declspec</span> استفاده کردم نه از فایل <span dir=ltr>.DEF</span> چون هم سخته هم پیچیدگیهایی داره هر چند برای ساختن DLLهای MFC از روش دوم بهره بردن.
پس MFC تو فایلهای WinMain.cpp و AppModule.cpp چیکار میخواسته بکنه...

---

Inprise
جمعه 18 دی 1383, 03:47 صبح
چون WinMain تو DLL های MFC مخفی شده

خیر . پیش پردازنده و کامپایلر ، زحمت تولید کدهای معادل رو برات میکشن . winMain نقطه شروع یک برنامه اجرائی است و نمیتونه داخل یک DLL باشه و تازه اکسپورت هم بشه .

Aminm_666
جمعه 18 دی 1383, 05:36 صبح
پس اجازه بدید اینجور سوال رو طرح کنم: MFC چیکار کرده که WinMainی توی برنامه هایی که باهاش مینویسیم وجود نداره. کجا مخفی شده؟ چطوری؟

Inprise
جمعه 18 دی 1383, 09:51 صبح
این ارتباطی با DLL نداره . کلاسهای مربوط به مدیریت برنامه و اشیائی که توسط ویزاردهای MFC هنگام ساخت یک برنامه تولید میشن ، winMain رو محصور میکنن . برنامه تو نهایتا" از همان winMain شروع میشه . DLL های MFC فقط حاوی کدهای زمان اجرای کتابخانهء MFC هستند . به عنوان مثال در زیر شاخهء mfc/src فایلی بنام appmodul.cpp وجود داره که میتونی WinMain رو اونجا پیدا کنی .

MFC under the hood (http://www.codeproject.com/cpp/mfcprogflow.asp)

مرتضی ن.
جمعه 18 دی 1383, 17:58 عصر
<span dir=ltr>
OK,
Sorry I can't type in Farsi,
I am not sure if MFC puts the WinMain in a DLL or statically links it to the main application but you CAN put your WinMain in a DLL, I did it yesterday and it works OK (though you need to test it on all supported OSs to make sure it’s really OK on all platforms, different version of windows really behave differently sometimes)

I personally prefer to use the DEF file and its EXPORT table, good luck if you want to use the __declXXXX,

I have also uploaded the small code I developed yesterday; please note that the code is provided AS IS this is you responsibility to test it thoroughly before using it in your application.



</span>

Inprise
جمعه 18 دی 1383, 19:51 عصر
همونطوری که گفتم EP استاندارد یک برنامه ویندوزی CPP تابع WinMain است . اینجا منظور از WinMain نقطه شروع برنامه است نه ترکیب کلمات Win و Main ! کدی که نوشتی یک کد کاملا بلا استفاده است . ( نحوه اکسپورتت هم اصولا غلطه )

توضیح بیشتر : کامپایلر سی ، نیاز داره یک نقطه شروع استاندارد برای برنامه در نظر بگیره و این نقطه شروع رو صراحتا" به لینکر معرفی کنه . نقطه شروع برنامه باید یک آدرس مشخص داشته باشه لهذا نمیتونه توی هیچ کتابخانهء دینامیکی قرار بگیره .

موفق باشید

Aminm_666
دوشنبه 21 دی 1383, 08:19 صبح
عالیجنابان مرتضی ن. و Inprise از همفکریتون ممنونم. از وقتی که گذاشتید و دردسری که متحمل شدید. با DEF فایل میشه WinMain رو export کرد. من هم امتحان کردم. کار کرد. حالا اگه خود بیل گیتس هم بیاد بگه نمیشه. شد! :موفق:

Inprise
دوشنبه 21 دی 1383, 08:48 صبح
تلاش بیشتری برای اینکه "بفهمی" نمیکنم . WinMain به معنای "نقطه شروع برنامه" فقط و فقط باید داخل خود برنامه باشه . آنچه که تو به خیال خودت داری اکسپورت میکنی ، یک کلمه است نه EntryPoint یک برنامه Win32 .

ولی برای اینکه خوش باشی همون کاری که کردی هم میتونه برات کافی باشه :sunglass:

Aminm_666
سه شنبه 22 دی 1383, 03:35 صبح
بر طبق آزمایشهایی که انجام دادم این WinMain خواه یک کلمه باشه خواه دو تا کلمه خواه شش تا حرف. کامپایلر بعنوان entry point قبولش داره و در زمان اجرا هیچ مشکلی پیش نمیاد. و همین برای من کافیه. اینکه اون پشت چه اتفاقی افتاده دیگه اهمیتی نداره. به اون چیزی که مد نظرم بوده رسیدم.
یک نکته شک برانگیز اینه که تو DEF فایلهای MFC خبری از WinMain نبود. در بدترین شرایط 50٪ حق با منه.

Inprise
سه شنبه 22 دی 1383, 12:56 عصر
کدی که نوشتی رو به همراه DLL ات ضمیمه کن تا بهت کمک کنم بفهمی Entry Point برنامه رو چطوری پیدا میکنن و تو چیکار کردی و جریان چیه .


یک نکته شک برانگیز اینه که تو DEF فایلهای MFC خبری از WinMain نبود. در بدترین شرایط 50٪ حق با منه.

WinMain برنامه های MFC اونجائی است که دفعه قبلی گفتم . چون حداقل توسعه گران MFC میدونستن که قبل از شروع یک برنامه ( از Entry Point ) نمیشه از توابع یک کتابخانه استفاده کرد ! ( چه برسه به اینکه EP توی خود اون کتابخانه ها باشه ) چون بدیهی و واضحه که ابتدا برنامه باید شروع بشه ، بعد توابع مربوطه بصورت دینامیک یا استاتیک فراخوانی بشن . علم یکی از معدود چیزهائی است که قطعی است . یعنی 50 درصد حق با منه و 60 درصد ! حق با توئه و غیره نداره . یه چیزی یا درسته یا غلطه .

Inprise
چهارشنبه 23 دی 1383, 00:59 صبح
<span dir=ltr>
OK,
Sorry I can't type in Farsi,
I am not sure if MFC puts the WinMain in a DLL or statically links it to the main application but you CAN put your WinMain in a DLL, I did it yesterday and it works OK (though you need to test it on all supported OSs to make sure it’s really OK on all platforms, different version of windows really behave differently sometimes)

I personally prefer to use the DEF file and its EXPORT table, good luck if you want to use the __declXXXX,

I have also uploaded the small code I developed yesterday; please note that the code is provided AS IS this is you responsibility to test it thoroughly before using it in your application.



</span>

آخرین مطلب مرتضی رو به دلیل مرتبط نبودن با بحث حذف کردم . اما برای اینکه ابهامش بر طرف بشه با توجه به کد خودش یه توضیحی میدم .

آنچه تو انجام دادی اکسپورت غلط یک تابع با نام WinMain است . بدون اینکه در برنامه کاربردی ازش استفاده شده باشه . این به معنای انجام کاری که Amin خواسته نیست . WinMain یا نقطه شروع برنامه تو داخل خود برنامه ات وجود داره ، یعنی هنگام اجرای برنامه ، برای شروع ، کنترل به DLL منتقل نمیشه . برای اینکه بصورت عینی این مساله رو ببینی ، کدت رو کمی تغییر بده ( اگر تونستی از winMain ای که مثلا اکسپورت کردی استفاده کن ) و بعد نتیجه نهائی رو Debug کن و آدرس EP رو با آدرس WinMain ای که داخل DLL وجود داره و به حافظه Load شده مقایسه کن . به سادگی خواهی دید که این آدرسها مطابقت ندارند و نقطه شروع برنامه ، تابع WinMain ای است که داخل خود برنامه وجود داره .

توضیحات و لینکی که صفحه قبل دادم برای درک نحوه عملکرد MFC کافیه . اما به عنوان یک توضیح اضافه :

یک Win32 Application نمیتونه WinMain نداشته باشه . یعنی عدم وجود WinMain به معنای کامپایل نشدن کد خواهد بود . WinMain حداقل عنصری است که باید تو یک برنامه Win32 لزوما" وجود داشته باشه . مثل در که حداقل نیاز یک اتاق است اگر قرار باشه کسی بتونه بره توی اون اتاق یا ازش خارج بشه .

MFC با پوشش برخی از توابع مانند WinMain سعی کرده توسعه برنامه رو از یک حالت Linar خارج کنه . اما نهایتا" قبل از کامپایل کد ، WinMain به برنامه تو اضافه میشه . DLL های MFC حاوی WinMain نیستند چون نمیتونن باشن . محتویات DLL ها تشکیل شده از پیاده سازی زمان اجرای کلاسهای MFC و لا غیر . مثل BPL های محصولات بورلند و VCL .

برای درک بهتر MFC ضمن توصیه مجدد به مطالعه لینک صفحه قبل ، توصیه میکنم مقاله مهدی موسوی در مورد معماری MFC رو تو کدپراجکت بخونید :

قسمت اول :
http://www.codeproject.com/cpp/mfc_architecture.asp

قسمت دوم :
http://www.codeproject.com/cpp/mfc_architecture2.asp



:)

Aminm_666
چهارشنبه 23 دی 1383, 06:18 صبح
درسته! entry point نمی تونه تو DLL باشه. درست ترش اینه که از داخل DLL اجرا نمیشه.

بدیهی و واضحه که ابتدا برنامه باید شروع بشه ، بعد توابع مربوطه بصورت دینامیک یا استاتیک فراخوانی بشن .
توابع کتابخانه ایستا در زمان کامپایل به برنامه پیوند زده میشن و تا زمان اجرا صبر نمی کنن. پس WinMain رو میشه با کتابخانه ایستا مخفی کرد چون در واقع به برنامه اضافه میشه. در این روش هم یه همچین اتفاقی افتاده. (قضیه 50٪ روشن شد؟)

WinMain یک تابع افسانه ای فراذهنی نیست. یک تابع معمولیه که توسط entry point اصلی (WinMainCRTStartup) فراخوانی میشه.

MFC با این کار بدنه WinMain رو به حداقل ممکن رسونده:

int WINAPI _tWinMain&#40;HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow&#41;
&#123;
// call shared/exported WinMain
return AfxWinMain&#40;hInstance, hPrevInstance, lpCmdLine, nCmdShow&#41;;
&#125;


و این بدنه نحیف تأثیری بر اندازه فایل اجرایی نهایی نخواهد داشت. AfxWinMain تو DLL هستش و export شده.

فکر می کنم دیگه پرونده این قضیه هم بسته شده.

Inprise
چهارشنبه 23 دی 1383, 14:04 عصر
خوشحالم که حل شد . اما نکته آخر :


توابع کتابخانه ایستا در زمان کامپایل به برنامه پیوند زده میشن و تا زمان اجرا صبر نمی کنن. پس WinMain رو میشه با کتابخانه ایستا مخفی کرد چون در واقع به برنامه اضافه میشه

اینطور نیست . کتابخانه های ایستا و پویا صرفا" در روش توزیع و نحوهء فراخوانی به حافظه ( و خروج از حافظه ) با هم تفاوت دارن . WinMain شروع Initialization توابع است و قبل از اون امکان فراخوانی هیچ تابعی وجود نداره . ( نمیخام وارد این بحث که WinMain خودش چی رو فراخوانی میکنه و غیره بشم ) .

و توضیح پایانی : ممکنه بعضی از دوستان با تجربه تر بپرسند Packer ها یا Encryptor ها یا سایر راه حلهائی که گاهی EP رو مخفی یا غیر قابل Trace میکنن چطور عمل میکنن . جوابش اینه که این ابزارها WinMain یا Main خودشون رو دارن و تمام برنامه اصلی رو محصور میکنن . برنامه هنگام اجرا از EP جدید اجرا میشه ( که اونم یه WinMain دیگه هست ) و بعد از UnPack یا Decrypt یا Dump کد تو حافظه ، باز هم کنترل اجرای برنامه اصلی به winMain اصلی برمیگرده . در واقع هیچکدام از توابعی که در کانتکست برنامه A فعال هستند نمیتونن زودتر از WinMain برنامهء A اجرا بشن . خواه توی کتابخانه های ایستا باشن ، یا پویا ، یا هر چیز دیگه ای که بشه تصور کرد .

روز خوش :)

مرتضی ن.
پنج شنبه 24 دی 1383, 00:30 صبح
مطلب مرتضی رو به دلیل مرتبط نبودن با بحث حذف کردم . اما برای اینکه ابهامش بر طرف بشه با توجه به کد خودش یه توضیحی میدم .

آنچه تو انجام دادی اکسپورت غلط یک تابع با نام WinMain است . بدون اینکه در برنامه کاربردی ازش استفاده شده باشه .

I don’t have any EBHAAAM! I am clear and I have posted a clear-small-compliable code, I am sure you haven’t even tried the code once the code exports and USES the WinMain, for your information:
Open the code in VC++ 6.0
Compile both DLL1 and DLLWinMain application, (DLL1.dll would be created in DLLWinMain application’s debug folder)

Put two break-points in DLL1.cpp file:
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE; /////BreakPoint here
}

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.

MessageBox(NULL,"TEST","TEST",MB_OK);
return 0; /////BreakPoint here
}

Debugging the application, you will see that:

1- it first loads the DLL (calling the DllMain)
2- goes to WinMain function
3- unloads the DLL (calls the DllMain again for unload)

Instead of going through what SHOULD be there and what COULD or COULD NOT be there, tell me based on your previous post, how this happens?


Morteza

Aminm_666
پنج شنبه 24 دی 1383, 04:07 صبح
آنچه در پی می آید نمونه کوچکی است از کاری که با راهنمایی جناب مرتضی خان انجام دادم(دل کندن از <span dir=ltr>__declspec</span> مایکروسافت). با همون روش «غلطی» که چند روزیه داریم روش جر و بحث می کنیم. ولی این روش غلط(به زعم اساتید!) جواب داده. بعنوان توضیح عرض کنم که WinMain رو تو DLL گذاشتم و تازه exportش هم کردم. وقتی هم که از این DLL برای پروژه های اجرایی استفاده می کنم تا هفت جد کامپایلر سراغ WinMain رو نمی گیرن. همون WinMainی که تو DLL هستش به خوبی و خوشی و میمنت اجرا میشه(فعلاْ از این مسئله صرف نظر می کنیم که همونی که تو DLL هست یا کپی اون یا هر چیز دیگه). این که در پشت صحنه چه اتفاقی افتاده سؤالیه که من هم دوست دارم جوابشو بدونم.

داخل پوشه HEP:
دو تا DLL با دوتا import library مربوطه(HEPD.dll و HEPD.lib برای نسخه Debug) و (HEP.dll و HEP.lib برای نسخه Release) به همراه فایلهای منبع DLLها.

داخل پوشه Sample:
دو تا فایل sample.h و sample.cpp قرار دارن. یه پروژه اجرایی Win32 خالی درست کنید و این دو تا فایل رو بهش اضافه کنید. اگه از پوشه Sample استفاده کنید کارتون راحت تر میشه. کامپایل کنید و نتیجه را مشاهده بفرمایید. (فکر می کنم اونایی که می تونن کمک کنن می دونن DLLها و LIBها رو کجا باید بذارن.)

Inprise
پنج شنبه 24 دی 1383, 16:35 عصر
سلام؛

توضیح : مطالب نامربوط به بحث رو بدون کوچکترین اغماضی حذف میکنم . برای مفید واقع شدن یه بحث فنی ، باید فضای اون بحث فنی نگه داشته بشه و این وظیفهء مدیران بخشهاست . باید تلاش کنیم در کنار بحث فنی ، اخلاق حرفه ای هم داشته باشیم ، که تو یه بحث در مورد یه مطلب پیش پا افتاده تصور نکنیم دعوا شده و تیکه به هم نندازیم . ( و دقیقا چون مدیر بخش هستم به کنایه ها جواب ندادم و نمیدم ) بنابر این کسانی که مایل هستن اینجا فعالیت کنن ، باید به قوانینش احترام بگذارند .

:)

@ مرتضی : من کدت رو بررسی کردم . البته نیازی به بررسی هم نبود . سعی میکنم این دفعه "ابهام" بر طرف بشه . برای ادامه این موضوع خوانندگان بحث باید حداقل یک دیباگر Assembler-Level داشته باشن . من WinDBG یا OllyDBG رو توصیه میکنم ؛ هر چند بقیه دیباگرهای موجود هم میتونن مفید باشن .

بعد از کامپایل کد ، خروجی رو با دیباگر اجرا کنین . براحتی خواهید دید که WinMain ای که داخل DLL قرار گرفته ، EPی برنامه نیست . فراخوانی و زمان فراخوانی اون هم کاملا" مشخص و قابل مشاهده است . حالا پیشنهاد میکنم به عنوان کمی تفریح ، برنامه اصلی رو به این شکل تغییر بدین :


int APIENTRY WinMain&#40;HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow&#41;

&#123; WinMain&#40;NULL,NULL,NULL,0&#41;;&#125;

حالا خروجی برنامه دوم رو با دیباگر اجرا کنین . خواهید دید که برنامه یک WinMain اصلی داره ، بصورت داخلی ؛ و تمامی ارجاعات به DLL لغو شدن . چرا این اتفاق افتاده ؟ یعنی با اضافه شدن یک WinMain دیگه به بدنهء WinMain قبلی ، DLL بطور کامل نا دیده گرفته میشه و هر دو WinMain کاملا" محلی تلقی میشن . ( آرگومانهای پاس شده به WinMain هم مشخص هستن . مثلا SW_Hide معادل 0 ) اگر WinMain به درستی از DLL اکسپورت شده و قاعدتا" میشه از اون استفاده کرد ، دلیل لغو فراخوانی از DLL به محض اضافه شدن WinMain دوم چیه ؟ منطقا" باید بشه از کلیهء توابع یک DLL همه جا و بطور نا محدود استفاده کرد . اگر WinMain قابل Export شدن از یک DLL هست ، و میشه به عنوان EP ازش استفاده کرد چرا EP برنامهء اول هیچ ارجاعی به WinMain موجود در DLL نداره ؟ جواب تمام این سوالات واضحه .

@ Amin : بعد از بررسی کد تو میشه از مجموع این مطالب نتیجه گیری کرد . بعد از کامپایل کدت و اجرای اون میشه پیام نمایش داده شده رو دید . آیا واقعا" WinMain داخل DLL فراخوانی شده ؟ خروجی رو با دیباگر اجرا کن . براحتی خواهی دید نقطه شروع برنامه ات تابع WinMainCRTStartUP است که بصورت Local و محلی فراخوانی شده و WinMain ای که از HEP فراخوانی شده هیچ نقشی در EP نداره . حالا مثل دفعهء قبل کد برنامه اصلی رو اینطوری تغییر میدیم :



BOOL XSampleApp&#58;&#58;InitInstance&#40;&#41;
&#123;
&#58;&#58;MessageBox&#40;NULL,
"The Sample application says&#58; Where is my WinMain?\nWhat you think about it?",
"XSampleApp", MB_OK|MB_ICONINFORMATION&#41;;

return FALSE;
&#125;
int WINAPI WinMain&#40;HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow&#41;
&#123;
XSampleApp theApp;
&#125;


کد بدون مشکل کامپایل میشه اما اتفاقی که می افته خیلی جالبه . این بار هم تمامی ارجاعات به DLL لغو شدن و برنامه بصورت محلی از WinMain خودش استفاده میکنه . XApplication که توسط HepWinMain تولید میشه ، به هیچ وجه ایجاد نمیشه . چرا ؟ اتفاق جدیدی نیفتاده . فقط XSampleApp theApp به داخل WinMain جدیدی که اضافه کردیم منتقل شده . چرا WinMain موجود در DLL فراخوانی نمیشه ؟ و چرا HepWinMain استفاده نمیشه ؟ مگه WinMain رو به درستی Export نکردی ؟ جواب این سوالات هم واضحه .


نتیجه ها :

- هیچکدام از کدهائی که نوشته اید از WinMain یا ارجاعی به اون ، وقتی که WinMain داخل DLL باشه ، به عنوان EP استفاده نمیکنن . ( بگذریم از اینکه کد اول ، به دلیل عدم وجود EP استاندارد توسط IDA هم به عنوان یک Win32 APP استاندارد شناخته نمیشه و قابل Disassemble شدن نیست )

- WinMain رو نمیشه از یک DLL اکسپورت کرد . اینجا WinMain به معنای EP است و نه ترکیب دو کلمه . شما با موفقیت تابعی به نام WinMain رو اکسپورت میکنین ، و تصور میکنین این به اون معناست که حالا EP برنامه داخل DLL است . در حالیکه Debug و Disassemble کد ها نشون میده ، در هر دو مورد WinMain ها هیچ نقشی در EP ندارند . در حالیکه پس از تغییر و دستکاری هر دو کد ، خروجی ها از WinMain به عنوان EP استفاده میکنن . ( هر دو مورد تغییر هم بر خلاف اصل استفاده از توابع DLL ها نیست . یعنی اگر بشه WinMain رو اکسپورت کرد ، باید کدهای دستکاری شده هم با کمی تفاوت مثل کدهای اولیه عمل کنن . در حالیکه این اتفاق نمی افته )

- فارغ از توضیحات فنی ( اگر حوصله میداشتم میشد هفت هشت صفحه برای هر کدوم از این سه نتیجه توضیح نوشت ) اصولا" منطق استفاده از WinMain خارجی ، قابل درک نیست . WinMain وظیفه مقدار دهی به متغیرهای لازم برای شروع برنامه و فراخوانی کتابخانه های متصل شده و ... رو به عهده داره . وقتی هنوز LoadLibrary هیچ آدرسی نداره ، چطوری میشه از برنامه خواست که اون رو صدا کنه تا او بتونه WinMain رو از DLL فراخوانی کنه ؟ مسئله خیلی ساده است . بالاخره هر برنامه نقطه شروعی میطلبه که مقدمات رو فراهم کنه . بعد از اون نقطه شروع ( EP ) تازه میشه LoadLibrary رو صدا زد ، از توابع Kernel و User و GDI استفاده کرد و ...الخ . وقتی WinMain داخل یک DLL قرار گرفته باشه ، چطور میتونه قبل از Load شدن به حافظه ، سایر کتابخانه ها رو فراخوانی کنه ؟ برنامه از کجا آغاز میشه ؟ چه کسی آدرسها رو مدیریت میکنه ؟

ممکنه یکی بپرسه اتصال استاتیک DLL ( که بحثش شد ) چطور ؟ مشکل رو حل میکنه ؟ جواب بازم منفیه . با اتصال استاتیک ، هر چند WinMain یه آدرس ثابت داره ، اما این آدرس رو چه کسی به Loader میده ؟ یعنی سیستم عامل چطور باید بفهمه آدرس WinMain چیست ؟ حتی اگر اکسپورت WinMain بصورت استاتیک هم مقدور میبود ، هیچ مکانیزمی برای آگاه سازی Loader سیستم عامل از آدرس EP وجود نداشت ، حالا بگذریم از اینکه این عملا" امکان نداره .

ممکنه یکی دیگه بپرسه با اتصال استاتیک DLL و استفاده از ویژگی EntryPoint و ثبت آدرس WinMain به عنوان EP این مشکل حله ؟ جوابش مثبته . اما این دقیقا" به معنای استفاده محلی از WinMain است . در واقع استفاده از WinMain یک کتابخانهء متصل شده بصورت استاتیک ، به همراه تنظیم آدرس EP برای لینکر ، فرقی با استفاده محلی از WinMain ندارد .

- اگر به منطق ماجرا هم نگاه کنین ، WinMain باید داخل خود برنامه قرار گرفته باشه . امکان اتصال دینامیک چیزی که خودش آدرس سایر اتصالهای دینامیک رو دریافت و در اختیار پردازنده قرار میده ، مضحک به نظر میاد . مثل ماجرای قدیمی بحث درباره مرغ و تخم مرغ .

اگر مایل باشید این بحث میتونه تا بررسی خط به خط کد تولید شده توسط اسمبلر ، ادامه پیدا کنه . هر چند که تصور میکنم اتفاق جدیدی نخواهد افتاد . بررسی عملکرد MSVCRT در کنترل EP برنامه هائی که توسط کامپایلر مایکروسافت کامپایل میشن ، خیلی میتونه به درک درست نحوهء مدیریت WinMain کمک کنه . ( همونطوری که قبلا" عرض کردم چطوری WinMain رو اضافه میکنه ) توسعه گران MFC هم با توجه به چنین نکاتی ، معماری MFC رو اونطوری که قبلا" بحث شد طراحی کردن . یعنی WinMain در هر حال داخل خود برنامه خواهد بود . پس برای مدیریت صحیح عملکرد اون ، در زمان اجرا ، از چند تابع پوششی استفاده کردن که لزوما" نباید داخل خود برنامه باشن ، در حالیکه WinMain برنامه های MFC هم مثل بقیه برنامه های C داخل خود برنامه است ، نه جای دیگه .

توضیح : عکسهای ضمیمه به همین بحث مربوطن ، مطابق ترتیب بررسی مطالب .

عصر خوش

Inprise
پنج شنبه 24 دی 1383, 16:40 عصر
--

Aminm_666
شنبه 26 دی 1383, 00:25 صبح
آغاز حیات یه برنامه Win32 با WinMainCRTStartup شروع میشه. entry point اصلی و ابتدایی اینه نه بر خلاف تصورت WinMain. اگه یوخده به خودت زحمت میدادی فراخوانی WinMain رو توسط WinMainCRTStartup مشاهده می کردی. این تفکر غلط رو از خودت دور کن که: قبل از WinMain هیچ اتفاقی نمی تونه بیافته و هیچ چیز نمی تونه فراخوانی شه. همین که DLL قبل از شروع WinMain بارگذاری می شه دلیلی بر این مدعاست. درسته که WinMain ناحیه ای تمام ارجاعات رو نقض می کنه. این طبیعی ترین چیزیه اتفاق افتاده. تو MFC هم یه WinMain ناحیه ای اضافه کن تا ببینی چه بلایی سر MFC می آد. WinMainCRTStartup برای ادامه کارش به یه WinMain احتیاج داره و این احتیاج بر آورده شده. برنامه بدون مشکل اجرا میشه و به اتمام می رسه. تنها چیزی که این وسط می مونه ناحیه ای نبودن WinMain است. این رو هم با مدد گرفتن از کتابخانه های ایستا میشه رفع کرد. کافیه WinMain قصه ما از داخل DLL کوچ کنه بره به یه کتابخانه ایستا.
داخل پوشه HEP:
DLLها با LIBهای مربوطه و فایلهای منبع.

داخل پوشه SHEP:
static library حاوی WinMain. با فایل منبع.

داخل پوشه Sample:
فایل منبع برای پروژه اجرایی.

Inprise
شنبه 26 دی 1383, 04:15 صبح
جواب قبلی من به اندازه کافی فنی و گویا بود . امیدوارم بعدا" سر فرصت یکبار دیگه دقیق مطالعه اش کنی و آنچه گفتم انجام بدی ؛ مرحله به مرحله . توضیح جدیدی برای ارائه ندارم . بخشی از نوشته ات و کدت موید آنچه گفتمه و بخشیش رو دقیقا" با استناد تو جواب قبلی رد کردم .

بهر حال اگر این داره به زعم تو مشکلت رو حل میکنه ؛ حالش و ببره . همینقدر که یک قدم به واقعیت نزدیک شدیم و دیدیم که فراخوانی WinMain از DLL ممکن نیست و در عمل اتفاق نمی افته کافیه . احتمالا" با برررسیهای بعدی خواهی دید که CRT مدیریت EP رو در صورت لزوم به عهده میگیره ( همونطوری که در مورد کد دوم تو جواب قبلیم توضیح دادم ) و WinMain موجود در DLL ایستا هم بدون تنظیم خصوصیت entryPoint نقطه شروع برنامه نیست . راه بررسی و کشف و شهود برای هر کسی که مایل باشه بازه .

:sunglass:

به عنوان نکته آخر : یه مطلب مختصر در مورد نحوهء عملکرد CRT در مدیریت EP های غیر استاندارد اینجا (http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2) هست که میتونه بخشی از مطالب جواب قبلی منو بیشتر توضیح بده ؛ تا بهتر مشخص بشه کد دقیقا از کجا و توسط چه کسی شروع میشه .

موفق باشید :)

Aminm_666
دوشنبه 28 دی 1383, 18:25 عصر
ایده من در مورد کتابخانه ایستا درسته. ایده ای که از اولش هم داشتم ولی فکر می کردم راه بهتری هم برای این کار هست. «توابع کتابخانه ایستا به فایل اجرایی کپی میشه». من جواب سوالاتم رو از MSDN می گیرم:

<span dir=ltr>
Recall that when you statically link, the linker copies the function from the static run-time library that ships with Visual C++ into your .exe.

When you dynamically link, the linker does not copy the function into your .exe. Instead, it places a reference to the function in your .exe, but the code itself lives in the dynamically linked library.
</span>

در ضمن تمام لینکهای این بخش همه چیز توشون هست الا اون چیزی که من دنبالش بودم. جستجوی خودم هم ثمری نداشت. ای بخشکی شانس...