نحوه ی ساخت dll در سی شارپ برای زبان های غیر دات نت

the_king

مدیرکل انجمن
آها ممنون استاد علی
ببینید من کلا میخوام یه dll بسازم که مثلا کنترلی مثل button داشته باشه و از اتوپلی فراخونی اش کنم . چون از پلاگین هایی که برای اتوپلی میسازیم ، مدیریت رویدادش را باید از api ویندوز انجام داد و هم سخت تره و هم خیلی از رویدادها را ممکنه نداشته باشه ، تصمیم گرفتم که رویدادهای کنترل را توی همین dll هندل کنم و کدهای نوشته شده در اتوپلی را از اینجا و توسط nlua اجرا کنم
دارد لقمه رو دور دهن میچرخونید. شما باید مستندات پلاگین های اتوپلی رو مطالعه کنید و بر اساس ساختار مشخص اش برای اتوپلی پلاگین بنویسید، چه سخت و چه آسون از کاری که الان میخواهید بکنید هم منطقی تره و هم سر راست تر. وقتی هدف نهایی این باشه که کد های اتوپلی اجرا بشه باید برای اتوپلی پلاگین بنویسید، نه اینکه چند تا کتابخانه و پلتفرم جدا رو بزور و با دردسر بهم وصل کنید که نهایتا باز بخواهید کد های اتوپلی رو اجرا کنه. nlua و API و NET. همه رو با هم قاطی کنید که نهایتش باز کد اتوپلی رو اجرا کنه؟
یه دوستی بنام آقا محسن دارم که میگه شبیه همین کار را (اجرای کدهای نوشته شده در اتوپلی) در dll ای که در pure basic نوشت ، انجام میده . پس اون چی کار میکنه به نظرتون؟
نظری ندارم.
شرایط من در سی شارپ و شرایط ایشون در pure basic انگار برابر هم هست دیگه . درسته؟
قاعدتا برابر نیست، شاید شبیه هم باشه اما دو تا کامپایلر کاملا متفاوته با خصوصیات و امکانات ذاتی متفاوت.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد استاد علی
ممنون
دوستم آقا محسن گفتن لوا قابلیت ثبت کردن توابع و ... را در خودش (در اینجا lua5.1.dll) داره . گفتن موتور اتوپلی وظیفه ی ثبت توابع اتوپلی را در لوا داره . یعنی فایل های lua5.1.dll ای که در پروژه های اتوپلی هست ، حاوی توابع ثبت شده ی اتوپلی هست (و احتمالا پلاگین هایی هم که در اتوپلی فعال میشن ، حاوی توابع اون ها هم باید باشه)
بعد کلاسی دادن که حاوی توابع فراخونی کننده ی C Api در لوا :
Lua 5.1 Reference Manual - contents
هست که این کلاس را پیوست کردم
البته با nlua هم میشه بجای این کلاس (برای تست کد زیر) استفاده کرد

چیزی که متوجه شدم اینه که تابعی که در لوا ثبت میشه ، فقط برای همون شی ای که ثبت اش کرد انگار در دسترس هه . برای بقیه ی اشیاء انگار در دسترس نیست . کد زیر را ببینین :


کد:
        private void button3_Click(object sender, EventArgs e)
        {
            IntPtr luaState = LuaCSharp.lua_open();
            LuaCSharp.lua_register(luaState, "LuaFunc", (LuaCSharp.LuaFunction)FormTest2.LuaFunc);
            int errCheck = LuaCSharp.luaL_dostring(luaState, "LuaFunc();");
            MessageBox.Show(errCheck.ToString());
            LuaCSharp.lua_close(luaState);

            /////////////////////////////////////
           
            IntPtr luaState_2 = LuaCSharp.lua_open();
            int errCheck_2 = LuaCSharp.luaL_dostring(luaState_2, "LuaFunc();");
            MessageBox.Show(errCheck_2.ToString(), "luaState_2");
            LuaCSharp.lua_close(luaState_2);
        }

        public static int LuaFunc(IntPtr luaState)
        {
            MessageBox.Show("Test");
            return 1;
        }

