Dear DaniWeb,

I am working on a source code editor using Scintilla and am currently having some issues with the CreateFile() function. It does not return an error when I am saving as a new file, but when I am saving changes to the current file, it returns INVALID_HANDLE_VALUE. I am using the function exactly how I have used it before in other projects.

I have my own error report system setup, so I know exactly where the error is coming from. But suprisingly this does not help me very much. I have looked up the CreateFile() syntax on MSDN, and every parameter has the correct type of value. Also, my compiler does not throw an error. I am using Windows Vista.

file = CreateFile(fileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (file != INVALID_HANDLE_VALUE)

Does anybody know why this line of code might be throwing INVALID_HANDLE_VALUE?

I take it you have tried using GetLastError() function & seeing what that is? (what is the value of GetLastError() for you?) Because the return value of CreateFile() is INVALID_HANDLE_VALUE only if the function fails.

As a 2nd "guess" are you using the CreateFile() on a file that is deemed already open with the "CREATE_ALWAYS" parameter? I don't know for sure but that might cause a problem?

I take it you have tried using GetLastError() function & seeing what that is? (what is the value of GetLastError() for you?) Because the return value of CreateFile() is INVALID_HANDLE_VALUE only if the function fails.

As a 2nd "guess" are you using the CreateFile() on a file that is deemed already open with the "CREATE_ALWAYS" parameter? I don't know for sure but that might cause a problem?

Yes, I haved used GetLastError(), when I try to use it just crashes my application. GetLastError() returns a DWORD, how could I retrieve the description from it? Is there another function that I could use?

Also, no, I closed any previous handles.

Yes, I haved used GetLastError(), when I try to use it just crashes my application. GetLastError() returns a DWORD, how could I retrieve the description from it? Is there another function that I could use?

Also, no, I closed any previous handles.

Well the number it returns is the error, you can read it on the MS site, however there is a way to format the messages... A little function I wrote with the help of MSDN.

DWORD MsgID = GetLastError();
	char *TextSize;
	std::cerr << "Error has occured: ";
	
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, MsgID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR) &TextSize, 0, 0);

	std::cout << TextSize << "\n";

	LocalFree(TextSize);

The error says (The system cannot find the path specified).
I use a variable called: LPSTR fileName = "";

This is my open code:

LPSTR tmp_file = OpenDlg(hwnd, hEdit);
if (tmp_file != NULL || tmp_file != "")
{
    fileName = tmp_file;
    OpenText(hEdit, fileName);
}

The functions used in the code and the code itself works fine.
This is the save code:

if (isSaved == false) {
                             if (fileName != "") {
                                 if (!SaveText(hEdit, fileName))
                                 {
                                     error("The file could not be saved.");
                                 }
                             } else {
                                 SendMessage(hwnd, WM_COMMAND, CTRL_MENU_FILE_SAVEAS, 0);
                             }
                         }

The SaveText function is returning FALSE due to the INVALID_HANDLE_VALUE.

Why is the path not being stored right in my variable?
Using LPSTR fileName[MAX_PATH]; does not work, because it is incompatible with the path string I try to assign it.

The error says (The system cannot find the path specified).
I use a variable called: LPSTR fileName = "";

This is my open code:

LPSTR tmp_file = OpenDlg(hwnd, hEdit);
if (tmp_file != NULL || tmp_file != "")
{
    fileName = tmp_file;
    OpenText(hEdit, fileName);
}

The functions used in the code and the code itself works fine.
This is the save code:

if (isSaved == false) {
                             if (fileName != "") {
                                 if (!SaveText(hEdit, fileName))
                                 {
                                     error("The file could not be saved.");
                                 }
                             } else {
                                 SendMessage(hwnd, WM_COMMAND, CTRL_MENU_FILE_SAVEAS, 0);
                             }
                         }

The SaveText function is returning FALSE due to the INVALID_HANDLE_VALUE.

Why is the path not being stored right in my variable?
Using LPSTR fileName[MAX_PATH]; does not work, because it is incompatible with the path string I try to assign it.

What is the path you're trying to save too? (I mean the absolute path) is it somewhere like Program Files or elsewhere where elevated privileges are required from the caller? As that ends up with that error even if you know for sure that path exists. The thing is when you 1st use it to say create/open the file, it will appear to do it, the next time you try to use the handle however is when you'll get the error about the handle. You could try to test for the invalid handle immediately after the open code, for example

LPSTR tmp_file = OpenDlg(hwnd, hEdit);
if (tmp_file != NULL || tmp_file != "")
{
    fileName = tmp_file;
    OpenText(hEdit, fileName);
}
if (hEdit == INVALID_HANDLE_VALUE)
//handle error ("Handle is invalid")

Try that & see if it triggers it there immediately after, as the problem looks as though it's more during the original attempt to get the handle that something is going wrong.

What is the path you're trying to save too? (I mean the absolute path) is it somewhere like Program Files or elsewhere where elevated privileges are required from the caller? As that ends up with that error even if you know for sure that path exists. The thing is when you 1st use it to say create/open the file, it will appear to do it, the next time you try to use the handle however is when you'll get the error about the handle. You could try to test for the invalid handle immediately after the open code, for example

