Delete the begin of a CString - c++

I receive file paths in the form of a CString. For Example: C:\Program Files\Program\Maps\World\North-America
I need to remove everything before Maps. I.e C:\Program Files\Program\ but this file path could be different.
I tried:
CString noPath = fullPath;
fullPath.Truncate(fullPath.ReverseFind('Maps'));
noPath.Replace(_T(fullPath),_T(""));
Which doesn't work consistently. It's cutting some file paths in the wrong place. The solution doesn't need to use Truncate/Replace but I'm not sure how else to do this

The CString I'm familiar with doesn't have a Truncate member and ReverseFind only works with single characters, not substrings; so fullPath's type is a mystery to me.
One thing I noticed: _T(fullPath) appears in your code, but the _T macro only works for literals (quoted strings or characters).
Anyway, here is a CString-only solution.
CString TruncatePath(CString path, CString subdir) {
CString sub = path;
const int index = sub.MakeReverse().Find(subdir.MakeReverse());
return index == -1 ? path : path.Right(index + subdir.GetLength());
}
...
CString path = _T("C:\\Program Files\\Program\\Maps\\World\\North-America");
CString sub_path = TruncatePath(path, _T("Maps\\"));
Gives you sub_path: Maps\World\North-America

You can use Delete function for this purpose.
for example:
CString path(_T("C:\\Program Files\\Program\\Maps\\World\\North-America"));
path.Delete(0, path.Find(_T("Maps"))); //pass first index and number of count to delete
Now variable path is having value Maps\\World\\North-America

Related

Function works perfectly but changes value after return

I have a function to concatenate two LPCWSTRs together by converting them to wstrings, adding them, converting it back, and then returning that value (taken from: How to concatenate a LPCWSTR?)
LPCWSTR addLPCWSTRs(LPCWSTR lpcwstr1, LPCWSTR lpcwstr2) {
//Add the strings together
std::wstring wstringCombined = std::wstring(lpcwstr1) + std::wstring(lpcwstr2);
//Convert from wstring back to LPCWSTR
LPCWSTR lpcwstrCombined = wstringCombined.c_str();
return lpcwstrCombined;
}
LPCWSTR BaseURL = L"https://serpapi.com/search.json?tbm=isch?q=";
LPCWSTR imageQuery = L"baby+animals";
LPCWSTR URL = addLPCWSTRs(BaseURL, imageQuery);
Before the return statement, the lpcwstrCombined value is correct, when I break before the return statement the debugger shows the value also to be correct.
The correct value should be:
When I break on the ending curly brace, the value that lpcwstr turns into a bunch of squares before 1-5 random symbols from other languages, and it's always changing.
Examples:
And this is without changing any code, simply resetting the debugger and running again. I have done hours of research on this and so far haven't found anything. A somewhat similar issue with arrays said to use pointers instead of face values but that didn't make a difference. Why does the variable change value outside of the function as soon as it is returned??
Edit:
After reading the comments I changed it to:
std::wstring addLPCWSTRs(LPCWSTR lpcwstr1, LPCWSTR lpcwstr2) {
//Add the strings together
std::wstring wstringCombined = std::wstring(lpcwstr1) + std::wstring(lpcwstr2);
//Convert from wstring back to LPCWSTR
return wstringCombined;
}
LPCWSTR BaseURL = L"https://serpapi.com/search.json?tbm=isch?q=";
LPCWSTR imageQuery = L"baby+animals";
LPCWSTR URL = addLPCWSTRs(BaseURL, imageQuery).c_str();
And the same issue still happens!
The issue is a misunderstanding of the lifetime of your memory. In your first example you have a dangling pointer:
std::wstring combined = ...
// Here you create the string (importantly, its memory)
LPCWSTR lpcwstrCombined = wstringCombined.c_str();
// Make a pointer to the string
return lpcwstrCombined;
// return the pointer
} // end of function the string is destroyed, including it's memory being freed
In your second example you do the same thing, just in a different way:
LPCWSTR URL = addLPCWSTRs(BaseURL, imageQuery).c_str();
// ^ This is a temporary, at the end of this statement, it will be
// destroyed along with its memory.
You need to keep the wstring arround:
std::wstring string_storage = addLPCWSTRs(BaseURL, imageQuery);
LPCWSTR URL = string_storage.c_str();
You can then use the URL for the scope of the string.
That means don't do something like this:
LPCWSTR URL;
{
std::wstring string_storage = addLPCWSTRs(BaseURL, imageQuery);
URL = string_storage.c_str();
} // string is destoryed leaving a dangling pointer (just to get you a third
// time)

How to use SHFileOperation() with CString paths

