plugins/consoles/rcons/server/win32/RemoteConsole.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // RemoteConsole.cpp
       
     2 // 
       
     3 // Copyright (c) 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include "Misc.h"
       
    14 #include "stdafx.h"
       
    15 #include <commdlg.h>
       
    16 #include "console_host.h"
       
    17 #include "RemoteConsole.h"
       
    18 #include "ConsoleWindow.h"
       
    19 
       
    20 LPCTSTR KWindowClassName = TEXT("RemoteConsoleWindowClass");
       
    21 LPCTSTR KRemoteConsoleName = TEXT("Remote Console");
       
    22 LPCTSTR KRemoteConsoleCommandReaderName = TEXT("Remote Console Command Reader");
       
    23 
       
    24 bool CRemoteConsole::sWindowClassRegistered = FALSE;
       
    25 int CRemoteConsole::sNextId = 1;
       
    26 CRemoteConsole* CRemoteConsole::sFirst = NULL;
       
    27 CRemoteConsole* CRemoteConsole::sLast = NULL;
       
    28 
       
    29 
       
    30 CRemoteConsole* CRemoteConsole::Instance(int aId)
       
    31 	{
       
    32 	CRemoteConsole* console = sFirst;
       
    33 	bool found(0);
       
    34 	while (console && !found)
       
    35 		{
       
    36 		if (console->iId == aId)
       
    37 			{
       
    38 			found = 1;
       
    39 			}
       
    40 		else
       
    41 			{
       
    42 			console = console->iNext;
       
    43 			}
       
    44 		}
       
    45 		
       
    46 
       
    47 	if (found)
       
    48 		{
       
    49 		return console;
       
    50 		}
       
    51 	return NULL;
       
    52 	}
       
    53 
       
    54 CRemoteConsole* CRemoteConsole::New(HINSTANCE aAppHandle, CSocketCommandReader& aCommandReader, LPCTSTR aTitle, int aWidth, int aHeight, TPreferences& aPreferences)
       
    55 	{
       
    56 	std::auto_ptr<CRemoteConsole> self(new(EThrow) CRemoteConsole(aCommandReader, aPreferences));
       
    57 	self->Construct(aAppHandle, aTitle, aWidth, aHeight);
       
    58 	return self.release();
       
    59 	}
       
    60 
       
    61 CRemoteConsole::~CRemoteConsole()
       
    62 	{
       
    63 	iConsole->StopCaptureToFile();
       
    64 	delete iCommandReader;
       
    65 	delete iKeyEventSocket;
       
    66 	delete iConsole;
       
    67 	if (sLast == this)
       
    68 		{
       
    69 		ASSERT(iNext == NULL);
       
    70 		sLast = iPrevious;
       
    71 		}
       
    72 	if (sFirst == this)
       
    73 		{
       
    74 		sFirst = iNext;
       
    75 		}
       
    76 	if (iPrevious)
       
    77 		{
       
    78 		iPrevious->iNext = iNext;
       
    79 		}
       
    80 	if (iNext)
       
    81 		{
       
    82 		iNext->iPrevious = iPrevious;
       
    83 		}
       
    84 	}
       
    85 
       
    86 int CRemoteConsole::Id() const
       
    87 	{
       
    88 	return iId;
       
    89 	}
       
    90 
       
    91 void CRemoteConsole::AttachKeyEventSocket(CClientSocket& aSocket)
       
    92 	{
       
    93 	ASSERT(iKeyEventSocket == NULL);
       
    94 	iKeyEventSocket = &aSocket;
       
    95 	iKeyEventSocket->SetClosureObserver(this);
       
    96 	}
       
    97 
       
    98 CRemoteConsole::CRemoteConsole(CSocketCommandReader& aCommandReader, TPreferences& aPreferences)
       
    99 	: iId(sNextId++), iCommandReader(&aCommandReader), iKeyEventSocket(NULL), iNext(NULL), iPrevious(NULL), iClosing(FALSE), iPreferences(aPreferences)
       
   100 	{
       
   101 	if (sFirst == NULL)
       
   102 		{
       
   103 		ASSERT(sLast == NULL);
       
   104 		sFirst = this;
       
   105 		sLast = this;
       
   106 		}
       
   107 	else
       
   108 		{
       
   109 		sLast->iNext = this;
       
   110 		iPrevious = sLast;
       
   111 		sLast = this;
       
   112 		}
       
   113 	}
       
   114 
       
   115 void CRemoteConsole::Construct(HINSTANCE aAppHandle, LPCTSTR aTitle, int aWidth, int aHeight)
       
   116 	{
       
   117 	if (!sWindowClassRegistered)
       
   118 		{
       
   119 		WNDCLASSEX wcex;
       
   120 		wcex.cbSize = sizeof(WNDCLASSEX); 
       
   121 		wcex.style			= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
       
   122 		wcex.lpfnWndProc	= (WNDPROC)CWindow::HandleMessage;
       
   123 		wcex.cbClsExtra		= 0;
       
   124 		wcex.cbWndExtra		= 0;
       
   125 		wcex.hInstance		= aAppHandle;
       
   126 		wcex.hIcon			= LoadIcon(aAppHandle, (LPCTSTR)IDI_CONSOLE_HOST);
       
   127 		wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
       
   128 		wcex.hbrBackground	= NULL;
       
   129 		wcex.lpszMenuName	= (LPCTSTR)ID_REMOTE_CONSOLE_MENU;
       
   130 		wcex.lpszClassName	= KWindowClassName;
       
   131 		wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
       
   132 		if (RegisterClassEx(&wcex) == 0)
       
   133 			{
       
   134 			throw KExceptionWindowClassRegistrationFailed;
       
   135 			}
       
   136 		sWindowClassRegistered = TRUE;
       
   137 		}
       
   138 
       
   139 	int posX = CW_USEDEFAULT;
       
   140 	int posY = CW_USEDEFAULT;
       
   141 	if (!iPreferences.SystemPositionedWindows())
       
   142 		{
       
   143 		posX = iPreferences.DefaultWindowPosX();
       
   144 		posY = iPreferences.DefaultWindowPosY();
       
   145 		}
       
   146 	iConsole = CConsoleWindow::New(aAppHandle, KWindowClassName, aTitle, posX, posY, (aWidth == -1) ? iPreferences.DefaultWindowWidth() : aWidth, (aHeight == -1) ? iPreferences.DefaultWindowHeight() : aHeight, iPreferences.NumOverflowLines(), this, this, FALSE);
       
   147 	iConsole->SetName(KRemoteConsoleName);
       
   148 	iCommandReader->ChangeHandler(*this);
       
   149 	iCommandReader->SetName(KRemoteConsoleCommandReaderName);
       
   150 	iCommandReader->ReadCommand();
       
   151 	}
       
   152 
       
   153 void CRemoteConsole::HandleSocketClosure(CSocket& aSocket)
       
   154 	{
       
   155 	if (!iClosing)
       
   156 		{
       
   157 		iConsole->SetTitle(TEXT("Remote console closed - press any key to close window"));
       
   158 		iConsole->SetDimmed(TRUE);
       
   159 		iClosing = TRUE;
       
   160 		}
       
   161 	}
       
   162 
       
   163 void CRemoteConsole::HandleWindowClosure(CWindow&)
       
   164 	{
       
   165 	delete this;
       
   166 	}
       
   167 
       
   168 LRESULT CRemoteConsole::HandleWindowCommand(UINT aMessage, WPARAM aWParam, LPARAM aLParam)
       
   169 	{
       
   170 	switch (LOWORD(aWParam))
       
   171 		{
       
   172 		case ID_RC_CAPTURE:
       
   173 			{
       
   174 			UINT checkMenuItem = MF_BYCOMMAND | MF_UNCHECKED;
       
   175 			if (iConsole->IsCapturingToFile())
       
   176 				{
       
   177 				iConsole->StopCaptureToFile();
       
   178 				}
       
   179 			else
       
   180 				{
       
   181 				TCHAR captureFileName[MAX_PATH];
       
   182 				if (GetCaptureFileName(captureFileName))
       
   183 					{
       
   184 					iConsole->CaptureToFile(captureFileName);
       
   185 					checkMenuItem = MF_BYCOMMAND | MF_CHECKED;
       
   186 					}
       
   187 				}
       
   188 			CheckMenuItem(GetMenu(iConsole->Handle()), ID_RC_CAPTURE, checkMenuItem);
       
   189 			break;
       
   190 			}
       
   191 		case ID_RC_CLOSE:
       
   192 			{
       
   193 			DestroyWindow(iConsole->Handle());
       
   194 			break;
       
   195 			}
       
   196 		case ID_EDIT_COPY:
       
   197 			{
       
   198 			iConsole->CopyToClipboard();
       
   199 			break;
       
   200 			}
       
   201 		case ID_EDIT_PASTE:
       
   202 			{
       
   203 			iConsole->PasteFromClipboard();
       
   204 			break;
       
   205 			}
       
   206 		default:
       
   207 			{
       
   208 			return DefWindowProc(iConsole->Handle(), aMessage, aWParam, aLParam);
       
   209 			}
       
   210 		}
       
   211 	return 0;
       
   212 	}
       
   213 
       
   214 class TKeyEvent
       
   215 	{
       
   216 public:
       
   217 	TCHAR iChar;
       
   218 	UINT iModifiers;
       
   219 	};
       
   220 
       
   221 void CRemoteConsole::HandleConsoleChar(TCHAR aChar, UINT aModifiers)
       
   222 	{
       
   223 	if (iClosing)
       
   224 		{
       
   225 		DestroyWindow(iConsole->Handle());
       
   226 		}
       
   227 	else if (iKeyEventSocket)
       
   228 		{
       
   229 		TKeyEvent keyEvent;
       
   230 		keyEvent.iChar = aChar;
       
   231 		keyEvent.iModifiers = aModifiers;
       
   232 		iKeyEventSocket->Write((char*)&keyEvent, sizeof(TKeyEvent));
       
   233 		}
       
   234 	}
       
   235 
       
   236 void CRemoteConsole::HandleConsoleString(LPCTSTR aString, int aLength)
       
   237 	{
       
   238 	if (iClosing)
       
   239 		{
       
   240 		DestroyWindow(iConsole->Handle());
       
   241 		}
       
   242 	else if (iKeyEventSocket)
       
   243 		{
       
   244 		for (int i = 0; i < aLength; ++i)
       
   245 			{
       
   246 			HandleConsoleChar(*(aString + i), 0);
       
   247 			}
       
   248 		}
       
   249 	}
       
   250 
       
   251 void CRemoteConsole::HandleSocketCommand(TPacketHeader::TPacketType aCommand, const char* aPacket, int aPacketLength, CSocketCommandReader& aReader)
       
   252 	{
       
   253 	ASSERT(&aReader == iCommandReader);
       
   254 	switch (aCommand)
       
   255 		{
       
   256 		case TPacketHeader::ECommandWrite:
       
   257 			{
       
   258 			const int* toWriteLength = new((char*)aPacket) int;
       
   259 			LPTSTR toWrite = (TCHAR*)(aPacket + sizeof(int));
       
   260 			iConsole->Write(toWrite, *toWriteLength);
       
   261 			break;
       
   262 			}
       
   263 		case TPacketHeader::ECommandGetCursorPos:
       
   264 			{
       
   265 			class TPos
       
   266 				{
       
   267 			public:
       
   268 				int iX;
       
   269 				int iY;
       
   270 				};
       
   271 			TPos pos;
       
   272 			iConsole->GetCursorPos(pos.iX, pos.iY);
       
   273 			iCommandReader->SendResponse((char*)&pos, sizeof(TPos));
       
   274 			break;
       
   275 			}
       
   276 		case TPacketHeader::ECommandSetAbsCursorPos:
       
   277 			{
       
   278 			const int* x = new((char*)aPacket) int;
       
   279 			const int* y = new(((char*)aPacket) + sizeof(int)) int;
       
   280 			iConsole->SetAbsCursorPos(*x, *y);
       
   281 			break;
       
   282 			}
       
   283 		case TPacketHeader::ECommandSetRelCursorPos:
       
   284 			{
       
   285 			const int* x = new((char*)aPacket) int;
       
   286 			const int* y = new(((char*)aPacket) + sizeof(int)) int;
       
   287 			iConsole->SetRelCursorPos(*x, *y);
       
   288 			break;
       
   289 			}
       
   290 		case TPacketHeader::ECommandSetCursorHeight:
       
   291 			{
       
   292 			const int* height = new((char*)aPacket) int;
       
   293 			iConsole->SetCursorHeight(*height);
       
   294 			break;
       
   295 			}
       
   296 		case TPacketHeader::ECommandGetScreenSize:
       
   297 			{
       
   298 			class TSize
       
   299 				{
       
   300 			public:
       
   301 				int iWidth;
       
   302 				int iHeight;
       
   303 				};
       
   304 			TSize size;
       
   305 			iConsole->GetConsoleSize(size.iWidth, size.iHeight);
       
   306 			iCommandReader->SendResponse((char*)&size, sizeof(TSize));
       
   307 			break;
       
   308 			}
       
   309 		case TPacketHeader::ECommandSetTitle:
       
   310 			{
       
   311 			iConsole->SetTitle((TCHAR*)aPacket);
       
   312 			break;
       
   313 			}
       
   314 		case TPacketHeader::ECommandClearScreen:
       
   315 			{
       
   316 			iConsole->ClearScreen();
       
   317 			break;
       
   318 			}
       
   319 		case TPacketHeader::ECommandClearToEndOfLine:
       
   320 			{
       
   321 			iConsole->ClearToEndOfLine();
       
   322 			break;
       
   323 			}
       
   324 		default:
       
   325 			{
       
   326 			// Unknown command - do nothing.
       
   327 			}
       
   328 		}
       
   329 	iCommandReader->ReadCommand();
       
   330 	}
       
   331 
       
   332 void CRemoteConsole::HandleSocketClosure(CSocketCommandReader& aReader)
       
   333 	{
       
   334 	HandleSocketClosure(aReader.Socket());
       
   335 	}
       
   336 
       
   337 bool CRemoteConsole::GetCaptureFileName(LPTSTR aFileName) const
       
   338 	{
       
   339 	GetDefaultCaptureFileName(aFileName);
       
   340 	OPENFILENAME ofn;
       
   341 	ZeroMemory(&ofn, sizeof(ofn));
       
   342 	ofn.lStructSize = sizeof(ofn);
       
   343 	ofn.hwndOwner = iConsole->Handle();
       
   344 	ofn.lpstrFile = aFileName;
       
   345 	ofn.nMaxFile = MAX_PATH;
       
   346 	ofn.lpstrFilter = TEXT("All\0*.*\0Text\0*.TXT\0");
       
   347 	ofn.nFilterIndex = 1;
       
   348 	ofn.lpstrFileTitle = NULL;
       
   349 	ofn.nMaxFileTitle = 0;
       
   350 	ofn.lpstrInitialDir = NULL;
       
   351 	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
       
   352 	ofn.lpstrTitle = TEXT("Capture to");
       
   353 	bool ok = !(GetSaveFileName(&ofn) == 0);
       
   354 	if (ok)
       
   355 		{
       
   356 		if (FileExists(aFileName))
       
   357 			{
       
   358 			LPCTSTR constErrorText = TEXT(" already exists. Overwrite it?");
       
   359 			std::auto_ptr<TCHAR> errorText(new(EThrow) TCHAR[wcslen(aFileName) + wcslen(constErrorText) + 1]);
       
   360 			wcscpy(errorText.get(), aFileName);
       
   361 			wcscat(errorText.get(), constErrorText);
       
   362 			if (MessageBox(iConsole->Handle(), errorText.get(), TEXT("Warning"), MB_OKCANCEL | MB_ICONWARNING) == IDOK)
       
   363 				{
       
   364 				if (DeleteFile(aFileName) <= 0)
       
   365 					{
       
   366 					throw KExceptionFailedToDeleteExistingCaptureFile;
       
   367 					}
       
   368 				}
       
   369 			else
       
   370 				{
       
   371 				ok = FALSE;
       
   372 				}
       
   373 			}
       
   374 		}
       
   375 	if (ok)
       
   376 		{
       
   377 		SetDefaultCaptureFilePath(aFileName);
       
   378 		}
       
   379 	return ok;
       
   380 	}
       
   381 
       
   382 void CRemoteConsole::GetDefaultCaptureFileName(LPTSTR aFileName) const
       
   383 	{
       
   384 	TCHAR formatString[MAX_PATH];
       
   385 	wcscpy(formatString, iPreferences.DefaultCaptureFilePath());
       
   386 	TCHAR windowTitle[MAX_PATH];
       
   387 	iConsole->GetTitle(windowTitle, MAX_PATH);
       
   388 	if (wcslen(formatString) + wcslen(windowTitle) + 10 > MAX_PATH) // + 10 for the '_%03d.txt\0'.
       
   389 		{
       
   390 		wcscpy(formatString, TEXT("c:\\"));
       
   391 		}
       
   392 	wcscat(formatString, windowTitle);
       
   393 	wcscat(formatString, TEXT("_%03d.txt"));
       
   394 	int i = 1;
       
   395 	bool uniqueNameFound(FALSE);
       
   396 	do
       
   397 		{
       
   398 		_snwprintf(aFileName, MAX_PATH, formatString, i++);
       
   399 		if (!FileExists(aFileName))
       
   400 			{
       
   401 			uniqueNameFound = TRUE;
       
   402 			}
       
   403 		}
       
   404 		while (!uniqueNameFound);
       
   405 	}
       
   406 
       
   407 void CRemoteConsole::SetDefaultCaptureFilePath(LPCTSTR aFileName) const
       
   408 	{
       
   409 	int pathLength;
       
   410 	for (pathLength = wcslen(aFileName) - 1; (pathLength > 0) && (aFileName[pathLength - 1] != TCHAR('\\')); --pathLength);
       
   411 	TCHAR path[MAX_PATH];
       
   412 	wcsncpy(path, aFileName, pathLength);
       
   413 	*(path + pathLength) = CHAR('\0');
       
   414 	iPreferences.SetDefaultCaptureFilePath(path);
       
   415 	iPreferences.Write();
       
   416 	}