طریقه ساخت dll در C++

the_king

مدیرکل انجمن
با سلام مجدد و تشکر از جناب آقای علی سعید
مهندس آیا امکان برگرداندن دو مقدار و یا بیشتر در یک فایل dll وجود دارد؟
چگونه و به چه ترتیب متغیرها باز میگردن؟
مقدار بازگشتی تابع همیشه یک مقدار بازگشتی ئه، نه چند مقدار بازگشتی. اما مقدار بازگشتی می تونه آدرس یک موقعیت از حافظه باشه که در اون موقعیت چند مقدار قرار بگیره،
مثلا یک آرایه باشه، یک struct باشه و ... در زبانهایی مثل C++ / C که مدیریت حافظه در دست برنامه نویسه، خیلی راحت میشه از یک تابع چند مقدار دریافت کرد، اما
به این نکته توجه کنید که اگر دارید DLL می سازید :
اولا زبانی که از این DLL استفاده می کنه مهمه، روش های برگرداندن چندین مقدار از تابع زیاده اما همه زبان ها اشاره گر و مدیریت حافظه انعطاف پذیر ندارند و در
بعضی زبان ها نمیشه از هر روشی استفاده کرد.
ثانیا FreeLibrary حافظه ای که در DLL استفاده میشه آزاد می کنه، اگر هنوز به مقداری که حافظه اش در DLL تخصیص داده شده نیاز دارید FreeLibrary رو اونجا اجرا نکنید.
جایی اجراش کنید که دیگه به مقدار ها نیازی نیست.

روش اول
در داخل تابع :
1) در داخل تابع یک حافظه ای به اندازه مورد نیاز ایجاد کنید.
2) مقدار های دلخواه رو در اون حافظه قرار دهید.
3) آدرس اون حافظه رو از تابع برگردونید.
در جایی که تابع رو فراخوانی کرده اید :
1) آدرس حافظه رو از تابع تحویل بگیرید.
2) از مقادیری که در اون آدرس حافظه هست هر طور که مایلید استفاده کنید.
3) حافظه مورد نظر رو آزاد کنید.
کد:
#include <iostream>
#include <conio.h>

using namespace std;

int *MyFunction()
{
    int *p = new int[3];
    p[0] = 123;
    p[1] = 456;
    p[2] = 789;
    return p;
}

int main()
{
    int *x = MyFunction();
    int a = x[0];
    int b = x[1];
    int c = x[2];
    cout << a << endl << b << endl << c << endl;
    delete[] x;
    getch();
    return 0;
}

روش دوم
در داخل تابع :
1) آدرس حافظه ای رو به عنوان محل قرار گیری مقادیر دریافت کنید (پارامتر ورودی)
2) مقادیر رو در اون حافظه ثبت کنید.
در جایی که تابع رو فراخوانی کرده اید :
1) آدرس حافظه ای رو که قرار است مقادیر در آن ثبت شوند به عنوان پارامتر ورودی به تابع ارسال کنید.
2) از مقادیری که در اون آدرس حافظه هست هر طور که مایلید استفاده کنید.

کد:
#include <iostream>
#include <conio.h>

using namespace std;

void MyFunction(int *p)
{
    p[0] = 123;
    p[1] = 456;
    p[2] = 789;
}

int main()
{
    int x[3];
    MyFunction(x);
    cout << x[0] << endl << x[1] << endl << x[2] << endl;
    getch();
    return 0;
}