I am trying to convert CString to LPCWSTR and it works well. But something went wrong in the processing of the code.
I want to copy a directory to another path so I am using SHFILEOPSTRUCT:
HWND console = GetConsoleWindow();
SHFILEOPSTRUCT s = { 0 };
s.hwnd = console;
s.wFunc = FO_COPY;
s.fFlags = FOF_SILENT;
CString _folderName("a6_töüst-Oa5Z.OZS-CI5O5235"),
firstPath("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\"),
lastPart("\\Documents\\*\0"),
firstPathDest("C:\\ORTIM-Daten\\a5Pc 2.0.3\\"),
lastPartDest("Documents\\"),
_folderNameDest("a6_töüst-Oa5Z.OZS-CI5O5235\0");
CString cstrTemp = firstPath + _folderName + lastPart,
cstrTempDest = firstPathDest + lastPartDest + _folderNameDest;
s.pTo = cstrTempDest /*_TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Documents\\a6_töüst-Oa5Z.OZS-CI5O5235\0")*/;
s.pFrom = cstrTemp /*_TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\a6_töüst-Oa5Z.OZS-CI5O5235\\Documents\\*\0")*/;
SHFileOperation(&s);
When I am using CString directly, the copy operation doesn't work, but when I use the _TEXT() macro (as in the comments) to assign the LPCWSTR members in the struct everything works.
EDIT 1
In both variants of source and destination paths the code compiles.
In this variant, the code compiles and does the copy operation:
s.pTo = _TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Documents\\a6_töüst-Oa5Z.OZS-CI5O5235\0");
s.pFrom = _TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\a6_töüst-Oa5Z.OZS-CI5O5235\\Documents\\*\0");
In the other variant, which I actually need, the code compiles too, but the copy operation doesn't take place:
s.pTo = cstrTempDest;
s.pFrom = cstrTemp;
SHFILEOPSTRUCT expects strings ending with two NUL characters, but NUL terminated strings by definition end with one and any additional NUL characters are ignored by CString methods that don't take explicit length argument.
You can force double NUL by adding one manually:
CString cstrTempDest = firstPathDest + lastPartDest + _folderNameDest;
// *** Add NUL manually ***
cstrTempDest.AppendChar( 0 );
s.pTo = cstrTempDest;
// For debuging - verify resulting string with example.
TCHAR* test = _TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Documents\\a6_töüst-Oa5Z.OZS-CI5O5235\0");
// +2 because we want to check two NULs at end.
ASSERT( memcmp( s.pTo, test, (_tcslen(test)+2)*sizeof(TCHAR) ) == 0 );
Alternative solution can use methods with explicit length argument:
CString cstrTempDest = firstPathDest + lastPartDest
+ CString(_folderNameDest, _tcslen(_folderNameDest)+1);
If your project is configured to use unicode character set, call CString constructors with wide strings:
CString _folderName(_T("a6_töüst-Oa5Z.OZS-CI5O5235")),
firstPath(_T("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\"))
...
CString in unicode mode automatically converts narrow strings to wide ones, but it can fail when threre is discrepancy between runtime and development codepages. If you plan to go Unicode and never look back, throw away _TEXT, TEXT and _T macros and just use wide literals:
CString _folderName( L"a6_töüst-Oa5Z.OZS-CI5O5235" ),
firstPath( L"C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\" )
...
You should also check SHFileOperation return value.
The answer of user msp0815 on creating double null ended CString solves your issue.
// strings must be double-null terminated
CString from(cstrTemp + (TCHAR)'\0');
PCZZTSTR szzFrom= from;
s.pFrom= szzFrom;
CString dest(cstrTempDest + (TCHAR)'\0');
PCZZTSTR szzDest= dest;
s.pTo= szzDest;
I generally don't use LPCWSTR that much but here is my idea:
CString TestCSTR = "Hello world";
LPCWSTR TestLPC;
TestLPC = (LPCWSTR)_TEXT(TestCSTR.GetString());
It works as expected in fact the variable TestLPC holds "Hello world" or to be more precise a long pointer to it. It should be possible to remove _TEXT without consequences but I'm not sure, the result is the same btw.

How to use MoveFile function of windows.h The function is prepending the path in filename

path[ ]="folder" ;
strcat(path,fname) ;
MoveFile(fname,path) ;
how to use MoveFile function of windows.h The function is prepending the path in filename
The way you are initializing path, it only has room to hold "folder", you can't append anything more to it without overflowing memory. You need to allocate more space for it, eg:
char path[MAX_PATH] = {};
strcpy(path, "folder");
strcat(path, "\\");
strcat(path, fname);
However, using the Win32 API PathCombine() (or related) function (or a 3rd party solution like boost::filesystem) would be safer:
char path[MAX_PATH] = {};
PathCombine(path, "folder", fname);
Now, with that said, you are passing fname as the first argument to MoveFile(). Assuming fname contains just a filename and no path, MoveFile() will look for the file in a path that is relative to the calling process's current working directory, which is a dynamic value that can (and usually does) change during the process's lifetime. NEVER rely on relative paths, ALWAYS use absolute paths instead.
char src[MAX_PATH] = {};
strcpy(src, "source folder");
strcat(src, "\\");
strcat(src, fname);
// or: PathCombine(src, "source folder", fname);
char dst[MAX_PATH] = {};
strcpy(dst, "destination folder");
strcat(dst, "\\");
strcat(dst, fname);
// or: PathCombine(dst, "destination folder", fname);
MoveFile(src, dst);
Thanks for reply .
I figured out what was the problem .
Actually was looping and concating the path so in each iteration the new file name was appended into path therefore the filename get changed .
But i solved it by assigning '\0' null character at the position from where i want to concat in each iteration .

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().