LPSTR tmp_file = OpenDlg(hwnd, hEdit);
if (tmp_file != NULL || tmp_file != "")
{
    fileName = tmp_file;
    OpenText(hEdit, fileName);
}
if (hEdit == INVALID_HANDLE_VALUE)
//handle error ("Handle is invalid")

Try that & see if it triggers it there immediately after, as the problem looks as though it's more during the original attempt to get the handle that something is going wrong.

Okay, I will check the handle immediatley after. But that is the open code, which works fine.
Also, I don't assign an absolute value to it, the user chooses the file.

I always choose: .../Documents/helloworld.txt
Which does actually exist because it is visible in the dialog.
There is nothing wrong with the open code. The text shows in the edit control fine.

Also, hEdit is not the file handle, it is the Edit Control

EDIT: Okay, I can't try to check it immediatley because the file handle is in include.h and I need to check it in main.cpp in order to do what you are telling me.

Okay, I will check the handle immediatley after. But that is the open code, which works fine.
Also, I don't assign an absolute value to it, the user chooses the file.

I always choose: .../Documents/helloworld.txt
Which does actually exist because it is visible in the dialog.
There is nothing wrong with the open code. The text shows in the edit control fine.

Also, hEdit is not the file handle, it is the Edit Control

Well it's misleading then, I treated it as the handle because it had a h before Edit like Microsofts convention of handles. Try an absolute path just to see if it does work or doesn't work still as expected. (just to see, because if it does work then you have a new lead on what the problem is, sure worth trying before hours of debug time)

With the handle testing I mainly just meant test it's state just after you 1st attempt to retrieve the handle to see if the problem is with not where you think. (in this case it would be before that test & not with the save code. As I get the idea it's more likely that the problem lay where you are retrieving the handle)

Alright I've just read your edit... How is it declared & when is the 1st time it attempts to retrieve a valid handle, (or atleast the time it attempts to retrieve a handle before you use it to save the file) can you track that down? (or post the code) As that is probably the best time to test the state, the idea is finding out where the problem is, I'm more wondering if it's before you try to use the handle like back when it tries to retrieve it, or not, as determining when it's happening is usually a good key to fixing it. I'm also pretty tired, up all night myself so excuse the rambling & the mess of text I tend to write at this time. ;)

Okay, here is a link to a zip file containing my 3 source files, and the exe with the problem. Because it would take too much time to explain where and how it is defined. And if I were to post the code it would be way too long.

Don't worry, the exe is not bad enough to crash your computer, just itself, but if you are still conserned you can look at the source before you run it.

The file "include.h" is the most important, it is the file containing the function that returns FALSE due to the INVALID_HANDLE_VALUE.

Here is the link to the source: RelikSCE.zip - 169.8 Kb

Okay, here is a link to a zip file containing my 3 source files, and the exe with the problem. Because it would take too much time to explain where and how it is defined. And if I were to post the code it would be way too long.

Don't worry, the exe is not bad enough to crash your computer, just itself, but if you are still conserned you can look at the source before you run it.

The file "include.h" is the most important, it is the file containing the function that returns FALSE due to the INVALID_HANDLE_VALUE.

Here is the link to the source: RelikSCE.zip - 169.8 Kb

