⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 小巧磁盘编辑器.txt

📁 D7设计的小巧磁盘编辑器 Window2000/Xp下的小巧磁盘编辑器
💻 TXT
字号:
                                                   Window2000/Xp下的小巧磁盘编辑器
     提起磁盘编辑器,我们就会想到Winhex,Advanced Disk Catalog ,Edittool等常用软件.如果能自己动手制作一个类似的磁盘工具,那将是很有趣的.这里就使用Dephi7在Window2000/2003/Xp环境下设计一款小巧的磁盘编辑器,可以在Fat32,Ntfs文件系统在正常工作.可以实现磁盘扇区的读取,修改,复制等常用功能.程序运行效果如图1所示.
     在Dephi新建一个项目,在窗体上放置一个stringgrid控件,用来显示和修改磁盘扇区的内容.两个按钮,分别用来读写相应扇区.两个spinedit控件,用来设置起始扇区和读写扇区的数目.一个DriveComboBox控件,用来选择磁盘.statusbar状态条用来显示当前状态.
     程序的关键是利用CreateFile(drive, GENERIC_ALL,  FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,0, 0)函数来打开需要读写的驱动器,然后利用ReadFile,WriteFile来进行磁盘读写。程序的核心是如何动态显示和修改磁盘扇区的内容.这里使用了两个整数型的数组seca和secb分别用来记录扇区的原始内容和修改后的内容.不管是否修改了扇区内容,在对磁盘进行写操作时,把数组secb作为数据源来提供扇区写入所需的数据.当然不点击"写扇区"按钮的话,一切操作都是安全的.
程序中用来在stringgrid中显示扇区内容的代码如下:
procedure tform1.BytesToGrid;  //此过程将扇区内容显示在stringgrid中.这里的stringgrid的option属性应包括:goFixedVertLine, goFixedHorzLine, goRangeSelect, goEditing, goTabs, goAlwaysShowEditor.
var
  i,j,k:Integer;
  c: Char;
  fbuf:pchar;
begin
   n:=nsectors.Value; //读写的扇区数
   s:=startsector.Value;//起始扇区数
   setlength(seca,n*bytepersectors);
   setlength(secb,n*bytepersectors); //动态设置数组的长度,seca和secb分别记录原始和变化后的扇区数据
   StatusBar1.Panels[1].Text := '';
   hDeviceHandle := CreateFile(driver, GENERIC_ALL, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,0, 0);//打开磁盘
   if (hDeviceHandle<> INVALID_HANDLE_VALUE) then  //是否打开成功
   begin
   fbuf:=allocmem(n*bytepersectors);
   FileSeek(hDevicehandle,s*bytepersectors,0); //定位扇区
    if FileRead(hDevicehandle,fbuf[0],n*bytepersectors)<>n*bytepersectors then
           raise exception.create('读磁盘错误!');
    stringgrid1.Rowcount:=n*32+1;//根据选择的扇区数动态的改变网格的行数
    for i:=0 to ((n*bytepersectors) div 16)-1 do
        StringGrid1.Cells[0,i+1] := IntToHex(i*16,4)+':';   //格式化显示stringgrid的0行表头信息
    for i:=0 to ((n*bytepersectors) div 16)-1 do
    for j:=1 to 16 do
      begin
      seca[j-1+16*i]:=integer(fbuf[j-1+16*i]);//将扇区数据转换为整型
      secb[j-1+16*i]:=seca[j-1+16*i];  //初始扇区数组数据
      end;
    for i:=0 to ((n*bytepersectors) div 16)-1 do begin
    StringGrid1.Cells[0,i+1] := IntToHex(i*16,4)+':';  //格式化显示stringgrid的0列内容
    for j:=1 to 16 do begin
      K := seca[j-1+16*i];
      StringGrid1.Cells[j,i+1]:=format('%.2x',[integer(fbuf[j-1+16*i])]);//在stringgrid的1至16列格式化数据显示
      C :=chr(k);
      if c<' ' then c:='.';
      StringGrid1.Cells[j+17,i+1] := c; //在stringgrid18至33列显示对应的asc码
      StatusBar1.Panels[1].Text := Format('逻辑磁盘 '+DriveComboBox1.Drive+'第 %D 扇区起连续'+inttostr(n)+'个扇区',[s]);
    end;
   end;
   freemem(fbuf);//释放内存
   closehandle(hDeviceHandle);  //关闭句柄
  end;
