Банк рефератов содержит более 364 тысяч рефератов, курсовых и дипломных работ, шпаргалок и докладов по различным дисциплинам: истории, психологии, экономике, менеджменту, философии, праву, экологии. А также изложения, сочинения по литературе, отчеты по практике, топики по английскому.
Полнотекстовый поиск
Всего работ:
364139
Теги названий
Разделы
Авиация и космонавтика (304)
Административное право (123)
Арбитражный процесс (23)
Архитектура (113)
Астрология (4)
Астрономия (4814)
Банковское дело (5227)
Безопасность жизнедеятельности (2616)
Биографии (3423)
Биология (4214)
Биология и химия (1518)
Биржевое дело (68)
Ботаника и сельское хоз-во (2836)
Бухгалтерский учет и аудит (8269)
Валютные отношения (50)
Ветеринария (50)
Военная кафедра (762)
ГДЗ (2)
География (5275)
Геодезия (30)
Геология (1222)
Геополитика (43)
Государство и право (20403)
Гражданское право и процесс (465)
Делопроизводство (19)
Деньги и кредит (108)
ЕГЭ (173)
Естествознание (96)
Журналистика (899)
ЗНО (54)
Зоология (34)
Издательское дело и полиграфия (476)
Инвестиции (106)
Иностранный язык (62791)
Информатика (3562)
Информатика, программирование (6444)
Исторические личности (2165)
История (21319)
История техники (766)
Кибернетика (64)
Коммуникации и связь (3145)
Компьютерные науки (60)
Косметология (17)
Краеведение и этнография (588)
Краткое содержание произведений (1000)
Криминалистика (106)
Криминология (48)
Криптология (3)
Кулинария (1167)
Культура и искусство (8485)
Культурология (537)
Литература : зарубежная (2044)
Литература и русский язык (11657)
Логика (532)
Логистика (21)
Маркетинг (7985)
Математика (3721)
Медицина, здоровье (10549)
Медицинские науки (88)
Международное публичное право (58)
Международное частное право (36)
Международные отношения (2257)
Менеджмент (12491)
Металлургия (91)
Москвоведение (797)
Музыка (1338)
Муниципальное право (24)
Налоги, налогообложение (214)
Наука и техника (1141)
Начертательная геометрия (3)
Оккультизм и уфология (8)
Остальные рефераты (21692)
Педагогика (7850)
Политология (3801)
Право (682)
Право, юриспруденция (2881)
Предпринимательство (475)
Прикладные науки (1)
Промышленность, производство (7100)
Психология (8692)
психология, педагогика (4121)
Радиоэлектроника (443)
Реклама (952)
Религия и мифология (2967)
Риторика (23)
Сексология (748)
Социология (4876)
Статистика (95)
Страхование (107)
Строительные науки (7)
Строительство (2004)
Схемотехника (15)
Таможенная система (663)
Теория государства и права (240)
Теория организации (39)
Теплотехника (25)
Технология (624)
Товароведение (16)
Транспорт (2652)
Трудовое право (136)
Туризм (90)
Уголовное право и процесс (406)
Управление (95)
Управленческие науки (24)
Физика (3462)
Физкультура и спорт (4482)
Философия (7216)
Финансовые науки (4592)
Финансы (5386)
Фотография (3)
Химия (2244)
Хозяйственное право (23)
Цифровые устройства (29)
Экологическое право (35)
Экология (4517)
Экономика (20644)
Экономико-математическое моделирование (666)
Экономическая география (119)
Экономическая теория (2573)
Этика (889)
Юриспруденция (288)
Языковедение (148)
Языкознание, филология (1140)

Реферат: Как сделать чтобы запущеный exe сам себя удалил 2

Название: Как сделать чтобы запущеный exe сам себя удалил 2
Раздел: Рефераты по информатике
Тип: реферат Добавлен 01:30:20 27 марта 2011 Похожие работы
Просмотров: 11 Комментариев: 27 Оценило: 2 человек Средний балл: 5 Оценка: неизвестно     Скачать

Укрощение строптивого… CD-ROM

Алексей Фоминов

Кто не мечтает о быстром CD-ROM? Быстрый CD-ROM – это хорошо… с одной стороны. А если на компакт-диске появилась трещина? Быстрый CD-ROM – это уже нехорошо. На скорости 52х такой компакт-диск читать просто опасно. А если на этом диске жизненно важные данные? Выход есть. Просто снизить скорость привода. Если вы знакомы с языком программирования Object Pascal, тогда читайте далее.

Использование интерфейса SCSI

SCSI (Small Computer System Interface - интерфейс малой компьютерной системы) – шина ввода/вывода, которая разрабатывалась как метод соединения нескольких классов периферийных устройств в главную систему, не требующий внесения модификации в общие аппаратные средства и программное обеспечение.

Поскольку цель данной статьи рассказать читателю о том, как программно управлять устройствами, которые подключаются к SCSI-шине, а не о том, как написать драйвер SCSI-устройства, описывать технические особенности шины SCSI и её отличие от IDE я не буду.

Каким же образом операционная система Windows общается со SCSI-устройствами?

