Shell Tree Control - это ActiveX компонент, реализующий отображение дерева каталогов, как в левой панели Проводника. С его помощью Вы можете дать некоторым частям своих программ профессиональный и интуитивно понятный интерфейс. Теперь не надо каждый раз вызывать API функцию SHBrowseForFolder() и рассеивать внимание пользователя на различных диалогах. Вы можете легко встроить этот компонент в свой проект на Visual C++, а благодаря поддержке компонентом автоматизации даже в Web-страницу. Как и любой COM-компонент, Shell Tree Control нуждается в регистрации в системе. Вы можете использовать для этого утилиту regsvr32.exe.
Для воспроизведения видео в Delphi есть компонент TMediaPlayer. Но как быть если необходимо воспроизвести флэш-ролик? Оказывается в Delphi можно воспроизвести Flash ролики. Как же это сделать?
Для начала необходимо импортировать компонент ActiveX: для этого в главном меню выберите Component -> Immport ActiveX Control... Появляется окно. Найдите и выделите в списке Shockwave Flash (Version 1.0). Можно выбрать вкладку на панели инструментов - раздел Palette page. Не будем менять. Нажмите Install... Появится еще одно окно, в котором вам нужно будет выбрать в какой пакет будет установлен компонент. Нажмите ОК. Появится окно с подтверждением. Нажмите YES. И, наконец, появляется сообщение об успешной установке. Нажмите ОК. На экране остается еще одно окно - "Package - dclusr.dpk". Закройте его и подтвердите сохранение.
Компонент установили. Он появится во вкладке ActiveX на панели инструментов.
Для того, чтобы понять как с ним работать напишим простейший плеер. Выложите на форму: TShockwaveFlash(для удобства назовите его просто Flash1), TTrackBar, TOpenDialog, TTimer и 3 кнопки TButton. Измените Caption кнопок на "Открыть", "Воспроизведение", "Стоп".
Изменим следующие свойства OpenDialog'a:
Свойство Filter измените на Флэш-ролики|*.swf;
Свойство DefaultExt на *.swf;
У Timer1 установите свойство Interval на 1.
Теперь напишем обработчик события OnClick для кнопки, которая будет вызывать OpenDialog. Это кнопка с Caption="Открыть":
По клику на кнопку "Воспроизведение" будем выполнять следующий код:
А по клику на кнопку "Стоп" будем выполнять следующий код:
И осталось еще автоматически двигать TrackBar. Для этого и нужен таймер.
Хотя надежность современных компьютерных систем в целом достаточно высока, время от времени в них происходят сбои, вызванные неисправностью аппаратных средств, ошибками в программном обеспечении, компьютерными вирусами, а также ошибками пользователей, системных администраторов и технического персонала.
Анализируя причины возникновения встречавшихся в нашей практике аварийных ситуаций, приводивших к потере данных, можно сказать, что все перечисленные сбои случаются примерно с одинаковой вероятностью.
Отказы аппаратных средств
Исчезновение данных может быть вызвано отказом различных устройств - жестких дисков и дисковых контроллеров, соединительных кабелей, оперативной памяти или центрального процессора компьютера. Внезапное отключение электропитания при отсутствии источника бесперебойного питания - также одна из наиболее распространенных причин исчезновения данных. В зависимости от того, что происходило в компьютере на момент отказа, последствия могут оказаться более или менее тяжелыми.
Отказы дисковых контроллеров
Чаще всего нам встречались случаи потерь данных при отказах дисковых контроллеров. При этом в момент аварии контроллер выполнял операцию записи, которая завершалась с ошибками. Как следствие, оказывались разрушенными системные области диска, после чего все данные или часть их становились недоступны.
Заметим, что дисковые контроллеры современных файловых серверов, таких, как Compaq Proliant, протоколируют сбои аппаратных средств и позволяют выполнять диагностику. Это дает возможность обнаружить опасные симптомы еще до того, как они приведут к отказу. Например, в одной компании на протяжении нескольких недель контроллер диска записывал в системный журнал сообщения о возможном отказе кэш-памяти, встроенной в контроллер. И когда эта память, наконец, отказала, пропало несколько гигабайт важных данных.
Зеркальные диски
Наиболее простой способ увеличения надежности хранения данных - подключить к одному контроллеру два жестких диска и средствами ОС выполнить их зеркальное отображение. При этом один диск играет роль основного, а другой дублирует всю информацию, записываемую на основной диск. При выходе из строя основного диска его функции автоматически переходят к зеркальному диску, в результате чего система продолжает работать без аварийной остановки.
К сожалению, зеркальные диски не помогут при сбое контроллера или ПО. Фактически данная технология поможет вам застраховаться только от такой неприятности, как поломка одного жесткого диска из зеркальной пары.
Если каждый из зеркальных дисков будет подключен к своему контроллеру, то надежность возрастет. Теперь система продолжит работу при выходе из строя не только одного диска, но и одного дискового контроллера.
Такие ОС, как Microsoft Windows NT и Novell NetWare способны создавать зеркальные диски программным путем без применения дополнительного оборудования.
Отказы кэш-памяти
Как вы, вероятно, знаете, кэш-память значительно ускоряет операции записи данных на диск и чтения с диска за счет временного хранения данных в очень быстрой оперативной памяти. Если данные кэшируются при чтении, то отказ кэш-памяти не приведет к их потере, так как на диске они останутся в неизменном виде. Что же касается кэширования при записи, то эта операция несет в себе потенциальную опасность.
Кэширование при записи предполагает, что данные вначале записываются в оперативную память, а затем, когда для этого возникает подходящий случай, переписываются на жесткий диск. Программа, сохраняющая данные на диске, получает подтверждение окончания процесса записи, когда данные оказываются в кэш-памяти. При этом фактическая запись их на диск произойдет позже. Так вот, если отказ кэш-памяти случится в "неподходящий" момент, то программа (или ОС) будет полагать, что данные уже записаны на диск, хотя фактически это не так. В результате могут оказаться разрушенными важнейшие внутренние структуры файловой системы.
Операционные системы обычно выполняют дополнительное кэширование данных, записываемых на диск или считываемых с диска, в основной оперативной памяти компьютера. Поэтому отказы оперативной памяти, а также внезапное отключение электропитания могут привести (и обычно приводят!) к возникновению фатальных неисправностей файловой системы. Именно поэтому так важно снабжать компьютеры, и особенно серверы, устройствами бесперебойного питания. Кроме того, такие устройства должны быть в состоянии корректно завершать работу ОС компьютера без вмешательства человека. Только в этом случае отключения электропитания не приведут к потере данных.
Неисправности электроники в дисках
Несколько слов заслуживают неисправности, возникающие в самих дисковых устройствах. Помимо механических повреждений, вызванных небрежным обращением с дисками, возникают отказы электронных схем, расположенных как вне, так и внутри герметичного корпуса диска. Отказы таких электронных схем могут привести, а могут и не привести к потере данных. В нашей практике встречались случаи, когда после замены электроники удавалось полностью восстановить данные, переписав их на другой диск.
Замена контроллера диска
Иногда данные пропадают после замены дискового контроллера на контроллер другого типа (такая проблема обычно возникает с контроллерами SCSI). Операционная система в этих случаях просто отказывается монтировать диск. Выбрав правильный тип контроллера, обычно удается легко ликвидировать данную проблему, однако так бывает не всегда.
Сбои, возникающие из-за пыли
Несмотря на то что корпуса современных серверов специальным образом защищены от проникновения пыли (для этого на вентиляторы устанавливают специальные воздушные фильтры), пыль все же проникает в компьютер. Она оседает на системной плате, конструктивных элементах корпуса и контроллерах. Так как в пыли есть металлические частички, она может вызывать замыкания между соединительными линиями, расположенными на системной плате или на платах контроллеров.
Когда компьютер переносят с одного места на другое, комочки пыли перекатываются внутри корпуса и могут привести к замыканию. Именно так пропали данные на сервере у одного из наших клиентов после перестановки сервера из одной стойки в другую.
Чтобы уменьшить вероятность возникновения сбоев из-за пыли, используйте в ответственных случаях специальные пылезащищенные корпуса и периодически выполняйте профилактические работы, удаляя пыль при помощи специального "компьютерного" пылесоса.
Дело в том, что PHP-сценарии, запущенные модулем mod_php, выполняются от имени пользователя wwwserver. Соответственно, если на чтение/модификацию не были выставлены разрешения для всех (достаточно 666 — для файлов, 777 — для каталогов), то модификация созданных такими скриптами файлов (каталогов) пользователю будет запрещена (при доступе по SSH, по FTP).
Исключить проблему можно, установив достаточные для модификации файлов посредством функции chmod.
Сделать это рекурсивно можно, исполнив PHP-сценарий:
Разместите этот файл на площадке, в директории, доступной веб-серверу, например, как: domain.tld/www/chmod.php где domain.tld/www — корневая директория (DocumentRoot) вашего сайта на сервере.
Вызывать скрипт нужно так: http://domain.tld/chmod.php?путь_к_нужной_директории
или так: http://domain.tld/chmod.php?/home/uXXXXX/domain.tld/www/путь_к_нужной_директории
В первом случае указывается путь относительно DocumentRoot для вашего сайта (domain.tld/www/ в данном примере). Во втором случае (uXXXXX — идентификатор вашей площадки) — абсолютный путь от корневой директории сервера.
При запуске скрипта без параметров будут изменены права для всех файлов и директорий, располагающихся в DocumentRoot.
Помню как я намучался когда первый раз столкнулся с проблемой превьюшек, поэтому и выложил этот скрипт, а вдруг кому-то поможет. С описанием я заморачиватся не стал - это же готовые решения, а не учебное пособие. Вобщем пользуйтесь.
З.Ы. Скрипт нужно разместить в отдельном файле, например thumb.php
Для отправки электронного письма, без использования почтового клиента, мы будем использовать компонент TNSMTP, который находится на вкладке FastNet.
Компонент TNSMTP позволяет отправлять электронную почту через почтовый сервер или выполнять другие команды, описанные в стандарте RFC 821. Данный компонент работает по протоколу SMTP (Simple Mail Transfer Protocol). По стандарту RFC 821 протокол SMTP использует порт 25. При подключении к почтовому серверу необходимо знать учетную запись (login) своего почтового ящика. Чаще всего, имя пользователя - это начальная часть вашего почтового адреса – до символа «@». Так же для подключения к SMTP серверу необходимо знать его адрес. Адрес своего почтового сервера указывается при создании на нем почтового ящика. Стоит заметить, что адрес почтового ящика и адрес сервера – это совершенно разные вещи.
Создадим небольшой пример. Добавим на форму стандартную кнопку и компонент TNSMTP.
Собственно, Вы можете и не добавлять на форму данный компонент, а просто прописать его в строках Uses. Такой вариант очень полезен, если Вы пишете программу в «консольном» режиме.
Код:
Но этого мы делать не будем. В обработчик кнопки поместим код расположенный ниже.
Код:
Для корректной работы компонента необходимо заполнить свойства Host и Port. Для того чтобы подключиться к серверу, необходимо вызывать метод Connect, а для отключения - Disconnect. Главное свойство компонента TNSMTP - PostMessage. Это свойство содержит в себе информацию об отправляемом письме: ToAddress (адрес получателя), FromAddress (адрес отправителя), Body (текст письма), Subject (тема письма) и FromName (имя отправителя). После отправки письма необходимо отключиться от сервера, используя метод Disconnect.
В данной статье рассмотрены принципы, помогающие компилятору Delphi генерировать более оптимальный с точки зрения скорости код. Если Вы не хотите вникать в подробности, в конце статьи есть «свод правил», которые рекомендуется соблюдать при написании программ.
Компилятор Delphi относится к разряду оптимизирующих. Но насколько качественно проводится оптимизация? Как «помочь» компилятору создать более быстрый код? Давайте разберемся с этим на экспериментах.
Оптимизация константных выражений
Пример 1:
С точки зрения оптимизации код можно упростить еще на этапе компиляции до
Но написанный выше листинг преобразуется в
С одной стороны компилятор не «сообразил», что значение переменной «a» можно преобразовать в константу и сложить с другой константой (которая, заметим, подставлена именно как константа) на этапе компиляции, с другой стороны был применен весьма хитрый трюк с LEA (об этом ниже). Тем не менее, код
в любом случае быстрее и короче.
Пример 2:
Скомпилированный код будет выглядеть
А ведь значение, присвоенной переменной «а» являлось константой и наш пример можно было бы переписать как:
Пример 3:
После компиляции получаем:
Т.е. компилятор преобразовал код так, как он был написан, а ведь можно было бы просто записать:
Оптимизация алгебраических выражений
Пример 4:
После компиляции эти переменные будут удалены, причем с предупреждением
Пример 5:
Код скомпилируется как есть! Таким образом мы обманули компилятор псевдо использованием переменных. Delphi не исправляет нашей «кривости», поэтому эта задача ложится исключительно на плечи программиста.
Пример 6:
Данный код можно оптимизировать до
И этого Delphi за нас не сделает.
Пример 7:
В данном примере первую строчку можно безболезненно удалить, что Delphi делать умеет.
Пример 8:
В данном случае можно избавится от одной операции умножения, присвоив значение выражения a*b временной переменной. Анализ ассемблерного листинга показывает, что компилятор именно так и поступает. Тем не менее, поменяв второе подвыражение на ((b*a)>0), компилятор принимает выражения за разные и генерирует умножение для обоих случаев, не смотря на то, что результат одинаков.
Оптимизация арифметических операций
Сложение и вычитание
Применение инструкции LEA вместо ADD позволяет производить сумму 3х операндов (двух переменных и одной константы) за один такт. Трюк заключается в том представление ближних указателей эквивалентно их фактическому значению, поэтому результат, возвращенный LEA равен сумме ее операндов. При возможности Delphi производит такую замену.
Деление
Операция деления требует гораздо больше тактов процессора, нежели умножение, поэтому замена деления на умножение может значительно ускорить работу. Существуют формулы, позволяющие выполнять такое преобразование. Тем не менее, Delphi не использует такую оптимизацию. Деление на степень двойки можно заменять сдвигом вправо на n бит, но даже в этом случае получаем следующий код:
Здесь учитывается особенность самой операции div – округление в большую сторону. Поэтому, если можно пренебрегать округлением, используйте c:=a shr 1 вместо с:=a div 2.
Умножение
Умножение на степень двойки можно заменять сдвигами битов. Delphi заменяет умножение сдвигами при умножении на 4,8,16 итд. При умножении на 2 производится суммированием переменной с собой.
Умножать на 3,5,6,7,8,10 и т. д. можно и без операции умножения – расписав выражение по формуле (a shl n)+a, где n – показатель степени двойки. Например, при умножении на 3 n=1. Delphi при возможности прибегает к этому трюку. Заметим, операнд LEA умеет умножать регистр на 2,4,8, что также при возможности используется компилятором. Например, умножение на 3 преобразуется в инструкцию
Оптимизация case of
Анализ скомпилированного кода показывает, что Delphi проводит утрамбовку дерева. Т.е. значения case сортируются и выбор нужного элемента производится при помощи двоичного поиска.
В случае, если элементы case of выстраиваются в арифметической прогрессии, компилятор формирует таблицу переходов. Т.е. создается массив указателей с индексами элементов, поэтому выбор нужно элемента выполняется за одну итерацию независимо от количества элементов.
Оптимизация циклов
Разворачивание циклов – не производится. Разворачивание циклов весьма спорный момент в оптимизации, поэтому принять грамотное решение может только человек. Delphi не производит разворачивания ни больших, ни маленьких циклов.
Слияние циклов – не производится. Если два цикла, следующие друг за другом имеют одинаковые границы итерационной переменной, разумно оба цикла объединить в один.
Вынесение инвариантного кода за пределы цикла – не выносится. Наиболее распространенный недочет – условие цикла записывается как:
Delphi будет при каждой итерации вызывать метод count, вычитать из результата 1 и потом уже сверять. Настоятельно рекомендуется переписывать подобный код как
Весь код VCL написан с нарушением этого правила. Очевидно, что проще подобного рода оптимизацию встроить в компилятор, нежели переписывать VCL :)
Замена циклов с предусловием на циклы с постусловием – производится. Циклы с постусловием имеют главное преимущество над другими видами циклов (с предусловием и с условием в середине) – они содержат всего одно ветвление. Delphi производит такую замену.
Замена инкремента на декремент – не производится. Более того, даже декрементный цикл компилируется в неоптимальный код, т.к. не используется флаг ZF. Вместо этого происходит сравнивание значения регистра с 0.
Удаление ветвлений – не производится.
Вывод:
1. Не используйте переменные для временного хранения констант или обязательно объявляйте «магические» числа как const, либо подставляйте в код непосредственные значения
2. Неиспользуемыми объявлениями и присвоениями можно безболезненно пренебрегать – Delphi умеет их вычищать.
3. Внимательно следите за использованием переменных, в частности лишним присвоениям их значений друг другу. Такого рода оптимизации Delphi делать не умеет.
4. Используйте свернутые математические выражения. (например, (3*a - a) /2 упрощается до a). Delphi не умеет упрощать математические выражения. (Да и что говорить, даже MathCAD не всегда грамотно умеет делать такие преобразования).
5. Не используйте конструкции типа a:=10*sin(45*pi/180); Delphi не вычислит эту константу на этапе компиляции, напротив, будет послушно вызывать sin и pi по ходу выполнения программы! В случае, если угол является переменной, по крайней мере pi можно заменить константой 3,1415...
6. Delphi прекрасно справляется с выражениями, полностью составленных из констант – они вычисляются на этапе компиляции.
7. Внимательно следите за условиями и их границами. Компилятор Delphi не умеет обнаруживать заведомо ложных условий. Также он не умеет удалять заведомо лишние условия. Например, (a>0) and (a<15616) and (a<>0)
8. Если в условии несколько раз проверяется одно и тоже выражение, следите, чтобы оно было выражено во всех конструкциях одинаково. В противном случае скомпилированный код будет не оптимален. Например, if ((a*b)>0) and ((a*b)<1024) then... При перестановке во втором случае b*a смысл выражения не изменится, но код будет иметь уже на одну операцию умножения, а две. Можно временно присвоить проверяемое выражение временной переменной, а затем уже проверять полученное значение.
9. Сообщение «Combining signed and unsigned types – widened both operands» сообщает не только о потенциальной ошибке – также вследствие преобразования мы теряем производительность. Например, z – объявлена как ineteger. условие if z>$abcd6123 then z:= $abcd6123; несмотря на его правильность вызовет данное предупреждение. Сгенерированный код будет, выполнять преобразования величин до 64-х бит, и дальнейшее уже сравнение 64-х битных операндов. Если изменить тип z на cardinal, мы избавимся от предупреждения и получим 3 строки кода, вместо 8 !
10. Delphi умеет оптимизировать сложение, умножение и частично деление. При делении на степень двойки, если не важно округление до большего, рекомендуется пользоваться shr 1 вместо div 2.
11. В case of при возможности используйте элементы, расположенные в арифметической прогрессии. Тем не менее, даже при невыполнении данного условия мы получим качественный код после утрамбовки дерева.
12. Выносите инвариантный код за тело цикла. Наиболее частая ошибка – for i:=1 to length(str) do... Дело в том, что при каждой итерации будет вызываться функция length, что пагубно скажется на производительности. Рекомендуется длину строки заранее присвоить переменной. Также не включайте в тело цикла код, заведомо не зависящий от изменения итерационной переменной.
Сравнивая Delphi с компиляторами Visual C++, WATCOM, Borland C++ (тестирование данных компиляторов приведено в [1]) приходим к выводу, что Delphi по своим оптимизирующим свойствам аналогичен Borland C++ (а кто сомневался? ;) ). Учитывая, что Borland C++ по итогам сравнения оказался последним, делаем несложный вывод. Весьма печален и тот факт, что большинство кода VCL написано с точки зрения «красоты» кода, а не его оптимальности с точки зрения скорости. Например, не соблюдается правило 12.
Событие - это какое-либо действие, осуществляемое пользователем либо браузером. Например, когда мы щелкаем (кликаем) на ссылке - осуществляется событие, его перехватывает специальный обработчик и перенаправляет нас на нужную страницу; при наведении курсора (указателя мыши) на ссылку в строке состояния (обычно находится в нижней части окна браузера) отображается адрес, так как обработчик "наведения курсора на объект (в данном случае на ссылку)" помещает туда этот адрес и так далее...
а). onmouseout и onmouseover
Для начала наведем курсор на кнопку "Сброс" или "Отправить" и обратим внимание на строку состояния. Вы должны увидеть там надпись с объяснением значения кнопки. Теперь отведите курсор и строка состояния очистится.
Содержимое строки состояния хранится в переменной window.status. Переменная это некоторый объект (можно представить себе ящик), значение которого (содержимое которого) можно изменять. Изменение значения осуществляется операцией присваивания (=), а выглядит она следующим образом:
имя_переменной = "значение"; (какие использовать кавычки: одинарные или двойные значения не имеет)
Поэтому для того, чтобы изменить надпись в строке состояния, нам нужно присвоить переменной window.status нужное нам значение (подсказку к кнопке), а когда курсор будет убран - присвоить пустую строку("").
Вся задача сводится к тому, чтобы определить когда пользователь наводит курсор на кнопку, а когда убирает его. Для этого нужно "сказать" обработчикам этих событий выполнить нужное нам действие. Обработчик события "наведение курсора" - onmouseover, а "отведение курсора" - onmouseout.
Очень многие тэги имеют атрибуты, начинающиеся с on (onclick, onmouseout, onfocus и т. д.). Значение этих атрибутов и есть, задача которую необходимо выполнить соответствующему обработчику. То есть для обработчика onmouseout есть атрибут onmouseout, для onmouseover - onmouseover. И в итоге мы получаем следующее определение кнопок:
Как Вы видите, атрибут onmouseover имеет в качестве значения JavaScript-код: window.status='Щелкните для отправки данных', как только курсор достигает кнопки, обработчик события mouseover - onmouseover, смотрит, что хранится в атрибуте onmouseover и выполняет необходимое действие(присвоение значения переменной window.status). Аналогично действует и обработчик события onmouseout: как только курсор уводиться от кнопки (то есть выполняется событие mouseout), то обработчик события - onmouseout выполняет код, содержащийся в атрибуте onmouseout.
То же самое и со второй кнопкой.
б). <a href="Java Scriptfunction()">Function</a>
Теперь щелкните на ссылке и откроется окошко с подсказкой. Но заметьте, что окно небольших размеров и у него нет панели инструментов - такого силами html не сделаешь! В данном примере мы имеем окно размером 300x200, без панелей инструментов, содержащее документ help.html.
Для того чтобы создать такое окошко существует следующий JavaScript-код:
где:
1. helpWindow - это имя переменной (как window.status, только в данном случае имя выбирается произвольно). Эта переменная нужна для последующей работы с окном (например, закрыть его нестандартным способом - с помощью JavaScript-сценария).
- Зачем? Не проще ли указывать просто имя открывающейся страницы, например help.html?
- А если у нас две копии одной и той же страницы? Или две страницы с одинаковым именем(например, в разных папках)? Вот для того, чтобы не перепутать страницы и свободно работать именно с тем окном с которым предполагаешь и сделанно, так чтобы "окно" присваивалось переменной, так как имя переменной можно выбрать любое.
2. window.open(что-то) - это функция. Функции выполняют определенную задачу, в данном случае window.open() открывает новое окно.
3. help.html - это страница, которую нужно открыть.
4. "" - В кавычках должно быть имя окна, но оно нам не пригодится, поэтому там нулевая строка. В следующих кавычках указываются "параметры открываемого окна": оно не должно содержать панели инструментов (toolbar=0) и должно быть шириной 300 пикселей, а высотой - 200 (width=300,height=200, соответственно).
Теперь все, что нужно это по событию "щелчка" выполнить этот код, однако есть два "но". Во-первых строка очень длинная, чтобы присвоить ее какому-либо атрибуту - будет некрасиво смотреться, да и вызывать неудобства при чтении кода страницы. Во-вторых, первоначальное предназначение ссылки - это переход на другую страницу, но нам переходить никуда не нужно, нам нужно выполнить вместо этого JavaScript-код.
Первое решается написанием функции. Как я уже говорил функция выполняет некоторую задача, причем для использования функции достаточно указать ее имя. Можно не только использовать предопределенные(функции, которые имеется в языке и без нас), но и писать их самому. Обычно функции определяются(пишутся) в разделе HEAD документа, в котором используются:
"function" значит, что дальше будет написана наша функция; help() - это имя функции (оно будет указываться вместо тела функции (между { и })).
Вторая проблема решается тоже довольно просто. Адрес страницы указывается в атрибуте href, а нам надо выполнить JavaScript код вместо перехода по ссылке:
"Java Script" означает, что дальше должен идти JavaScript-код, и что он должен выполняться вместо стандартного перехода по ссылке. В данном случае наш JavaScript-код - это созданная нами функция help().
в). onclick
Нам не остается ничего более, как закрыть окно со справкой. Для этого воспользуемся кнопкой "Закрыть". Но нас интересует то, как работает эта кнопка, а имеет она следующий вид:
Дабы закрыть окно мы сделали щелчок(Click) на кнопке "Закрыть", а щелчок это нажатие и отпускание кнопки мыши, причем и то и другое должно быть произведено на одном и том же элементе (например, на кнопке). Кликая, на кнопке мы активируем обработчик события onClick, который выполняет для нас JavaScript-код, прописанный в атрибуте onclick нашей кнопки. Помните мы открывали окно? Мы писали window.open(), а здесь тоже самое только window.close(). window - это текущее окно, а close() - закрыть.
Это одно из наиболее частоупотребляемых событий.
г). onfocus и onblur
Ну что ж будем ближе подбираться к вводу требуемой от нас информации.
Как я уже говорил: элемент получает фокус когда на нем происходит нажатие кнопки мыши, или на него осуществляется переход посредством клавиши табуляции (Tab), а теряет, когда фокус получает другой элемент. Наше поле для ввода получит фокус тогда, когда пользователь решиться ввести информацию. При этом было бы удобно, чтобы текст с подсказкой ("Введите Ваше имя") автоматически выделялся и посетитель мог его удалить одним нажатием на del, а не удалять по одному символу, или выделять текст вручную. Удобство пользователя свято. Итак, для этого мы воспользуемся событием focus. Для выделения текста используется метод select(). То есть атрибутом к полю надо прописать: onfocus="this.select();", this обозначает, что выделение должно происходить именно в этом текстовом поле (а можно прописать путь и к другому, но это не целесообразно).
А теперь попробуйте ничего не изменяя (или все удалив) убрать фокус (например, щелкнув в любом месте окна, или нажав Tab). Это событие blur, я прописал в нем выполнение функции: onblur="check();". Сама же функция имеет следующий вид (в разделе head страницы с формой между <script> и </script>):
document.forms[0].name.value - это то, что введено в текстовое поле. document - это текущий документ, forms[0] - первая форма на нашей страницы (отсчет с нуля), name = имя поля (задается атрибутом name (<input name="name">)), а value это и есть нужное нам значение (то, что введенно в текстовое поле, к которому м ы и написали путь). Введенное в поле мы присваиваем переменной val (var значит, что дальше идет имя переменной), чтобы в дальнейшем каждый раз не писать весь путь целиком.
Следующее это оператор if(если). Он выглядит следующим образом:
Мы сравниваем содержание переменной val с пустой строкой ('') и с начальной строкой ('Введите Ваше имя'). Обратите внимание, что сравнение не как в математике(с одним =), а сравниваются двума ==. || - или. Функция alert выводит окно с ошибкой (то, что в скобках - это текст ошибки). То есть:
И на всякий случай приведу целиком строку с кодом поля input:
д). onreset и onsubmit
Допустим, что пользователь заполнил форму неправильно, и он хочет очистить все поля формы одновременно: для этого он воспользуется стандартной кнопкой reset. Но что если пользователь щелкнет на ней по случайности (рука дрогнет, или в суете спутает с кнопкой submit), а форма была огромная, и он долго мучился ее заполнять..., ему будет грустно, и еще он будет долго материться. Поэтому хорошо бы у него дополнительно спросить: действительно ли он хочет очистить форму.
Вообще событие reset обрабатывается до очистки формы. А чтобы отменить очистку вообще, нам просто напросто надо вернуть обработчику события значение false, то есть прописать в соответствующем атрибуте: "return false;", а чтобы продолжить очистку: "return true;". А теперь вспомним функцию, которая выдает вопрос пользователю на подтверждение чего-либо, эта функция: "confirm('Вопрос?');". При нажатии "Ok", эта функция заменяется на true, а при нажатии "Cancel" на false. То есть все что от нас требуется, это прописать в теге <form> атрибут: onreset="return confirm('Вы действительно хотите сбросить форму?');". Тогда при нажатии "Ok" там на самом деле будет "return true;", и форма будет очищена, а если "Cancel", то "return false;" и очистка формы будет отменена.
Подобным образом действует событие submit, которое возникает при попытке отправить форму. Поскольку в нашем случае форму отправлять никуда не надо, то у меня просто написано: onsubmit="return false;". И сколько бы Вы не щелкали ничего не изменится (разве что Вы JavaScript отключите).
Обычно же обработчик onsubmit используется для верификации формы (то есть проверки на заполнение всех необходимых полей, правильность их заполнения, скажем, проверка по определенному шаблону и т. п.), для этого создается функция, которая выполняет все действия. Функция должна содержать операторы "return true" и "return false", которые позволяют, заменить функцию на true или false, соответственно, в зависимости от результатов проверки (если успешно, то true, если нет false). Но верификация данных это обширная тема, которая не может быть рассмотрена здесь. Один из примеров базовой верификации я привел, когда объяснял событие blur - подобную функцию можно использовать и здесь. Тогда <form> будет содержать атрибут: onsubmit="return function();".
Но не забывайте, что нельзя ограничиваться одной лишь проверкой языком JavaScript, ибо его поддержка может быть отключена у посетителя, и тогда все Ваши труды по защите...
е). onmousedown и onmouseup
Еще одна пара событий не нашла достойного места на странице, но я ее реализовал в виде кнопки "Button". Причем это не обычная html-кнопка, она реализована в виде двух картинок. Исходная кнопка хранится в файле с именем npressed.jpg, а нажатая - pressed.jpg. Чтобы достичь эффекта нажатия кнопки нам необходимо, чтобы при при щелчке на ней(this) значение атрибута src (путь к картинке) тега <img> менялось на pressed.jpg, а при отпускании обратно на npressed.jpg. Нажатие кнопки обрабатывает onmousedown, а отпускание - onmouseup, то есть здесь все просто:
ж). onload, onunload и onabort
Обработчик события onload активируется, когда начинает загружаться графическая часть страницы (все тексты, графика и т.п.). onload является атрибутом тега <body>. Если честно я не вижу сколько бы реального применения этому событию, зато я нашел, что можно сделать с onunload. onunload это тоже атрибут тега <body>. Событие unload происходит когда мы пытаемся покинуть данную страницу (переходим по ссылке на другую, закрываем окно браузера, обновляем страницу и т. д.). Откройте еще раз окошко справки. Допустим, что пользователь прочитал справку, и хочет отправить форму, или уйдет с нашего сайта, но при этом он забыл закрыть это маленькое окошко с подсказкой, мы на выходе закроем его сами. А для этого тег <body> (у начального документа) у нас будет выглядеть следующим образом:
Вы должны бы помнить, что helpWindow это имя нашего окна (ведь именно этой переменной мы присваивали его открытие: helpWindow = window.open("help.html", "", "toolbar=0,width=300,height=200")), а метод close() закрывает это окно. Некоторые нехорошие люди используют это событие, чтобы когда посетители уходили с его страницы, появлялись какие-либо окна, так называемые pop-up.
onabort - атрибут тега <img>. Когда пользователь отменяет загрузку изображения происходит событие abort. Но отмена загрузки изображения может не входить в наши плане. И в качестве предупреждения у нас может быть написано нечто похожее на
ЗАКЛЮЧЕНИЕ
Есть некоторые события о которых я здесь нарочно не упомянул, потому что не нашел им достойного применения, но Вам они возможно пригодятся, поэтому я уделю им немного внимания.
onchange - обработчик события, который активируется, когда Вы изменяете содержимое текстового элемента или текстовой области (<TEXTAREA>) (например, когда Вы вводите или удаляете очередную букву какого-либо текстового поля).
onselect - обработчик события выбора текста. То есть это событие происходит, когда пользователь пытается выделить текст в текстовом элементе или текстовой области.
onerror - обработчик события error, которое возникает при ошибке загрузки документа или изображения (то есть onerror это атрибут тегов <body> и <img>). Оно возникает при синтаксической ошибке JavaScript-кода (но Вы ведь не будете специально делать в нем ошибки), либо ошибкой времени выполнения (например, если Ваш скрипт выполняет какие-либо вычисления и у Вас по ошибке получится так, что некое число будет делиться на ноль, а это недопустимо - это и есть одна из ошибок времени выполнения).
Так же не забывайте, что я привел лишь по одному примеру из десятков возможных на каждое событие. Здесь главное Ваша фантазия и навыки. Например, события mouseout, mouseover, mouseup, mousedown часто используются для создания выпадающих меню и других визуальных эффектов, но это весьма трудный материал, который требует более глубоких знаний, причем не одного JavaScript.
Когда вы вызываете функцию Windows, она проверяет переданные ей параметры, а затем пытается выполнить работу. Если передан недопустимый параметр или если данную операцию нельзя выполнить по другой причине, она возвращает значение, свидетельствующее об ошибке. За каждой ошибкой закреплен свой 32 битный код. Функция Windows, обнаружив ошибку, через механизм локальной памяти потока сопоставляет соответствующий код ошибки с вызывающим потоком. Это позволяет потокам работать независимо друг от друга, не вмешиваясь в чужие ошибки.
Когда функция вернет вам управление, ее возвратное значение будет указывать на то, что произошла какая-то ошибка. Какая именно - вы узнаете, вызвав функцию GetLastError(). Она просто возвращает 32-битный код ошибки для данного потока. Список кодов ошибок, определенных Microsoft, содержится в файле WinError.h.
Функцию GetLastError необходимо вызывать сразу же за проверяемой функцией, иначе код ошибки будет утерян.
Для отладки бывает нужно следить не за одной ошибкой , а за их постоянным изменением, для этого нет необходимости включать в код постоянные проверки и чтение GetLastError, можно в окне дебагирования Visual C++ ввести @err,hr. В окне вы увидите значение переменной ошибки.
Так как ошибки, которые возникают в программе, возникают не только в процессе отладки, но могут быть обусловлены текущим состоянием системы, на которй бежит программа, то иногда бывает полезно сообщить тип ошибки в нормальном текстовом виде.
В Windows есть специальная функция, которая "конвертирует" код ошибки в ее описание, - FormatMessage.
Для разработчика особенно важно, при создании API или SDK подобных вещей, создавать сходный механизм возврата ошибок для своих функций.
С этой целью вы просто устанавливаете код последней ошибки в потоке и возвращаете значение FALSE, INVALID_HANDLE_VALUE, NULL или что-то другое, более подходящее по ситуации. Чтобы установить код последней ошибки в потоке используйте SetLastError.
Параметр - 32-битное число. Использовать лучше подходящий код ошибки Windows, однако если такового подходящего не нашлось, то можно ввести свой собственный код ошибки. Он должен представлять собой 32-битное число, разбитое по следующим правилам.
Биты
31-30 - Код тяжести - 0=успех, 1=информация, 2=предупреждение, 3=ошибка
29 - Кем определен - 0-Microsoft 1-пользователем
28 - Должен быть 0
27-16 - Определяется Microsoft. (Код подсистемы)
15-0 - Код ошибки.
Собственно Microsoft обещает, что бит 29 будет в ее ошибках всегда равен 0 поэтому, поставив там 1, вы будете в какой-то степени в безопасности от конфликтов с кодами ошибок Microsoft.
При разработке больших приложений, оперирующих большими объемами информации на первое место при отладке встает проблема обнаружения неправильного распределения памяти. Суть проблемы состоит в том, что если мы выделили участок памяти, а затем освободили не весь выделенный объем, то образуются блоки памяти, которые помечены как занятые, но на самом деле они не используются. При длительной работе программы такие блоки могут накапливаться, приводя к значительному расходу памяти.
Для обнаружения подобных ошибок создано специализированное программное обеспечение (типа BoundsChecker от Numega), однако чаще бывает удобнее встроить механизм обнаружения утечки в свои проекты. Поэтому метод должен быть простым, и в то же время как можно более универсальным. Кроме того, не хотелось бы переписывать годами накопленные мегабайты кода, написанного и отлаженного задолго до того, как вам пришло в голову оградить себя от ошибок. Так что к списку требований добавляется стандартизация, т.е. нужно каким-то образом встроить защиту от ошибок в стандартный код.
Предлагаемое решение основывается на перегрузке стандартных операторов распределения памяти new и delete. Причем перегружать мы будем глобальные операторы new|delete, т.к. переписать эти операторы для каждого разработанного ранее класса было бы очень трудоемким процессом. Т.о. после перегрузки нам нужно будет только отследить распределение памяти и, соответственно, освобождение ее в момент завершения программы. Все несоответствия - ошибка.
Реализация
Проект написан на Visual C++, но переписать его на любой другой диалект С++ не будет слишком сложной задачей. Во-первых, нужно переопределить стандартные операторы new и delete так, чтобы это работало во всех проектах. Поэтому в stdafx.h добавляем следующий фрагмент:
Как видите, переопределение операторов происходит в блоке #ifdef/#endif. Это ограждает наш код от влияния на релиз компилируемой программы. Вы, наверное, заметили, что теперь оператор new имеет три параметра вместо одного. Два дополнительных параметра содержат имя файла и номер строки, в которой выделяется память. Это удобно для обнаружения конкретного места, где происходит ошибка. Однако код наших проектов по-прежнему ссылается на оператор new, принимающий один параметр. Для исправления этого несоответствия нужно добавиить следующий фрагмент
Теперь все наши операторы new будут вызываться с тремя параметрами, причем недостающие параметры подставит препроцессор. Конечно, пустые переопределенные функции ни в чем нам не помогут, так что давайте добавим в них какой-нибудь код:
Для полноты картины нужно переопределить операторы new[] и delete[], однако никаких существенных отличий здесь нет - творите!
Последний штрих - пишем функции AddTrack() и RemoveTrack(). Для создания списка используемых блоков памяти будем использовать стандартные средства STL:
Перед самым завершением программы наш список allocList содержит ссылки на блоки памяти, котороые не были освобождены. Все, что нужно сделать - вывести эту информацию куда-нибудь. В нашем проекте мы выведем список неосвобожденных участков памяти в окно вывода отладочных сообщений Visual C++:
Надеюсь, этот проект сделает ваши баг-листы короче, а программы устойчивее. Удачи!
Изменяя аргумент iAngle, можно вращать начальную точку - центр. А изменяя iSector можно выводить текст как по окружности, так и по дуге (она задается в градусах). Наверняка многие видели такой эффектик. Какой-нибудь текст крутится вокруг центра и меняется его радиус - расстояние от центра до букв. И тут можно такое же сделать. Для этого надо вызывать эту процедуру по таймеру, где перед вызовом изменять iAngle и iR (переменные завести). Только перед каждым рисованием, надо в этой функции очищать уже нарисованное, чтобы не оставалось старого. А если это непосредственно на канве делается медленно и мигает, но надо рисовать на битмапе и оттуда изображение копировать.
Для программирования расширенных хранимых процедур Microsoft предоставляет ODS (Open Data Service) API набор макросов и функций, используемых для построения серверных приложений позволяющих расширить функциональность MS SQL Server 2000.
Расширенные хранимые процедуры - это обычные функции написанные на С/C++ с применением ODS API и WIN32 API, оформленные в виде библиотеки динамической компоновки (dll) и призванные, как я уже говорил, расширять функциональность SQL сервера. ODS API предоставляет разработчику богатый набор функций позволяющих передавать данные клиенту, полученные от любых внешних источников данных (data source) в виде обычных наборов записей (record set). Так же, extended stored procedure может возвращать значения через переданный ей параметр (OUTPUT parametr).
Как работают расширенные хранимые процедуры.
* Когда клиентское приложение вызывает расширенную хранимую процедуру, запрос передаётся в TDS формате через сетевую библиотеку Net-Libraries и Open Data Service ядру MS SQL SERVER.
* SQL Sever находит dll библиотеку ассоциированную с именем расширенной хранимой процедуры и загружает её в свой контекст, если она не была загружена туда ранее, и вызывает расширенную хранимую процедуру, реализованную как функцию внутри dll.
* Расширенная хранимая процедура выполняет на сервере необходимые ей действия и передаёт набор результатов клиентскому приложению, используя сервис предоставляемый ODS API.
Особенности расширенных хранимых процедур.
* Расширенные хранимые процедуры - это функции выполняющиеся в адресном пространстве MS SQL Server и в контексте безопасности учётной записи под которой запущена служба MS SQL Server;
* После того, как dll библиотека с расширенными хранимыми процедурами была загружена в память, она остаётся там до тех пор, пока SQL Server не будет остановлен, или пока администратор не выгрузит её принудительно, используя команду :
DBCC DLL_name (FREE).
* Расширенная хранимая процедура запускается на выполнение так же, как и обычная хранимая процедура:
EXECUTE xp_extendedProcName @param1, @param2 OUTPUT
@param1 входной параметр
@param2 входной/выходной параметр
Внимание!
Так как расширенные хранимые процедуры выполняются в адресном пространстве процесса службы MS SQL Server, любые критические ошибки, возникающие в их работе, могут вывести из строя ядро сервера, поэтому рекомендуется тщательно протестировать Вашу DLL перед установкой на рабочий сервер.
Создание расширенных хранимых процедур.
Расширенная хранимая процедура эта функция имеющая следующий прототип:
Параметр pSrvProc указатель на SRVPROC структуру, которая является описателем (handle) каждого конкретного клиентского подключения. Поля этой структуры недокументированны и содеражат информацию, которую библиотека ODS использует для управления коммуникацией и данными между серверным приложением (Open Data Services server application) и клиентом. В любом случае, Вам не потребуется обращаться к этой структуре и тем более нельзя модифицоравать её. Этот параметр требуется указывать при вызове любой функции ODS API, поэтому в дальнейшем я небуду останавливаться на его описании.
Использование префикса xp_ необязательно, однако существует соглашение начинать имя расширенной хранимой процедуры именно так, чтобы подчеркнуть отличие от обычной хранимой процедуры, имена которых, как Вы знаете, принято начинать с префикса sp_.
Так же следует помнить, что имена расширенных хранимых процедур чувствительны к регистру. Не забывайте об этом, когда будете вызвать расширенную хранимую процедуру, иначе вместо ожидаемого результата, Вы получите сообщение об ошибке.
Если Вам необходимо написать код инициализации/деинициализации dll, используйте для этого стандартную функцию DllMain(). Если у Вас нет такой необходимости, и вы не хотите писать DLLMain(), то компилятор соберёт свою версию функции DLLMain(), которая ничего не делает, а просто возвращает TRUE. Все функции, вызываемые из dll (т.е. расширенные хранимые процедуры) должны быть объявлены, как экспортируемые. Если Вы пишете на MS Visual C++ используйте директиву __declspec(dllexport). Если Ваш компилятор не поддерживает эту директиву, опишите экспортируемую функцию в секции EXPORTS в DEF файле.
Итак, для создания проекта, нам понадобятся следующие файлы:
* Srv.h заголовочный файл, содержит описание функций и макросов ODS API;
* Opends60.lib файл импорта библиотеки Opends60.dll, которая и реализует весь сервис предоставляемый ODS API.
Microsoft настоятельно рекомендует, чтобы все DLL библиотеки реализующие расширенные хранимые процедуры экспортировали функцию:
Когда MS SQL Server загружает DLL c extended stored procedure, он первым делом вызывает эту функцию, чтобы получить информацию о версии используемой библиотеки.
Для написания своей первой extended stored procedure, Вам понадобится установить на свой компьютер:
- MS SQL Server 2000 любой редакции (у меня стоит Personal Edition). В процесе инсталляции обязательно выберите опцию source sample
- MS Visual C++ (я использовал версию 7.0 ), но точно знаю подойдёт и 6.0
Установка SQL Server -a нужна для тестирования и отладки Вашей DLL. Возможна и отладка по сети, но я этого никогда не делал, и поэтому установил всё на свой локальный диск. В поставку Microsoft Visual C++ 7.0 редакции Interprise Edition входит мастер Extended Stored Procedure DLL Wizard. В принципе, ничего сверх естественного он не делает, а только генерирует заготовку шаблон расширенной хранимой процедуры. Если Вам нравятся мастера, можете использовать его. Я же предпочитаю делать всё ручками, и поэтому не буду рассматривать этот случай.
Теперь к делу:
- Запустите Visual C++ и создайте новый проект - Win32 Dynamic Link Library.
- Включите в проект заголовочный файл - #include <srv.h>;
- Зайдите в меню Tools => Options и добавьте пути поиска include и library файлов. Если , при установке MS SQL Server, Вы ничего не меняли, то задайте:
- C:Program FilesMicrosoft SQL Server80ToolsDevToolsInclude для заголовочных файлов;
- C:Program FilesMicrosoft SQL Server80ToolsDevToolsLib для библиотечных файлов.
- Укажите имя библиотечного файла opends60.lib в опциях линкера.
На этом подготовительный этап закончен, можно приступать к написанию своей первой extended stored procedure.
Постановка задачи.
Прежде чем приступать к программированию, необходимо чётко представлять с чего начать, какой должен быть конечный результат, и каким способом его добиться. Итак, вот нам техническое задание:
Разработать расширенную хранимую процедуру для MS SQL Server 2000, которая получает полный список пользователей зарегистрированных в домене, и возвращает его клиенту в виде стандартного набора записей (record set). В качестве первого входного параметра функция получает имя сервера содержащего базу данных каталога (Active Directory), т.е имя контролера домена. Если этот параметр равен NULL, тогда необходимо передать клиенту список локальных групп. Второй параметр будет использоваться extended stored procedure для возварата значения результата успешной/неуспешной работы (OUTPUT параметр). Если, расширенная хранимая процедура выполнена успешно, тогда необходимо передать количество записей возвращённых в клиентский record set , если в процессе работы не удалось получить требуемую информацию, значение второго параметра необходимо установить в -1, как признак неуспешного завершения.
.
А вот шаблон расширенной хранимой процедуры, который нам предстоит наполнить содержанием:
Работа с входными параметрами
В этой главе я не хочу рассеивать Ваше внимание на посторонних вещах, а хочу сосредоточить его на работе с переданными в расширенную хранимую процедуру параметрами. Поэтуму мы несколько упростим наше техническое задание и разработаем тольку ту его часть, которая работает с входными параметрами. Но сначал не много теории
Первое действие, которое должна выполнить наша exteneded stored procedure , - получить параметры, которые были переданы ей при вызове. Следуя приведённому выше алгоритму нам необходимо выполнить следующие действия:
- Определить кол-во переданных параметров;
- Убедится, что переданные параметры имеют верный тип данных;
- Убедиться, что указанный OUTPUT параметр имеет достаточную длину, для сохранения в нём значения возвращаемого нашей extended stored procedure.
- Получить переданные параметры;
- Установить значения выходного параметра как результат успешного/неуспешного завершения работы extended stored procedure .
Теперь рассмотрим подробно каждый пункт:
Определение количества переданных в расширенную хранимую процедуру параметров
Для получения количества переданных параметров необходимо использовать функцию:
.
При успешном завершении функция возвращает количество переданных в расширенную хранимую процедуру параметров. Если extended stored procedure была вызвана без параметров - srv_rpcparams ввернёт -1. Параметры могут быть переданы по имени или по позиции (unnamed). В любом случае, нельзя смешивать эти два способа. Попытка передачи в функцию входных параметров по имени и по позиции одновременно - приведёт к возникновению ошибки, и srv_rpcparams вернёт 0 .
[pagebreak]
Определение типа данных и длины переданых параметров
Для получения информации о типе и длине переданных параметров Microsoft рекомендует использовать функцию srv_paramifo. Эта универсальная функция заменяет вызовы srv_paramtype, srv_paramlen, srv_parammaxlen, которые теперь считаются устаревшими. Вот её прототип:
.
.
.
.
.
.
.
.
.
.
pByte - указатель на переменную получающую информацию о типе входного параметра;
pbType задаёт порядковый номер параметра. Номер первого параметра начинается с 1.
pcbMaxLen - указатель на переменную, в которую функция заносит максимальное значение длины параметра. Это значение обусловлено конкретным типом данных переданного параметра, его мы и будем использовать, чтобы убедиться втом, что OUTPUT параметр имеет достаточную длину для сохранения передаваемых данных.
pcbActualLen указатель на реальную длину параметра переданного в расширенную хранимую процедуру при вызове. Если передаваемый параметр имеет нулевую длину, а флаг pfNull устанавлен в FALSE то (* pcbActualLen) ==0.
pbData - указатель на буфер, память для которого должна быть выделена перед вызовом srv_paraminfo. В этом буфере функция размещает полученные от extended stored procedure входные параметры. Размер буфера в байтах равен значению pcbMaxLen. Если этот параметр установлен в NULL, данные в буфер не записываются, но функция корректно возвращает значения *pbType, *pcbMaxLen, *pcbActualLen, *pfNull. Поэтому вызывать srv_paraminfo нужно дважды: сначала с pbData=NULL, потом, выделив необходимый размер памяти под буфер равный pcbActualLen, вызвать srv_paraminfo второй раз, передав в pbData указатель на выделенный блок памяти.
pfNull указатель на NULL-флаг. srv_paraminfo устанавливает его в TRUE, если значение входного параметра равно NULL.
Проверка, является ли второй параметр OUTPUT параметром.
Функция srv_paramstatus() предназначена для определения статуса переданного параметра:
.
.
.
.
.
n - номер параметра переданного в расширенную хранимую процедуру при вызове. Напомню: параметры всегда нумеруются с 1.
Для возврата значения, srv_paramstatus использует нулевой бит. Если он установлен в 1 переданный параметр является OUTPUT параметром, если в 0 обычным параметром, переданным по значению. Если, exteneded stored procedure была вызвана без параметров, функция вернёт -1.
Установка значения выходного параметра.
Выходному параметру, переданному в расширеную хранимую можно передать значение используя функцию srv_paramsetoutput. Эта новая функция заменяет вызов функции srv_paramset, которая теперь считается устаревашай, т.к. не поддерживает новые типы данных введённые в ODS API и данные нулевой длины.
.
.
.
.
.
.
.
.
n - порядковый номер параметра, которому будет присвоено новое значение. Это должен быть OUTPUT параметр.
pbData указатель на буфер с данными, которые будут посланы клиенту для установки значения выходного параметра.
cbLen длина буфера посылаемых данных. Если тип данных переданного OUTPUT параметра определяет данные постоянной длины и не разрешает хранение значения NULL (например SRVBIT или SRVINT1), то функция игнорирует параметр cbLen. Значение cbLen=0 указывает на данные нулевой длины, при этом парметр fNull должен быть установлен в FALSE.
fNull установите этот его в TRUE, если возвращаемому параметру необходимо присвоить значение NULL, при этом значение cbLen должно быть равно 0, иначе функция завершится с ошибкой. Во всех остальных случаях fNull=FALSE.
В случае успешного завершения функция возвращает SUCCEED. Если возвращаемое значение равно FAIL, значит вызов был неудачным. Всё просто и понятно
Теперь мы достаточно знаем, для того чтобы написать свою первую расширенную хранимую процедуру, которая будет возвращать значение через переданный ей параметр.Пусть, по сложившейся традиции, это будет строка Hello world! Отладочну версию примера можно скачать здесь.
. Не рассмотренными остались функции srv_sendmsg и srv_senddone. Функция srv_sendmsg используется для посылки сообщений клиенту. Вот её прототип:
msgtype определяет тип посылаемого клиенту сообщения. Константа SRV_MSG_INFO обозначает информационное сообщение, а SRV_MSG_ERROR сообщение об ошибке;
msgnum номер сообщения;
class - степень тяжести возникшей ошибки. Информационные сообщения имеют значение степени тяжести меньшее или равное 10;
state номер состояния ошибки для текущего сообщения. Этот параметр предоставляет информацию о контексте возникшей ошибки. Допустимые значения лежат в диапазоне от 0 до 127;
rpcname в настоящее время не используется;
rpcnamelen - в настоящее время не используется;
linenum здесь можно указать номер строки исходного кода. По этому значению, в последствие будет легко установить в каком месте возникла ошибка. Если Вы не хотите использовать эту возможность, тогда установите linenum в 0;
message указатель на строку посылаемую клиенту;
msglen определяет длину в байтах строки сообщения. Если это строка заканчивается нулевым символом, то значение этого параметра можно установить равным SRV_NULLTERM.
Возвращаемыме значения:
- в случае успеха SUCCEED
- при неудаче FAIL.
В процессе работы расширенная хранимая процедура должна регулярно сообщать клиентскому приложению свой статус, т.е. посылать сообщения о выполненных действиях. Для этого и предназначена функция srv_senddone:
status - статус флаг. Значение этого параметра можно задавать использую логические операторы AND и OR для комбинирования констант приведённых в таблице:
Status flag Описание
SRV_DONE_FINAL Текущий набор результатов является окончательным;
SRV_DONE_MORE Текущий набор результатов не является окончательным следует ожидать очердную порцию данных;
SRV_DONE_COUNT Параметр count содержит верное значение
SRV_DONE_ERROR Используется для уведомления о возникновении ошибок и немедленном завершении.
into зарезервирован, необходимо установить в 0.
count количество результирующих наборов данных посылаемых клиенту. Если флаг status установлен в SRV_DONE_COUNT, то count должен содержать правильное количество посылаемый клиенту наборв записей.
Возвращаемыме значения:
- в случае успеха SUCCEED
- при неудаче FAIL.
Установка расширенных хранимых процедур на MS SQL Server 2000
1.Скопируйте dll библиотеку с расширенной хранимой процедурой в каталог binn на машине с установленным MS SQL Server. У меня этот путь следующий: C:Program FilesMicrosoft SQL ServerMSSQLBinn;
2.Зарегистрирйте расширенную хранимую процедуру на серверt выполнив следующий скрипт:
Заключение
На этом первая часть моей статьи закончена. Теперь я уверен Вы готовы справиться с нашим техническим заданием на все 100%. В следующей статье Вы узнаете:
- Типы данных определённые в ODS API;
- Особенности отладки расширенных хранимых процдур;
- Как формировать recordset-ы и передавать их клиентскому приложению;
- Чстично мы рассмотрим функции Active Directory Network Manegment API необходимые для получения списка доменных пользователей;
- Создадим готовый проект (реализуем наше техническое задание)
Надеюсь - до скорой встречи!
Итак, вот оно время торжественного открытия, ваш шедевр уже занимает почетное место на бескрайних просторах всемирной сети. Все превосходно выглядит, смотрится потрясающе - но, это только половина Вашего успеха. Теперь всю эту красоту нужно донести до широкой аудитории.
В сети существует множество способов, которые могут помочь для успешной раскрутки проекта, но не каждым стоит пользоваться! Существует много подводных камней, речь о которых пойдет в этой статье по ходу описания.
Эта статья о том, как можно быстро раскрутить проект и обойти все неприятности.
Вернемся немного, день открытия!!!
Первое, всегда начинайте, заявляйте, говорите, только тогда, когда проект уже полностью закончен. Любой посетитель, увидев табличку Under construction, навсегда уйдет и больше не вернется.
Первый этап
Первым делом вам нужно обзавестись статистикой, по моему мнению, сейчас несомненным лидером является Hotlog.ru. Бесплатный проект. Множество статистики и отчетов, засчитывает реальный IP один раз.
После чего нужно зарегистрироваться в ТОПах, о пользе прочтете ниже.
ТОП это еще и поиск по ключевым словам и не только рейтинг, что очень важно в раскрутке. Старайтесь четко определится с тематикой. При регистрации обратите внимание, что в вашей рубрике существуют подразделы, соответственно чем меньше сайтов в них, тем более реально выбиться в число первых. Если в разделе более тысячи сайтов и у первой десятке более 1000 посещений в день, соответственно вам будет трудно пробиться к вершине, а вот сотня другая, это как раз то, что нужно.
Для топов лидеры - Rambler.ru, Mail.ru, Rax.ru, требуется наличие логотипа-счетчика. И еще устанавливайте счетчики на всех страницах, ведь интересно знать кого, что интересует и не что в дальнейшем делать упор.
Вторым элементом, являются поисковые системы. Дело это потребует от вас множество усилий. Найти сотню другую популярных - очень просто. Зайдите в рейтинг на Rambler или SpyLog.ru - Интернет>поисковые системы. В Большинстве отечественных регистрация бесплатно, среди зарубежных бесплатных с каждым днем становиться все меньше. Тут все просто, заходите по ссылке - Добавить URL.. и вписываем в форму все Ваши данные и ключевые слова. Есть одна проблема, Большинство таких систем могут проиндексировать сайт через 1-2 недели, а то и месяца. Есть уникальные, по 6 месяцев и то не обещают.
Наберитесь терпения. Не забывайте о важных правилах. Для правильного написания Мета тегов, читайте здесь и воспользуйтесь генератором. Прочтите статью Джефа Просиса "Web и роботы". При правильном написании Ваших данных Роботы поисковых систем выведут ваш сайт на первые места. В Запросах ваш сайт будет смотреться правильно, и вызывать доверие у будущих посетителей.
Придерживайтесь следующих правил: всегда публикуйте правдивую информацию, точно указывайте тему и направление проекта. Ведь вам не раз приходилось в поисках чего-то важного находить ссылку, говоря себе: -вот она!!! Ждать загрузки бесчисленной рекламы баннеров и не найти на сайте ничего подобного! Будьте точны, следуйте правилам сетевой этики и Вам воздастся!
Это и есть первый, самый важный этап.
Но спустя даже полугодие, Вы не обнаружите обилие посетителей, что же не правильно, почему так мало??? Может с контентом что-то не то? Есть вероятность. При создании постарайтесь насытить свой сайт множеством интересной информации, поставить "Информеры"( небольшой код, обновляющийся автоматически без вашего участия, в нем могут быть новости, погода, анекдоты и т.п.) придя на сайт посетитель может вновь вернуться за свежей информацией. Обязательно подписывайте заголовки страниц «title» .
Второй этап
Заставьте счетчик крутиться, крутиться, крутиться и сойти с ума. Большинство утверждают, что целевая аудитория не принесет желаемых посещений, во всяком случае сначала, Нужна быстрая раскрутка, даже если на сайт попадут и незаинтересованные пользователи. В общем, они правы. Вы можете возразить: "Минутку, а зачем мне привлекать незаинтересованных?" Ответ прост - все дело в рейтингах. Выше рейтинг - больше посетителей, в том числе и заинтересованных. Вот так ТОПы и будут поддерживать проект, чем выше ссылка в топах, тем больше посетителей.
Вспомните, когда Вы что-то искали в топах, всегда ли вы доходили до конца списков? Нет! не всегда. А при статистике 30-40 посетителей ваш рейтинг среди остальных будет где-то посередине. Итак, найдя в ТОПе Вашу ссылку ищущий нажимает на нее, тем самым повышает её рейтинг, так получается замкнутый круг. И счетчик уже будет показывать в десятки раз больше 300-400 и более посещений. Но как попасть хотя бы в первые 5 страниц рейтингов. Ответ здесь - NeoSap.ru. Это система накруток незаинтересованных в Вашей информации, попросту серферы, которые будут просматривать ваш сайт.
Регистрация бесплатная, У Вас на счету должны быть единицы системы, в данном случае это кредиты. В среднем один кредит - одно посещение, кредиты можно купить, а можно и заработать. Заработать легче всего, кредит начисляется за просмотр Вами сайта партнера, то есть такого же, как и вы. За час можно просмотреть около 100 сайтов, даже в авторежиме, окно эксплорера в фоне грузит страницы и Вам начисляются кредиты. Соответственно такое же число просмотров будет и у вас на сайте, реальными пользователями. Ну что решились тогда вам сюда Регистрация.
Одно немаловажное правило, внимательно читайте пользовательское соглашение ТОПов, а именно пункт о накрутке, за такие действия Вас из рейтинга и удалить могут. Поэтому в настройках NeoSap указывайте в режиме просмотр сайтов "Ручной серфинг" - обязательно. Настройте время просмотра, что бы посещения были равномерными. Это очень важный пункт, не пренебрегайте им.
Этап третий
Баннерообменные системы. В этих системах можно и нужно регистрироваться, но только тогда когда счетчик стабильно выдает более 100 посетителей в сутки. Иначе не будет смысла насыщать страницу рекламой, тем самым, портя вид. В системах существует индекс показов. К примеру при 500 показах в день, Ваш рекламный баннер будет иметь индекс 90%, то есть показываться где-то 450 раз, а при 20-30 посетителях индекс равен 3-5%. Выбирайте надежную систему если вы на Украине могу посоветовать УБС.
Правило - Не ставьте баннер вверху страницы, не эстетично, поместите в самый низ, если выберите небольшой где-то в стороне.
Заключение
Вот мы и сделали первый шаг к масштабной раскрутке проекта. Немаловажным фактом является автоподпись писем, обязательно укажите в нем адрес страницы. При посещении сайтов подобной тематики, оставляйте записи и комментарии в гостевых книгах и форумах, конечно со ссылкой на сайт и результат не заставит долго ждать.
Как правило, выделенный сервер для хостинга заказывает себе компания, у которой достаточно большие запросы по нагрузке процессора, оперативной памяти, нагрузке на базу данных и емкий винчестер. Управление выделенным сервером ложиться либо на саму компания, либо можно заказать услугу администрирования сервера удаленно или в арендуемом дата-центре хостинг-провайдера.
Если ваш сайт вырос из уровня виртуального хостинга и активно использует ресурсы сервера, то есть смысл перенести его на отдельный сервер. Так вы не только будете избавлены от проблем с другими виртуальными хостами и перегруженностью сервера, но и получите все возможности для настройки и администрирования сервера для своих индивидуальных нужд.
Также на выделенном сервере можно организовать базу электронных почтовых ящиков, которая нужна будет вам при работе вашей фирмы. В рамках одного виртуального сервера можно без проблем обеспечить работу до 500 почтовых ящиков.
Это позволяет разрабатывать приложения, позволяющие хранить данные на стороне сервера, а также запросы и использовать скрипты для работы вашего сайта в полном объеме, не боясь, что вас отключат за чрезмерную нагрузку на процессор или базу данных.
Не забывайте и о трафике, ведь дл крупных ресурсов с графикой и файлами его величина в 1000GB и более не должна вызывать у вас удивления.
В любое время можно провести модернизацию оборудования, расширить пропускную способность канала, увеличить емкость винчестера и оперативной памяти, приобрести более быстрый процессор, поставить более совершенную систему охлаждения.
Протокол обмена управляющими сообщениями ICMP (Internet Control Message Protocol) позволяет маршрутизатору сообщить конечному узлу об ошибках, с которыми машрутизатор столкнулся при передаче какого-либо IP-пакета от данного конечного узла.
Управляющие сообщения ICMP не могут направляться промежуточному маршрутизатору, который участвовал в передаче пакета, с которым возникли проблемы, так как для такой посылки нет адресной информации - пакет несет в себе только адрес источника и адрес назначения, не фиксируя адреса промежуточных маршрутизаторов.
Протокол ICMP - это протокол сообщения об ошибках, а не протокол коррекции ошибок. Конечный узел может предпринять некоторые действия для того, чтобы ошибка больше не возникала, но эти действия протоколом ICMP не регламентируются.
Каждое сообщение протокола ICMP передается по сети внутри пакета IP. Пакеты IP с сообщениями ICMP маршрутизируются точно так же, как и любые другие пакеты, без приоритетов, поэтому они также могут теряться. Кроме того, в загруженной сети они могут вызывать дополнительную загрузку маршрутизаторов. Для того, чтобы не вызывать лавины сообщения об ошибках, потери пакетов IP, переносящие сообщения ICMP об ошибках, не могут порождать новые сообщения ICMP.
Формат сообщений протокола ICMP
Существует несколько типов сообщений ICMP. Каждый тип сообщения имеет свой формат, при этом все они начинаются с общих трех полей: 8-битного целого числа, обозначающего тип сообщения (TYPE), 8-битного поля кода (CODE), который конкретизирует назначение сообщения, и 16-битного поля контрольной суммы (CHECKSUM). Кроме того, сообщение ICMP всегда содержит заголовок и первые 64 бита данных пакета IP, который вызвал ошибку.
Это делается для того, чтобы узел-отправитель смог более точно проанализировать причину ошибки, так как все протоколы прикладного уровня стека TCP/IP содержат наиболее важную информацию для анализа в первых 64 битах своих сообщений.
Поле типа может иметь следующие значения:
Значение | Тип сообщения
0_________Эхо-ответ (Echo Replay)
3_________Узел назначения недостижим (Destination Unreachable)
4_________Подавление источника (Source Quench)
5_________Перенаправление маршрута (Redirect)
8_________Эхо-запрос (Echo Request)
11________Истечение времени дейтаграммы (Time Exceeded for a Datagram)
12________Проблема с параметром пакета (Parameter Problem on a Datagram)
13________Запрос отметки времени (Timestamp Request)
14________Ответ отметки времени (Timestamp Replay)
17________Запрос маски (Address Mask Request)
18________Ответ маски (Address Mask Replay)
Как видно из используемых типов сообщений, протокол ICMP представляет собой некоторое объединение протоколов, решающих свои узкие задачи.
Эхо-протокол
Протокол ICMP предоставляет сетевым администраторам средства для тестирования достижимости узлов сети. Эти средства представляют собой очень простой эхо-протокол, включающий обмен двумя типами сообщений: эхо-запрос и эхо-ответ. Компьютер или маршрутизатор посылают по интерсети эхо-запрос, в котором указывают IP-адрес узла, достижимость которого нужно проверить. Узел, который получает эхо-запрос, формирует и отправляет эхо-ответ и возвращает сообщение узлу - отправителю запроса.
В запросе могут содержаться некоторые данные, которые должны быть возвращены в ответе. Так как эхо-запрос и эхо-ответ передаются по сети внутри IP-пакетов, то их успешная доставка означает нормальное функционирование всей транспортной системы интерсети.
Во многих операционных системах используется утилита ping, которая предназначена для тестирования достижимости узлов. Эта утилита обычно посылает серию эхо-запросов к тестируемому узлу и предоставляет пользователю статистику об утерянных эхо-ответах и среднем времени реакции сети на запросы.
Сообщения о недостижимости узла назначения
Когда маршрутизатор не может передать или доставить IP-пакет, он отсылает узлу, отправившему этот пакет, сообщение "Узел назначения недостижим" (тип сообщения - 3). Это сообщение содержит в поле кода значение, уточняющее причину, по которой пакет не был доставлен. Причина кодируется следующим образом:
Код - | - Причина
0________Сеть недостижима
1________Узел недостижим
2________Протокол недостижим
3________Порт недостижим
4________Требуется фрагментация, а бит DF установлен
5________Ошибка в маршруте, заданном источником
6________Сеть назначения неизвестна
7________Узел назначения неизвестен
8________Узел-источник изолирован
9________Взаимодействие с сетью назначения административно запрещено
10_______Взаимодействие с узлом назначения административно запрещено
11_______Сеть недостижима для заданного класса сервиса
12_______Узел недостижим для заданного класса сервиса
Маршрутизатор, обнаруживший по какой-либо причине, что он не может передать IP-пакет далее по сети, должен отправить ICMP-сообщение узлу-источнику, и только потом отбросить пакет. Кроме причины ошибки, ICMP-сообщение включает также заголовок недоставленного пакета и его первые 64 бита поля данных.
Узел или сеть назначения могут быть недостижимы из-за временной неработоспособности аппаратуры, из-за того, что отправитель указал неверный адрес назначения, а также из-за того, что маршрутизатор не имеет данных о маршруте к сети назначения.
Недостижимость протокола и порта означают отсутствие реализации какого-либо протокола прикладного уровня в узле назначения или же отсутствие открытого порта протоколов UDP или TCP в узле назначения.
Ошибка фрагментации возникает тогда, когда отправитель послал в сеть пакет с признаком DF, запрещающим фрагментацию, а маршрутизатор столкнулся с необходимостью передачи этого пакета в сеть со значением MTU меньшим, чем размер пакета.
Перенаправление маршрута
Маршрутные таблицы у компьютеров обычно являются статическими, так как конфигурируются администратором сети, а у маршрутизаторов - динамическими, формируемыми автоматически с помощью протоколов обмена маршрутной информации. Поэтому с течением времени при изменении топологии сети маршрутные таблицы компьютеров могут устаревать. Кроме того, эти таблицы обычно содержат минимум информации, например, только адреса нескольких маршрутизаторов.
Для корректировки поведения компьютеров маршрутизатор может использовать сообщение протокола ICMP, называемое "Перенаправление маршрута" (Redirect).
Это сообщение посылается в том случае, когда маршрутизатор видит, что компьютер отправляет пакет некоторой сети назначения нерациональным образом, то есть не тому маршрутизатору локальной сети, от которого начинается более короткий маршрут к сети назначения.
Механизм перенаправления протокола ICMP позволяет компьютерам содержать в конфигурационном файле только IP-адреса его локальных маршрутизаторов. С помощью сообщений о перенаправлении маршрутизаторы будут сообщать компьютеру всю необходимую ему информацию о том, какому маршрутизатору следует отправлять пакеты для той или иной сети назначения. То есть маршрутизаторы передадут компьютеру нужную ему часть их таблиц маршрутизации.
В сообщении "Перенаправление маршрута" маршрутизатор помещает IP-адрес маршрутизатора, которым нужно пользоваться в дальнейшем, и заголовок исходного пакета с первыми 64 битами его поля данных. Из заголовка пакета узел узнает, для какой сети необходимо пользоваться указанным маршрутизатором.