Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Mar 10th, 2006, 8:11 AM   #1
Chesso
Newbie
 
Join Date: Mar 2006
Posts: 7
Rep Power: 0 Chesso is on a distinguished road
Problem with GetOpenFileName buffer too small.

I have written a DLL for a Delphi application I am making and decided to have the Open/Save dialog
functionality within an external DLL instead of inside the application.

The problem is I have to hard code the buffer which makes the DLL much larger then it should be.

I have read on MSDN about this problem but it really does not help as I am not too proficient with C++ in
general as I only use it when I need it. I have found plenty of article about this issue but they only explain
how to solve it using MFC with VS. I am however using Dev-CPP enviroment.

Here is the function source:

std::string OpenSaveDialog(int Open, char* InitDir)
{
 OPENFILENAME ofn;
 char szFileName[21000] = "";
 string FData("");
    
 ZeroMemory(&ofn, sizeof(OPENFILENAME));
 ofn.lStructSize = sizeof(OPENFILENAME);
 ofn.hwndOwner = NULL;
 ofn.lpstrFile = szFileName;
 ofn.nMaxFile = 21000;
 
 switch(Open)
 {
  case 0: break;
  case 1:
    ofn.lpstrFilter = "All Supported Files\0*.mp3;*.mp2;*.wav;*.wma;*.mid;*.ogg\0";
    ofn.lpstrInitialDir = InitDir;
    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT;
    
    if (GetOpenFileName(&ofn))
    {
     int len = strlen(ofn.lpstrFile);
     
     if( ofn.lpstrFile[len + 1] == 0) { return ofn.lpstrFile; } // If single file was selected.
     else {
     // This is the directory.
      FData = ofn.lpstrFile;
     
      ofn.lpstrFile += len + 1;
      while(ofn.lpstrFile[0]) {
     
     // This will contain the current file name from multiple selection.
      FData = FData + "|" + ofn.lpstrFile;      
      
      // Find next name
      len = strlen(ofn.lpstrFile);
      ofn.lpstrFile += len + 1;
      } 
       return FData;                        
     }
    }
    else { return "CANCEL"; }
  break;
  case 2: 
    ofn.lpstrFilter = "All Supported Files\0*.sm3l;*.sm3;*.m3u;*.pls\0";
    ofn.lpstrInitialDir = InitDir;
    ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
    ofn.lpstrDefExt = "sm3l";
    
    if (GetOpenFileName(&ofn)) { return ofn.lpstrFile; }
    else { return "CANCEL"; }
  break;  
  case 3:
    ofn.lpstrFilter = "SM3 format\0*.sm3\0M3U Format\0*.m3u\0PLS Format\0*.pls\0";
    ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
    ofn.lpstrDefExt = "sm3l";
    
    if (GetSaveFileName(&ofn)) { return ofn.lpstrFile; }
    else { return "CANCEL"; }                                   
 }
}

Does anyone know how to solve this issue? From what I read on MSDN I need some sort of callback function to resize the buffer if necessary and read something about calling it twice.....
Chesso is offline   Reply With Quote
Old Mar 10th, 2006, 9:00 AM   #2
nnxion
Programming Guru
 
nnxion's Avatar
 
Join Date: Jun 2005
Location: elemental plane
Posts: 1,429
Rep Power: 5 nnxion is on a distinguished road
Quote:
Originally Posted by MSDN
nMaxFile
Specifies the size, in TCHARs, of the buffer pointed to by lpstrFile. For the ANSI version, this is the number of bytes; for the Unicode version, this is the number of characters. The buffer must be large enough to store the path and file name string or strings, including the terminating NULL character. The GetOpenFileName and GetSaveFileName functions return FALSE if the buffer is too small to contain the file information. The buffer should be at least 256 characters long.
Why in the world use 21000? It says at least 256, but the MAX_PATH (on Windows XP) is 260. Why not make it that.

