I'm trying to use the open file dialog to allow the user of my program to select an image which will then be processed using opencv.
I have a function in which i open the dialog and try to load the image:
Mat load_image()
{
OPENFILENAME ofn; // common dialog box structure
TCHAR 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 = L"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);
char filepath[260];
wcstombs(filepath, ofn.lpstrFile, 260);
cout << filepath << endl;
Mat src = imread(filepath);
//imshow("src", src);
return src;
}
The code you see here works, opens the dialog box and allows the user to choose a file. The filepath is then converted to string (to be passed into imread). The problem occurs when I try to interact with the image src.
For example, if I uncomment the 'imshow' line, GetOpenFileName will return 0 and the dialog box doesnt even open. This happens more than not, I cant actually access the image because everything I try causes this to happen.
In order for the function to work it is called like this:
load_image();
But if I try to assign an image ie:
img = load_image();
the same problem occurs. Help! What could possibly be causing this?
As it is mentioned in the previous comment, the CreateFile method locks the image file so cv::imread() is not able to access/read its content.
Try to avoid using of CreateFile, I see no reason of using it in your code, the following code is working well:
cv::Mat load_image()
{
cv::Mat outMat;
OPENFILENAME ofn; // common dialog box structure
TCHAR szFile[260]; // buffer for file name
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = NULL;
ofn.lpstrFile = szFile;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"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)
{
char filepath[260];
wcstombs(filepath, ofn.lpstrFile, 260);
cout << filepath << endl;
outMat = cv::imread(filepath);
}
return outMat;
}
int main()
{
cv::Mat image = load_image();
cv::imshow("image", image);
cv::waitKey(-1);
return 0;
}
These are just things I notice in your code...so I don't expect this to work but maybe it will help.
imread is probably failing. You opened the file using CreateFile and locked it as a result of opening it (No Sharing Attributes. See CreateFile for more info). imread tries to open the file anyways so you don't need to create your own handle! Just use the file path received and call imread instead of using CreateFile.
Mat src;
if (GetOpenFileName(&ofn)==TRUE)
{
// Succeeded in choosing a file
char filepath[260];
wcstombs(filepath, ofn.lpstrFile, 260);
cout << filepath << endl;
src = imread(filepath);
}
Also if you don't have an hwnd then you should just set ofn.hwndOwner=NULL instead of arbitrarily setting it.
If you so choose to use CreateFile (maybe you wish to open it for manual read access for your own purposes outside of OpenCV), then make sure to call CloseHandle( HANDLE h ) on the file handle before you open the file again.
Related
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?
I am trying to create a file dialog where the user selects an existing file or create a new one by selecting a location and entering a name. The browsing works fine, but when I try to save the file, it gives me the following error
fail: file != NULL.
I also have to convert the text that is meant to be written to the file from std::wstring to char *, hence the sprint. I can't figure out what I am doing wrong.
Below is the code I am currently working with:
HMODULE hModule = GetModuleHandleW(NULL);
OPENFILENAME ofn;
char szFile[260]; // buffer for file name
HWND hwnd = NULL; // owner window
HANDLE hf; // file handle
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrTitle = TEXT("Select a location to save the information");
ofn.nMaxFile = sizeof(szFile);
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;
if(GetSaveFileName(&ofn)==TRUE)
{
wchar_t hostName[2048] = L"";
DWORD sz = 2048;
hf = CreateFile(ofn.lpstrFile, GENERIC_READ,
0, (LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
(HANDLE)NULL);
char * buffer = new char[242];
//sprintf(buffer, "%ls", hostInfo.c_str());
_snprintf_s(buffer,242, _TRUNCATE, "%ls", hostInfo.c_str());
std::ofstream stream(ofn.lpstrFile, std::ofstream::binary);
stream.write(buffer, 243);
//delete[] buffer;
stream.close();
}
EDIT:
Found the problem. I did not set the pointer for lpstrFile resulting in the selected path being NULL hence the File != NULL assert fail
I was already using tinyxml 1 before I implemented the function GetOpenFileName in my code, so I know the load works whenever I give it a relative path or an absolute path.
I just don't understand why it doesn't work whenever the function GetOpenFileName executes first. I actually tried a few times to test and every time I executed that function, regardless of whether I used the filepath it gave me or not, tinyxml still wouldn't find the xml.
std::string tutName = getTutorialFilename();
if(tutName != "") {
std::cout << "Before replacing: " << tutName << std::endl;
boost::replace_all(tutName, "\\", "/");
bool loadTutorial = tutorial->loadTutorialSteps(tutName);
if(loadTutorial) {
std::cout << "success!" << std::endl;
} else {
std::cout << "failed: " << tutName << "to load" << std::endl;
}
}
The Function getTutorialFilename, which uses GetOpenFilename:
std::string getTutorialFilename() {
OPENFILENAME ofn; // common dialog box structure
char 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 = "XML\0*.xml*\0All\0*.*\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);
std::string tutorialFilename(szFile);
return tutorialFilename;
}
return "";
}
I know it finds the tutorialFilename with no extra spaces as I've ran the debugger on that, but I still can't understand why tinyxml fails to load.
I figured out the issue. TinyXML was outputting the error 13 - permission denied due to CreateFile blocking access to the file. I deleted that function because I don't need it.
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;
}
}
}
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);