以下的程序实现监控某个驱动器或目录,如果有生存*.3B文件,则对其进行改名(主要是针对DOS程序如EDIT保存.3b文件时进行修改)...
此程序在WindowsXP下调试完全正常,但是在Win98下却在 CreateFile 时提示参数错误,请高手帮忙看看,很急啊...  或者能用其他方法解决也行
代码如下:
unit UnitMain;interfaceuses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, Buttons,fileCtrl;type
  TFrmMain = class(TForm)
    Panel1: TPanel;
    Label1: TLabel;
    CJLabel1: TLabel;
    bStart: TButton;
    bStop: TButton;
    ckWatchSubTree: TCheckBox;
    GroupBox1: TGroupBox;
    ckMonitorFileName: TCheckBox;
    ckMonitorDirName: TCheckBox;
    ckMonitorAttributes: TCheckBox;
    ckMonitorSize: TCheckBox;
    ckMonitorLastWrite: TCheckBox;
    ckMonitorSecurity: TCheckBox;
    ckMonitorCreationDate: TCheckBox;
    ckMonitorLastAccess: TCheckBox;
    Memo1: TMemo;
    btnSetPwd: TBitBtn;
    btnExit: TBitBtn;
    GroupBox2: TGroupBox;
    SpeedButton1: TSpeedButton;
    ePath: TEdit;
    procedure bStartClick(Sender: TObject);
    procedure bStopClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ePathDblClick(Sender: TObject);
    procedure btnExitClick(Sender: TObject);
  private
    { D閏larations priv閑s }
    FDirectoryHandle: THandle;
    FNotificationBuffer: array[0..4096] of Byte;
    FWatchThread: TThread;
    FNotifyFilter: DWORD;
    FOverlapped: TOverlapped;
    FPOverlapped: POverlapped;
    FBytesWritten: DWORD;
    FCompletionPort: THandle;
    bBegin:boolean;
    strWatchDir,strSourceExt,strTargetExt:string;
  public
    { Private declarations }
  public
    procedure WatchRename(strFile:string);
    procedure AppendStrToFile(strFile:string;strCon:string);
    function FileGetSize(FileName:string): Int64;
    function GenerateNewFileName(strFile,strSExt,strTExt:string):string;
    { D閏larations publiques }
  end;var
  FrmMain: TFrmMain;type
  PFileNotifyInformation = ^TFileNotifyInformation;
  TFileNotifyInformation = record
    NextEntryOffset: DWORD;
    Action: DWORD;
    FileNameLength: DWORD;
    FileName: array[0..0] of WideChar;
  end;const
  FILE_LIST_DIRECTORY   = $0001;const
  SAction: array[FILE_ACTION_ADDED..FILE_ACTION_RENAMED_NEW_NAME] of String =
  ( 'ADDED %s',
    'DELETED %s',
    'MODIFIED %s',
    'RENAMED %s [...]',
    '[...] into %s');implementation{$R *.DFM}uses
  ShlObj, ActiveX;type
  TWaitThread = class(TThread)
  private
    FForm: TFrmMain;
    procedure HandleEvent;
  protected
    procedure Execute; override;
  public
    constructor Create(Form: TFrmMain);
  end;constructor TWaitThread.Create(Form: TFrmMain);
begin
  inherited Create(True);
  FForm := Form;
  FreeOnTerminate := False;
end;procedure TWaitThread.HandleEvent;
var
  FileOpNotification: PFileNotifyInformation;
  Offset: Longint;
  strTmp,strMid:string ;
begin
  with FForm do
  begin
    Pointer(FileOpNotification) := @FNotificationBuffer[0];
    repeat
      Offset := FileOpNotification^.NextEntryOffset;
      strTmp := Format(SAction[FileOpNotification^.Action], [WideCharToString(@(FileOpNotification^.FileName))]);
      strMid := ePath.Text + WideCharToString(@(FileOpNotification^.FileName));
      if (Pos(strWatchDir, strMid)>0) then //新建文件是否属于监控目录下
      begin
         WatchRename(strMid);
      end;//      lbEvents.Items.Add(strMid);
      PChar(FileOpNotification) := PChar(FileOpNotification)+Offset;
    until Offset=0;
  end;