Or why not increase the size of the buffer (using the keyword new) while the GetOpenFileName function returns FALSE. You will have to check what error returns, you can do so with the CommDlgExtendedError function, you are looking for the FNERR_BUFFERTOOSMALL error code.
__________________
"Employ your time in improving yourself by other men's writings, so that you shall gain easily what others have labored hard for."
-- Socrates
nnxion is offline   Reply With Quote
Old Mar 10th, 2006, 3:47 PM   #3
Chesso
Newbie
 
Join Date: Mar 2006
Posts: 7
Rep Power: 0 Chesso is on a distinguished road
Why 21000? because it's just long enough for 100 files each with a character length of 100 plus the length of the directory and any additional spacing or added characters by me for easier parsing.

I already know I get the buffer to small error, It doesn't need any checking.
Chesso is offline   Reply With Quote
Old Mar 10th, 2006, 4:40 PM   #4
nnxion
Programming Guru
 
nnxion's Avatar
 
Join Date: Jun 2005
Location: elemental plane
Posts: 1,429
Rep Power: 5 nnxion is on a distinguished road
Sorry, I missed the multiple files part. Just increase the size of the buffer by catching the CDN_SELCHANGE Notification, which is received by your OFNHookProc hook procedure. Easy as Dell.
__________________
"Employ your time in improving yourself by other men's writings, so that you shall gain easily what others have labored hard for."
-- Socrates
nnxion is offline   Reply With Quote
Old Mar 10th, 2006, 4:46 PM   #5
Chesso
Newbie
 
Join Date: Mar 2006
Posts: 7
Rep Power: 0 Chesso is on a distinguished road
Sorry to be bothersome but if you have the time to make up an example for me it would be greatly appreciated. I'm used to handling all this stuff in Delphi and there's still quite a bit I haven't picked up yet.
Chesso is offline   Reply With Quote
Old Mar 11th, 2006, 4:19 AM   #6
nnxion
Programming Guru
 
nnxion's Avatar
 
Join Date: Jun 2005
Location: elemental plane
Posts: 1,429
Rep Power: 5 nnxion is on a distinguished road
Well I don't know if this works as I haven't tested fed it to the compiler and never done it before, but here goes anyway:
std::string OpenSaveDialog(int Open, char* InitDir)
{
	OPENFILENAME ofn;
	char * szFileName = NULL;
	string FData("");

	ZeroMemory(&ofn, sizeof(OPENFILENAME));
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = NULL;
	ofn.lpstrFile = szFileName;
	ofn.nMaxFile = 21000;
	ofn.lpfnHook = OFNHookProc;

	switch(Open)
	{
		case 0:
		break;

		case 1:
			ofn.lpstrFilter = "All Supported Files\0*.mp3;*.mp2;*.wav;*.wma;*.mid;*.ogg\0";
			ofn.lpstrInitialDir = InitDir;
			ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT;

			if (GetOpenFileName(&ofn))
			{
				int len = strlen(ofn.lpstrFile);

				if( ofn.lpstrFile[len + 1] == 0)
				{
					return ofn.lpstrFile;
				} // If single file was selected.

				else
				{
					// This is the directory.
					FData = ofn.lpstrFile;

					ofn.lpstrFile += len + 1;
					while(ofn.lpstrFile[0])
					{
						// This will contain the current file name from multiple selection.
						FData = FData + "|" + ofn.lpstrFile;

						// Find next name
						len = strlen(ofn.lpstrFile);
						ofn.lpstrFile += len + 1;
					}
					return FData;
				}
			}

			else
			{
				return "CANCEL";
			}
		break;

		case 2:
			ofn.lpstrFilter = "All Supported Files\0*.sm3l;*.sm3;*.m3u;*.pls\0";
			ofn.lpstrInitialDir = InitDir;
			ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
			ofn.lpstrDefExt = "sm3l";

			if(GetOpenFileName(&ofn))
			{
				return ofn.lpstrFile;
			}

			else
			{
				return "CANCEL";
			}
		break;

		case 3:
			ofn.lpstrFilter = "SM3 format\0*.sm3\0M3U Format\0*.m3u\0PLS Format\0*.pls\0";
			ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
			ofn.lpstrDefExt = "sm3l";

			if (GetSaveFileName(&ofn)) { return ofn.lpstrFile; }

			else
			{
				return "CANCEL";
			}
		break;
	}
}

