Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. //
  8. //-----------------------------------------------------------------------------
  9. // $Log: $
  10. //
  11. // $NoKeywords: $
  12. //=============================================================================//
  13. #include "stdafx.h"
  14. #include <wincon.h>
  15. #include "hammer.h"
  16. #include "ProcessWnd.h"
  17. #include "osver.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include <tier0/memdbgon.h>
  20. #define IDC_PROCESSWND_EDIT 1
  21. #define IDC_PROCESSWND_COPYALL 2
  22. LPCTSTR GetErrorString();
  23. CProcessWnd::CProcessWnd()
  24. {
  25. Font.CreatePointFont(100, "Courier New");
  26. }
  27. CProcessWnd::~CProcessWnd()
  28. {
  29. }
  30. BEGIN_MESSAGE_MAP(CProcessWnd, CWnd)
  31. ON_BN_CLICKED(IDC_PROCESSWND_COPYALL, OnCopyAll)
  32. //{{AFX_MSG_MAP(CProcessWnd)
  33. ON_BN_CLICKED(IDC_PROCESSWND_COPYALL, OnCopyAll)
  34. ON_WM_TIMER()
  35. ON_WM_CREATE()
  36. ON_WM_SIZE()
  37. //}}AFX_MSG_MAP
  38. END_MESSAGE_MAP()
  39. /////////////////////////////////////////////////////////////////////////////
  40. // CProcessWnd operations
  41. int CProcessWnd::Execute(LPCTSTR pszCmd, ...)
  42. {
  43. CString strBuf;
  44. va_list vl;
  45. va_start(vl, pszCmd);
  46. while(1)
  47. {
  48. char *p = va_arg(vl, char*);
  49. if(!p)
  50. break;
  51. strBuf += p;
  52. strBuf += " ";
  53. }
  54. va_end(vl);
  55. return Execute(pszCmd, (LPCTSTR)strBuf);
  56. }
  57. void CProcessWnd::Clear()
  58. {
  59. m_EditText.Empty();
  60. Edit.SetWindowText("");
  61. Edit.RedrawWindow();
  62. }
  63. void CProcessWnd::Append(CString str)
  64. {
  65. m_EditText += str;
  66. if (getOSVersion() >= eWinNT)
  67. {
  68. Edit.SetWindowText(m_EditText);
  69. }
  70. else
  71. {
  72. DWORD length = m_EditText.GetLength() / sizeof(TCHAR);
  73. // Gracefully handle 64k edit control display on win9x (display last 64k of text)
  74. // Copy to clipboard will work fine, as it copies the m_EditText contents
  75. // in its entirety to the clipboard
  76. if (length >= 0x0FFFF)
  77. {
  78. LPTSTR string = m_EditText.GetBuffer(length + 1);
  79. LPTSTR offset;
  80. offset = string + length - 0x0FFFF;
  81. Edit.SetWindowText(offset);
  82. m_EditText.ReleaseBuffer();
  83. }
  84. else
  85. {
  86. Edit.SetWindowText(m_EditText);
  87. }
  88. }
  89. Edit.LineScroll(Edit.GetLineCount());
  90. Edit.RedrawWindow();
  91. }
  92. int CProcessWnd::Execute(LPCTSTR pszCmd, LPCTSTR pszCmdLine)
  93. {
  94. int rval = -1;
  95. SECURITY_ATTRIBUTES saAttr;
  96. HANDLE hChildStdinRd_, hChildStdinWr, hChildStdoutRd_, hChildStdoutWr, hChildStderrWr;
  97. // Set the bInheritHandle flag so pipe handles are inherited.
  98. saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  99. saAttr.bInheritHandle = TRUE;
  100. saAttr.lpSecurityDescriptor = NULL;
  101. // Create a pipe for the child's STDOUT.
  102. if(CreatePipe(&hChildStdoutRd_, &hChildStdoutWr, &saAttr, 0))
  103. {
  104. if(CreatePipe(&hChildStdinRd_, &hChildStdinWr, &saAttr, 0))
  105. {
  106. if (DuplicateHandle(GetCurrentProcess(),hChildStdoutWr, GetCurrentProcess(),&hChildStderrWr,0, TRUE,DUPLICATE_SAME_ACCESS))
  107. {
  108. /* Now create the child process. */
  109. STARTUPINFO si;
  110. memset(&si, 0, sizeof si);
  111. si.cb = sizeof(si);
  112. si.dwFlags = STARTF_USESTDHANDLES;
  113. si.hStdInput = hChildStdinRd_;
  114. si.hStdError = hChildStderrWr;
  115. si.hStdOutput = hChildStdoutWr;
  116. PROCESS_INFORMATION pi;
  117. CString str;
  118. str.Format("%s %s", pszCmd, pszCmdLine);
  119. if (CreateProcess(NULL, (char*) LPCTSTR(str), NULL, NULL, TRUE,
  120. DETACHED_PROCESS, NULL, NULL, &si, &pi))
  121. {
  122. HANDLE hProcess = pi.hProcess;
  123. #define BUFFER_SIZE 4096
  124. // read from pipe..
  125. char buffer[BUFFER_SIZE];
  126. BOOL bDone = FALSE;
  127. while(1)
  128. {
  129. DWORD dwCount = 0;
  130. DWORD dwRead = 0;
  131. // read from input handle
  132. PeekNamedPipe( hChildStdoutRd_, NULL, NULL, NULL, &dwCount, NULL);
  133. if (dwCount)
  134. {
  135. dwCount = min (dwCount, (DWORD)BUFFER_SIZE - 1);
  136. ReadFile( hChildStdoutRd_, buffer, dwCount, &dwRead, NULL);
  137. }
  138. if(dwRead)
  139. {
  140. buffer[dwRead] = 0;
  141. Append(buffer);
  142. }
  143. // check process termination
  144. else if(WaitForSingleObject(hProcess, 1000) != WAIT_TIMEOUT)
  145. {
  146. if(bDone)
  147. break;
  148. bDone = TRUE; // next time we get it
  149. }
  150. }
  151. rval = 0;
  152. }
  153. else
  154. {
  155. SetForegroundWindow();
  156. CString strTmp;
  157. strTmp.Format("* Could not execute the command:\r\n %s\r\n", str.GetBuffer());
  158. Append(strTmp);
  159. strTmp.Format("* Windows gave the error message:\r\n \"%s\"\r\n", GetErrorString());
  160. Append(strTmp);
  161. }
  162. CloseHandle(hChildStderrWr);
  163. }
  164. CloseHandle(hChildStdinRd_);
  165. CloseHandle(hChildStdinWr);
  166. }
  167. CloseHandle(hChildStdoutRd_);
  168. CloseHandle(hChildStdoutWr);
  169. }
  170. return rval;
  171. }
  172. /////////////////////////////////////////////////////////////////////////////
  173. // CProcessWnd message handlers
  174. void CProcessWnd::OnTimer(UINT nIDEvent)
  175. {
  176. CWnd::OnTimer(nIDEvent);
  177. }
  178. int CProcessWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
  179. {
  180. if (CWnd::OnCreate(lpCreateStruct) == -1)
  181. return -1;
  182. // create big CEdit in window
  183. CRect rctClient;
  184. GetClientRect(rctClient);
  185. CRect rctEdit;
  186. rctEdit = rctClient;
  187. rctEdit.bottom = rctClient.bottom - 20;
  188. Edit.Create(WS_CHILD | WS_BORDER | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN, rctClient, this, IDC_PROCESSWND_EDIT);
  189. Edit.SetReadOnly(TRUE);
  190. Edit.SetFont(&Font);
  191. CRect rctButton;
  192. rctButton = rctClient;
  193. rctButton.top = rctClient.bottom - 20;
  194. m_btnCopyAll.Create("Copy to Clipboard", WS_CHILD | WS_VISIBLE, rctButton, this, IDC_PROCESSWND_COPYALL);
  195. m_btnCopyAll.SetButtonStyle(BS_PUSHBUTTON);
  196. return 0;
  197. }
  198. void CProcessWnd::OnSize(UINT nType, int cx, int cy)
  199. {
  200. CWnd::OnSize(nType, cx, cy);
  201. // create big CEdit in window
  202. CRect rctClient;
  203. GetClientRect(rctClient);
  204. CRect rctEdit;
  205. rctEdit = rctClient;
  206. rctEdit.bottom = rctClient.bottom - 20;
  207. Edit.MoveWindow(rctEdit);
  208. CRect rctButton;
  209. rctButton = rctClient;
  210. rctButton.top = rctClient.bottom - 20;
  211. m_btnCopyAll.MoveWindow(rctButton);
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose: Prepare the process window for display. If it has not been created
  215. // yet, register the class and create it.
  216. //-----------------------------------------------------------------------------
  217. void CProcessWnd::GetReady(void)
  218. {
  219. if (!IsWindow(m_hWnd))
  220. {
  221. CString strClass = AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW), HBRUSH(GetStockObject(WHITE_BRUSH)));
  222. CreateEx(0, strClass, "Compile Process Window", WS_OVERLAPPEDWINDOW, 50, 50, 600, 400, AfxGetMainWnd()->GetSafeHwnd(), HMENU(NULL));
  223. }
  224. ShowWindow(SW_SHOW);
  225. SetActiveWindow();
  226. Clear();
  227. }
  228. BOOL CProcessWnd::PreTranslateMessage(MSG* pMsg)
  229. {
  230. // The edit control won't get keyboard commands from the window without this (at least in Win2k)
  231. // The right mouse context menu still will not work in w2k for some reason either, although
  232. // it is getting the CONTEXTMENU message (as seen in Spy++)
  233. ::TranslateMessage(pMsg);
  234. ::DispatchMessage(pMsg);
  235. return TRUE;
  236. }
  237. static void CopyToClipboard(const CString& text)
  238. {
  239. if (OpenClipboard(NULL))
  240. {
  241. if (EmptyClipboard())
  242. {
  243. HGLOBAL hglbCopy;
  244. LPTSTR tstrCopy;
  245. hglbCopy = GlobalAlloc(GMEM_DDESHARE, text.GetLength() + sizeof(TCHAR) );
  246. if (hglbCopy != NULL)
  247. {
  248. tstrCopy = (LPTSTR) GlobalLock(hglbCopy);
  249. strcpy(tstrCopy, (LPCTSTR)text);
  250. GlobalUnlock(hglbCopy);
  251. SetClipboardData(CF_TEXT, hglbCopy);
  252. }
  253. }
  254. CloseClipboard();
  255. }
  256. }
  257. void CProcessWnd::OnCopyAll()
  258. {
  259. // Used to call m_Edit.SetSel(0,1); m_Edit.Copy(); m_Edit.Clear()
  260. // but in win9x the clipboard will only receive at most 64k of text from the control
  261. CopyToClipboard(m_EditText);
  262. }