diff -r 000000000000 -r 7f656887cf89 plugins/consoles/rcons/server/win32/RemoteConsole.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/consoles/rcons/server/win32/RemoteConsole.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,416 @@ +// RemoteConsole.cpp +// +// Copyright (c) 2010 Accenture. All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Accenture - Initial contribution +// + +#include "Misc.h" +#include "stdafx.h" +#include <commdlg.h> +#include "console_host.h" +#include "RemoteConsole.h" +#include "ConsoleWindow.h" + +LPCTSTR KWindowClassName = TEXT("RemoteConsoleWindowClass"); +LPCTSTR KRemoteConsoleName = TEXT("Remote Console"); +LPCTSTR KRemoteConsoleCommandReaderName = TEXT("Remote Console Command Reader"); + +bool CRemoteConsole::sWindowClassRegistered = FALSE; +int CRemoteConsole::sNextId = 1; +CRemoteConsole* CRemoteConsole::sFirst = NULL; +CRemoteConsole* CRemoteConsole::sLast = NULL; + + +CRemoteConsole* CRemoteConsole::Instance(int aId) + { + CRemoteConsole* console = sFirst; + bool found(0); + while (console && !found) + { + if (console->iId == aId) + { + found = 1; + } + else + { + console = console->iNext; + } + } + + + if (found) + { + return console; + } + return NULL; + } + +CRemoteConsole* CRemoteConsole::New(HINSTANCE aAppHandle, CSocketCommandReader& aCommandReader, LPCTSTR aTitle, int aWidth, int aHeight, TPreferences& aPreferences) + { + std::auto_ptr<CRemoteConsole> self(new(EThrow) CRemoteConsole(aCommandReader, aPreferences)); + self->Construct(aAppHandle, aTitle, aWidth, aHeight); + return self.release(); + } + +CRemoteConsole::~CRemoteConsole() + { + iConsole->StopCaptureToFile(); + delete iCommandReader; + delete iKeyEventSocket; + delete iConsole; + if (sLast == this) + { + ASSERT(iNext == NULL); + sLast = iPrevious; + } + if (sFirst == this) + { + sFirst = iNext; + } + if (iPrevious) + { + iPrevious->iNext = iNext; + } + if (iNext) + { + iNext->iPrevious = iPrevious; + } + } + +int CRemoteConsole::Id() const + { + return iId; + } + +void CRemoteConsole::AttachKeyEventSocket(CClientSocket& aSocket) + { + ASSERT(iKeyEventSocket == NULL); + iKeyEventSocket = &aSocket; + iKeyEventSocket->SetClosureObserver(this); + } + +CRemoteConsole::CRemoteConsole(CSocketCommandReader& aCommandReader, TPreferences& aPreferences) + : iId(sNextId++), iCommandReader(&aCommandReader), iKeyEventSocket(NULL), iNext(NULL), iPrevious(NULL), iClosing(FALSE), iPreferences(aPreferences) + { + if (sFirst == NULL) + { + ASSERT(sLast == NULL); + sFirst = this; + sLast = this; + } + else + { + sLast->iNext = this; + iPrevious = sLast; + sLast = this; + } + } + +void CRemoteConsole::Construct(HINSTANCE aAppHandle, LPCTSTR aTitle, int aWidth, int aHeight) + { + if (!sWindowClassRegistered) + { + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; + wcex.lpfnWndProc = (WNDPROC)CWindow::HandleMessage; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = aAppHandle; + wcex.hIcon = LoadIcon(aAppHandle, (LPCTSTR)IDI_CONSOLE_HOST); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = NULL; + wcex.lpszMenuName = (LPCTSTR)ID_REMOTE_CONSOLE_MENU; + wcex.lpszClassName = KWindowClassName; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + if (RegisterClassEx(&wcex) == 0) + { + throw KExceptionWindowClassRegistrationFailed; + } + sWindowClassRegistered = TRUE; + } + + int posX = CW_USEDEFAULT; + int posY = CW_USEDEFAULT; + if (!iPreferences.SystemPositionedWindows()) + { + posX = iPreferences.DefaultWindowPosX(); + posY = iPreferences.DefaultWindowPosY(); + } + iConsole = CConsoleWindow::New(aAppHandle, KWindowClassName, aTitle, posX, posY, (aWidth == -1) ? iPreferences.DefaultWindowWidth() : aWidth, (aHeight == -1) ? iPreferences.DefaultWindowHeight() : aHeight, iPreferences.NumOverflowLines(), this, this, FALSE); + iConsole->SetName(KRemoteConsoleName); + iCommandReader->ChangeHandler(*this); + iCommandReader->SetName(KRemoteConsoleCommandReaderName); + iCommandReader->ReadCommand(); + } + +void CRemoteConsole::HandleSocketClosure(CSocket& aSocket) + { + if (!iClosing) + { + iConsole->SetTitle(TEXT("Remote console closed - press any key to close window")); + iConsole->SetDimmed(TRUE); + iClosing = TRUE; + } + } + +void CRemoteConsole::HandleWindowClosure(CWindow&) + { + delete this; + } + +LRESULT CRemoteConsole::HandleWindowCommand(UINT aMessage, WPARAM aWParam, LPARAM aLParam) + { + switch (LOWORD(aWParam)) + { + case ID_RC_CAPTURE: + { + UINT checkMenuItem = MF_BYCOMMAND | MF_UNCHECKED; + if (iConsole->IsCapturingToFile()) + { + iConsole->StopCaptureToFile(); + } + else + { + TCHAR captureFileName[MAX_PATH]; + if (GetCaptureFileName(captureFileName)) + { + iConsole->CaptureToFile(captureFileName); + checkMenuItem = MF_BYCOMMAND | MF_CHECKED; + } + } + CheckMenuItem(GetMenu(iConsole->Handle()), ID_RC_CAPTURE, checkMenuItem); + break; + } + case ID_RC_CLOSE: + { + DestroyWindow(iConsole->Handle()); + break; + } + case ID_EDIT_COPY: + { + iConsole->CopyToClipboard(); + break; + } + case ID_EDIT_PASTE: + { + iConsole->PasteFromClipboard(); + break; + } + default: + { + return DefWindowProc(iConsole->Handle(), aMessage, aWParam, aLParam); + } + } + return 0; + } + +class TKeyEvent + { +public: + TCHAR iChar; + UINT iModifiers; + }; + +void CRemoteConsole::HandleConsoleChar(TCHAR aChar, UINT aModifiers) + { + if (iClosing) + { + DestroyWindow(iConsole->Handle()); + } + else if (iKeyEventSocket) + { + TKeyEvent keyEvent; + keyEvent.iChar = aChar; + keyEvent.iModifiers = aModifiers; + iKeyEventSocket->Write((char*)&keyEvent, sizeof(TKeyEvent)); + } + } + +void CRemoteConsole::HandleConsoleString(LPCTSTR aString, int aLength) + { + if (iClosing) + { + DestroyWindow(iConsole->Handle()); + } + else if (iKeyEventSocket) + { + for (int i = 0; i < aLength; ++i) + { + HandleConsoleChar(*(aString + i), 0); + } + } + } + +void CRemoteConsole::HandleSocketCommand(TPacketHeader::TPacketType aCommand, const char* aPacket, int aPacketLength, CSocketCommandReader& aReader) + { + ASSERT(&aReader == iCommandReader); + switch (aCommand) + { + case TPacketHeader::ECommandWrite: + { + const int* toWriteLength = new((char*)aPacket) int; + LPTSTR toWrite = (TCHAR*)(aPacket + sizeof(int)); + iConsole->Write(toWrite, *toWriteLength); + break; + } + case TPacketHeader::ECommandGetCursorPos: + { + class TPos + { + public: + int iX; + int iY; + }; + TPos pos; + iConsole->GetCursorPos(pos.iX, pos.iY); + iCommandReader->SendResponse((char*)&pos, sizeof(TPos)); + break; + } + case TPacketHeader::ECommandSetAbsCursorPos: + { + const int* x = new((char*)aPacket) int; + const int* y = new(((char*)aPacket) + sizeof(int)) int; + iConsole->SetAbsCursorPos(*x, *y); + break; + } + case TPacketHeader::ECommandSetRelCursorPos: + { + const int* x = new((char*)aPacket) int; + const int* y = new(((char*)aPacket) + sizeof(int)) int; + iConsole->SetRelCursorPos(*x, *y); + break; + } + case TPacketHeader::ECommandSetCursorHeight: + { + const int* height = new((char*)aPacket) int; + iConsole->SetCursorHeight(*height); + break; + } + case TPacketHeader::ECommandGetScreenSize: + { + class TSize + { + public: + int iWidth; + int iHeight; + }; + TSize size; + iConsole->GetConsoleSize(size.iWidth, size.iHeight); + iCommandReader->SendResponse((char*)&size, sizeof(TSize)); + break; + } + case TPacketHeader::ECommandSetTitle: + { + iConsole->SetTitle((TCHAR*)aPacket); + break; + } + case TPacketHeader::ECommandClearScreen: + { + iConsole->ClearScreen(); + break; + } + case TPacketHeader::ECommandClearToEndOfLine: + { + iConsole->ClearToEndOfLine(); + break; + } + default: + { + // Unknown command - do nothing. + } + } + iCommandReader->ReadCommand(); + } + +void CRemoteConsole::HandleSocketClosure(CSocketCommandReader& aReader) + { + HandleSocketClosure(aReader.Socket()); + } + +bool CRemoteConsole::GetCaptureFileName(LPTSTR aFileName) const + { + GetDefaultCaptureFileName(aFileName); + OPENFILENAME ofn; + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = iConsole->Handle(); + ofn.lpstrFile = aFileName; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrFilter = TEXT("All\0*.*\0Text\0*.TXT\0"); + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + ofn.lpstrTitle = TEXT("Capture to"); + bool ok = !(GetSaveFileName(&ofn) == 0); + if (ok) + { + if (FileExists(aFileName)) + { + LPCTSTR constErrorText = TEXT(" already exists. Overwrite it?"); + std::auto_ptr<TCHAR> errorText(new(EThrow) TCHAR[wcslen(aFileName) + wcslen(constErrorText) + 1]); + wcscpy(errorText.get(), aFileName); + wcscat(errorText.get(), constErrorText); + if (MessageBox(iConsole->Handle(), errorText.get(), TEXT("Warning"), MB_OKCANCEL | MB_ICONWARNING) == IDOK) + { + if (DeleteFile(aFileName) <= 0) + { + throw KExceptionFailedToDeleteExistingCaptureFile; + } + } + else + { + ok = FALSE; + } + } + } + if (ok) + { + SetDefaultCaptureFilePath(aFileName); + } + return ok; + } + +void CRemoteConsole::GetDefaultCaptureFileName(LPTSTR aFileName) const + { + TCHAR formatString[MAX_PATH]; + wcscpy(formatString, iPreferences.DefaultCaptureFilePath()); + TCHAR windowTitle[MAX_PATH]; + iConsole->GetTitle(windowTitle, MAX_PATH); + if (wcslen(formatString) + wcslen(windowTitle) + 10 > MAX_PATH) // + 10 for the '_%03d.txt\0'. + { + wcscpy(formatString, TEXT("c:\\")); + } + wcscat(formatString, windowTitle); + wcscat(formatString, TEXT("_%03d.txt")); + int i = 1; + bool uniqueNameFound(FALSE); + do + { + _snwprintf(aFileName, MAX_PATH, formatString, i++); + if (!FileExists(aFileName)) + { + uniqueNameFound = TRUE; + } + } + while (!uniqueNameFound); + } + +void CRemoteConsole::SetDefaultCaptureFilePath(LPCTSTR aFileName) const + { + int pathLength; + for (pathLength = wcslen(aFileName) - 1; (pathLength > 0) && (aFileName[pathLength - 1] != TCHAR('\\')); --pathLength); + TCHAR path[MAX_PATH]; + wcsncpy(path, aFileName, pathLength); + *(path + pathLength) = CHAR('\0'); + iPreferences.SetDefaultCaptureFilePath(path); + iPreferences.Write(); + }