Это зависит от версии операционной системы. В системах семейства Windows 9х (95, 98, 98SE, Me) применяется ASPI (Advanced SCSI Programmer Interface – улучшенный интерфейс программирования SCSI). В стандартную поставку этих операционных систем входят ASPI-драйвер и библиотека для работы с ним, разработанные фирмой Adaptec. В системах семейства Windows NT (NT 4.0, 2000, XP, Server) используется SPTI (SCSI Pass Through Interface – интерфейс передачи через SCSI). То есть, в NT-системах компания Майкрософт полностью отказалась от продукта фирмы Adaptec и создала свой интерфейс общения со SCSI-устройствами. Принесло ли это пользу пользователям? Вряд ли. На мой субъективный взгляд, рядовому пользователю всё равно, как происходит доступ к SCSI, ему важно, чтобы всё работало правильно. Принесло ли это пользу разработчикам программного обеспечения? Однозначно нет. Теперь, разрабатывая приложения для управления SCSI-устройствами, разработчик должен либо создавать две версии своего продукта (одну для Win9x, другую для WinNT), либо включать поддержку двух интерфейсов в свой продукт, что вряд ли является целесообразным с точки зрения размера программы.

Какой из двух интерфейсов лучше, мне сказать трудно. Отмечу лишь то, что программа Nero использует ASPI-драйвер, специально разработанный для неё фирмой Adaptec.

Рассмотрим сначала программирование с помощью интерфейса ASPI, на примере управления приводом CD-ROM/R/RW.

Предполагается, что читатель умеет работать с динамически компонуемыми библиотеками (dll). Как вы будете подключать библиотеку для работы с ASPI-драйвером wnaspi32.dll (статически или динамически) – дело ваше, главное, чтобы ваше приложение правильно импортировало из этой библиотеки необходимые нам функции.

Я подключал эту библиотеку статически и импорт нужных нам функций у меня выглядел так:

function GetASPI32SupportInfo:DWORD; external 'wnaspi32.dll'

name 'GetASPI32SupportInfo';

function SendASPI32Command(LPSRB:Pointer):DWORD; external 'wnaspi32.dll'

name 'SendASPI32Command'.

Функция GetASPI32SupportInfo инициализирует ASPI и возвращает информацию об основной конфигурации. При успешном выполнении она возвращает двойное слово (DWORD), в котором старший байт младшего слова содержит статус ASPI, а младший байт – количество устройств (адаптеров), поддерживающих ASPI. Байт статуса может содержать следующие значения:

$01 – выполнено без ошибок;

$E8 – нет адаптеров;

$E2 – не может быть выполнено под управлением Windows 3.1;

$E3 – неправильная установка ASPI, или имеются конфликты ресурсов;

$E7 – установка ASPI нарушена (требуется повторная установка);

$E9 – недостаточно системных ресурсов для инициализации ASPI;

$E4 – общий внутренний сбой ASPI.

Количество возвращенных адаптеров представляет собой количество логических шин, а не физических адаптеров. Для адаптеров с единственной шиной количество адаптеров и количество логических шин идентичны.

Функция SendASPI32Command оперирует со всеми SCSI-запросами ввода/вывода. Каждый SCSI-запрос использует SCSI Request Block (SRB – Блока Запроса SCSI), определяющий операцию ASPI, которую нужно выполнить.

Параметр, передаваемый функции SendASPI32Command – указатель на определённую структуру. Описание этих структур приведено ниже.

type

SRB_HAInquiry = packed record

SRB_Cmd: Byte; // код команды ASPI (константа SC_HA_INQUIRY = $00)

SRB_Status, // байт статуса ASPI команды

SRB_HaId, // номер адаптера ASPI

SRB_Flags: Byte; // зарезервировано, должно быть 0

SRB_Hdr_Rsvd: Dword; // зарезервировано, должно быть 0

HA_Count: Byte; // количество адаптеров

HA_SCSI_ID: Byte; // ID SCSI-адаптера

HA_ManagerId: array [0..15] of Byte; // строка, описывающая менеджер

HA_Identifier: array [0..15] of Byte; // строка, описывающая адаптер

HA_Unique: array [0..15] of Byte; // уникальные параметры адаптера

HA_Rsvd1: Word; // зарезервировано, должно быть 0

end;

PSRB_HAInquiry = ^SRB_HAInquiry;

TSRB_HAInquiry = SRB_HAInquiry;

Структура TSRB_HAInquiry используется для получения информации о физических SCSI-адаптерах.

type

SRB_GDEVBlock = packed record

SRB_Cmd, // код команды ASPI (константа SC_GET_DEV_TYPE = $01);

SRB_Status, // байт статуса ASPI команды;

SRB_HaId, // номер адаптера ASPI;

SRB_Flags: Byte; // зарезервировано, должно быть 0;

SRB_Hdr_Rsvd: Dword; // зарезервировано, должно быть 0;

SRB_Target, // ID объекта SCSI;

SRB_Lun, // Logical Unit Number (LUN - логический номер устройства);

SRB_DeviceType, // тип периферийного устройства;

SRB_Rsvd1: Byte; // зарезервировано, должно быть 0;

end;

