I have manages to use ShellExecute in VC++ in order to launch a document.
Now I wish to run a command-line tool that receives some arguments, and to run in the background (as hidden, not minimized) and let it block my program flow, so that i'll be able to wait for it to finish.
How to i alter the command-line of:
ShellExecute(NULL,"open",FULL_PATH_TO_CMD_LINE_TOOL,ARGUMENTS,NULL,SW_HIDE);
The problem is, I have tool that converts html to pdf, and I wish that once the tool finished, aka pdf is ready, to have another ShellExecute to view it.
There is a CodeProject article that shows how, by using ShellExecuteEx instead of ShellExecute:
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = "c:\\MyProgram.exe";
ShExecInfo.lpParameters = "";
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
CloseHandle(ShExecInfo.hProcess);
The crucial point is the flag SEE_MASK_NOCLOSEPROCESS, which, as MSDN says
Use to indicate that the hProcess member receives the process handle. This handle is typically used to allow an application to find out when a process created with ShellExecuteEx terminates
Also, note that:
The calling application is responsible for closing the handle when it is no longer needed.
You can also use CreateProcess instead of ShellExecute/ShellExecuteEx. This function includes a cmd.exe wrapper option, returning the exit code, and returning stdout. (The includes may not be perfect).
Notes: In my use, I knew that there had to be stdout results, but the PeekedNamePipe function wouldn't always return the bytes count on the first try, hence the loop there. Perhaps, someone can figure this out and post a revision? Also, maybe an alternate version should be produced which returns stderr separately?
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <Shellapi.h>
/*
Note:
The exitCode for a "Cmd Process" is not the exitCode
for a sub process launched from it! That can be retrieved
via the errorlevel variable in the command line like so:
set errorlevel=&[launch command]&echo.&echo exitCode=%errorlevel%&echo.
The stdOut vector will then contain the exitCode on a seperate line
*/
BOOL executeCommandLine( const CStringW &command,
DWORD &exitCode,
const BOOL asCmdProcess=FALSE,
std::vector<CStringW> *stdOutLines=NULL )
{
// Init return values
BOOL bSuccess = FALSE;
exitCode = 0;
if( stdOutLines ) stdOutLines->clear();
// Optionally prepend cmd.exe to command line to execute
CStringW cmdLine( (asCmdProcess ? L"cmd.exe /C " : L"" ) +
command );
// Create a pipe for the redirection of the STDOUT
// of a child process.
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
bSuccess = CreatePipe( &g_hChildStd_OUT_Rd,
&g_hChildStd_OUT_Wr, &saAttr, 0);
if( !bSuccess ) return bSuccess;
bSuccess = SetHandleInformation( g_hChildStd_OUT_Rd,
HANDLE_FLAG_INHERIT, 0 );
if( !bSuccess ) return bSuccess;
// Setup the child process to use the STDOUT redirection
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Execute a synchronous child process & get exit code
bSuccess = CreateProcess( NULL,
cmdLine.GetBuffer(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo ); // receives PROCESS_INFORMATION
if( !bSuccess ) return bSuccess;
WaitForSingleObject( piProcInfo.hProcess, (DWORD)(-1L) );
GetExitCodeProcess( piProcInfo.hProcess, &exitCode );
CloseHandle( piProcInfo.hProcess );
CloseHandle( piProcInfo.hThread );
// Return if the caller is not requesting the stdout results
if( !stdOutLines ) return TRUE;
// Read the data written to the pipe
DWORD bytesInPipe = 0;
while( bytesInPipe==0 ){
bSuccess = PeekNamedPipe( g_hChildStd_OUT_Rd, NULL, 0, NULL,
&bytesInPipe, NULL );
if( !bSuccess ) return bSuccess;
}
if( bytesInPipe == 0 ) return TRUE;
DWORD dwRead;
CHAR *pipeContents = new CHAR[ bytesInPipe ];
bSuccess = ReadFile( g_hChildStd_OUT_Rd, pipeContents,
bytesInPipe, &dwRead, NULL);
if( !bSuccess || dwRead == 0 ) return FALSE;
// Split the data into lines and add them to the return vector
std::stringstream stream( pipeContents );
std::string str;
while( getline( stream, str ) )
stdOutLines->push_back( CStringW( str.c_str() ) );
return TRUE;
}
Using ShellExecuteEx sometimes doesn't work if COM is used, so the following remarks must be considered.
Because ShellExecuteEx can delegate execution to Shell extensions
(data sources, context menu handlers, verb implementations) that are
activated using Component Object Model (COM), COM should be
initialized before ShellExecuteEx is called. Some Shell extensions
require the COM single-threaded apartment (STA) type. In that case,
COM should be initialized as shown here:
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)
There are instances where ShellExecuteEx does not use one of these
types of Shell extension and those instances would not require COM to
be initialized at all. Nonetheless, it is good practice to always
initalize COM before using this function.
More from MSDN here
https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecuteexa
Related
I'm trying to check if a file on a jffs2 fs exist from a kernel space. I have a Barrier Breaker OpenWrt with a 3.10.14 Linux kernel. (There's an MTD subsystem in use, so I have pseudo block devices for partitions on a NAND flash (/dev/mtdblock1, ...12).)
(I'm implementing some upgrading logic which requires keeping some state between reboots, to store this state, I use the file.)
To check a file existence I just try to open the file (without an O_CREAT flag) and make a decision based on a result of opening. I use the next article about opening a file from within kernel: Read/write files within a Linux kernel module.
I'm able to check a file existence using this approach, but this file is placed not on a rootfs partition, so I have to mount that partition before I can open the file on it.
I'm able to mount the partition, open file (to check it existence) and close it, if it was opened, but failed to un-mount it: I got an error -16: EBUSY which, as I guess, means that someone else keep using this block device/mount point. So a question who can keep a reference on it?
I think it's a bad idea, but just to test, I tried to un-mount forcibly with an MNT_FORCE, but, as this article https://linux.die.net/man/2/umount states that this option only for NFS fs, nothing changed.
Here's a code:
/* lool at https://stackoverflow.com/questions/1184274/read-write-files-within-a-linux-kernel-module */
static struct file *file_open( const char *path, int flags, int rights )
{
struct file *filp = NULL;
mm_segment_t oldfs;
int err = 0;
oldfs = get_fs();
set_fs( get_ds() );
filp = filp_open( path, flags, rights );
set_fs( oldfs );
if( IS_ERR( filp ) )
{
err = PTR_ERR( filp );
return NULL;
}
return filp;
}
bool need_to_switch_to_me_upgrade_mode( void )
{
struct file* me_upgrade_finished_file;
dev_t me_upgrade_dev;
char full_name[256] = { 0 };
bool result;
int err;
const char* me_upgrade_dir = "/me_upgrade";
const char* me_upgrade_dev_name = "/dev/me_upgrade";
const char* me_upgrade_finished_flag = "/etc/me_upgrade_finished";
// /dev/mtdblock6
const char* me_upgrade_finished_flag_partition = "/dev/mtdblock" str( RECOVERY_ROOTFS_DATA_MTD_PART_NUM );
err = sys_mkdir( (const char __user __force *) me_upgrade_dir, 0700 );
if( err < 0 )
panic( "fail to mkdir %s\n", me_upgrade_dir );
me_upgrade_dev = name_to_dev_t( me_upgrade_finished_flag_partition );
err = create_dev( me_upgrade_dev_name, me_upgrade_dev );
if( err < 0 )
panic( "fail to create_dev %s\n", me_upgrade_dev_name );
err = sys_mount( me_upgrade_dev_name, me_upgrade_dir, "jffs2", MS_SILENT, NULL );
if( err < 0 )
panic( "fail to mount %s on to %s, err: %d\n", me_upgrade_dev_name, me_upgrade_dir, err );
strlcat( full_name, me_upgrade_dir, sizeof( full_name ) );
strlcat( full_name, me_upgrade_finished_flag, sizeof( full_name ) );
me_upgrade_finished_file = file_open( full_name, O_RDONLY, 0 );
if( !me_upgrade_finished_file )
{
printk( "fail to open a %s file\n", full_name );
result = true;
}
else
{
printk( "success to open a file\n" );
result = false;
}
if( me_upgrade_finished_file )
{
err = filp_close( me_upgrade_finished_file, NULL );
printk( "filp_close returned: %d\n", err );
}
err = sys_umount( me_upgrade_dir, MNT_DETACH );
printk( "sys_umount returned: %d\n", err );
sys_unlink( me_upgrade_dev_name ); // destroy_dev( me_upgrade_dev_name );
sys_rmdir( me_upgrade_dir );
return result;
}
This code is called from a kernel_init_freeable function (init/main.c) after we have MTD subsystem initialized (after do_basic_setup() and before a rootfs gets mounted).
So the questions are:
who can keep using a block device/mount point after I closed a file?
is any other ways to check if file exist from within kernel?
I have a second option, just to place my state in a partition without any fs, and check it by performing a raw access to the flash memory, but this approach will require significant changes to user code I have now, so I'm trying to avoid it...
P.S. I tried to change a call to file_open/filp_close by sys_open/sys_close (with the same arguments), but nothing changed...
I've somehow written a program to spawn a process but unable to kill it after 2 seconds automatically( It actually does not kill):
void createproc() {
//WaitForSingleObject(&processInfo.hProcess, INFINITE)
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
wchar_t commandline_args[] = L"\"C:\\ddnvnc\\WebServer.exe\" ";
if (!CreateProcess(NULL, // No module name (use command line)
commandline_args, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
MessageBox(NULL,
_T("Failed"),
_T("Windows Desktop Guided Tour"),
NULL);
}
Sleep(2000);
CloseHandle(&pi.hThread);
TerminateProcess(&pi.hProcess,0);
MessageBox(NULL,
_T("KIlled"),
_T("Windows Desktop Guided Tour"),
NULL);
}
What I want is to spawn and kill the process after 2 seconds, this will be in an infinite loop.
CloseHandle(&pi.hThread);
TerminateProcess(&pi.hProcess,0);
Use pi.hThread instead of &pi.hThread. Note that the order should be reversed.
You can use WaitForSingleObject instead of Sleep, and terminate the process only if it's not terminated already (for example by the user)
//Sleep(2000);
//TerminateProcess(pi.hProcess, 0);
if(WaitForSingleObject(pi.hProcess, 1000) == WAIT_TIMEOUT)
TerminateProcess(pi.hProcess, 0);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
I am using windows named pipe example. When I run sample programs to create pipe, write something and receive it in client program everything is just fine. When I move client code into dll, which runs in windows service it just won't receive sent bytes.
Server's code is as follows:
ThreadParams * params = reinterpret_cast<ThreadParams*>(args);
CString * connectionString = params->connectString;
HANDLE hPipe;
DWORD dwBytesRead;
TCHAR buf[1024];
int len;
hPipe = CreateNamedPipe(PIPE_NAME, // Name
PIPE_ACCESS_OUTBOUND | WRITE_OWNER, // OpenMode
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, // PipeMode
2, // MaxInstances
1024, // OutBufferSize
1024, // InBuffersize
2000, // TimeOut
NULL); // Security
if (hPipe == INVALID_HANDLE_VALUE)
{
Globals::WriteLog("Could not create the pipe",1);
exit(1);
}
Globals::WriteLog("connect...",1);
ConnectNamedPipe(hPipe, NULL);
Globals::WriteLog("...connected",1);
swprintf(buf, connectionString->GetBuffer());
len = wcslen(buf);
if (!WriteFile(hPipe, buf, len*sizeof(TCHAR), &dwBytesRead, NULL))
Globals::WriteLog("WriteFile failed",1);
else
wprintf(L"written %d bytes\n",dwBytesRead);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
And client:
CString finalResult = _T("");
HANDLE hOut = INVALID_HANDLE_VALUE;
TCHAR buf[1024];
DWORD len;
DWORD dwWritten;
Global::WriteLog("pwrite: waiting for the pipe...",1);
if (WaitNamedPipe(PIPE_NAME, NMPWAIT_WAIT_FOREVER) == 0)
{
Global::WriteLog("WaitNamedPipe failed. error=%d",1,GetLastError());
goto cleanup;
}
Global::WriteLog("the pipe is ready",1);
hOut = CreateFile(PIPE_NAME,
GENERIC_READ,
0,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hOut == INVALID_HANDLE_VALUE)
{
Global::WriteLog("CreateFile failed with error %d",1,GetLastError());
goto cleanup;
}
Global::WriteLog("Opened the pipe",1);
for (;;)
{
if (!ReadFile(hOut, buf, sizeof(buf), &dwWritten, NULL))
{
Global::WriteLog("ReadFile failed -- probably EOF. Read %d bytes.",1,dwWritten);
goto cleanup;
}
else
break;
}
finalResult = CString(buf);
Global::WriteLog("String from pipe:%S",1,buf);
cleanup:
if(hOut != INVALID_HANDLE_VALUE)
CloseHandle(hOut);
Server's code runs in a thread if that changes anything (I've tested it with this thread version in sample program and there was no problem with this).
Why does it not work?
Thanks in advance
Okay, it seems I figured it out. It seems I didn't understood documentation properly.
At server's side WriteFile function doesn't block until the string is read. My program simply wrote data and then closed handle - pipe. Client didn't catch the message and threw error stating that there is no process on the other side of pipe.
Also from client I removed for(;;) loop.
To wait for read operation on client side to complete I added
FlushFileBuffers(hPipe);
after successful write operation.
Hope that help somebody
(5) 0x1c6235e1 in ProxyClass::Method_C (this=0xb3a0c8, sendFilePath=...) at ./src/ProxyClass.cpp:112
(6) 0x2c8706c1 in Class1::Method_B (this=0x1fc5a1, profile=0x2c8f2340 "fileProfile1", filePathAndFileName=0x0) at ./src/Class1.cpp:860
(7) 0x2c4ae4c0 in Method_B (profile=0x42c <Address 0x42c out of bounds>, filePathAndFileName=0x0) at ./src/Class1_interface.cpp:310
(8) 0x2c1e5c3c in Method_A (profile=0x42c <Address 0x42c out of bounds>, filename=0x2c601c1c "/tmp/temporaryfile.tmp") at ./src/file.cpp:890
I have the above core file snippet that is debugged with gnu gdb. This core file is created on an embedded system running Linux. There is no manipulation to the variables within the function calls...
My questions are below:
How come the profile looks like Address 0x42c out of bounds on 8th frame and while there is no change to profile until the 9th frame how can that become something meaningful("fileSchema")?
My embedded system crashes because the filename(char *) equals to 0x2c601c1c and the path is printed like this on the 8 th frame "/tmp/temporaryfile.tmp". However, again without manipulation to filename variable, Method_A calls Method_B but the char pointer suddenly becomes null on 7th frame (filePathAndFileName=0x0). Then, my system crashes. How can that char * pointer transforms to NULL with manipulation?
The crash occurs on the 6th frame because in Class1::Method_B the following line is executed "std::string filePath( filePathAndFileName);". A null char pointer is being tried to get initialized to a string and I think it causes the crash and the Abort signal (Program terminated with signal 6, Aborted.). How can I avoid that char * to become null within the pass of that variable between the methods? Any idea why it becomes null?
static TUint16 Method_A(char* profile, char* filename)
{
TUint16 a; //after the call of Method_B,the other part of this method being processed but anyway the code never passes to there because of th crash..
Method_B(profile,filename);
...
...
...
return a;
}
unsigned char Method_B_interface(char* profile, char* filePathAndFileName)
{
unsigned char returnValue = 0;
if ( callbackObject->Method_B( profile, filePathAndFileName ) )
{
returnValue = 1;
}
return returnValue;
}
bool Class1::Method_B(char* profile, char* filePathAndFileName)
{
bool returnValue = true;
std::string filePathString( filePathAndFileName );
std::string profileString( profile );
if(profileString == "fileProfile1")
{
if(xClass != NULL)
{
returnValue = xClass->Method_C(filePathString);
}
}
...
...
...
return returnValue;
}
bool ProxyClass::Method_C(const std::string& exportFilePathAndFileName)
{
bool returnValue;
std::string message = "dummy", parameters;
Serializer::serialize( message, exportFilePathAndFileName );
proxyRequest->synchCall( message, parameters );
getResponse(parameters);
Serializer::deserialize( parameters, returnValue );
return returnValue;
}
I am creating a pty using openpty in C, and sharing it between master/parent and slave/child. The child could fork/exec and pass on the file descriptor to other programs. I want to inject commands to the child, but if I pass them immediately they get lost. How can I tell from the parent process that someone is blocking on input from stdin? I happen to be working on SUSE 10, but I would prefer a distro independent solution.
Edit : The answer to this question is still interesting to me, but may not be relevant to the problem. I'll get to that later.
A simplified version of the code would be to use the script source code (some of the headers may need to be fixed), and add the lines
char* command = "echo 'Hello World!'\r\n", written = 0;
(void)write(master, command, strlen(command));
(void)write(STDOUT_FILENO, "Sent command\r\n", 14);
before the big
for (;;) {
in main.
I had been executing a csh from script, but I then noticed that the script command was dumping some garbage (as viewed in vi)
^[[>0;115;0c
onto the parent's stdin. If I instead exec a bash shell, nothing gets dumped out and the program injects the command just fine.
I'm still curious as to the answer to the question being asked, but it is clearly no longer relevant to my problem, as there is something else going on. If anyone does know how to see if a pty is being read feel free to answer.
As far as I know, file descriptors will not survive a trip to another process. You can share them between threads, though.
As for knowing when there is something to read, I'd try using select with the appropriate file descriptor in the read set.
I have noticed same problem about losting stuff when I write to master fd.
Problem can be avoided by using the slave fd for writing. And the master fd for stdin of child.
This way:
int main(void)
{
int master_fd = -1;
int slave_fd = -1;
if( openpty( &master_fd, &slave_fd, NULL, NULL, NULL ) != -1 )
{
const pid_t child_pid = fork();
if( child_pid != -1 )
{
if( child_pid )
{
const char command[] = "command\n";
close( master_fd );
write( slave_fd, command, strlen(command) );
close( slave_fd );
}
else
{
close( slave_fd );
dup2( master_fd, STDIN_FILENO );
execlp( "/bin/cat", "cat", (char*)0 );
}
}
}
return 0;
}
You may even add delays to child process and it still works.
So parent process can exit before the child process do anything:
~ # temp_test
~ # command
cat: read error: Input/output error
~ #
EDIT:
Little bit different example, because error print out of cat causes confusing:
if( child_pid )
{
const char command[] = "command\n";
close( master_fd );
write( slave_fd, command, sizeof(command) );
close( slave_fd );
}
else
{
char buffer[100];
ssize_t i;
ssize_t len;
close( slave_fd );
do
{
len = read( master_fd, buffer, sizeof(buffer) );
for( i = 0; i < len; i++ )
printf("%c", buffer[i] );
} while( len > 0 );
}
And result:
~ # temp_test
command
~ #