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

1606683296_1_0.gif

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

استخراج اطلاعات از درون اسمبلی
پیش از اینکه درباره روش ساخت افزونه‌ها در دات‌نت بدانید، باید با مفاهیم مرتبط با این موضوع آشنا شوید. System.Reflection از جمله کتابخانه‌های پرکاربرد دنیای دات‌نت است. این کتابخانه ضمن آنکه دسترسی به اطلاعاتی درباره اسمبلی‌ها، ماژول‌ها، اعضا، پارامترها و دیگر عناصری را که در یک کد مدیریت‌شده قرار دارند، فراهم می‌کند، آن‌ها را بررسی کرده و متادیتاها (metadata) متعلق به آن‌ها را در اختیار برنامه‌نویسان قرار می‌دهد. با استفاده از متد‌ها و خاصیت‌های کتابخانه Reflection، برنامه‌نویس به صورت پویا در مدت زمان اجرای یک کد، می‌تواند اسمبلی خود را به صورت اختیاری بارگذاری کند. این تکنیک راه آسانی برای پیاده‌سازی ساختار پلاگین‌ها در اختیار برنامه‌نویسان قرار می‌دهد.

مطلب پیشنهادی

۸ ترفند افزایش امنیت اسناد آفیس
نکات امنیتی آفیس را جدی بگیرید

اما مهم‌ترین پرسش این است که چگونه می‌توان به انواع داده‌ای که در یک اسمبلی وجود دارد، دست پیدا کرد؟ پاسخ Reflection است که امکان کشف نوع‌های قرارگرفته در یک اسمبلی را به‌آسانی امکان‌پذیر می‌سازد. برای اینکه با نحوه کارکرد این کتابخانه بهتر آشنا شوید، باید آن را در عمل مشاهده کنید. برای این منظور ویژوال استودیو را باز کنید، در فهرست File روی گزینه New Project کلیک کرده و زبان برنامه‌نویسی سی‌شارپ را انتخاب کنید. در پانل میانی از میان الگوهای موجود، گزینه Windows Forms Application را انتخاب کنید. برای نشان دادن عناصر درون یک برنامه از کنترل Treeview استفاده کنید. این کنترل را به همراه یک دکمه (Button) و یک کنترل برچسب (LabelText) روی فرم قرار دهید. روی کنترل دکمه دوبار کلیک کنید تا رویداد مربوط به آن ساخته شود. در کنترل ساخته‌شده دستوراتی را که در فهرست شماره یک مشاهده می‌کنید، قرار دهید. در ابتدای برنامه خود لازم است تا کتابخانه using System.Reflection; را وارد کنید.
فهرست ۱ :

using System.Reflection;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog openfile = new OpenFileDialog();
            openfile.Filter = “Assemblies (*.exe،*.dll)|*.exe;*.dll|All files (*.*)|*.*”;

            if (openfile.ShowDialog() == DialogResult.OK)
            {
                AssemblyName.Text = openfile.FileName;
                Mytree.Nodes.Clear();

                Assembly assembly = Assembly.LoadFrom(AssemblyName.Text);
                foreach (Type t in assembly.GetTypes())
                {
                    TreeNode Nodes = new TreeNode(“TeeNode-> “ + t.Name);
                    Mytree.Nodes.Add(Nodes);

                    foreach (MethodInfo mi in t.GetMethods())
                    {
                        Nodes.Nodes.Add(new TreeNode(“Methods-> “ + mi.Name));
                    }

                    foreach (PropertyInfo pi in t.GetProperties())
                    {
                        Nodes.Nodes.Add(new TreeNode(“Properties-> “ + pi.Name));
                    }

                    foreach (FieldInfo fi in t.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic))
                    {
                        Nodes.Nodes.Add(new TreeNode(“FiledInfo-> “ + fi.Name));
                    }

                    foreach (EventInfo ei in t.GetEvents())
                    {
                        Nodes.Nodes.Add(new TreeNode(“Events-> “ + ei.Name));
                    }

                    foreach (Type ei in t.GetInterfaces())
                    {
                        Nodes.Nodes.Add(new TreeNode(“Interfaces-> “ + ei.Name));
                    }
                }
            }
        }
    }
}