تابع LuaFunc برای ثبت در لوا ، نوشته شد
اولین بار لوا را باز و در شی luaState ذخیره کردم . با همین شی ، تابع LuaFunc را در لوا ذخیره و بعدش با luaL_dostring اجرا کردم که تابع با موفقیت اجرا شد (بنابراین پیام دیالوگ مسیج رشته ی "Test" را داد)
اما بعد که یه شی دیگه از لوا ساختم و در luaState_2 ذخیره کردم (این بار دیگه تابع را ثبت نکردم چون در کد قبلی ثبت شده بود) ، دیگه تابع LuaFunc اجرا نشد و تابع luaL_dostring مقدار غیر از صفر (که به معنای ارور هست) را برگردوند
این نشون میده بصورت شی گرا و صرفا در همون لحظه اون تابع در لوا ثبت میشه و بصورت استاتیک ثبت نمیشه . اگه این طوری باشه ، کارایی نداره در جاهای دیگه و در دسترس قرار نمیگیره .
مگه روش ثبت یا روش فراخونی دیگه ای وجود داره؟
 

پیوست ها

  • Lua.rar
    3.9 کیلوبایت · بازدیدها: 3

the_king

مدیرکل انجمن
مگه روش ثبت یا روش فراخونی دیگه ای وجود داره؟
من هنوز مقصود و هدف شما رو متوجه نشدم، اما اینکه یک مکانیسمی رو هی Open کنید و بعد Close کنید و بعد مجددا یکی دیگه Open کنید و باز Close کنید همونقدر دلیل منطقی لازم داره که اینکه بیایید بجایش یک شیء ای رو ابتدای برنامه Open کنید و تا وقتی برنامه در حال اجرا است از همون یک نمونه استفاده کنید و نهایتا موقع خروج از برنامه Close کنید. در ضمن وقتی شما یک فرم رو باز می کنید و میبندید و مجددا باز می کنید یکسری کد که تعاریف و مشخصات فرم هستند بصورت تکراری مجددا اجرا می شوند، مثل همون Form1_Load و InitializeComponent . بنابر این خیلی واقعه ناگواری نیست که بیایید برای Register کردن اون توابع یک متد اختصاصی بسازید و بعد از Open کردن یکبار اون متد رو فرخوانی کنید تا تمامی توابع تعریف شوند.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
من هنوز مقصود و هدف شما رو متوجه نشدم، اما اینکه یک مکانیسمی رو هی Open کنید و بعد Close کنید و بعد مجددا یکی دیگه Open کنید و باز Close کنید همونقدر دلیل منطقی لازم داره که اینکه بیایید بجایش یک شیء ای رو ابتدای برنامه Open کنید و تا وقتی برنامه در حال اجرا است از همون یک نمونه استفاده کنید و نهایتا موقع خروج از برنامه Close کنید. در ضمن وقتی شما یک فرم رو باز می کنید و میبندید و مجددا باز می کنید یکسری کد که تعاریف و مشخصات فرم هستند بصورت تکراری مجددا اجرا می شوند، مثل همون Form1_Load و InitializeComponent . بنابر این خیلی واقعه ناگواری نیست که بیایید برای Register کردن اون توابع یک متد اختصاصی بسازید و بعد از Open کردن یکبار اون متد رو فرخوانی کنید تا تمامی توابع تعریف شوند.

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
کلا با چه روشی میشه تابع ثبت شده در لوا را توسط هر شی (خروجی متد lua_open) فراخونی کرد؟ یعنی تابع ثبت شده ، بصورت استاتیک در دسترس باشه و وابسته به شی خاصی نباشه؟

نمیشه که وابسته به همون شی باشه وگرنه اصلا چیزی بنام ثبت کردن ، معنا نداره که استفاده ی مجدد بشه
 

the_king

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نمیدونم، وقتی نه کاری با لوا داشتم و نه nlua، از کجا باید بدونم؟ قصد دارید کار خاصی رو انجام بدید که مربوط به یک کتابخانه خاص ئه و نمی دونید عملی هست یا نه، طبعا باید وقت صرف کنید و مستنداتش رو بخونید و در موردش تحقیق کنید.توقع که ندارید من یا شخص دیگری برای کاری که شما می خواهید انجام بدید بجاتون وقت صرف مطالعه و تحقیق کنه.

سلام
ممنون
نه استاد علی این چه حرفی هه؟
فقط گفتم بگم اگه بلد بودید (مثل مباحث قبلی اتوپلی که کمک های بسیار بزرگی کردید) ، راهنمایی کنید . نه اینکه وقت جدیدی بذارید و ...
البته من منابع را پیگیری کردم مثل این :

Lua and C

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