end; 
程序的完整源代码如下:
 unit diskedirunt;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Spin, shellapi,FileCtrl, Grids, ComCtrls;

type
  TForm1 = class(TForm)
    DriveComboBox1: TDriveComboBox;
    Button1: TButton; //写扇区按钮
    startsector: TSpinEdit;
    nsectors: TSpinEdit;
    Label1: TLabel;
    Label2: TLabel;
    StatusBar1: TStatusBar;
    StringGrid1: TStringGrid;
    Button2: TButton; //读扇区按钮
    Label3: TLabel;
    procedure FormShow(Sender: TObject);
    procedure DriveComboBox1Change(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure StringGrid1KeyPress(Sender: TObject; var Key: Char);
    procedure StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
      var Value: String);
    procedure StringGrid1Exit(Sender: TObject);
    procedure StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
      var CanSelect: Boolean);
    procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure nsectorsChange(Sender: TObject);
    procedure startsectorChange(Sender: TObject);
  private
   driver:pchar;  //驱动器名称
   bytepersectors:integer; //每扇区字节数,默认为512
   s,n:integer;
   seca,secb:array of integer;  //分别保存原始和变化的扇区数据
   procedure BytesToGrid;
   procedure OnFocusChange;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  ColOld: Integer = 1;   //根据用户的在stringgrid的选择改变光标所在的行列数
  RowOld: Integer = 1;
  CellKeyPress: Integer;  //判断在stringgrid中的按键
  CharSellsCount:integer =17;  
  hdevicehandle:thandle;  //文件句柄
  Form1: TForm1;

implementation

uses wlt;

{$R *.dfm}

procedure TForm1.OnFocusChange;  //在stringgrid里改变光标位置时动态刷新数组的内容
var
  I: Integer;
  C: Char;
begin
  I := ColOld-1+(RowOld-1)*16;
  with StringGrid1 do
    if Length(Cells[ColOld,RowOld])>2 then begin   //没有修改则显示seca中的原始数据
      Cells[ColOld,RowOld] := IntToHex(seca[i],2);
    end else
    try
      secb[i] := StrToInt('$'+Cells[ColOld,RowOld]); //保存修改后的扇区数据到secb数组中
      C := Chr(secb[i]);
      if c<' ' then c:='.';
      Cells[ColOld+17,RowOld] := C;
    except; end;
end;

procedure tform1.BytesToGrid; //在stringgrid中动态显示扇区的内容
var
  i,j,k:Integer;
  c: Char;
  fbuf:pchar;
