Hi i am trying to make a GUI for image compare software. The idea is to choose a picture with OPENFILENAME, then get its address with ofn.lpstrFile then make a histogram for that image. So i use:
return(ofn.lpstrFile);
I can cout the address or write it to an .xml file and the address is correct, but when i am trying to do the histogram it gives me all zeros. Behaves like the address was invalid.
Any ideas ?
my code :
string path=browse(); //getting the string from ofn.lpstrFile
path.c_str();
replace(path.begin(), path.end(), '\\', '/'); //converting backslash to slash also may be the problem
HistCreation(path,root_dir);
and
void HistCreation(string path,string root_dir) {
Mat img;
img = imread(path); // here if i manually enter the address everything works fine, if I insert the path then loads empty image
.
.
.
I also tried
char * cstr = new char[path.length() + 1];
std::strcpy(cstr, path.c_str());
Did not work either
std::string returns the string and that's all you need. This is example to open a bitmap file.
(Edit)
#include <iostream>
#include <string>
#include <windows.h>
std::string browse(HWND hwnd)
{
std::string path(MAX_PATH, '\0');
OPENFILENAME ofn = { sizeof(OPENFILENAME) };
ofn.hwndOwner = hwnd;
ofn.lpstrFilter =
"Image files (*.jpg;*.png;*.bmp)\0*.jpg;*.png;*.bmp\0"
"All files\0*.*\0";
ofn.lpstrFile = &path[0];
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn))
{
//string::size() is still MAX_PATH
//strlen is the actual string size (not including the null-terminator)
//update size:
path.resize(strlen(path.c_str()));
}
return path;
}
int main()
{
std::string path = browse(0);
int len = strlen(path.c_str());
if (len)
std::cout << path.c_str() << "\n";
return 0;
}
Note, Windows uses NUL-terminated C-strings. It knows the length of the string by looking for the zero at the end.
std::string::size() is not always the same thing. We can call resize to make sure they are the same thing.
You shouldn't need to replace \\ with /. If your library complains about \\ then replace as follows:
Example:
...
#include <algorithm>
...
std::replace(path.begin(), path.end(), '\\', '/');
Use std::cout to examine the output instead of guessing if it worked or not. In Windows program you can use OutputDebugString or MessageBox to see what the string is.
HistCreation(path, root_dir);
I don't know what root_dir is supposed to be. If HistCreation fails or it has the wrong parameter then you have a different problem.
Related
I am trying get path of the exe file at the same folder where this program will been. but i couldnt figure out how to do, i did something like this but it only gets the current programs path, and i dont know how to replace filenames between my program and the program i want to get path.
so simply can you help me about get the path of an exe (i know the name of that exe ) at the same folder where this program will been...
char fullp[MAX_PATH];
char selfp[MAX_PATH] = "..//myprogram.exe";
char otherprogram[MAX_PATH] = "//test.exe";
DWORD szPath;
szPath = GetModuleFileName(NULL, selfp, sizeof(selfp));
The Win32 API has a whole bunch of Path Handling functions available.
For instance, once you have obtained the calling process's full path from GetModuleFileName(), you can use PathRemoveFileSpec() to remove the filename leaving just the folder path:
char selfdir[MAX_PATH] = {0};
GetModuleFileNameA(NULL, selfdir, MAX_PATH);
PathRemoveFileSpecA(selfdir);
And then use either PathAppend() or PathCombine() to append a different filename to that path:
char otherprogram[MAX_PATH] = {0};
lstrcpyA(otherprogram, selfdir);
PathAppendA(otherprogram, "test.exe");
char otherprogram[MAX_PATH] = {0};
PathCombineA(otherprogram, selfdir, "test.exe");
OP is most of the way there. Here is an example of how to get the rest of the way.
To simplify the solution, I'm leaving char arrays as far behind as possible and using std::string.
#include <iostream>
#include <string>
#include <windows.h>
int main()
{
char selfp[MAX_PATH];
std::string otherprogram = "Failed to get path";
DWORD szPath;
szPath = GetModuleFileName(NULL, selfp, MAX_PATH);
if (szPath != 0) // successfully got path of current program
{
// helper string to make life much, much easier
std::string helper = selfp;
//find last backslash in current program path
size_t pos = helper.find_last_of( "\\" );
if (pos != std::string::npos) // found last backslash
{
// remove everything after last backslash. This should remove
// the current program's name.
otherprogram = helper.substr( 0, pos+1);
// append new program name
otherprogram += "test.exe";
}
}
std::cout << otherprogram << std::endl;
}
I use the OPENFILENAME ofn way to open a browse file dialog in win32 application.
I want to be able to use dynamic the file filtering according to what user needs and not as predefined to all files
ofn.lpstrFilter = L"All Files\0*.*\0\0";
I tried to change the predefined code with a dynamic one but it seems that even the null-terminated character is treated as string in the below code
string UserChoice = "Exe Files\0*.exe\0\0";
wstring ChoiceTemp = s2ws(UserChoice); // convert string to lpcwstr
LPCWSTR FilterByUser = ChoiceTemp.c_str();
ofn.lpstrFilter = FilterByUser;
It seems that the \0 is not recognized as null character in the browse file dialog and it doesn't show any files at all, my knowledge on c++ is on my first steps and i can`t make it work without any help on this issue and i searched around the net but nothing came in handy.
Any suggestion on how to make it work ?
You can use std::string for strings with embedded terminators, but you have to use the correct std::string constructor to create the string.
More specifically either the one where you explicitly specify a length (number 4 in the linked constructor reference) or a start and end iterator (number 6). In this case, the first one is best:
string UserChoice("Exe Files\0*.exe\0", 16);
lpstrFilter is usually a constant string so there is no need for std::wstring. Just define a constant string:
const wchar_t* filter =
L"All files\0*.*\0"
L"Exe files\0*.exe\0";
But it can be done as follows if necessary (I am repeating #Joachim Pileborg)
std::wstring filter =
L"All files|*.*|"
L"Exe files|*.exe|";
std::replace(filter.begin(), filter.end(), '|', '\0');
ofn.lpstrFilter = filter.data();
Use filter.data() instead of c_str(). To select a particular filter use nFilterIndex
wchar_t filename[MAX_PATH];
wcscpy_s(filename, L"c:\\test\\default file.txt");
OPENFILENAME ofn = { sizeof(OPENFILENAME) };
ofn.lpstrFile = filename;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFilter = filter;
ofn.nFilterIndex = 2; //select "Exe files"
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
I'm using GetOpenFileName function from Winapi, and I'm applying filter to the select file dialog.
THIS works perfectly:
LPSTR mfilter = "Filter\0*.PDF\0";
ofn.lpstrFilter = mfilter;
if(GetOpenFileName(&ofn)){
...
THIS fails (dialog opens but no filters apply):
string mfilter = "Filter\0*.PDF\0";
ofn.lpstrFilter = mfilter.c_str();
if(GetOpenFileName(&ofn)){
...
I need to use std:string because I'm getting the file extension via parameters and this type facilitates the concatenation but I'm getting incompatibility issues...
This would be my code if it worked as expected (IT FAILS the same as previous example):
const char * ext = &(4:); //Ampersand parameter (from CA Plex) It contains "PDF"
string mfilter = "Filter\0*." + ext + "\0"; //Final string: Filter\0*.PDF\0;
ofn.lpstrFilter = mfilter.c_str();
When I use this method, I'm getting runtime exception:
string mf;
mf.append("Filter")
.append('\0')
.append("*.pdf")
.append('\0');
ofn.lpstrFilter = mf.c_str();
With
string mfilter = "Filter\0*.PDF\0";
you are calling an std::string contructor, which terminates the string at the first \0.
The following code:
string mfilter = "Filter\0*.PDF\0";
cout << "string:" << mfilter << " len: " << mfilter.length() << endl;
prints
string: Filter len: 6
The string is only constructed until the first \0 terminator. Do the string is only composed of the word "Filter".
The GetOpenFileName function uses TCHARs, and TCHARs become WCHARs in case of UNICODE character set is used.
Here's an example:
std::wstring getOpenFileName(HWND hWnd, const std::wstring& sFilter)
{
wchar_t buffer[MAX_PATH] = L"";
OPENFILENAMEW ofn = {0};
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = sFilter.c_str();
ofn.nFilterIndex = 1;
ofn.lpstrFile = buffer;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
if( !::GetOpenFileNameW( &ofn ) )
return L"";
return buffer;
}
If you want to parametrize lpstrFilter based on std::wstring you can just use wstring::c_str() to get LPCTSTR which is const wchar* in case of UNICODE.
IMPORTANT: The problem is that the std::wstring constructor that takes a const wchar* assumes the input is a C string. C strings are '\0' terminated and thus parsing stops when it reaches the '\0' character. To compensate for this you need to use the constructor that takes two parameters a pointer to the char array and a length.
You can also use string::push_back() method to append NULLs.
std::wstring sFilter = L"PDF Files";
sFilter.push_back('\0');
sFilter.append(L"*.pdf");
sFilter.push_back('\0');
string mfilter = "Filter\0*.PDF\0";
This calls a std::basic_string constructor that uses a null-terminated string. It will stop parsing the string literal at "Filter".
Try this one instead:
string mfilter( "Filter\0*.PDF", 13 ); // need double null at end
This calls a std::basic_string constructor that uses "the first count characters of character string pointed to by s. s can contain null characters."
You have to either count the characters yourself, or write wrapper code if you encounter this problem more often.
Related: std::basic_string constructors.
As for your runtime error:
string mf;
mf.append("Filter")
.append('\0')
.append("*.pdf")
.append('\0');
append() does not have an overload for a single character type. You are probably hitting the const CharT* s overload, with a null pointer.
Use either append( 1, '\0' ) or append( "", 1 ), either of which should append a null byte.
I have tried googling, but people seem to have the same problem: we can't get a list of the selected files.
This is a simple piece of working code that is similar to what I use:
OPENFILENAME ofn = { sizeof ofn };
wchar_t file[1024];
file[0] = '\0';
ofn.lpstrFile = file;
ofn.nMaxFile = 1024;
ofn.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER;
GetOpenFileName(&ofn);
How do I actually get the filenames I selected? Currently I can only get it to work without OFN_ALLOWMULTISELECT flag, so it returns the one selected filename into ofn.lpstrFile. I tried to print out all the string variables inside that struct, but found nothing. It only shows the main folder of the selected files.
It looks like the ofn.lpstrFile contains all the filenames, separated with a NULL and ending with another NULL (effectively ending with an empty string).
If the OFN_ALLOWMULTISELECT flag is set and the user selects multiple files, the buffer contains the current directory followed by the file names of the selected files. For Explorer-style dialog boxes, the directory and file name strings are NULL separated, with an extra NULL character after the last file name. For old-style dialog boxes, the strings are space separated and the function uses short file names for file names with spaces. You can use the FindFirstFile function to convert between long and short file names. If the user selects only one file, the lpstrFile string does not have a separator between the path and file name.
From MSDN.
A possible implementation to parse the contents could be;
wchar_t* str = ofn.lpstrFile;
std::wstring directory = str;
str += ( directory.length() + 1 );
while ( *str ) {
std::wstring filename = str;
str += ( filename.length() + 1 );
// use the filename, e.g. add it to a vector
}
Checking nFileExtension may NOT be reliable because it can also be 0 if the user entered no file extension (but just the dot, like "file.").
I think to distinguish between single and multi file selection one has to check if there is a null character (terminator) at position nFileOffset - 1.
Try this:
wchar_t file[1025] = {0}; // room for an extra null terminator, just in case
...
ofn.nMaxFile = 1024;
...
wchar_t* ptr = ofn.lpstrFile;
ptr[ofn.nFileOffset-1] = 0;
std::wcout << L"Directory: " << ptr << std::endl;
ptr += ofn.nFileOffset;
while (*ptr)
{
std::wcout << L"File: " << ptr << std::endl;
ptr += (lstrlenW(ptr)+1);
}
If you select a single file when using OFN_ALLOWMULTISELECT, the nFileExtension field contains the offset to the extension. If you select multiple files, the nFileExtension field contains 0.
This way you can determine if a single file was selected, and just read/copy the buffer pointed to by the lpstrFile field (which will be a single null terminated string containing the full path and filename including extension)
or if multiple files where selected, then you parse the buffer pointed to by the lpstrFile field, using nFileOffset to read/copy the folder first (using lstrcpyn for example and specifying length to read as the nFileOffset value) and then read/copy from nFileOffset to next null which is file1 string, add the file string length +1 to get next position to read/copy next file string etc till you reach a file string that starts with null - which is the double null for end of all files (as the last string before this is null terminated)
Here is a more complete version of the answers by Niall and Remy.
vector<string> &filePaths;
if ( GetOpenFileName( &ofn ) == TRUE )
{
wchar_t *p = ofn.lpstrFile;
wstring path = p;
p += path.size() + 1;
if ( *p == 0 )
{
// there is only one string, being the full path to the file
filePaths.push_back( ConvertWideCharToUtf8( path.c_str() ) );
}
else
{
// multiple files follow the directory
for ( ; *p != 0 ; )
{
wstring fileName = p;
filePaths.push_back( ConvertWideCharToUtf8( ( path + L"\\" + fileName ).c_str() ) );
p += fileName.size() + 1;
}
}
}
Where we also have the function:
string ConvertWideCharToUtf8( const wchar_t *wideText )
{
int len = WideCharToMultiByte( CP_UTF8, 0, wideText, -1, NULL, 0, NULL, NULL );
char *buffer = (char *)malloc( len );
WideCharToMultiByte( CP_UTF8, 0, wideText, -1, buffer, len, NULL, NULL );
string s = buffer;
free( buffer );
return s;
}
i have a buffer
char buffer[size];
which i am using to store the file contents of a stream(suppose pStream here)
HRESULT hr = pStream->Read(buffer, size, &cbRead );
now i have all the contents of this stream in buffer which is of size(suppose size here). now i know that i have two strings
"<!doctortype html" and ".html>"
which are present somewhere (we don't their loctions) inside the stored contents of this buffer and i want to store just the contents of the buffer from the location
"<!doctortype html" to another string ".html>"
in to another buffer2[SizeWeDontKnow] yet.
How to do that ??? (actually contents from these two location are the contents of a html file and i want to store the contents of only html file present in this buffer). any ideas how to do that ??
You can use strnstr function to find the right position in your buffer. After you've found the starting and ending tag, you can extract the text inbetween using strncpy, or use it in place if the performance is an issue.
You can calculate needed size from the positions of the tags and the length of the first tag nLength = nPosEnd - nPosStart - nStartTagLength
Look for HTML parsers for C/C++.
Another way is to have a char pointer from the start of the buffer and then check each char there after. See if it follows your requirement.
If that's the only operation which operates on HTML code in your app, then you could use the solution I provided below (you can also test it online - here). However, if you are going to do some more complicated parsing, then I suggest using some external library.
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
const char* beforePrefix = "asdfasdfasdfasdf";
const char* prefix = "<!doctortype html";
const char* suffix = ".html>";
const char* postSuffix = "asdasdasd";
unsigned size = 1024;
char buf[size];
sprintf(buf, "%s%sTHE STRING YOU WANT TO GET%s%s", beforePrefix, prefix, suffix, postSuffix);
cout << "Before: " << buf << endl;
const char* firstOccurenceOfPrefixPtr = strstr(buf, prefix);
const char* firstOccurenceOfSuffixPtr = strstr(buf, suffix);
if (firstOccurenceOfPrefixPtr && firstOccurenceOfSuffixPtr)
{
unsigned textLen = (unsigned)(firstOccurenceOfSuffixPtr - firstOccurenceOfPrefixPtr - strlen(prefix));
char newBuf[size];
strncpy(newBuf, firstOccurenceOfPrefixPtr + strlen(prefix), textLen);
newBuf[textLen] = 0;
cout << "After: " << newBuf << endl;
}
return 0;
}
EDIT
I get it now :). You should use strstr to find the first occurence of the prefix then. I edited the code above, and updated the link.
Are you limited to C, or can you use C++?
In the C library reference there are plenty of useful ways of tokenising strings and comparing for matches (string.h):
http://www.cplusplus.com/reference/cstring/
Using C++ I would do the following (using buffer and size variables from your code):
// copy char array to std::string
std::string text(buffer, buffer + size);
// define what we're looking for
std::string begin_text("<!doctortype html");
std::string end_text(".html>");
// find the start and end of the text we need to extract
size_t begin_pos = text.find(begin_text) + begin_text.length();
size_t end_pos = text.find(end_text);
// create a substring from the positions
std::string extract = text.substr(begin_pos,end_pos);
// test that we got the extract
std::cout << extract << std::endl;
If you need C string compatibility you can use:
char* tmp = extract.c_str();