Hello again everyone, Im having trouble with this function for saving a file from a richedit control within a child window in my application. I have put in extra messageboxes etc to helo me find the error. when I implement this function with valid parameters I recieve the "Invalid handle value" message box so I gathered that there is something wrong creating the handle to the file. However when I use this function for the first time for example when i create a file and save plain text into it, the function creats the file and writes to it successfully, but when i try again to save into this same file I recieve the "Invalid Handle Value" message. Here is the code for the function...

BOOL SaveFile(HWND owner,HWND hEdit, LPCTSTR pszFileName)
{
	HANDLE hFile;
	BOOL bSuccess = FALSE;
	
	MessageBox(owner,pszFileName,0,0); // Testing if the parameter from pszFileName has been recieved

    // Create the file (overwrite existing files) and assign the handle to hFile
	hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL,
		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
		
	//########## RETURNS INVALID HANDLE VALUE ############
	//###### MAYBE PROBLEM WITH CREATING THE FILE ########
	//####################################################
	
    // If the handle to the file has been created sucessfully
	if(hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwTextLength;
        // Get text length of edit control within child window for allocating memory
		dwTextLength = GetWindowTextLength(hEdit);

		// If there is no text then there is nothing to write to the file that has been created
		if(dwTextLength > 0)
		{
			LPSTR pszText;
			// Amount of me mory to be allocated = textsize + 1 for null terminator
			DWORD dwBufferSize = dwTextLength + 1;

            // Allocate memory for the text
			pszText = GlobalAlloc(GPTR, dwBufferSize);
			if(pszText != NULL)
			{   
                // Get the Text to be saved to the file fromt he edit control
			    // within the child window.
				if(GetWindowText(hEdit, pszText, dwBufferSize))
				{
					DWORD dwWritten;
					
                    // Write the text to the file
					if(WriteFile(hFile, pszText, dwTextLength, &dwWritten, NULL))
						bSuccess = TRUE;
					
                    //Set Title of child window to the filename	
					SetWindowText(owner, pszFileName);
					MessageBox(owner,"File saved",0,0); // Using to find error
				}
				else
				{
                 MessageBox(owner,"Could not retrieve text",0,MB_ICONERROR); // Using to find error
                }
                // Free memory allocated for text
				GlobalFree(pszText); 
			}
			else
			{
             MessageBox(owner,"Could not allocate memory",0,MB_ICONERROR); // Using to find error
            }
		}
		else
		{
         MessageBox(owner,"No text",0,0);// Using to find error
        }
        // Close the handle to the file if it exists
		CloseHandle(hFile);
	}
	else
	{
         MessageBox(owner,"Invalid handle value",0,MB_ICONERROR); // Using to find error
    }
	return bSuccess;
}

Thanks in advance...

Why dont you use the GetLastError Function to get the detailed error number? Then you will be able to find why it is failing.

Oh Thanks, I have found out the error code...32: File cannot be accessed because it is being use by another process. Could this mean I have forgotten to close a handle to a file somewhere? I have checked around for this and still cannot find out why.

Just as I thought...Most probably you have opened it using another application. Since it is a Rich-Edit Control, my best guess is that you have opened it using MS-Word and trying to overwrite it while it is open..

That is what I thought as it stated another "Process" ie another application, but it is only being used by my application. The thing is...when i first use the function to save the file it works perfectly, but then when make more changes to the richedit control text and attempt to save it again it does not work...I thought this may be due to forgetting to close a handle to the file somewhere but i cant find any errors.

If you are running Norton Antivirus turn it off during development. Sometimes it causes problems like that. Don't forget to turn it back on when you are done.

In my application I have it so that when i click a save button on the toolbar or menu item it will check to see if the file exists and then decide whether to save the file using the filename from the child window title or create a save as dialog box. The savefileas function creates the dialog box using the OPENFILENAME structure and calling GetSaveFileName, from which i then pass the file specified by the user into my SaveFile function. When I save the file as.. it seems to work every time however, when i call the savefile function say when the file exists it gives this error...ie

//SaveFile Function...
BOOL SaveFile()
{
//Processing...
}