UINT CALLBACK OFNHookProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	UINT neededSize;
	switch(message)
	{
		case WM_INITDIALOG:
			if(!SetProp(GetParent(hDlg), "OFN", (void *)lParam))
			{
			  MessageBox(NULL, "SET PRop Failed", "ERROR", MB_OK);
			}
		break;

		case WM_NOTIFY:
			OFNOTIFY* lpof = (OFNOTIFY*)lParam;

			if(lpof->hdr.code == CDN_SELCHANGE)
			{
				neededSize = CommDlg_OpenSave_GetSpec(GetParent(hDlg), NULL, 0);
				neededSize += MAX_PATH;

				pOfn = (LPOPENFILENAME)GetProp(GetParent(hDlg), "OFN");
				if(pOfn->nMaxFile < neededSize)
				{
					if(pOfn->lpstrFile == NULL)
					{
						pOfn->lpstrFile = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, neededSize);
					}

					else
					{
						pOfn->lpstrFile = (LPTSTR)HeapReAlloc(GetProcessHeap(), 0, pOfn->lpstrFile, neededSize);
					}

					if(pOfn->lpstrFile != NULL)
					{
							pOfn->lpstrFile[0] = '\0';
							pOfn->nMaxFile  = neededSize;
					}
				}
			}
		break;

		case WM_DESTROY:
			RemoveProp(GetParent(hDlg), "OFN");
		break;
		}
	}
	return 0;
}
Hopes that helps you.
__________________
"Employ your time in improving yourself by other men's writings, so that you shall gain easily what others have labored hard for."
-- Socrates
nnxion is offline   Reply With Quote
Old Mar 11th, 2006, 5:08 AM   #7
Chesso
Newbie
 
Join Date: Mar 2006
Posts: 7
Rep Power: 0 Chesso is on a distinguished road
Dev-CPP is giving me quite a few compile errors.....

OFNHookProc Undeclared(first use this function)
`pOfn` undeclared(first use this function)
jump to case label
crosses initalization of `OFNOTIFY*lpof`

Err yeah there's more but Iv'e never had alot of these errors so i'm clueless.

EDIT: Putting the OFNHookProc above my function gets rid of a couple of errors but most remain.
Chesso is offline   Reply With Quote
Old Mar 11th, 2006, 6:58 AM   #8
Cache
Hobbyist
 
Join Date: Sep 2005
Posts: 261
Rep Power: 4 Cache is on a distinguished road
Quote:
Originally Posted by Chesso
Putting the OFNHookProc above my function gets rid of a couple of errors but most remain.
Or you could put the function prototype at the top of the file.

Quote:
`pOfn` undeclared(first use this function)
The value being assigned to pOfn is cast as type LPOPENFILENAME. So I assume the following will solve that issue:
LPOPENFILENAME pOfn = (LPOPENFILENAME)GetProp(GetParent(hDlg), "OFN");

Quote:
jump to case label
crosses initalization of `OFNOTIFY*lpof`
The WM_NOTIFY case in OFNHookProc initializes new variables, so it should be enclosed in curly braces. There is also a superfluous brace.
Cache is offline   Reply With Quote
Old Mar 11th, 2006, 9:47 AM   #9
Chesso
Newbie
 
Join Date: Mar 2006
Posts: 7
Rep Power: 0 Chesso is on a distinguished road
I still can't seem to get it to compile without complaining about alot of stuff.

This is a DLL not a normal Win32 application, there's no windows or anything like that created so the DLL doesn't really have a handle I suppose....

The two functions in this DLL aren't defined at the top of the file or anything, there just in my .h file for exporting.

And i'm just going to say this again but the only experience I have with C++ is writing extremely basic DLL's and a base Win32 GUI. Everything else iv'e done in either Visual Basic or for the last year and a half Borland Delphi.
Chesso is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 3:13 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC