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.