//SaveFileAs function
BOOL SaveFileAs()
{
 OPENFILENAME ofn;
 //initialise the ofn structure
 char szFile[MAX_PATH];
 ofn.lpstrFile = szFile; 
 //....Initialise rest of structure...
 //Pass the structure into GetSaveFileName
 
 //Then call SaveFile function with the filename specified by the user

 SaveFile(....szFile);

}

Therefore this leads me to think that when i am passing the parameters into savefile() when the file exists, something is going wrong...but when the parameters are passed through the saveas dialog box the parameters are passwed correctly. It is confusing...any suggestions ?

It is difficult to point out the cause from here. It will be better if you set a breakpoint just after the call for the GetSaveFileName function and see if all the fields, especially the file name of the OPENFILENAME structure, are filled properly. You better use the ofn.Flags = OFN_OVERWRITEPROMPT; Statement before the GetSaveFileName call if you are not doing so already.

Yes I have set the OPENFILENAME structure correctly...It is the process of saving the file using the text from the child window title that does not work correctly...The procedure to save the file as however works fine. The savefileas procedure uses the savefile() function within it so therefore i dont think there is anything wrong with the savefile() function itself...rather the way I am passing parameters to it when not using the saveas procedure.

Iam running out of options here. I also think that the SaveFile function is okay. If the filename is correctly returned from GetSaveFileName, the SaveFile function should behave identically in both cases. This is a long shot but try,

char szFile[MAX_PATH] = "";
 ofn.lpstrFile = szFile; 
//....Initialise rest of structure...
 //Pass the structure into GetSaveFileName

If that does not work, I advice you to post the full code of the SaveFile and SaveFileAs functions.

Ok I will post all of the code i have been using for saving the files...
This is the WM_COMMAND Message processing for saving files for the MDIClient...

case CM_FILE_SAVE:
                 {
                 LPSTR WindowText;                              
                 
                 DWORD dwTextLength;
                 dwTextLength = GetWindowTextLength(hwnd);
                 
                 if (dwTextLength > 0)
                 {
                   DWORD dwBufferSize;
                   dwBufferSize = dwTextLength + 1;

                   WindowText = GlobalAlloc(GPTR, dwBufferSize);

                   if(WindowText != NULL)
                   {
                     if ( ! GetWindowText(hwnd, WindowText, dwBufferSize) )
                     {
                        MessageBox(hwnd,"Error Getting window text",0,MB_ICONERROR);  
                     }
                   }
                   else
                   {
                     MessageBox(hwnd,"Error allocating memory for text",0,MB_ICONERROR);    
                   }
                   
                 }
                 else
                 {
                   MessageBox(hwnd,"No Window text",0,MB_ICONERROR);    
                 }
                    
                 // Text of the child window is retrieved correctly !!
                 HANDLE hFile;
                 
                 hFile = CreateFile(WindowText, GENERIC_READ, FILE_SHARE_READ, NULL,
                 OPEN_EXISTING, 0, NULL);
                 
                 if (hFile != INVALID_HANDLE_VALUE)
                 {  
                    if ( ! SaveFile(hwnd,GetDlgItem(hwnd,IDC_CHILD_EDIT),WindowText) )     
                    {
                       MessageBox(hwnd,"Could not save file",0,MB_ICONERROR);     
                    }          
                 }
                 else 
                 {
                    if ( ! SaveFileAs(hwnd,GetDlgItem(hwnd,IDC_CHILD_EDIT)))
                    {
                       MessageBox(hwnd,"Could not save file",0,MB_ICONEXCLAMATION);     
                    }     
                 }
                 CloseHandle(hFile);
                     SendDlgItemMessage(hwnd,IDC_CHILD_EDIT,EM_SETMODIFY,FALSE,0);                     
                 }
            break;
            case CM_FILE_SAVEAS:
                 {
                     SaveFileAs(hwnd,GetDlgItem(hwnd,IDC_CHILD_EDIT));
                     SendDlgItemMessage(hwnd,IDC_CHILD_EDIT,EM_SETMODIFY,FALSE,0);
                 }
             break;

This is the SaveFile function...

