You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
314 lines
7.5 KiB
314 lines
7.5 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $Workfile: $
|
||
|
// $Date: $
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// $Log: $
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include <wincon.h>
|
||
|
#include "hammer.h"
|
||
|
#include "ProcessWnd.h"
|
||
|
#include "osver.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include <tier0/memdbgon.h>
|
||
|
|
||
|
|
||
|
#define IDC_PROCESSWND_EDIT 1
|
||
|
#define IDC_PROCESSWND_COPYALL 2
|
||
|
|
||
|
|
||
|
LPCTSTR GetErrorString();
|
||
|
|
||
|
|
||
|
CProcessWnd::CProcessWnd()
|
||
|
{
|
||
|
Font.CreatePointFont(100, "Courier New");
|
||
|
}
|
||
|
|
||
|
CProcessWnd::~CProcessWnd()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CProcessWnd, CWnd)
|
||
|
ON_BN_CLICKED(IDC_PROCESSWND_COPYALL, OnCopyAll)
|
||
|
//{{AFX_MSG_MAP(CProcessWnd)
|
||
|
ON_BN_CLICKED(IDC_PROCESSWND_COPYALL, OnCopyAll)
|
||
|
ON_WM_TIMER()
|
||
|
ON_WM_CREATE()
|
||
|
ON_WM_SIZE()
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CProcessWnd operations
|
||
|
|
||
|
int CProcessWnd::Execute(LPCTSTR pszCmd, ...)
|
||
|
{
|
||
|
CString strBuf;
|
||
|
|
||
|
va_list vl;
|
||
|
va_start(vl, pszCmd);
|
||
|
|
||
|
while(1)
|
||
|
{
|
||
|
char *p = va_arg(vl, char*);
|
||
|
if(!p)
|
||
|
break;
|
||
|
strBuf += p;
|
||
|
strBuf += " ";
|
||
|
}
|
||
|
|
||
|
va_end(vl);
|
||
|
|
||
|
return Execute(pszCmd, (LPCTSTR)strBuf);
|
||
|
}
|
||
|
|
||
|
void CProcessWnd::Clear()
|
||
|
{
|
||
|
m_EditText.Empty();
|
||
|
Edit.SetWindowText("");
|
||
|
Edit.RedrawWindow();
|
||
|
}
|
||
|
|
||
|
void CProcessWnd::Append(CString str)
|
||
|
{
|
||
|
m_EditText += str;
|
||
|
if (getOSVersion() >= eWinNT)
|
||
|
{
|
||
|
Edit.SetWindowText(m_EditText);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DWORD length = m_EditText.GetLength() / sizeof(TCHAR);
|
||
|
|
||
|
// Gracefully handle 64k edit control display on win9x (display last 64k of text)
|
||
|
// Copy to clipboard will work fine, as it copies the m_EditText contents
|
||
|
// in its entirety to the clipboard
|
||
|
if (length >= 0x0FFFF)
|
||
|
{
|
||
|
LPTSTR string = m_EditText.GetBuffer(length + 1);
|
||
|
LPTSTR offset;
|
||
|
offset = string + length - 0x0FFFF;
|
||
|
Edit.SetWindowText(offset);
|
||
|
m_EditText.ReleaseBuffer();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Edit.SetWindowText(m_EditText);
|
||
|
}
|
||
|
}
|
||
|
Edit.LineScroll(Edit.GetLineCount());
|
||
|
Edit.RedrawWindow();
|
||
|
}
|
||
|
|
||
|
int CProcessWnd::Execute(LPCTSTR pszCmd, LPCTSTR pszCmdLine)
|
||
|
{
|
||
|
int rval = -1;
|
||
|
SECURITY_ATTRIBUTES saAttr;
|
||
|
HANDLE hChildStdinRd_, hChildStdinWr, hChildStdoutRd_, hChildStdoutWr, hChildStderrWr;
|
||
|
|
||
|
// Set the bInheritHandle flag so pipe handles are inherited.
|
||
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||
|
saAttr.bInheritHandle = TRUE;
|
||
|
saAttr.lpSecurityDescriptor = NULL;
|
||
|
|
||
|
// Create a pipe for the child's STDOUT.
|
||
|
if(CreatePipe(&hChildStdoutRd_, &hChildStdoutWr, &saAttr, 0))
|
||
|
{
|
||
|
if(CreatePipe(&hChildStdinRd_, &hChildStdinWr, &saAttr, 0))
|
||
|
{
|
||
|
if (DuplicateHandle(GetCurrentProcess(),hChildStdoutWr, GetCurrentProcess(),&hChildStderrWr,0, TRUE,DUPLICATE_SAME_ACCESS))
|
||
|
{
|
||
|
/* Now create the child process. */
|
||
|
STARTUPINFO si;
|
||
|
memset(&si, 0, sizeof si);
|
||
|
si.cb = sizeof(si);
|
||
|
si.dwFlags = STARTF_USESTDHANDLES;
|
||
|
si.hStdInput = hChildStdinRd_;
|
||
|
si.hStdError = hChildStderrWr;
|
||
|
si.hStdOutput = hChildStdoutWr;
|
||
|
PROCESS_INFORMATION pi;
|
||
|
CString str;
|
||
|
str.Format("%s %s", pszCmd, pszCmdLine);
|
||
|
if (CreateProcess(NULL, (char*) LPCTSTR(str), NULL, NULL, TRUE,
|
||
|
DETACHED_PROCESS, NULL, NULL, &si, &pi))
|
||
|
{
|
||
|
HANDLE hProcess = pi.hProcess;
|
||
|
|
||
|
#define BUFFER_SIZE 4096
|
||
|
// read from pipe..
|
||
|
char buffer[BUFFER_SIZE];
|
||
|
BOOL bDone = FALSE;
|
||
|
|
||
|
while(1)
|
||
|
{
|
||
|
DWORD dwCount = 0;
|
||
|
DWORD dwRead = 0;
|
||
|
|
||
|
// read from input handle
|
||
|
PeekNamedPipe( hChildStdoutRd_, NULL, NULL, NULL, &dwCount, NULL);
|
||
|
if (dwCount)
|
||
|
{
|
||
|
dwCount = min (dwCount, (DWORD)BUFFER_SIZE - 1);
|
||
|
ReadFile( hChildStdoutRd_, buffer, dwCount, &dwRead, NULL);
|
||
|
}
|
||
|
if(dwRead)
|
||
|
{
|
||
|
buffer[dwRead] = 0;
|
||
|
Append(buffer);
|
||
|
}
|
||
|
// check process termination
|
||
|
else if(WaitForSingleObject(hProcess, 1000) != WAIT_TIMEOUT)
|
||
|
{
|
||
|
if(bDone)
|
||
|
break;
|
||
|
bDone = TRUE; // next time we get it
|
||
|
}
|
||
|
}
|
||
|
rval = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetForegroundWindow();
|
||
|
CString strTmp;
|
||
|
strTmp.Format("* Could not execute the command:\r\n %s\r\n", str.GetBuffer());
|
||
|
Append(strTmp);
|
||
|
strTmp.Format("* Windows gave the error message:\r\n \"%s\"\r\n", GetErrorString());
|
||
|
Append(strTmp);
|
||
|
}
|
||
|
|
||
|
CloseHandle(hChildStderrWr);
|
||
|
}
|
||
|
CloseHandle(hChildStdinRd_);
|
||
|
CloseHandle(hChildStdinWr);
|
||
|
}
|
||
|
CloseHandle(hChildStdoutRd_);
|
||
|
CloseHandle(hChildStdoutWr);
|
||
|
}
|
||
|
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CProcessWnd message handlers
|
||
|
|
||
|
|
||
|
void CProcessWnd::OnTimer(UINT nIDEvent)
|
||
|
{
|
||
|
CWnd::OnTimer(nIDEvent);
|
||
|
}
|
||
|
|
||
|
int CProcessWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
||
|
{
|
||
|
if (CWnd::OnCreate(lpCreateStruct) == -1)
|
||
|
return -1;
|
||
|
|
||
|
// create big CEdit in window
|
||
|
CRect rctClient;
|
||
|
GetClientRect(rctClient);
|
||
|
|
||
|
CRect rctEdit;
|
||
|
rctEdit = rctClient;
|
||
|
rctEdit.bottom = rctClient.bottom - 20;
|
||
|
|
||
|
Edit.Create(WS_CHILD | WS_BORDER | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN, rctClient, this, IDC_PROCESSWND_EDIT);
|
||
|
Edit.SetReadOnly(TRUE);
|
||
|
Edit.SetFont(&Font);
|
||
|
|
||
|
CRect rctButton;
|
||
|
rctButton = rctClient;
|
||
|
rctButton.top = rctClient.bottom - 20;
|
||
|
|
||
|
m_btnCopyAll.Create("Copy to Clipboard", WS_CHILD | WS_VISIBLE, rctButton, this, IDC_PROCESSWND_COPYALL);
|
||
|
m_btnCopyAll.SetButtonStyle(BS_PUSHBUTTON);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void CProcessWnd::OnSize(UINT nType, int cx, int cy)
|
||
|
{
|
||
|
CWnd::OnSize(nType, cx, cy);
|
||
|
|
||
|
// create big CEdit in window
|
||
|
CRect rctClient;
|
||
|
GetClientRect(rctClient);
|
||
|
|
||
|
CRect rctEdit;
|
||
|
rctEdit = rctClient;
|
||
|
rctEdit.bottom = rctClient.bottom - 20;
|
||
|
Edit.MoveWindow(rctEdit);
|
||
|
|
||
|
CRect rctButton;
|
||
|
rctButton = rctClient;
|
||
|
rctButton.top = rctClient.bottom - 20;
|
||
|
m_btnCopyAll.MoveWindow(rctButton);
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Prepare the process window for display. If it has not been created
|
||
|
// yet, register the class and create it.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CProcessWnd::GetReady(void)
|
||
|
{
|
||
|
if (!IsWindow(m_hWnd))
|
||
|
{
|
||
|
CString strClass = AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW), HBRUSH(GetStockObject(WHITE_BRUSH)));
|
||
|
CreateEx(0, strClass, "Compile Process Window", WS_OVERLAPPEDWINDOW, 50, 50, 600, 400, AfxGetMainWnd()->GetSafeHwnd(), HMENU(NULL));
|
||
|
}
|
||
|
|
||
|
ShowWindow(SW_SHOW);
|
||
|
SetActiveWindow();
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
BOOL CProcessWnd::PreTranslateMessage(MSG* pMsg)
|
||
|
{
|
||
|
// The edit control won't get keyboard commands from the window without this (at least in Win2k)
|
||
|
// The right mouse context menu still will not work in w2k for some reason either, although
|
||
|
// it is getting the CONTEXTMENU message (as seen in Spy++)
|
||
|
::TranslateMessage(pMsg);
|
||
|
::DispatchMessage(pMsg);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void CopyToClipboard(const CString& text)
|
||
|
{
|
||
|
if (OpenClipboard(NULL))
|
||
|
{
|
||
|
if (EmptyClipboard())
|
||
|
{
|
||
|
HGLOBAL hglbCopy;
|
||
|
LPTSTR tstrCopy;
|
||
|
|
||
|
hglbCopy = GlobalAlloc(GMEM_DDESHARE, text.GetLength() + sizeof(TCHAR) );
|
||
|
|
||
|
if (hglbCopy != NULL)
|
||
|
{
|
||
|
tstrCopy = (LPTSTR) GlobalLock(hglbCopy);
|
||
|
strcpy(tstrCopy, (LPCTSTR)text);
|
||
|
GlobalUnlock(hglbCopy);
|
||
|
|
||
|
SetClipboardData(CF_TEXT, hglbCopy);
|
||
|
}
|
||
|
}
|
||
|
CloseClipboard();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CProcessWnd::OnCopyAll()
|
||
|
{
|
||
|
// Used to call m_Edit.SetSel(0,1); m_Edit.Copy(); m_Edit.Clear()
|
||
|
// but in win9x the clipboard will only receive at most 64k of text from the control
|
||
|
CopyToClipboard(m_EditText);
|
||
|
}
|