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.
313 lines
7.5 KiB
313 lines
7.5 KiB
//========= 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); |
|
}
|
|
|