BOOL SaveFile(HWND owner,HWND hEdit, LPCTSTR pszFileName)
{
	HANDLE hFile;
	BOOL bSuccess = FALSE;
	
	MessageBox(owner,pszFileName,0,0); // Testing if the parameter from pszFileName has been recieved

    // Create the file (overwrite existing files) and assign the handle to hFile
	hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL,
		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
		
	//########## RETURNS INVALID HANDLE VALUE ############
	//###### MAYBE PROBLEM WITH CREATING THE FILE ########
	//####################################################
	
    // If the handle to the file has been created sucessfully
	if(hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwTextLength;
        // Get text length of edit control within child window for allocating memory
		dwTextLength = GetWindowTextLength(hEdit);

		// If there is no text then there is nothing to write to the file that has been created
		if(dwTextLength > 0)
		{
			LPSTR pszText;
			// Amount of me mory to be allocated = textsize + 1 for null terminator
			DWORD dwBufferSize = dwTextLength + 1;

            // Allocate memory for the text
			pszText = GlobalAlloc(GPTR, dwBufferSize);
			if(pszText != NULL)
			{   
                // Get the Text to be saved to the file fromt he edit control
			    // within the child window.
				if(GetWindowText(hEdit, pszText, dwBufferSize))
				{
					DWORD dwWritten;
					
                    // Write the text to the file
					if(WriteFile(hFile, pszText, dwTextLength, &dwWritten, NULL))
						bSuccess = TRUE;
					
                    //Set Title of child window to the filename	
					SetWindowText(owner, pszFileName);
					MessageBox(owner,"File saved",0,0); // Using to find error
				}
				else
				{
                 MessageBox(owner,"Could not retrieve text",0,MB_ICONERROR); // Using to find error
                }
                // Free memory allocated for text
				GlobalFree(pszText); 
			}
			else
			{
             MessageBox(owner,"Could not allocate memory",0,MB_ICONERROR); // Using to find error
            }
		}
		else
		{
         MessageBox(owner,"No text",0,0);// Using to find error
        }
        // Close the handle to the file if it exists
		CloseHandle(hFile);
	}
	else
	{
         ShowLastError ( ) //Function calls GetLastError and then displays the error in a MessageBox
         MessageBox(owner,"Invalid handle value",0,MB_ICONERROR); // Using to find error
    }
	return bSuccess;
}

Finally this is the SaveFileAs Function...

BOOL SaveFileAs(HWND owner,HWND hwnd)
{
                   BOOL RetVal = FALSE;
                     
                   char szFile[MAX_PATH];
                   OPENFILENAME sfn;
                   ZeroMemory(&sfn, sizeof(sfn));
                   sfn.lStructSize = sizeof(sfn);
                   sfn.hwndOwner = hwnd;
                   sfn.lpstrFile = szFile;
                   //
                   // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
                   // use the contents of szFile to initialize itself.
                   //
                   sfn.lpstrFile[0] = '\0';
                   sfn.nMaxFile = sizeof(szFile);
                   sfn.lpstrFilter = "C Source File(*.c*)\0*.c;\0C++ Source File(*.cpp*)\0*.cpp;\0C Header File(*.h*)\0*.h;\0Resource Script(*.rc*)\0*.rc;\0";
                   sfn.nFilterIndex = 1;
                   sfn.lpstrFileTitle = NULL;
                   sfn.nMaxFileTitle = 0;
                   sfn.lpstrInitialDir = NULL;
                   sfn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
                   sfn.lpstrDefExt = "c";

                   GetSaveFileName(&sfn);
                   
                   if (SaveFile(owner,hwnd,szFile))
                   {
                     RetVal = TRUE;
                   }
                   
                   return RetVal;
}

As you can see the WM_COMMAND Message for the MDIClient procedure attempts to create a handle to an existing file..not overwriting! If the file exists the handle is created successfully which is then checked further down. If the file exists, the SaveFile function is called directly, using the WindowText of the ChildWindow as the Filename parameter and if the file does not exist, the SaveFileAs function is called. This basically does what most Text Editors do, decides whether to automatically save the file using its current filename or save the file as the user specifies...

When the user chooses to SaveFileAs...or the program decides that function is to be used, it works fine...the correct dialog appears and and prompts the user to overwrite existing files etc. The SaveFileAs function as you can see calls the SaveFile function and specifies the owner window parameter, the richedit control handle parameter and the filename specified by the user. THIS WORKS FINE !

My problem however is that when the file exists already and the user clicks save, the program takes the current filename of the file from the Title of the Child window and uses this as the FileName parameter. When this method is taken the error is generated. GetLastError() shows me what I have described above that the file is being used by another process etc.

