Windows API MoveFile() not working for running exe


Keywords:c 


Question: 

Here is a simple C program for illustration:

#include <windows.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    //MoveFile(argv[0], "dst.exe");
    getchar();

    return 0;
}

make an test.exe from code above.

Now execute test.exe, the test.exe hangs there due to getchar(), then I can cut and paste this exe freely.

But when I uncomment that MoveFile(argv[0], "dst.exe");, I was hoping it could move itself to dst.exe, it turns out to have a dst.exe, while program.exe is still there, just like CopyFile() does.

From what I know, in Windows, when exe is running I can rename it, move it, but not deleting it, that MoveFile() behaves as a combination of CopyFile() and DeleteFile()

And also see this from Microsoft doc MoveFileEx.

BOOL WINAPI MoveFileEx(
  _In_     LPCTSTR lpExistingFileName,
  _In_opt_ LPCTSTR lpNewFileName,
  _In_     DWORD   dwFlags
);

dwFlags has an option MOVEFILE_COPY_ALLOWED

the file is to be moved to a different volume, the function simulates the move by using the CopyFile and DeleteFile functions. If the file is successfully copied to a different volume and the original file is unable to be deleted, the function succeeds leaving the source file intact. This value cannot be used with MOVEFILE_DELAY_UNTIL_REBOOT.

Further confirming my guess, and I tested with MoveFileEx() with option MOVEFILE_REPLACE_EXISTING , recompiled the program, run it, now MoveFileEx() just returned as fail, not even dst.exe generated.

But I can definitely cut and paste that exe while running, MoveFileEx() should does so, why???

If they can't, what should I do to make it just like cut and paste.


1 Answer: 

If the target destination is on the same volume, MoveFile just updates the corresponding directory entries. The file's MFT record is not changed, its index remained the same, its contents is not touched. Because the file is not affected at all, you can move it within the same directory (i.e. rename) or within the same volume even if the file is in use (note: this is true for files being executed; in general, this is true only if the file was open with FILE_SHARE_DELETE).

If the target directory is on another volume, the system needs to copy it (will fail if the file is open in exclusive mode) and delete it on the old volume (will fail unconditionally if the file is in use).

Cut&paste works ok within the same volume and does not on different volumes. The reason is that the file clipboard operations use a different technique than the text ones.

When you select a text and press Ctrl-X, the text string is moved to an allocated global memory block and the block is passed to Windows. The program does not own it anymore. The text is physically in the Windows Clipboard and you can paste it as many times as you wish.

When you press Ctrl-X on a file, it is not moved to the Clipboard. The Clipboard will receive a file descriptor, which contains info about the file and the requested operation (this technique is known as delayed rendering). When you press Ctrl-C, the Clipboard will simply ask the object owner (i.e. Windows Explorer) to perform the requested operation. And the Explorer will perform it using the very same MoveFile.

Note that you can paste a cut file only once because the first Ctrl-C will invalidate the descriptor in the Clipboard. A copied file can be pasted several times.