Sprawdzanie, czy plik jest używany przez inny proces

0

W programie wykorzystuję zewnętrzny moduł EXE o nazwie pdftopng w celu przekonwertowania pliku PDF do PNG. Moduł uruchamiam z wykorzystaniem ShellExecute i rozpoczyna się generowanie PNG. Plik źródłowy jest dość duży (mapa) więc zapis do PNG chwilę trwa (jakieś 2-3 sekundy). Potem muszę zamienić PNG na BMP i wyświetlić do w programie. Fragment kodu wygląda następująco:

ShellExecute(Handle,'open',PChar(Directory+'\Source\PDF\pdftopng.exe'),PChar('Plik.pdf Plik.png'), nil, SW_HIDE);

Convert_PNG_To_BMP(Plik.png, Plik.bmp) //moja procedura;

Pomiędzy ShellExecute a Convert_PNG_To_BMP muszę wstawić procedurę, która sprawdzi, czy uruchomiony moduł zewnętrzny zakończył już zapis do pliku PNG. FileExists odpada bo plik tworzony jest na samym początku zapisu i utworzenie pliku nie oznacza ukończenia zapisu.
Próbowałem także zastosowania IsFileInUse, ale procedura dotyczy aplikacji exe, a nie pliku z danymi.

Proszę o pomoc jak sprawdzić, czy plik PNG jest używany przez pdftopng.exe, gdyż dopiero po zwolnieniu pliku mogę wywołać kolejną procedurę zapisu PNG do BMP. W przeciwnym wypadku program zgłasza błąd, że plik PNG jest używany przez inny proces (konkretnie pdftopng.exe).

0

Jest jeszcze taka metoda, że jak jeden proces ma otwarty deskryptor pliku do zapisu i plik istnieje, to inny proces próbując otworzyć też do zapisu na istniejącym pliku, bo jak nie ma to może wyprzedzić pierwszego, i jak nie powiedzie się utworzenie deskryptora to wyleci błąd, który akurat będzie informował o tym, że plik jest w użyciu.

3

Zacznijmy od tego, że funkcja ShellExecute to pewnego rodzaju wytrych z wieloma różnymi side-effects i quirksami. Odradzam korzystania z niej. Zamiast tego użyj CreateProcess i oczekuj na zakończenie - WaitForSingleObject(...).

0

po prostu co jakiś czas próbuj otworzyć plik w trybie wyłączności jednocześnie wyłapując wyjątek "brak dostępu" aż dasz radę go otworzyć

0

Dzięki za sugestie. Ostatecznie zastosowałem takie rozwiązanie:

repeat
Sleep(100); // czeka 0,1 sekundy i sprawdza poniższą funkcją, czy pdftopng.exe jest zajęty
until IsFileInUse(PChar(Directory+'\Source\PDF\pdftopng.exe'))=False;

gdzie:
IsFileInUse

0

w taki sposób odpalam zewnętrzną aplikację i czekam na jej zakończenie :

if fileexists(Fexaname) then
         begin
           fillchar(SEInfo, sizeof(SEInfo), 0);
           SEInfo.cbSize := sizeof(TShellExecuteInfo);
           SEInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
           SEInfo.Wnd := application.Handle;
           SEInfo.lpFile := pwidechar(Fexename);
           SEInfo.lpParameters := pwidechar(Faparams);
           SEInfo.nShow := SW_SHOWNORMAL;
           if ShellExecuteEx(@SEInfo) then
           begin
             repeat
               GetExitCodeProcess(SEInfo.hProcess, ExitCode);
             until (ExitCode <> STILL_ACTIVE) ;
           end;
         end;
0

@grzegorz_so: czy mi się zdaje, czy Twoja pętla zżera całą dostępną moc CPU?

0
furious programming napisał(a):

@grzegorz_so: czy mi się zdaje, czy Twoja pętla zżera całą dostępną moc CPU?

dla wielordzeniowego CPU może "zżerać" moc jednego rdzenia, i tym samym nie "zabije" systemu ..

1 użytkowników online, w tym zalogowanych: 0, gości: 1