How to set path inside of c++ program using system() function - c++

I need to write c++ program which sets path using system() function:
system("set PATH=%PATH%;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64");
system("nvcc -x cu -o cudapair cudapair.c");
But it doesnt work. It throws error, because path wasn't set. What's the problem?

I need to write c++ program which sets path using system() function
I'm assuming what you actually need to do is write a C++ program that
sets the PATH for the environment in which it will then execute
nvcc -x cu -o cudapair cudapair.c
You think you need to make that environment setting with
the system function, but in fact you don't.
You should understand that a process cannot change its own environment.
A process inherits its environment from its parent process, and it
can change the environment that is inherited by its child processes.
That's why your posted attempt does not work.
system("set PATH=%PATH%;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64");
executes a child process of your program. That child process gets the same environment settings
as your program, and can't change them. What does that child process do? It invokes the
Windows shell to run the commandline:
set PATH=%PATH%;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64");
This would change the environment settings of any more child processes that were started
by this commandline. But there aren't any. The commandline makes an environment setting
that no process uses. Your system call returns. That environment setting no longer
exists anywhere. Nothing has changed.
You then call:
system("nvcc -x cu -o cudapair cudapair.c");
which starts a second child process, again with the same environment settings that your
program started with.
What you should do
Get the value of PATH from the environment that your program inherits.
Using that value, create the new value of PATH that you want to pass to your child process.
Put that new value of PATH into the environment your child process will inherit.
Run your child process.
You use system only to do 4.
To do 1, use the Microsoft C library function getenv_s
(It is a secure variant of the Standard C++ std::getenv)
To do 3, use the Microsoft C library function _putenv_s (Note the leading underscore.)
Here is an illustrative program for Visual C++:
#include <iostream>
#include <string>
#include <cstdlib>
const std::size_t ENV_BUF_SIZE = 1024; // Enough for your PATH?
int main()
{
char buf[ENV_BUF_SIZE];
std::size_t bufsize = ENV_BUF_SIZE;
int e = getenv_s(&bufsize,buf,bufsize,"PATH");
if (e) {
std::cerr << "`getenv_s` failed, returned " << e << '\n';
exit(EXIT_FAILURE);
}
std::string env_path = buf;
std::cout << "In main process, `PATH`=" << env_path << std::endl;
env_path += ";C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64";
e = _putenv_s("PATH",env_path.c_str());
if (e) {
std::cerr << "`_putenv_s` failed, returned " << e << std::endl;
exit(EXIT_FAILURE);
}
std::cout << std::endl;
e = std::system("echo \"In child process `PATH`=%PATH%\"");
if (e) {
std::cerr << "`std::system` failed, returned " << e << std::endl;
exit(EXIT_FAILURE);
}
return 0;
}
See it live

Related

WriteConsole doesn't work with PowerShell ISE?

WriteConsole does not work with PowerShell ISE.
Neither WriteConsoleW or WriteConsoleA do.
See, for example, this program:
#include <iostream>
#include <Windows.h>
void w() {
DWORD written;
BOOL const success = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"Printed\n", 8, &written, nullptr);
std::wcout << (success ? L"Success" : L"Failure") << L". Wrote " << written << L" characters." << std::endl;
}
void a() {
DWORD written;
BOOL const success = WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), "Printed\n", 8, &written, nullptr);
std::cout << (success ? "Success" : "Failure") << ". Wrote " << written << " characters." << std::endl;
}
int main() {
w();
a();
return 0;
}
Ran from PowerShell (or Command Prompt, or Git Bash), it prints:
Printed
Success (wrote 8 characters)
Printed
Success (wrote 8 characters)
But from PowerShell ISE:
Failure (wrote 0 characters)
Failure (wrote 0 characters)
To provide background information on Bertie Wheen's own helpful answer:
Perhaps surprisingly, the Windows PowerShell ISE does not allocate a console by default. (The console-like UI that the ISE presents is not a true Windows console).
A console is allocated on demand, the first time a console-subsystem program is run in a session (e.g., cmd /c ver)
Even once that has happened, however, interactive console-subsystem programs are fundamentally unsupported (try choice /m "Prompt me", for instance).
Interactively, you can test if a console has been allocated or not with the following command: [Console]::WindowTop; if there's no console, you'll get a The handle is invalid error.
It follows from the above that your program cannot assume that a console is present when run in the ISE.
One option is to simply not support running in the ISE, given that it is:
no longer actively developed
and there are various reasons not to use it (bottom section), notably not being able to run PowerShell (Core) 6+, and the limitations with respect to console-subsystem programs mentioned above.
As for a successor environment: The actively developed, cross-platform editor that offers the best PowerShell development experience is Visual Studio Code with its PowerShell extension.
As for the potential reason for the poor console support in the ISE: zett42 notes:
A possible reason why ISE developers choose not to allocate a console could stem from the historic difficulties of creating a custom, embedded console within an app's own window. Developers had to resort to hackish, unsupported ways of doing that. Only recently (2018) Windows got a dedicated pseudo-console (ConPTY) API.
The reason why is shown by this program:
#include <iostream>
#include <Windows.h>
int main() {
DWORD const file_type = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
if (file_type == FILE_TYPE_CHAR) {
std::cout << "char" << std::endl;
} else if (file_type == FILE_TYPE_PIPE) {
std::cout << "pipe" << std::endl;
} else {
std::cout << file_type << std::endl;
}
return 0;
}
When run from PowerShell (or Command Prompt, or Git Bash), it prints:
char
But from PowerShell ISE:
pipe
WriteConsole cannot write through a pipe, and thus fails. The same thing happens when run from PowerShell / Command Prompt / Git Bash if the output is piped.

Cannot write an array in a Ubuntu device using C++ (Debug Assertion Failed. Expression (stream !=NULL))

I am working on Windows and I am trying to write an array into a Ubuntu device using C++ in Visual Studio 2019. Here's a sample of my code:
int Run_WriteCalibTable(char *pcIPAddress, int iNumArgs, float *fArgs, int *iAnsSize, char *sAns)
...
...
...
char pcFolderName[256];
char pcFileName[256];
sprintf(pcFolderName, "%s\\%s",pcSavePath, pcUUTSerialNumber);
sprintf(pcFileName, "%s\\calib_rfclock.conf",pcFolderName);
// WRITE TABLE ON PC
FILE *pFileW;
pFileW = fopen(pcFileName,"wb");
fwrite(&CalibTable, sizeof(char), CalibTable.hdr.v1.u32Len, pFileW);
fclose(pFileW);
}
return 0;
However, I keep having this pop-up from Microsoft Visual C++ Debug Library that says:
Debug Assertion Failed:
Program:...
File: f:\dd\vctools\crt_bld\sefl_x86\crt\src\fwrite.c
Line: 77
Expression: (stream != NULL)
...
I found this thread and I tried logging in as root on my Ubuntu device. I also tried:
mount -o remount,rw /path/to/parent/directory
chmod 777 /path/to/parent/directory
And I can also create/edit manualy any file in the directory I'm trying to write into with my code, but I get the same error when running it.
Anyone knows what could cause this? I think it could be on the Windows side, but I don't know what I am doing wrong. Thanks a lot in advance.
You never check that opening the file succeeds - and it most likely fails, which is why you get the debug pop-up. Your use of \ as directory delimiters may be the only reason why it fails, but you should check to be sure.
I suggest that you use std::filesystem::path (C++17) to build your paths. That makes it easy to create paths in a portable way. You could also make use of a C++ standard std::ofstream to create the file. That way you don't need to close it afterwards. It closes automatically when it goes out of scope.
Example:
#include <cerrno>
#include <cstring>
#include <filesystem>
#include <fstream>
int Run_WriteCalibTable(char *pcIPAddress, int iNumArgs, float *fArgs,
int *iAnsSize, char *sAns)
{
...
// Build std::filesystem::paths:
auto pcFolderName = std::filesystem::path(pcSavePath) / pcUUTSerialNumber;
auto pcFileName = pcFolderName / "calib_rfclock.conf";
// only try to write to the file if opening the file succeeds:
if(std::ofstream pFileW(pcFileName, std::ios::binary); pFileW) {
// Successfully opened the file, now write to it:
pFileW.write(reinterpret_cast<const char*>(&CalibTable),
CalibTable.hdr.v1.u32Len);
} else {
// Opening the file failed, print the reason:
std::cerr << pcFileName << ": " << std::strerror(errno) << std::endl;
}
...
}

Connect To Matlab 2017b from c++ vs2013

I would like to read some variable's value in Matlab from c++. I searched in Internet and found out below example in Matlab Documentation Page.
for using this example I Did below steps:
I add this include path to project :
c:\program files\Matlab\r2017b\extern\include
then I Add this path Library Directory :
c:\program Files\Matlab\r2017b\extern\lib\win64\microsoft
then I Add this library to project :
"libMatlabEngine.lib"
"libMatlabDataArray.lib"
then I placed needed DLLs beside application EXE file.
then I ran the application after that application faced with access violataion error when startMATLAB() Method has been ran.
Note: I had other problem that I resolved it. but I think that problem was very strange and may be knowing that problem help you to find main reason of my problems.
problem was : when I set dll's files path in environment variables my app didn't find dlls and get "no entry point to *.dll" run time error. but when I copy dlls beside of exe, my app saw them.(I restarted VS2013 after change environment variables.)
#include "MatlabDataArray.hpp"
#include "MatlabEngine.hpp"
#include <iostream>
void callgetVars() {
using namespace matlab::engine;
// Start MATLAB engine synchronously
std::unique_ptr<MATLABEngine> matlabPtr = startMATLAB();
// Evaluate MATLAB statement
matlabPtr->eval(convertUTF8StringToUTF16String("[az,el,r] = cart2sph(5,7,3);"));
// Get the result from MATLAB
matlab::data::TypedArray<double> result1 = matlabPtr->
getVariable(convertUTF8StringToUTF16String("az"));
matlab::data::TypedArray<double> result2 = matlabPtr->
getVariable(convertUTF8StringToUTF16String("el"));
matlab::data::TypedArray<double> result3 = matlabPtr->
getVariable(convertUTF8StringToUTF16String("r"));
// Display results
std::cout << "az: " << result1[0] << std::endl;
std::cout << "el: " << result2[0] << std::endl;
std::cout << "r: " << result3[0] << std::endl;
}
I use vs2013 and Matlab 2017b in windows 7.
Thanks for your help.

How can I overcome silent failure to change the PATH environment variable in VC++ 2013?

My goal is to write code that prepends a directory to the existing value of the PATH environment variable and sets the PATH environment variable to the new value for the duration of the program so that DLLs can be loaded from the new directory as well as from directories previously on the path. The code only needs to run on Windows and only needs to be compiled with Visual C++ 2013 and 2015. (Ideally, I'd like to be able to compile with MinGW as well, but the fact that there's no equivalent to /DELAYLOAD means that that may not be possible.)
I found, after experimentation, that SetEnvironmentVariable[W] silently fails to change the value of PATH, but _putenv, _putenv_s, _wputenv, and _wputenv_s work correctly --- but only on VC++ 2015. On VC++ 2013, they fail silently, and leave the value of PATH unchanged (the same way that SetEnvironmentVariable fails silently on VC++ 2013). I have not found any references to this behavior anywhere that I have searched on the Internet.
I can put up with using _putenv rather than SetEnvironmentVariable, but I need to figure out a way to change the value of PATH dynamically in VS2013, even if it's different from the way that works in VS2015.
UPDATE:
Here's prependDirToEnvVarW() (and getPathFromEnvVarW(), which it calls). prependDirToEnvVarW() works correctly on VC++ 2015 but silently fails to change the path on VC++ 2013.
inline std::wstring getPathFromEnvVarW()
{
DWORD bufferSize = GetEnvironmentVariableW(L"PATH", NULL, 0);
std::wstring ret(bufferSize, wchar_t(0));
DWORD getPathEnv = GetEnvironmentVariableW(L"PATH", &ret[0], bufferSize);
return (getPathEnv ? ret : L"");
}
inline bool prependDirToEnvVarW(const std::wstring & wstrDir)
{
const std::wstring PATH_VAR_NAME = L"PATH";
std::wstring wstrPrevPath = getPathFromEnvVarW();
std::wstring wstrValue = wstrDir;
if (!wstrValue.empty() && wstrValue[wstrValue.length() - 1] != L';')
{
wstrValue += L";";
}
wstrValue += wstrPrevPath;
std::replace(wstrValue.begin(), wstrValue.end(), L'/', L'\\');
errno_t retVal = _wputenv_s(PATH_VAR_NAME.c_str(), wstrValue.c_str());
std::cout << "Attempted to change PATH to:\n" <<
std::string(wstrValue.cbegin(), wstrValue.cend()) << std::endl;
if (retVal == 0)
{
return true;
}
else
{
std::cout << "retVal is nonzero: " << retVal
<< " (compare to EINVAL == " << EINVAL << ")" << std::endl;
return false;
}
}
The premise is incorrect. The PATH is the last thing searched for DLLs.
Instead, you should be calling SetDllDirectory() or AddDllDirectory() . This sets the DLL search path so that your added path is searched second, right after the executable directory.
If you need finer control than that, you will need to specify a full pathname to the LoadLibrary() function.

Unix/C++: Open new terminal and redirect output to it

My program (C++ on Solaris 10) writes output via wcout to its terminal when it is started from a shell. But when I execute it from within Sun Studio or the file manager is does not have a terminal and the ouput appears in the Sun Studio output window or nowhere at all.
I would like it to open its own terminal window in any of the three cases and attach wcout to this terminal window. I want this to be done be the program itself with C++ system calls not by the way how the program is executed from some shell or script. Because then execution in the Studio IDE and double-click in the file manager would still have the same effect.
Being a Windows programmer that seems quite natural to me but I could not find out how this is done in my Unix books nor in the web. Am I requesting the wrong thing, is it really so hard to do or am I missing something?
The following is close to what you want. It still has a few bugs:
The xterm cannot be normally closed (it closes when the program terminates, though). I have no idea why this is so.
Before the intended output, a number is output. Again, I have no idea why.
I don't seem to be able to redirect input.
Maybe someone else know how to fix those bugs (and any others I might not have noticed).
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <sstream>
int main()
{
int pt = posix_openpt(O_RDWR);
if (pt == -1)
{
std::cerr << "Could not open pseudo terminal.\n";
return EXIT_FAILURE;
}
char* ptname = ptsname(pt);
if (!ptname)
{
std::cerr << "Could not get pseudo terminal device name.\n";
close(pt);
return EXIT_FAILURE;
}
if (unlockpt(pt) == -1)
{
std::cerr << "Could not get pseudo terminal device name.\n";
close(pt);
return EXIT_FAILURE;
}
std::ostringstream oss;
oss << "xterm -S" << (strrchr(ptname, '/')+1) << "/" << pt << " &";
system(oss.str().c_str());
int xterm_fd = open(ptname,O_RDWR);
char c;
do read(xterm_fd, &c, 1); while (c!='\n');
if (dup2(pt, 1) <0)
{
std::cerr << "Could not redirect standard output.\n";
close(pt);
return EXIT_FAILURE;
}
if (dup2(pt, 2) <0)
{
std::cerr << "Could not redirect standard error output.\n";
close(pt);
return EXIT_FAILURE;
}
std::cout << "This should appear on the xterm." << std::endl;
std::cerr << "So should this.\n";
std::cin.ignore(1);
close(pt);
return EXIT_SUCCESS;
}
You want to output to a file (redirect, using a logging API or close stdout/reopen it as a file). And then tail it with tail -f in a terminal of your choice.
This has added benefit of saving your log output for review even if the terminal crashes/is killed.
When you invoke your program, instead of running: myprog 1 2 3 a b c, run xterm -e myprog 1 2 3 a b c.
I would recommnend to create a shell script that runs the terminal to which you pass your program to execute, then you should call that script instead of your program from the file manager.
Your script.sh:
#!/bin/sh
xterm -e /path_to_your_program/your_program
Using mknod to create pipe in /tmp every linux have /tmp and everyone always allowed to use it
system("mknod /tmp/printing_pipe pipe");
system("qterminal -e tail -f /tmp/printing_pipe");
write to the /tmp/printing_pipe to use it