TSRB_GDEVBlock = SRB_GDEVBlock;

PSRB_GDEVBlock = ^SRB_GDEVBlock;

Структура TSRB_GDEVBlock используется для идентификации устройств на шине SCSI.

type

SRB_ExecSCSICmd = packed record

SRB_Cmd, // код команды ASPI (константа SC_EXEC_SCSI_CMD = $02)

SRB_Status, // байт статуса ASPI команды

SRB_HaId, // номер адаптера ASPI

SRB_Flags: Byte; // флаги запроса ASPI

SRB_Hdr_Rsvd: Dword; // зарезервировано, должно быть 0

SRB_Target, // ID объекта SCSI

SRB_Lun: Byte; // Logical Unit Number (LUN - логический номер устройства)

SRB_Rsvd1: Word; // зарезервировано для выравнивания

SRB_BufLen: Dword; // длина буфера

SRB_BufPointer: Pointer; // указатель на буфер данных

SRB_SenseLen, // длина значения;

SRB_CDBLen, // длина Command Descriptor Block – блока дескриптора команды

SRB_HaStat, // статус адаптера

SRB_TargStat: Byte; // статус объекта

SRB_PostProc, // указатель на функцию постинга (см.ниже)

SRB_Rsvd2: Pointer; // зарезервировано, должно быть 0;

SRB_Rsvd3, // зарезервировано для выравнивания

CDBByte: array [0..15] of byte; // SCSI Command Descriptor Block

// буфер значения для SCSI-запроса

SenseArea: array [0..SENSE_LEN + 1] of byte;

end;

TSRB_ExecSCSICmd = SRB_ExecSCSICmd;

PSRB_ExecSCSICmd = ^SRB_ExecSCSICmd;

Структура TSRB_ExecSCSICmd используется для выполнения команд ввода/вывода. Константа SENSE_LEN (длина буфера значения) по умолчанию равна 14.

На мой взгляд, теории пока достаточно. Перейду к практике.

Для начала инициализируем ASPI.

function GetASPI: Integer;

var

dwSupportInfo: DWORD;

byASPIStatus,byHACount: Byte;

begin

Result := 0;

dwSupportInfo := GetASPI32SupportInfo;

byASPIStatus := HIBYTE(LOWORD(dwSupportInfo)); // статус ASPI

byHACount := LOBYTE(LOWORD(dwSupportInfo)); // количество адаптеров

case byASPIStatus of

SS_COMP: Result := Integer(byHACount);

SS_NO_ADAPTERS: ShowMessage('ASPI-контроллеры не обнаружены!');

SS_ILLEGAL_MODE: ShowMessage(

'ASPI не может быть выполнен под управлением Windows 3.1!');

SS_NO_ASPI: ShowMessage(

'Неправильная установка ASPI, или имеются конфликты ресурсов!');

SS_MISMATCHED_COMPONENTS: ShowMessage(

'Установка ASPI нарушена! Установите повторно, пожалуйста!');

SS_INSUFFICIENT_RESOURCES: ShowMessage(

'Недостаточно системных ресурсов для инициализации ASPI!');

SS_FAILED_INIT: ShowMessage('Общий внутренний сбой ASPI!');

end;

end;

Итак, мы получили информацию об имеющихся SCSI-адаптерах. Теперь выделим из их числа (если их несколько) устройства CD-ROM/R/RW. Для этого создадим вспомогательные структуры: TCDROM и TCDROMs.

type

TCDROM=record

HaID, // номер адаптера ASPI

Target, // ID объекта SCSI

Lun: Byte; // логический номер устройства

DriveLetter: string; // буквенное обозначение диска

VendorID, // идентификатор производителя

ProductID, // идентификатор продукта

Revision, // изменение

VendorSpec, // спецификация производителя

Description: string; // описание

end;

Тип TCDROM будет хранить необходимые нам данные об устройствах CD-ROM.

type

TCDROMs=record

CdromCount: Byte;

Cdroms: array [Byte] of TCDROM;

end;

Поскольку у некоторых пользователей может быть подключено несколько CD-ROM, мы объявили тип TCDROMs, содержащий в себе информацию о количестве CD-ROM и массив элементов TCDROM. А теперь давайте напишем функцию для определения всех имеющихся в системе устройств CD-ROM, объявив перед этим глобальную переменную Cdroms: TCDROMs.

// в качестве параметра передаётся количество всех SCSI-адаптеров,

// имеющихся в системе. Результат работы функции – количество CD-ROM.

function GetCDROMs(var Adapters:Byte): Integer;

var

sh: TSRB_HAInquiry;

sd: TSRB_GDEVBlock;

maxTgt: Byte;

H, T, L: byte;

Begin

Result := 0;

if Adapters = 0 then

exit; // если количество адаптеров 0 – выходим

// начинаем перебирать все адаптеры

for H := 0 to Adapters - 1 do

begin

FillChar(sh,sizeof(sh),0); // инициализируем структуру TSRB_HAInquiry

// (константа SC_HA_INQUIRY = $00) запрос ASPI для получения информации

// об адаптерах.

sh.SRB_Cmd := SC_HA_INQUIRY;