ضمنا یک سوال دیگه داشتم و اینکه ی فایل dll که حدود 120 ورودی میتواند دریافت نوشتم و از یک نرم افزار مونیتورینگ صنعتی فرا خوندمش، با نوشتن یک عدد ثابت dll به خوبی کار میکنه، اون عدد ثابت شماره کانال یک A/D صنعتی هست، اما وقتی
بیشتر از یک عدد به عنوان انتخاب کانال ورودی میفرستم یک عدم هماهنگی بین dll و نرم افزار مونیتورینگ به وجود میاد و فقط یکی از مقادیر خروجی و اونم اولین مقدار در تمام متغییرها قرار میگره، حال آنکه با انتخاب کانال می بایست مقدار دیجیتال مربوط
به هر کانال در متغییر مربوطه قرار بگیره، نرم افزار مونیتورینگ کدهای مخصوص خودش را داره و اسم زبانش cicode می باشد، به انعطاف پذیری زبان نرم افزار مطمین نیستم و از طرفی به سنکرون بودن و یا عدم سرعت پاسخگویی کافی dll هم شک دارم
از لحاظ برنامه نویسی c++ چه کاری میتوان برا سنکرون سازی انجام داد؟
با تشکر از جنابعالی.
ممکنه به سنکرون بودن و نبودن ربطی نداشته باشه، برخی از سخت افزار ها دو تا پورت خاص مثلا X و Y دارند، در X آدرس مورد نظر m رو قرار می دهید (مرحله تنظیم آدرس)
و در ادامه در Y مقدار v رو قرار می دهید (مقدار v در آدرس m سخت افزار قرار می گیره) یا از Y مقدار v رو می خونید (مقدار v از آدرس m سخت افزار خونده میشه)
حالا اگر زمانی که بین قرار دادن مقدار در X و Y مکث می کنید کم باشه، سخت افزار مورد نظر فرصت تنظیم آدرس روی m رو نداره و عملیات موفقیت آمیز نمیشه.
 

ariyan321

New Member
سلام، آقای مهندس علی سعید.
جناب مهندس، بنده تو سنکرون کردن توابع داخل فایل inpout32.dll با برنامه خودم مشکل دارم به این نتیجه رسیدم که باید خودم ارتباط برنامه را مستقیما با پورت برقرار کنم، آیا میتونید در این زمینه به بنده کمک کنید، اطلاعاتی که به دست آوردم اینکه دسترسی به ring0 مستقیما در winXP امکان پذیر نیست، برای این منظور باید از سطح kernel استفاده بشه، بنده از توابع داخل kernel سر در نیاوردم، میشه کمک بفرمایید.
ی سوال دیگه، آیا دسترسی به پورت و ایجاد dll با استفاده از دستورات اسمبلی ممکن هست، منظورم دسترسی مستقیم هست، تا دیگه احتیاج به سطح کرنل نباشه؟
لطفا کمک بفرمایید.
 

the_king

مدیرکل انجمن
سلام، آقای مهندس علی سعید.
جناب مهندس، بنده تو سنکرون کردن توابع داخل فایل inpout32.dll با برنامه خودم مشکل دارم به این نتیجه رسیدم که باید خودم ارتباط برنامه را مستقیما با پورت برقرار کنم، آیا میتونید در این زمینه به بنده کمک کنید، اطلاعاتی که به دست آوردم اینکه دسترسی به ring0 مستقیما در winXP امکان پذیر نیست، برای این منظور باید از سطح kernel استفاده بشه، بنده از توابع داخل kernel سر در نیاوردم، میشه کمک بفرمایید.
ی سوال دیگه، آیا دسترسی به پورت و ایجاد dll با استفاده از دستورات اسمبلی ممکن هست، منظورم دسترسی مستقیم هست، تا دیگه احتیاج به سطح کرنل نباشه؟
لطفا کمک بفرمایید.
شما در استفاده از inpout32.dll به مشکل برخوردید، کتابخانه ناشناخته و تست نشده ای هم نیست که ازش ایراد بگیریم.
حالا یا درست کد نویسی نمی کنید یا کاری که با سخت افزار انجام می دهید روال خاصی داره که رعایت نکرده اید.
مشکل کد شما هر چی که هست مربوط به کد و روالی است که بکار می برید، ایراد این dll نیست که بخواهید خودتان نمونه اش را بنویسید.
در هر صورت این جور dll ها رو درایور نویس ها طراحی می کنند، من و شما هم درایور بنویسیم نهایتا چیزی شبیه به همین کتابخانه میشه.
ایراد کار شما مربوط به نوع ارتباط تون با پورت نیست، ایراد کد تون رو پیدا کنید.

