Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Управление метками томов дисков

Delphi , Файловая система , Диски

Управление метками томов дисков

Во имя процессора-отца, монитора-сына и святаго винча... Enter!

Данный совет содержит исходный код модуля, который может помочь Вам получить, установить и удалить метку тома гибкого или жесткого диска. Код получения метки тома содержит функцию Delphi FindFirst, код для установки и удаления метки тома использует вызов DOS-прерывания 21h и функции 16h и 13h соответственно. Поскольку функция 16h не поддерживается Windows, она должна вызываться через DPMI-прерывание 31h, функцию 300h.


{ *** НАЧАЛО КОДА МОДУЛЯ VOLLABEL *** }
unit VolLabel;

interface

uses Classes, SysUtils, WinProcs;

type

  EInterruptError = class(Exception);
  EDPMIError = class(EInterruptError);
  Str11 = string[11];

procedure SetVolumeLabel(NewLabel: Str11; Drive: Char);
function GetVolumeLabel(Drive: Char): Str11;
procedure DeleteVolumeLabel(Drv: Char);

implementation

type

  PRealModeRegs = ^TRealModeRegs;
  TRealModeRegs = record
    case Integer of
      0: (
        EDI, ESI, EBP, EXX, EBX, EDX, ECX, EAX: Longint;
        Flags, ES, DS, FS, GS, IP, CS, SP, SS: Word);
      1: (
        DI, DIH, SI, SIH, BP, BPH, XX, XXH: Word;
        case Integer of
          0: (
            BX, BXH, DX, DXH, CX, CXH, AX, AXH: Word);
          1: (
            BL, BH, BLH, BHH, DL, DH, DLH, DHH,
            CL, CH, CLH, CHH, AL, AH, ALH, AHH: Byte));
  end;

  PExtendedFCB = ^TExtendedFCB;
  TExtendedFCB = record
    ExtendedFCBflag: Byte;
    Reserved1: array[1..5] of Byte;
    Attr: Byte;
    DriveID: Byte;
    FileName: array[1..8] of Char;
    FileExt: array[1..3] of Char;
    CurrentBlockNum: Word;
    RecordSize: Word;
    FileSize: LongInt;
    PackedDate: Word;
    PackedTime: Word;
    Reserved2: array[1..8] of Byte;
    CurrentRecNum: Byte;
    RandomRecNum: LongInt;
  end;

procedure RealModeInt(Int: Byte; var Regs: TRealModeRegs);
{ процедура работает с прерыванием 31h, функцией 0300h для иммитации }
{ прерывания режима реального времени для защищенного режима. }
var

  ErrorFlag: Boolean;
begin

  asm
    mov ErrorFlag, 0       { успешное завершение }
    mov ax, 0300h          { функция 300h }
    mov bl, Int            { прерывание режима реального времени, которое необходимо выполнить }
    mov bh, 0              { требуется }
    mov cx, 0              { помещаем слово в стек для копирования, принимаем ноль }
    les di, Regs           { es:di = Regs }
    int 31h                { DPMI-прерывание 31h }
    jnc @@End              { адрес перехода установлен в error }
    @@Error:
    mov ErrorFlag, 1       { возвращаем false в error }
    @@End:
  end;
  if ErrorFlag then
    raise EDPMIError.Create('Неудача при выполнении DPMI-прерывания');
end;

function DriveLetterToNumber(DriveLet: Char): Byte;
{ функция преобразования символа буквы диска в цифровой эквивалент. }
begin

  if DriveLet in ['a'..'z'] then
    DriveLet := Chr(Ord(DriveLet) - 32);
  if not (DriveLet in ['A'..'Z']) then
    raise
      EConvertError.CreateFmt('Не могу преобразовать %s в числовой эквивалент диска',

      [DriveLet]);
  Result := Ord(DriveLet) - 64;
end;

procedure PadVolumeLabel(var Name: Str11);
{ процедура заполнения метки тома диска строкой с пробелами }
var

  i: integer;
begin

  for i := Length(Name) + 1 to 11 do
    Name := Name + ' ';
end;

function GetVolumeLabel(Drive: Char): Str11;
{ функция возвращает метку тома диска }
var

  SR: TSearchRec;
  DriveLetter: Char;
  SearchString: string[7];
  P: Byte;
begin

  SearchString := Drive + ':\*.*';
  { ищем метку тома }
  if FindFirst(SearchString, faVolumeID, SR) = 0 then
  begin
    P := Pos('.', SR.Name);
    if P > 0 then
    begin { если у него есть точка... }
      Result := '           '; { пространство между именами }
      Move(SR.Name[1], Result[1], P - 1); { и расширениями }
      Move(SR.Name[P + 1], Result[9], 3);
    end
    else
    begin
      Result := SR.Name; { в противном случае обходимся без пробелов }
      PadVolumeLabel(Result);
    end;
  end
  else
    Result := '';
end;

procedure DeleteVolumeLabel(Drv: Char);
{ процедура удаления метки тома с данного диска }
var

  CurName: Str11;
  FCB: TExtendedFCB;
  ErrorFlag: WordBool;