برنامه را اجرا کنید. روی دکمه Browse کلیک کرده و یک فایل اسمبلی (exe یا dll) انتخاب کنید. پیشنهاد می‌شود فایل اجرایی خود برنامه را انتخاب کنید. خروجی فهرست شماره یک را در شکل 1 مشاهده می‌کنید.


شکل ۱

اما قطعه کد بالا دقیقاً چه کاری انجام می‌دهد؟ کلاس Assembly برای بارگذاری اسمبلی‌های دات‌نت استفاده می‌شود. این کلاس دسترسی به متادیتاها و بخش‌های اصلی موجود در یک اسمبلی را امکان‌پذیر می‌سازد. اگر به نوع‌های داده‌ای که در دامین جاری استفاده می‌شود نیاز دارید، از متد AppDomain.GetAssemblies استفاده کنید. بعد از بارگذاری اسمبلی مدنظر، برای دریافت اطلاعات داخلی آن باید تعدادی از متدها و خاصیت‌ها را فراخوانی کنید. متدهای استفاده‌شده در این قطعه کد بدین شرح هستند: 
• GetTypes: با فراخوانی این متد به نوع‌های تعریف‌شده در یک اسمبلی دسترسی خواهید داشت.
• PropertyInfo، MethodInfo، FieldInfo، EventInfo، Type: اطلاعات مربوط به یک خاصیت، متد، فیلد، رویداد و یک واسط را به‌همراه متادیتاهای مربوط به هر یک از اشیا یادشده، در اختیارتان قرار می‌دهد. این اطلاعات با خاصیت Name دریافت می‌شود و درون کنترل Tree قرار می‌گیرند.

تعریف کلاس پویا
بعضی مواقع نیاز به بارگذاری پویای نمونه‌ای از یک کلاس دارید. زمانی که قصد استفاده از یک کلاس را دارید، باید ارجاعی به اسمبلی که کلاس درون آن قرار دارد، در برنامه خود وارد کنید. در غیر این صورت کامپایلر پیغام خطای نشناختن کلاس یا عناصر مرتبط به آن را نشان می‌دهد. به کمک reflectionها، می‌توانید از کلاسی استفاده کنید که مرجع مربوط به آن کلاس در زمان ساخت برنامه کاربردی در آن ضمیمه نشده است. این کار با فراخوانی کتابخانه پویایی که کلاس درون آن قرار دارد، به همراه تعریف نام کلاس در متد GetType و در نهایت ساخت نمونه‌ای از کلاس مدنظر با فراخوانی متد CreateInstance انجام می‌شود. فهرست شماره دو نحوه پیاده‌سازی این کار را نشان می‌دهد. 
فهرست ۲ :

Assembly assembly = Assembly.LoadFrom(“MyDynamicFile.dll”);
Type type = assembly.GetType(“MyDynamicFile.MyClass”);
            object obj = Activator.CreateInstance(type);

با توجه به اینکه در این مدل فراخوانی، به مرجع اصلی کلاس دسترسی ندارید، در نتیجه امکان تعیین نوع واقعی شی وجود ندارد. برای این منظور از نوع object استفاده می‌شود.

دسترسی پویا به متدی که در کلاس پویا قرار دارد
کلاس‌ها زمانی به صورت پویا استفاده می‌شوند که متدهایی درون آن‌ها قرار داشته باشد. برای دسترسی به متدهای قرارگرفته در کلاسی که به شیوه پویا بارگذاری شده است، روش‌های مختلفی وجود دارد. فهرست شماره سه ساده‌ترین روش را نشان می‌دهد.
فهرست ۳: فراخوانی کلاس به همراه متد مربوط به آن

 Assembly assembly = Assembly.LoadFrom(“MyDynamicFile.dll”);
            Type type = assembly.GetType(“MyDynamicFile.MyClass”);
            object obj = Activator.CreateInstance(type);

            int result = (int)type.InvokeMember(“Rotate”، BindingFlags.Instance |
BindingFlags.InvokeMethod ،null، obj،new object[] { 90، 45 });

ساختار افزونه‌ها
حال که با مقدمات ساخت افزونه‌ها آشنا شدید، زمان آن رسیده است تا در عمل با نحوه ساخت افزونه‌ای ساده برای یک برنامه کاربردی آشنا شوید. ساخت افزونه برای این برنامه کاربردی در سه مرحله انجام می‌شود: 
1. ساخت رابط اصلی که یک رابط (افزونه) با کدهای اشتراکی است.
2. پیاده‌سازی هر افزونه در قالب پروژه‌ جداگانه در ویژوال استودیو -در این مقاله افزونه چرخش Rotate و تغییر رنگ Change Color- زمانی‌که هر یک از این افزونه‌ها جداگانه ساخته شدند، لازم است تا فایل‌های کامپایل شده (Dll) در مسیر فایل برنامه اصلی (exe) کپی شوند تا برنامه اصلی توانایی شناسایی و دسترسی به آن‌ها را داشته باشد.
3. در آخرین مرحله، برنامه اصلی ساخته می‌شود و دستورات لازم برای شناسایی و بارگذاری متدها و کلاس‌های قرارگرفته در افزونه‌ها در آن جای می‌گیرد.

• ساخت اسمبلی مشترک
در مرحله اول نیازمند یک اسمبلی هستید که هم برنامه اصلی و هم افزونه‌ به آن ارجاع داشته باشند. این اسمبلی رابطی را پیاده‌سازی می‌کند که هر افزونه باید در هر کد مشترکی که در نظر دارد به آن دسترسی داشته باشد، آن را پیاده‌سازی کند. ویژوال استودیو را اجرا کرده و پروژه‌ای از نوع Class Library به نام MainInterface ایجاد کنید. (شکل 2) در ادامه دستورات فهرست چهار را درون این کتابخانه وارد کنید.


شکل ۲

فهرست ۴:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MainInterface
{
    public interface MyImageAddon
    {
        System.Drawing.Image RunAddon(System.Drawing.Image image);
        string Name { get; }
    }
}

برای اجرای صحیح برنامه باید اسمبلی System.Drawing را در برنامه وارد کنید. روی نام پروژه کلیک‌راست کرده و از زیرفهرست Add گزینه Reference را انتخاب کنید. در پنجره ظاهرشده گزینه System.Drawing را انتخاب کنید. (شکل 3) برنامه را یک بار دیگر کامپایل کنید تا فایل کتابخانه پویای ساخته شود. 


شکل ۳  

 

• ساخت افزونه
در این مرحله قصد داریم افزونه خود را طراحی کنیم. افزونه‌ مدنظر از رابط MainInterface ارث‌بری می‌کند. در نتیجه متد و خاصیت تعریف‌شده در بخش قبل باید در آن پیاده‌سازی شود. در ویژوال استودیو، پروژه جدیدی از نوع Class Library به نام MyRotate ایجاد کنید. 
اولین کاری که در این مرحله باید انجام دهید، وارد کردن اسمبلی MainInterface در برنامه کاربردی است. روی پروژه کلیک‌راست کرده، گزینه Add Reference را انتخاب و اسمبلی MainInterface.dll را در پروژه کاربردی خود وارد کنید. برای این کار از دکمه Browse در پایین صفحه استفاده کنید و به مسیری بروید که پروژه قبلی در آن ساخته شده است. فایل dll درون پوشه bin قرار دارد. اضافه کردن این کتابخانه به‌منظور ارث‌بری از رابطی است که در بخش قبل ساختید.  
در مرحله بعد Class1 باید از رابط MyImageAddOn ارث‌بری کرده و در ادامه متد و خاصیت قرارگرفته در رابطی را که از آن ارث‌بری کرده است، پیاده‌سازی ‌کند. فهرست پنج نحوه پیاده‌سازی این فرایند را نشان می‌دهد. فراموش نکنید همانند پروژه قبلی مرجع متعلق به کتابخانه System.Drawing را به پروژه وارد کنید.
فهرست ۵ :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using MainInterface;

namespace MyRotate
{
    public class Class1 : MyImageAddon
    {
        public Image RunAddon(Image image)
        {
            Bitmap bitmap1 = new Bitmap(image);
            Bitmap bitmap2 = new Bitmap(image);
            for (int row = 0; row < bitmap1.Height; ++row)
            {
for (int col = 0; col < bitmap1.Width; ++col)
                {
 bitmap2.SetPixel(bitmap1.Width - col - 1, bitmap1.Height - row - 1,bitmap1.GetPixel(col, row));
                }
            }
            bitmap1.Dispose();
            return bitmap2;
        }

        public string Name
        {
            get
            {
                return “Invert Image”;
            }
        }
    }
}

• ساخت برنامه اصلی
بعد از طراحی موفقیت‌آمیز افزونه، زمان آن رسیده است که برنامه اصلی را ایجاد کنید. در این مرحله باید افزونه‌ ساخته‌شده را در برنامه اصلی استفاده کنید. برای این منظور پروژه‌ای از نوع Windows Forms Application به نام MyPicture بسازید. در برنامه اصلی ضمن بارگذاری کتابخانه پویا، به این فیلدها نیاز داریم: 
1. یک کنترل PictureBox روی فرم قرار دهید.
2. یک دکمه (Button) روی فرم قرار دهید.
3. حال از زیرگروه Menus & Toolbars کنترل MenuStrip را انتخاب کنید و روی فرم قرار دهید. 
4. در پنجره Solution Explorer روی گزینه Reference کلیک کرده و اسمبلی MainInterface را که در اولین مرحله ساختید، در برنامه وارد کنید. کدهای فهرست شماره شش را در برنامه کاربردی وارد کنید.
فهرست ۶ :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MainInterface;
using System.Reflection;
using System.IO;

namespace MyPicture
{
    public partial class Form1 : Form
    {
        private Dictionary<string, MainInterface.MyImageAddon> Addon=
new Dictionary<string, MainInterface.MyImageAddon>();

        public Form1()
        {
            InitializeComponent();
            Assembly assembly = Assembly.GetExecutingAssembly();
            string path = Path.GetDirectoryName(assembly.Location);
            LoadAddons(path);
            CreateMenu();
        }

        private void LoadAddons(string path)
        {
            Addon.Clear();
            foreach (string dll in Directory.GetFiles(path, “*.dll”))
            {
                try
                {
                    Assembly assembly = Assembly.LoadFrom(dll);
                    foreach (Type type in assembly.GetTypes())
                    {
                        if (type.GetInterface(“MyImageAddon”) == typeof(MainInterface.MyImageAddon))
                        {
                            MyImageAddon plugin = Activator.CreateInstance(type) as MyImageAddon;
                            Addon[plugin.Name] = plugin;
                        }
                    }
                }
                catch (BadImageFormatException)
                {
                }
            }
        }
        private void CreateMenu()
        {
            toolStripMenuItem1.DropDownItems.Clear();
            foreach (var pair in Addon)
            {
                ToolStripMenuItem toolstrip=new ToolStripMenuItem(pair.Key);
                toolstrip.Click += new EventHandler(menuItem);
                toolStripMenuItem1.DropDownItems.Add(toolstrip);
            }
        }

  void menuItem(object sender, EventArgs e)
        {
            ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
            MainInterface.MyImageAddon plugin = Addon[menuItem.Text];
            try
            {
              pictureBox1.Image = plugin.RunAddon(pictureBox1.Image);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, “Plugin is not valid”);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.OpenFileDialog openImage = new OpenFileDialog();
            openImage.Filter = “All images (*.bmp, *.png, *.jpg)|*.bmp;*.png;*.jpg”;
            if (openImage.ShowDialog() == DialogResult.OK)
            {
             pictureBox1.Image = Image.FromFile(openImage.FileName);
            }
        }
    }
}

قبل از اجرای برنامه به این نکته توجه کنید که فایل‌های کتابخانه‌های پویا (DLL) باید در مسیر پوشه اصلی برنامه کپی شده باشند. برنامه را اجرا کنید؛ زمانی که برنامه اجرا می‌شود، افزونه‌ مدنظر را جست‌وجومی‌کند. اگر همه‌چیز را به‌درستی طراحی کرده باشید، برنامه اجرا می‌شود. روی دکمه Browse کلیک کرده و یک تصویر را انتخاب کنید تا در برنامه بارگذاری شود. از فهرست برنامه گزینه Invert را انتخاب کنید. همان‌گونه که در شکل 4 مشاهده می‌کنید، تصویر درون باکس وارونه‌شده نشان داده می‌شود. به این ترتیب، موفق شدیم افزونه‌ای را به‌درستی طراحی کنیم.


