Handle multiple file selection - c++

I have the following code:
void OpenJpgFile(HWND hWnd)
{
OPENFILENAME ofn;
wchar_t szFileName[17*MAX_PATH] = L"";
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrTitle = L"Selecione as fotos que deseja adicionar...";
ofn.lpstrFilter = L"Arquivos JPEG (*.jpg)\0*.jpg\0Todos os Arquivos (*.*)\0*.*\0";
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT;
ofn.lpstrDefExt = L"jpg";
if(GetOpenFileName(&ofn))
{
//Test
MessageBox(hWnd,ofn.lpstrFileTitle,L"TESTE",NULL);
if(gpBitmap)
{
delete gpBitmap;
}
gpBitmap = new Bitmap(szFileName);
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
}
}
What I wanted to know is how can I get the name of all files the user has selected...
All I can get is the path to the folder... is there an array that keeps the file names?

Per the documentation of OFN_ALLOWMULTISELECT when OFN_EXPLORER is also specified, lpstrFile will contain the directory followed by the names of the files, separated by null characters, and terminated with two adjacent null characters. When you call new Bitmap(szFileName) you are treating szFileName incorrectly - that is you pass it to a constructor that expects a standard single-null terminated string. Instead you have to process it more carefully to read past the initial null, and probably recreate your full file paths.
This string format happens to be the same format as used for REG_MULTI_SZ so, aside from not having to worry about missing final terminators, advice related to handling values of type REG_MULTI_SZ can help you here.
Note that to be fully general, you may also have to handle cases that require a larger buffer. See GetOpenFileName() with OFN_ALLOWMULTISELECT flag set for another angle on that

Related

How to get a path to file in c++?

I am making an app with ImGUI to choose pictures. So I need to call "OPENFILENAME" to call a dialog window, and there is my code to do it:
OPENFILENAME ofn;
::memset(&ofn, 0, sizeof(ofn));
TCHAR f1[MAX_PATH];
f1[0] = 0;
ofn.lStructSize = sizeof(ofn);
ofn.nFilterIndex = 2;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFile = f1;
ofn.Flags = OFN_FILEMUSTEXIST;
if (::GetOpenFileName(&ofn) != FALSE)
{
show_path = TRUE;
}
But later I need to have a path to image, which I chose in char type and lpstrFile is a THCAR type. I found anything to make THCAR into char.
Am I doing choosing file in right way, and if yes, how can I get in usual char format a path to file?

Call to GetOpenFileNameA causes common dialog error 2

I'm trying to open a dialog box using GetOpenFileNameA. However, the dialog does not open. Instead, I get a nice CommDlgError 2. Searching Google and StackOverflow for this error did not produce any helpful results.
Confusingly, this code works on a school computer that also uses Visual Studio, albeit a different version.
Note: All variables not declared in this block of code are "global" variables that are only accessible within the main code module.
void GetInputFile()
{
char szFileNameIN[MAX_PATH];
char szFileNameOUT[MAX_PATH];
// get the input file name
OPENFILENAME ofn;
ZeroMemory(&fInputPath, sizeof(fInputPath));
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFilter = LPWSTR("Any File\0*.*\0");
ofn.lpstrFile = LPWSTR(fInputPath);
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = LPWSTR(szFileNameIN);
ofn.nMaxFileTitle = MAX_PATH;
ofn.lpstrTitle = LPWSTR("Select an input File");
ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST;
if (GetOpenFileNameA(LPOPENFILENAMEA(&ofn))) // user selected an input file
{
}
else {
// Get error
TCHAR error[MAX_LOADSTRING];
wsprintf(error,TEXT("%i"),CommDlgExtendedError());
MessageBox(NULL,error,TEXT("ERROR"),MB_OK);
}
}
Those awful (LPWSTR) casts tell me that you are compiling with UNICODE defined, so the OPENFILENAME struct you are using is actually OPENFILENAMEW; given that you are using GetOpenFileNameA, you have to use OPENFILENAMEA (or use straight GetOpenFileName with wide strings).
(and remember that, as a rule of thumb, if you have to cast pointers to/from anything different than void * and similar, you are probably doing something wrong; adding pointer casts will only silence the compiler, not make the error go away)
You are using the TCHAR version of OPENFILENAME. Since you are assigning Unicode string pointers to its fields, that means your project is being compiled with UNICODE defined, so TCHAR maps to wchar_t and OPENFILENAME maps to OPENFILENAMEW. But you are using ANSI character buffers and the ANSI version of GetOpenFileName(), and using incorrect type-casts all over the place.
So get rid of all the type-casts, and then either:
use proper TCHAR types and APIs for everything:
void GetInputFile()
{
TCHAR szFileNameIN[MAX_PATH];
TCHAR szFileNameOUT[MAX_PATH];
// get the input file name
OPENFILENAME ofn;
ZeroMemory(&fInputPath, sizeof(fInputPath));
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFilter = TEXT("Any File\0*.*\0");
ofn.lpstrFile = fInputPath; // must be TCHAR[]...
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = szFileNameIN;
ofn.nMaxFileTitle = MAX_PATH;
ofn.lpstrTitle = TEXT("Select an input File");
ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn)) // user selected an input file
{
}
else
{
// Get error
TCHAR error[MAX_LOADSTRING];
wsprintf(error, TEXT("%i"), CommDlgExtendedError());
MessageBox(NULL, error, TEXT("ERROR"), MB_OK);
}
}
use proper CHAR/WCHAR types and APIs for everything:
void GetInputFile()
{
WCHAR szFileNameIN[MAX_PATH];
WCHAR szFileNameOUT[MAX_PATH];
// get the input file name
OPENFILENAMEW ofn;
ZeroMemory(&fInputPath, sizeof(fInputPath));
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFilter = L"Any File\0*.*\0";
ofn.lpstrFile = fInputPath; // must be WCHAR[]...
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = szFileNameIN;
ofn.nMaxFileTitle = MAX_PATH;
ofn.lpstrTitle = L"Select an input File";
ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST;
if (GetOpenFileNameW(&ofn)) // user selected an input file
{
}
else
{
// Get error
WCHAR error[MAX_LOADSTRING];
wsprintfW(error, L"%i", CommDlgExtendedError());
MessageBoxW(NULL, error, L"ERROR", MB_OK);
}
}
void GetInputFile()
{
CHAR szFileNameIN[MAX_PATH];
CHAR szFileNameOUT[MAX_PATH];
// get the input file name
OPENFILENAMEA ofn;
ZeroMemory(&fInputPath, sizeof(fInputPath));
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFilter = "Any File\0*.*\0";
ofn.lpstrFile = fInputPath; // must be CHAR[]...
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = szFileNameIN;
ofn.nMaxFileTitle = MAX_PATH;
ofn.lpstrTitle = "Select an input File";
ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST;
if (GetOpenFileNameA(&ofn)) // user selected an input file
{
}
else
{
// Get error
CHAR error[MAX_LOADSTRING];
wsprintfA(error, "%i", CommDlgExtendedError());
MessageBoxA(NULL, error, "ERROR", MB_OK);
}
}

winapi openfiledialog c++

I use mingw, c++
I would like to open multiple files, something like this:
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = "TXT\0"
"*.txt\0";
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT;
ofn.lpstrDefExt = "txt";
But how can I get the filenameS? If I check the szFileName variable, it only contains the folder name.
From the documentation:
If the user selects more than one file, the lpstrFile buffer returns the path to the current directory followed by the file names of the selected files. The nFileOffset member is the offset, in bytes or characters, to the first file name
the directory and file name strings are NULL separated, with an extra NULL character after the last file name.
From your question:
If I check the szFileName variable, it only contains the folder name.
Keep checking one character past the terminating '\0'.
Each time the following character isn't another '\0', that's the start of a new filename.

GetOpenFileName and system function call run time errors c++ win32 api

