07-30-2012، 10:15 AM
بعنوان یک زبان برنامهنویسی با توسعه سریع، ویژوال بیسیک نظر خیلی از برنامهنویسان را از جهت سادگی به خود معطوف کرد. برنامهنویسی با ویژوال بیسیک در کمترین زمان صورت میگیرد حال آنکه در مقابل زبانهایی چون C و ++C اغلب اوقات به روزها کار مفید نیاز است.
اما بیشترین انتقادی که برنامهنویسان از ویژوال بیسیک دارند در این است که قادر به تولید کتابخانههای پویا (DLL) نیست. حقیقتا این نظر مورد قبول است که نمیتوان این نوع فایلها را در کنار فایلهای اجرایی(Exe) یا ActiveX Exe تولید کرد.
در این مقاله ما قصد داریم که نگاه دقیقی به نحوه تولید فایلهای اجرایی در ویژوال بیسیک یندازیم و بعد با طی مراحل سادهای موفق به ایجاد فایلهای DLL بشویم تا از زیر بار این انتقاد نیز رهایی یابیم.
قبلا به این موضوع اشاره شد که فایهای DLL آن دست از برنامههایی هستند که یکبار نوشته میشوند و در پروژههای بعدی بکرات میتواند از آنها استفاده برد. چیزی که هسته ویندور را تشکیل میدهد اینگونه فایلها هستند. علاوه بر آن تکنیکهایی وجود دارد که شما را قادر میسازد تا برنامههایی بنویسید که قادرند خود را بروز برسانند و یا خود ترمیم باشند. بهتر از آن اینکه برنامهای بنویسید که با الحاق اینگونه فایلها بدان قدرت و امکانات جدید بدان افزود. همانند نرمافزارهای رایج از جمله Winamp.
کتابخانههای پویای قابل اتصال (DLL) چه هستند؟اما بیشترین انتقادی که برنامهنویسان از ویژوال بیسیک دارند در این است که قادر به تولید کتابخانههای پویا (DLL) نیست. حقیقتا این نظر مورد قبول است که نمیتوان این نوع فایلها را در کنار فایلهای اجرایی(Exe) یا ActiveX Exe تولید کرد.
در این مقاله ما قصد داریم که نگاه دقیقی به نحوه تولید فایلهای اجرایی در ویژوال بیسیک یندازیم و بعد با طی مراحل سادهای موفق به ایجاد فایلهای DLL بشویم تا از زیر بار این انتقاد نیز رهایی یابیم.
قبلا به این موضوع اشاره شد که فایهای DLL آن دست از برنامههایی هستند که یکبار نوشته میشوند و در پروژههای بعدی بکرات میتواند از آنها استفاده برد. چیزی که هسته ویندور را تشکیل میدهد اینگونه فایلها هستند. علاوه بر آن تکنیکهایی وجود دارد که شما را قادر میسازد تا برنامههایی بنویسید که قادرند خود را بروز برسانند و یا خود ترمیم باشند. بهتر از آن اینکه برنامهای بنویسید که با الحاق اینگونه فایلها بدان قدرت و امکانات جدید بدان افزود. همانند نرمافزارهای رایج از جمله Winamp.
یک DLL مجموعهای از توابع و پروسههایی است که میتواند از برنامه یا DLLهای نظیر خود فراخوانده شود.
استفاده از اینگونه کتابخانههای دو مزیت اصلی دارد:
1- امکان به اشتراک گذاری از کد را فراهم میسازند. یک DLL میتواند مورد استفاده خیلی از برنامههای قرار گیرد. بعنوان مثال کتابخانه Win32 API نمونهای از این سری فایلها است. بعلاوه از زمانی که پروسههای گوناگون قادر به فراخوانی یک DLL واحد هستند امکان به اشتراک گذاری کدها و روتینها فراهم آمده است. یک فایل DLL تنها یکبار به درون حافظه لود میشود و بارها توسط پروسههای گوناگونی مورد استفاده قرار میگیرد و این یعنی مدیریت حافظه بهتر.
2- مزیت دیگر امکان نوشتن برنامهها بصورت اجزای منفصل است که این اجزا خود قابل تعویض با نگارشهای جدیدتر جهت توسعه نرمافزار خواهند بود بدون اینکه خطی از کد برنامه اصلی دگرگون شود.
با این توصیف فایلهای کتابخانهای درونی که در پروژههای مورد استفاده قرار میگیرد در صورت تغییر نیاز هست تا پروژه اصلی دوباره کمپایل شود تا بتوان با آن ارتباط بر قرار کرد. اما در DLL ها چون بصورت پویا و قابل انعطاف نوشته شدهاند این اتصال در بیرون از بدنه اصلی و درست در زمان فراخوانی آن قبیل از متدها و توابع شکل میگیرد و این خود تفاوت آشکار از مزیت این گونه از فایلها میباشد.همچنین یک فایل DLL میتواند حاوی توابعی باشد که فقط مورد استفاده خود هست و از درون به آن دسترسی نخواهیم داشت و آندسته از تابعی را که نیاز هست معرفی میکنیم تا از بیرون بدان دسترسی داشته باشیم. در این مرحله نیاز به معرفی در فایلهای Def هست که در پروژههای C و C++ مورد استفاده قرار میگیرد.
و اما ساختار DLL
فایلهای DLL حاوی یک مدخل شروع انتخابی (optional entry point) و پایانی هستند که در زمانی که توسط برنامههای دیگر به درون حافظه لود یا آنلود میشوند قابل اجرا است. ویندوز این پروسه را در زمانی که یک برنامه DLLها را بدرون حافظه لود یا آنلود میکند اجرا میکند.
این دو نوع پروسه به DLL این امکان را میدهد که یک سری از مقدمات را پیش از استفاده مهیا کند یا بعد از استفاده پاکسازی نماید. در ویژال بیسیک این تابع بدین گونه تعریف میشود:
[align=left]Public Function DllMain(hinstDLL As Long, fdwReason As Long , lpwReserved As Long) As Boolean
که پارامترهای آن بدین قرارند:1- امکان به اشتراک گذاری از کد را فراهم میسازند. یک DLL میتواند مورد استفاده خیلی از برنامههای قرار گیرد. بعنوان مثال کتابخانه Win32 API نمونهای از این سری فایلها است. بعلاوه از زمانی که پروسههای گوناگون قادر به فراخوانی یک DLL واحد هستند امکان به اشتراک گذاری کدها و روتینها فراهم آمده است. یک فایل DLL تنها یکبار به درون حافظه لود میشود و بارها توسط پروسههای گوناگونی مورد استفاده قرار میگیرد و این یعنی مدیریت حافظه بهتر.
2- مزیت دیگر امکان نوشتن برنامهها بصورت اجزای منفصل است که این اجزا خود قابل تعویض با نگارشهای جدیدتر جهت توسعه نرمافزار خواهند بود بدون اینکه خطی از کد برنامه اصلی دگرگون شود.
با این توصیف فایلهای کتابخانهای درونی که در پروژههای مورد استفاده قرار میگیرد در صورت تغییر نیاز هست تا پروژه اصلی دوباره کمپایل شود تا بتوان با آن ارتباط بر قرار کرد. اما در DLL ها چون بصورت پویا و قابل انعطاف نوشته شدهاند این اتصال در بیرون از بدنه اصلی و درست در زمان فراخوانی آن قبیل از متدها و توابع شکل میگیرد و این خود تفاوت آشکار از مزیت این گونه از فایلها میباشد.همچنین یک فایل DLL میتواند حاوی توابعی باشد که فقط مورد استفاده خود هست و از درون به آن دسترسی نخواهیم داشت و آندسته از تابعی را که نیاز هست معرفی میکنیم تا از بیرون بدان دسترسی داشته باشیم. در این مرحله نیاز به معرفی در فایلهای Def هست که در پروژههای C و C++ مورد استفاده قرار میگیرد.
و اما ساختار DLL
فایلهای DLL حاوی یک مدخل شروع انتخابی (optional entry point) و پایانی هستند که در زمانی که توسط برنامههای دیگر به درون حافظه لود یا آنلود میشوند قابل اجرا است. ویندوز این پروسه را در زمانی که یک برنامه DLLها را بدرون حافظه لود یا آنلود میکند اجرا میکند.
این دو نوع پروسه به DLL این امکان را میدهد که یک سری از مقدمات را پیش از استفاده مهیا کند یا بعد از استفاده پاکسازی نماید. در ویژال بیسیک این تابع بدین گونه تعریف میشود:
[align=left]Public Function DllMain(hinstDLL As Long, fdwReason As Long , lpwReserved As Long) As Boolean
hInstDLL که حاوی یک مقدار یکتا بعنوان دستگیره فایل DLL است.
fdwReason مشخص کننده دلیل فراخوانی این پروسه توسط سیستمعامل است که یکی از چهار مقدار زیر را به خود منتصب میکند:
DLL_PROCESS_ATTACH (1): یک پروسه در حال لود DLL به دورن حافظه است. هر پیشنیاز باید در اینجا شکل گیرد.
DLL_THREAD_ATTACH (2): یک ریسمان (Thread) برای این DLL در حال تولید است. هر پیشنیاز برای ایجاد ریسمان در این مرحله میتواند شکل بگیرد.
DLL_THREAD_DETACH (3) ریسمان در حال پایان یافتن است. به منظور پاکسازی DLL از حافظه.
DLL_PROCESS_DETACH (0) فایل DLL در حال خروح از حافظه است. بمنظور پاکسازی سایر کارها توسط برنامهنویس امکان انجام در این مرحله فراهم آمده است.
lpvReserved: حاوی مقدار اضافی در استفاده از DLL_PROCESS_ATTACH یا DLL_PROCESS_DETACH میباشد.
مقدار برگشتی تابع DllMain در هنگام صدا زدن بصورت DLL_PROCESS_ATTACH مقدار TRUE را باید به خود بگیرد.
در تلاش برای تولید و توسعه یک DLL نمونه قصد این را داریم که یک کتابخانه ریاضی تشکیل دهیم. کد زیر در ماژولی بنام MathLib.Bas قرار میگیرد:
Option Explicit
Public Const DLL_PROCESS_DETACH = 0
Public Const DLL_PROCESS_ATTACH = 1
Public Const DLL_THREAD_ATTACH = 2
Public Const DLL_THREAD_DETACH = 3
Public Const DLL_PROCESS_DETACH = 0
Public Const DLL_PROCESS_ATTACH = 1
Public Const DLL_THREAD_ATTACH = 2
Public Const DLL_THREAD_DETACH = 3
Public Function DllMain(hInst As Long, fdwReason As Long, lpvReserved As Long) As Boolean
Select Case fdwReason
Case DLL_PROCESS_DETACH
' No per-process cleanup needed
Case DLL_PROCESS_ATTACH
DllMain = True
Case DLL_THREAD_ATTACH
' No per-thread initialization needed
Case DLL_THREAD_DETACH
' No per-thread cleanup needed
End Select
End Function
Select Case fdwReason
Case DLL_PROCESS_DETACH
' No per-process cleanup needed
Case DLL_PROCESS_ATTACH
DllMain = True
Case DLL_THREAD_ATTACH
' No per-thread initialization needed
Case DLL_THREAD_DETACH
' No per-thread cleanup needed
End Select
End Function
Public Function Increment(var As Integer) As Integer
If Not IsNumeric(var) Then Err.Raise 5
Increment = var + 1
End Function
If Not IsNumeric(var) Then Err.Raise 5
Increment = var + 1
End Function
Public Function Decrement(var As Integer) As Integer
If Not IsNumeric(var) Then Err.Raise 5
Decrement = var - 1
End Function
If Not IsNumeric(var) Then Err.Raise 5
Decrement = var - 1
End Function
Public Function Square(var As Long) As Long
If Not IsNumeric(var) Then Err.Raise 5
Square = var ^ 2
End Function
If Not IsNumeric(var) Then Err.Raise 5
Square = var ^ 2
End Function