How do I wait to delete a file until after the program I started has finished using it?

后端 未结 2 696
野性不改
野性不改 2021-01-07 12:54

I have been looking for a way to open a file saved to my computer via a Delphi app with its appropriate application. The file is stored in a Varbinary field in a SQL databas

2条回答
  •  野趣味
    野趣味 (楼主)
    2021-01-07 13:24

    Hers a snip from a unit I use for a similar purpose. I found these functions online somewhere over the the years so I take no credit and make no promises.

    I personally use the WaitExec() function to launch a pdf (retrieved from a database) in Acrobat for editing and then re-save it to our database when done.

    I have used the two other functions at other times as well so I know they all work to one degree or another but I think WaitExec() worked best in an interactive mode, while Launch() worked better from a thread or non-interactive mode.

    The IsFileInUse function can tell you if the file you created is in use by any other processes and may be a viable option as well.

    uses SysUtils, Windows, ShellAPI, Forms, Registry, Classes, Messages, Printers,
        PSAPI, TlHelp32, SHFolder;
    
    
    
    function IsFileInUse(fName: string): boolean;
    var
        HFileRes: HFILE;
    begin
        Result := False;
        if not FileExists(fName) then
            Exit;
        HFileRes := CreateFile(pchar(fName), GENERIC_READ or GENERIC_WRITE,
            0 {this is the trick!}, nil, OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL, 0);
        Result := (HFileRes = INVALID_HANDLE_VALUE);
        if not Result then
            CloseHandle(HFileRes);
    end;
    
    function Launch(sCommandLine: string; bWait: Boolean; AppHandle: HWND): Boolean;
    var
        SEI: TShellExecuteInfo;
        Mask: Longint;
    begin
        Mask := SEE_MASK_NOCLOSEPROCESS;
        FillChar(SEI, Sizeof(SEI), #0);
        SEI.cbsize := Sizeof(SEI);
        SEI.wnd := AppHandle;
        SEI.fmask := Mask;
    
        //if FExeStyleString<>'' then SEI.LPVERB:=pchar(FExeStyleString);
        SEI.LPFile := pchar(sCommandline);
    
        //SEI.LPParameters := pchar(FExeParameters);
        //SEI.LPDirectory  := pchar(FExepath);
        SEI.nshow := SW_SHOWNORMAL; // SW_SHOWMINIMIZED, SW_SHOWMAXIMIZED
        ShellexecuteEx(@SEI);
    
        if bWait then
            WaitforSingleObject(SEI.hProcess, INFINITE);
        Result := True;
    end;
    
    function WaitExec(const CmdLine:AnsiString;const DisplayMode:Integer):Integer;
      {Execute an app, wait for it to terminate then return exit code.  Returns -1
       if execution fails. DisplayMode is usually either sw_ShowNormal or sw_Hide.}
     var
       S:TStartupInfo;
       P:TProcessInformation;
       M:TMsg;
       R:DWord;
     begin
       FillChar(P,SizeOf(P),#0);
       FillChar(S,Sizeof(S),#0);
       S.cb := Sizeof(S);
       S.dwFlags := STARTF_USESHOWWINDOW;
       S.wShowWindow := DisplayMode;
       if not CreateProcess(nil,
         PChar(CmdLine),                { pointer to command line string }
         nil,                           { pointer to process security attributes }
         nil,                           { pointer to thread security attributes }
         False,                         { handle inheritance flag }
         CREATE_NEW_CONSOLE or          { creation flags }
         NORMAL_PRIORITY_CLASS,
         nil,                           { pointer to new environment block }
         nil,                           { pointer to current directory name }
         S,                             { pointer to STARTUPINFO }
         P)                             { pointer to PROCESS_INF }
       then begin
        ShowMessage('Create Process failed. Save this message for IT: ' + CmdLine);
        Result:=-1
       end
       else begin
    //     WaitforSingleObject(P.hProcess,INFINITE);
    //   The following replacement better satisfies DDE requirements
         repeat
           R := MsgWaitForMultipleObjects(1, // One event to wait for
           P.hProcess, // The array of events
           FALSE, // Wait for 1 event
           INFINITE, // Timeout value
           QS_ALLINPUT); // Any message wakes up
           if R>WAIT_OBJECT_0 then begin
             M.Message := 0;
             while PeekMessage(M,0,0,0,PM_REMOVE) do begin
               TranslateMessage(M);
               DispatchMessage(M);
             end
           end;
    
         until R=WAIT_OBJECT_0;
    
         // put value into Result.... non zero = success
         GetExitCodeProcess(P.hProcess,DWord(Result));
    
         CloseHandle(P.hProcess);
         CloseHandle(P.hThread);
         P.hProcess:=0;
         P.hThread:=0;
       end;
    end;
    

提交回复
热议问题