فرقی نمی کنه که زبانی که باهاش با پورت ها ارتباط برقرار می کنید اسمبلی، #C یا ++C باشه، فرقی نمی کنه که کد اش رو شما نوشته باشید یا شخص دیگری.
فرقی نمی کنه که DLL اش رو شما بسازید یا از یک DLL آماده استفاده کنید. به هر حال نهایتا یکسری کد زبان ماشین اجرا می شه، چون ماشین (پردازنده) هیچ
زبانی بجز زبان خودش رو نمی شناسه. عدم دسترسی به پورت یک محدودیت سخت افزاری و جزئی از حلقه حفاظتی پردازنده است.
چیزی نیست که بخواهید با تغییر زبان برنامه نویسی دورش بزنید. درایور از عهده اینکار بر میاد چون درایور در ring0 (همان Kernel Mode) اجرا میشه.
در خود برنامه شما مستقیما اجرا نمیشه چون برنامه شما همیشه در ring3 (همان User Mode) اجرا میشه.
 

ariyan321

New Member
با تشکر از راهنمایی جنابعالی، اما خود نویسنده dll و همکارش که برای 64 بیت اون را گسترش داده هم گفتند که استفاده از این dll اونم با سرعت بالا مناسب نیست، و بهتر است خودت تو خود برنامه اصلی این کار را بکنی!!!!!!!
من در استفاده از این dll هر آنچه از دستورات شرطی بود استفاده کردم، حتی با فرض اینکه بافرش پر باشد هم قبل از اجرای دستورات مختلف اون را سعی میکردم خالی کنم، ولی هربار همون مشکل قبل که عدم هماهنگی وجود داشت و مشکلات دیگر هم اضافه می شد، ضمنا، اضافه کنم که تو استفاده از این dll مقداری که از پورت برمیگرده، در بازه هایی به صورت علامت دار منظور میشه و همین تا مدتی من را به اشتباه انداخته بود، در کل میگم که مشکلاتی این dll داره و برای مقاصد آموزشی نوشته شده است...
این برداشت من بوده بعد از حدود 3 ماه استفاده دائمی از اون، در مورد سطح کرنل و نوشتن درایور هم دوست دارم امتحانش کنم و نتیجه رو هم خدمتتان اعلام خواهم کرد، کمک بفرمایید تا زودتر به نتیجه برسم، از کجا شروع کنم؟
 

the_king

مدیرکل انجمن
با تشکر از راهنمایی جنابعالی، اما خود نویسنده dll و همکارش که برای 64 بیت اون را گسترش داده هم گفتند که استفاده از این dll اونم با سرعت بالا مناسب نیست، و بهتر است خودت تو خود برنامه اصلی این کار را بکنی!!!!!!!
من در استفاده از این dll هر آنچه از دستورات شرطی بود استفاده کردم، حتی با فرض اینکه بافرش پر باشد هم قبل از اجرای دستورات مختلف اون را سعی میکردم خالی کنم، ولی هربار همون مشکل قبل که عدم هماهنگی وجود داشت و مشکلات دیگر هم اضافه می شد، ضمنا، اضافه کنم که تو استفاده از این dll مقداری که از پورت برمیگرده، در بازه هایی به صورت علامت دار منظور میشه و همین تا مدتی من را به اشتباه انداخته بود، در کل میگم که مشکلاتی این dll داره و برای مقاصد آموزشی نوشته شده است...
این برداشت من بوده بعد از حدود 3 ماه استفاده دائمی از اون، در مورد سطح کرنل و نوشتن درایور هم دوست دارم امتحانش کنم و نتیجه رو هم خدمتتان اعلام خواهم کرد، کمک بفرمایید تا زودتر به نتیجه برسم، از کجا شروع کنم؟
روی مشکلاتی که در برنامه تان دارید فکر کنید، روی استفاده ای که از inpout32.dll می کنید هم فکر کنید. inpout32.dll صرفا کاری رو انجام میده که شما دستورش رو می دهید،
حالا یا مقداری رو از پورت می خونه یا داخلش می نویسه. سر خود که اینکار رو نمی کنه. شما هر وقت فراخوانی اش کنید کار می کنه. اگه عدم هماهنگی ای باشه مربوط به کد شما است.
نهایت ایراد inpout32.dll این می تونه باشه که کند باشه. اگه کد شما درست بود، برنامه شما هم کاملا درست کار می کرد، صرفا کند می بود.

