MoveFileEx 함수는 컴퓨터가 재시작 될 때까지 파일 이름 변경이나 삭제를 지연시킬 수 있는 유용한 옵션이 있다.
사용 중인 DLL을 교체한다거나 언인스톨 시 파일을 삭제할 때 파일이 사용 중이어서 삭제할 수 없는 경우에 쓸 수 있다.

MoveFile 함수는 내부적으로 CreateFile 함수를 통해 파일을 오픈하는데 이 때 DesiredAccessDELETE을 사용한다.
파일이 잘 열렸다면 RenameInformation IRP를 날린 후 핸들을 닫고 성공으로 반환한다.
하지만 다른 위치에서 이미 파일이 열려있었다면 먼저 파일을 연 쪽에서 FILE_SHARE_DELETE를 함께 주지 않았었을 경우 파일 열기가 ERROR_SHARING_VIOLATION 으로 실패하게 되어 MoveFile 함수 또한 실패하는 것이다.

재부팅 시에라도 dll 등을 교체시켜주거나 깨끗하게 삭제하기를 원한다면 MoveFileEx함수를 호출 할 때 세 번째 파라미터로 MOVEFILE_DELAY_UNTIL_REBOOT 옵션을 주면 된다.
이렇게 하면 MoveFileEx함수는 레지스트리의 HKLM\System\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations 위치에 어떤 오퍼레이션이었는지 정보를 적어 놓기만 하고 리턴한다.
시스템이 재부팅 되고 나서 응용프로그램들이 실행되기 전 운영체제에서 레지스트리를 확인해 보고 해당 동작을(이름 변경 혹은 삭제) 수행해 주기 때문에 어떤 파일이던지 삭제가 가능하다.
HKLM 위치에 써야 하기 때문에 관리자 권한이 필요하다.

알아두면 좋을 관련 지식들.

  1. 다른 곳에서 파일을 열고 있다고 이름 변경을 못하는 것은 아니다.
    먼저 파일을 연 쪽에서 어떤 공유 모드로 파일을 열었는지가 중요하다.
    파일을 먼저 오픈하는 쪽에서 FILE_SHARE_DELETE옵션을 주어서 CreateFile을 하면 다른 위치에서 해당 파일의 이름을 변경할 수 있다.
    심지어는 삭제도 가능한데(DeleteFile을 호출하면 성공한다) 이때는 파일이 삭제 상태로만 마킹되며 파일 시스템 드라이버는 해당 파일을 열어 놓은 모든 핸들이 닫힐 때 실제로 삭제를 수행한다.
    이렇게 삭제 상태로 마킹되어 있는 동안에는 또 다른 곳에서 파일 오픈 시도가 생겼을 때 ERROR_ACCESS_DENIED 에러가 발생하게 된다.
    파일 핸들을 닫기 전까지는 이런 DELETE_PENDING 상태의 파일을 삭제되지 않은 상태의 파일로 다시 돌리는 것 또한 가능하다.

  2. 어딘가에서 파일 삭제를 허용하지 않고 먼저 파일을 열어두었을 시에 MoveFileExMOVEFILE_DELAY_UNTIL_REBOOT 옵션을 주어 함수를 호출하면 파일 열기 시 ERROR_SHARING_VIOLATION에러를 받게 된다. 하지만 이 때는 MoveFileEx 함수가 실패로 리턴하지 않고 레지스트리에 기록을 해주기 때문에, 어떤 상태의 파일이든지 간에 이름 변경이나 삭제를 할 수가 있는 것이다.

  3. 함수 모양을 봤을 때 MoveFileExDeleteFile처럼 HANDLE을 인자로 전달받지 않고 파일 경로를 전달 받는 함수는 모두 내부적으로 파일을 오픈한다.

  4. SetFileInformationByHandle 함수를 사용하면 추가적으로 파일을 다시 열지 않고 Rename, Delete 등의 작업을 할 수 있다.
    이 함수는 파일 시스템 드라이버에 전달되는 IRP와 거의 비슷하게 매핑되는 아주 강력한 함수이다.
    파일 속성에 대한 모든 조작은 이 함수를 통해서 할 수 있다.
    하지만 워낙 저수준의 함수이기 때문에 사용법이 조금 어렵게 느껴질 수도 있다.
    아래 글에 해당 함수를 사용하여 이름 변경을 하는 코드에 대한 설명이 있다.
    하위 디렉터리의 파일이 변경되었는지 감지하는 법



함께 읽으면 좋은 글: