-2

So, before starting, I have been researching (not only on Stack Overflow) and I can't find a solution to my problem.

I am trying to copy a file to a certain place (and if possible, change its name at the same time I copy it) using Windows' CopyFile function.

I've created a sample program to show the error.

#include <iostream>
#include <Windows.h>
using namespace std;

int main()
{
    cout << "Copy in progress" << endl;
    bool X = CopyFile(L"test.txt", L"C:\\", 1); //NOT C: nor C:\\ 
    if (!X){ cout << "FALLO AL COPIAR\n"; cout << "Error: "<<GetLastError();}
    else{ cout << "COPIADO CORRECTO";  }
    cin.get(); cin.get();
    return 0;
}

GetLastError() returns 3 - which means ERROR_PATH_NOT_FOUND - but, believe me, I've checked every file (test.txt is in the same place as the built .exe, I'm running as admin...) and it still gives 3.

I can't manage to make it work. Notice the L"test" this is done because I use Visual Studio with certain character set settings, I've tried to change that config and use "test.txt" -> Still error 3.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
78dtat78da
  • 112
  • 1
  • 9
  • did you try using full path? – Amit Dec 27 '15 at 20:50
  • 1
    Don't ever post screenshots of code. Post the code instead. Screenshots escape text searches, making your question less discoverable. – IInspectable Dec 27 '15 at 23:17
  • I reverted the edit. Please let's stick to the original question. If you don't understand what `L` means, and why you use it, you aren't ready to write code on Windows. – David Heffernan Dec 28 '15 at 05:28
  • CopyFile is a tested, verified, trusted and documented API. If it is saying, Error 0x3, that surely means, you are somehow messing with the path of file (either in Source, or Destination or both). – Abhineet Dec 28 '15 at 05:37

3 Answers3

2

You need to provide a filename:

bool X = CopyFile(L"test.txt", L"C:\\test.txt", 1);
Danny_ds
  • 11,201
  • 1
  • 24
  • 46
  • 1
    And you should use a full path in the first parameter, not a relative path. There is no guarantee that the process's initial working directory is the same directory where the .exe is located. Best to retrieve the calling process's actual path and append the desired filename to it. – Remy Lebeau Dec 27 '15 at 21:25
  • @RemyLebeau - Indeed. – Danny_ds Dec 27 '15 at 21:35
  • Guys, I've "found" the error (more or less). In my code, Im using string path = getenv("USERPROFILE"); Which retrieves me the USERPROFILE variable (or any other) By surprise, the CopyFile (seems to) copies fine the file if using %TEMP% ("TEMP") but not with any other variable neither being administrator, so, lol. – 78dtat78da Dec 27 '15 at 21:53
  • @PedroJavierFernández - What are the contents of `path`, `secondPath` and `finalPath`? – Danny_ds Dec 27 '15 at 23:00
  • @PedroJavierFernández: You asked a different question, and that question has been answered with this answer. If you need help constructing a fully qualified pathname from an environment variable, ask a different question. If `CopyFile` fails with error code 3, you messed up either source or destination (or both) pathnames. – IInspectable Dec 28 '15 at 11:34
1

You may check the function signature from the MSDN:

BOOL WINAPI CopyFile(
  _In_ LPCTSTR lpExistingFileName,
  _In_ LPCTSTR lpNewFileName,
  _In_ BOOL    bFailIfExists
);

I suppose, it requires not target directory (as e.g. cp command would), but the entire file name. Hint: make sure that all directories before the final file name are created when you call CopyFile.

Yet another hint: on POSIX systems, you have no similar routine (well, you have something similar on OS X, but it's OS-specific). However, here's what you can do (and this is how CopyFile actually works behind the scene):

  1. Open two file handles via open for POSIX or CreateFile for Windows. One handle is opened for reading (source file) and the other one is opened for writing (destination file).
  2. Read from the handle that you opened for reading into the temporary buffer (BUFSIZ buffer size is usually enough).
  3. Write the data from the buffer into the handle opened for writing.
  4. Repeat until there are bytes available into the readable handle.

This is how it generally works, though OS-specific routines may be tuned with some black magic (e.g. they can perform memory mapping, send file from one descriptor into the other without exiting from kernel mode, etc.).

ghostmansd
  • 3,285
  • 5
  • 30
  • 44
  • 1
    CopyFile works. Please don't suggest otherwise @ghost – David Heffernan Dec 28 '15 at 05:15
  • @David: Please read my answer carefully. It doesn't tells OP that `CopyFile` is broken; it explains *how* it works and the same time demonstrates why `CopyFile` has such signature (I mean why it has two file names, not file name and a directory name). – ghostmansd Dec 28 '15 at 05:55
  • You've advised the asker that a good way forward is to copy the files contents rather than use CopyFile. That's appalling advice. – David Heffernan Dec 28 '15 at 09:08
  • 1
    It's also worth pointing out that CopyFile does way more than you say. It copies meta data and alternate streams too. – David Heffernan Dec 28 '15 at 09:16
  • Well, I agree, you're right, it is worth noting. However, I disagree that I propose to use copy file contents *instead* of calling `CopyFile`: I mention this way since it is the most evident way to get the file whose contents are the same (I doubt that topic starter cares about meta). When one wants to have some kind of `CopyFile` for POSIX (and one really just wants to have a copy of the file contents), I think my advice makes sense. All in all, I think it is a senseless dispute. – ghostmansd Dec 28 '15 at 12:24
  • 1
    Alternate data streams are file contents. Please don't propose a solution that isn't. – IInspectable Dec 29 '15 at 02:59
  • @ghost Why do you find it so hard to use CopyFile anyway? It's not remotely difficult. You just need two file names. Once you've got two file names you are home. I don't understand why you think that is hard. Not least because your proposed solution involves the same two file names. – David Heffernan Dec 29 '15 at 08:43
  • My god, @David, you did notice that the upper part of the post recommends to visit MSDN and see how to use `CopyFile`, didnt't you? :-) – ghostmansd Dec 29 '15 at 12:42
  • 1
    Read the first comment to your answer to see how well the asker got the message. I propose you remove the second part of the answer. – David Heffernan Dec 29 '15 at 13:35
0

try:

CopyFile(L"test.txt", L"C:\\test.txt", 1);
  • Ok, this has worked for me. But now, in the real program (since that was an example I couldn't run neither) I have a wchar_t array containing source and another with destination. Both have the filename at the end, but, ( I believe is caused by single '\' ) it gaves me error 3. I'll try to explain better my situation. Even I have correct variables (full path, not relative, with provided filename) and it gives error 3 (being admin or not). Any Ideas? – 78dtat78da Dec 27 '15 at 21:33
  • 1
    Without explaining, what the issue is, and what has been done to resolve it, and why, this answer is of very little help. – IInspectable Dec 27 '15 at 21:50
  • Ok, I try to explain. I was not sure what the issue was, and how I resolved it, but doing changes on my code, i deduced that: 1. When using CopyFile() over enviroment variables there are some restrictions. It can't copy to certain variables such as %userprofile% but can copy to %temp% (not sure, since I can't see the copied file even my tool says it has been copied..) 2. When using CopyFile() over environment vairiables, you sometimes need to replace the filename from the path. And that's it. It's not fully solved, But I'll try to post updates If i achieve something. – 78dtat78da Dec 27 '15 at 22:08
  • If you aren't sure, what the OP is asking, write a comment. The [comment everywhere privilege](http://stackoverflow.com/help/privileges/comment) is awarded, once you earn 50 reputation. The comment posted as an update isn't even remotely related to the question, and it doesn't address any of the issues I pointed out above. This does not constitute an answer to the question. – IInspectable Dec 27 '15 at 23:40