Creating ActiveX in .NET
Сегодня пришлось создавать ActiveX control в Visual Studio 2008. Очень интересный опыт получился. Сразу замечу, что по моему скромному мнению, данные контролы стоит создавать с использованием библиотеки ATL.
В данном уроке мы будем использовать C#, но данную методику можно применять и на языке VB#. Данный контрол позволяет перехватывать событие Drag & Drop и отображать изображение в окне своего представления.
Примечание любые не статические, публичные члены становятся доступны при указании атрибута ComVisible
[ComVisible(true)]
public string FilePath
{
get { return m_filepath; }
set { m_filepath = value; }
}
Для начала создайте проект типа Class Library и назовите его DragNDrop
После этого перейдите на вкладку Build в свойствах проекта и отметьте галочку Register for COM Interopt
Подпишите сборку перейдя на вкладку Signing и выбрав чек бокс Sign the Assembly и выберите пункт New
Удалите файл Class1.cs и добавьте новый пользовательский контрол под именем DragNDrop
Добавьте обработчики событий DragDrop, DragEnter
Переключитесь на представление кода и добавьте следующие атрибуты к классу DragNDrop
[
ProgId("DnDControl.DragNDrop"),
Guid("31DCDFBA-6C3C-40b8-9BD9-E4B376BD56BC"),// Внимание измените данное значение на созданный вами GUID
ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDual)
]
public partial class DragNDrop : UserControl
переопределите метод OnPaint
protected override void OnPaint(PaintEventArgs e)
{
// If there is an image and it has a location,
// paint it when the Form is repainted.
base.OnPaint(e);
if (this.picture != null && this.pictureLocation != Point.Empty)
{
e.Graphics.DrawImage(this.picture, this.pictureLocation);
}
}
Добавьте 2 переменных:
private Image picture;
private Point pictureLocation;
Измените методы
private void DragNDrop_DragEnter(object sender, DragEventArgs e)
{
// If the data is a file or a bitmap, display the copy cursor.
if (e.Data.GetDataPresent(DataFormats.Bitmap) ||
e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.None;
}
}
private void DragNDrop_DragDrop(object sender, DragEventArgs e)
{
// Handle FileDrop data.
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
// Assign the file names to a string array, in
// case the user has selected multiple files.
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
try
{
// Assign the first image to the picture variable.
this.picture = Image.FromFile(files[0]);
// Set the picture location equal to the drop point.
this.pictureLocation = this.PointToClient(new Point(e.X, e.Y));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
// Handle Bitmap data.
if (e.Data.GetDataPresent(DataFormats.Bitmap))
{
try
{
// Create an Image and assign it to the picture variable.
this.picture = (Image)e.Data.GetData(DataFormats.Bitmap);
// Set the picture location equal to the drop point.
this.pictureLocation = this.PointToClient(new Point(e.X, e.Y));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
// Force the form to be redrawn with the image.
this.Invalidate();
}
После этого добавьте 2 метода для регистрации вашего контрола:
#region Регистрация контрола
[ComRegisterFunction()]
public static void RegisterClass(string key)
{
// Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
StringBuilder sb = new StringBuilder(key);
sb.Replace(@"HKEY_CLASSES_ROOT\", "");
// Open the CLSID\{guid} key for write access
RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
// And create the 'Control' key - this allows it to show up in
// the ActiveX control container
RegistryKey ctrl = k.CreateSubKey("Control");
ctrl.Close();
// Next create the CodeBase entry - needed if not string named and GACced.
RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
inprocServer32.Close();
// Finally close the main key
k.Close();
}
[ComUnregisterFunction()]
public static void UnregisterClass(string key)
{
StringBuilder sb = new StringBuilder(key);
sb.Replace(@"HKEY_CLASSES_ROOT\", "");
// Open HKCR\CLSID\{guid} for write access
RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
// Delete the 'Control' key, but don't throw an exception if it does not exist
k.DeleteSubKey("Control", false);
// Next open up InprocServer32
RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
// And delete the CodeBase key, again not throwing if missing
k.DeleteSubKey("CodeBase", false);
// Finally close the main key
k.Close();
}
#endregion