Windows System Programming: Move / Delete a File or Folder
Published: 2020-07-21 03:12:27

Hello devs

In this post I will cover moving a file or directory from one path (source) to another (destination). Along with this moving part, I will also cover how you can delete an existing file or folder.

So basically if you want to rename a file / directory or even change the location of a file / directory, you need to work move "it" from source path to the destination path.

To perform move operation, you need to call [MoveFileA](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefilea) function from `WinBase.h`.

If you would see, MoveFile is a pretty straightforward function

```c++
BOOL MoveFile(
  LPCTSTR lpExistingFileName,
  LPCTSTR lpNewFileName
);
```
Function parameters description as follows
+ **lpExistingFileName** &rarr; Location of the file/folder in the local computer you want to move. If the path is not found, it might return **ERROR_FILE_NOT_FOUND**.
+ **lpNewFileName** &rarr; The new name for the **non existing **file or directory. If you will pass the path that already exists, it will return **ERROR_ALREADY_EXISTS**.

In case you are wondering how to overwrite the existing path, use [MoveFileExA](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexa), where the 3rd parameter should be **MOVEFILE_REPLACE_EXISTING**.

**Note:** In MoveFileExA, If _lpNewFileName_ or _lpExistingFileName_ name a directory and _lpExistingFileName_ exists, an error is reported.

The complete code as follows
```c++
#include <Windows.h>
#include <iostream>
#include <WinBase.h>

int main(int argc, char** argv)
{

	if (argc < 3) {
		printf("usage: %s <old filename / dirname> <new filename / dirname>\n", argv[0]);
		return 1;
	}

	/** 
	  * Function Documentation
	  * https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefilea
	  */
	BOOL flag = MoveFileA(argv[1], argv[2]);

	if (flag) {
		printf("Renamed\n");
	}
	else {
		switch (GetLastError())
		{
		case ERROR_FILE_NOT_FOUND:
			printf("ERR: File '%s' not found\n", argv[1]);
			break;
		case ERROR_ALREADY_EXISTS:
			printf("ERR: '%s' already exists\n", argv[2]);
			break;
		default:
			printf("ERR: %d\n", GetLastError());
			break;
		}
		return 1;
	}
	return 0;
}
```

Now comes the part of removing file and directory.

Unlike moving operation, the remove operation is different for file and directory. So in this I will introduce another approach to detect to check if the path exists and determining if the existing path is a file or directory.

First of all, you need to check the existence of the path that has to be removed. For this, you need to use [PathFileExistsA](https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-pathfileexistsa), declared in `shlwapi.h`.

```c++
BOOL PathFileExistsA(
  LPCSTR pszPath
);
```

Function parameters description as follows
+ **pszPath** &rarr; A pointer to null-terminated `const char*` that contains the full path of the object to verify.

If the path exists, it will return `TRUE`, otherwise `FALSE`.

To make this code in working condition, you should tell the linker to link the `Shlwapi.lib` library as well. 

**NOTE:** Header file is a something that contains only the declaration/prototype of the functions. But the actual definition (steps describing the function execution, aka function body) are written in library. [[READ MORE](https://stackoverflow.com/a/924495)]

So in C++, the libraries are linked with [pragma](https://docs.microsoft.com/en-us/cpp/preprocessor/pragma-directives-and-the-pragma-keyword?view=vs-2019) directive, [comment(lib, "&lt;library name or path&gt;")](https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=vs-2019#lib)

The snippet to link Shlwapi.lib would be
```c++
#pragma comment(lib, "Shlwapi.lib")
```
 
Ok, so now come back to removing thing. Once it's verified that file exists, it's time to determine type of path (whether it's a file or a directory). For this, you need to call [GetFileAttributesA](https://docs.microsoft.com/en-gb/windows/win32/api/fileapi/nf-fileapi-getfileattributesa) from `fileapi.h`. 

```c++
DWORD GetFileAttributesA(
  LPCSTR lpFileName
);
```
Function parameters description as follows
+ **lpFileName** &rarr; The name of the file or directory you want to look file attributes for.

It will return a numerical output, which is mapped to [file attribute constants](https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants). In this case, I am interested in **FILE_ATTRIBUTE_DIRECTORY**, the handle that identifies a directory.

At this time, you know if the path exists or not and whether it's a directory or a file. Now you should perform the remove operation on it.

To delete file use [DeleteFileA](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-deletefilea) and for directory use [RemoveDirectoryA](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya)

Both of them are declared in `fileapi.h` and require only one parameter (type = `const char*`). But in case of RemoveDirectoryA,  path must specify an empty directory.

```c++
BOOL RemoveDirectoryA(
  LPCSTR lpPathName
);

BOOL DeleteFileA(
  LPCSTR lpFileName
);
```

The complete code as follows
```c++
#include <Windows.h>
#include <fileapi.h>
#include <iostream>
#include <Shlwapi.h>

#pragma comment(lib, "Shlwapi.lib")

int main(int argc, char* argv[]) {
	if (argc == 1) {
		printf("usage: %s <file or directory name>\n", argv[0]);
		return 1;
	}

	// checking if file exists (for getting file attributes)
	// https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-pathfileexistsa
	if (PathFileExistsA(argv[1])) {
		// https://docs.microsoft.com/en-gb/windows/win32/api/fileapi/nf-fileapi-getfileattributesa
		if (GetFileAttributesA(argv[1]) == FILE_ATTRIBUTE_DIRECTORY) {
			// the path is a diretory
			// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya
			if (RemoveDirectoryA(argv[1])) {
				printf("Directory '%s' deleted\n", argv[1]);
			} else {
				switch (GetLastError())
				{
				default:
					printf("ERROR: DeleteFileA - %d\n", GetLastError());
					break;
				}
			}
		} else {
			// the path is a file
			// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-deletefilea
			if (DeleteFileA(argv[1])) {
				printf("File '%s' deleted\n", argv[1]);
			} else {
				switch (GetLastError())
				{
				default:
					printf("ERROR: DeleteFileA - %d\n", GetLastError());
					break;
				}
			}
		}
	} else {
		printf("File / Directory '%s' not exists\n", argv[1]);
		return 1;
	}
	return 0;
}
```

I hope you have learnt something new today. Follow the links to reach me

+ Email: tbhaxor@gmail.com
+ Twitter: [@tbhaxor](https://twitter.com/tbhaxor)
+ Facebook: [@tbhaxor](https://fb.com/tbhaxor)
+ GitHub: [@tbhaxor](https://github.com/tbhaxor)
+ LinkedIn: [@gurkirat--singh](https://www.linkedin.com/in/gurkirat--singh)
+ Instagram: [@_tbhaxor_](https://instagram.com/_tbhaxor_)