Delete Files with C++ on windows - c++

I am writing a C++ program and I want to have some created files deleted if meeting with some conditions. These file have various file names that are assigned using type "string" in each iteration. Now I'm trying to delete some of the files with their file names, but it seems that neither Deletefile function nor remove can deal with C++ strings. I have also tried to convert the strings to c type char* but it doesn't work.
I'm using visual studio community 2015 on windows 10.
Is their any convenient way for this problem?

As said in the comment - the function .c_str() returns C-compatible string that can be use with DeleteFile and remove.
If that doesn't work, I'd guess that you app is compiled as Unicode , meaning you will have to use std::wstring instead of std::string.
try to combine the two ways:
std::string fileName = "C://file.txt";
std::wstring wFileName(fileName.begin(),fileName.end());
auto res = DeleteFile(wFileName.c_str());
remove however, uses "regular" const char*.

Related

How to use txt files in C++Builder?

I work in C++Builder 6. I have a file.txt with 5 words, I would like to be able to save all these words in an AnsiString, then change something in them and save it again in file.txt. Anyone have any idea?
C++Builder 6 did not offer much in the way of structured file I/O. Modern versions of C++Builder provide more options.
In BCB6, the simplest solution would be to use the TStringList class in <Classes.hpp>, with its LoadFromFile() and SaveToFile() methods, and its Text or Strings[] properties.
Alternatively, you can use the standard C++ std::(i|o)fstream classes in <fstream>. An AnsiString can be used with the << and >> operators of the standard C++ streams by defining VCL_IOSTREAM in your project's Conditionals list.

How can I convert an std::filesystem::path to LPCSTR for use in one of the LoadLibrary() variants?

On Windows I'm trying to use one of the variants of LoadLibrary() to open a dll previously written to an std::filesystem::path with an ofstream.
Note: I know the dll is written correctly as I can use it in the standard fashion by linking to it at runtime.
I've been trying to combine the methods from the two answers below.
How to convert std::string to LPCSTR?
how to convert filesystem path to string
This seems like it should be pretty basic but with anything I've tried so far I either get an error about conversion to LPCSTR or something like C2228: left of '.c_str' must have class/struct/union which I am baffled by.
Here's a simple example:
// Assuming I have
// std::filesystem::path path1
// correctly set, I should be able to directly access it in
// a number of ways; i.e. path1.c_str(), path1.string.c_str(), etc.
// in order to pass it the function or a temp variable.
// However direct use of it in LoadLibrary() fails with the C2228 error.
HINSTANCE hGetProcIDDLL = LoadLibrary(path1.c_str());
I've tried avoiding the macro and calling LoadLibraryA() directly with no luck.
I've also tried various ways of passing path1 with path1.string(), path1.string.c_str(), path1.wstring(), etc. with no luck.
I've also tried using a temp variable in a number of ways to avoid the cast within LoadLibrary().
LPCSTR temp_lpcstr = path1.c_str(); // Also tried things like path1.string() path1.string.c_str()
// Also tried just using a temp string...
std::string temp_string = path1.string(); // and variants.
I'm willing to try playing with the encoding (like path1.u8string() etc.) but I think it shouldn't be necessary with use of LoadLibraryA() directly.
I'm trying to avoid C casts and would prefer a c++ static_ or dynamic_ but I'll use anything that works.
Any help is appreciated.
Thanks in advance.
UPDATE
#eryk-sun's comment and #Gulrak's answer solved it for me.
It looks like with my setup, path1.c_str() alone is wchar_t but the LoadLibrary() macro was not picking that up and directing it to LoadLibraryW() as it should.
Note: For anyone else who might stumble onto this in the future here's more details of my specific setup. I'm using the MSVC compiler from 16.1.0 (~VS2019) but that's getting called from VSCode and CMake. I'm not explicitly defining _UNICODE however VSCode's intellisense certainly thinks it's been defined somewhere and points me to LoadLibraryA(). However, I think the compiler is not actually seeing that define so it interprets path1.c_str() as a wchar_t.
Actually on Windows you should be able to use LoadLibraryW(path1.c_str()) as on Windows the returned type of std::filesystem::path::c_str() should be a const wchar_t* so it's a good fit for the LoadLibraryW expected LPCWSTR.
As for the error of C2228 my guess is, you tried path1.string.c_str() as given by your comment, wich should have been path1.string().c_str(). That would give you a LPCSTR compatible string for LoadLibaryA, but if there is a chance of Non-ASCII in your path I would suggest using the explicit LoadLibaryW version.
In any way: When interfacing WinAPI with std::filesystem::path you should use the explicit A/W-Version to make your code safe independent of the state of _UNICODE, and I allways suggest the *W versions.
You should use string member function of path class which returns std::string. Then call c_stron the returned string.
std::filesystem::path path /* = initialization here */;
std::string str = path.string();
/* some handle = */ LoadLibrary(str.c_str());

Windows.h behaves different in windows form C++

I made some code in an empty project (visual studio) it uses Windows.h
i want to put this program inside my c++ windows form application.
so i made a class for it. odd thing is the code gives me an error
#include "ImageCompiler.h"
ImageCompiler::ImageCompiler()
{
}
void ImageCompiler::find_images()
{
}
std::vector<string> ImageCompiler::get_all_files_names_within_folder(string folder)
{
std::vector<std::string> names;
std::string search_path = folder + "/*.*";
WIN32_FIND_DATA fd;
HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
names.push_back(fd.cFileName);
}
} while (::FindNextFile(hFind, &fd));
::FindClose(hFind);
}
return names;
}
it says that search_path (const char *) does not match argument (LPCWSTR)
there is nothing special in the header file (only #include Windows.h)
and some other class things.
if i create a empty program with just windows.h and this code it will work.
but not in the windows form application even when its in another file and
they don't include each other. i don't understand this.
i'm actually really stupid and bad in programming so its probably a stupid
mistake. i hope someone can help me. i can give you the code from the
Myform.h but i don't think that will help.
in windows.h the type strings and string pointer type aliases are defined according to whether or not you are building with or without Unicode support. In this case the W (for wide) in LPCWSTR indicates Unicode build, so char* interfaces are not compatible.
The simplest solution if you don't need it is to switch off Unicode/wide-character string support for the build. I sm not sure however if that is possible for C++/CLI, in which case use 'wchar` interfaces where necessary.
An empty project including windows.h compiles simply because you will not have used any interfaces. If there is no code, there is no attempt to assign incompatible types, so no error.
To begin with, if you're using Managed C++ (C++/CLI), use it as much as possible. Listing all files with Managed C++ is possible and much easier than with unmanaged C++.
Managed C++ uses UNICODE. What is unicode? Shortly, it let's you use letters other than english. In your code you're not using unicode. That means if you happend to find a file which was, say, named with russian letters, you would not get its actual name.
In windows.h there are functions and variables unicode and non-unicode. Unicode version functions differ from non-unicode in name by having letter W at the end of their names in most cases. You can always find it by googling "function or variable name unicode". So you can use them by adding W to your function, for example FindFirstFileW instead of FileFirstFileA. Which your compiler is directing to by accessing FindFirstFile, but you could change that (make compiler seek unicode functions automatically) depeding on what program for compiling your code you're using. Google it.
To answer your question... this is how you edit your code:
all strings to wstrings
WIN32_FIND_DATA to WIN32_FIND_DATAW
"/*.*" to L"/*.*"
Find... functions to Find...W

movefile() fails error 2 or 123

I'm updating a c++ routine to move files that was written in visual studio express 2008/2010. I'm now running VS Express 2012
Obviously there are changes to the compiler because string functions have to be upgraded to strcpy_s etc. No problem. This is a console app. I never extended my C++ knowledge past C++ to C# etc. as I need little more than to be able to write small utils to do things on the command line. Still I'm able to write somewhat complex utilities.
My issue is movefile() function always fails to move with either error 2 or 123. I'm working in C:\users\alan\downloads folder so I know I have permission. I know the file is there. Small snippet of code is:
char source=".\\test.txt"; // edited for clarity.
char dest=".\\test.txt1";
printf("\nMove\n %s\n to %s\n",source,dest); // just to see what is going on
MoveFile((LPCWSTR) source, (LPCWSTR) dest);
printf("Error %u\n",GetLastError());
output is :
Move
.\test.txt
to .\test.txt1
Error 2
All of my strings are simple char strings and I'm not exactly sure, even after reading, what LPCWSTR was type def'd for and if this is the culprit. So to get this to compile I simply typedef'd my strings. And it compiles. But still it won't move the files.
The code is more complex in developing the source & dest variables but I've reduce it to a simple "just append a 1 to the file name" situation to see if I can just simply rename it. I thought C:\xxx\yyy\zzz\test.txt was maybe wrong in some fashion but that idea fell though with the above test. I've done it with and without the .\ same issue. I'm running out of ideas other than making my own fileopen read/write binary function to replace movefile(). I'm really against that but if I have to I will.
EDIT: I pasted the printf from original code that used FullPathName, I've corrected the snippet.
The fact that you are casting your arguments to LPCWSTR suggests that you are compiling your program with UNICODE defined, which means you are calling MoveFileW and the compiler warned about an argument type mismatch.
Inserting a cast does not fix that. You are telling the compiler to stop complaining, but you haven't actually fixed the problem (the underlying data is still wrong).
Actual solutions:
Use WCHAR as MoveFileW expects (or TCHAR/LPTSTR and the _T macro).
Explicitly call MoveFileA
Compile without UNICODE defined.
Thanks Andrew Medico. I used MoveFileA and the program seems to work now.
I'm not sure I turned off unicode, but I did change one item in the properties.
I'll need to read up on the compiler about unicode/ansi settings. But for now the issue is fixed and I'm sure I've got the idea of what I need to do. "research"!!!!

How do I properly call the CopyFile function in Visual C++?

I have a function which takes two CHAR* as input viz. int _stdcall FileTrans(char* InFile, char* OutFile) in a DLL project.
In the function I'm just calling CopyFile(InFile, OutFile, false); after some process (not related to the files). But it says that it needs both inputs as LPCWSTR. I Googled it but couldn't find anything very interesting.
Like all Windows API functions that accept a string parameter, there are actually two variants of the CopyFile function:
CopyFileA is the ANSI version, which takes narrow (non-Unicode) strings in the system's default character set. Basically, it accepts parameters of type const char*, but the Windows headers use the typedef LPCSTR for this.
CopyFileW is the wide version, which takes Unicode strings. In order to do this, it accepts parameters of type w_char*, but the Windows headers use the typedef LPCWSTR for this (note the additional W in the typedef).
Then, depending on whether the UNICODE preprocessor macro is defined for your project (either in your code before you include the Windows headers, or in your project's properties in Visual Studio), the Windows headers define the unadorned CopyFile as either CopyFileA or CopyFileW. Naturally, if UNICODE is defined, CopyFile will be defined as the Unicode version CopyFileW. Otherwise, it will be defined as CopyFileA. The idea is that the call to the general CopyFile function is automatically resolved at compile time to the correct variant.
Of course, now that you understand all of that, you can mostly forget about it. In modern Windows programming, there is absolutely no reason to call the old ANSI versions of functions or to deal with narrow strings at all. Forget that char* can even be used as a string type—those strings are dead to you. The only strings you're going to be using from now on are Unicode strings, composed of wchar_t characters. Thus the UNICODE symbol should always be defined for your code, and you should only use the W version of Windows API functions.
Looking again at the prototype for the CopyFileW function (the same one you get when you call CopyFile with UNICODE defined), we see:
BOOL WINAPI CopyFile(LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
BOOL bFailIfExists);
Recall that you learned above that LPCWSTR is just a typedef synonym for const wchar_t*, a C-style string that is composed of wide characters. You already know why the parameters are marked const: because the function doesn't modify those values.
And because you also learned above that these are the only types of strings that you should be using anymore, the next step is to modify your FileTrans function to accept wide strings (and make them const if it's not going to modify them):
int _stdcall FileTrans(const wchar_t* InFile, const wchar_t* OutFile);
Now, from inside of FileTrans, you can call CopyFile without any problems because you have the right type of strings.
But a bit of free, extra advice: never use raw C-style strings in C++. Always use the C++ string class, defined in the std namespace by the <string> header.
There are two common variants of this class, std::string and std::wstring. As before, the w refers to wide strings, which are the only type you want to use in Windows. So std::wstring is your new replacement for CHAR* throughout your code base.
Change your declaration of the FileTrans function to look like this:
#include <string>
// ...some other stuff...
int __stdcall FileTrans(const std::wstring& InFile, const std::wstring& OutFile);
Note that I've changed your original CHAR* parameters to constant references to std::wstring objects. Constant references work well here, since you're not going to be changing either of those values inside of the function.
If you're unclear on what constant means, how to use references, or how class types generally work in C++, please consult your favorite C++ book)—this is required knowledge for all C++ programmers. Remember that C++ is not the same language as C and therefore the same idioms do not apply. In many cases, there is a better way to do things, and this is certainly an example of such a case.