PDA

توجه ! این یک نسخه آرشیو شده می باشد و در این حالت شما عکسی را مشاهده نمی کنید برای مشاهده کامل متن و عکسها بر روی لینک مقابل کلیک کنید : مقدمه بسیار ساده‌ای بر توابع api در دات نت



TAHA
09-30-2009, 02:34 PM
برنامه نویسان ویژوال بیسیک تا قبل از ورود دات نت بسیار به توابع API وابسته بودند. به علت این که ویژوال بیسیک توابع و کلاسهای آماده بسیار کمی رو عرضه میکرد و حتی کنترلهای عمومی ویندوز رو هم به صورت بسیار ناقصی پشتیبانی می‌کرد، از این رو به وفور در برنامه‌ها از توابع API استفاده میشد.
اما در دات نت وضع بدین گونه نیست و شما می‌تونید از دریای کلاسها و توابع موجود در دات نت فریم ورک بهره بگیرید. بسیاری از اعمالی رو که در گذشته با مشقت فراوان و با استفاده از توابع API و به شکل نامطمئنی انجام می‌دادیم امروز به سادگی انجام پذیر است.
با این حال باز هم اگرچه بندرت ولی در مواردی ناچار به استفاده از این توابع خواهیم بود.
همون طور که می‌دونیم نخستین قدم برای استفاده از یک تابع API اعلام و وارد کردن اون تابع به برنامه است. در VB.NET دو راه برای اعلام یک تابع API وجود دارد. یکی استفاده از عبارت کلیدی Declare و دیگری استفاده از خصوصیت DllImport.
استفاده از Declare تا حد زیادی مشابه قبل می‌باشد لیکن برخی تفاوتهای جزئی نیز وجود دارد.
یکی از این تفاوتها این است که در گذشته اعلام این توابع با دسترسی سراسری تنها در ماژولهای استاندارد (*.bas) ممکن بود ولی در دات نت می‌توان یک تابع API رو درون هر کلاسی و با دسترسی Public اعلام کرد.
تفاوت دیگری که می‌توان اشاره کرد این است که اگر احیانا خواستید یک تابع قدیمی رو به دات نت تبدیل کنید تمام متغیرهای از نوع Long رو باید به Integer تبدیل کنید. به عبارت دیگر در دات نتInteger برابر Long در VB6.0 است.
در مورد استفاده از رشته‌ها و ساختارها تفاوتهای عمده‌ای وجود داره که اگر کسی مایل بود بعدا مختصری در مورد اون با هم صحبت خواهیم کرد. توی MSDN توضیحات کاملی در این زمینه وجود داره.
این یک مثال برای چگونگی اعلام یک تابع API در VB.NET است:
:

Declare Function MoveFile Lib "kernel32.dll" Alias "MoveFileA" (ByVal lpExistingFileName As String, ByVal lpNewFileName As String) As Integer
روش دوم استفاده از DllImport است. این Attribute یک تابع در برنامه ما را به یک تابع داخل Dll منسوب می‌کند. برای بهره گیری از این خصوصیت باید فضای اسمی System.Runtime.InteropServices به صدر ماژول اضافه شود. این Attribute در کلاس DllImportAttribute قرار دارد.
شکل اعلام یک تابع با استفاده از این روش را در این مثال ملاحظه می‌کنیم.
کد:

<DllImport("KERNEL32.DLL", EntryPoint := "MoveFileW", _
SetLastError := True, CharSet := CharSet.Unicode, _
ExactSpelling := True, _
CallingConvention := CallingConvention.StdCall)> _
Public Shared Function MoveFile(src As String, dst As String) As Boolean
' Leave function empty - DLLImport attribute forwards calls to MoveFile to
' MoveFileW in KERNEL32.DLL.
End Function
در C#‎:



[DllImport("KERNEL32.DLL", EntryPoint = "MoveFileW",
SetLastError = true, CharSet = CharSet.Unicode,
ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern bool MoveFile(string src,string dst);
بدنه تابع خالی می‌ماند و محتوای اون بوسیله DllImport فراخوانده میشود آرگومان اول که نام Dll رو معین میکنه و ارگومان دوم که نقطه ورودی تابع موردنظر رو تعیین میکنه آرگومانهای ضروری هستند و بقیه را میتوان درج نکرد. ولی بهتر است که از همین ترکیب پیروی شود.

به نظر من استفاده از روش دوم بهتره. چرا که روش دوم با اندک تغییراتی در سایر زبانهای دات نت هم کاربرد داره.

از این آدرس می‌تونید نرم‌افزاری رو دریافت کنید که اعلام اکثر توابع API رو به زبانهای مختلف در خودش داره.
http://www.activevb.de/rubriken/apiv...viewereng.html (http://www.activevb.de/rubriken/apiviewer/index-apiviewereng.html)

TAHA
09-30-2009, 02:36 PM
ارسال ساختارها و کلاسها به عنوان پارامتر:

اگرچه در اکثر موارد فراخوانی Dll ها به شکل یکسانی صورت میگیرد ولی برخی استثنائات در این زمینه وجود دارد که به شرح برخی از آنها می پردازیم.
یکی از این استثنائات ارسال Structure ها می‌باشد.
بسیاری از توابع در کتابخانه‌های Unmanged یک کلاس یا ساختار را به عنوان آرگومان می‌پذیرند. هنگامی که از سیستم خواسته میشود که یک عضو کلاس یا Structure را به یک تابع ارسال کند، سیستم نیاز به یک سری اطلاعات اضافی برای فرمت آن ساختار دارد تا بتواند ترکیب و آرایش اصلی آن را حفظ نماید.

خصیصه StructLayout برای این منظور به کار می‌رود. این خصیصه کلاس یا ساختار موجود در برنامه ما را برای تابع احضار شده تفسیر میکند و آرایش و ترتیب قرارگرفتن اعضا را برای آن مشخص می‌کند.

ترکیب اعضا میتواند به سه شکل تعریف شود: اتوماتیک، ترتیبی و صریح.

در حالت اتوماتیک اعضا به صورت اتوماتیک در زمان اجرا مرتب میشوند.
تذکر: این گزینه را برای ارسال ساختار به توابع API به کار نبرید. در صورت انجام چنین کاری با یک خطا مواجه خواهید شد.

در حالت صریح ترتیب قرارگیری اعضا به صورت صریح مشخص میشود. یعنی ما به صراحت مشخص می‌کنیم که هر عضو باید در کجا قرار بگیرد. این کار از طریق خصلت FieldOffset برای هر فیلد انجام میشود.

در حالت ترتیبی اعضا با همان ترتیبی که در برنامه مشخص شده‌اند و بدون اینکه تغییری در آرایش آنها داده شود، ارسال میشوند.

مثال زیر چگونگی تعریف انواع Rect و Point و ارسال آنها به تابع PtInRect در User32.dll را نمایش میدهد. (این تابع بررسی می‌کند که یک نقطه داخل یک مستطیل قرار می‌گیرد یا خیر)
شکل اصلی این تابع به صورت زیر است:



BOOL PtInRect(const RECT *lprc, POINT pt);
توجه داشته باشید که از آنجا که تابع انتظار یک اشاره گر به ساختار Rect را دارد، ساختار Rect را باید از طریق مرجع (ByRef) به تابع ارسال کنید.
کد:

Imports System.Runtime.InteropServices

<StructLayout(LayoutKind.Sequential)> Public Structure Point 'این ساختار به صورت ترتیبی پاس خواهد شد
Public x As Integer
Public y As Integer
End Structure

<StructLayout(LayoutKind.Explicit)> Public Structure Rect ' این ساختار به صورت صریح پاس خواهد شد
<FieldOffset(0)> Public left As Integer
<FieldOffset(4)> Public top As Integer
<FieldOffset(8)> Public right As Integer
<FieldOffset(12)> Public bottom As Integer
End Structure

Class Win32API
'اعلام تابع
Declare Function PtInRect Lib "user32.dll" _
(ByRef lprc As Rect,ByVal pt As Point) As Boolean
End Class
در C#‎:
کد:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)] public struct Point //این ساختار به صورت ترتیبی پاس خواهد شد
{
public int x;
public int y;
}

[StructLayout(LayoutKind.Explicit)] public struct Rect // این ساختار به صورت صریح پاس خواهد شد
{
[FieldOffset(0)] public int left;
[FieldOffset(4)] public int top;
[FieldOffset(8)] public int right;
[FieldOffset(12)] public int bottom;
}
تعریف کلاسها هم تقریبا به همین صورت انجام میشود.