نمایش نتایج 1 تا 12 از 12

نام تاپیک: dispose کردن یک شی

  1. #1
    کاربر دائمی
    تاریخ عضویت
    مرداد 1388
    محل زندگی
    کنار یه ساحل خیلی زیبا
    پست
    922

    dispose کردن یک شی

    با سلام به همه اساتید
    من یه کد نوشتم و از اشیایی استفاده کردم و در آخر اونا رو dispose کردم اما باز کد آنالیزر ویژوال استدیو رو که اجرا میکنم میگه برای این اشیا اینترفیس Idispose رو پیاده سازی کن
    کدهای من
     DataTable dt = new DataTable();
    SqlDataAdapter dataAdapter = new SqlDataAdapter("loaddall", connection);
    dataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
    dataAdapter.Fill(dt);
    dataGridView1.DataSource = dt;
    dt.Dispose();
    dataAdapter.Dispose();

    حتی این کد رو به این صورت نوشتم اما باز همون هشدار ها رو میده
     DataTable dt = new DataTable();
    SqlDataAdapter dataAdapter = new SqlDataAdapter("loaddall", connection);
    dataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
    dataAdapter.Fill(dt);
    dataGridView1.DataSource = dt;
    dt.Dispose();
    dataAdapter.Dispose();
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    آیا من نکته ای رو رعایت نمیکنم یا این گیر میده>؟!!!!!!!!!!!
    هشدار"Warning 1 CA2000 : Microsoft.Reliability : In method object 'dataAdapter' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'dataAdapter' before all references to it are out of scope.
    "

    وقتی هم که از بلاک یوزینگ استفاده میکنم خب یک شی بیشتر که نمیشه تعریف کرد؟!!!

  2. #2
    مدیر بخش آواتار مهرداد صفا
    تاریخ عضویت
    تیر 1391
    محل زندگی
    select Country,City From World where Country.Name=IRAN and City.Contains(حضرت معصومه(ع))
    پست
    1,499

    نقل قول: dispose کردن یک شی

    نقل قول نوشته شده توسط esafb52 مشاهده تاپیک
    وقتی هم که از بلاک یوزینگ استفاده میکنم خب یک شی بیشتر که نمیشه تعریف کرد؟!!!
    سلام.
    به این صورت عمل کنید:

    using (DataTable table2 = new DataTable())
    {
    using (SqlDataAdapter adapter2 = new SqlDataAdapter("select * from sys.databases", "server=.\\sqlexpress;integrated security=true;"))
    {
    adapter2.Fill(table2);
    dataGridView1.DataSource = table2;
    }
    }
    چشم ظاهر گر نبیند عیب نیست چشم دل گر ننگرد باید گریست
    **********
    اَلسَّلامُ عَلَى الْحُسَيْنِ وَ عَلى عَلِىِّ بْنِ الْحُسَيْنِ وَ عَلى اَوْلادِ الْحُسَيْنِ وَ عَلى اَصْحابِ الْحُسَيْنِ

  3. #3
    کاربر دائمی
    تاریخ عضویت
    مرداد 1388
    محل زندگی
    کنار یه ساحل خیلی زیبا
    پست
    922

    نقل قول: dispose کردن یک شی

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

  4. #4
    مدیر بخش آواتار مهرداد صفا
    تاریخ عضویت
    تیر 1391
    محل زندگی
    select Country,City From World where Country.Name=IRAN and City.Contains(حضرت معصومه(ع))
    پست
    1,499

    نقل قول: dispose کردن یک شی

    نقل قول نوشته شده توسط esafb52 مشاهده تاپیک
    ولی چرا اون Dispose ها عمل نمیکنن اگر هم عمل میکنن پس اون پیام دلیلش چیه؟
    شاید به این دلیل که ممکن است قبل از اینکه برنامه به خط مربوط به dispose برسد exception اتفاق بیفتد. در چنین حالتی استفاده از using باعث می شود object به طور خودکار dispose شود.
    چطور میشه حافظه اختصاص یافته به یک شی رو دید که چقدر است
    لطفا در یک تاپیک مجزا مطرح کنید.
    چشم ظاهر گر نبیند عیب نیست چشم دل گر ننگرد باید گریست
    **********
    اَلسَّلامُ عَلَى الْحُسَيْنِ وَ عَلى عَلِىِّ بْنِ الْحُسَيْنِ وَ عَلى اَوْلادِ الْحُسَيْنِ وَ عَلى اَصْحابِ الْحُسَيْنِ

  5. #5
    کاربر دائمی
    تاریخ عضویت
    مرداد 1388
    محل زندگی
    کنار یه ساحل خیلی زیبا
    پست
    922

    نقل قول: dispose کردن یک شی

    به این صورت نوشتم حل شد میذارم اینجا دوستان هم استفاده کنند
    try
    {
    dt = new DataTable();
    dataAdapter = new SqlDataAdapter("loaddall", connection);
    dataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
    dataAdapter.Fill(dt);
    dataGridView1.DataSource = dt;
    }
    finally
    {
    dt.Dispose();
    dataAdapter.Dispose();
    }

  6. #6
    کاربر دائمی آواتار FastCode
    تاریخ عضویت
    تیر 1388
    محل زندگی
    /dev/null
    پست
    3,486

    نقل قول: dispose کردن یک شی

    لطفا GC.Collect(); رو بدون اینکه حتی یک خط راجع بهش تحقیق کرده باشید صدا نزنید.اونکاری که فکر میکنی رو نمیکنه.

  7. #7
    کاربر دائمی
    تاریخ عضویت
    مرداد 1388
    محل زندگی
    کنار یه ساحل خیلی زیبا
    پست
    922

    نقل قول: dispose کردن یک شی

    با سلام جناب استاد فست کد اتفاقا یه مقدار راجبش خوندم مفدترینش چیزهایی که من خوندم اینا هستن

    وقتی شما Object ای رو new می کنید، باعث میشید تا ctor اون Object فراخوانی بشه. اما در مورد destructor ها وقتی اون object رو null میذارید، destructor فراخوانی نمیشه. در واقع شما کنترلی روی زمان فراخوانی اون ندارید. destructor وقتی فراخوانی میشه که GC صلاح بدونه. اما GC چی هستش؟ Garbage Collector یا همون GC، مدیریت تخصیص و آزادسازی حافظه یه برنامه رو در .NET به عهده داره. همه چیز در heap مدیریت شده رخ میده، heap ای که بسیار شبیه Heap کدهای native هستش با این تفاوت که Object ها توسط برنامه نویس آزاد نمیشن، بلکه هنگامی آزاد میشن که دیگه نیازی بهشون نیست. (بد نیست بدونید که GC در درون خودش حاوی pointer به object هایی هستش که تو heap مدیریت شده نگه داشته میشه. به این pointer ها root میگن. وقتی برنامه شروع به کار میکنه یا هر وقت شما Object ای رو new می کنید، CLR یه graph از root ها رو میگیره و تو یه زمان از پیش تعیین شده شروع به آزاد سازی همه اون object هایی میکنه که root اونها null شده. هر وقت شما یه object ای رو که new کردین، مساوی null بذارین، سیستم تشخصی میده و root مربوط به اون object رو هم null میکنه تا بعدا بتونه سر فرصت اونهایی که null هستن رو، release کنه).

    اما سیستم از کجا می خواد بفهمه که دیگه نیازی به یه Object نیست؟ برای فهمیدن جواب این سوال ایتدا باید بدونیم که C#‎‎ دو نوع عمومی از type ها رو پشتیبانی میکنه: value type ها و Reference Type ها.

    value-type ها تایپهای enum، built-in ها و struct ها هستن. اونها میتونند مستقیم مقادیر رو در خودشون حفظ کنن. Stack، حافظه ای هستش که این نوع تایپها توسط سیستم در اون نگهداری میشن. در مقابل reference-type ها رو داریم، که در واقع reference یا pointer به یک instance رو در stack نگه میدارن و خود instance رو در heap مدیریت شده. البته من قبلا در مورد value-type ها و reference ها در این پست توضیحاتی داده بودم که خوندنش خالی از لطف نیست.

    اما چه اتفاقی می افته وقتی شما یه Object ای رو new می کنید؟ CLR فرض میکنه که حافظه سیستم نامحدوده و شروع به تخصیص حافظه بصورت ترتیبی می کنه. یعنی خونه به خونه حافظه رو میره جلو و اختصاص میده به Object هایی که شما new می کنید. اما واقعیت اینه که سیستم، حافظه محدودی داره و تا ابد نمیتونه این مساله ادامه پیدا کنه، پس یه نفر باید فضاهای بلا استفاده تو heap رو آزاد کنه و اینجاست که GC توسط root هایی که بالا توضیح دادم، اقدام به آزادسازی حافظه می کنه. اما هنوز یه کار دیگه هم باید انجام بشه، و اون Compact کردن حافظه هستش. اما همه این مراحل به نظرتون باندازه کافی سریع هستش؟ فکرش رو کنید، وقتی GC شروع به آزاد سازی حافظه کنه، باید بره لیست همه root هایی که مساوی null هستن رو بیاره و دونه به دونه اقدام به آزادسازی اونا کنه که کاملا مشخصه که بسیار روند کندی هستش.

    پس اومدن گفتن جای اینکه تو یه فاز بریم و object هایی که root اونها الان null هست رو آزاد کنیم، بیاییم این کار رو تو چند مرحله انجام بدیم. اما با توجه به این مفروضات که اولا Compact کردن بخشی از heap سریعتر از compact کردن کل heap هستش و ثانیا Object های قدیمیتر احتمالا بیشتر باقی می مونن تا object های جدیدتر.

    اما فازها: گفتن ما 3 تا فاز تعریف میکنیم. فاز اول وقتی هستش که یه object ای new میشه. همه object هایی که new میشن تو فاز 1 ذخیره میشن تا وقتی که فاز یک پر بشه. هر وقت این اتفاق افتادش، GC شروع به آزادسازی تمام Object هایی میکنه که دیگه جایی reference نشدن و مابقی که هنوز در حال استفاده هستن compact میشن و به سمت چپ میان. (حافظه رو خونه های چپ به راست افقی در نظر بگیرید). تمام Object هایی که باقی می مونن (یعنی هنوز در حال استفاده هستن)، میرن تو فاز 2. وقتیکه دوباره فاز 1 پر شدش، همه Object هایی که تو فاز 2 بودن میرن تو فاز 3. هر وقت هر 3 فاز پر بشن، OutOfMemoryException، داده میشه.

    ////////////////////
    بحث مدیریت حافظه ،یکی از بحث های مهم در عرصه نرم افزار نویسی است.مثلا شرکت موزیلا بعد از FIreFox2 یک فراخوان برای برنامه نویس ها میده تا مشکل استفاده از حافظه زیاد موقع بارگذاری رو کم کنه (و انصافا توی FireFox3 موفق هم بوده).این مطلب اونقدر در مورد این نرم افزار مهم بوده که طرفدارای دو آتشه IE این مشکل رو به عنوان اولین ایراد FireFox مطرح می کردند!
    با این موضوع که در نرم افزار های داخلی هم این مطلب رعایت نمیشه (البته معمولا) موافقم.شاید به این دلیل که برنامه نویسی که داره برنامه رو می نویسی ،خودش روی یک سیستم آنچنانی (از نرم افزار تا سخت افزار) کار می کنه و نمی دونه بعضی ها می خواهند این نرم افزار رو روی یک سیستم با حداقل امکانات اجرا کنند! به همین دلیل سینه چاک های VB زیادن و VC کارها کم! در هر حال بگذریم....

    اما دوستان به منابع مدیریت شده (که مقصود مدیریت توسط GC) و منابع مدیریت نشده (که همچنان کمافی السابق باید توسط برنامه نویس مدیریت بشه - مثل فایلها ، Connection ها و ...) اشاره کردند.ولی قبل از این که در مورد این دو سئوال که 'آیا این بیهوده نبوده که متغیرهای محلی dt وda را هم Dispose کرده' و 'آیا این کلاس مدیریت شده است' با هم بحث کنیم.می خواهم یک بار دیگر مراحل کار GC رو مرور کنیم (هر چند همه می دونیم ولی برای استناد به اون به تکرار نیازه!).درضمن این مطالب برای انواع دارای نوع Refence است نه انواع مقدار (مثل int یا struct و ..).

    1) وقتی از کلمه کنیدی new استفاده می کنید،CLR یک فضا برای اون تخصیص داده و به GC اعلام می کنه کی متغیر جدید داره و یک شمارنده Refrence برای اون ایجاد میکنه!
    2) اگر این فضای تخصیص داده شده به متغیری تخصیص داده بشه (مثلا متغیری که به این فضا اشاره دارد به متغیر دیگری تخصیص داده بشه)،به شکل اتوماتیک به شمارنده Refrence افزوده می شه.به همین دلیل است که دات نت اجازه پیاده سازی عملگر انتساب (=) رو به برنامه نویسی نمی ده (در یک کلاس همه عملگر ها به غیر از انتساب قابل پیاده سازی هستند!).
    3) هنگامی که یک متغیر نابود می شه (مثلا یک متغیر محلی که با خروج از تابع نابود میشه)،یا متغیری که قبلا یک Refrence به محلی از حافظه داشته،حالا اشاره به محل دیگه ای کنه (با انتساب مقدار دیگه ای به اون)،به شکل اتوماتیک از شمارنده Refrence کاسته می شه.توجه کنید که به محض به صفر رسیدن این شمارنده ،فضای مورد بجث آزاد نمیشه!
    4) هر گاه GC اقدام به پاک سازی حافظه کنه (اینجاست که زمان این کار معلوم نیست) ،دو عملیات رخ میده اول اینکه فضا هایی که شمارنده Refrence اونها صفر است ،رها سازی می شوند.دوم تمام اطلاعات موجود در حافظه دوباره باز آرایی میشوند تا فضا های مورد استفاده در کنار هم قرار گیرند (بحث Boxing هم مربوط به این کار GC است).البته برنامه نویس با برنامه متوجه جابجایی اطلاعات در حافظه نمی شوند و عملا با همان Refrence که در متغیر ها هستند دسترسی به مقادیر ممکن است!(باید بگم این بحث کاملتر از این توضیح کوچک است ولی تا همینجا کافی به نظر می رسه).

    حالا سئوال اینه که 'کی GC اقدام به رها سازی حافظه می کنه (مرحله4)؟'.زمان این عمل معلوم نیست (درضمن این عملیات دریک Thread مستقل از Thread اصلی انجام میشه).شاید چند ثانیه نیز طول بکشه! پس نتیجه میگیریم که بین مراحل سوم و چهارم ،با اینکه دیگر نیاز به حافظه مورد نحث نیست،ولی هنوز در حافظه مکانی برای آن منظور شده.شاید برای متغیر های کوچک ،خیلی مهم نباشد ولی برای متغیر هایی با حافظه مصرفی بزرگ،قطعا می تواند نگران کننده باشد.
    برای این کار دو راه حل را میشناسم (راه های دیگری هم شاید باشد که من از آن بی خبر باشم).راه اول استفاده از متد Dispose اشیای است.در این حالت فضای مصرفی آنها تا حد امکان کوچک میشود.مثلا کد زیر را در یکی از صفحات همین سایت دیدم :

    public void PaintGradient(Control _control, LinearGradientMode _direction, Color _gradientColorStart, Color _gradientColorEnd)
    {
    //https://barnamenevis.org/showpost.php...3&postcount=35
    LinearGradientBrush gradBrush;
    gradBrush = new LinearGradientBrush(new Rectangle(0, 0, _control.Width, _control.Height), _gradientColorStart, _gradientColorEnd, _direction);
    Bitmap bmp = new Bitmap(_control.Width, _control.Height);
    Graphics g = Graphics.FromImage(bmp);
    g.FillRectangle(gradBrush, new Rectangle(0, 0, _control.Width, _control.Height));
    _control.BackgroundImage = bmp;
    _control.BackgroundImageLayout = ImageLayout.Stretch;
    }



    به نظر شما فراخوانی یک متد مثل Paint برای یک کنترل چند بار صورت می گیرد.شاید چندین بار در یک ثانیه.البته در یک پیاده سازی بد می توان این مقدار را به چند هزار بار در یک ثانیه رساند (توجه کنید که فراخوانی یک متد مثل این، کاملا به پیاده سازی وابسته است).همینطور که ملاحظه می کنید شی gradBrush هرگز نابود نمی شود تا وقتی که GC به حسابش برسد! حالا اگر فرض کنید که در یک برنامه این متد چند ده بار در ثانیه فراخوانی شود و GC نیز 5 ثانیه یک بار عمل کند (تکرار می کنم : این که GC کی عمل کند به خیلی عوامل وابسته بوده و قابل پیش بینی نیست!).در نتیجه تا زمانی که GC عمل کند ،چه مقدار حافظه،بی مورد مصرف شده است!در حالی که در انتهای این متد می توان با یک خط ساده مثل
    gradBrush.Dispose();

    این حافظه را به سیستم برگرداند!در این متد فقط یک متغیر اینگونه است.ممکن است در برنامه های بزرگتر،تعداد متغیر ها هم بیشتر و هم فضای مورد استفاده آنها بزرگتر و تعداد فراخوانی آنها بیشتر باشد! پس بهتر است در کلاس هایمان اولا عادت کنیم که متد Dispose را پیاده سازی کنیم و ثانیا در انتهای هر متد متغیر های بلا مصرف را Dispose کنیم (کار از محکم کاری عیب نمی کند!).توجه کنید که مخرب کلاس (destructor) در فرایند مرحله 4 GC فراخوانی می شود.
    راه حل دوم هم استفاده از متدهای خوده GC است مثل Collect و WaitForPendingFinalizers (این متد Thread اصلی را می خواباند تا فرآیند پاک سازی حافظه انجام شود.به عبارت دیگر یک جور فعال سازی GC برای مرحله 4 است)،که معمولا به شکل
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();



    و چند تا دیگه

  8. #8
    کاربر دائمی
    تاریخ عضویت
    تیر 1389
    محل زندگی
    به جبر روزگار تهران هستم.
    پست
    2,718

    نقل قول: dispose کردن یک شی

    نقل قول نوشته شده توسط esafb52 مشاهده تاپیک
    ولی چرا اون Dispose ها عمل نمیکنن اگر هم عمل میکنن پس اون پیام دلیلش چیه؟
    چطور میشه حافظه اختصاص یافته به یک شی رو دید که چقدر است
    ممنون
    سلام دوست من.
    این کد رو بذار توی فرم لود :
    Timer memoryWatcher = new Timer();
    memoryWatcher.Interval = 500;
    memoryWatcher.Tick += (o, a) =>
    {
    Process app = Process.GetCurrentProcess();
    this.Text = "Total Memory used : " + ((app.PrivateMemorySize / 1024) / 1024).ToString("0 MB");
    this.Text += "\t And Total Time Elapsed : " + app.TotalProcessorTime.ToString();
    };

    memoryWatcher.Start();

    یه گرید بذار روی فرم و این کد رو هم داخل یه دکمه بذار :
    DataTable dt = new DataTable();
    dt.Columns.Add("Row");
    dt.Columns.Add("FirstName");
    dt.Columns.Add("LastName");
    dt.Columns.Add("Address");
    //
    for (int i = 1; i <= 750000; i++)
    {
    dt.Rows.Add(i, "AliReza", "Akbari", "Iran - Tehran");
    }
    datagridview1.DataSource = dt;

    حالا دیتاتیبل رو dispose کن.نتیجه جالبی رخ میده.
    خواهی دید که هیچ اتفاقی نمی افته و حافظه تخصیص داده شده به دیتاتیبل باز پس گرفته نمیشه. (میتونی از task manager هم رم سیستمت رو زیر نظر بگیری).

  9. #9
    کاربر دائمی
    تاریخ عضویت
    مرداد 1388
    محل زندگی
    کنار یه ساحل خیلی زیبا
    پست
    922

    نقل قول: dispose کردن یک شی

    اتفاقا جناب veniz2008
    من این کد رو تست کردم و نتیجه هم داد شما هم تست کنید
     try
    {
    dt = new DataTable();
    dataAdapter = new SqlDataAdapter("loaddall", connection);
    dataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
    dataAdapter.Fill(dt);
    dataGridView1.DataSource = dt;
    long m = GC.GetTotalMemory(true);
    MessageBox.Show(m.ToString());
    }
    finally
    {
    dt.Dispose();
    dataAdapter.Dispose();
    long m = GC.GetTotalMemory(true);
    MessageBox.Show(m.ToString());

    }

  10. #10
    کاربر دائمی
    تاریخ عضویت
    تیر 1389
    محل زندگی
    به جبر روزگار تهران هستم.
    پست
    2,718

    نقل قول: dispose کردن یک شی

    دوست من، متد GetTotalMemory میزان حافظه مصرفی رو برحسب بایت نمایش میده. ولی همونطور که گفتم کدهایی که نوشتید رم مصرفی رو به سیستم بر نمیگردونه. با dispoce نمیتونید تضمین کنید که حافظه مصرفی برگشت داده بشه.
    آخرین ویرایش به وسیله veniz2008 : چهارشنبه 02 بهمن 1392 در 17:24 عصر

  11. #11
    کاربر دائمی
    تاریخ عضویت
    مرداد 1388
    محل زندگی
    کنار یه ساحل خیلی زیبا
    پست
    922

    نقل قول: dispose کردن یک شی

    نقل قول نوشته شده توسط veniz2008 مشاهده تاپیک
    دوست من، متد GetTotalMemory میزان حافظه مصرفی رو برحسب بایت نمایش میده. ولی همونطور که گفتم کدهایی که نوشتید رم مصرفی رو به سیستم بر نمیگردونه. با dispoce نمیتونید حافظه رو پس بگیرید.
    پس چه جوری میشه این کار رو کرد؟ممنون میشم راهنمایی کنید یا لینکی چیزی بهم بدین
    ممنون

  12. #12
    کاربر دائمی آواتار FastCode
    تاریخ عضویت
    تیر 1388
    محل زندگی
    /dev/null
    پست
    3,486

    نقل قول: dispose کردن یک شی

    خیلیش درست بود و برای خیلیش هم دوست دارم مترجم رو از نزدیک ببینم.
    خیلی چیزها رو هم کلا نگفته بود.مثلا اصلا به LOH و سناریو های چند هسته ای اشاره نکرده.به روش علامتگزاری اشاره نکرده.به object های static اشاره نشده.روش تخصیص pointer ها رو توضیح نداده.اندازه heap ها رو توضیح نداده.object pinning رو هم خورده. و اصلا اسمی از Finalizer Queue نیاورده.در ضمن طوری مطلب رو بیان کرده که کاربر فکر میکنه هر لحظه در اجرای کدش ممکنه دستوری اجرا کنه که باعث بشه یک شیئ از حافظه حذف بشه.و این گوشه ای از ایراداتش بود.
    با این حال باز هم واقعا برای من جای تعجب است که شما اینها رو میدونی و باز هم از GC.Collect استفاده میکنی.البته ممکنه همه اش هم تقصیر شما نباشه.برای اینکه یک مقدار بهتر با موضوع آشنا بشید به نظر من بهتره یک مقدار راجع به Page Table ها ,TLB و اینکه سیستم عامل واقعا چه زمانی فکر میکنه یک نقطه از حافظه خالی هست تحقیق کنید.

تاپیک های مشابه

  1. نحوه صحیح dispose کردن view ها
    نوشته شده توسط biodread در بخش Android Studio
    پاسخ: 5
    آخرین پست: سه شنبه 14 خرداد 1392, 23:33 عصر
  2. سوال: برطرف کردن خطای can not access a dispose object
    نوشته شده توسط thviser در بخش C#‎‎
    پاسخ: 3
    آخرین پست: سه شنبه 23 خرداد 1391, 14:10 عصر
  3. سوال: Dispose کردن ViewModel
    نوشته شده توسط mehri_ema در بخش WPF
    پاسخ: 1
    آخرین پست: پنج شنبه 17 آذر 1390, 13:00 عصر
  4. کپی کردن یک فولدر
    نوشته شده توسط Gladiator در بخش برنامه نویسی در Delphi
    پاسخ: 5
    آخرین پست: سه شنبه 20 مرداد 1383, 10:56 صبح
  5. پیدا کردن مسیر ویندوز و ....
    نوشته شده توسط (امید) در بخش مباحث عمومی دلفی و پاسکال
    پاسخ: 4
    آخرین پست: سه شنبه 18 شهریور 1382, 01:24 صبح

قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •