Errno is not set using c++ system api while invoking powershell script - c++

I am using system api to invoke the powershell script and that script is not setting the errno to any value which is not giving me hint if the command execution is success or failure.
Below is my powersehll script which is simply setting the exit code, but this exit code is not set when I am calling this script using c++ system api.
test.ps1
#-------------------------------------------------------------------------------
function ExitWithCode {
#-------------------------------------------------------------------------------
param($exitcode)
$host.SetShouldExit($exitcode);
exit
}
ExitWithCode -exitcode 1
Execution of script using c++ program
string cmd = "";
std::getline(cin, cmd);
errno = 0;
cout <<" system " <<cmd << " ------> " << endl;
cout << system(cmd.c_str()) << " errno " << errno << endl;
Output of the c++ program
powershell -ExecutionPolicy Unrestricted -File "C:\test.ps1"
system powershell -ExecutionPolicy Unrestricted -File "C:\test.ps1" ------>
0 errno 0
system command output is 0 but the errno is alos set to 0. Any idea why the errno is not set?

The exit keyword in PowerShell sets the return code to 0 by default. As you are just calling exit without an argument, the return code will always be 0. Change your function to this:
#-------------------------------------------------------------------------------
function ExitWithCode {
#-------------------------------------------------------------------------------
param($exitcode)
exit $exitcode
}
ExitWithCode -exitcode 1
Or don't reinvent the wheel and just call:
exit 1

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.

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

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

Creating tar.gz-archive from c++ program does not work

I use the following code snippet for creating a tar.gz-archive in an extensive measurement software. After collecting some data in several files I want to archive and compress them for later use.
Everything works fine when I start the program from the shell, all the data is collected and archived correctly.
However the program should start automatically after system start of an embedded Linux system. When it's started via a script in /etc/init.d, no data files are archived/compressed, even though I get the return value 0. Furthermore, the tar.gz-file is created, but it's empty.
Everything else is working fine.
Can anyone please explain, what I have to do in this special case of an automatic start?
int returnValue = -1;
std::string jobString = RESULT_PATH;
jobString += "/";
jobString += lastJobString;
std::string jobFiles = lastJobString + "*.*";
std::string cmd = "tar cvf - ";
cmd += jobFiles;
cmd += " | gzip > ";
cmd += jobString;
cmd += ".tar.gz";
std::cout << "archiving and compressing " << jobFiles << ": " << cmd << std::flush << std::endl;
returnValue = system(cmd.c_str());
std::cout << "archiving and compressing finished. Code: " << returnValue << std::flush << std::endl;
I know that there are several librariers, like libarchive, libtar, etc. which to use is not as lazy as firing a system command, but I would like to know why this does not work for my case.
Furthermore, the version of tar in my busy box does not support option z.
I finally found a solution for my problem and maybe for all the cases when a system command is called by a daemon:
The trick is to create a new shell by the command sh and change the current directory before the tar-function is called:
std::string cmd = "sh -c \" cd ";
cmd += SOURCE_DIR;
cmd+= " && tar cvf - ";
cmd += jobFiles;
cmd += " | gzip > ";
cmd += jobString;
cmd += ".tar.gz";
returnValue = system(cmd.c_str());
Maybe this will help other users heading to the same problem.

Meaning of a numerical ErrorMessage

I am trying to interface with an OEM library. Everything worked on one computer but I am getting lots of problems on another computer.
I the code is throwing a COM exception but I can't figure out the meaning of a error code that doesn't have a ErrorMessage();
The code
#include "stdafx.h"
#include <afx.h>
#include <iostream>
using namespace std;
#import "MTBApi.tlb" named_guids //raw_interfaces_only
using namespace MTBApi;
void DisplayError(_com_error* e)
{
CString message;
// if it is an application error thrown by .NET
if (e->Error() >= 0x80041000)
{
IErrorInfo* info;
BSTR msg;
info = e->ErrorInfo();
info->GetDescription(&msg);
info->Release();
message = CString(msg);
}
// other com errors
else
{
message = e->ErrorMessage();
}
cout << "MTB Error: " << message <<":"<<(unsigned int) e->Error()<< endl;
}
int main(int argc, char **argv)
{
for (int i = 0 ; i < 4 ; i++)
{
IMTBConnectionPtr m_MTBConnection;
try
{
cout <<"1" << endl;
HRESULT a = CoInitializeEx(NULL,COINIT_SPEED_OVER_MEMORY);
cout <<"2" << endl;
m_MTBConnection = IMTBConnectionPtr(CLSID_MTBConnection);
cout <<"3" << endl;
m_MTBConnection->Close();
cout <<"4" << endl;
CoUninitialize();
cout <<"5" << endl;
}
catch(_com_error e)
{
DisplayError(&e);
}
cout << endl;
}
}
The runtime output
1
2
MTB Error: 00000000002205F8:2147746132
1
2
MTB Error: 00000000002205F8:2147746132
1
2
MTB Error: 00000000002205F8:2147746132
1
2
MTB Error: 00000000002205F8:2147746132
Rather Verbose Output from Dependency Walker
http://pastebin.com/7Y33z3Pj
cout << "MTB Error: " << message <<":"<<(unsigned int) e->Error()<< endl;
cout isn't very good at displaying Unicode strings, it merely displays the string pointer value. Not useful of course, use wcout instead. And favor displaying the error code in hex. 0x80040154 is a very common COM error, "Class not registered". Thousands of questions about it already, you just need to get the COM server registered properly. Ask the vendor or author if you don't know how to do that.
00000000002205F8 looks like a memory pointer. You are passing a CString to cout, which only accepts char* or std::string for string values. Maybe the CString contains a Unicode string that is not being converted to Ansi correctly. Also, when calling IErrorInfo::GetDescription(), you are leaking the returned BSTR. You need to free it with SysFreeString() when you are done using it.
Error code 2147746132 (hex 0x80040154) is Severity=FAIL, Facility=FACILITY_ITF, Code=340. FACILITY_ITF typically means the error code is a custom error code defined by the interface that failed. But in this case, 0x80040154 is also a standard error code: REGDB_E_CLASSNOTREG.
If your problem is to rectify the error which you are getting then
then issue is as #Remy pointed out , your com assembly is not registered in the machine you are currently executing your program rather in the other machine it got registered. Register the assembly (for eg COMAssembly.dll which is in C:\ drive) by running the following command in command prompt.
regsvr32 c:\COMAssembly.dll
if its a C++ com assembly , if its a C# assembly register it by using command
regasm c:\COMAssembly.dll
(where regasm can be run in a VS command prompt , otherwise if you are running in normal command prompt then you have to first call vsvars32.bat then call regasm)

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