//  showmessage(strMid);
end;procedure TWaitThread.Execute;
var
  numBytes: DWORD;
  cbOffset: DWORD;
  CompletionKey: DWORD;
begin
  while not Terminated do
  begin
    GetQueuedCompletionStatus( FForm.FCompletionPort, numBytes, CompletionKey, FForm.FPOverlapped, INFINITE);
    if CompletionKey <> 0 then
    begin
      Synchronize(HandleEvent);
      with FForm do
      begin
        FBytesWritten := 0;
        ZeroMemory(@FNotificationBuffer, SizeOf(FNotificationBuffer));
        ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), ckWatchSubTree.Checked, FNotifyFilter, @FBytesWritten, @FOverlapped, nil);
      end;
    end
    else
      Terminate;
  end;
end;

解决方案 »

  1.   

    procedure TFrmMain.bStartClick(Sender: TObject);
    begin
      strWatchDir := ePath.Text;
      strSourceExt := '.3B';
      strTargetExt := '.3BB';  FNotifyFilter := 0;
      if ckMonitorFileName.Checked then
        FNotifyFilter := FNotifyFilter or FILE_NOTIFY_CHANGE_FILE_NAME;
      if ckMonitorDirName.Checked then
        FNotifyFilter := FNotifyFilter or FILE_NOTIFY_CHANGE_DIR_NAME;
      if ckMonitorAttributes.Checked then
        FNotifyFilter := FNotifyFilter or FILE_NOTIFY_CHANGE_ATTRIBUTES;
      if ckMonitorSize.Checked then
        FNotifyFilter := FNotifyFilter or FILE_NOTIFY_CHANGE_SIZE;
      if ckMonitorLastWrite.Checked then
        FNotifyFilter := FNotifyFilter or FILE_NOTIFY_CHANGE_LAST_WRITE;
      if ckMonitorLastAccess.Checked then
        FNotifyFilter := FNotifyFilter or FILE_NOTIFY_CHANGE_LAST_ACCESS;
      if ckMonitorCreationDate.Checked then
        FNotifyFilter := FNotifyFilter or FILE_NOTIFY_CHANGE_CREATION;
      if ckMonitorSecurity.Checked then
        FNotifyFilter := FNotifyFilter or FILE_NOTIFY_CHANGE_SECURITY;
      if FNotifyFilter = 0 then
      begin
         ShowMessage('Vous devez monitorer au moins 1 関閚ement !');
         exit;
      end;
    //  lbEvents.Clear;
      FDirectoryHandle := CreateFile(PChar(ePath.Text),
        FILE_LIST_DIRECTORY,
        FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
        nil,
        OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED,
        0);
      if FDirectoryHandle = INVALID_HANDLE_VALUE then
      begin
        beep;
        FDirectoryHandle := 0;
        ShowMessage(SysErrorMessage(GetLastError));
        exit;
      end;
      FCompletionPort := CreateIoCompletionPort(FDirectoryHandle, 0, Longint(pointer(self)), 0);
      ZeroMemory(@FNotificationBuffer, SizeOf(FNotificationBuffer));
      FBytesWritten := 0;
      if not ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), ckWatchSubTree.Checked, FNotifyFilter, @FBytesWritten, @FOverlapped, nil) then
      begin
        CloseHandle(FDirectoryHandle);
        FDirectoryHandle := 0;
        CloseHandle(FCompletionPort);
        FCompletionPort := 0;
        ShowMessage(SysErrorMessage(GetLastError));
        exit;
      end;
      ePath.Enabled := False;
      bStart.Enabled := False;
      bStop.Enabled := True;
      FWatchThread := TWaitThread.Create(self);
      TWaitThread(FWatchThread).Resume;
    end;procedure TFrmMain.bStopClick(Sender: TObject);
    begin
      if FCompletionPort = 0 then
        exit;
      PostQueuedCompletionStatus(FCompletionPort, 0, 0, nil);
      FWatchThread.WaitFor;
      FWatchThread.Free;
      CloseHandle(FDirectoryHandle);
      FDirectoryHandle := 0;
      CloseHandle(FCompletionPort);
      FCompletionPort := 0;
      ePath.Enabled := True;
      bStart.Enabled := True;
      bStop.Enabled := False;
    end;procedure TFrmMain.FormDestroy(Sender: TObject);
    begin
      bStop.Click;
    end;procedure TFrmMain.FormCreate(Sender: TObject);
    begin
      FCompletionPort := 0;
      FDirectoryHandle := 0;
      FPOverlapped := @FOverlapped;
      ZeroMemory(@FOverlapped, SizeOf(FOverlapped));
      bStartClick(self);
    end;procedure TFrmMain.ePathDblClick(Sender: TObject);
    var
      SelectionPIDL: PItemIDList;
      BrowseInfo: TBrowseInfo;
      ShellAllocator: IMalloc;
      PathBuffer: array[0..MAX_PATH] of Char;
    begin
      // simplest implementation of BrowseForFolder
      // to get more information refer to MSDN Library or Check Brad Stower's excellent site www.delphifreestuff.com
      bStopClick(self);  ZeroMemory(@BrowseInfo, SizeOf(BrowseInfo));
      BrowseInfo.hwndOwner := Handle;
      BrowseInfo.ulFlags := BIF_RETURNONLYFSDIRS;
      CoInitialize(nil);
      try
        SelectionPIDL := ShBrowseForFolder(BrowseInfo);
        if SelectionPIDL <> nil then
        try
          ZeroMemory(@PathBuffer, SizeOf(PathBuffer));
          if not SHGetPathFromIDList(SelectionPIDL, @PathBuffer) then
          begin
            beep;
            exit;
          end;
          ePath.Text := StrPas(@PathBuffer[0]);
        finally
          if SHGetMalloc(ShellAllocator) = 0 then
          begin
            ShellAllocator.Free(SelectionPIDL);
            ShellAllocator := nil;
          end;
        end;
      finally
        CoUnInitialize;
      end;
      bStartClick(self);
    end;procedure TFrmMain.AppendStrToFile(strFile:string;strCon:string);
    var
      F:textfile;
    begin
         AssignFile(F,strFile);
       try
         Append(F);
       except   end;
         try
           Writeln(F,strCon);
         finally
           Closefile(F);
         end;
    end;procedure TFrmMain.WatchRename(strFile:string);
    var
      FN, FEXT, FDIR, FName,strNewFile,strFullNewName: string;
    begin
      if not FileExists(strFile) then exit;  //文件不存在则返回
      if FileGetSize(strFile)=0 then exit;  //文件大小为0则返回
      FN := strFile;
      FEXT := ExtractFileExt(FN);
      if UpperCase(FEXT)<>UpperCase(strSourceExt) then exit; //不是需要监控的文件扩展名则返回
      FDIR := ExtractFilePath(FN);
      FName := ExtractFileName(FN);  strNewFile:=GenerateNewFileName(strFile,strSourceExt,strTargetExt);
      try
      RenameFile(FN, FDIR + strNewFile);
      strFullNewName:=FDIR + strNewFile ;
      memo1.Lines.add(strFullNewName);
      sleep(2000);
      AppendStrToFile(strFullNewName,chr(13)+FormatDateTime('yyyy年mm月dd',now())+chr(13)+FormatDateTime('hh:mm:ss',now()));   //文件末尾添加当前时间
      except  end;
    end;function TFrmMain.GenerateNewFileName(strFile,strSExt,strTExt:string):string;
    var
      strReverse,strNewFile,strTmp,strTmp2:string;
      FN, FEXT, FDIR, FName: string;
      iTmp:integer;
    begin
      FN := strFile;
      FEXT := ExtractFileExt(FN);
      FDIR := ExtractFilePath(FN);
      FName := ExtractFileName(FN);
      strTmp:=copy(FName,1,length(FName)-length(FEXT));
      iTmp:=1;
      while(FileExists(FDIR+strTmp+'~'+inttostr(iTmp)+strTExt)) do
      begin
        iTmp:=iTmp+1;
      end;
      strNewFile:=strTmp+'~'+inttostr(iTmp)+strTExt ;
      result:=strNewFile;
    end;function TFrmMain.FileGetSize(FileName:string): Int64;
    var w32fd: TWin32FindData; h: THandle;
    begin
      Result := 0;
      if FileName='' then Exit;
      h := Windows.FindFirstFile(PChar(FileName),w32fd);
      if h <> INVALID_HANDLE_VALUE then
         with w32fd do Result := nFileSizeHigh * MAXDWORD + nFileSizeLow;
      Windows.FindClose(h);
    end;
    procedure TFrmMain.btnExitClick(Sender: TObject);
    begin
      bStopClick(self);
      application.Terminate;
    end;end.
      

  2.   

    NT下的一些命令9X是没有的
    4年前就抛弃9X的开发了:)能在XP好,就OK了,XP是现在的基本配置
      

  3.   

    主要是执行CreateFile这个函数时出错,其他地方没错...我用到的就是在98下的,因为我的另外一个软件也只能在98下运行
      

  4.   

    if SysUtils.Win32Platform = VER_PLATFORM_WIN32_NT then  // Windows NT, Windows 2000
      begin
        // 提示! 改变名称可适用于其它驱动器,如第二个驱动器: '\\.\PhysicalDrive1\'
        hDevice := CreateFile('\\.\PhysicalDrive0', GENERIC_READ or GENERIC_WRITE,
                              FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
      end
      else // Version Windows 95 OSR2, Windows 98
        hDevice := CreateFile('\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0);
      

  5.   

    ly_liuyang(Liu Yang):NT下的一些命令9X是没有的
    wilowind(无风雪亦飘): hDevice := CreateFile('\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0);知之為知之,不知為不知,回復一點意義都沒有。
      

  6.   

    FDirectoryHandle := CreateFile(PChar(ePath.Text),
        FILE_LIST_DIRECTORY,
        FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
        nil,
        OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED,
        0);
    把CreateFile里参数改一些试试:
    FDirectoryHandle := CreateFile(PChar(ePath.Text),
        General_Read or General_Write,
        FILE_SHARE_READ or FILE_SHARE_WRITE,
        nil,
        OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED,
        0);
      

  7.   

    1.WIN98下追踪一下不就完事了.
      

  8.   

    把CreateFile里参数改一些试试:
    FDirectoryHandle := CreateFile(PChar(ePath.Text),
        General_Read or General_Write,
        FILE_SHARE_READ or FILE_SHARE_WRITE,
        nil,
        OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED,
        0);这种改法试过来,还是不行...
    这个函数还有其他函数可以替代吗,我只要能知道哪个目录及子目录有保存文件操作可以了,不一定要用这种方法...
      

  9.   

    else // Version Windows 95 OSR2, Windows 98
        hDevice := CreateFile('\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0);
    这个方法也不行,提示系统找不到设备
      

  10.   

    http://community.csdn.net/Expert/topic/3320/3320780.xml?temp=9.379214E-02
    这个贴子里的方法,对文件的建立操作可以监控,但是对DOS的EDIT保存的动作和COPY的动作没办法获得...  因为我用到的一个软件跟EDIT的保存类似...想不到这个问题这么麻烦.... 有知道的请不吝赐教啊...
      

  11.   

    改成这样:    FDirectoryHandle := CreateFile(PChar(ePath.Text), 0, 0, nil, OpenExisting, 0, 0);如果还错就是  PChar(ePath.Text) 的问题了
      

  12.   

    再不就 不是createfile的问题
      

  13.   

    可能是createfile在win98下不支持...大家有没有其他的解决方法?  不一定用这个方法,只要能实现就行