PDA

View Full Version : مقدمه بسیار ساده‌ای بر توابع API در دات نت



Abbas Arizi
یک شنبه 26 بهمن 1382, 14:13 عصر
برنامه نویسان ویژوال بیسیک تا قبل از ورود دات نت بسیار به توابع 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/apiviewer/index-apiviewereng.html

Vahab
یک شنبه 26 بهمن 1382, 15:07 عصر
ممنون

sh
یک شنبه 26 بهمن 1382, 16:53 عصر
سلام

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

sh
یک شنبه 26 بهمن 1382, 18:18 عصر
دوستان دیگر اگر مطلب تکمیلی یا کتاب یا مثالهای عملی دارن لطف کنند و ارائه بدن

با تشکر

Abbas Arizi
پنج شنبه 30 بهمن 1382, 00:29 صبح
ارسال ساختارها و کلاسها به عنوان پارامتر:

اگرچه در اکثر موارد فراخوانی 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;
}
تعریف کلاسها هم تقریبا به همین صورت انجام میشود.

Vahab
پنج شنبه 30 بهمن 1382, 11:25 صبح
بازم ممنون

امیدوارم ادامه پیدا کنه

sh
پنج شنبه 30 بهمن 1382, 15:40 عصر
سلام

عباس جان دستت درد نکنه :flower:

امیدوارم تا افتادن صحیح دوزاری من کمی ادامه بدی

با تشکر