sh.SRB_HaID := H;

SendASPI32Command(@sh); // посылаем ASPI команду

if sh.SRB_Status=SS_COMP then // если выполнено без ошибок, тогда:

begin

// четвёртый байт уникальных параметров определяет максимальное

// количество объектов SCSI

maxTgt := sh.HA_Unique[3];

// если этот байт равен 0, тогда присваиваем переменной максимально

// возможное значение (константа MAXTARG=7)

if maxTgt=0 then maxTgt := MAXTARG;

for T := 0 to maxTgt-1 do // начинаем перебирать все объекты SCSI

begin

for L := 0 to MAXLUN-1 do // и все логические номера устройств

begin

// инициализируем структуру TSRB_GDEVBlock

FillChar(sd,sizeof(sd),0);

// команда запрашивает тип устройства для объекта SCSI (константа

// SC_GET_DEV_TYPE = $01)

sd.SRB_Cmd := SC_GET_DEV_TYPE;

sd.SRB_HaID := H;

sd.SRB_Target := T;

sd.SRB_Lun := L;

SendASPI32Command(@sd); // посылаем ASPI-команду

// если выполнено без ошибок, и устройство является CD-ROM,

// заполняем переменную Cdroms.

if (sd.SRB_Status=SS_COMP) and (sd.SRB_DeviceType=DTYPE_CDROM) then

begin

Cdroms.Cdroms[Cdroms.CdromCount].HaID := H;

Cdroms.Cdroms[Cdroms.CdromCount].Target := T;

Cdroms.Cdroms[Cdroms.CdromCount].Lun := L;

// получаем информацию об этом CD-ROM

CdromInfo(Cdroms.CdromCount);

// увеличиваем счётчик количества устройств CD-ROM

inc(Cdroms.CdromCount);

end;

end;

end;

end;

end;

Result := Cdroms.CdromCount; // присваиваем результату функции количество CD-ROM

end;

Вы, наверное, обратили внимание на то, что в коде используется процедура CdromInfo. Это процедура, с помощью которой, мы получаем информацию о нашем CD-ROM. Перед тем, как привести её описание, я хочу рассказать вам о том, как происходит управление SCSI-устройствами посредством специальных команд, и как при этом используется структура TSRB_ExecSCSICmd.

Вот поля структуры TSRB_ExecSCSICmd, на которые нужно, прежде всего, обратить внимание: SRB_Cmd, SRB_Flags, SRB_CDBLen, CDBByte. Поле SRB_Cmd всегда должно содержать значение SC_EXEC_SCSI_CMD. Поле SRB_Flags должно определять направление передачи данных. Если данные передаются из SCSI-устройства в приложение, используется шестнадцатиричное значение $08 (определим это значение как константу SRB_DIR_IN). Если происходит обратная передача данных (от приложения к SCSI-устройству), используется шестнадцатиричное значение $10 (определим это значение как константу SRB_DIR_OUT). В зависимости от посылаемой команды, поле SRB_CDBLen может содержать значения: 6, 10 или 12. Массив байт CDBByte подробно описывает параметры выполняемой команды. Значение массива различно для всех команд. Замечу лишь, то, что нулевой байт этого массива всегда определяет код команды. Какие команды я имею в виду? Например: команда установки скорости CD-привода, команда записи CD-R или CD-RW-диска, команды управления аудио-CD (Play, Pause, Stop и так далее).

Существуют SCSI-команды, которые поддерживают все устройства, и есть команды, которые специфичны для определённого типа устройств. Первая команда, которую мы рассмотрим, команда INQUIRY, является обязательной для всех устройств. Она запрашивает информацию о SCSI-устройстве. А теперь собственно перейдём к коду процедуры:

// параметр, передаваемый процедуре – номер CD-ROM.

procedure CdromInfo(const Number: Byte);

var

// буфер будет содержать информацию о приводе

buffer: array [1..100] of Char;

begin

// инициализируем буфер (просто обнуляем его)

Fillchar(buffer, sizeof(buffer), 0);

// инициализируем структуру TSRB_ExecSCSICmd (глобальная переменная Srb)

Fillchar(Srb, sizeof(TSRB_ExecSCSICmd), 0);

hEvent := CreateEvent(nil, true, false, nil); // создаём событие

ResetEvent(hEvent); // переключаем на наше событие

with Srb do

begin

SRB_Cmd := SC_EXEC_SCSI_CMD;

SRB_HaId := Cdroms.Cdroms[Number].HaID;

SRB_Target := Cdroms.Cdroms[Number].Target;

SRB_Lun := Cdroms.Cdroms[Number].Lun;

// здесь добавляется ещё один флаг SRB_EVENT_NOTIFY ($40), уведомляющий

// систему о событии

SRB_Flags := SRB_DIR_IN or SRB_EVENT_NOTIFY;

SRB_BufLen := sizeof(buffer); // указываем размер буфера

SRB_BufPointer := @buffer; // определяем указатель на наш буфер

SRB_SenseLen := SENSE_LEN; // определяем длину буфера значения

SRB_CDBLen := 6; // эта команда – шестибайтная

SRB_PostProc := Pointer(hEvent); // процедура постинга – созданное событие

CDBByte[0] := $12; // код команды INQUIRY

// сюда помещаем старший байт длины буфера

CDBByte[3] := HIBYTE(sizeof(buffer));

// а сюда помещаем младший байт длины буфера

CDBByte[4] := LOBYTE(sizeof(buffer));

end;

// после того как заполнили структуру TSRB_ExecSCSICmd, посылаем

// ASPI-команду

dwASPIStatus := SendASPI32Command(@Srb);

if dwASPIStatus=SS_PENDING then

WaitForSingleObject(hEvent, INFINITE); // ждём окончания обработки команды

CloseHandle(hEvent); // закрываем хэндл события

// если команда выполнена без ошибок, заполняем данные об устройстве:

if Srb.SRB_Status=SS_COMP then

begin

with Cdroms.Cdroms[Number] do

begin

// восемь байт буфера, начиная с девятого, содержат

// идентификатор производителя

VendorID := PChar(Copy(buffer, 9, 8));

// шестнадцать байт, начиная с семнадцатого, содержат

// идентификатор продукта

ProductID := PChar(Copy(buffer, 17, 16));

// четыре байта, начиная с тридцать третьего, содержат номер

// изменения продукта

Revision := PChar(Copy(buffer, 33, 4));

// двадцать байт, начиная с тридцать седьмого, содержат

// спецификацию производителя

VendorSpec := PChar(Copy(buffer, 37, 20));

end;

end;

end;

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

Следующие две процедуры, на мой взгляд, заинтересуют большее число пользователей. Уверен, многие из вас постоянно пользуются, или пользовались ранее, программами, управляющими скоростью привода CD-ROM (например, программой CDSlow). Хотите написать подобную программу сами? Позвольте помочь вам кодом, состоящим из двух процедур, одна из которых определяет текущую и максимально поддерживаемую скорость привода, а другая устанавливает необходимую пользователю скорость.

Для этого я воспользовался SCSI-командой MODE SENSE(10). Цифра десять означает, что команда десятибайтная. Это важно, потому что существует такая же шестибайтная команда. В принципе, можно было бы воспользоваться и шестибайтной командой, но поскольку команда MODE SENSE(10) более совершенна, я остановил свой выбор на ней. Итак, для чего же нужна данная команда? Всё просто, она читает значения режимов (Mode Sense), установленных для SCSI-устройства. Существуют так называемые страницы режима (Mode Page), в которых хранится некоторая информация (например, параметры скорости привода, параметры для записи CD-R/RW-дисков и многое другое). Доступ к этим страницам осуществляется по их коду с использованием команды MODE SENSE.

Опишем вспомогательный тип TCDSpeeds.

type

TCDSpeeds=record

MaxSpeed, // максимальная скорость чтения

CurrentSpeed, // текущая скорость чтения

MaxWriteSpeed, // максимальная скорость записи

CurrentWriteSpeed:integer; // текущая скорость записи

end;

Теперь, я думаю, понятно для чего эта структура нужна.

// какие параметры передавать функции, объяснять, по моему, не надо

function GetCDSpeeds(Host,Target,Lun:Byte):TCDSpeeds;

var

buffer: array [0..29] of Byte; // буфер для принимаемых данных

Здесь я сделаю небольшое пояснение относительно размера буфера. Данные, возвращаемые при использовании страницы режима CD Capabilities and Mechanical Status Page, имеют размер 20 байт. Но, как вы заметили, я использовал буфер размером 30 байт, и вот почему. Перед самой страницей режима, идут заголовок режима параметров, код страницы и её размер. Размер заголовка при использовании шестибайтной команды MODE SENSE составляет 4 байта, а при использовании команды MODE SENSE(10) – 8 байт.

Продолжим. Код, который уже встречался ранее, приведен без комментариев:

begin

hEvent := CreateEvent(nil, true, false, nil);

FillChar(buffer,sizeof(buffer),0);

FillChar(Srb,sizeof(TSRB_ExecSCSICmd),0);

Srb.SRB_Cmd := SC_EXEC_SCSI_CMD;

Srb.SRB_Flags := SRB_DIR_IN or SRB_EVENT_NOTIFY;

Srb.SRB_Target := Target;

Srb.SRB_HaId := Host;

Srb.SRB_Lun := Lun;

Srb.SRB_BufLen := sizeof(buffer);

Srb.SRB_BufPointer := @buffer;

Srb.SRB_SenseLen := SENSE_LEN;

Srb.SRB_CDBLen := $0A; // это десятибайтная команда

Srb.SRB_PostProc := Pointer(hEvent);

Srb.CDBByte[0] := $5A; // код команды MODE SENSE(10)

// код страницы CD Capabilities and Mechanical Status Page

Srb.CDBByte[2] := $2A;

Srb.CDBByte[7] := HIBYTE(sizeof(buffer));

Srb.CDBByte[8] := LOBYTE(sizeof(buffer));

ResetEvent(hEvent);

dwASPIStatus := SendASPI32Command(@Srb);

if dwASPIStatus=SS_PENDING then

WaitForSingleObject(hEvent,INFINITE);

if Srb.SRB_Status<>SS_COMP then

