source-engine/hammer/processwnd.cpp

314 lines
7.5 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= 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);
}