Abbas Arizi
پنج شنبه 30 بهمن 1382, 16:37 عصر
خواهش می‌کنم. قابلی نداره.
انشااله اگه دو زاری خودم توی بعضی مسائل کامل افتاد، باز هم ادامه میدم. :wink:
البته با توجه به اینکه از هفته آینده کلاس و مدرسه دوباره شروع میشه و اوقات بیکاری من به شدت کاهش پیدا می‌کنه :( ممکنه وقوع این امر کمی به تاخیر بیفته.
به هر حال از دوستان دیگه اگر کسی اطلاعات خوبی داره که به درد بقیه می‌خوره دریغ نکنه.

sh
شنبه 02 اسفند 1382, 20:51 عصر
سلام

آقای عریضی اگر ممکنه یک مثال از استفاده از تابع RASDIAL در VB.NET برایم بزنید

با تشکر

Abbas Arizi
یک شنبه 03 اسفند 1382, 16:09 عصر
عجب تابع خفنیه.
من نه تنها خودم نتونستم کدشو بنویسم، حتی کدهایی که از این ور و اون ور هم گیر آوردم هیچ کدوم کار نکرد. نه اونی که با VB نوشته شده بود نه اونی که با VB.NET نه سی شارپ :گیج: :گیج: . فقط یه کد VC دل :heart: بود که کار کرد.
شرمنده :oops:

حالا بازم پیگیرش هستم اگه بعدا به نتیجه‌ای رسیدم در جریان میذارمت.

sh
یک شنبه 03 اسفند 1382, 20:02 عصر
سلام

(:D) عباس جون پس خیال میکنی به خاطر چی شد که من سر بحث توابع API رو باز کردم اولین مشکلی که داشتم با همین تابع بود

انشالله که این بحث ادامه داشته باشه چون واقعا دات نت خیلی پیج و خم داره

نمیدونم آقای آذیش این تاپیک رو دیده یا نه :?:


با تشکر

Abbas Arizi
یک شنبه 03 اسفند 1382, 20:38 عصر
درسته. توی دات نت استفاده از توابع API نسبت به قبل خیلی پیچیده تره و این کاملا طبیعیه. فراخوانی یک Unmanaged Code از یک Managed Code طبیعتا پیچیدگیهای خاص خودش رو داره.
ولی از یک طرف دیگه صرفنظر از زبان برنامه نویسی و پلتفرم هر کدام از توابع کاربرد و قواعد خاص خودشون رو دارن که باید به طور جداگانه مطالعه بشن و در اون مورد باید به مستندات خود این توابع مراجعه کرد.
در مورد این تابع هم همین طوره. هنوز کارکردهای اون یه مقدار مبهمه. چون من با VB که از این قید و بندها فارغه هم نتونستم کدی بنویسم که جواب درست بده.

sh
جمعه 08 اسفند 1382, 15:34 عصر
سلام

راستی آقای عریضی تونستی کاری بکنی با این تابع یا نه ؟

Abbas Arizi
جمعه 08 اسفند 1382, 16:07 عصر
امروز یه کم دیگه باهاش ور رفتم ولی نشد. عجیبه که به هیچ صراطی مستقیم نیست. من چند تا کد مختلف هم توی چند تا سایت پیدا کردم ولی جواب نمیده.
می‌تونم ازت بپرسم برای چه کاری میخوایش؟

sh
جمعه 08 اسفند 1382, 16:49 عصر
سلام

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

البته اگر کامپوننت هم گیر آوردی بد نیست ولی علاقه دارم از همون توابع API استفاده کنم توی چند تا فروم انگلیسی هم نوشتم ولی انگار هیچ کس نمیتونه :(

راستی یه چیزی گیر آوردم ببین میتونی از توش کد VB.NET بیرون بکشی اگر تونستی مارو از یاد نبر :wink:


با تشکرhttp://www.codeproject.com/useritems/RasDemo/RasDemo.zip

Farhad.B.S
جمعه 08 اسفند 1382, 17:44 عصر
برای نیاز فعلیتون میتونید از این تابع استفاده کنید :


Declare Function InternetDial Lib "wininet.dll" (ByVal hwndParent As Int32, ByVal lpszConnectoid As String, ByVal dwFlags As Int32, ByRef lpdwConnection As Int32, ByVal dwReserved As Int32) As Int32


در باره RASDIAL هم میتونید یه نگاهی به این اکتیوایکس بندازید :
http://www.coolstf.com/docs/rasdial.html

یه مطلب دیگه اینکه اگه منظورتون نوشتن یه برنامه کلاینت/سرور در سطح TCP/IP هستش ، winsock هم گزینه خیلی خوبی هستش - هم امکان استفاده از اکتیوایکسش هست و هم امکان استفاده از ای پی آی هاش وجود داره.

Abbas Arizi
جمعه 08 اسفند 1382, 18:05 عصر
به نظر من بهتره از اسمبلیهای همین کد #C که داری استفاده کنی. کد خیلی خوب و جامعیه.

sh
جمعه 08 اسفند 1382, 18:07 عصر
سلام

دستت درد نکنه راستی کلا چه فرقی بین استفاده از این دی ال ال و تابه RAS و Winsock هست وین سوک که تاجائی که من میدونم در ارتباط با شبکه ها و کنترل پورتها هست میشه یکم مسئله از حیث تفاوت دقیق مطرح کنید

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

Farhad.B.S
شنبه 09 اسفند 1382, 19:00 عصر
RAS یا Remote Access Service یه سرویس هستش که شامل دو بخش کلاینت و سرور میشه ، شما میتونید به عنوان یه RAS Client به یه RAS Server وصل بشید و از امکانات اون استفاده کنید ، به عنوان مثال وصل شدن شما به ISP تون و استفاده از امکانات اون (دریافت اطلاعات و مرور صفحات وب و...) معمولا از طریق همین سرویس هستش.
Winsock هم ای پی آی های در سطح ویندوز هست که از اون برای ارسال/دریافت اطلاعات استفاده میشه و البته در سطح TCP/IP ، یعنی شما باید اول یه ارتباط از لحاظ فیزیکی با یه جایی داشته باشی (به عنوان مثال استفاده با از RAS برای وصل شدن به یه آی اس پی) و بعد با استفاده از توابع Winsock به ادامه ارتباط بپردازی.

sh
شنبه 09 اسفند 1382, 20:13 عصر
سلام

من مشکلم با همون برنامه ای که گذاشتم تقریبا حل شده ولی هنوز اندر کف استفاده از تابع API مربوط به RAS توی دات نت هستم

HAMIDyekta
دوشنبه 06 شهریور 1385, 14:57 عصر
این فایل که خرابه

shadishadishadi
یک شنبه 03 دی 1385, 01:08 صبح
سلام
خسته نباشین
با api جطوری میشه برنامه ای که تحت داس اجرا میشه رو اجرا کرد؟

mostafa20
سه شنبه 08 خرداد 1386, 09:14 صبح
با سلام
من تازه به این جمع اضافه شدم امیدوارم که بتونم کمک کنم
من با Rasapi32.dll کار کردم و تونستم باهاش یه dialup بسازم
اگه دوست دارین واستون توضیح بدم که چه جوریه ولی خودم تو بعضی قسمت های بعد از اتصال مشکل بر خوردم کسی هست که چیزی بدونه
مثلا System Tray پس از اتصال و ConnectionStatus

PC2st
پنج شنبه 17 خرداد 1386, 22:15 عصر
مثلا System Tray پس از اتصال و ConnectionStatus
بصورت دستی، system try براش بگذار و Connection State هم با تابع InternetGetConnectedState از فایل wininet.dll قابل دسترسه.

VisualStudio
سه شنبه 13 شهریور 1386, 12:15 عصر
این هم یک نمونه کد فراخوانی توابع در VB.NET مرجع خود MSDN
امیدوارم این سورس کمکتون کنه و مفید واقع بشه

majidcomputer
یک شنبه 11 فروردین 1387, 11:09 صبح
از مطلبتون خیلی استفاده کردم

ممنون

sooran
پنج شنبه 16 خرداد 1387, 12:32 عصر
سلام من میخواستم بدونم چطوری از توابع api برای پیدا کردن پرینترهای متصل به شبکه در #c استفاده کنم

firoozi90
دوشنبه 16 مرداد 1391, 12:41 عصر
System.Runtime.InteropServices

کسی می تونه در مورد این فضای نام توضیح کامل بده؟