// если ошибка, обнуляем структуру TCDSpeeds

FillChar(Result,sizeof(TCDSpeeds),0);

else begin

// почему сумма байт делится на 176? 176 – это скорость передачи

// данных, равная одному килобайту в секунду.

Result.MaxSpeed := ((buffer[16] shl 8) + buffer[17]) div 176;

Result.CurrentSpeed := ((buffer[22] shl 8) + buffer[23]) div 176;

Result.MaxWriteSpeed := ((buffer[26] shl 8) + buffer[27]) div 176;

Result.CurrentWriteSpeed := ((buffer[28] shl 8) + buffer[29]) div 176;

end;

CloseHandle(hEvent);

end;

Итак, скорости мы определили, теперь нужно научиться ими управлять.

Для этого воспользуемся SCSI-командой SetCDSpeed.

// параметры ReadSpeed и WriteSpeed – скорость чтения и записи соответственно

function SetSpeed(

Host, Target, Lun : Byte;

ReadSpeed, WriteSpeed : integer) : boolean;

begin

if ReadSpeed=0 then

result := false

else

begin

hEvent := CreateEvent(nil, true, false, nil);

FillChar(Srb,sizeof(TSRB_ExecSCSICmd), 0);

Srb.SRB_Cmd := SC_EXEC_SCSI_CMD;

// обратите внимание здесь данные передаются из приложения в

// устройство (флаг SRB_DIR_OUT)

Srb.SRB_Flags := SRB_DIR_OUT or SRB_EVENT_NOTIFY;

Srb.SRB_Target := Target;

Srb.SRB_HaId := Host;

Srb.SRB_Lun := Lun;

Srb.SRB_SenseLen := SENSE_LEN;

Srb.SRB_CDBLen := $0C; // эта команда двенадцатибайтная

Srb.SRB_PostProc := Pointer(hEvent);

Srb.CDBByte[0] := $BB; // код команды Set CD Speed

// устанавливаем скорость чтения

Srb.CDBByte[2] := Byte((ReadSpeed * 176) shr 8);

Srb.CDBByte[3] := Byte(ReadSpeed * 176);

if WriteSpeed<>0 then // если привод пишущий

begin

// ...устанавливаем скорость записи

Srb.CDBByte[4] := Byte((WriteSpeed * 176) shr 8);

Srb.CDBByte[5] := Byte(WriteSpeed * 176);

end;

ResetEvent(hEvent);

dwASPIStatus := SendASPI32Command(@Srb);

if dwASPIStatus=SS_PENDING then

WaitForSingleObject(hEvent,INFINITE);

if Srb.SRB_Status<>SS_COMP then

result := false

else

result := true;

end;

end;

Напоследок хочу рассказать о том, как узнать все скорости, которые поддерживает привод. Разместите на форме компоненты TComboBox и TButton. В обработчике события OnClick компонента TButton поместите следующий код:

var

i : integer;

begin

ComboBox1.Items.Clear; // очищаем элементы выпадающего списка

with Cdroms.Cdroms[0] do // используем первый CD-ROM

begin

// открываем цикл от 1 до максимальной скорости привода

for i := 1 to GetCDSpeeds(HaID, Target, Lun).MaxSpeed do

begin

SetSpeed(HaID, Target, Lun, i, 0); // устанавливаем скорость, равную i

if i = GetCDSpeeds(HaID, Target, Lun).CurrentSpeed then

// сравниваем, если текущая скорость равна i, заносим это

// значение в выпадающий список

ComboBox1.Items.Add(IntToStr(i));

end;

end;

end;

Вот и всё. Следующая часть статьи посвящена работе с SPTI-интерфейсом.

Использование интерфейса SPTI

Итак, в предыдущей статье было рассказано, как управлять приводом CD-ROM, используя интерфейс ASPI.

Однако интерфейс ASPI поддерживается в операционных системах семейства Win9x, которые сейчас используются крайне редко. Здесь я расскажу о том, как осуществлять управление CD-ROM посредством SPTI-интерфейса, который поддерживается в операционных системах WinNT, 2000, XP, 2003 Server. Начну с описания основных структур, которые при этом понадобятся:

type

TScsiPassThrough = record

Length : Word; // Размер структуры TScsiPassThrough

ScsiStatus : Byte; // Статус SCSI-запроса

PathId : Byte; // Идентификатор SCSI-адаптера

TargetId : Byte; // Идентификатор объекта SCSI

Lun : Byte; // Logical Unit Number (LUN - логический номер устройства)

// Длина CDB (Command Descriptor Block – блока дескриптора команды)

CDBLength : Byte;

SenseInfoLength : Byte; // Длина буфера значения

DataIn : Byte; // Байт, определяющий тип запроса (ввод или вывод)

DataTransferLength : DWORD; // Размер передаваемых данных

TimeOutValue : DWORD; // Время ожидания запроса в секундах

DataBufferOffset : DWORD; // Смещение буфера данных

SenseInfoOffset : DWORD; // Смещение буфера значения

// SCSI Command Descriptor Block (Блок дескриптора команды)

CDB: array [0..15] of Byte;

end;

Следующая структура:

TScsiPassThroughWithBuffers = record

spt : TScsiPassThrough;

bSenseBuf : array [0..31] of Byte; // Буфер значения

bDataBuf : array [0..191] of Byte; // Буфер данных

end;

ScsiPassThroughWithBuffers=TScsiPassThroughWithBuffers;

PScsiPassThroughWithBuffers=^TScsiPassThroughWithBuffers;

Как видите, эта структура содержит тип TScsiPassThrough и два буфера. Для удобства мы будем использовать структуру TScsiPassThroughWithBuffers.

Теперь постараюсь объяснить принцип использования интерфейса SPTI.

Сначала, с помощью функции CreateFile, создаём хэндл для доступа к устройству. Затем заполняем данными структуру TScsiPassThroughWithBuffers. И, наконец, с помощью функции DeviceIoControl, посылаем устройству управляющий код.

Выглядит это примерно так:

procedure GetSPTIDrives; // Процедура получает информацию о CD-ROM

var

j : integer;

s : string;

len, returned : DWORD;

sptwb : TScsiPassThroughWithBuffers;

Cdroms : TCdroms; // Структура Tcdroms описана в предыдущей статье

const

SCSI_IOCTL_DATA_IN = 1;

IOCTL_SCSI_PASS_THROUGH = ($00000004 shl 16)

or (($0001 or $0002) shl 14) or ($0401 shl 2) or (0);

begin

// Кроме строки '\\.\E : ', можно использовать, 'cdrom0', 'cdrom1' и т.д.

// в зависимости от количества устройств

hDevice := CreateFile('\\.\E : ', GENERIC_READ or GENERIC_WRITE,

FILE_SHARE_READ or FILE_SHARE_WRITE,

nil, OPEN_EXISTING, 0, 0);

if hDevice=INVALID_HANDLE_VALUE then

ShowMessage('INVALID_HANDLE_VALUE');

sptwb.Spt.Length := sizeof(TSCSIPASSTHROUGH);

sptwb.Spt.CdbLength := 6; // Шестибайтная команда

sptwb.Spt.SenseInfoLength := 24;

// Команда будет получать данные от устройства (ввод)

sptwb.Spt.DataIn := SCSI_IOCTL_DATA_IN;

// Устанавливаем размер передаваемых данных

sptwb.Spt.DataTransferLength := sizeof(sptwb.bDataBuf);

sptwb.Spt.TimeOutValue := 10; // Время ожидания – 10 секунд

sptwb.Spt.DataBufferOffset := DWORD(@sptwb.bDataBuf)-DWORD(@sptwb);

sptwb.Spt.SenseInfoOffset := DWORD(@sptwb.bSenseBuf)-DWORD(@sptwb);

len := sptwb.Spt.DataBufferOffset+sptwb.spt.DataTransferLength;

// Команда INQUIRY вам уже известна по предыдущей статье

sptwb.Spt.CDB[0] := SCSI_INQUIRY;

sptwb.Spt.CDB[3] := HiByte(sizeof(sptwb.bDataBuf));

sptwb.Spt.CDB[4] := LoByte(sizeof(sptwb.bDataBuf));

if DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, @sptwb,

len, @sptwb, len, Returned, nil) and (sptwb.Spt.ScsiStatus = $00) then

begin

// Нижеследующие циклы предназначены для разделения информации о

// производителе, спецификации и т.д. Если вашей программе это не нужно,

// можно сделать так : ShowMessage(PChar(@sptwb.bDataBuf[8]));

s := '';

for j := 8 to 15 do

s := s + Chr(sptwb.bDataBuf[j]);

// Идентификатор производителя

Cdroms.Cdroms[Cdroms.ActiveCdrom].VendorID := s;

s := '';

for j := 16 to 31 do

s := s + Chr(sptwb.bDataBuf[j]);

Cdroms.Cdroms[Cdroms.ActiveCdrom].ProductID := s; // Идентификатор продукта

s := '';

for j := 32 to 35 do

s := s+chr(sptwb.bDataBuf[j]);

Cdroms.Cdroms[Cdroms.ActiveCdrom].Revision := s; // Номер изменения

s := '';

for j := 36 to 55 do

s := s+chr(sptwb.bDataBuf[j]);

// Спецификация производителя

Cdroms.Cdroms[Cdroms.ActiveCdrom].VendorSpec := s;

end;

end;

Если вы заметили, использование параметров PathId, TargetId и Lun для интерфейса SPTI не является обязательным (в отличие от ASPI). Поэтому, если вы всё же хотите, чтобы ваша программа определяла идентификатор SCSI-адаптера, идентификатор объекта SCSI и логический номер устройства, могу посоветовать воспользоваться таким кодом:

procedure Get_PathId_TargetId_Lun;

var

buf : array [0..1023] of Byte;

pscsiAddr:PSCSI_ADDRESS;

const

IOCTL_SCSI_GET_ADDRESS = $41018;

begin

ZeroMemory(@buf, sizeof(buf));

pscsiAddr := PSCSI_ADDRESS(@buf);

pscsiAddr^.Length := sizeof(TSCSI_ADDRESS);