-------------------------------------

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد علی ، میشه یه message یا همون notify (بصورت شخصی سازی شده) به یه پنجره (پنجره ی اصلی اتوپلی که هندل اش را داریم) فرستاد؟
مثلا میخوام وقتی روی دکمه کلیک شد (در سی شارپ) ، یه notify (شامل هندل اون کنترل و رشته ای به عنوان نام رویداد مثلا "Click") را به پنجره ی اتوپلی بفرسته . این شدنی هه؟
تا اینکه در اتوپلی با api ویندوز ، این پیام و رویداد را مدیریت کنم
 

the_king

مدیرکل انجمن
سلامی مجدد
استاد علی ، میشه یه message یا همون notify (بصورت شخصی سازی شده) به یه پنجره (پنجره ی اصلی اتوپلی که هندل اش را داریم) فرستاد؟
مثلا میخوام وقتی روی دکمه کلیک شد (در سی شارپ) ، یه notify (شامل هندل اون کنترل و رشته ای به عنوان نام رویداد مثلا "Click") را به پنجره ی اتوپلی بفرسته . این شدنی هه؟
تا اینکه در اتوپلی با api ویندوز ، این پیام و رویداد را مدیریت کنم
بحث توابع API و ارسال و دریافت پیام ئه دیگه. در ویندوز بصورت ذاتی بین پنجره ها Message رد و بدل میشه که چند تا متد API داره با کمی کارکرد متفاوت.
هر پیامی یک گیرنده داره که Handle یک پنجره است، یک کد پیام داره که یک مقدار عددی ئه، دو تا پارامتر wParam و lParam داره که برای هر پیامی معنی و کاربرد خاص خودش رو داره و یک مقدار بازگشتی متد داره برای پیام هایی که باید جوابی داشته باشند.

SendMessage پیامی رو ارسال می کنه که باید جوابی داشته باشه که تا دریافت نکنه منتظر میمونه.
SendMessageTimeout پیامی رو ارسال می کنه که باید جوابی داشته باشه ولی صرفا انتظار تا یک مدت زمانی مشخص که با Timeout دیگه از انتظار پشیمون میشه و میره سراغ اجرای بقیه کد ها.
PostMessage پیامی رو ارسال می کنه که برایش جوابی لازم نیست و تا پیام ارسال شد، بدون انتظار کار تمومه و اجرای کد های بعدی رو ادامه میده.
SendNotifyMessage ترکیب SendMessage و PostMessage ئه، بدین ترتیب که اگر پیام داخل نخی رد و بدل بشه منتظر پاسخ میمونه و اگر پیام از یک نخ به نخ دیگه ارسال میشه منتظر پاسخ نمیمونه.
SendMessageCallback پیامی رو ارسال می کنه که نیاز به پاسخ داره ولی تمایلی به انتظار برای پاسخ نداره و یک متد Callback برای این منظور معرفی کرده که هر وقت پاسخ داده شد اون متد فراخوانی بشه.
اگر میخواهید پیامی ایجاد کنید که اختصاصی باشه باید از محدوده کد پیام های 0x8000 الی 0xBFFF استفاده کنید تا با پیام های شناخته شده تداخلی نداشته باشه. برای ارسال مقادیر از هر نوع داده ای دو تا پارامتر wParam و lParam وجود داره که یک آدرس حافظه Unmanaged رو داخلشون قرار بدهید تا دریافت کننده پیام بتونه داده رو از اون آدرس بخونه. یا داخل lParam و wParam به دلخواه یک مقدار عددی صحیح یا یک کد ارسال کنید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اگر میخواهید پیامی ایجاد کنید که اختصاصی باشه باید از محدوده کد پیام های 0x8000 الی 0xBFFF استفاده کنید تا با پیام های شناخته شده تداخلی نداشته باشه. برای ارسال مقادیر از هر نوع داده ای دو تا پارامتر wParam و lParam وجود داره که یک آدرس حافظه Unmanaged رو داخلشون قرار بدهید تا دریافت کننده پیام بتونه داده رو از اون آدرس بخونه. یا داخل lParam و wParam به دلخواه یک مقدار عددی صحیح یا یک کد ارسال کنید.

ممنون استاد علی
از توضیحاتی که قبل از این نقل قول گفتید هم بسیار ممنونم
خط اول این رو من متوجه نشدم . یعنی چی محدوده کد پیام باید بین 0x8000 الی 0xBFFF باشه؟
بعد اینکه اگه بخوام از رشته برای ارسال پیام استفاده کنم (بجز روش آدرس حافظه که برای wParam و lParam گفتید) ، از تابع RegisterWindowMessage میتونم استفاده کنم؟ :

