1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
/*-------------------------------------------------------------------*/
/* CONSPAWN.C (c) "Fish" (David B. Trout), 2005-2006 */
/* This program is spawned by Hercules as a result of */
/* the 'sh' (shell) command. It's purpose is to simply */
/* call the host's shell (command interpreter) program */
/* with the arguments supplied (usually to invoke yet */
/* another program), redirecting the results back to */
/* Hercules for display. NOTE that this program does */
/* not perform the actual stdio redirection itself, but */
/* rather relies on Hercules to have set that up before */
/* invoking this program. */
/*-------------------------------------------------------------------*/
// $Id: conspawn.c 5147 2009-02-01 21:27:16Z rbowler $
//
// $Log$
// Revision 1.3 2006/12/08 09:43:18 jj
// Add CVS message log
//
#include "hstdinc.h"
#define PGMNAME "conspawn"
int main(int argc, char* argv[])
{
int i, k, rc;
char* p;
#ifdef _MSVC_
#pragma comment(lib,"shell32.lib") // (need ShellExecute)
// --------------------------------------------------------
// PROGRAMMING NOTE: We MUST use "ShellExecute" for Windows
// GUI programs since: 1) GUI programs don't use stdio,
// 2) they never exit until the user manually closes them.
//
// Erroneously using the 'system()' function to start a GUI
// program causes HercGUI to hang at PowerOff as it waits
// for its child process to close its stdio handles which
// GUI programs never do until they exit (which they never
// do until the user manually closes them).
//
// The reason this phenomenon occurs even though Hercules
// does indeed close ITS OWN stdio handles when it ends is
// because its child processes that it creates ALSO inherit
// the same stdio handles! (I.e. the GUI programs that Herc
// starts end up never closing "Herc's" [inherited] stdio
// handles, which are the same handles that HercGUI waits
// on! Thus GUI programs started by Herc using the 'system'
// API end up hanging HercGUI! (during Herc PowerOff))
//
// Thus, for GUI apps, we MUST use "ShellExecute" here
// to prevent HercGUI from hanging at PowerOff. Also note
// that this hang obviously does not occur when Hercules
// is run in command-line (non-HercGUI) mode even when
// the 'system()' API is erroneously used, since Herc is
// obviously (duh!) not being run under the control of an
// external GUI in such a situation. -- Fish, Aug. 2006
// --------------------------------------------------------
if (argc >= 2 && strcasecmp(argv[1],"startgui") == 0)
{
////////////////////////////////////////////////////////
// Windows GUI program; no stdio; use 'ShellExecute'...
////////////////////////////////////////////////////////
// REFERENCE: upon entry:
// argv[0] "conspawn"
// argv[1] "startgui"
// argv[2] (program to start)
// argv[3..n] (arguments for program)
HWND hwnd = NULL;
LPCTSTR lpOperation = NULL;
LPCTSTR lpFile = argv[2];
LPCTSTR lpParameters = NULL;
LPCTSTR lpDirectory = NULL;
INT nShowCmd = SW_SHOWNORMAL;
char* pszErrMsg = NULL;
// Build arguments string from passed args...
for (i=3, k=0; i < argc; i++)
k += strlen(argv[i]) + 1;
if (k)
{
// (allocate room for arguments string)
if (!(p = malloc(sizeof(char)*k)))
{
errno = ENOMEM;
perror( PGMNAME );
return -1;
}
*p = 0;
// (build arguments string from args)
for (i=3; i < argc; ++i)
{
strcat(p,argv[i]);
if (i != (argc-1)) strcat(p," ");
}
lpParameters = p;
}
else
p = NULL;
rc = (intptr_t) ShellExecute( hwnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd );
if (p)
free(p);
if ( rc > 32)
return 0; // rc > greater than 32 == success...
// rc <= less than or equal 32 == error...
switch (rc)
{
case 0: pszErrMsg = "The operating system is out of memory or resources"; break;
case SE_ERR_FNF: pszErrMsg = "The specified file was not found"; break;
case SE_ERR_PNF: pszErrMsg = "The specified path was not found"; break;
case SE_ERR_ACCESSDENIED: pszErrMsg = "The operating system denied access to the specified file"; break;
case ERROR_BAD_FORMAT: pszErrMsg = "The .exe file is invalid (non-Microsoft Win32 .exe or error in .exe image)"; break;
case SE_ERR_OOM: pszErrMsg = "There was not enough memory to complete the operation"; break;
case SE_ERR_DLLNOTFOUND: pszErrMsg = "The specified dynamic-link library (DLL) was not found"; break;
case SE_ERR_SHARE: pszErrMsg = "A sharing violation occurred"; break;
case SE_ERR_ASSOCINCOMPLETE: pszErrMsg = "The file name association is incomplete or invalid"; break;
case SE_ERR_DDETIMEOUT: pszErrMsg = "The DDE transaction could not be completed because the request timed out"; break;
case SE_ERR_DDEFAIL: pszErrMsg = "The DDE transaction failed"; break;
case SE_ERR_DDEBUSY: pszErrMsg = "The Dynamic Data Exchange (DDE) transaction could not be completed because other DDE transactions were being processed"; break;
case SE_ERR_NOASSOC: pszErrMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable"; break;
default:
printf(PGMNAME": ShellExecute(\"%s\", \"%s\",...) failed: Unknown error; rc=%d (0x%08.8X).\n",
lpFile, lpParameters, rc, rc );
return -1;
}
printf( PGMNAME": ShellExecute(\"%s\", \"%s\",...) failed: %s.\n",
lpFile, lpParameters, pszErrMsg );
return -1;
}
#endif // _MSVC_
////////////////////////////////////////////////////////
// Command line program using stdio; use 'system()'...
////////////////////////////////////////////////////////
// Re-build a complete command line from passed args...
for (i=1, k=0; i < argc; i++)
k += strlen(argv[i]) + 1;
if (!k)
{
errno = EINVAL;
perror( PGMNAME );
printf( PGMNAME": Usage: command [args]\n");
return -1;
}
// (allocate room for command line)
if (!(p = malloc(sizeof(char)*k)))
{
errno = ENOMEM;
perror( PGMNAME );
return -1;
}
*p = 0;
// (rebuild command-line from args)
for (i=1; i < argc; ++i)
{
strcat(p,argv[i]);
if (i != (argc-1)) strcat(p," ");
}
// Ask system() to process command line...
// NOTE: the below call WILL NOT RETURN
// until the program being called exits!
rc = system(p);
free(p);
// --------------------------------------------------------
// PROGRAMMING NOTE: only rc == -1 need be reported since,
// if the command interpreter called a batch/cmd file for
// example, it could have set its own custom return code.
//
// Only -1 means the system() call itself failed, which
// is the only thing that actually needs to be reported.
// --------------------------------------------------------
if ( -1 == rc )
perror( PGMNAME );
return rc;
}
|