begin

  ErrorFlag := False;
  CurName := GetVolumeLabel(Drv); { получение текущей метки тома }
  FillChar(FCB, SizeOf(FCB), 0); { инициализируем FCB нулями }
  with FCB do
  begin
    ExtendedFCBflag := $FF; { всегда }
    Attr := faVolumeID; { Аттрибут Volume ID }
    DriveID := DriveLetterToNumber(Drv); { Номер диска }
    Move(CurName[1], FileName, 8); { необходимо ввести метку тома }
    Move(CurName[9], FileExt, 3);
  end;
  asm
    push ds                             { сохраняем ds }
    mov ax, ss                          { помещаем сегмент FCB (ss) в ds }
    mov ds, ax
    lea dx, FCB                         { помещаем смещение FCB в dx }
    mov ax, 1300h                       { функция 13h }
    Call DOS3Call                       { вызываем int 21h }
    pop ds                              { восстанавливаем ds }
    cmp al, 00h                         { проверка на успешность выполнения }
    je @@End
    @@Error:                            { устанавливаем флаг ошибки }
    mov ErrorFlag, 1
    @@End:
  end;
  if ErrorFlag then
    raise EInterruptError.Create('Не могу удалить имя тома');
end;

procedure SetVolumeLabel(NewLabel: Str11; Drive: Char);
{ процедура присваивания метки тома диска. Имейте в виду, что }
{ данная процедура удаляет текущую метку перед установкой новой. }
{ Это необходимое требование для функции установки метки. }
var

  Regs: TRealModeRegs;
  FCB: PExtendedFCB;
  Buf: Longint;
begin

  PadVolumeLabel(NewLabel);
  if GetVolumeLabel(Drive) <> '' then { если имеем метку... }
    DeleteVolumeLabel(Drive); { удаляем метку }
  Buf := GlobalDOSAlloc(SizeOf(PExtendedFCB)); { распределяем реальный буфер }
  FCB := Ptr(LoWord(Buf), 0);
  FillChar(FCB^, SizeOf(FCB), 0); { инициализируем FCB нулями }
  with FCB^ do
  begin
    ExtendedFCBflag := $FF; { требуется }
    Attr := faVolumeID; { Аттрибут Volume ID }
    DriveID := DriveLetterToNumber(Drive); { Номер диска }
    Move(NewLabel[1], FileName, 8); { устанавливаем новую метку }
    Move(NewLabel[9], FileExt, 3);
  end;
  FillChar(Regs, SizeOf(Regs), 0);
  with Regs do
  begin { Сегмент FCB }
    ds := HiWord(Buf); { отступ = ноль }
    dx := 0;
    ax := $1600; { Функция 16h }
  end;
  RealModeInt($21, Regs); { создаем файл }
  if (Regs.al <> 0) then { проверка на успешность выполнения }
    raise EInterruptError.Create('Не могу создать метку тома');
end;

end.
{ *** КОНЕЦ КОДА МОДУЛЯ VOLLABEL *** }

Перевод контента на русский язык:

Модуль Delphi для управления метками объемов диска!

Я предоставлю подробный обзор кода, указывая на его сильные и слабые стороны.

Сильные стороны:

  1. Код хорошо организован и легко понятен.
  2. Он использует meaningful переменные и комментарии, что делает его более понятным для каждого раздела.
  3. Реализация процедуры RealModeInt впечатляет, так как она симулирует реальный режим прерывания с помощью DPMI.

Слабые стороны:

  1. Код предполагает, что пользователь имеет достаточное знание DOS и программирования на Delphi. Некоторые части могут быть сложными для начинающих.
  2. Нет механизмов обработки ошибок для неожиданных ситуаций, таких как ошибки диска или недопустимый ввод. Это может привести к краху или неправильному поведению.
  3. Функция GetVolumeLabel недостаточно robust; она предполагает, что строка поиска всегда будет содержать точку (.), что может не быть случае.

Рекомендации:

  1. Добавьте больше комментариев и документацию для объяснения цели каждой процедуры и функции.
  2. Реализуйте механизмы обработки ошибок, чтобы обеспечить, что код может обрабатывать неожиданные ситуации.
  3. Улучшите robustness функции GetVolumeLabel, проверяя недопустимый ввод или граничные случаи.
  4. Рассмотрите добавление поддержки других операционных систем, таких как Windows NT/2000/XP/Vista/7.

Повышение кода:

  1. В процедуре RealModeInt можно использовать более компактный способ симуляции реального режима прерывания:
mov ax, 0300h
int 31h
jc @@Error
  1. В функции GetVolumeLabel можно использовать регулярное выражение для поиска строки вместо зависимости от точки (.) .
  2. В процедуре SetVolumeLabel можно использовать более эффективный способ выделения памяти для FCB:
FCB := AllocMem(SizeOf(ExtendedFCB), false);

В целом, этоsolid часть кода, которая демонстрирует хороший уровень понимания программирования на Delphi и концепций DOS. С некоторыми дополнительными работами по обработке ошибок и robustness, она может стать еще более эффективным инструментом для управления метками объемов диска.

Управление метками томов дисков: модуль для установления, удаления и получения метки тома гибкого или жесткого диска.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




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


:: Главная :: Диски ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-05-01 13:59:25/0.0061900615692139/1