RegisterWindowMessage function (Windows)
 

the_king

مدیرکل انجمن
ممنون استاد علی
از توضیحاتی که قبل از این نقل قول گفتید هم بسیار ممنونم
خط اول این رو من متوجه نشدم . یعنی چی محدوده کد پیام باید بین 0x8000 الی 0xBFFF باشه؟

پیام کد داره، شماره داره، مثلا WM_SIZE که مقدارش 5 ئه. برای پیام تون باید یک کد انتخاب کنید. شما وقتی پیامی به یک پنجره می فرستید این کد ارسال میشه، در System.Windows.Forms.Message همون Msg ئه. شما که نمی خواهید پیام تون کدی داشته باشه که کد یک رخداد عادی پنجره مثل جابجایی ماوس باشه و اشتباه گرفته بشه و تداخل پیش بیاد و کاری انجام بده که ربطی به کارکرد پیام شما نداره. باید کدی رو انتخاب کنید که در محدوده کد های سفارشی ارتباط بین برنامه ای باشه.
بعد اینکه اگه بخوام از رشته برای ارسال پیام استفاده کنم (بجز روش آدرس حافظه که برای wParam و lParam گفتید) ، از تابع RegisterWindowMessage میتونم استفاده کنم؟ :
RegisterWindowMessage function (Windows)
بجز نداره، RegisterWindowMessage نه پیام ارسال می کنه و نه برای wParam و lParam جایگزینی مشخص کرده و نه اصلا کاری به روال ارسال داره. برای کاربرد شما هم مورد استفاده ای نداره. کاربرد اش زمانی است که یکسری برنامه قاطی و پاتی قراره انواع پیام های زیادی رو با هم رد و بدل کنند که تصمیم گرفتن برای کد پیام منحصر بفرد که با هم اشتباه نشه براشون دشواره و برنامه نویس نگرانه که کدی که برای یک پیام انتخاب کرده در برنامه دیگری برای مقصود دیگری ثبت شده باشه. از اونجایی که انتخاب کد پیام در این شرایط دشوار میشه و نمی توانید روی یک کد مشخص برای پیام ها تصمیم بگیرید با این سیستم ثبت پیام RegisterWindowMessage می توانید یک نام ثبت کنید تا بخواهید سیستم بهتون برای اون نام پیام یک کد پیام تخصیص بده.
اما از اونجایی که ارتباط در برنامه شما صرفا بین دو پروسه است که با سایر برنامه ها پیام اختصاصی رد و بدل نمی کنند و کد هر دوشون رو هم خودتون می نویسید و هر دو هم آمادگی ارتباط با یک کد پیام از قبل تعریف شده رو دارند، دلیلی وجود نداره که نتوانید یک کد پیام خاص برای هر موردی انتخاب کنید و نیازی به RegisterWindowMessage داشته باشید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
پیام کد داره، شماره داره، مثلا WM_SIZE که مقدارش 5 ئه. برای پیام تون باید یک کد انتخاب کنید. شما وقتی پیامی به یک پنجره می فرستید این کد ارسال میشه، در System.Windows.Forms.Message همون Msg ئه. شما که نمی خواهید پیام تون کدی داشته باشه که کد یک رخداد عادی پنجره مثل جابجایی ماوس باشه و اشتباه گرفته بشه و تداخل پیش بیاد و کاری انجام بده که ربطی به کارکرد پیام شما نداره. باید کدی رو انتخاب کنید که در محدوده کد های سفارشی ارتباط بین برنامه ای باشه.