begin
   n:=nsectors.Value;
   s:=startsector.Value;
   setlength(seca,n*bytepersectors);
   setlength(secb,n*bytepersectors);
   StatusBar1.Panels[1].Text := '';
   hDeviceHandle := CreateFile(driver, GENERIC_ALL, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,0, 0);
   if (hDeviceHandle<> INVALID_HANDLE_VALUE) then
   begin
   fbuf:=allocmem(n*bytepersectors);
   FileSeek(hDevicehandle,s*bytepersectors,0);
    if FileRead(hDevicehandle,fbuf[0],n*bytepersectors)<>n*bytepersectors then
           raise exception.create('读磁盘错误!');
    stringgrid1.Rowcount:=n*32+1;
    for i:=0 to ((n*bytepersectors) div 16)-1 do
        StringGrid1.Cells[0,i+1] := IntToHex(i*16,4)+':';
    for i:=0 to ((n*bytepersectors) div 16)-1 do
    for j:=1 to 16 do
      begin
      seca[j-1+16*i]:=integer(fbuf[j-1+16*i]);
      secb[j-1+16*i]:=seca[j-1+16*i];
      end;
    for i:=0 to ((n*bytepersectors) div 16)-1 do begin
    StringGrid1.Cells[0,i+1] := IntToHex(i*16,4)+':';
    for j:=1 to 16 do begin
      K := seca[j-1+16*i];
      StringGrid1.Cells[j,i+1]:=format('%.2x',[integer(fbuf[j-1+16*i])]);
      C :=chr(k);
      if c<' ' then c:='.';
      StringGrid1.Cells[j+17,i+1] := c;
      StatusBar1.Panels[1].Text := Format('逻辑磁盘 '+DriveComboBox1.Drive+'第 %D 扇区起连续'+inttostr(n)+'个扇区',[s]);
    end;
   end;
   freemem(fbuf);
   closehandle(hDeviceHandle);
  end;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  driver:=pchar('\\.\'+drivecombobox1.Drive+':');//在formshow中设置初始驱动器值
  BytesToGrid;
end;

procedure TForm1.DriveComboBox1Change(Sender: TObject);
begin
  Button2Click(self);//改变驱动器时,刷新网格显示
end;

procedure TForm1.FormCreate(Sender: TObject);
var
i:integer;
begin
   startsector.Value:=0;
   nsectors.Value:=1;
   bytepersectors:=512;
   with StringGrid1 do begin //网格分两部分,一边以16进制显示扇区数据,一边显示相应的asc值.
    ColWidths[0] := 50;
    for i := 17 to 33 do begin
      TabStops[i] := False;
      ColWidths[i] := 11; //设置网格列的宽度
    end;
    for i := 1 to 16 do Cells[i,0] := IntToHex(i-1,2); //设置表头信息
    for i := 18 to 33 do Cells[i,0] := IntToHex(i-18,1);
    Cells[0,0] := '偏移';
 end;
end;

procedure TForm1.StringGrid1KeyPress(Sender: TObject; var Key: Char);
begin     //根据在网格中的按键,进行光标的定位
if Key<>#8 then begin
    Key := UpCase(Key);
    if not (Key in ['0'..'9','A'..'F']) then Key := #0 else    //只允许输入特定字符
     with StringGrid1 do
      if CellKeyPress>1 then begin
        if Length(Cells[Col,Row])>1 then begin
          if (Col+1+CharSellsCount)<ColCount then begin
            Col := Col+1;   //光标换列
            CellKeyPress := 1;
          end else begin
            if (Row+1)<RowCount then begin
              Col := 1; Row := Row+1; //光标换行
              CellKeyPress := 1;
            end else Key := #0;
          end;
        end;
      end else Inc(CellKeyPress);
  end;
  if Key<>#0 then StatusBar1.Panels[1].Text := Format('修改逻辑磁盘 '+DriveComboBox1.Drive+'第 %D 扇区',[startsector.Value]);  //,如进行扇区数据的修改,则在状态栏中显示修改信息
end;


procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol,
  ARow: Integer; var Value: String);  //根据在网格中选择的位置改变记录行列的ColOld ,
  RowOld 变量的值.
var   
  S: String;
  L: Integer;
begin
  with StringGrid1 do begin
    S := Cells[ColOld,RowOld];
    L := Length(S);
    case L of
      0: Cells[ColOld,RowOld] := '00';
      1: Cells[ColOld,RowOld] := '0'+S;
    end;
  end;
  ColOld := ACol;
  RowOld := ARow;
end;


procedure TForm1.StringGrid1Exit(Sender: TObject);
begin
with StringGrid1 do
    if Col<16 then
      Col := Col+1
    else begin
      Col := 1; Row := Row+1; //改变行列的值
    end;
  OnFocusChange;  //当光标所在的行列变化时,刷新网格显示.
end;

procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean); //选择网格数据时动态刷新网格内容
begin
if aCol>16 then CanSelect := False;
  CellKeyPress := 0;
  OnFocusChange;
