ارتباط لوا و #c با استفاده از ++c

SajjadKhati

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


کد:
[DllExport("ArrayPointer", CallingConvention.StdCall)]
        public static void ArrayPointer(IntPtr arrayArg, int arrayLength)
        {
            int[] myArray = new int[arrayLength];
            Marshal.Copy(arrayArg, myArray, 0, arrayLength);
        }


        [DllExport("ArrayPointer2", CallingConvention.StdCall)]
        public static int ArrayPointer2(IntPtr arrayArg, int arrayLength)
        {
            int[] myArray = new int[arrayLength];
            Marshal.Copy(arrayArg, myArray, 0, arrayLength);

            return myArray[0];
        }


        [DllExport("ArrayPointer3", CallingConvention.StdCall)]
        public static int ArrayPointer3(int[] myArray)
        {

            return myArray[0];
        }

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

SajjadKhati

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

کد:
[DllExport("ArrayPointer4", CallingConvention.StdCall)]
        public static int ArrayPointer4(int arrayPtr, int arrayLength)
        {
            try
            {
                IntPtr realArrayptr = (IntPtr)arrayPtr;
                int[] arrayInC = new int[arrayLength];
                Marshal.Copy(realArrayptr, arrayInC, 0, arrayLength);

                return arrayInC[0];
            }
            catch (Exception)
            {
                return 0;
            }
        }

کد اتوپلی :

کد:
myArr = {658, 42, 23};

