Changeset 71 for trunk/src


Ignore:
Timestamp:
Jul 7, 2009, 1:49:11 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

corelib: OS/2: Partly implemented QProcess using native pipes (#7).

Location:
trunk/src/corelib/io
Files:
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/corelib/io/qprocess.cpp

    r2 r71  
    231231    \snippet doc/src/snippets/process/process.cpp 0
    232232
    233     \section1 Notes for Windows Users 
     233    \section1 Notes for Windows Users
    234234
    235235    Some Windows commands (for example, \c dir) are not provided by
     
    413413    processError = QProcess::UnknownError;
    414414    processState = QProcess::NotRunning;
     415#ifdef Q_OS_OS2
     416    pid = PID_NULL;
     417#else
    415418    pid = 0;
     419#endif
    416420    sequenceNumber = 0;
    417421    exitCode = 0;
     
    454458{
    455459    q_func()->setProcessState(QProcess::NotRunning);
     460#if !defined(Q_OS_OS2)
    456461#ifdef Q_OS_WIN
    457462    if (pid) {
     
    469474#endif
    470475    pid = 0;
     476#else
     477    pid = PID_NULL;
     478#endif
    471479    sequenceNumber = 0;
    472480    dying = false;
    473481
     482#if !defined(Q_OS_OS2)
    474483    if (stdoutChannel.notifier) {
    475484        stdoutChannel.notifier->setEnabled(false);
     
    504513    destroyPipe(stderrChannel.pipe);
    505514    destroyPipe(stdinChannel.pipe);
     515#else
     516    destroyPipe(stdoutChannel);
     517    destroyPipe(stderrChannel);
     518    destroyPipe(stdinChannel);
     519#endif
     520#if !defined(Q_OS_OS2)
    506521    destroyPipe(childStartedPipe);
    507522    destroyPipe(deathPipe);
     523#endif
    508524#ifdef Q_OS_UNIX
    509525    serial = 0;
     
    518534    qint64 available = bytesAvailableFromStdout();
    519535    if (available == 0) {
     536#if !defined(Q_OS_OS2)
    520537        if (stdoutChannel.notifier)
    521538            stdoutChannel.notifier->setEnabled(false);
    522539        destroyPipe(stdoutChannel.pipe);
     540#else
     541        destroyPipe(stdoutChannel);
     542#endif
    523543#if defined QPROCESS_DEBUG
    524544        qDebug("QProcessPrivate::canReadStandardOutput(), 0 bytes available");
     
    573593    qint64 available = bytesAvailableFromStderr();
    574594    if (available == 0) {
     595#if !defined(Q_OS_OS2)
    575596        if (stderrChannel.notifier)
    576597            stderrChannel.notifier->setEnabled(false);
    577598        destroyPipe(stderrChannel.pipe);
     599#else
     600        destroyPipe(stderrChannel);
     601#endif
    578602        return false;
    579603    }
     
    628652                                      writeBuffer.nextDataBlockSize());
    629653    if (written < 0) {
     654#if !defined(Q_OS_OS2)
    630655        destroyPipe(stdinChannel.pipe);
     656#else
     657        destroyPipe(stdinChannel);
     658#endif
    631659        processError = QProcess::WriteError;
    632660        q->setErrorString(QProcess::tr("Error writing to process"));
     
    766794            qDeleteInEventHandler(stdinChannel.notifier);
    767795            stdinChannel.notifier = 0;
    768         } 
     796        }
    769797    }
    770798#ifdef Q_OS_WIN
     
    773801    flushPipeWriter();
    774802#endif
     803#if !defined(Q_OS_OS2)
    775804    destroyPipe(stdinChannel.pipe);
     805#else
     806    destroyPipe(stdinChannel);
     807#endif
    776808}
    777809
     
    10751107/*!
    10761108    Returns the native process identifier for the running process, if
    1077     available.  If no process is currently running, 0 is returned.
     1109    available.  If no process is currently running, 0 is returned on all
     1110    platforms except OS/2 which returns PID_NULL in this case.
    10781111*/
    10791112Q_PID QProcess::pid() const
  • trunk/src/corelib/io/qprocess.h

    r2 r71  
    5656#if (!defined(Q_OS_WIN32) && !defined(Q_OS_WINCE)) || defined(qdoc)
    5757typedef qint64 Q_PID;
     58#elif defined(Q_OS_OS2)
     59typedef PID Q_PID;
     60#define PID_NULL PID(~0)
    5861#else
    5962QT_END_NAMESPACE
  • trunk/src/corelib/io/qprocess_os2.cpp

    r63 r71  
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    44** Contact: Qt Software Information (qt-info@nokia.com)
     5**
     6** Copyright (C) 2009 netlabs.org. OS/2 parts.
    57**
    68** This file is part of the QtCore module of the Qt Toolkit.
     
    4244#include "qprocess.h"
    4345#include "qprocess_p.h"
    44 #include "qwindowspipewriter_p.h"
    45 
    46 #include <qdatetime.h>
    47 #include <qdir.h>
    48 #include <qfileinfo.h>
    49 #include <qtimer.h>
    50 #include <qthread.h>
    51 #include <qmutex.h>
    52 #include <qwaitcondition.h>
    53 #include <private/qwineventnotifier_p.h>
    54 #include <private/qthread_p.h>
    55 #include <qdebug.h>
    56 
    57 #include "private/qfsfileengine_p.h" // for longFileName and win95FileName
     46// @todo need?
     47//#include "qwindowspipewriter_p.h"
     48
     49// @todo need what?
     50//#include <qdatetime.h>
     51//#include <qdir.h>
     52//#include <qfileinfo.h>
     53//#include <qtimer.h>
     54//#include <qthread.h>
     55//#include <qmutex.h>
     56//#include <qwaitcondition.h>
     57//#include <private/qthread_p.h>
     58//#include <qdebug.h>
    5859
    5960
     
    6465//#define QPROCESS_DEBUG
    6566
    66 #define NOTIFYTIMEOUT 100
    67 
    68 static void qt_create_pipe(Q_PIPE *pipe, bool in)
    69 {
    70     // Open the pipes.  Make non-inheritable copies of input write and output
    71     // read handles to avoid non-closable handles (this is done by the
    72     // DuplicateHandle() call).
    73 
    74 #if !defined(Q_OS_WINCE)
    75     SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE };
    76 
    77     HANDLE tmpHandle;
    78     if (in) {                   // stdin
    79         if (!CreatePipe(&pipe[0], &tmpHandle, &secAtt, 1024 * 1024))
    80             return;
    81         if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(),
    82                              &pipe[1], 0, FALSE, DUPLICATE_SAME_ACCESS))
    83             return;
    84     } else {                    // stdout or stderr
    85         if (!CreatePipe(&tmpHandle, &pipe[1], &secAtt, 1024 * 1024))
    86             return;
    87         if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(),
    88                              &pipe[0], 0, FALSE, DUPLICATE_SAME_ACCESS))
    89             return;
    90     }
    91 
    92     CloseHandle(tmpHandle);
    93 #else
    94         Q_UNUSED(pipe);
    95         Q_UNUSED(in);
    96 #endif
    97 }
     67// @todo need?
     68//#define NOTIFYTIMEOUT 100
     69
     70enum
     71{
     72    PIPE_SIZE_STDIN = 65520, // max
     73    PIPE_SIZE_STDOUT = 65520, // max
     74    PIPE_SIZE_STDERR = 4096,
     75
     76// @todo need?
     77//  POLL_TIMER = 100,
     78//
     79//  // new pipe data notification
     80//  WM_U_PIPE_RDATA = WM_USER + 0,
     81//  WM_U_PIPE_CLOSE = WM_USER + 1,
     82};
    9883
    9984/*
     
    10792
    10893    if (&channel == &stderrChannel && processChannelMode == QProcess::MergedChannels) {
    109         return DuplicateHandle(GetCurrentProcess(), stdoutChannel.pipe[1], GetCurrentProcess(),
    110                                &stderrChannel.pipe[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
    111     }
     94        // we will make a stdout to stderr redirection upon process startup
     95        channel.pipe = HP_NULL;
     96        channel.file = HF_NULL;
     97        return true;
     98    }
     99
     100    // we need the process identifier to guarantee pipe name unicity
     101    PPIB ppib = NULL;
     102    DosGetInfoBlocks(NULL, &ppib);
     103
     104    APIRET rc = 0;
     105    char pathBuf[CCHMAXPATH];
    112106
    113107    if (channel.type == Channel::Normal) {
    114         // we're piping this channel to our own process
    115         qt_create_pipe(channel.pipe, &channel == &stdinChannel);
     108        const char *name;
     109        ULONG pipeMode;
     110        ULONG outBufSize;
     111        ULONG inBufSize;
     112        ULONG fileMode;
     113        if (&channel == &stdinChannel) {
     114            name = "Stdin";
     115            pipeMode = NP_ACCESS_OUTBOUND;
     116            outBufSize = PIPE_SIZE_STDIN;
     117            inBufSize = 0;
     118            fileMode = OPEN_ACCESS_READONLY;
     119        } else if (&channel == &stdoutChannel) {
     120            name = "Stdout";
     121            pipeMode = NP_ACCESS_INBOUND;
     122            outBufSize = 0;
     123            inBufSize = PIPE_SIZE_STDOUT;
     124            fileMode = OPEN_ACCESS_WRITEONLY;
     125        } else if (&channel == &stderrChannel) {
     126            name = "Stderr";
     127            pipeMode = NP_ACCESS_INBOUND;
     128            outBufSize = 0;
     129            inBufSize = PIPE_SIZE_STDERR;
     130            fileMode = OPEN_ACCESS_WRITEONLY;
     131        } else {
     132            Q_ASSERT(false);
     133            return false;
     134        }
     135
     136        sprintf(pathBuf, "\\pipe\\Qt\\%08lX\\QProcess\\%p\\%s",
     137                ppib->pib_ulpid, name, this);
     138        rc = DosCreateNPipe(pathBuf, &channel.pipe,
     139                            pipeMode | NP_NOINHERIT, NP_NOWAIT | NP_TYPE_BYTE | 1,
     140                            outBufSize, inBufSize, 0);
     141        if (rc != NO_ERROR) {
     142            qWarning("QProcessPrivate::createChannel: DosCreateNPipe(%s) "
     143                     "returned %lu", pathBuf, rc);
     144            return false;
     145        }
     146        DosConnectNPipe(channel.pipe);
     147
     148        // open the client end of the pipe
     149        ULONG action = 0;
     150        rc = DosOpen(pathBuf, &channel.file, &action, 0, FILE_NORMAL, FILE_OPEN,
     151                     fileMode | OPEN_SHARE_DENYREADWRITE | OPEN_FLAGS_NOINHERIT,
     152                     (PEAOP2) NULL);
     153        if (rc != NO_ERROR) {
     154            qWarning("QProcessPrivate::createChannel: DosOpen(%s) "
     155                     "returned %lu", pathBuf, rc);
     156            return false;
     157        }
    116158
    117159        return true;
    118160    } else if (channel.type == Channel::Redirect) {
    119161        // we're redirecting the channel to/from a file
    120         SECURITY_ATTRIBUTES secAtt = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
     162        channel.pipe = HP_NULL;
     163        QByteArray fname = QFile::encodeName(channel.file);
     164        ULONG action = 0;
    121165
    122166        if (&channel == &stdinChannel) {
    123             // try to open in read-only mode
    124             channel.pipe[1] = INVALID_Q_PIPE;
    125             QT_WA({
    126                 channel.pipe[0] =
    127                     CreateFileW((TCHAR*)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
    128                                 GENERIC_READ,
    129                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
    130                                 &secAtt,
    131                                 OPEN_EXISTING,
    132                                 FILE_ATTRIBUTE_NORMAL,
    133                                 NULL);
    134             }, {
    135                 channel.pipe[0] =
    136                     CreateFileA(QFSFileEnginePrivate::win95Name(channel.file),
    137                                 GENERIC_READ,
    138                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
    139                                 &secAtt,
    140                                 OPEN_EXISTING,
    141                                 FILE_ATTRIBUTE_NORMAL,
    142                                 NULL);
    143             });
    144             if (channel.pipe[0] != INVALID_Q_PIPE)
     167            // open in read-only mode
     168            rc = DosOpen(fname, &channel.file, &action, 0, FILE_NORMAL, FILE_OPEN,
     169                         OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_NOINHERIT,
     170                         (PEAOP2) NULL);
     171            if (rc == NO_ERROR)
    145172                return true;
    146173
     
    148175        } else {
    149176            // open in write mode
    150             channel.pipe[0] = INVALID_Q_PIPE;
    151             DWORD creation;
    152             if (channel.append)
    153                 creation = OPEN_ALWAYS;
    154             else
    155                 creation = CREATE_ALWAYS;
    156 
    157             QT_WA({
    158                 channel.pipe[1] =
    159                     CreateFileW((TCHAR*)QFSFileEnginePrivate::longFileName(channel.file).utf16(),
    160                                 GENERIC_WRITE,
    161                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
    162                                 &secAtt,
    163                                 creation,
    164                                 FILE_ATTRIBUTE_NORMAL,
    165                                 NULL);
    166             }, {
    167                 channel.pipe[1] =
    168                     CreateFileA(QFSFileEnginePrivate::win95Name(channel.file),
    169                                 GENERIC_WRITE,
    170                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
    171                                 &secAtt,
    172                                 creation,
    173                                 FILE_ATTRIBUTE_NORMAL,
    174                                 NULL);
    175             });
    176             if (channel.pipe[1] != INVALID_Q_PIPE) {
     177            ULONG flags = channel.append ? FILE_OPEN : FILE_CREATE;
     178            rc = DosOpen(fname, &channel.file, &action, 0, FILE_NORMAL,
     179                         channel.append ? FILE_OPEN : FILE_CREATE,
     180                         OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_NOINHERIT,
     181                         (PEAOP2) NULL);
     182            if (rc == NO_ERROR) {
    177183                if (channel.append) {
    178                     SetFilePointer(channel.pipe[1], 0, NULL, FILE_END);
     184                    ULONG actual;
     185                    DosSetFilePtr(channel.file, 0, &actual);
    179186                }
    180187                return true;
     
    200207            sink = &channel.process->stdinChannel;
    201208
    202             if (source->pipe[1] != INVALID_Q_PIPE) {
    203                 // already constructed by the sink
    204                 // make it inheritable
    205                 HANDLE tmpHandle = source->pipe[1];
    206                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle,
    207                                      GetCurrentProcess(), &source->pipe[1],
    208                                      0, TRUE, DUPLICATE_SAME_ACCESS))
    209                     return false;
    210 
    211                 CloseHandle(tmpHandle);
    212                 return true;
    213             }
    214 
    215209            Q_ASSERT(source == &stdoutChannel);
    216210            Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);
    217 
    218             qt_create_pipe(source->pipe, /* in = */ false); // source is stdout
    219             sink->pipe[0] = source->pipe[0];
    220             source->pipe[0] = INVALID_Q_PIPE;
    221 
    222             return true;
    223211        } else {
    224212            // we are the sink;
     
    226214            sink = &channel;
    227215
    228             if (sink->pipe[0] != INVALID_Q_PIPE) {
    229                 // already constructed by the source
    230                 // make it inheritable
    231                 HANDLE tmpHandle = sink->pipe[0];
    232                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle,
    233                                      GetCurrentProcess(), &sink->pipe[0],
    234                                      0, TRUE, DUPLICATE_SAME_ACCESS))
    235                     return false;
    236 
    237                 CloseHandle(tmpHandle);
    238                 return true;
    239             }
    240216            Q_ASSERT(sink == &stdinChannel);
    241217            Q_ASSERT(source->process == this && source->type == Channel::PipeSource);
    242 
    243             qt_create_pipe(sink->pipe, /* in = */ true); // sink is stdin
    244             source->pipe[1] = sink->pipe[1];
    245             sink->pipe[1] = INVALID_Q_PIPE;
    246 
     218        }
     219
     220        if (source->pipe != HP_NULL && sink->file != HF_NULL) {
     221            // already created, do nothing
     222            Q_ASSERT(sink->pipe == HP_NULL && source->file == HF_NULL);
    247223            return true;
    248         }
    249     }
    250 }
    251 
    252 void QProcessPrivate::destroyPipe(Q_PIPE pipe[2])
    253 {
    254     if (pipe[0] == stdinChannel.pipe[0] && pipe[1] == stdinChannel.pipe[1] && pipeWriter) {
    255         delete pipeWriter;
    256         pipeWriter = 0;
    257     }
    258 
    259     if (pipe[0] != INVALID_Q_PIPE) {
    260         CloseHandle(pipe[0]);
    261         pipe[0] = INVALID_Q_PIPE;
    262     }
    263     if (pipe[1] != INVALID_Q_PIPE) {
    264         CloseHandle(pipe[1]);
    265         pipe[1] = INVALID_Q_PIPE;
    266     }
    267 }
    268 
    269 
    270 static QString qt_create_commandline(const QString &program, const QStringList &arguments)
    271 {
    272     QString args;
    273     if (!program.isEmpty()) {
    274         QString programName = program;
    275         if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1String(" ")))
    276             programName = QLatin1String("\"") + programName + QLatin1String("\"");
    277         programName.replace(QLatin1String("/"), QLatin1String("\\"));
    278 
    279         // add the prgram as the first arg ... it works better
    280         args = programName + QLatin1String(" ");
    281     }
    282 
    283     for (int i=0; i<arguments.size(); ++i) {
    284         QString tmp = arguments.at(i);
    285         // in the case of \" already being in the string the \ must also be escaped
    286         tmp.replace( QLatin1String("\\\""), QLatin1String("\\\\\"") );
    287         // escape a single " because the arguments will be parsed
    288         tmp.replace( QLatin1String("\""), QLatin1String("\\\"") );
    289         if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
    290             // The argument must not end with a \ since this would be interpreted
    291             // as escaping the quote -- rather put the \ behind the quote: e.g.
    292             // rather use "foo"\ than "foo\"
    293             QString endQuote(QLatin1String("\""));
    294             int i = tmp.length();
    295             while (i>0 && tmp.at(i-1) == QLatin1Char('\\')) {
    296                 --i;
    297                 endQuote += QLatin1String("\\");
     224        } else {
     225            // create a single pipe for both processes (source will get its handle)
     226            Q_ASSERT(source->pipe == HP_NULL && source->file == HF_NULL);
     227            Q_ASSERT(sink->pipe == HP_NULL && sink->file == HF_NULL);
     228
     229            sprintf(pathBuf, "\\pipe\\Qt\\%08lX\\QProcess\\%p\\SinkTo\\%p",
     230                    ppib->pib_ulpid, sink->process, source->process);
     231            rc = DosCreateNPipe(pathBuf, &source->pipe,
     232                                NP_ACCESS_OUTBOUND | NP_NOINHERIT, NP_NOWAIT | NP_TYPE_BYTE | 1,
     233                                PIPE_SIZE_STDOUT, 0, 0);
     234            if (rc != NO_ERROR) {
     235                qWarning("QProcessPrivate::createChannel: DosCreateNPipe(%s) "
     236                         "returned %lu", pathBuf, rc);
     237                return false;
    298238            }
    299             args += QLatin1String(" \"") + tmp.left(i) + endQuote;
    300         } else {
    301             args += QLatin1Char(' ') + tmp;
    302         }
    303     }
    304     return args;
    305 }
    306 
    307 static QByteArray qt_create_environment(const QStringList &environment)
    308 {
    309     QByteArray envlist;
    310     if (!environment.isEmpty()) {
    311         QStringList envStrings = environment;
    312             int pos = 0;
    313             // add PATH if necessary (for DLL loading)
    314         if (envStrings.filter(QRegExp(QLatin1String("^PATH="),Qt::CaseInsensitive)).isEmpty()) {
    315             QByteArray path = qgetenv("PATH");
    316             if (!path.isEmpty())
    317                 envStrings.prepend(QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path)));
    318         }
    319         // add systemroot if needed
    320         if (envStrings.filter(QRegExp(QLatin1String("^SystemRoot="),Qt::CaseInsensitive)).isEmpty()) {
    321             QByteArray systemRoot = qgetenv("SystemRoot");
    322             if (!systemRoot.isEmpty())
    323                 envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot)));
    324         }
    325 #ifdef UNICODE
    326         if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
    327             for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); ++it) {
    328                 QString tmp = *it;
    329                 uint tmpSize = sizeof(TCHAR) * (tmp.length()+1);
    330                 envlist.resize(envlist.size() + tmpSize);
    331                 memcpy(envlist.data()+pos, tmp.utf16(), tmpSize);
    332                 pos += tmpSize;
    333                 }
    334                 // add the 2 terminating 0 (actually 4, just to be on the safe side)
    335                 envlist.resize( envlist.size()+4 );
    336                 envlist[pos++] = 0;
    337                 envlist[pos++] = 0;
    338                 envlist[pos++] = 0;
    339                 envlist[pos++] = 0;
    340         } else
    341 #endif // UNICODE
    342         {
    343             for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); it++) {
    344                 QByteArray tmp = (*it).toLocal8Bit();
    345                 uint tmpSize = tmp.length() + 1;
    346                 envlist.resize(envlist.size() + tmpSize);
    347                 memcpy(envlist.data()+pos, tmp.data(), tmpSize);
    348                 pos += tmpSize;
     239            DosConnectNPipe(source->pipe);
     240
     241            // open the client end of the pipe that sink will get
     242            ULONG action = 0;
     243            rc = DosOpen(pathBuf, &sink->file, &action, 0, FILE_NORMAL, FILE_OPEN,
     244                         OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE | OPEN_FLAGS_NOINHERIT,
     245                         (PEAOP2) NULL);
     246            if (rc != NO_ERROR) {
     247                qWarning("QProcessPrivate::createChannel: DosOpen(%s) "
     248                         "returned %lu", pathBuf, rc);
     249                return false;
    349250            }
    350             // add the terminating 0 (actually 2, just to be on the safe side)
    351             envlist.resize(envlist.size()+2);
    352             envlist[pos++] = 0;
    353             envlist[pos++] = 0;
    354         }
    355     }
    356     return envlist;
    357 }
     251
     252            source->file = HF_NULL;
     253            sink->pipe = HP_NULL;
     254            return true;
     255        }
     256    }
     257}
     258
     259void QProcessPrivate::destroyPipe(QProcessPrivate::Channel &channel)
     260{
     261    if (channel.file != HF_NULL) {
     262        DosClose(channel.file);
     263        channel.file = HP_NULL;
     264    }
     265
     266    if (channel.pipe != HP_NULL) {
     267        DosDisConnectPipe(channel.pipe);
     268        DosClose(channel.pipe);
     269        channel.pipe = HP_NULL;
     270    }
     271}
     272
     273// @todo need?
     274//static QString qt_create_commandline(const QString &program, const QStringList &arguments)
     275//{
     276//    QString args;
     277//    if (!program.isEmpty()) {
     278//        QString programName = program;
     279//        if (!programName.startsWith(QLatin1Char('\"')) && !programName.endsWith(QLatin1Char('\"')) && programName.contains(QLatin1String(" ")))
     280//            programName = QLatin1String("\"") + programName + QLatin1String("\"");
     281//        programName.replace(QLatin1String("/"), QLatin1String("\\"));
     282//
     283//        // add the prgram as the first arg ... it works better
     284//        args = programName + QLatin1String(" ");
     285//    }
     286//
     287//    for (int i=0; i<arguments.size(); ++i) {
     288//        QString tmp = arguments.at(i);
     289//        // in the case of \" already being in the string the \ must also be escaped
     290//        tmp.replace( QLatin1String("\\\""), QLatin1String("\\\\\"") );
     291//        // escape a single " because the arguments will be parsed
     292//        tmp.replace( QLatin1String("\""), QLatin1String("\\\"") );
     293//        if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
     294//            // The argument must not end with a \ since this would be interpreted
     295//            // as escaping the quote -- rather put the \ behind the quote: e.g.
     296//            // rather use "foo"\ than "foo\"
     297//            QString endQuote(QLatin1String("\""));
     298//            int i = tmp.length();
     299//            while (i>0 && tmp.at(i-1) == QLatin1Char('\\')) {
     300//                --i;
     301//                endQuote += QLatin1String("\\");
     302//            }
     303//            args += QLatin1String(" \"") + tmp.left(i) + endQuote;
     304//        } else {
     305//            args += QLatin1Char(' ') + tmp;
     306//        }
     307//    }
     308//    return args;
     309//}
     310//
     311//static QByteArray qt_create_environment(const QStringList &environment)
     312//{
     313//    QByteArray envlist;
     314//    if (!environment.isEmpty()) {
     315//        QStringList envStrings = environment;
     316//        int pos = 0;
     317//        // add PATH if necessary (for DLL loading)
     318//        if (envStrings.filter(QRegExp(QLatin1String("^PATH="),Qt::CaseInsensitive)).isEmpty()) {
     319//            QByteArray path = qgetenv("PATH");
     320//            if (!path.isEmpty())
     321//                envStrings.prepend(QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path)));
     322//        }
     323//        // add systemroot if needed
     324//        if (envStrings.filter(QRegExp(QLatin1String("^SystemRoot="),Qt::CaseInsensitive)).isEmpty()) {
     325//            QByteArray systemRoot = qgetenv("SystemRoot");
     326//            if (!systemRoot.isEmpty())
     327//                envStrings.prepend(QString(QLatin1String("SystemRoot=%1")).arg(QString::fromLocal8Bit(systemRoot)));
     328//        }
     329//#ifdef UNICODE
     330//        if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
     331//            for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); ++it) {
     332//                QString tmp = *it;
     333//                uint tmpSize = sizeof(TCHAR) * (tmp.length()+1);
     334//                envlist.resize(envlist.size() + tmpSize);
     335//                memcpy(envlist.data()+pos, tmp.utf16(), tmpSize);
     336//                pos += tmpSize;
     337//            }
     338//            // add the 2 terminating 0 (actually 4, just to be on the safe side)
     339//            envlist.resize( envlist.size()+4 );
     340//            envlist[pos++] = 0;
     341//            envlist[pos++] = 0;
     342//            envlist[pos++] = 0;
     343//            envlist[pos++] = 0;
     344//        } else
     345//#endif // UNICODE
     346//        {
     347//            for (QStringList::ConstIterator it = envStrings.constBegin(); it != envStrings.constEnd(); it++) {
     348//                QByteArray tmp = (*it).toLocal8Bit();
     349//                uint tmpSize = tmp.length() + 1;
     350//                envlist.resize(envlist.size() + tmpSize);
     351//                memcpy(envlist.data()+pos, tmp.data(), tmpSize);
     352//                pos += tmpSize;
     353//            }
     354//            // add the terminating 0 (actually 2, just to be on the safe side)
     355//            envlist.resize(envlist.size()+2);
     356//            envlist[pos++] = 0;
     357//            envlist[pos++] = 0;
     358//        }
     359//    }
     360//    return envlist;
     361//}
    358362
    359363void QProcessPrivate::startProcess()
     
    362366
    363367    bool success = false;
    364 
    365     if (pid) {
    366         CloseHandle(pid->hThread);
    367         CloseHandle(pid->hProcess);
    368         delete pid;
    369         pid = 0;
    370     }
    371     pid = new PROCESS_INFORMATION;
    372     memset(pid, 0, sizeof(PROCESS_INFORMATION));
    373368
    374369    q->setProcessState(QProcess::Starting);
     
    379374        return;
    380375
    381 #if defined(Q_OS_WINCE)
    382     QString args = qt_create_commandline(QString(), arguments);
    383 #else
    384     QString args = qt_create_commandline(program, arguments);
    385     QByteArray envlist = qt_create_environment(environment);
    386 #endif
    387 
    388 #if defined QPROCESS_DEBUG
    389     qDebug("Creating process");
    390     qDebug("   program : [%s]", program.toLatin1().constData());
    391     qDebug("   args : %s", args.toLatin1().constData());
    392     qDebug("   pass environment : %s", environment.isEmpty() ? "no" : "yes");
    393 #endif
    394 
    395     DWORD dwCreationFlags = 0;
    396     if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based))
    397         dwCreationFlags |= CREATE_NO_WINDOW;
    398 
    399 #ifdef UNICODE
    400     if (!(QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)) {
    401 #if defined(Q_OS_WINCE)
    402         QString fullPathProgram = program;
    403         if (!QDir::isAbsolutePath(fullPathProgram))
    404             fullPathProgram = QFileInfo(fullPathProgram).absoluteFilePath();
    405         fullPathProgram.replace(QLatin1String("/"), QLatin1String("\\"));
    406         success = CreateProcessW((WCHAR*)fullPathProgram.utf16(),
    407                                  (WCHAR*)args.utf16(),
    408                                  0, 0, false, 0, 0, 0, 0, pid);
    409 #else
    410         dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
    411         STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
    412                                          (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
    413                                          (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
    414                                          0, 0, 0,
    415                                          STARTF_USESTDHANDLES,
    416                                          0, 0, 0,
    417                                          stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1]
    418         };
    419         success = CreateProcessW(0, (WCHAR*)args.utf16(),
    420                                  0, 0, TRUE, dwCreationFlags,
    421                                  environment.isEmpty() ? 0 : envlist.data(),
    422                                  workingDirectory.isEmpty() ? 0
    423                                     : (WCHAR*)QDir::toNativeSeparators(workingDirectory).utf16(),
    424                                  &startupInfo, pid);
    425 #endif
    426     } else
    427 #endif // UNICODE
    428     {
    429 #ifndef Q_OS_WINCE
    430             STARTUPINFOA startupInfo = { sizeof( STARTUPINFOA ), 0, 0, 0,
    431                                          (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
    432                                          (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
    433                                          0, 0, 0,
    434                                          STARTF_USESTDHANDLES,
    435                                          0, 0, 0,
    436                                          stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1]
    437             };
    438 
    439             success = CreateProcessA(0, args.toLocal8Bit().data(),
    440                                      0, 0, TRUE, dwCreationFlags, environment.isEmpty() ? 0 : envlist.data(),
    441                                      workingDirectory.isEmpty() ? 0
    442                                         : QDir::toNativeSeparators(workingDirectory).toLocal8Bit().data(),
    443                                      &startupInfo, pid);
    444 #endif // Q_OS_WINCE
    445     }
    446 #ifndef Q_OS_WINCE
    447     if (stdinChannel.pipe[0] != INVALID_Q_PIPE) {
    448         CloseHandle(stdinChannel.pipe[0]);
    449         stdinChannel.pipe[0] = INVALID_Q_PIPE;
    450     }
    451     if (stdoutChannel.pipe[1] != INVALID_Q_PIPE) {
    452         CloseHandle(stdoutChannel.pipe[1]);
    453         stdoutChannel.pipe[1] = INVALID_Q_PIPE;
    454     }
    455     if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
    456         CloseHandle(stderrChannel.pipe[1]);
    457         stderrChannel.pipe[1] = INVALID_Q_PIPE;
    458     }
    459 #endif // Q_OS_WINCE
     376// @todo remove
     377//#if defined(Q_OS_WINCE)
     378//    QString args = qt_create_commandline(QString(), arguments);
     379//#else
     380//    QString args = qt_create_commandline(program, arguments);
     381//    QByteArray envlist = qt_create_environment(environment);
     382//#endif
     383//
     384//#if defined QPROCESS_DEBUG
     385//    qDebug("Creating process");
     386//    qDebug("   program : [%s]", program.toLatin1().constData());
     387//    qDebug("   args : %s", args.toLatin1().constData());
     388//    qDebug("   pass environment : %s", environment.isEmpty() ? "no" : "yes");
     389//#endif
     390
     391
     392
     393
     394
     395
     396
     397
     398
     399
     400
     401
     402
    460403
    461404    if (!success) {
     
    470413    q->setProcessState(QProcess::Running);
    471414    // User can call kill()/terminate() from the stateChanged() slot
    472     // so check before proceeding 
    473     if (!pid)
     415    // so check before proceeding
     416    if (pid == PID_NULL)
    474417        return;
    475418
    476     if (threadData->eventDispatcher) {
    477         processFinishedNotifier = new QWinEventNotifier(pid->hProcess, q);
    478         QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_processDied()));
    479         processFinishedNotifier->setEnabled(true);
    480         notifier = new QTimer(q);
    481         QObject::connect(notifier, SIGNAL(timeout()), q, SLOT(_q_notified()));
    482         notifier->start(NOTIFYTIMEOUT);
    483     }
    484 
    485     // give the process a chance to start ...
    486     Sleep(SLEEPMIN*2);
     419// @todo check this
    487420    _q_startupNotification();
    488421}
     
    875808                                   };
    876809        success = CreateProcessW(0, (WCHAR*)args.utf16(),
    877                                  0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, 0, 
     810                                 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, 0,
    878811                                 workingDir.isEmpty() ? (const WCHAR *)0 : (const WCHAR *)workingDir.utf16(),
    879812                                 &startupInfo, &pinfo);
  • trunk/src/corelib/io/qprocess_p.h

    r2 r71  
    5959#include "private/qiodevice_p.h"
    6060
    61 #ifdef Q_OS_WIN
     61#if defined(Q_OS_WIN)
    6262#include "QtCore/qt_windows.h"
    6363typedef HANDLE Q_PIPE;
    6464#define INVALID_Q_PIPE INVALID_HANDLE_VALUE
     65#elif defined(Q_OS_OS2)
     66#include "QtCore/qt_os2.h"
     67#define HP_NULL HPIPE(~0)
     68#define HF_NULL HFILE(~0)
    6569#else
    6670typedef int Q_PIPE;
     
    9397        Channel() : process(0), notifier(0), type(Normal), closed(false), append(false)
    9498        {
     99#if !defined(Q_OS_OS2)
    95100            pipe[0] = INVALID_Q_PIPE;
    96101            pipe[1] = INVALID_Q_PIPE;
     102#else
     103            pipe = HP_NULL;
     104            file = HF_NULL;
     105#endif
    97106        }
    98107
     
    123132        QString file;
    124133        QProcessPrivate *process;
     134#if !defined(Q_OS_OS2)
    125135        QSocketNotifier *notifier;
    126136        Q_PIPE pipe[2];
     137#else
     138        HPIPE pipe;
     139        HFILE file;
     140#endif
    127141
    128142        unsigned type : 2;
     
    168182    QRingBuffer writeBuffer;
    169183
     184#if !defined(Q_OS_OS2)
    170185    Q_PIPE childStartedPipe[2];
    171186    Q_PIPE deathPipe[2];
     
    179194    QWindowsPipeWriter *pipeWriter;
    180195    QWinEventNotifier *processFinishedNotifier;
     196#else
     197    void destroyPipe(Channel &channel);
     198#endif
    181199
    182200    void startProcess();
Note: See TracChangeset for help on using the changeset viewer.