I've been working on a simple windows program using Visual C++ 2010 express on a 64bit Windows 7 machine. So far I have simple menu with and an editable text area. I'm trying to allow the user select a media file (movie or music file) and play it using the default program.
When the user selects from the menu File->Play->File from Computer it runs the following code.
case ID_PLAY_FFC:
{
system("cd c:/windows/system32/&&cmd.exe");
FileOpen(hWnd);
system("cd c:/windows/system32/&&cmd.exe");
}
break;
The problem is that the first system call runs as expected. The second call tells me that "cmd.exe is not recognized as an internal or external command, operable program, or batch file". I've tried placing the second system call within the File Open function and it seems to work anywhere before GetOpenFileName but not after.
The only thing I really need to get the is file path so I was wondering if any one knew how to fix this problem or a better way to accomplish this?
code for FileOpen():
void FileOpen(HWND hwnd)
{
OPENFILENAME ofn; // common dialog box structure
char szFile[MAX_PATH]; // buffer for file name MAX_PATH = 260
HANDLE hf; // file handle
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// Display the Open dialog box.
//system("cd c:/windows/system32/&&cmd.exe"); will execute here.
if (GetOpenFileName(&ofn)==TRUE)
{
//system("cd c:/windows/system32/&&cmd.exe"); but not here.
hf = CreateFile(ofn.lpstrFile,
GENERIC_READ,
0,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (hf == (HANDLE)-1)
{
MessageBox(NULL,"Could not open this file", "File I/O Error", MB_ICONSTOP);
return;
}
}
}
The GetOpenFileName() function changes the working directory and drive as part of it's operation. Your call to cd does not change the working drive and cmd.exe is still not in the working directory.
The solution depends on what exactly you're trying to do in the end, but you can specify the full path to cmd.exe (See the %COMSPEC% environment variable) and not rely on a command interpreter, or pass the OFN_NOCHANGEDIR flag to tell it not to clobber the working directory.
Note that there isn't any real reason for a (GUI) app to require a specific working path. You should fully qualify everything you can.
Calling system() starts a new process, so even if your cd commands were valid (which they are not), it would not matter because you would be changing the working directory of another process, not your app's process. To set the working directory of your app's process, use SetCurrentDirectory() instead of system(), eg:
case ID_PLAY_FFC:
{
SetCurrentDirectory(TEXT("c:/windows/system32/"));
FileOpen(hWnd);
SetCurrentDirectory(TEXT("c:/windows/system32/"));
}
break;
However, you don't need to do that manually because the OFN_NOCHANGEDIR flag of GetOpenFileName() automatically handles that internally for you. Whatever the calling process's working directory is, GetOpenFileName() will preserve it when OFN_NOCHANGEDIR is specified.
Try this:
case ID_PLAY_FFC:
{
FileOpen(hWnd);
}
break;
void FileOpen(HWND hwnd)
{
OPENFILENAME ofn; // common dialog box structure
TCHAR szFile[MAX_PATH+1]; // buffer for file name MAX_PATH = 260
// Zero out szFile so that GetOpenFileName does
// not use the contents to initialize itself.
ZeroMemory(szFile, sizeof(szFile));
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFilter = TEXT("All\0*.*\0Text\0*.TXT\0");
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
// Display the Open dialog box.
if (GetOpenFileName(&ofn)==TRUE)
{
int ret = (int) ShellExecute(
hwnd,
NULL,
ofn.lpstrFile,
NULL,
TEXT("c:/windows/system32/"),
SW_SHOWNORMAL);
if (ret <= 32)
{
MessageBox(NULL, TEXT("Could not open this file"), TEXT("File I/O Error"), MB_ICONSTOP);
return;
}
}
}

Save/Open Common Dialog boxes in win32 without MFC

How do you create the deafault Save/Open dialog boxes using pure unmanaged Win32 API ?
Following the guide here, the following code is executed when WM_CREATE message is handled in the message loop of the main window:
Ive included <Commdlg.h> also.
OPENFILENAMEA ofn;
char Buffer[300];
fill(Buffer, Buffer + 300, '\0');
ofn.lStructSize = sizeof(OPENFILENAMEA);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = Buffer;
ofn.nMaxFile = 300;
ofn.Flags = OFN_EXPLORER;
ofn.lpstrFilter = NULL;
ofn.lpstrCustomFilter = NULL;
ofn.nFilterIndex = 0;
ofn.lpstrFileTitle = NULL;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = NULL;
out << GetOpenFileNameA(&ofn) << endl;
out << Buffer << (int)CommDlgExtendedError();
However, this code gives NO output whatsoever. Help?!
the following code is executed when WM_CREATE message is handled
Look in the Output window and observe the first-chance exception notification for 0xc0000005, an AccessViolation exception. There's a backstop in the Wow64 emulator that swallows exceptions while WM_CREATE is being dispatched.
The exception is caused by not fully initializing the OPENFILENAMEA structure. Quick fix:
OPENFILENAMEA ofn = {0};
And favor displaying the dialog before calling ShowWindow() instead of the WM_CREATE message handler.
The overall idea is right, but if you are passing the handle of the window you are creating as the owner, then it is not going to be initialized yet.
For diagnostics, consider creating variables to store the API function return values and examining them in the debugger.
It is also more convenient and less error-prone to initialize the structure to zero, instead of explictely zeroing out unneeded members, like this:
OPENFILENAME ofn = { 0 };
GetOpenFileName blocks (for a while), and then returns either TRUE if the dialog was closed by 'OK', or FALSE if it was cancelled.
The actual result (the directory/file path) can be read from the OPENFILENAME structure.
from https://learn.microsoft.com/en-us/windows/win32/dlgbox/using-common-dialog-boxes#opening-a-file we get a utf-16 version of this, with some small changes of mine:
OPENFILENAME ofn = { 0 }; // common dialog box structure
WCHAR szFile[260]; // buffer for file name
HWND hwnd; // owner window
HANDLE hf; // file handle
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// Display the Open dialog box.
if (GetOpenFileName(&ofn)==TRUE)
hf = CreateFile(ofn.lpstrFile,
GENERIC_READ,
0,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);