Programming is one of the most
difficult branches of applied mathematics;
the poorer mathematicians
had better remain pure mathematicians.
--- EDSGER WYBE DIJKSTRA, How do we tell truths that might hurt? (1975)
Arrogance in computer science is measured in nanodijkstras.
--- ALAN KAY, ?
difficult branches of applied mathematics;
the poorer mathematicians
had better remain pure mathematicians.
--- EDSGER WYBE DIJKSTRA, How do we tell truths that might hurt? (1975)
Arrogance in computer science is measured in nanodijkstras.
--- ALAN KAY, ?
Implementation of the "right click" functionality was just the first step on our journey to the Grand Unification of the Host and her Guest. Today we are going to make the second step: "incoming folder".
As we can see in "Crystal Reports" or "Word 2007" examples, the following actions are required:
- open the folder
- find the file
- right-click on it
- select 'doknir' in pop-up menu
- We need to split method wodShellMenu1Click - new method is called CreateJob:
 procedure TForm1.wodShellMenu1Click(ASender: TObject;
   const Item: IMenuItem; const Name, Directory, Targets: WideString);
 var
    cFile: string;
 begin
    Memo1.Lines.Add(Directory);
    Memo1.Lines.Add(Name);
    Memo1.Lines.Add('['+Targets+']');
    if Pos(';',Targets)>0 then begin
       ShowMessage('Please select only one file!');
    end else begin
       if UpperCase(ExtractFileExt(Targets)) = '.LNK' Then begin
          cFile:=GetTarget(Targets);
          Memo1.Lines.Add(cFile);
       end else begin
          cFile:=Targets;
       end;
    end;
    CreateJob(cFile);
    Memo1.Lines.Add('------------------------------');
 end;    // wodShellMenu1Click
 procedure TForm1.CreateJob(cFile: string);
 var
    SearchRec: TSearchRec;
    cTmpFile, cJob, cJb, cFile2: string;
    nSize: integer;
    cExt, cExt2: string;
 begin
    nSize:=-1;
    if FileExists(cFile) then  begin
       if not Forms.Application.Active then
          Forms.Application.Restore;
       if WindowState=wsMinimized then WindowState:=wsNormal;
       Forms.Application.BringToFront;
       FindFirst(cFile, faAnyFile, SearchRec);   // +cExt.Caption
       if (Length(SearchRec.Name)>0) and (SearchRec.Size>0) then begin
          nSize:=SearchRec.Size;
          Memo1.Lines.Add('size='+IntToStr(nSize) ) ;
       end;
       FindClose(SearchRec);
       if nSize>50000000 then begin
         if MessageDlg('File '+cFile+' is large! Do you want to continue?',
          mtConfirmation,  [mbYes, mbNo], 0) <> mrYes then begin
             Memo1.Lines.Add('------------------------------');
             exit;
         end;
       end;
       cExt:=ExtractFileExt( cFile );
       if cExt<>'' then begin
          cFile2:=LeftStr(cFile, Length(cFile)-Length(cExt) );
          cExt2:=ExtractFileExt( cFile2 );
          if cExt2<>'' then cExt:=cExt2+cExt;
       end;
 //      ShowMessage(cExt);
       cTmpFile:=TmpFile( cTmpPath, cExt );
       try
          FileCopy(cFile,  cTmpFile);
       except
          ShowMessage('Error copy: '+cFile);
       end;
       if FileExists( cTmpFile ) then begin
          // create job (random file name)
          cJb:=TmpFile(cJobsPath,'.jb');
          cJob:=ChangeFileExt(cJb,'.job');
          Memo1.Lines.Add('job='+ cJob);
          with TIniFile.Create(cJob) do begin
             WriteString('doknir job', 'tmp file', ExtractFileName(cTmpFile));
             WriteString('doknir job', 'original file', cFile);
             UpdateFile;
             Free;
          end;
          RenameFile(cJb, cJob);
       end;
    end;
 end;    // CreateJob- We need a function to get "My Documents" folder:
 function GetMyDocuments: string;
 var
    Res: Bool;
    Path: array[0..Max_Path] of Char;
 begin
    Res := ShGetSpecialFolderPath(0, Path, csidl_Personal, False);
    if not Res then raise
       Exception.Create('Could not determine My Documents path');
    Result := Path;
 end;   // GetMyDocuments- We need two timers: "TimerMon" and "TimerChg". They are disabled and with intervals 500 and 2500 ms, respectively. The first timer monitors "incoming folder". When a new file appears, it stops and starts the second timer which checks if the size of incoming file is changing. If not it stops, creates a job to send the document to the virtual appliance and it starts the first timer.
- Specific subfolder in "My documents" will be called [_doknir_] (so that it will be alphabetically on the top in the list of folders). The method FormCreate has these new lines:
    cMyDok:=GetMyDocuments()+'\[_doknir_]';
    bFindFirst:=TRUE;
    TimerMon.Enabled:=TRUE;  // start monitor cMyDok- And finally, here are two methods for the timer events:
procedure TForm1.TimerMonTimer(Sender: TObject);
// monitor incoming folder
var
   nRes: integer;
begin
   TimerMon.Enabled:=FALSE;
   if bFindFirst then begin
      nRes:=FindFirst(cMyDok+'\*.*', faArchive , srDok);
   end else begin
      nRes:=FindNext(srDok);
   end;
   if (nRes=0) then begin
      if bFindFirst then begin
         Memo1.Lines.Add('--------------');
         Memo1.Lines.Add('findfirst: '+srDok.Name+
            '  size='+IntToStr(srDok.Size) );
         bFindFirst:=FALSE;
      end;
      if (srDok.Name<>'.') and (srDok.Size>0) then begin
          TimerChg.Enabled:=TRUE;
      end else begin
          TimerMon.Enabled:=TRUE;
      end;
   end else begin  // nRes<>0
      if not bFindFirst then begin
         bFindFirst:=TRUE;
         FindClose(srDok);
      end;
      TimerMon.Enabled:=TRUE;
   end;
end;   // TimerMonTimer
procedure TForm1.TimerChgTimer(Sender: TObject);
// is size of file changing ...
var
   nSize: Int64;
   fs: TFileStream;
   cTo: string;
begin
   TimerChg.Enabled:=FALSE;
   Memo1.Lines.Add('incoming: '+srDok.Name);
   fs:=NIL;
   try
      nSize:=-1;
      fs:=TFileStream.Create(cMyDok+'/'+srDok.Name,
      fmOpenRead+fmShareDenyNone);
      nSize:=fs.Size;
   finally
      fs.Free;
   end;
   Memo1.Lines.Add('stream size: ' + IntToStr(nSize) );
   if (srDok.Size=nSize) then begin // size ok
      cTo:=cMyDok+'/done/'+srDok.Name;
      Memo1.Lines.Add('size ok: '+IntToStr(nSize) );
      if FileExists(cTo) then
         DeleteFile(cTo);  // temporary ***
      if RenameFile(cMyDok+'/'+srDok.Name, cTo) then begin
         CreateJob(cTo);
      end;
   end;
   TimerMon.Enabled:=TRUE;  // monitor for next file
end;   // TimerChgTimerSo, from now on, every time we save or put a document into the subfolder [_doknir_] of folder "My Documents", it will appear in the virtual appliance.
[]
 

No comments:
Post a Comment