diff options
author | Constantin Kaplinsky <const@tightvnc.com> | 2006-05-16 08:48:31 +0000 |
---|---|---|
committer | Constantin Kaplinsky <const@tightvnc.com> | 2006-05-16 08:48:31 +0000 |
commit | ac30668d41335ff9fb606332888a6ec0df83f3ce (patch) | |
tree | 1331ebd2da8e8c091fef9270f8280f82366f5b76 /vncviewer/ConnectingDialog.cxx | |
parent | cbfb59805d3b2317503411ef188e06408365b1b2 (diff) | |
download | tigervnc-ac30668d41335ff9fb606332888a6ec0df83f3ce.tar.gz tigervnc-ac30668d41335ff9fb606332888a6ec0df83f3ce.zip |
Win32 vncviewer merged with VNC 4.1.1 code. The merge is incomplete - the code compiles but does not always work properly yet.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/merge-with-vnc-4.1.1@552 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'vncviewer/ConnectingDialog.cxx')
-rw-r--r-- | vncviewer/ConnectingDialog.cxx | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/vncviewer/ConnectingDialog.cxx b/vncviewer/ConnectingDialog.cxx new file mode 100644 index 00000000..60fcb661 --- /dev/null +++ b/vncviewer/ConnectingDialog.cxx @@ -0,0 +1,160 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// -=- ConnectingDialog.cxx + +#include <stdlib.h> +#include <vncviewer/ConnectingDialog.h> +#include <vncviewer/resource.h> +#include <network/TcpSocket.h> +#include <rfb/Threading.h> +#include <rfb/Hostname.h> +#include <map> + +using namespace rfb; +using namespace rfb::win32; + + +// ConnectingDialog callback +static BOOL CALLBACK ConnectingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { + bool* activePtr = (bool*)GetWindowLong(hwnd, GWL_USERDATA); + switch (uMsg) { + case WM_INITDIALOG: + SetWindowLong(hwnd, GWL_USERDATA, lParam); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDCANCEL: + if (activePtr) + *activePtr = false; + return TRUE; + } + break; + case WM_DESTROY: + if (activePtr) + *activePtr = false; + return TRUE; + } + return 0; +} + + +// Global map, used by ConnectingDialog::Threads to call back to their owning +// ConnectingDialogs, while coping with the fact that the owner may already have quit. +static std::map<int, ConnectingDialog*> dialogs; +static int nextDialogId = 0; +static Mutex dialogsLock; + + +// ConnectingDialog::Thread +// Attempts to connect to the specified host. If the connection succeeds, the +// socket is saved in the owning ConnectingDialog, if still available, and the +// event is signalled. If the connection fails, the Exception text is returned +// to the dialog. If the dialog is already gone, the Exception/socket are discarded. +// NB: This thread class cleans itself up on exit - DO NOT join()! +class ConnectingDialog::Thread : public rfb::Thread { +public: + Thread(int dialogId_, const char* hostAndPort) : dialogId(dialogId_) { + setDeleteAfterRun(); + getHostAndPort(hostAndPort, &host.buf, &port); + } + virtual void run() { + try { + returnSock(new network::TcpSocket(host.buf, port)); + } catch (rdr::Exception& e) { + returnException(e); + } + } + void returnSock(network::Socket* s) { + Lock l(dialogsLock); + if (dialogs.count(dialogId)) { + dialogs[dialogId]->newSocket = s; + SetEvent(dialogs[dialogId]->readyEvent); + } else { + delete s; + } + } + void returnException(const rdr::Exception& e) { + Lock l(dialogsLock); + if (dialogs.count(dialogId)) { + dialogs[dialogId]->errMsg.replaceBuf(strDup(e.str())); + SetEvent(dialogs[dialogId]->readyEvent); + } + }; + CharArray host; + int port; + int dialogId; +}; + + +ConnectingDialog::ConnectingDialog() : dialog(0), readyEvent(CreateEvent(0, TRUE, FALSE, 0)), + newSocket(0), dialogId(0) { +} + +network::Socket* ConnectingDialog::connect(const char* hostAndPort) { + Thread* connectThread = 0; + bool active = true; + errMsg.replaceBuf(0); + newSocket = 0; + + // Get a unique dialog identifier and create the dialog window + { + Lock l(dialogsLock); + dialogId = ++nextDialogId; + dialogs[dialogId] = this; + dialog = CreateDialogParam(GetModuleHandle(0), + MAKEINTRESOURCE(IDD_CONNECTING_DLG), 0, &ConnectingDlgProc, (long)&active); + ShowWindow(dialog, SW_SHOW); + ResetEvent(readyEvent); + } + + // Create and start the connection thread + try { + connectThread = new Thread(dialogId, hostAndPort); + connectThread->start(); + } catch (rdr::Exception& e) { + errMsg.replaceBuf(strDup(e.str())); + active = false; + } + + // Process window messages until the connection thread signals readyEvent, or the dialog is cancelled + while (active && (MsgWaitForMultipleObjects(1, &readyEvent.h, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)) { + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessage(&msg); + } + + // Remove this dialog from the table + // NB: If the dialog was cancelled then the thread is still running, and will only + // discover that we're gone when it looks up our unique Id in the dialog table. + { + Lock l(dialogsLock); + dialogs.erase(dialogId); + } + + // Close the dialog window + DestroyWindow(dialog); dialog=0; + + // Throw the exception, if there was one + if (errMsg.buf) + throw rdr::Exception(errMsg.buf); + + // Otherwise, return the socket + // NB: The socket will be null if the dialog was cancelled + return newSocket; +} |