کدی که استفاده می کنید ایراد داره، حتی اگه برایش درایور هم بنویسید چون ایراد داره کار نمی کنه، حتی بدتر هم میشه، چرا؟
چون اگه کد ایراد دار در درایور باشه احتمال کرش کردن سیستم و صفحه آبی و ... هست.
اینا ایراد inpout32.dll هم نمی تونه باشه، چرا؟ چون اگه به قول شما مشکل عدم هماهنگی است، یا به دلیل دسترسی همزمان و عدم هماهنگ
خود کد شما به پورت ئه (که ربطی به inpout32.dll نداره) یا نتیجه سرعت بیش از حد کد شما در مقابل سرعت پاسخگویی سخت افزار ئه که فقط
زمانی این حالت پیش میاد که سرعت دسترسی کد شما به پورت بالا است. اگه inpout32.dll به اندازه کافی کند بود که این مشکل پیش نمی اومد.

قطعا اگه تمامی روال دسترسی به پورت رو با درایور نویسی یکجا اجرا کنید سرعت بیشتر میشه اما عدم هماهنگی به بیش از حد بودن سرعت بستگی داره،
اگر هماهنگ نیست باید سرعت رو کاهش بدهید، نه اینکه بخواهید سریعتر اش کنید. مگر مشکل کد شما الان کندی اجرا شه؟ اول کدی بنویسید که
بدون ایراد اجرا بشه، بعد به فکر بهینه سازی اش باشید. درایور نویسی کار راحتی نیست، سراغش نروید مگر اینکه دلیل قانع کننده ای برایش باشه،
ایراد کار شما مرتبط با کندی اجرا یا اهداف آموزشی inpout32.dll نیست، زبان بیسیک هم اهداف آموزشی داشت.

یک نگاهی به این مطالب بندازید :
Driver Development Part 1: Introduction to Drivers

Getting Started Writing Windows Drivers
 

ariyan321

New Member
بنده یک کارت 32 کاناله دارم که باید با سرعت زیاد این کانالها را بخونم، اینکه میفرمایید اول یک برنامه بنویسید و از عملکرد اون اطمینان حاصل کنید، من برنامه را نوشتم و اونم نه برای 32 کانال، بلکه برای 1 کانال، و بسیار خوب جواب میداد، بماند که بعضی اوقات اطلاعات را علامت دار برمیگرداند، اما به هر ترتیب، برنامه ای نوشته شد که علامت از بین برود، به هر حال در خواندن 32 کانال و بیشتر کند عمل میکند، بنده اومدم این inpout32.dll را در یک فایل Dll که خودم نوشتم فراخوندم، فایل هم چیز خاصی نداشت، فقط آدرس پورت، بعلاوه شماره کانال را مشخص میکرد و منتظر میموند تا اطلاعات برگده و اونم بزار تو خروجی dll ، اما وقتی فقط برای خوندن دو کانال اقدام میکنم، مقدار کانال اول را در متغییر دوم میزاره و دوم را در اول!!!!!!!!!!!
هر چقدر فکر کردم که چه مشکلی میتونه داشته باشه، نتونستم عیبی از برنامه خودم بگیرم!!! چون خیلی اصلاحش کردم، انواع دستورات شرطی را گذاشتم تا تابع را خوب منتظر بزارم تا کارت کارش را درست و کامل انجام بده، اما به این نتیجه رسیدم مشکل از inpout32.dll هست! حتی برنامه را بارها دیباگ کردم، در حین دیباگ کردن، کاملا صحیح انجام میشه، اما با سرعت که اجرا میشه، دیتاها جابه جا میشه و کانالها عقب میفتن و مقادیر مثلا کانال 5 در 4 قرار میگیره!!!
عیب از کجا میتونه باشه وقتی تو دیباگ کردن کاملا صحیح عمل میکنه؟!!!!!!
 

the_king

