WIN32_FIND_DATA - Get the absolute path - c++

I'm using something like this:
std::string tempDirectory = "./test/*";
WIN32_FIND_DATA directoryHandle;
memset(&directoryHandle, 0, sizeof(WIN32_FIND_DATA));//perhaps redundant???
std::wstring wideString = std::wstring(tempDirectory.begin(), tempDirectory.end());
LPCWSTR directoryPath = wideString.c_str();
//iterate over all files
HANDLE handle = FindFirstFile(directoryPath, &directoryHandle);
while(INVALID_HANDLE_VALUE != handle)
{
//skip non-files
if (!(directoryHandle.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
//convert from WCHAR to std::string
size_t size = wcslen(directoryHandle.cFileName);
char * buffer = new char [2 * size + 2];
wcstombs(buffer, directoryHandle.cFileName, 2 * size + 2);
std::string file(buffer);
delete [] buffer;
std::cout << file;
}
if(FALSE == FindNextFile(handle, &directoryHandle)) break;
}
//close the handle
FindClose(handle);
which prints the names of each file in the relative directory ./test/*.
Is there any way to determine the absolute path of this directory, just like realpath() does on Linux without involving any 3rd party libraries like BOOST? I'd like to print the absolute path to each file.

See the GetFullPathName function.

You can try GetFullPathName
Or you can use SetCurrentDirectory and GetCurrentDirectory. You might want to save the current directory before doing this so you can go back to it afterwards.
In both cases, you only need to get the full path of your search directory. API calls are slow. Inside the loop you just combine strings.

Related

CopyFile to a custom location, with string conversion problem

I am trying to make this application copy itself to appdata, which requires the USERNAME, which I already have.
But, for some reason, the file doesn't copy to this place. I tried a lot of string conversion to char, but none of them worked for the strcat() and CopyFile() functions.
Here is the code:
char user[UNLEN + 1];
char Original[MAX_PATH];
DWORD User_len = UNLEN + 1;
GetUserName(user, & User_len);
std::string Path("C:\\Users\\");
Path += user;
Path += ("\\AppData\\Other Stuff");
GetModuleFileName(NULL, OriginalFile, sizeof(OriginalFile))
char *PathChr = new char(Path.length() + 1); // Might be wrong but continue...
strcat(PathChr, "something.exe");
CopyFile(OriginalFile, PathChr, NULL);
The question is now solved!
You are not allocating enough memory for PathChr. You are allocating only 1 char, not Path.length() number of chars. You need to use [] instead of () when calling new, eg:
char *PathChr = new char[Path.length() + 1];
...
delete[] PathChr;
Alternatively, forget using new[], just use the std::string you already created, eg:
std::string Path = "C:\\Users\\";
Path += user;
Path += "\\AppData\\Other Stuff\\";
Path += "something.exe";
...
CopyFileA(OriginalFile, Path.c_str(), NULL);
But, since you already know the maximum array length up front (UNLEN + 43), you don't need a dynamically allocated string at all, a fixed array will suffice:
char user[UNLEN + 1];
char Path[UNLEN + 46];
char Original[MAX_PATH];
DWORD User_len = UNLEN + 1;
GetUserName(user, &User_len);
strcpy(Path, "C:\\Users\\");
strcat(Path, user);
strcat(Path, "\\AppData\\Other Stuff\\something.exe");
GetModuleFileName(NULL, OriginalFile, sizeof(OriginalFile));
CopyFileA(OriginalFile, Path, NULL);
That being said, the location of the AppData folder is user-customizable, so do not hard-code it. The correct way to get the actual AppData path is to use SHGetFolderPath() with CSIDL_(LOCAL_)APPDATA, or SHGetKnownFolderPath() with FOLDERID_(Roaming|Local)AppData, eg:
char AppData[MAX_PATH];
char Path[MAX_PATH];
char Original[MAX_PATH];
SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, AppData);
LPSTR pDest = PathCombineA(Path, AppData, "Other Stuff\\something.exe");
GetModuleFileName(NULL, OriginalFile, sizeof(OriginalFile));
CopyFileA(OriginalFile, pDest, NULL);

Getting Path of the executable in current folder C++

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;
}

How to save ofn.lpstrFile to string properly?

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.

Way to move a file to another directory without specifying filename in destination directory?

I need a way to move a file to another directory without having to specify the file name in the destination directory.
TCHAR szFileName[MAX_PATH];
GetModuleFileName(NULL, szFileName, MAX_PATH);
wchar_t* Favfolder = 0;
SHGetKnownFolderPath(FOLDERID_Favorites, 0, NULL, &Favfolder);
wstringstream ss(szFileName);
wstringstream ff(Favfolder);
rename(ss.str(), ff.str()); //Won't work
If I use rename, ff.str()doesn't include the file name, so it won't work.
The proper way to do it would be to write:
rename(C:\\Users\\blah\\blah\\filename.exe, C:\\Users\\blah\\newdir\\filename.exe);
What I'm doing is:
rename(C:\\Users\\blah\\blah\\filename.exe, C:\\Users\\blah\\newdir);
But I can't figure out a way to include the filename.exe in the second example.
I assume that you are using wstring, not a wstringstream.
Use find_last_of(link) to find the position of last \ in the ss.
Get the filename by substr(link).
Paste the filename at the end of ff.
EDIT:
Function which do all the work:
int move(const string &oldPath, const string &newDir)
{
const size_t pos = oldPath.find_last_of('\\');
const string newPath = newDir + '\\' + (pos == string::npos ? oldPath : oldPath.substr(pos));
return rename(oldPath.c_str(), newPath.c_str());
}
Unfortunately, rename doesn't support wchar_t so I did have to use a string, not a wstring

Comparison of process name

I write filtering system and use Winsock2 LSP.
In WSPConnect I need to compare executable filename of process with harcoded Unicode String.
I do:
LPWSTR moduleName = {0};
GetModuleFileNameEx (GetCurrentProcess(),0,moduleName,_MAX_FNAME );
LPWSTR mn = L"redirect.exe";
if (lstrcmp (moduleName, mn) == 0){ ...some code there...}
What I am doing wrong?
You should compare "case-insensitive": lstrcmpi
You need to pass a correct char array...
Also you should always check the result values of function calls!
Also you should not use the TCHAR version of GetModuleFileNameEx if you explicit use wchar_t => GetModuleFileNameExW!
Also you should use the method GetModuleFileNameW if you want to get the name of the current process! This is more reliable!
ALso you should use MAX_PATH instead of _MAX_FNAME, because the method might also return the full path!
Also be sure that your string is correctly NUL-terminated!
Also you must be aware that the returned path might contain the full path, so comparing with the process name does never match...
Also you must be aware that the path might contion the short file name! (not in your case, because the name is not longer than 8 characters; but if you compare it with "MyExecutable.exe" you also must compare with the short file name; see GetShortPathName
The code part should now look like:
WCHAR moduleName[MAX_PATH+1];
if (GetModuleFileNameW (NULL, moduleName, MAX_PATH) != 0)
{
moduleName[MAX_PATH] = 0;
LPWSTR mn = L"redirect.exe";
int len = lstrlen(moduleName);
int lenmn = lstrlen(mn);
if (len > lenmn)
{
if (lstrcmpi (&moduleName[len-lenmn], mn) == 0){ ...some code there...}
}
}
You need to declare storage space, just a pointer is not enough
LPWSTR moduleName = {0};
GetModuleFileNameEx (GetCurrentProcess(),0,moduleName,_MAX_FNAME );
should be
TCHAR moduleName[_MAX_PATH];
GetModuleFileNameEx(GetCurrentProcess(), 0, moduleName, _countof(moduleName));
and use case-insensitive lstrcmpi().