How to start explorer.exe with QProcess when the path to the specified file contains spaces? - c++

I want to start explorer and select a specific file. So I run
QProcess::startDetached(command);
with command set to
explorer.exe /select,C:\Users\....\file.txt
This works fine, but will fail if the path to the file contains spaces. But if I put the path in quotes
explorer.exe /select,"C:\Users\....\file.txt"
the explorer will open the documents folder and not the specified path.
Running the same string from the command line works fine.
The string is initialized with
command = "explorer.exe" + "/select," + "\"" + QDir::toNativeSeparators(path) + "\"";

How to achieve this is indeed not so intuitive, but also not impossible.
Solution
Decompose all arguments of the command, explorer.exe, as separate strings, i.e. /select, ,, the_path.
Example
QProcess::startDetached("explorer.exe", QStringList{"/select", ",", "C:\\Users\\Your Username\\Desktop\\Folder With Spaces\\file.txt"});

Related

Automating BLF to MAT File Conversion in Vector CANalyzer

I'm trying to automate my conversion of a bunch of BLF files into Matlab MAT files. I found a similar question on here and used the answer to get started:
Is there a way to automate BLF to CSV conversion in Vector CANoe?
I would just comment on that thread, but my account here is new so I can't.
I followed the instructions in the other thread to set it up for CANalyzer and BLF/MAT files. When I run the BAT file I get an error in the Write window of CANalyzer that says:
System Logging file 'logfile001.blf' could not be imported
So the issue seems to be that the BLF isn't getting imported into CANalyzer properly. Has anyone tried this before or have any suggestions on what to try? I've never really used VBS so I'm having a hard time troubleshooting the code.
Here's my code as I have it written.
For the BAT file:
for /F %%x in ('cd') do for %%i in (*.blf) do c:\windows\system32\wscript.exe canalyzer_convert.vbs %%i %%x
For the VBS script:
'-----------------------------------------------------------------------------
' converts the filenames which are passed via startup parameter to MAT files with the help of CANalyzer
'-----------------------------------------------------------------------------
Dim src_file, dst_file, pos
Set App = CreateObject("CANalyzer.Application")
Set Measurement = App.Measurement
Set args = WScript.Arguments
' read first command line parameter
arg0=args.Item(0)
arg1=args.Item(1)
If Measurement.Running Then
Measurement.Stop
End If
Wscript.Sleep 500
'---------------------------------------------------------------------------
' you have to create an empty CANalyzer configuration and specify the path and file name below
'-----------------------------------------------------------------------------
App.Open("c:\CANalyzer\empty_config.cfg")
'-----------------------------------------------------------------------------
' create destination file name and append .mat -- you could change this to different file format that is supported by CANalyzer
' next line has to be cut down to src_file="" & arg0 or src_file=arg0 to avoid adding folder name to file name, but this script still crashes
src_file=arg0
dst_file=src_file & ".mat"
Set Logging = App.Configuration.OnlineSetup.LoggingCollection(1)
Set Exporter = Logging.Exporter
With Exporter.Sources
.Clear
.Add(src_file)
End With
' Load file
Exporter.Load
With Exporter.Destinations
.Clear
.Add(dst_file)
End With
Exporter.Save True
App.Quit
Set Exporter = Nothing
Set Logging = Nothing
Set App = Nothing
Set args = Nothing
Set Measurement = Nothing
If you compare mine to the answer from the other thread, you'll see I had to remove the arg1 info from this line
src_file=arg1 & "" & arg0
If I don't remove arg1 from there, then CANalyzer tries to import a BLF file that also includes the folder name in the file name and crashes the script. I think it may be causing problems with
Set Logging = App.Configuration.OnlineSetup.LoggingCollection(1)
because that line appears to reference
arg1=args.Item(1)
Any help would be appreciated.

Running CMD line in C++ Using variables (not string literals) as Params

I've executed this command in the CMD window and it works. I now need to run it in 2015 VC++ program code but I cannot get it.
I've read the various posts dealing with this but they are mainly for string literals and I have variables. I think this is throwing off the double quotes. I do not have to use _wsystem if there is a better/safer way.
UPDATED:
std::wstringstream wss;
wss << std::wstring(L"\"") << CPathUtil::get_exe_fullpath() << std::wstring(L"\"") << L" /q /a " << std::wstring(L"\"") + cp.c_str() + std::wstring(L"\"");
const auto command = wss.str();
const auto result = _wsystem(command.c_str());
It still does not run from VC++ app..
command = "C:\Users\Valued Customer\Documents\Visual Studio 2015\Projects\svn_3dg_wc\x64\Debug\MyAppD.exe" /q /a "C:\Users\Valued Customer\Documents\Visual Studio 2015\Projects\svn_3dg_wc\Samples\New folder\C - Copy (2).abc"
If I copy value from debugger and paste into CMD window, it works.
Any ideas?
The quotes you add in the last step before calling _wsystem turn the whole string into a single command. The quotes are needed to group space-delimited "words" in the command.
The contents of param should be something like
"C:\Users\Valued Customer\Documents\Visual Studio 2015\Projects\svn_wc\x64\Debug\MyApp.exe" /q /a "C:\Users\Valued Customer\Documents\Visual Studio 2015\Projects\svn_3dg_wc\Samples\New folder\C - Copy (2).abc"
Note that the /q /a part is not within quotes, only the paths to the files (which contains spaces and therefore needs the quotes).
Also note that there's no multiple of quotes anywhere, only single double-quotes.

C++ system() not working when there are spaces in two different parameters

I'm trying to run a .exe that requires some parameters by using system().
If there's a space in the .exe's path AND in the path of a file passed in parameters, I get the following error:
The filename, directory name, or volume label syntax is incorrect.
Here is the code that generates that error:
#include <stdlib.h>
#include <conio.h>
int main (){
system("\"C:\\Users\\Adam\\Desktop\\pdftotext\" -layout \"C:\\Users\\Adam\\Desktop\\week 4.pdf\"");
_getch();
}
If the "pdftotext"'s path doesn't use quotation marks (I need them because sometimes the directory will have spaces), everything works fine. Also, if I put what's in "system()" in a string and output it and I copy it in an actual command window, it works.
I thought that maybe I could chain some commands using something like this:
cd C:\Users\Adam\Desktop;
pdftotext -layout "week 4.pdf"
So I would already be in the correct directory, but I don't know how to use multiple commands in the same system() function.
Can anyone tell me why my command doesn't work or if the second way I thought about would work?
Edit: Looks like I needed an extra set of quotation marks because system() passes its arguments to cmd /k, so it needs to be in quotations. I found it here:
C++: How to make a my program open a .exe with optional args
so I'll vote to close as duplicate since the questions are pretty close even though we weren't getting the same error message, thanks!
system() runs command as cmd /C command. And here's citation from cmd doc:
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
It seems that you are hitting case 2, and cmd thinks that the whole string C:\Users\Adam\Desktop\pdftotext" -layout "C:\Users\Adam\Desktop\week 4.pdf (i.e. without the first and the last quote) is the name of executable.
So the solution would be to wrap the whole command in extra quotes:
//system("\"D:\\test\" nospaces \"text with spaces\"");//gives same error as you're getting
system("\"\"D:\\test\" nospaces \"text with spaces\"\""); //ok, works
And this is very weird. I think it's also a good idea to add /S just to make sure it will always parse the string by the case 2:
system("cmd /S /C \"\"D:\\test\" nospaces \"text with spaces\"\""); //also works
I got here looking for an answer, and this is the code that I came up with (and I was this explicit for the benefit of next person maintaining my code):
std::stringstream ss;
std::string pathOfCommand;
std::string pathOfInputFile;
// some code to set values for paths
ss << "\""; // command opening quote
ss << "\"" << pathOfCommand << "\" "; // Quoted binary (could have spaces)
ss << "\"" << pathOfInputFile << "\""; // Quoted input (could have spaces)
ss << "\""; // command closing quote
system( ss.str().c_str() ); // Execute the command
and it solved all of my problems.
Good learning from here on the internals of System call.Same issue reproducible(of course) with C++ string, TCHARs etc.
One approach that always helped me is SetCurrentDirectory() call. I first set current path and then execute. This has worked for me so far. Any comments welcome.
-Sreejith. D. Menon