myArrSize = MemoryEx.TableRequiredSize(myArr);
handleArray = MemoryEx.AllocateEx(myArrSize);
pointerArray = handleArray:GetPointer();
isArrayCopied = MemoryEx.Table(pointerArray, myArr);
    if (isArrayCopied) then
    mainArray = MemoryEx.Table(pointerArray);
        if (mainArray) then
            handleArray:SetArrayType(MEMEX_ARR_INT);
               
            dllPath = _SourceFolder.."\\ClassLibrary2.dll";
            dllHdl = Library.Load(dllPath);
            if (dllHdl) then
            myInt1 = dllHdl.ArrayPointer5(pointerArray, 3);
            Dialog.Message("16", myInt1, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
            dllHdl:Close_();
            end
        end
    end

الان برنامه کرش نمیشه . nil هم توی سی شارپ نمیشه
ولی عدد مورد نظرم که میخواستم صفر امین خونه از آرایه ای که در لوا هست (عدد 658) رو در کد سی شارپ برگردونه رو یه عدد پرت و پلا رو برمیگردونه .
الان کد سی شارپ در بالا مشکل نداره و درست هست استاد علی؟ من نمیدونم باید دنبال کدوم مشکل در کدوم کد بگردم . ظاهر کدها درست باید عمل کنن !
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
آو
استاد علی ، در کد بالا وقتی MessageBox.Show رو میزنم ، یه عدد دیگه رو اصلا نشون میده برای عضو آرایه . مطمئنین اون کد Marshal.Copy ، آرایه رو از اشاره گر به آرایه ی سی شارپ کپی میکنه؟ :


کد:
[DllExport("ArrayPointer4", CallingConvention.StdCall)]
        public static int ArrayPointer4(int arrayPtr, int arrayLength)
        {
            try
            {
                IntPtr realArrayptr = (IntPtr)arrayPtr;
                int[] arrayInC = new int[arrayLength];
                Marshal.Copy(realArrayptr, arrayInC, 0, arrayLength);
                MessageBox.Show(arrayInC[0].ToString(), "in c#");

                return arrayInC[0];
            }
            catch (Exception)
            {
                return 0;
            }
        }
 

the_king

مدیرکل انجمن
سلام استاد علی
من چندین متد با چندین روش متفاوت رو تست کردم ولی توی همه شون به بن بست خوردم :
من الان میخوام کلا یه آرایه ی پر (مثلا آرایه ای از اعداد) از لوا بفرستم برای dll ام و توی dll هم مثلا مقدار خونه ی صفر ام آرایه که یه عدد میشه رو برام برگردونه
الان وقتی میخوام از لوا ، آرایه رو بفرستم ، باید اشاره گر اون آرایه رو از لوا بفرستم یا خود آرایه رو بفرستم؟ اصلا مگه خود یه کلاسی که میفرستیم ، مگه اشاره گر به اون کلاس نیست؟ یعنی خود آرایه ، در واقع اشاره گری به آرایه هست همونطور که گفتین دیگه . پس فرقش چیه که واقعا خودمون اشاره گر به آرایه رو (با متدها و کلاس ها و روش های متفاوت) بفرستیم یا خود آرایه رو بفرستیم؟
بعد اینکه فرق اشاره گر intptr با اشاره گری که خودمون بصورت unsafe مینویسیم و حتی با اشاره گرهای عادی یعنی شی هایی که به کلاس اشاره میکنن (مثلا شی ای از آرایه یا شی ای از یه کلاس و ...) چین؟
حالا من اشاره گر به خونه ی آرایه رو میفرستادم ولی یا برنامه کرش میشد یا اگه کرش نمیشد ، با اونکه از لوا ، آرایه ی پر رو میفرستادم ولی در dll مقدارش nil میشد !
اصلا نمیدونم مشکل از کدهای ارسالی از لوا هست یا کدهای سی شارپم !
اگر زبان ارسال کننده و دریافت کننده تون هر دو Native بود و آدرس های حافظه Native بودند، واقعا فرقی نمی کرد، یعنی فرضا در زبانی مثل ++C اسم آرایه خودش اشاره گر ئه، و چه شما array[0]& یعنی آدرس اولین خونه حافظه و چه array رو ارسال کنید هر دو یک مقدار اند و معادل هم هستند. اما در مورد NET. که اصلا نمیشه چنین کاری کرد. شما می توانید آدرس شروع آرایه تون در #C رو بفهمید، اما اولا آدرس حافظه اش ثابت نمی مونه که روی مقدارش حساب باز کنید چون GC مدام در حال جابجایی آدرس ها است و ممکنه کسری از ثانیه بعد و موقع ارسال به اتوپلی جابجا شده باشه و ثانیا آدرس حفاظت شده است و نمیشه ازش مقدار خونده بشه یا نوشته بشه. حالا بماند که اگه ازش مقدار میخوندید هم بخاطر فرمت خاص آرایه ها بدرد اتوپلی نمی خورد. در مورد اتوپلی هم من واقعا نمیدونم ساختار آرایه هاش چطوریه اما در اینکه اشاره گر ارسال میشه شکی نیست، طور دیگه ای نمیتونه باشه.

تو تنظیمات Build پروژه تون که x86 رو انتخاب کرده اید؟ محض اطمینان می پرسم که اگه ویندوز تون 64 بیتی ئه سی شارپ تون 64 بیتی اجراش نکنه چون اونوقت IntPtr ئه 64 بیتی ئه و معادل int نیست و کرش کردن هم طبیعیه.
در کارکرد متد های Marshal شک نکنید. کلا وقتی پارامتر به یک تابع ارسال میشه بجز قرار گیری مقدار در پشته و یا رجیستر ها چیزی نیست. و وقتی با stdCall آرایه یا هر داده بزرگتر از int ارسال میشه راهی بجز همون ارسال اشاره گر وجود نداره. قطعا آدرس اشاره گر ارسال میشه ولی بذارید براتون یک مثال فنی بزنم تا ببینید گاهی خوندن مقدار از یک نوع داده پیچیده ریزه کاری داره. ممکنه اون 4 بایت اولی که با Marshal از ptr می خوانید خودش یک اشاره گر باشه که به داده واقعی اشاره کنه :
کد:
        public static void ArrayPointer(IntPtr arrayArg, int arrayLength)
        {
            var myArray = new int[arrayLength];
            var ptr = Marshal.ReadIntPtr(arrayArg);
            Marshal.Copy(ptr, myArray, 0, arrayLength);

        }
ثانیا داده داخل خونه های آرایه چرا باید int باشه؟ اگر اتوپلی بخواد بین نوع داده های مختلف فرق بذاره حتما باید نوع داده رو کنار مقادیر ذخیره کنه، مثلا اگه فرض کنیم 5 کد اعداد int باشه باید به ازای هر خونه از آرایه یک مقدار ثابت 5 در حافظه باشه که حالا یک بایتی یا چند بایتی ئه و برای اینه که مشخص کنه داده بعدی در آرایه از چه نوعی ئه. تازه ممکنه هر خونه از حافظه خودش یه اشاره گر برای دسترسی به مقدار واقعی باشه، چون طول داده های هر خونه که الزاما اندازه یه int چهار بایتی نیست، اگه نوع داده بزرگتر هم باشه حتما برای هر خونه باز اشاره گر دارند.
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اگر زبان ارسال کننده و دریافت کننده تون هر دو Native بود و آدرس های حافظه Native بودند، واقعا فرقی نمی کرد، یعنی فرضا در زبانی مثل ++C اسم آرایه خودش اشاره گر ئه، و چه شما array[0]& یعنی آدرس اولین خونه حافظه و چه array رو ارسال کنید هر دو یک مقدار اند و معادل هم هستند. اما در مورد NET. که اصلا نمیشه چنین کاری کرد. شما می توانید آدرس شروع آرایه تون در #C رو بفهمید، اما اولا آدرس حافظه اش ثابت نمی مونه که روی مقدارش حساب باز کنید چون GC مدام در حال جابجایی آدرس ها است و ممکنه کسری از ثانیه بعد و موقع ارسال به اتوپلی جابجا شده باشه و ثانیا آدرس حفاظت شده است و نمیشه ازش مقدار خونده بشه یا نوشته بشه.
سلام
ممنون استاد علی
این کارها رو که گفتید ، توی سی شارپ هم با کلمه ی کلیدی fixed میشه انجام داد :


کد:
private void button9_Click(object sender, EventArgs e)
        {
            unsafe
            {
                int[] myArray = { 10, 20, 129, 4, 98 };
                for (int i = 0; i < myArray.Length; i++)
                {
                    MessageBox.Show(myArray[i].ToString(), "myArray");
                }

                fixed (int* arrayPointer = myArray)
                {
                    for (int i = 0; i < myArray.Length; i++)
                    {
                        MessageBox.Show(arrayPointer[i].ToString(), "arrayPointer");
                    }
                    arrayPointer[2] = 999999;
                }
                MessageBox.Show(myArray[2].ToString(), "myArray");
            }
        }
fixed ، اشاره گری (خونه ی حافظه ای که اشاره گر بهش اشاره میکنه) که در پرانتز اش مقدار اولیه دادیم رو در GC ثابت نگه میداره دیگه (اینو برای خودم گفتم برای بعدا که یادم رفت ، بخونم:green:)

حالا بماند که اگه ازش مقدار میخوندید هم بخاطر فرمت خاص آرایه ها بدرد اتوپلی نمی خورد. در مورد اتوپلی هم من واقعا نمیدونم ساختار آرایه هاش چطوریه اما در اینکه اشاره گر ارسال میشه شکی نیست، طور دیگه ای نمیتونه باشه.
منظورتون از فرمت ، همونطور که گفتین ، اینه که مثلا عضو های آرایه ی لوا ، اشاره گر هستن یا مقدار مستقیم دارن؟ منم نمیدونم اما حدس میزنم به احتمال بسیار زیاد ، هر ساختاری که آرایه از نوع dynamic در سی شارپ داره ، لوا هم همون ساختار رو داره
اگه اشتباه هم نکنم ، ساختار آرایه ی dynamic این طوره که اعضایی که از نوع استراکچر (اعداد و استراکچر و ...) باشن ، مقدار دارن (اشاره گر نیست) و اعضاهایی که از نوع کلاس و آرایه و delegate باشن ، اشاره گرن . درست هه؟


تو تنظیمات Build پروژه تون که x86 رو انتخاب کرده اید؟ محض اطمینان می پرسم که اگه ویندوز تون 64 بیتی ئه سی شارپ تون 64 بیتی اجراش نکنه چون اونوقت IntPtr ئه 64 بیتی ئه و معادل int نیست و کرش کردن هم طبیعیه.
آره X86 انتخاب هه
البته قضیه ی کرش کردن ، در اون کد آخرین پستی که در بالا دادم ، گفتم که حل شد


در کارکرد متد های Marshal شک نکنید. کلا وقتی پارامتر به یک تابع ارسال میشه بجز قرار گیری مقدار در پشته و یا رجیستر ها چیزی نیست. و وقتی با stdCall آرایه یا هر داده بزرگتر از int ارسال میشه راهی بجز همون ارسال اشاره گر وجود نداره. قطعا آدرس اشاره گر ارسال میشه ولی بذارید براتون یک مثال فنی بزنم تا ببینید گاهی خوندن مقدار از یک نوع داده پیچیده ریزه کاری داره. ممکنه اون 4 بایت اولی که با Marshal از ptr می خوانید خودش یک اشاره گر باشه که به داده واقعی اشاره کنه :
کد:
        public static void ArrayPointer(IntPtr arrayArg, int arrayLength)
        {
            var myArray = new int[arrayLength];
            var ptr = Marshal.ReadIntPtr(arrayArg);
            Marshal.Copy(ptr, myArray, 0, arrayLength);

        }
الان ، اگه در سی شارپ ، خودمون اشاره گر اگه تعریف کنیم (همون که علامت ستاره میزارن و بصورت unsafe مینویسن . نه اینکه با کلاس IntPtr کار کنیم) ، خوب ساختار آرایه در هر دو در این صورت برابر میشن دیگه و میتونیم با هم (آرایه در زبان های Unmanaged و Managed) ارتباط برقرار کنیم دیگه . درست هه؟
اگه آره ، من الان مشکلم پس یه چیز هست . اینکه از اتوپلی ، اشاره گر میتونم بفرستم . خوب؟ اما این اشاره گر ، مثل سی شارپ نیست که بصورت مثلا *int تعریف بشه . واقعا اون اشاره گر ، یه عدد واقعی هست . یعنی یه int هست ، منتها عددی که به خونه ی اولین عضو آرایه اشاره میکنه . با این اوصاف ، من الان فکر کنم مشکلم این باشه که یه طوری عدد رو به اشاره گر تبدیل کنم . یعنی در واقع ، توی سی شارپ ، چجوری میشه عدد رو به اشاره گر تبدیل کرد؟
نگاه کنید ، من منظورم کدی مثل کد زیر نیست :

کد:
[DllExport("ArrayPointer7", CallingConvention.StdCall)]
        public static void ArrayPointer7(int arrayPtr, int arrayLength)
        {
            unsafe
            {
                int* mainPointer = &arrayPtr;
            }
        }
چون کد بالا ، مثل کد زیر میمونه :
کد:
unsafe
            {
                int myInt = 4521;
                int* mainPointer = &myInt;
            }
و در هر دو ، آدرس ای که خود اون عدد در خونه ی خاصی از حافظه هست ، توی اشاره گر mainPointer ریخته میشه . یعنی ممکنه ، متغییر myInt که مقدار عدد 4521 ، توی خونه ی شماره ی 99 از حافظه ی رم باشه که اشاره گرمون به شماره ی خونه ی 99 در رم اشاره میکنه
سئوال من اینه که در کد بالا ، چجوری میشه اشاره گری تعریف کنیم که به مقدار همون عدد ، به عنوان اشاره گر ، اشاره کنه؟ یعنی اشاره گرمون در بالا ، به خونه ی 4521 در حافظه اشاره کنه؟


ثانیا داده داخل خونه های آرایه چرا باید int باشه؟ اگر اتوپلی بخواد بین نوع داده های مختلف فرق بذاره حتما باید نوع داده رو کنار مقادیر ذخیره کنه، مثلا اگه فرض کنیم 5 کد اعداد int باشه باید به ازای هر خونه از آرایه یک مقدار ثابت 5 در حافظه باشه که حالا یک بایتی یا چند بایتی ئه و برای اینه که مشخص کنه داده بعدی در آرایه از چه نوعی ئه.
این تیکه رو متوجه نشدم منظورتون چیه و به چه قسمتی از حرف یا کدم اشاره میکنین :green:
 

SajjadKhati

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

کد:
[DllExport("ArrayPointer8", CallingConvention.StdCall)]
        public static unsafe int ArrayPointer8(int arrayPtr, int arrayLength)
        {
            int* mainPointer = (int*)arrayPtr;
            for (int i = 0; i < arrayLength; i++)
            {
                MessageBox.Show(mainPointer[i].ToString(), "In C#");
                mainPointer[i] = i;
            }
               
            return (int)mainPointer;
        }

اینو هم توی اتوپلی :

کد:
myArray = {164, 10, 41, 57, 2500, 1};

tableSize = MemoryEx.TableRequiredSize(myArray);
handleMyArray = MemoryEx.AllocateEx(tableSize);
handleMyArray:SetArrayType(MEMEX_ARR_INT); 
myArrayPointer = handleMyArray:GetPointer();
isCreatedInBuffer = MemoryEx.Table(myArrayPointer, myArray);
if (isCreatedInBuffer == true and myArrayPointer ~= nil) then
myArrayInBuffer = MemoryEx.Table(myArrayPointer);
    if (myArrayInBuffer ~= nil) then
    -------------
        for index,value in pairs(myArrayInBuffer) do
        Dialog.Message("befor", "index : "..index.."\nvalue : "..value.."\nmyArrayPointer : "..myArrayPointer, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
        end
    dllPath = _SourceFolder.."\\ClassLibrary2.dll";
    dllHdl = Library.Load(dllPath);
        if (dllHdl ~= nil) then
        ---------------------
        firstElementInDll = dllHdl.ArrayPointer8(myArrayPointer, #myArrayInBuffer);
            for index,value in pairs(myArrayInBuffer) do
            Dialog.Message("after call dll", "index : "..index.."\nvalue : "..value.."\n\nfirstElementInDll : "..firstElementInDll.."\nmyArrayPointer : "..myArrayPointer, MB_OK, MB_ICONINFORMATION, MB_DEFBUTTON1);
            end
        dllHdl:Close_();
        end
    end
end

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

the_king

مدیرکل انجمن
سلام
ممنون استاد علی
این کارها رو که گفتید ، توی سی شارپ هم با کلمه ی کلیدی fixed میشه انجام داد :
fixed ، اشاره گری (خونه ی حافظه ای که اشاره گر بهش اشاره میکنه) که در پرانتز اش مقدار اولیه دادیم رو در GC ثابت نگه میداره دیگه (اینو برای خودم گفتم برای بعدا که یادم رفت ، بخونم:green:)
نه fixed صرفا آدرس حافظه رو ثابت نگه میداره، ارتباط بین محیط Managed و Unmanaged همون مسائل قبلی رو داره و سر جاش ئه. fixed که محیط Managed رو به Unmanaged تبدیل نمی کنه. کد کامپایل شده #C در یک محیط Managed که اجرا نمیشه، ماشین مجازی داره. ثابت کردن موقعیت آدرس حافظه، ساختار هیچ آرایه ای رو تغییر نمیده.

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

اگه اشتباه هم نکنم ، ساختار آرایه ی dynamic این طوره که اعضایی که از نوع استراکچر (اعداد و استراکچر و ...) باشن ، مقدار دارن (اشاره گر نیست) و اعضاهایی که از نوع کلاس و آرایه و delegate باشن ، اشاره گرن . درست هه؟
دارن و لازم هم هست، ولی کافی نیست، وقتی در یک خونه نوع داده های متفاوتی قابل قرار گرفتن باشه هم طول داده مهمه و هم کد مشخص کننده نوع داده. وگرنه در حافظه صرفا یکسری بایت قرار گرفته، از روی مقدار باینری نمیشه فهمید نوع داده چیه. اگر معلوم نباشه که این بایت ها مربوط به چه نوع داده ای و با چه طولی هستند قابل استفاده نیستند.

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

الان ، اگه در سی شارپ ، خودمون اشاره گر اگه تعریف کنیم (همون که علامت ستاره میزارن و بصورت unsafe مینویسن . نه اینکه با کلاس IntPtr کار کنیم) ، خوب ساختار آرایه در هر دو در این صورت برابر میشن دیگه و میتونیم با هم (آرایه در زبان های Unmanaged و Managed) ارتباط برقرار کنیم دیگه . درست هه؟
همه چی رو با هم قاطی می کنید، اشاره گر در #C چه ربطی به ساختار آرایه در اتوپلی داره؟ شما به هر طریقی که بخواهید می توانید مقدار اشاره گر به یک آرایه در #C رو بدست بیاورید، مقدارش هم صرفا یک عدد ئه که یک آدرس حافظه است. ساختار آرایه در اتوپلی یا #C که عوض نمیشه، در ضمن ساختار []int در #C در اون قسمت که مربوط به خوندن و نوشتنه، خیلی ساده و سر راست ئه. و فکر نمی کنم مشکلی در نوشتن در []int داشته باشید.
مشکل خودتون رو درست تفسیر نمی کنید، ساختار آرایه هایی که در اتوپلی دارید رو نمی دانید، اگر ساختارش رو بدونید می توانید در #C یا هر زبان دیگری از مقادیر داخلش استفاده کنید. حالا شما در #C دارید راه های متفاوتی برای دریافت اشاره گر و یا مقدار دادن در آرایه های #C رو امتحان می کنید که نتیجه همه شان هم یکی است، برای تجربه های جدید خوبه ولی اصلا ربطی به مشکل شما ندارند. شما که مشکل تان IntPtr یا آرایه های []int نیست.

این تیکه رو متوجه نشدم منظورتون چیه و به چه قسمتی از حرف یا کدم اشاره میکنین :green:
در مورد این ;myIntArray = {10, 30, 513} گفتم. چرا باید معادل [3]int باشه؟ مگر غیر از اینه که در هر خانه اش می تونه نوع داده متفاوتی قرار بگیره؟ و یا چرا باید مقدار های عددی int باشند؟ چه اطمینانی هست که double یا short یا long نباشند؟

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

کد:
[DllExport("ArrayPointer7", CallingConvention.StdCall)]
        public static void ArrayPointer7(int arrayPtr, int arrayLength)
        {
            unsafe
            {
                int* mainPointer = &arrayPtr;
            }
        }
چون کد بالا ، مثل کد زیر میمونه :
کد:
unsafe
            {
                int myInt = 4521;
                int* mainPointer = &myInt;
            }
و در هر دو ، آدرس ای که خود اون عدد در خونه ی خاصی از حافظه هست ، توی اشاره گر mainPointer ریخته میشه . یعنی ممکنه ، متغییر myInt که مقدار عدد 4521 ، توی خونه ی شماره ی 99 از حافظه ی رم باشه که اشاره گرمون به شماره ی خونه ی 99 در رم اشاره میکنه
سئوال من اینه که در کد بالا ، چجوری میشه اشاره گری تعریف کنیم که به مقدار همون عدد ، به عنوان اشاره گر ، اشاره کنه؟ یعنی اشاره گرمون در بالا ، به خونه ی 4521 در حافظه اشاره کنه؟
کد:
                int* ptr = (int*)4521;
و در نظر بگیرید که این مقدار 4521 یک آدرسی است که خودتون اختراع کردید، بجز در زبان هایی مثل اسمبلی قرار دادن مقدار ثابت به عنوان آدرس اشاره گر بی معنی و غیر قابل استفاده است. اینکه شما یک مقدار ثابت رو به اشاره گر تبدیل کنید هیچ کاربردی نداره، نه در اتوپلی و نه در #C
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نه fixed صرفا آدرس حافظه رو ثابت نگه میداره، ارتباط بین محیط Managed و Unmanaged همون مسائل قبلی رو داره و سر جاش ئه. fixed که محیط Managed رو به Unmanaged تبدیل نمی کنه. کد کامپایل شده #C در یک محیط Managed که اجرا نمیشه، ماشین مجازی داره. ثابت کردن موقعیت آدرس حافظه، ساختار هیچ آرایه ای رو تغییر نمیده.


نمیدونم از روی چه چیزی همچین حدسی می زنید. در نظر بگیرید که انواع داده ای که در NET. هست خاص خودشه، و ماشین مجازی اجرا کننده خاص خودش رو هم داره، از نظر ساختار شباهتی به محیط های غیر NET. نداره. اگر لوا با زبان های NET. نوشته شده همون ساختار رو داره وگرنه نه.


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

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

سلام
ممنون استاد علی
به پست بالا هم نگاهی بکنین ، انگار یه قدم به جواب نزدیک تر از قبل شده ولی هنوز بی جواب هه :)


همه چی رو با هم قاطی می کنید، اشاره گر در #C چه ربطی به ساختار آرایه در اتوپلی داره؟ شما به هر طریقی که بخواهید می توانید مقدار اشاره گر به یک آرایه در #C رو بدست بیاورید، مقدارش هم صرفا یک عدد ئه که یک آدرس حافظه است. ساختار آرایه در اتوپلی یا #C که عوض نمیشه، در ضمن ساختار []int در #C در اون قسمت که مربوط به خوندن و نوشتنه، خیلی ساده و سر راست ئه. و فکر نمی کنم مشکلی در نوشتن در []int داشته باشید.
مشکل خودتون رو درست تفسیر نمی کنید، ساختار آرایه هایی که در اتوپلی دارید رو نمی دانید، اگر ساختارش رو بدونید می توانید در #C یا هر زبان دیگری از مقادیر داخلش استفاده کنید. حالا شما در #C دارید راه های متفاوتی برای دریافت اشاره گر و یا مقدار دادن در آرایه های #C رو امتحان می کنید که نتیجه همه شان هم یکی است، برای تجربه های جدید خوبه ولی اصلا ربطی به مشکل شما ندارند. شما که مشکل تان IntPtr یا آرایه های []int نیست.
آها ، مشکل من اینه که ساختار آرایه در لوا رو باید بدونم؟
در حال حاضر که نمیدونم و تا حالا هم اصلا با مبحث ساختار آرایه یا ساختار داده در سی شارپ و لوا کار نکردم و اطلاعی ندارم و اصلا نمیدونم برای این مبحث ، اصلا باید از چی شروع کنم
میشه راهنمایی کنین که برای دونستن ساختار داده در لوا ، باید چه چیزهایی رو بخونم؟
اول اینکه ، کل مباحث و متدهای لوا ، در این دو صفحه (مخصوصا لینک اول) هست :
Programming in Lua (first edition)
و
Lua 5.1 Reference Manual - contents

چیزی که شما میخواین ، انگار باید توی لینک اول ، بخش 11 (بخش Data Structures) و دقیق تر بخش 11.1 (Arrays) باشه . درست هه؟ :
Programming in Lua : 11
و
Programming in Lua : 11.1

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



در مورد این ;myIntArray = {10, 30, 513} گفتم. چرا باید معادل [3]int باشه؟
آرایه در لوا ،معادل int نیست که . من که گفتم . معادل dynamic در سی شارپ هه (حداقل شباهت بسیار زیادی از لحاظ عملکرد ظاهری دارن ولی باطن شو نمیدونم). حالا چجوری کد گذاری میکنه و کد نوع داده ای رو مشخص میکنه ، گفتم که ؛ من اصلا ساختمان داده بلد نیستم . نمیدونم .
منظورتون از اینکه گفتین "چرا باید معادل [3]int باشه" ؛ درباره ی int بودن یا نبودن اش که توضیح دادم ولی درباره ی 3 عضو داشتن اش هم جزء سئوال تون بود؟ آرایه ی بالا ، 3 عضو داره . اگه منظورتون از نوع Int ، نام myIntArray ای هست که گفتم ، این فقط اسم متغییر هست :) کلا من سئوال تون درباره ی این قسمت int رو متوجه نشدم دقیقا .


مگر غیر از اینه که در هر خانه اش می تونه نوع داده متفاوتی قرار بگیره؟ و یا چرا باید مقدار های عددی int باشند؟ چه اطمینانی هست که double یا short یا long نباشند؟
آره . میتونه در هر خونه اش ، انواع داده ای مختلف قرار بگیره
همین . منم نمیدونم از چه نوعی هستن اما فکر کنم عددهای رند رو از نوع int بگیره (چون بجز این اگه میبود ، وقتی به متدهای نوشته شده در dll سی شارپ میفرستادم ، طبعا باید از جانب سی شارپ ، ارور میگرفتم که عددها رو ارور نمیده . به همین منوال ، احتمال میدم عددهایی که اعشار میذاریم رو از نوع double بگیره . فکر نکنم نوع های دیگه ای بجز این دو داشته باشه یعنی short و long و float و ... رو بعید میدونم داشته باشه



کد:
                int* ptr = (int*)4521;
و در نظر بگیرید که این مقدار 4521 یک آدرسی است که خودتون اختراع کردید، بجز در زبان هایی مثل اسمبلی قرار دادن مقدار ثابت به عنوان آدرس اشاره گر بی معنی و غیر قابل استفاده است. اینکه شما یک مقدار ثابت رو به اشاره گر تبدیل کنید هیچ کاربردی نداره، نه در اتوپلی و نه در #C

ممنون
:rose:
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
آها
راستی استاد علی ، فراموش کردم بگم
به آرایه در لوا مربوط نمیشه . آخه لوا با اشاره گر و ایناها نمیتونه کار کنه ، با پلاگین MemortEx که برای اتوپلی هست ، آرایه ی تعریف شده در لوا رو میگیرم و با استفاده از این پلاگین ، دوباره یه حافظه ی جدید در رم تعریف میکنم و آرایه رو در حافظه ی جدید میریزم و بعد آدرس این حافظه ی جدید رو برای سی شارپ ارسال میکنم (بصورت عدد)
بنابراین حتما پلاگین MemoryEx حالا از هر زبون ای که استفاده میکنه ، باید جدای از لوا ، آرایه رو در رم تعریف کرده و ریخته باشه در حافظه دیگه؟!
پس دونستن ساختتار داده ی آرایه ی لوا ، فکر نکنم کاری کنه . باید ساختار آرایه در پلاگین MemoryEx رو بدونیم. نه؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
در کارکرد متد های Marshal شک نکنید. کلا وقتی پارامتر به یک تابع ارسال میشه بجز قرار گیری مقدار در پشته و یا رجیستر ها چیزی نیست. و وقتی با stdCall آرایه یا هر داده بزرگتر از int ارسال میشه راهی بجز همون ارسال اشاره گر وجود نداره. قطعا آدرس اشاره گر ارسال میشه ولی بذارید براتون یک مثال فنی بزنم تا ببینید گاهی خوندن مقدار از یک نوع داده پیچیده ریزه کاری داره. ممکنه اون 4 بایت اولی که با Marshal از ptr می خوانید خودش یک اشاره گر باشه که به داده واقعی اشاره کنه :
کد:
        public static void ArrayPointer(IntPtr arrayArg, int arrayLength)
        {
            var myArray = new int[arrayLength];
            var ptr = Marshal.ReadIntPtr(arrayArg);
            Marshal.Copy(ptr, myArray, 0, arrayLength);

        }

سلام
استاد علی ، این کد رو توی سی شارپ که تست میکنم ، با اونکه کدش رو توی try-catch میذارم ، بازم نمیتونه ارور رو مهار کنه و خطایی که در عکس توی همین پست پیوست کردم رو میده و کدش هم اینه :

کد:
private void button14_Click(object sender, EventArgs e)
        {
            int[] myArray = new int[] { 457, 635, 5774, 4, 45, 2 };
            unsafe
            {
                fixed (int* fixedPointer = &myArray[0])
                {
                    int Int = Form1.ArrayPointer9((int)fixedPointer, myArray.Length);
                    MessageBox.Show(Int.ToString());
                }
            }


        }

        public static int ArrayPointer9(int arrayPtr, int arrayLength)
        {
            try
            {
                IntPtr tempPointer = (IntPtr)arrayPtr;
                int[] myArray = new int[arrayLength];
                IntPtr mainPointer = Marshal.ReadIntPtr(tempPointer);
                Marshal.Copy(mainPointer, myArray, 0, arrayLength);
                return myArray[0];
            }
            catch (Exception)
            {
                return 0;
            }

        }

شاید بگین ، سی شارپ که Unmanaged Memory نداره و واسه همین نمیتونه اشاره گر آرایه ای که فرستادم رو از Unmanaged Momory در متد Marshal.Copy ، کپی کنه ولی اشاره گر آرایه ی لوا هم که میرفستم برای متد ArrayPointer9 ، بازم برنامه کرش میکنه و اشکال از همین متد Marshal.Copy هه
---------------------
یه چیز دیگه اینکه گفتین از اشاره گر و کلا فضای unsafe سعی کنم استفاده نکنم و بجاش از کلاس IntPtr استفاده کنم اما اگه من بخوام از طریق همین کلاس IntPtr ، شی ای بسازم که مثلا اشاره گر یک عدد (مثلا در کد int a=5;) رو بگیره (یعنی به آدرس جایی که a هست ، اشاره کنه) ، باید چی کار کنم؟ یا مثلا همین آدرس عضو اول یه آرایه رو چجوری میشه توسط IntPtr گرفت؟
ممنون
 

SajjadKhati

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

پیوست ها

  • 1.JPG
    1.JPG
    80.3 کیلوبایت · بازدیدها: 2

the_king

مدیرکل انجمن
مستندات داخلی میخواد، راهنمای کد نویسی اش کار ساز نیست.
کد:
myArrSize = 5 * 4;
handleArray = MemoryEx.AllocateEx(myArrSize);
pointerArray = handleArray:GetPointer();
handleArray:SetArrayType(MEMEX_ARR_INT);
handleArray[0] = 1;
handleArray[1] = 2;
handleArray[2] = 3;
handleArray[3] = 4;
handleArray[4] = 5;
dllHdl = Library.Load("ClassLibrary2.dll");
if (dllHdl) then
    dllHdl.Test(pointerArray, 5);
    dllHdl:Close_();
end

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

namespace ClassLibrary2
{
    public class Class1
    {
        [DllExport("Test", CallingConvention.StdCall)]
        public static void Test(IntPtr ptr, int count)
        {
            var arr = new int[count];
            Marshal.Copy(ptr, arr, 0, count);
            var s = new StringBuilder();
            s.Append("arr = {");
            for (int i = 0; i < count; i++)
            {
                s.Append(arr[i].ToString());
                if (i < count - 1)
                {
                    s.Append(", ");
                }
            }
            s.Append("}");
            MessageBox.Show(s.ToString(), "Test", MessageBoxButtons.OK);
        }
    }
}
 

the_king

مدیرکل انجمن
یه چیز دیگه اینکه گفتین از اشاره گر و کلا فضای unsafe سعی کنم استفاده نکنم و بجاش از کلاس IntPtr استفاده کنم اما اگه من بخوام از طریق همین کلاس IntPtr ، شی ای بسازم که مثلا اشاره گر یک عدد (مثلا در کد int a=5;) رو بگیره (یعنی به آدرس جایی که a هست ، اشاره کنه) ، باید چی کار کنم؟ یا مثلا همین آدرس عضو اول یه آرایه رو چجوری میشه توسط IntPtr گرفت؟
ممنون
برای خود #C چون کاربردی نداره معادل Safe ای نداره، نه اینکه نشه انجامش داد، پیچیده میشه، اما اگه برای ارسال به خارج از #C منظورتونه با ref همون متغیر رو به عنوان پارامتر ارسال می کنید، اشاره گر اش ارسال میشه. یعنی بجای int با ref int پارامتر رو تعریف می کنید و با ref هم بجای مقدارش، آدرسش رو ارسال می کنید. در نظر بگیرید که متغیر های int از نوع Value Type اند و آدرس اشاره گر بصورت عادی ندارند.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
مستندات داخلی میخواد، راهنمای کد نویسی اش کار ساز نیست.
کد:
myArrSize = 5 * 4;
handleArray = MemoryEx.AllocateEx(myArrSize);
pointerArray = handleArray:GetPointer();
handleArray:SetArrayType(MEMEX_ARR_INT);
handleArray[0] = 1;
handleArray[1] = 2;
handleArray[2] = 3;
handleArray[3] = 4;
handleArray[4] = 5;
dllHdl = Library.Load("ClassLibrary2.dll");
if (dllHdl) then
    dllHdl.Test(pointerArray, 5);
    dllHdl:Close_();
end

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

namespace ClassLibrary2
{
    public class Class1
    {
        [DllExport("Test", CallingConvention.StdCall)]
        public static void Test(IntPtr ptr, int count)
        {
            var arr = new int[count];
            Marshal.Copy(ptr, arr, 0, count);
            var s = new StringBuilder();
            s.Append("arr = {");
            for (int i = 0; i < count; i++)
            {
                s.Append(arr[i].ToString());
                if (i < count - 1)
                {
                    s.Append(", ");
                }
            }
            s.Append("}");
            MessageBox.Show(s.ToString(), "Test", MessageBoxButtons.OK);
        }
    }
}

سلام
به معنی دقیق کلمه ، یک دنیا تشکر :rose: :rose: :clap:
واقعا خیلی درگیر این موضوع بودم (و البته همینطور قضیه ی اون پنجره در سی شارپ :green:)
و البته اگه میخوایم تغییر بدیم مقدار درون آرایه رو ، همونطور که گفتین کدش میشه :


کد:
[DllExport("Test", CallingConvention.StdCall)]
        public static void Test(IntPtr ptr, int count)
        {
            var arr = new int[count];
            Marshal.Copy(ptr, arr, 0, count);
            var s = new StringBuilder();
            s.Append("arr = {");
            for (int i = 0; i < count; i++)
            {
                s.Append(arr[i].ToString());
                if (i < count - 1)
                {
                    s.Append(", ");
                }
            }
            s.Append("}");
            MessageBox.Show(s.ToString(), "Test", MessageBoxButtons.OK);
           
            //----------------- change unmanaged array content
            for (int i = 0; i < count; i++)
            {
                arr[i] = 100;
            }

            Marshal.Copy(arr, 0, ptr, count);
        }

الان پس کلا مشکل کدهای اتوپلی بود؟ عجب کدش رو عالی درست کردین . ممنون
الان توی اتوپلی ، این کد رو که نوشتین :

کد:
handleArray = MemoryEx.AllocateEx(myArrSize);
handleArray[0] = 1;
handleArray[1] = 2;
handleArray[2] = 3;
handleArray[3] = 4;
handleArray[4] = 5;

با این کدی که قبلا نوشتم :

کد:
myArr = {658, 42, 23};

myArrSize = MemoryEx.TableRequiredSize(myArr);
handleArray = MemoryEx.AllocateEx(myArrSize);
pointerArray = handleArray:GetPointer();
isArrayCopied = MemoryEx.Table(pointerArray, myArr);
    if (isArrayCopied) then
    mainArray = MemoryEx.Table(pointerArray);
    end

بصورت عادی ، به نظر میرسه ، 2 تا کد نباید فرقی داشته باشن. یعنی خروجی متد AllocateEx که بصورت مستقیم ، مقدار آرایه اش رو دادین ، با کدم که اشاره گر آرایه ی handleArray رو میگیره و با استفاده از تابع MemoryEx.Table در همون اشاره گر ، آرایه ای رو کپی میکنه (که انگار باید عملکردی شبیه متد Marshal.Copy در سی شارپ داشته باشه) ، نباید فرق خاصی داشته باشه !! . فرق شون چیه؟
بعد اینکه اروری که در عکس پست بالا گذاشتم ، برای چی هست؟ و کلا چرا اتوپلی با کدی که دادم ، قبلا ، موقع فراخونی اون متد ، وقتی به کد Marshal.Copy میرسید ، کرش میشد (یعنی در واقع علت کرش اش همون خطا در عکس بالا بود) . علت ارور کد در عکس بالا چیه؟
 

the_king

مدیرکل انجمن
سلام
به معنی دقیق کلمه ، یک دنیا تشکر :rose: :rose: :clap:
واقعا خیلی درگیر این موضوع بودم (و البته همینطور قضیه ی اون پنجره در سی شارپ :green:)
و البته اگه میخوایم تغییر بدیم مقدار درون آرایه رو ، همونطور که گفتین کدش میشه :


کد:
[DllExport("Test", CallingConvention.StdCall)]
        public static void Test(IntPtr ptr, int count)
        {
            var arr = new int[count];
            Marshal.Copy(ptr, arr, 0, count);
            var s = new StringBuilder();
            s.Append("arr = {");
            for (int i = 0; i < count; i++)
            {
                s.Append(arr[i].ToString());
                if (i < count - 1)
                {
                    s.Append(", ");
                }
            }
            s.Append("}");
            MessageBox.Show(s.ToString(), "Test", MessageBoxButtons.OK);
         
            //----------------- change unmanaged array content
            for (int i = 0; i < count; i++)
            {
                arr[i] = 100;
            }

            Marshal.Copy(arr, 0, ptr, count);
        }

الان پس کلا مشکل کدهای اتوپلی بود؟ عجب کدش رو عالی درست کردین . ممنون
الان توی اتوپلی ، این کد رو که نوشتین :

کد:
handleArray = MemoryEx.AllocateEx(myArrSize);
handleArray[0] = 1;
handleArray[1] = 2;
handleArray[2] = 3;
handleArray[3] = 4;
handleArray[4] = 5;

با این کدی که قبلا نوشتم :

کد:
myArr = {658, 42, 23};

myArrSize = MemoryEx.TableRequiredSize(myArr);
handleArray = MemoryEx.AllocateEx(myArrSize);
pointerArray = handleArray:GetPointer();
isArrayCopied = MemoryEx.Table(pointerArray, myArr);
    if (isArrayCopied) then
    mainArray = MemoryEx.Table(pointerArray);
    end

بصورت عادی ، به نظر میرسه ، 2 تا کد نباید فرقی داشته باشن. یعنی خروجی متد AllocateEx که بصورت مستقیم ، مقدار آرایه اش رو دادین ، با کدم که اشاره گر آرایه ی handleArray رو میگیره و با استفاده از تابع MemoryEx.Table در همون اشاره گر ، آرایه ای رو کپی میکنه (که انگار باید عملکردی شبیه متد Marshal.Copy در سی شارپ داشته باشه) ، نباید فرق خاصی داشته باشه !! . فرق شون چیه؟
بعد اینکه اروری که در عکس پست بالا گذاشتم ، برای چی هست؟ و کلا چرا اتوپلی با کدی که دادم ، قبلا ، موقع فراخونی اون متد ، وقتی به کد Marshal.Copy میرسید ، کرش میشد (یعنی در واقع علت کرش اش همون خطا در عکس بالا بود) . علت ارور کد در عکس بالا چیه؟
مساله همون آرایه myArr ئه، محتویاتش که معادل یک آرایه []int نیست. MemoryEx.Table از اطلاعاتش کپی می گیره ولی چی داخلشه رو بررسی نکردم، هر چی هست شکل یک آرایه []int نیست. البته این رو در نظر بگیرید که اون حافظه ای که با AllocateEx ساختید باید بالاخره آزاد بشه، کدی برایش ننوشته اید که handleArray آزاد بشه . اگه اینکار رو نکنید کد تون Memory Leak و نشتی داره و به تدریج حافظه آزاد سیستم کم میشه، قطعا حافظه زیادی نیست ولی بالاخره ایراد کد ئه.
خطا به این دلیل ئه که آدرس حافظه ای که میخواهید ازش Copy کنید معتبر نیست، یعنی یا اصلا اون مقدار اشاره گر نیست و واقعا یک آدرس حافظه نبوده و یا اشاره گر هست ولی در ناحیه ای از حافظه بوده که مجوز دسترسی نداشته، که به احتمال زیاد دلیل همون اولی است.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
استاد علی ، میگم اتوپلی نمیتونه آرایه ای از رشته []string ارسال کنه . درسته؟
همینطور نمیتونه آرایه ای از کاراکترها ارسال کنه . درسته؟
چون متد MemoryExOOP:SetArrayType در پلاگین MemoryEx این دو نوع رو ساپورت نمیکنه . درسته؟
شما نمیدونین نوع هایی مثل WORD (نام ثابت کاملش MEMEX_ARR_WORD) و DWORD و QWORD در این متد MemoryExOOP:SetArrayType در این پلاگین ، چیه؟ آخه من توی هیچ زبانی نوع word و ... ندیدم!
 

the_king

مدیرکل انجمن
سلام
استاد علی ، میگم اتوپلی نمیتونه آرایه ای از رشته []string ارسال کنه . درسته؟
همینطور نمیتونه آرایه ای از کاراکترها ارسال کنه . درسته؟
چون متد MemoryExOOP:SetArrayType در پلاگین MemoryEx این دو نوع رو ساپورت نمیکنه . درسته؟
شما نمیدونین نوع هایی مثل WORD (نام ثابت کاملش MEMEX_ARR_WORD) و DWORD و QWORD در این متد MemoryExOOP:SetArrayType در این پلاگین ، چیه؟ آخه من توی هیچ زبانی نوع word و ... ندیدم!
آرایه ای از رشته []string رو در ذهن تون چطوری تفسیر می کنید؟ در نظر بگیرید که رشته استاندارد یک اشاره گر شروع میخواد و یک کاراکتر صفر یا null برای انتهای رشته.
اگه تفسیر من رو بپرسید، شما وقتی یک []string رو می فرستید دارید یک آرایه از اشاره گر رو می فرستید که باز هر کدوم از اون اشاره گر ها یک حافظه مجزا برای یک رشته رو نشانه رفته اند. یعنی اگه چهار تا رشته رو بفرستید پنج تا حافظه مجزا باید تخصیص بدهید، یکی برای مقادیر اشاره گر ها و چهار تا برای رشته ها.

خود اتوپلی که بجز CallFunction چیزی نداره که اونم یک مقدار عددی 32 بیتی LONG داره و یک رشته ANSI، همین. آرایه ارسال نمی کنه.
این محدودیت هایی که میگید ربطی به خود اتوپلی هم که نداره، دارید در مورد یک پلاگین خاص صحبت می کنید. در ضمن اینجا انجمن زبان های #C++/C/C ئه، انجمن اتوپلی یا پلاگین هاش که نیست که بخواهیم در مورد اونها صحبت کنیم. اون نوع داده برای راهنمای نحوه پر کردن حافظه است وگرنه حافظه ای که ارسال میشه همیشه واحدش بایته و طولش هم تغییر نمی کنه.
قاعدتا اگه به طریقی داده رو داخل حافظه کپی کنید کفایت می کنه، اینکه MemoryEx از چه نوعی فرضش می کرد مهم نیست، چه بایت بایت و چه چهار بایت چهار بایت پر بشه مهم اینه که مقدار داخل حافظه چی باشه.

WORD و DWORD و QWORD واحد اندازه گیری داده بر حسب پردازنده اند، مثلا واحد های 16 بیتی یا 32 بیتی. منظور اینه که فرضا نشون بده فلان پردازنده در هر دستور بهمان اش چه اندازه داده ای رو پردازش می کنه.
در معماری های مختلف که پردازنده های متفاوتی دارند طولشون هم فرق می کنه پس حرفی که می زنم فعلا و در مورد کامپیوتر های شخصی سازگار با پردازده های اینتل صدق می کنه، WORD یک واحد 16 بیتی ئه یا دو بایتی. DWORD دابل اونه، یعنی دو برابر WORD میشه، پس DWORD یک واحد 32 بیتی یا 4 بایتی ئه. QWORD چهار برابر WORD ئه، پس QWORD یک واحد 64 بیتی یا 8 بایتی ئه.
اگه با #C مقایسه کنید، WORD معادل short یا Int16 و DWORD معادل int یا Int32 و QWORD معادل long یا Int64 خواهد بود.
جزئی از تعاریف پایه برنامه نویسی ویندوز هم هستند، اینجا تعریف شون بر اساس ++C هست :
Windows Data Types
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
آرایه ای از رشته []string رو در ذهن تون چطوری تفسیر می کنید؟ در نظر بگیرید که رشته استاندارد یک اشاره گر شروع میخواد و یک کاراکتر صفر یا null برای انتهای رشته.
اگه تفسیر من رو بپرسید، شما وقتی یک []string رو می فرستید دارید یک آرایه از اشاره گر رو می فرستید که باز هر کدوم از اون اشاره گر ها یک حافظه مجزا برای یک رشته رو نشانه رفته اند. یعنی اگه چهار تا رشته رو بفرستید پنج تا حافظه مجزا باید تخصیص بدهید، یکی برای مقادیر اشاره گر ها و چهار تا برای رشته ها.


سلام
ممنون استاد علی :rose:
نظر که نه ولی درستش این باید باشه که رشته ، آرایه ای از کاراکترهاست دیگه؟! و آرایه ای از رشته ها میشه آرایه ی 2 بعدی (در واقع در سی شارپ میشه jagged array ای که 2 بعد باشه) از کاراکترها که حالا هر کاراکتر ، 2 بایت رو اشغال میکنن دیگه؟!
با توضیحات زیر که دادین پس این پلاگین فقط میتونه آرایه ای از اعداد ارسال کنه (چون WORD و ... در واقع همون int32 و ... که گفتین میشن) . پس یه راه میمونه و اگه اون شدنی باشه . اونم راه ارسال آرایه ی چند بعدی با این پلاگین هه (یعنی آرایه ی 2 بعدی توسط این پلاگین MemoryEx که عضو داخلی آرایه ، خودش آرایه ای از اعداد به عنوان کد اسکی کاراکتر مورد نظر رو بفرسته یعنی در واقع هر آرایه ی داخلی ، خودش یه رشته بشه)
کلا فرستادن آرایه ی 2 بعدی توسط پلاگین MemoryEx امکان پذیره؟ اگه آره ، چه تغییراتی باید توی کد زیر که دادین ، داد؟ :


کد:
myArrSize = 5 * 4;
handleArray = MemoryEx.AllocateEx(myArrSize);
pointerArray = handleArray:GetPointer();
handleArray:SetArrayType(MEMEX_ARR_INT);
handleArray[0] = 1;
handleArray[1] = 2;
handleArray[2] = 3;
handleArray[3] = 4;
handleArray[4] = 5;

البته توی لوا ، تعریف آرایه ی 2 بعدی بصورت زیر امکان پذیره :

کد:
myArr2D = {};

myArr2D[0] = {};
myArr2D[1] = {};
myArr2D[2] = {};

myArr2D[0][0] = 10;
myArr2D[0][1] = 20;

myArr2D[1][0] = 100;
myArr2D[1][1] = 200;

myArr2D[2][0] = 1000;
myArr2D[2][1] = 2000;
ولی خوب بصورت آرایه ی عادی و بدون استفاده از اون پلاگین که گفتین سازگار نیستن


خود اتوپلی که بجز CallFunction چیزی نداره که اونم یک مقدار عددی 32 بیتی LONG داره و یک رشته ANSI، همین. آرایه ارسال نمی کنه.
این محدودیت هایی که میگید ربطی به خود اتوپلی هم که نداره، دارید در مورد یک پلاگین خاص صحبت می کنید. در ضمن اینجا انجمن زبان های #C++/C/C ئه، انجمن اتوپلی یا پلاگین هاش که نیست که بخواهیم در مورد اونها صحبت کنیم. اون نوع داده برای راهنمای نحوه پر کردن حافظه است وگرنه حافظه ای که ارسال میشه همیشه واحدش بایته و طولش هم تغییر نمی کنه.
قاعدتا اگه به طریقی داده رو داخل حافظه کپی کنید کفایت می کنه، اینکه MemoryEx از چه نوعی فرضش می کرد مهم نیست، چه بایت بایت و چه چهار بایت چهار بایت پر بشه مهم اینه که مقدار داخل حافظه چی باشه.

WORD و DWORD و QWORD واحد اندازه گیری داده بر حسب پردازنده اند، مثلا واحد های 16 بیتی یا 32 بیتی. منظور اینه که فرضا نشون بده فلان پردازنده در هر دستور بهمان اش چه اندازه داده ای رو پردازش می کنه.
در معماری های مختلف که پردازنده های متفاوتی دارند طولشون هم فرق می کنه پس حرفی که می زنم فعلا و در مورد کامپیوتر های شخصی سازگار با پردازده های اینتل صدق می کنه، WORD یک واحد 16 بیتی ئه یا دو بایتی. DWORD دابل اونه، یعنی دو برابر WORD میشه، پس DWORD یک واحد 32 بیتی یا 4 بایتی ئه. QWORD چهار برابر WORD ئه، پس QWORD یک واحد 64 بیتی یا 8 بایتی ئه.
اگه با #C مقایسه کنید، WORD معادل short یا Int16 و DWORD معادل int یا Int32 و QWORD معادل long یا Int64 خواهد بود.
جزئی از تعاریف پایه برنامه نویسی ویندوز هم هستند، اینجا تعریف شون بر اساس ++C هست :
Windows Data Types

ممنون :rose:
 

the_king

مدیرکل انجمن

سلام
ممنون استاد علی :rose:
نظر که نه ولی درستش این باید باشه که رشته ، آرایه ای از کاراکترهاست دیگه؟! و آرایه ای از رشته ها میشه آرایه ی 2 بعدی (در واقع در سی شارپ میشه jagged array ای که 2 بعد باشه) از کاراکترها که حالا هر کاراکتر ، 2 بایت رو اشغال میکنن دیگه؟!

دقیقا همون jagged array آرایه است، اما ساختار jagged array در حافظه رو در نظر بگیرید. اگه دارید از سمت اتوپلی حافظه اش رو ایجاد می کنید مهمه که بدونید چطوری ایجاد میشه.
اگر ANSI باشه یک بایتی و اگه Unicode باشه دو بایتی و اگه UTF-8 باشه طول متغیر داره.


با توضیحات زیر که دادین پس این پلاگین فقط میتونه آرایه ای از اعداد ارسال کنه (چون WORD و ... در واقع همون int32 و ... که گفتین میشن) . پس یه راه میمونه و اگه اون شدنی باشه . اونم راه ارسال آرایه ی چند بعدی با این پلاگین هه (یعنی آرایه ی 2 بعدی توسط این پلاگین MemoryEx که عضو داخلی آرایه ، خودش آرایه ای از اعداد به عنوان کد اسکی کاراکتر مورد نظر رو بفرسته یعنی در واقع هر آرایه ی داخلی ، خودش یه رشته بشه)
کلا فرستادن آرایه ی 2 بعدی توسط پلاگین MemoryEx امکان پذیره؟ اگه آره ، چه تغییراتی باید توی کد زیر که دادین ، داد؟ :
شاید راه ساده تری باشه، من نه تسلط ای به MemoryEx دارم و نه حقیقتش علاقه ای.
کد:
myArrSize = 3 * 4;
handleArray = MemoryEx.AllocateEx(myArrSize);
pointerArray = handleArray:GetPointer();
handleArray:SetArrayType(MEMEX_ARR_DWORD);
s1 = MemoryEx.AllocateEx(1024);
s2 = MemoryEx.AllocateEx(1024);
s3 = MemoryEx.AllocateEx(1024);
handleArray[0] = s1:GetPointer();
handleArray[1] = s2:GetPointer();
handleArray[2] = s3:GetPointer();
MemoryEx.String(handleArray[0], -1, MEMEX_UNICODE, "First line.");
MemoryEx.String(handleArray[1], -1, MEMEX_UNICODE, "Second line.");
MemoryEx.String(handleArray[2], -1, MEMEX_UNICODE, "Third line.");
dllHdl = Library.Load("Test.dll");
if (dllHdl) then
    dllHdl.Test2(pointerArray, 3);
    dllHdl:Close_();
    MemoryEx.Free(s1);
    MemoryEx.Free(s2);
    MemoryEx.Free(s3);
    MemoryEx.Free(handleArray);
end

کد:
        [DllExport("Test2", CallingConvention.StdCall)]
        public static void Test2(IntPtr ptr, int count)
        {
            var arr = new string[count];
            for (int i = 0; i < count; i++)
            {
                var sptr = Marshal.ReadIntPtr(ptr, i * IntPtr.Size);
                arr[i] = Marshal.PtrToStringUni(sptr);
            }
            MessageBox.Show(string.Join(Environment.NewLine, arr), "Test2", MessageBoxButtons.OK);
        }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
دقیقا همون jagged array آرایه است، اما ساختار jagged array در حافظه رو در نظر بگیرید. اگه دارید از سمت اتوپلی حافظه اش رو ایجاد می کنید مهمه که بدونید چطوری ایجاد میشه.
اگر ANSI باشه یک بایتی و اگه Unicode باشه دو بایتی و اگه UTF-8 باشه طول متغیر داره.


شاید راه ساده تری باشه، من نه تسلط ای به MemoryEx دارم و نه حقیقتش علاقه ای.
کد:
myArrSize = 3 * 4;
handleArray = MemoryEx.AllocateEx(myArrSize);
pointerArray = handleArray:GetPointer();
handleArray:SetArrayType(MEMEX_ARR_DWORD);
s1 = MemoryEx.AllocateEx(1024);
s2 = MemoryEx.AllocateEx(1024);
s3 = MemoryEx.AllocateEx(1024);
handleArray[0] = s1:GetPointer();
handleArray[1] = s2:GetPointer();
handleArray[2] = s3:GetPointer();
MemoryEx.String(handleArray[0], -1, MEMEX_UNICODE, "First line.");
MemoryEx.String(handleArray[1], -1, MEMEX_UNICODE, "Second line.");
MemoryEx.String(handleArray[2], -1, MEMEX_UNICODE, "Third line.");
dllHdl = Library.Load("Test.dll");
if (dllHdl) then
    dllHdl.Test2(pointerArray, 3);
    dllHdl:Close_();
    MemoryEx.Free(s1);
    MemoryEx.Free(s2);
    MemoryEx.Free(s3);
    MemoryEx.Free(handleArray);
end

کد:
        [DllExport("Test2", CallingConvention.StdCall)]
        public static void Test2(IntPtr ptr, int count)
        {
            var arr = new string[count];
            for (int i = 0; i < count; i++)
            {
                var sptr = Marshal.ReadIntPtr(ptr, i * IntPtr.Size);
                arr[i] = Marshal.PtrToStringUni(sptr);
            }
            MessageBox.Show(string.Join(Environment.NewLine, arr), "Test2", MessageBoxButtons.OK);
        }

سلام
واقعا ممنونم استاد علی:rose:
ولی من این خط رو توی سی شارپ متوجه نشدم دقیقا چی کار میکنه؟ :

کد:
var sptr = Marshal.ReadIntPtr(ptr, i * IntPtr.Size);

و علاوه بر اون ، همینطور این پروپرتی IntPtr.Size چیه و چی رو محاسبه میکنه؟
 

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

بالا