بجز نداره، RegisterWindowMessage نه پیام ارسال می کنه و نه برای wParam و lParam جایگزینی مشخص کرده و نه اصلا کاری به روال ارسال داره. برای کاربرد شما هم مورد استفاده ای نداره. کاربرد اش زمانی است که یکسری برنامه قاطی و پاتی قراره انواع پیام های زیادی رو با هم رد و بدل کنند که تصمیم گرفتن برای کد پیام منحصر بفرد که با هم اشتباه نشه براشون دشواره و برنامه نویس نگرانه که کدی که برای یک پیام انتخاب کرده در برنامه دیگری برای مقصود دیگری ثبت شده باشه. از اونجایی که انتخاب کد پیام در این شرایط دشوار میشه و نمی توانید روی یک کد مشخص برای پیام ها تصمیم بگیرید با این سیستم ثبت پیام RegisterWindowMessage می توانید یک نام ثبت کنید تا بخواهید سیستم بهتون برای اون نام پیام یک کد پیام تخصیص بده.
اما از اونجایی که ارتباط در برنامه شما صرفا بین دو پروسه است که با سایر برنامه ها پیام اختصاصی رد و بدل نمی کنند و کد هر دوشون رو هم خودتون می نویسید و هر دو هم آمادگی ارتباط با یک کد پیام از قبل تعریف شده رو دارند، دلیلی وجود نداره که نتوانید یک کد پیام خاص برای هر موردی انتخاب کنید و نیازی به RegisterWindowMessage داشته باشید.

ممنون استاد علی
پس Msg باید بین عددهای 32768 تا 49151 باشه . یعنی غیر از این اعداد باشه ، با کدهای جدول زیر که کدهای تعریف شده هستن ، تداخل بوجود میاره براش؟
بنابراین ، میتونم هر عددی بین این بازه ی عددی که گفتید ، برای آرگومان Msg بطور دلخواه مشخص کنم و نیازی نیست طبق جدول زیر ، کد بدم :

About Messages and Message Queues (Windows)

درسته؟
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد علی ، من توی سی شارپ اینو نوشتم (خروجی dll) :


کد:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RGiesecke.DllExport;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;

namespace control
{
    public class DllImportClass
    {

        [DllImport("user32.dll", EntryPoint = "SetParent")]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

    }

    public class button
    {
        private static IntPtr HandleMainWindow;

        [DllExport("CreateButton", CallingConvention = CallingConvention.StdCall)]
        public static int CreateButton(IntPtr handleMainWindow,string name, string text, int x, int y, int width, int height)
        {
            button.HandleMainWindow = handleMainWindow;
            Button btnNew = new Button();
            btnNew.Name = name;
            btnNew.Text = text;
            btnNew.Bounds = new Rectangle(new Point(x, y), new Size(width, height));
            btnNew.Click += new EventHandler(button.btnNew_Click);
           
            DllImportClass.SetParent(btnNew.Handle, handleMainWindow);
            return btnNew.Handle.ToInt32();
        }

        private static void btnNew_Click(object sender, EventArgs e)
        {
            Button btnNew = sender as Button;
            if (btnNew != null)
            {
                MessageBox.Show("prev");
                Message.Create(button.HandleMainWindow, 32800, btnNew.Handle, IntPtr.Zero);
                MessageBox.Show("next");
            }
           
        }

    }
}

و توی اتوپلی (با فعال کردن پلاگین MemoryEx) :
در رویداد On Show صفحه :

کد:
hdlMainWindows = Application.GetWndHandle();

hdlDll = Library.Load("Button.dll", false);
if (hdlDll ~= nil) then
btnHdl = hdlDll.CreateButton(hdlMainWindows, "button1", "button1", 120, 200, 85, 35);
result = Subclass.Create(hdlMainWindows, EventHandler);


hdlDll:Close_();
end

و در Global Function :

کد:
function EventHandler(hWnd, uMsg, wParam, lParam)
    if (uMsg == 32800) then
    Dialog.Message("Notice", "into Autopley Button Click", MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
   
    end
return Subclass.OldWinProc(hWnd, uMsg, wParam, lParam);
end

ولی کد داخل شرط تابع EventHandler در اتوپلی ، اجرا نمیشه! . کد MessageBox.Show در رویداد سی شارپ ، قبل و بعد از تابع Message.Create ، اجرا میشه . پس باید نتیجه گرفت که در سی شارپ مشکلی نباید باشه . درسته؟

در اتوپلی هم انگار نباید مشکلی در کد باشه!
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
با تابع api کار کردم درست شد . انگار تابع system.windows.forms.message.create و کلا این استراکچر ، فقط Message میسازه ولی نمیفرسته
ممنون استاد علی از راهنمایی تون

کدش این شد :


کد:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RGiesecke.DllExport;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;

namespace control
{
    public class DllImportClass
    {

        [DllImport("user32.dll", EntryPoint = "SetParent")]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", EntryPoint = "SendMessageA")]
        public static extern IntPtr SendMessageA(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

    }

    public class button
    {
        private static IntPtr HandleMainWindow;

        [DllExport("CreateButton", CallingConvention = CallingConvention.StdCall)]
        public static int CreateButton(IntPtr handleMainWindow,string name, string text, int x, int y, int width, int height)
        {
            button.HandleMainWindow = handleMainWindow;
            Button btnNew = new Button();
            btnNew.Name = name;
            btnNew.Text = text;
            btnNew.Bounds = new Rectangle(new Point(x, y), new Size(width, height));
            btnNew.Click += new EventHandler(button.btnNew_Click);
           
            DllImportClass.SetParent(btnNew.Handle, handleMainWindow);
            return btnNew.Handle.ToInt32();
        }

        private static void btnNew_Click(object sender, EventArgs e)
        {
            Button btnNew = sender as Button;
            if (btnNew != null)
            {
                DllImportClass.SendMessageA(button.HandleMainWindow, 32800, btnNew.Handle, IntPtr.Zero);
            }
           
        }

    }
}
 

the_king

مدیرکل انجمن
ممنون استاد علی
پس Msg باید بین عددهای 32768 تا 49151 باشه . یعنی غیر از این اعداد باشه ، با کدهای جدول زیر که کدهای تعریف شده هستن ، تداخل بوجود میاره براش؟
بنابراین ، میتونم هر عددی بین این بازه ی عددی که گفتید ، برای آرگومان Msg بطور دلخواه مشخص کنم و نیازی نیست طبق جدول زیر ، کد بدم :

About Messages and Message Queues (Windows)

درسته؟
طبق همون جدول ئه دیگه، از خودم که محدوده اختراع نکردم، اون لینکی که دادید همون توصیه ای رو می کنه که من کردم :
class.png
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
واقعا ممنونم استاد علی :rose:
خیلی کمک کردین
درباره ی ثبت توابع در لوا ، انگار همون بصورت شی گرا هه . یعنی هر شی ای که لوا را باز کنه ، فقط برای همون شی در دسترس هه . نمیدونم این جوری چه قابلیت مهمی میتونه داشته باشه!
شما نمیدونین چرا استفاده از لوا در دلِ زبان های دیگه ، در پروژه های بزرگ ، مرسوم هه؟
مثلا همونطور که گفتم ، میدونم خیلی از بازی ها ، پادویش ، photoshop lightroom و بسیاری نرم افزارهای دیگه که در لیست زیر میتونین ببینین ، از لوا در دلِ خودشون استفاده میکنن :

List of applications using Lua - Wikipedia

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

the_king

مدیرکل انجمن
واقعا ممنونم استاد علی :rose:
خیلی کمک کردین
درباره ی ثبت توابع در لوا ، انگار همون بصورت شی گرا هه . یعنی هر شی ای که لوا را باز کنه ، فقط برای همون شی در دسترس هه . نمیدونم این جوری چه قابلیت مهمی میتونه داشته باشه!
شما نمیدونین چرا استفاده از لوا در دلِ زبان های دیگه ، در پروژه های بزرگ ، مرسوم هه؟
مثلا همونطور که گفتم ، میدونم خیلی از بازی ها ، پادویش ، photoshop lightroom و بسیاری نرم افزارهای دیگه که در لیست زیر میتونین ببینین ، از لوا در دلِ خودشون استفاده میکنن :

List of applications using Lua - Wikipedia

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ممنون استاد علی
میگم توی سی شارپ این کد رو نوشتم :


کد:
        [DllExport("UnmanagedStrArray", CallingConvention = CallingConvention.StdCall)]
        public static int UnmanagedStrArray()
        {
            string[] arrayStr = new string[2] { "salam", "koja bodi to??!" };
            int[] tempArray = new int[arrayStr.Length];
            IntPtr ptrUnmArray = Marshal.AllocHGlobal(arrayStr.Length * IntPtr.Size);
           
            for (int i = 0; i < arrayStr.Length; i++)
            {
                IntPtr ptrStrElement = Marshal.StringToHGlobalAnsi(arrayStr[i]);
                tempArray[i] = ptrStrElement.ToInt32();
            }

            Marshal.Copy(tempArray, 0, ptrUnmArray, arrayStr.Length);

            return ptrUnmArray.ToInt32();
        }

و توی اتوپلی این کد رو :


کد:
hdlDll = Library.Load("Button.dll", false);
if (hdlDll ~= nil) then
ptrStrArray = hdlDll.UnmanagedStrArray();
    for i=0, 1 do
    ptr = ptrStrArray + (i * 4);
    mtStr = MemoryEx.String(ptr, -1, MEMEX_ASCII);
   
    Dialog.Message("Notice", mtStr, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
    end

hdlDll:Close_();
end

البته قبلا قضیه ی رشته را گفته بودین ولی میخوام بدونم این روش و این کد چرا جواب نمیده؟
میخوام توی سی شارپ آرایه ای از رشته ها (ی managed) را ، اول هر عضو از این آرایه را توی یه حافظه ی unmanaged (که ansi هست) بذارم (توسط Marshal.AllocHGlobal) و اشاره گر هر کدوم را توی یه آرایه ی int بذارم و این آرایه ای از int ها را توی آدرس حافظه ی unmanaged (همون ptrUnmArray در کد بالا) بذارم
بعد هم که میخوام از توی اتوپلی این رشته ها را بخونم
اما توی اتوپلی ، اون رشته ای نیست که توی سی شارپ نوشته بودم . یعنی رشته های نامربوط دیگه رو میده
 

the_king

مدیرکل انجمن
ممنون استاد علی
میگم توی سی شارپ این کد رو نوشتم :


کد:
        [DllExport("UnmanagedStrArray", CallingConvention = CallingConvention.StdCall)]
        public static int UnmanagedStrArray()
        {
            string[] arrayStr = new string[2] { "salam", "koja bodi to??!" };
            int[] tempArray = new int[arrayStr.Length];
            IntPtr ptrUnmArray = Marshal.AllocHGlobal(arrayStr.Length * IntPtr.Size);
          
            for (int i = 0; i < arrayStr.Length; i++)
            {
                IntPtr ptrStrElement = Marshal.StringToHGlobalAnsi(arrayStr[i]);
                tempArray[i] = ptrStrElement.ToInt32();
            }

            Marshal.Copy(tempArray, 0, ptrUnmArray, arrayStr.Length);

            return ptrUnmArray.ToInt32();
        }

و توی اتوپلی این کد رو :


کد:
hdlDll = Library.Load("Button.dll", false);
if (hdlDll ~= nil) then
ptrStrArray = hdlDll.UnmanagedStrArray();
    for i=0, 1 do
    ptr = ptrStrArray + (i * 4);
    mtStr = MemoryEx.String(ptr, -1, MEMEX_ASCII);
  
    Dialog.Message("Notice", mtStr, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
    end

hdlDll:Close_();
end

البته قبلا قضیه ی رشته را گفته بودین ولی میخوام بدونم این روش و این کد چرا جواب نمیده؟
میخوام توی سی شارپ آرایه ای از رشته ها (ی managed) را ، اول هر عضو از این آرایه را توی یه حافظه ی unmanaged (که ansi هست) بذارم (توسط Marshal.AllocHGlobal) و اشاره گر هر کدوم را توی یه آرایه ی int بذارم و این آرایه ای از int ها را توی آدرس حافظه ی unmanaged (همون ptrUnmArray در کد بالا) بذارم
بعد هم که میخوام از توی اتوپلی این رشته ها را بخونم
اما توی اتوپلی ، اون رشته ای نیست که توی سی شارپ نوشته بودم . یعنی رشته های نامربوط دیگه رو میده
اینجا مشکل مربوط به String نیست، چون متن نمونه انگلیسی ئه تبدیل به ANSI اش مشکلی ایجاد نمی کنه. کد #C تون ایرادی نداره، البته با در نظر گرفتن اینکه اولا 32 بیتی ئه و ثانیا حافظه ای که ایجاد کرده رو آزاد نمی کنه، یعنی به تدریج با اجرا های مکرر حافظه آزاد سیستم رو کاهش میده. بهتره یک متدی هم بسازید که بشه حافظه ای که ساخته بود آزاد کنه.
ایراد در کد اتوپلی شما است. ptrStrArray چه آدرسیه؟ آدرس شروع آرایه ای که اشاره گر string ها داخلش قرار دارند. شما باید اشاره گر ها رو از داخل این آرایه بخوانید ولی این کار رو نمی کنید. شما اصلا اشاره گر ها رو از این آدرس نمی خوانید. خود آدرس شروع و خانه های بعدی که اصلا ربطی به آرایه نداشتند رو میخواهید به عنوان اشاره گر رشته تفسیر کنید.
کد:
    ptr = MemoryEx.DWORD(ptrStrArray + (i * 4));
 

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

بالا