مدیرکل انجمن
بنده یک کارت 32 کاناله دارم که باید با سرعت زیاد این کانالها را بخونم، اینکه میفرمایید اول یک برنامه بنویسید و از عملکرد اون اطمینان حاصل کنید، من برنامه را نوشتم و اونم نه برای 32 کانال، بلکه برای 1 کانال، و بسیار خوب جواب میداد، بماند که بعضی اوقات اطلاعات را علامت دار برمیگرداند، اما به هر ترتیب، برنامه ای نوشته شد که علامت از بین برود، به هر حال در خواندن 32 کانال و بیشتر کند عمل میکند، بنده اومدم این inpout32.dll را در یک فایل Dll که خودم نوشتم فراخوندم، فایل هم چیز خاصی نداشت، فقط آدرس پورت، بعلاوه شماره کانال را مشخص میکرد و منتظر میموند تا اطلاعات برگده و اونم بزار تو خروجی dll ، اما وقتی فقط برای خوندن دو کانال اقدام میکنم، مقدار کانال اول را در متغییر دوم میزاره و دوم را در اول!!!!!!!!!!!
هر چقدر فکر کردم که چه مشکلی میتونه داشته باشه، نتونستم عیبی از برنامه خودم بگیرم!!! چون خیلی اصلاحش کردم، انواع دستورات شرطی را گذاشتم تا تابع را خوب منتظر بزارم تا کارت کارش را درست و کامل انجام بده، اما به این نتیجه رسیدم مشکل از inpout32.dll هست! حتی برنامه را بارها دیباگ کردم، در حین دیباگ کردن، کاملا صحیح انجام میشه، اما با سرعت که اجرا میشه، دیتاها جابه جا میشه و کانالها عقب میفتن و مقادیر مثلا کانال 5 در 4 قرار میگیره!!!
عیب از کجا میتونه باشه وقتی تو دیباگ کردن کاملا صحیح عمل میکنه؟!!!!!!

پردازنده کامپپیوتر شما یک ساعت داخلی داره با یک نرخ مشخص پالس در ثانیه، مثلا 2 میلیارد پالس در ثانیه.
سخت افزاری که باهاش کار می کنید هم یک ساعت داخلی داره با یک نرخ مشخص تعداد پالس در ثانیه، مثلا 340 میلیون پالس در ثانیه.
این دو (چه در پردازنده و چه در اون سخت افزار تون) برای هر عملیات مرتبط با پورت حداقل به اندازه یک پالس زمان لازم دارند که البته معمولا
کار با پورت ورودی / خروجی بیشتر از یک پالس زمان لازم داره و چندین پالس طول می کشه.

اگه این زمان لازم برای پاسخگویی رعایت نشه و در زمانی سریعتر از ظرفیت سخت افزاری به پورت ها رجوع بشه،
داده ای از پورت دریافت میشه که مرتبط با مقدار ارسال شده چند دفعه قبلتر است، نه آخرین داده ارسال شده.

از اونجایی که کمتر سخت افزاری و کمتر پورت ای سرعت ساعت داخلی پردازنده کامپیوتر تون رو داره،
کامپیوتر بعد از ارسال هر داده ای رو پورت برای دریافت نتیجه از سخت افزار مقابل باید چندین پالس مکث کنه
تا سخت افزار مقابل که کند تره فرصت برای پاسخگویی داشته باشه. مقدار تعداد پالس هایی که باید صبر کنه
هم بستگی به ساعت داخلی شون و مشخصات سخت افزاری داره که باهاش ارتباط برقرار می کنید.
این یک چیزی شبیه به Over Clocking ئه، یک حلقه وقت تلف کن مثل کد زیر ایجاد کنید و مقدار n یا حتی اون 10000 رو اونطور تنظیم کنید
که هم تا حد امکان کم باشه (حلقه سریعتر تموم بشه) و هم اونقدر کم نباشه که داده اشتباهی دریافت بشه و
بعد هم که مقدار مناسب بدست آمد یک ضریب اطمینان، مثلا 1.2 برابر اش کنید تا همیشه به قدر کافی کند باشه :
کد:
int n = 10;
for (int i = 0; i < n; i++)
	for (j = 0; j < 10000; j++);
 

جدیدترین ارسال ها

بالا