popen and system behaves unexpectedly with multiple quoted file paths

I am trying to execute a dos command from within my C++ program, however soon as I add quotes to the output filepath (of a redirection) the command no longer gets executed and returns instantly. I've shown an example below of a path without spaces, but since paths may have spaces and thus be quoted for the shell to understand it properly I need to solve this dilemma - and I'm trying to get the simplest case working first.
i.e.
The following WORKS:
sprintf(exec_cmd,"\"C:/MySQL Server 5.5/bin/mysqldump.exe\" -u%s -p%s %s > C:/backup.bak",user,password,db_name);
system(exec_cmd);
The following does NOT work (notice the quotes around the output):
sprintf(exec_cmd,"\"C:/MySQL Server 5.5/bin/mysqldump.exe\" -u%s -p%s %s > \"C:/backup.bak\"",user,password,db_name);
system(exec_cmd);
I'm guessing it is choking somewhere. I've tried the same "exec_cmd" in popen to no avail.
Any help/advice is greatly appreciated.
I don't think your shell (cmd.exe) allows redirection to a file name with spaces. I couldn't make my command.com from DOS 6.22 accept it (I don't have a cmd.exe nearby to test).
Anyway, you can use the --result-file option to pass the redirection to the command itself.
mysqldump ... --result-file="file name" ...

Dumping memory in gdb - how to choose the file name at run time

I'm running a program that does processing on a file.
I want to be able to supply the program with several files, and by attaching to it with gdb, I want to get a memory dump at a certain point in the code for each of the files. I want the dump for each file to go to a file with the same filename as the input file (maybe after formatting it a little, say adding a suffix)
So suppose I have a function called HereIsTheFileName(char* filename), and another function called DumpThisMemoryRegion(void* startAddr, void* endAddr), I want to do something like the following:
To get the file name to an environment variable:
break HereIsTheFileName
commands 1
set $filename = malloc(strlen(filename) + 1)
call memcpy($filename, filename, strlen(filename) + 1)
end
Then to dump the memory to the filename I saved earlier:
break DumpThisMemoryRegion
commands 2
append binary memory "%s.memory"%$filename startAddr endAddr
end
(I would even settle for the filename as it is, without formatting, if that turns out to be the difficult part)
However, I couldn't get gdb to accept anything except an exlicit file name for the append/dump commands. when I ran "append binary memory $filename ..." I got the output in the file "/workdir/$filename".
Is there any way to make gdb choose the file name at runtime?
Thanks!
I don't know how to make append accept a runtime filename, but you can always cheat a bit by writing the whole thing to a file and then sourcing that file, using logging.
By putting this in your ~/.gdbinit
define reallyappend
printf "using gdbtmp.log to dump memory to file %s\n", $arg0
set logging file gdbtmp.log
set logging overwrite on
set logging redirect on
set logging on
printf "append binary memory %s 0x%x 0x%x", $arg0, $arg1, $arg2
set logging off
set logging redirect off
set logging overwrite off
source gdbtmp.log
end
you can use the function reallyappend instead, for example with
(gdb) set $filename = "somethingruntimegenerated"
(gdb) reallyappend $filename startAddr endAddr
I don't know if logging works ok in an "commands" environment, but you can give it a shot at least.
Yeah, you can't use a variable here for the filename argument.
The best suggestion I can offer is to write a script that will
set all the breakpoints and set up the "append" commands, and
use text editing or awk and sed to set up the filenames in the
script.