شکل ۴

• ساخت افزونه تغییر رنگ
برای ساخت افزونه تغییر رنگ باید مراحل قبل را یک‌بار دیگر تکرار کنیم: 
1. ابتدا پروژه‌ای از نوع Class Library به نام ChangeColor ایجاد کنید. 
2. در پروژه ساخته‌شده ابتدا ارجاع مربوط به MainInterface را با استفاده از گزینه AddReference در پروژه وارد کنید. 
3. در این قسمت در نظر داریم فرایند یک انتخاب رنگ ساده را در اختیار کاربر قرار دهیم. 
بر همین اساس به اسمبلی System.Windows.Forms و System.Drawing نیاز داریم. این کتابخانه قرار است دیالوگ انتخاب رنگ Color را در برنامه اصلی ظاهر سازد. شکل 5 اسمبلی‌های واردشده در پروژه را نشان می‌دهد.
4. دستورات فهرست هفت را در برنامه وارد کنید.


شکل ۵

فهرست ۷ :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MainInterface;
using System.Drawing;
using System.Windows.Forms;
namespace ChangeColor
{
    public class Class1:MyImageAddon
    {
      public System.Drawing.Image RunAddon(System.Drawing.Image image)
        {
    ColorDialog color = new ColorDialog();
            Color color2;

 if (color.ShowDialog() == DialogResult.OK)
            {
                color2 = color.Color;
            }
            else
                color2 = Color.BlueViolet;
Bitmap bitmap = new Bitmap(image);

for (int row = 0; row < bitmap.Height; ++row)
                {
 for (int col = 0; col < bitmap.Width; ++col)
                    {
      color2 = bitmap.GetPixel(col, row);
                        if (color2.B > 0 )
                        {
color2 = Color.FromArgb(color2.A, color2.R, color2.G, color.Color.B);

                        }
                        else if (color2.G > 0)
                        {
 color2 = Color.FromArgb(color2.A, color2.R, color.Color.G, color2.B);
                        }
                        else if(color2.R > 0)
                        {
color2 = Color.FromArgb(color2.A, color.Color.R, color.Color.G, color2.B);
                        }
    bitmap.SetPixel(col, row, color2);
                    }
                }
            
            return bitmap;
        }

        public string Name
        {
            get { return “Change Color image”; }
        }
    }
}

برنامه را کامپایل کنید تا کتابخانه پویا ساخته شود. اگر این فرایند موفقیت‌آمیز بوده باشد، یک کتابخانه پویای ColorChange.Dll در اختیار دارید. کتابخانه ساخته‌شده را در مسیر فایل اجرایی برنامه کپی کرده و برنامه اصلی را یک‌بار دیگر اجرا کنید. اکنون گزینه‌ای به نام Change Color در فهرست اصلی برنامه قرار گرفته است. با کلیک روی این گزینه دیالوگ تغییر رنگ نشان داده می‌شود. (شکل 6) حال اگر رنگی را از درون این جعبه انتخاب کنید، رنگ تصویر تغییر پیدا می‌کند. (شکل 7) کتابخانه‌های پویا باید مانند شکل 8 در مسیر فایل اصلی برنامه یا مسیر شناخته‌شده برای برنامه کاربردی قرار گرفته باشند.


شکل ۶


شکل ۷


شکل ۸

==============================

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

ماهنامه شبکه را از کجا تهیه کنیم؟
ماهنامه شبکه را می‌توانید از کتابخانه‌های عمومی سراسر کشور و نیز از دکه‌های روزنامه‌فروشی تهیه نمائید.

ثبت اشتراک نسخه کاغذی ماهنامه شبکه     
ثبت اشتراک نسخه آنلاین

 

کتاب الکترونیک +Network راهنمای شبکه‌ها

  • برای دانلود تنها کتاب کامل ترجمه فارسی +Network  اینجا  کلیک کنید.

کتاب الکترونیک دوره مقدماتی آموزش پایتون

  • اگر قصد یادگیری برنامه‌نویسی را دارید ولی هیچ پیش‌زمینه‌ای ندارید اینجا کلیک کنید.

ایسوس

نظر شما چیست؟