Alright thanks, you know so much actual code (implementation) shouldn't really go in a header but I'm not about to go into that :D Anyway when I click Save As & put in an absolute path (C:\Users\<Username>\Desktop, the file saves fine as it should.

You will have to excuse all the former talk about where the handle were 1st retrieved as it has just occured to me that due to being up all night I weren't thinking straight & that has nothing to do with it since the handle is obtained when attempting to save the file & the problem lay within fileName (obviously) which would be the path, by the looks of it anyway, so yea please excuse me going off the rails there! :)

I'm just looking at it now, can see the SaveDlg, the text is put into SaveFileDialog Save; & returned is Save.File(); so I'm just going to look for how that connects & all, but as said an absolute (full directory path) seems to work. So a way round this could be to default a path & anything put into the dialog box would get appended onto it, of course it'd need the proper checking to ensure valid filename & all but it can be done. I'm just going to go & have a look at Save.File() & how it eventually gets to SaveText(HWND, LPCTSTR). (Just to see)

Just so you know, the SaveAs works perfect, it is just the Save that is the problem.

Just so you know, the SaveAs works perfect, it is just the Save that is the problem.

Ah alright, thanks for letting me know I were focusing more on the save as. I just used save & it still works with an absolute path. (In that if choose the full path to the desktop it will still write, any paths that the program doesn't have privilege to save at (for example Program Files, or similar, then it won't work until you've made the program prompt for higher privileges) It seems like the easiest (maybe best, maybe not) way to get around it is to default to a specific path like desktop or documents that is verified to be there. What exactly are you wanting the save to do? I mean obviously you'll want it to save & it seems like the only problem is the actually path defaulting.

Edit: It seems that after you've set an absolute path to save the 1st time, for example C:\Users\<Username>\Desktop, even if you close the program & go back into it, every subsequent save will save to that directory & is essentially working as it should. The only problem comes in with the invalid handle is when you cancel, or the 1st time you save you don't give it an absolute path.

The save is supposed to save the changes to the file if one is already open. If one is not, it will send the command message for SaveAs to prompt a dialog.

I have made a program like this before, and I have never needed any higher priviledge to save in Documents. It has always worked before.

My guess is that the fileName variable (LPSTR fileName = "") is not getting the value, but I am unsure. Because when I use tmp_file for the SaveAs, it seems to work. Also, I am using the same file writing function for Save as I am SaveAs. So the handles are exactly the same, so if it is invalid, the SaveAs should report the same error, but it does not.

So therefor the error cannot be in "SaveText()", it must be in the WM_COMMAND case for CTRL_MENU_FILE_SAVE.

And as to why that is I am still completely clueless.

The save is supposed to save the changes to the file if one is already open. If one is not, it will send the command message for SaveAs to prompt a dialog.

I have made a program like this before, and I have never needed any higher priviledge to save in Documents. It has always worked before.

My guess is that the fileName variable (LPSTR fileName = "") is not getting the value, but I am unsure. Because when I use tmp_file for the SaveAs, it seems to work. Also, I am using the same file writing function for Save as I am SaveAs. So the handles are exactly the same, so if it is invalid, the SaveAs should report the same error, but it does not.

So therefor the error cannot be in "SaveText()", it must be in the WM_COMMAND case for CTRL_MENU_FILE_SAVE.

And as to why that is I am still completely clueless.

Alright, I think I see where you're getting at.

So fileName = "", in the Window Procedure it checks if it is "" or not it sends a message for CTRL_MENU_SAVEAS, which calls the function SaveDlg expecting a LPSTR returned. Save Dialog returns the value put into the textbox via Save.File(); Which implementation is in dlgs.h

char* SaveFileDialog::File(void)
{
    if(Opened)
	{
        if(Success)
	      return FileName;
	    else
	    {
	        if(ShowErrors == true)
		    {
		        MessageBox(_Parent, "An error occured or the operation was canceled!", "ERROR", MB_OK | MB_ICONERROR);
		    }
	    }
	}
}

Assuming Opened & Success are true it returns FileName which ends up returned back in the Windows Procedure in tmp_file, it then calls SaveText with the tmp_file in hand. You're right this seems like a merry go round!

I guess next it's to see if Opened & Success are both evaluating to true. Try shoving a messagebox & a few elses in the SaveFileDialog::File() function, just to see, since if either of them aren't, it'll pretty much skip rest of the function without returning anything. (might be the problem)

To which I will take leave of this problem for the moment here, since I really need some sleep now :) I would imagine someone else will be able to sort it since there are far better programmers than myself here. So good luck.

Okay, Yuicia.

But actually, Save.File() is only used in the SaveAs, which works perfect.

Save.File() is only used by SaveAs, so that has nothing to do with it.

Here is the outlook if anyone else would like to help me (which seems unlikely since only 1 other person has posted in this thread):

Open: This works, opens the file, shows the text.
SaveAs: This works, Saves the file, no errors returned.
Save: Says the file handle is invalid, even when it is the very same used in SaveAs.

Okay, Yuicia.

But actually, Save.File() is only used in the SaveAs, which works perfect.

Save.File() is only used by SaveAs, so that has nothing to do with it.

Here is the outlook if anyone else would like to help me (which seems unlikely since only 1 other person has posted in this thread):

Open: This works, opens the file, shows the text.
SaveAs: This works, Saves the file, no errors returned.
Save: Says the file handle is invalid, even when it is the very same used in SaveAs.

When you use save it checks for isSaved, if that is false then it checks for if (fileName != "") which if it is it sends a message back to Windows Procedure that is the same as if you click Save As, hence you end up with it calling SaveDlg & subsequently Save.File(); later on. (SaveDlg returns the value returned from Save.File())

I would like to note that I don't get an Invalid Handle when I run the program I only get invalid file name which once I've changed to a full path, filename & extention saves just fine even with save. (since it calls save as) if I open a file & click save then I get an error about the file name, directory name or volume label has incorrect syntax & can't be saved. I think that is generated by GetLastError() you'll have to let me know if comparing it with strlen or similar sorts the error, as it may just be mistaken comparison, it usually is something small, silly, easy to miss.

Oh, Yiucia.

This thread is now solved, I decided to completely re-write my save, new, open, and SaveAs code. It was a pain in the ass but it helped. And then when you and ArkM answered my other question, it solved the rest of this one. Thanks again, and for your interest in this question.

Oh, Yiucia.

This thread is now solved, I decided to completely re-write my save, new, open, and SaveAs code. It was a pain in the ass but it helped. And then when you and ArkM answered my other question, it solved the rest of this one. Thanks again, and for your interest in this question.

I were going to mention that I would have re-wrote it all myself so I knew what were going on, then erased that part & added the last sentence instead. Glad to hear it's been solved. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.