Since when the SaveFile() function is called by the SaveFileAs() function and works correctly, I dont think there can be a problem with SaveFile(). So therefore I think there is something wrong with when I am passing the parameters to SaveFile() straight from the WM_COMMAND processing of the MDI Client.

Thanks for your help...tough 1 :(

Okay. Got it. You are trying to open the same file twice.
Here are the culprits.

case CM_FILE_SAVE:
{
	//...
	HANDLE hFile;
	hFile = CreateFile( WindowText, GENERIC_READ, FILE_SHARE_READ, NULL,
				OPEN_EXISTING, 0, NULL );
	// This function is successfull only when there is a file of name WindowText.
	if ( hFile != INVALID_HANDLE_VALUE )
	{
		// YOu are here because hFile is valid. i.e the File is open.
		// Now you are calling save File. Go to the SaveFile now.
		if ( !SaveFile( hwnd, GetDlgItem( hwnd, IDC_CHILD_EDIT ), WindowText )) 
		{
			MessageBox( hwnd, "Could not save file", 0, MB_ICONERROR );
		}
	}
	else
	{
	//...
	}
}
BOOL SaveFile( HWND owner, HWND hEdit, LPCTSTR pszFileName )
{
	HANDLE hFile;

	// We are here because hFile was valid. ie a File of pszFileName is open already. But you call CreateFile again.

	// Try to create a file of name pszFileName...
	hFile = CreateFile( pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
				FILE_ATTRIBUTE_NORMAL, NULL );

	// But we had opened it before calling this function remember?
	// Therefore this hFile should be Invalid with Access Error.

	if ( hFile != INVALID_HANDLE_VALUE )
	{
		// Will not go here if the file exists...
	}
	else
	{
	}
	return bSuccess;
}

Did you get where you are going wrong? You can fix it with a crude fix like this.

case CM_FILE_SAVE:
{
	//...
	HANDLE hFile;
	hFile = CreateFile( WindowText, GENERIC_READ, FILE_SHARE_READ, NULL,
				OPEN_EXISTING, 0, NULL );
	// This function is successfull only when there is a file of name WindowText.
	if ( hFile != INVALID_HANDLE_VALUE )
	{
		// YOu are here because hFile is valid. i.e the File is open.
                // Crude Fix - Close the file :-)
                CloseHandle( hFile );
		// Now you are calling save File. Go to the SaveFile now.
		if ( !SaveFile( hwnd, GetDlgItem( hwnd, IDC_CHILD_EDIT ), WindowText )) 
		{
			MessageBox( hwnd, "Could not save file", 0, MB_ICONERROR );
		}
	}
	else
	{
	//...
	}
}
BOOL SaveFile( HWND owner, HWND hEdit, LPCTSTR pszFileName )
{
	HANDLE hFile;

	// We are here because hFile was valid. ie a File of pszFileName is open already. But you call CreateFile again.

	// Try to create a file of name pszFileName...
	hFile = CreateFile( pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
				FILE_ATTRIBUTE_NORMAL, NULL );

	// Thank god we closed the file.
	if ( hFile != INVALID_HANDLE_VALUE )
	{
		//...
	}
	else
	{
	}
	return bSuccess;
}

As I said that was a Crude Fix. Basically your design is wrong. That was why the error occured in the first place.

The Better Pseudocode will be something like this.

Global Variable FileName
On FileSave

if ( FileName not NULL )
SAve to FileName
else
Show File Save As
Assign Value for FileName
Save to FileName
Close FileName

On FileSaveAs

Show Save As Dialog
Assign value to FileName
Save To FileName
Close FileName

Haha thankyou so much...genious lol :P I didnt realise that...I thought that I wouldnt have to close the handle to the file if hFile = INVALID_HANDLE_VALUE, but i suppose it would be better to do that just to avoid errors. Anyway thanks a lot, it is very much appreciated. :)

I thought that I wouldnt have to close the handle to the file if hFile = INVALID_HANDLE_VALUE

Actually you dont have to close it if

hFile == INVALID_HANDLE_VALUE

. But in this case the condition is

if ( hFile != INVALID_HANDLE_VALUE )
{ 
...

. So you have to close it before trying to open it again.

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.