if (DeviceIoControl(hDevice, IOCTL_SCSI_GET_ADDRESS, nil, 0,

pscsiAddr, sizeof(TSCSI_ADDRESS), returned, nil)) then

begin

Cdroms.Cdroms[Cdroms.ActiveCdrom].HaID := pscsiAddr^.PortNumber;

Cdroms.Cdroms[Cdroms.ActiveCdrom].Target := pscsiAddr^.TargetId;

Cdroms.Cdroms[Cdroms.ActiveCdrom].Lun := pscsiAddr^.Lun;

end else

ShowMessage(SysErrorMessage(GetLastError));

end;

В этом куске кода используется структура PSCSI_ADDRESS, которая выглядит следующим образом:

type

TSCSI_ADDRESS = record

Length : LongInt; // Размер структуры TSCSI_ADDRESS

PortNumber : Byte; // Номер адаптера SCSI

PathId : Byte; // Идентификатор адаптера SCSI

TargetId : Byte; // Идентификатор объекта SCSI

Lun : Byte; // Логический номер устройства

end;

SCSI_ADDRESS = TSCSI_ADDRESS;

PSCSI_ADDRESS = ^TSCSI_ADDRESS;

Как вы уже успели заметить, SCSI-команды для интерфейсов ASPI и SPTI одинаковы, поэтому необходимо знать лишь сами команды и заполнять соответствующим образом CDB (Command Descriptor Block). Для наглядности приведу пример использования интерфейса SPTI для установки скорости CD-ROM. Сравните этот код с таким же, но использующим интерфейс ASPI, и вы сами увидите все отличия.

function SPTISetSpeed(ReadSpeed, WriteSpeed:integer):Boolean;

var

spti:TScsiPassThroughWithBuffers;

const

SCSI_IOCTL_DATA_OUT = 0;

Rate = 176;

begin

spti.Spt.Length := sizeof(TSCSIPASSTHROUGH);

spti.Spt.CdbLength := 10;

spti.Spt.SenseInfoLength := 24;

spti.Spt.DataIn := SCSI_IOCTL_DATA_OUT;

spti.Spt.TimeOutValue := 10;

spti.spt.DataBufferOffset := DWORD(@spti.bDataBuf)-DWORD(@spti);

spti.spt.SenseInfoOffset := DWORD(@spti.bSenseBuf)-DWORD(@spti);

spti.Spt.DataTransferLength := sizeof(spti.bDataBuf);

spti.spt.CDB[0] := $BB;

spti.spt.CDB[2] := BYTE(ReadSpeed*Rate shr 8);

spti.spt.CDB[3] := BYTE(ReadSpeed*Rate);

if WriteSpeed<>0 then

begin

spti.spt.CDB[4] := BYTE(WriteSpeed*Rate shr 8);

spti.spt.CDB[5] := BYTE(WriteSpeed*Rate);

end else

spti.spt.CDB[4] := $FF;

spti.spt.CDB[5] := $FF;

if DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH, @spti, len, @spti, len, returned, nil) and

(spti.spt.ScsiStatus=$00) then result := true

else

result := false;

end;

Думаю, данный код не нуждается в пояснениях.

Кстати, всё вышесказанное (в том числе и в предыдущей статье) относится не только к устройствам CD-ROM, но и к другим SCSI-устройствам. Отличия лишь в командах. Есть команды, которые обязательны для всех устройств (MODE SELECT, MODE SENSE, INQUIRY и т.д.), и есть команды, которые специфичны для разных типов устройств (BLANK – для устройств CD-RW, PRINT – для принтеров, SCAN – для сканеров, и т.д.).

Теперь вы знаете, как осуществляется управление устройствами, подключёнными к шине SCSI. Какой использовать интерфейс, ASPI или SPTI, или оба вместе – дело ваше. Могу сказать лишь, что для использования двух интерфейсов рациональнее будет либо создать два приложения для двух семейств операционных систем Windows, либо создать две отдельные библиотеки и подгружать их в зависимости от операционной системы, поскольку поддержка двух интерфейсов в одном приложении может отрицательно сказаться на его размере и объеме используемой оперативной памяти.

Оценить/Добавить комментарий
Имя
Оценка
Комментарии:
Хватит париться. На сайте FAST-REFERAT.RU вам сделают любой реферат, курсовую или дипломную. Сам пользуюсь, и вам советую!
Никита10:28:34 05 ноября 2021
.
.10:28:32 05 ноября 2021
.
.10:28:31 05 ноября 2021
.
.10:28:30 05 ноября 2021
.
.10:28:28 05 ноября 2021

Смотреть все комментарии (27)
Работы, похожие на Реферат: Как сделать чтобы запущеный exe сам себя удалил 2

Назад
Меню
Главная
Рефераты
Благодарности
Опрос
Станете ли вы заказывать работу за деньги, если не найдете ее в Интернете?

Да, в любом случае.
Да, но только в случае крайней необходимости.
Возможно, в зависимости от цены.
Нет, напишу его сам.
Нет, забью.



Результаты(287687)
Комментарии (4159)
Copyright © 2005-2021 HEKIMA.RU [email protected] реклама на сайте