среда, 10 декабря 2008 г.

Creating ActiveX in .NET

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

clip_image002[3]

После этого перейдите на вкладку Build в свойствах проекта и отметьте галочку Register for COM Interopt

clip_image004[3]

Подпишите сборку перейдя на вкладку Signing и выбрав чек бокс Sign the Assembly и выберите пункт New

clip_image006[3]

Удалите файл Class1.cs и добавьте новый пользовательский контрол под именем DragNDrop

clip_image008[3]

Добавьте обработчики событий DragDrop, DragEnter

clip_image010[3]


Переключитесь на представление кода и добавьте следующие атрибуты к классу 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

 

 

пятница, 5 декабря 2008 г.

JavaScript url parser

Сегодня пришлось создавать решение которое включало в себя приведенный ниже код, в принципе это все можно было сделать и на сервере, но надо.

В чем особенность смотрите в комментариях к функциям, мои замечания для блога выделены жирным.

<script type="text/javascript">
// внимание данный скрипт должен быть вставлен ПОСЛЕ !!! формы вывода
/* Сдвигаем дату на указанное количество дней

params:
date a Date object
shift a day count offset
*/
function GetTimeShift(date,shift )
{
var g = new Date(date.toDateString());
g.setHours(shift * 24);
return g.toLocaleDateString();
}
/*

Тут все просто в страничке динамически созданной сервером ищем поля ввода и устанавливаем нужные нам значения (кстати по id не ищу исменно по тому что страница может быть, и будет развернута не один раз)
Установка значений при инициализации текстовых боксов.
Параметры:
date дата и время начала отсчета в формате строки
plane - сдвиг для планируемой даты в днях
fact - сдвиг для фактической даты в днях
prom - сдвиг для промежуточной даты в днях
intPlan - сдвиг для Внутренней плановой даты в днях
*/
function setDate(date,plane,fact,prom,intPlan)
{
var mt = new Date(date);
t = document.body.getElementsByTagName('INPUT');
    for(i=0;i<t.length;i++)
    {
        var er = t[i];
        if(er.title == 'Дата')       
            er.value = GetTimeShift(mt,0);
        else if(er.title == 'Плановая')                   
            er.value = GetTimeShift(mt,plane);
        else if(er.title == 'Фактическая')
            er.value = GetTimeShift(mt,fact); 
        else if(er.title == 'Промежуточная')
            er.value = GetTimeShift(mt,prom); 
        else if(er.title == 'Внутренняя плановая')
            er.value = GetTimeShift(mt,intPlan); 
             
    }
}
/*

А вот тут мне особенно нравиться :)

Мы производим разбор параметров переданных в адресной строке и используем их для вызова функции заполнения ячеек, все таки удобная штука JS
Параметры которые анализируем
startDate=12/05/2008 Месяц/день/Год
planDate
factDate
promDate
internalDate
*/
function CompouseDateReq(uri)
{
var date,plane,fact,prom,intPlan;
var ar = uri.split('&');
var arg = new Array();
arg['startDate'] = arg['planDate'] = arg['factDate'] = arg['promDate'] = arg['internalDate']= 0;
for(i=0;i<ar.length;i++)
{
    arg[ar[i].split('=')[0]] = ar[i].split('=')[1];
}
// setDate(date,plane,fact,prom,intPlan)
setDate(arg['startDate'],arg['planDate'],arg['factDate'],arg['promDate'],arg['internalDate']);
}

/*

тут все очень просто извлекаем адрес документа и отделяем параметры запроса

*/
function parseUrlParam()
{
var st = new String();
st = document.URL;
try{
CompouseDateReq(st.split('?')[1]);
}
catch(ex)
{
return;
}
}
parseUrlParam();
</script>