Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.8k views
in Technique[技术] by (71.8m points)

c++ - How do I do popen() in Windows Console App

A Package like popen

I have spent some time researching the code that people have written to send data to and receive data from sub programs using

  • CreateProcess.lpCommandLine
  • STARTUPINFO.hStdInput as a file
  • STARTUPINFO.hStdInput as a pipe
  • STARTUPINFO.hStdOutput as a file
  • STARTUPINFO.hStdOutput as a pipe

The specific problems handled are

  • When to use cmd.exe
  • How to stay in the same window
  • How to detect when to send data

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The code is

#include   <stdio.h>
#include     <stdlib.h>
#include     <stdarg.h>
#include   <conio.h>
#include   <windows.h>
#include   <process.h>
#include     <sys/stat.h>

#if _MSC_VER < 1900
#define CONSTEXPR const
#else
#define CONSTEXPR constexpr
#endif

#if _DEBUG
#define NULL_OP stdout
#else
#define NULL_OP NULL
#endif


typedef short Cc;
#define OK 0
#define nullptr (0)

#define PATHCHR ';'
#define DIRSEPCHAR  '\'

#define NFILEN 256

#define in_range(a,b,c) ((unsigned)((a)-(b)) <= (unsigned)((c)-(b)) && ((signed)c)-(b) >= 0)


char * concat(char * tgt, ...)
{
  va_list ap;
  va_start(ap, tgt);

{ char * s;
  tgt[0] = 0;

  while ((s = va_arg(ap, char *)) != nullptr)
    strcat(tgt, s);

  return tgt;
}}

                    /* at most n chars including the 0 */

char * strpcpypfx(char * t_, const char * s_, int n_, char term)

{ short n;
  char ch;
  const char * s = s_;
  char * t = t_;

  for (n = -1; ++n < n_ && (ch = s[n]) != 0 && ch != term;
      )
    t[n] = ch;
  
  t[n] = 0;

  return t_;
}

                    /* at most n chars including the 0 */
char * strpcpy(char * t_, const char * s_, int n_)
#if 0
{ register short n = n_;
  register char * s = s_;
  register char * t = t_;
 
  if (t != null)
  { while (--n > 0 && (*t++ = *s++) != 0)
      ;
  
    if (n == 0)
      *t = 0;
  }
  return t_;
}
#else
{ return strpcpypfx(t_, s_, n_-1, 0);
}
#endif

/* ################# string match routines ##################### */

char bad_strmatch;

const char * com_match(const char * t_, const char * s_, int mask)

{ register int tix = 0;
  register const char * s = s_;
  register char ch;

#if CHARCODE != ASCII
  if (mask == 0x20)
    for (; *s != 0 && (ch = t_[tix]) != 0 && toupper(ch) == toupper(*s); ++s)
      ++tix;
  else 
#endif
    for (; *s != 0 && (ch = t_[tix]) != 0 && (ch | mask) == (*s | mask); ++s)
      ++tix;
  bad_strmatch = *s;
  return &t_[tix];
}

/* replace the last entry in dir by file */
/* t can equal dir */

char * pathcat(char * t, int bufsz, const char * dir, const char * file)
    
{ register int tix;

  if (dir[0] == '.' && dir[1] == '/' && dir[2] == '.' && dir[3] == '.' && dir[4] == '/')
    dir += 2;

  if (file[0] == '/' || file[0] == '\')
    strpcpy(t, file, bufsz);
  else
  { for (tix = -1; ++tix < bufsz - 1 && dir[tix] != 0; )
      t[tix] = dir[tix];

    t[tix] = 0;
   
    while (1)
    { while (--tix >= 0 && t[tix] != '/' && t[tix] != '\') /* strip back to / */
        ;

      if (tix > 0)
      { if (t[tix-1] != '.' &&
            file[0] == '.'  && file[1] == '.' && file[2] == '/')
        { for (file = &file[2]; *++file == '/';)        /* strip forward to non / */
            ;
          continue;
        }
      }

      break;
    }
  
  { int six = 0;
    for (; ++tix < bufsz - 1 && file[six] != 0; ++six)
      t[tix] = file[six];

    t[tix] = 0;
  }}
  return t;
}



int name_mode(const char * s)

{   struct stat fstat_;
    if (stat(s, &fstat_) != OK)
      return 0;
    return fstat_.st_mode;
}

#define fexist(fn) name_mode(fn)


static char fspec[256+2];   /* full path spec to search */

bool fex_path(const char * dir, const char * file)
    
{ if (dir != nullptr)
  { char * pc = pathcat(&fspec[0], sizeof(fspec), dir, file);
    if (fexist(pc))
      return true;
  }
  
  return false;  
}

#define INTWIDTH (sizeof(int) * 3)


char * int_asc(int i)
            /* integer to translate to a string */
{
  static char result[INTWIDTH+2];
    memset(&result, ' ', INTWIDTH); 

{   char *sp = &result[INTWIDTH+1];
    int v = i;      /* sign of resulting number */

    if (v < 0)
      v = -v;

    *sp = 0;
    do 
    { *(--sp) = '0' + v % 10;   /* and install the new digit */
      v = v / 10;
    } while (v);

    if (i < 0)
      *(--sp) = '-';        /* and install the minus sign */

    return sp;
}}



char * g_invokenm;


void flook_init(char * cmd)

{ g_invokenm = _strdup(cmd);

  if (g_invokenm[0] == '"')
  { ++g_invokenm;
    g_invokenm[strlen(g_invokenm)-1] = 0;
  }
{ char * sp;
  for (sp = g_invokenm; *sp != 0 && *sp != ' '; ++sp)
    if (*sp == '\')
      *sp = '/';

  if (*sp != 0)
    *sp = 0;

}}



/*  wh == I => 
    Look up the existence of a file in the current working directory || 
    along the include path in the INCLDIRS environment variable. 
    wh == E => 
    Look up the existence of a file in the current working directory || 
    along the normal $PATH
    else 
      if wh is in uppercase then look first in the $HOME directory
      always look up a file along the normal $PATH.
*/
const char * flook(char wh, const char * fname)

{          char uwh = toupper(wh);
  register char *path;  /* environmental PATH variable */
//         char buf[100];

    if (fexist(fname))
      return fname;
                              /* if we have an absolute path check only there! */
    if (*fname == '\' || *fname == '/' ||
        *fname != 0 && fname[1] == ':')
      return nullptr;

    //loglog1("not so far %s", fname);

    if (fname != g_invokenm)
  { if (fex_path(flook('E', g_invokenm), fname))
        return fspec;
    }

    path = getenv("PATH");

    if (path != nullptr)
      for (; *path != 0; ++path)
      { int ix;

        if (path[0] == '-' && path[1] == 'I'
         || path[0] == '.' && path[1] == '/')
          path += 2;

/*      fspec[0] = 0;
            if (inclmod != nullptr && path[0] != '/')
              strcpy(&fspec[0], inclmod);
*/
        for (ix = -1; ix < (int)sizeof(fspec)-2 &&
                       *path != 0
                   && *path != PATHCHR
                      ; )
          fspec[++ix] = *path++;
        
        if (path[-1] != DIRSEPCHAR)
          fspec[++ix] = '/';
            
        fspec[ix+1] = 0;            
/*  { char buf[200];
      strcat(strcat((buf, "PATHE "),fspec);
      MessageBox(nullptr, buf, "pe",MB_YESNO|MB_ICONQUESTION);
    } */
        if (fex_path(fspec, fname))
          return fspec;

        if (*path == 0)
          break;
      }

    return nullptr; /* no such luck */
}



char * mkTempName (/*out*/char *buf, const char *name)
{
#ifdef _CONVDIR_CHAR
 #define DIRY_CHAR _CONVDIR_CHAR
#else
 #define DIRY_CHAR DIRSEPCHAR
#endif
    static const char *tmpDir = NULL ;
                 char c2[2];
    const  char * td = tmpDir != NULL ? tmpDir : (char *)getenv("TEMP");

    c2[0] = c2[1] = 0;

    if (td == NULL)
#if (defined _DOS) || (defined _WIN32)
                        /* the C drive : better than ./ as ./ could be on a CD-Rom etc */
        td = "c:\" ;
#else
        td = "./" ;
#endif
    else
        if (td[strlen(td)-1] != DIRY_CHAR)
            c2[0] = DIRY_CHAR;
    
    tmpDir = td;
    concat(buf,td,c2,"me",int_asc(_getpid()),name,0);

    return &buf[strlen(buf)];
}


#define DUMMY_STDIN_FILE         "stdin.~~~" 

HANDLE CreateF(char * filenm)

{ int gen = GENERIC_WRITE;
    int share = FILE_SHARE_WRITE;
    int cmd = CREATE_ALWAYS;
    HANDLE Hdl;
    int ct = 2;

    (void)mkTempName(filenm, DUMMY_STDIN_FILE);
    
    for (; ;)
    {   Hdl = CreateFile(filenm,gen,share,NULL,
                                            cmd,FILE_ATTRIBUTE_NORMAL,NULL);
        if (--ct == 0)
            break;
        if (Hdl >= 0)                   /* VALID_HANDLE_VALUE */
            CloseHandle(Hdl);

        gen = GENERIC_READ;
        share = FILE_SHARE_READ;
        cmd = OPEN_ALWAYS;
    }

    return Hdl;
}


bool v_opt = false;

void mbwrite(const char * msg)

{ if (v_opt)
        printf("%s
", msg);
}



void flagerr(const char * fmt)

{ DWORD ec = GetLastError();
    fprintf(stderr, fmt, ec);
}


void ErrorMessage(const char *str)  //display detailed error info
{   LPVOID msg;
  FormatMessage(
              FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
              NULL,
              GetLastError(),
              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
              (LPTSTR) &msg,
              0,
              NULL
               );
    fprintf(stderr, "%s: %s
",str, (const char*)msg);
  LocalFree(msg);
}


void setMyConsoleIP()

{ HANDLE ConsIn = GetStdHandle( STD_INPUT_HANDLE );
  if (ConsIn < 0)                                       /* INVALID_HANDLE_VALUE */
    flagerr("Piperr %d");

/* SetStdHandle( STD_INPUT_HANDLE, g_ConsIn ); */
  if (0 == SetConsoleMode(ConsIn, ENABLE_WINDOW_INPUT))
    flagerr("PipeC %d");
}


class Pipe
{ public:
    enum Modes {    WL_IHAND = 1,
                                WL_SHELL = 2,
                                WL_AWAIT_PROMPT = 4,
                                WL_HOLD  = 8,
                                WL_CNC   = CREATE_NEW_CONSOLE,
                                WL_CNPG  = CREATE_NEW_PROCESS_GROUP,
                                WL_SPAWN   = 0x1000,
                                WL_SHOWW     = 0x2000,
                                WL_NOIHAND = 0x4000 };

    typedef unsigned int CmdMode;

    static int menu[4];

#if _MSC_VER >= 1900
  static_assert(WL_CNC > WL_HOLD && WL_CNPG > WL_HOLD);
#endif

    static
     Cc WinLaunch(Cc & sysRet, CmdMode flags,
                              const char *app = nullptr, const char * ca = nullptr, 
                    const char * in_data = nullptr, 
                    HANDLE ip = 0, const char *outfile = 0);        // char *outErr,
};

Cc Pipe::WinLaunch(Cc & sysRet, CmdMode flags,
                                     const char *app, const char * ca, 
                           const char * in_data, 
                           HANDLE ip, const char *outfile)  // char *outErr,
{ char buff[1024];           //i/o buffer
    const char * fapp = app == nullptr ? nullptr : flook('P', app);
    
    if      (fapp != nullptr)                   // never use comspec
        app = fapp;
    else if (flags & WL_SHELL)
    {   const char * comSpecName = (char*)getenv("COMSPEC");
        if (comSpecName == nullptr)
            comSpecName = "cmd.exe";

        if (ca == nullptr)
        { app = nullptr;
            ca = comSpecName;
        }
        else                                    /* Create the command line */
        { int len = strlen(concat(buff," /c "", app == nullptr ? "" : app,0));
            char * dd = buff+len;
            char ch;
            char prev = 'A';
            const char * ss = ca;
            if (len+strlen(ss) >= sizeof(buff))
                return -1;

            for (; (ch = *ss++); prev = ch)
            {   if (ch == '/' &&                                        // &&!(flags & LAUNCH_LEAVENAMES)
                      (in_range(toupper(prev), 'A','Z')
                  || in_range(prev, '0', '9')
                    ||                  prev == '_'  || prev == ' '))
                    ch = '\';
        
                if (ch == '"')
                    *dd++ = '\';
                *dd++ = ch;
            }

            *dd = '"';
            dd[1] = 0;
            ca = buff;
            app = comSpecName;
        }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...