end;

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState); //当修改扇区数据时,对修改的部分进行醒目的显示
var
i:integer;
begin
with StringGrid1.Canvas do
    if (aCol>0) and (aRow>0) then begin
      case aCol of
        1..16: I := aCol-1+(aRow-1)*16;
        18..33: I := aCol-18+(aRow-1)*16;
      else I := -1;
      end;
      if I>=0 then
        if seca[I]<>secb[I] then begin //对原始seca数据和变化的secb数据进行对比,不同则表示修改了扇区数据
          Brush.Color := clred;
          FillRect(Rect);
          TextOut(Rect.Left+2,Rect.Top+2,StringGrid1.Cells[aCol,aRow]);
        end;  //重新以红色显示修改的数据
    end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 driver:=pchar('\\.\'+drivecombobox1.Drive+':');
 BytesToGrid;  //读取扇区数据
end;

procedure TForm1.Button1Click(Sender: TObject);  //将指定的扇区写至选择的逻辑盘的对应扇区位置
var
p:pchar;
i,j:integer;
writesec:string;
begin
    if Form2.ShowModal <> mrOk then Exit; //显示磁盘写入的窗体
    driver:=pchar('\\.\'+form2.DriveComboBox1.Drive+':'); //取得指定逻辑盘
    p:=allocmem(n*bytepersectors);
    setlength(writesec,n*bytepersectors); //动态设置字符串长度,用以保存扇区数据
    writesec:='';
    for i:=0 to ((n*bytepersectors) div 16)-1 do
    for j:=1 to 16 do
     writesec := writesec + chr(secb[j-1+16*i]); //将secb中的保存的扇区数据转移至特定字符串中
     p:=pchar(writesec);//将数据转化为pchar类型
    hDeviceHandle := CreateFile(driver, GENERIC_ALL,
    FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,0, 0); //打开目标盘
    if (hDeviceHandle <> INVALID_HANDLE_VALUE) then
    begin
     FileSeek(hDevicehandle,form2.SpinEdit1.Value*bytepersectors,0); //扇区定位
    if FileWrite(hDevicehandle,p[0],n*bytepersectors)<>n*bytepersectors then  //写入扇区数据,完成扇区写操作1
       raise exception.create('Write错误%d');
    StatusBar1.Panels[1].Text :='写逻辑磁盘 '+form2.DriveComboBox1.Drive+'成功!';
    closehandle(hDeviceHandle); //关闭句柄
 end;
end;

procedure TForm1.nsectorsChange(Sender: TObject);
begin
   if nsectors.Value<1 then  //改变扇区数量时进行判断
   begin
   MessageBox(0, '扇区数不能为0!','小巧磁盘编辑器', MB_OK + MB_ICONERROR + MB_DEFBUTTON2 +
       MB_TOPMOST);
   nsectors.Value:=1;
   end;
   Button2Click(self);//改变网格数据
end;

procedure TForm1.startsectorChange(Sender: TObject);
begin
Button2Click(self); //起始扇区改变时,改变网格的内容
end;

end.
写扇区的源码如下:
unit wlt;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Spin, FileCtrl;

type
  TForm2 = class(TForm)  //写扇区窗体
    Label1: TLabel;
    Button1: TButton;
    Button2: TButton;
    Label2: TLabel;
    SpinEdit1: TSpinEdit;
    DriveComboBox1: TDriveComboBox;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormShow(Sender: TObject);
begin
spinedit1.Value:=0; //起始扇区数置0
end;

procedure TForm2.Button1Click(Sender: TObject);
begin
if MessageBox(0, '磁盘扇区写入可能存在危险,是否继续?',
       '小巧磁盘编辑器', MB_YESNO + MB_ICONERROR + MB_DEFBUTTON2 +
       MB_TOPMOST) = IDNO then
 close;      
end;

end.
 当然这只是在windows2000/xp下读写扇区的的一般方法.还有一些需要进一步完善的地方.例如判断磁盘的总扇区数,进行必要的约束等.限于篇幅就不一一列举了.

测试环境: Dephi7+Windows2000,Ntfs文件系统.

    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -