WinProcess.cpp
上传用户:cnxinhai
上传日期:2013-08-06
资源大小:265k
文件大小:13k
- /* This is the class that handles the Windows system functionality.
- * Process and thread stuff is handled here.
- *
- * Copyright (C) 2001, 2002 Adam Schlag
- */
- /*
- * FreeBurn Software License
- * (based on the Apache Software License)
- *
- * Version 1.1
- *
- * Copyright (c) 2001, 2002 The FreeBurn Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. The end-user documentation included with the redistribution, if any, must
- * include the following acknowledgment:
- *
- * "This product includes software developed by the FreeBurn
- * Project (http://freeburn.sourceforge.net/)."
- *
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "FreeBurn" and "FreeBurn Project" must not be
- * used to endorse or promote products derived from this software
- * without prior written permission. For written permission, please
- * contact aschlag@users.sourceforge.net.
- *
- * 5. Products derived from this software may not be called "FreeBurn",
- * nor may "FreeBurn" appear in their name, without prior written
- * permission of the FreeBurn Project.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE FREEBURN PROJECT OR ITS
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the FreeBurn Project. For more
- * information on the FreeBurn Project and FreeBurn, please see
- * <http://freeburn.sourceforge.net/>.
- *
- * This software is distributed with software that is released under the GNU
- * General Public License (GPL). You can find the terms of this license in the
- * file GPL.txt distributed in this package. You can find information on the
- * software distributed with this package in the file PROGRAMS.txt.
- */
- // included for using Windows process/thread stuff
- #include <windows.h>
- // include file for FOX library
- #include <fx.h>
- // include file for BaseThread, so we can use CBaseThread
- #include "BaseThread.h"
- // include file for this class
- #include "WinProcess.h"
- // top-level FreeBurn include/definition file
- #include "FreeburnDefs.h"
- // This constructor sets up all the class data
- // that will be used later
- CWinProcess::CWinProcess() : CBaseThread()
- {
- // We want these handles to be inherited by
- // the thread we'll create, so we need to set
- // up a SECURITY_ATTRIBUTES struct saying that
- // we want to do that.
- SECURITY_ATTRIBUTES sa;
- // set the length of sa to the size of SECURITY_ATTRIBUTES
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- // sa is only used to set up events, so it doesn't matter
- // if handles are inherited, and we don't need a Security
- // Descriptor pointer, so we set these as follows:
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
- // Initialize to some kind of null value the basic class data
- m_stdoutReadHandle = NULL;
- m_stdinWriteHandle = NULL;
- m_charsRead = 0;
- strcpy(m_readBuffer, "");
- // This creates the event that output is ready
- // to be read from using getStringText()
- m_processEvent = CreateEvent(&sa, FALSE, FALSE, "WinProcessEvent");
- // This creates the event that the process is complete
- m_completeEvent = CreateEvent(&sa, FALSE, FALSE, "WinProcessCompleteEvent");
- // This creates the semaphore to serialize reading/writing to m_readBuffer
- m_threadSemaphore = CreateSemaphore(&sa, 0, 1, "WinProcessSemaphore");
- }
- // Class destructor, closes all open handles
- CWinProcess::~CWinProcess()
- {
- CloseHandle(m_processEvent);
- CloseHandle(m_completeEvent);
- CloseHandle(m_threadSemaphore);
- }
- // returns m_processEvent
- FXInputHandle CWinProcess::getProcessEventHandle()
- {
- return m_processEvent;
- }
- // returns m_completeEvent
- FXInputHandle CWinProcess::getCompleteEventHandle()
- {
- return m_completeEvent;
- }
- // This creates the process with the given command
- FXint CWinProcess::createCommandWithPipes(FXString& commandString)
- {
- // Handles for creating the pipes
- HANDLE hTempStdoutRead;
- HANDLE hTempStdinWrite;
- HANDLE hStdinRead;
- HANDLE hStdoutWrite;
-
- // Other variables for the child process and
- // file i/o stuff
- SECURITY_ATTRIBUTES secatt;
- PROCESS_INFORMATION procinfo;
- STARTUPINFO startinfo;
- BOOL bOk;
- FXchar* command;
- // get the command string
- command = (char*)commandString.text();
-
- // Set up the SECURITY_ATTRIBUTES for the stdout/stderr pipe
- // this is the same as we did in the class constructor.
- secatt.nLength = sizeof(SECURITY_ATTRIBUTES);
- secatt.bInheritHandle = TRUE;
- secatt.lpSecurityDescriptor = NULL;
-
- // Create a pipe for sending the child stdin
- if (!CreatePipe(&hStdinRead, &hTempStdinWrite, &secatt, 0))
- {
- return -1; // return an error number for tracking later if needed
- }
- // Create a pipe for getting the child stdout/stderr
- if (! CreatePipe(&hTempStdoutRead, &hStdoutWrite, &secatt, 0))
- {
- return -1; // return an error number for tracking later if needed
- }
- // Duplicate the write end of the stdin handle, so the handle
- // isn't inherited when the child process is created.
- bOk = DuplicateHandle(GetCurrentProcess(), // The process with handle to duplicate
- hTempStdinWrite, // the actual handle to duplicate
- GetCurrentProcess(), // handle of the process to duplicate to
- &m_stdinWriteHandle, // pointer to the duplicate handle
- 0, // access for duplicate handle
- FALSE, // handle inheritance flag (we don't want to inherit)
- DUPLICATE_SAME_ACCESS); // optional actions
- //check if DuplicateHandle() went ok
- if (!bOk)
- {
- return -4;
- }
- // Duplicate the read end of the handle, so funny stuff
- // doesn't happen when reading later.
- // see the comments above for what each field is for
- bOk = DuplicateHandle(GetCurrentProcess(),
- hTempStdoutRead,
- GetCurrentProcess(),
- &m_stdoutReadHandle,
- 0,
- FALSE,
- DUPLICATE_SAME_ACCESS);
- // check if DuplicateHandle() went ok
- if (!bOk)
- {
- return -4;
- }
-
- // close the temporary write stdin handle
- if (!CloseHandle(hTempStdinWrite))
- {
- return -5;
- }
- // Close the temporary read handle
- if (!CloseHandle(hTempStdoutRead))
- {
- return -5;
- }
- // Setup the PROCESS_INFORMATION variable for the
- // child process
- ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION));
- // Setup the STARTUPINFO variable for the
- // child process
- ZeroMemory(&startinfo, sizeof(STARTUPINFO)); // clear the memory here
- startinfo.cb = sizeof(STARTUPINFO); // set the size
- startinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; // flags to use
- startinfo.wShowWindow = SW_HIDE; // hide the process (we don't want to see it)
- startinfo.hStdInput = hStdinRead; // stdin handle
- startinfo.hStdOutput = hStdoutWrite; // stdout handle
- startinfo.hStdError = hStdoutWrite; // stderr handle
- // Create the child process to execute cdrecord
- if (!CreateProcess(NULL, // pointer to name of executable module (NULL, we're using command line)
- command, // pointer to the command line string we want to execute
- NULL, // pointer to process security attributes (we're not using any)
- NULL, // pointer to thread security attributes (again, not necessary)
- TRUE, // handle inheritance flag (inherit the handles for stdin/stdout/stderr)
- DETACHED_PROCESS, // creation flags (create the process detached from our own)
- NULL, // pointer to new environment block (not using this)
- NULL, // pointer to current directory name (just use the programs current directory)
- &startinfo, // pointer to STARTUPINFO
- &procinfo)) // pointer to PROCESS_INFORMATION
- {
- return -6;
- }
- // close the write end of the stdout/stderr pipe,
- CloseHandle(hStdinRead);
- // so we can read from the pipe
- CloseHandle(hStdoutWrite);
- // we don't need the thread or process handles,
- // so let's close them too
- CloseHandle(procinfo.hThread);
- CloseHandle(procinfo.hProcess);
- // start the thread to process I/O
- start();
- // return another error if the thread wouldn't start
- // for some freaky reason
- if (m_status != STARTED)
- {
- return -7;
- }
-
- // Success!
- return 0;
- }
- // This returns the contents and length of m_readBuffer
- // (m_charsRead is the length of m_readBuffer).
- // It also releases the semaphore, so the thread reading the process
- // output can continue.
- FXint CWinProcess::getStringText(FXString& outputString)
- {
- // make sure the string is empty
- outputString.clear();
-
- // append the string in the buffer to the output string
- outputString.append(m_readBuffer);
-
- // let the thread know it can keep getting output
- ReleaseSemaphore(m_threadSemaphore, 1, NULL);
- return 0;
- }
- // This is the function that will be run in the thread...
- void CWinProcess::theThreadFunc(void)
- {
- // variables for the read
- BOOL bOk;
-
- // close the input handle
- CloseHandle(m_stdinWriteHandle);
- // loop until we're done getting output
- for(;;)
- {
- // Read from the process' output pipe
- bOk = ReadFile(m_stdoutReadHandle, m_readBuffer, CONSOLE_LINE_SIZE, (DWORD*)(&m_charsRead), NULL);
-
- // if ReadFile() didn't return ok, or if it read zero chars,
- // we're done, so break out of the loop
- if (!bOk || m_charsRead == 0)
- {
- break;
- }
-
- // put a ' ' at the end of the buffer so it's a terminated string
- // and there aren't funny errors later when reading the string
- m_readBuffer[m_charsRead] = ' ';
-
- // fire the event that another process/thread/whatever
- // can read the string m_readBuffer
- // If it doesn't work, change the thread status
- if (!SetEvent(m_processEvent))
- {
- m_status = THREAD_ERROR;
- }
- // Now wait for the string to be read before we overwrite it
- WaitForSingleObject(m_threadSemaphore, INFINITE);
- // Reset the values of m_charsRead and m_readBuffer, so we
- // know they can't corrupt anything
- m_charsRead = 0;
- strcpy(m_readBuffer, "");
-
- }
- // We're done with reading output, so close
- // the process' output handle
- CloseHandle(m_stdoutReadHandle);
- // fire the event that the thread is done processing
- // I/O from the process.
- // If it doesn't work, change the thread status to
- // an error.
- if (!SetEvent(m_completeEvent))
- {
- m_status = THREAD_ERROR;
- }
-
- // we're done, so change the thread status
- // to complete.
- m_status = COMPLETED;
- }