123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2010 D. R. Commander. 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 INT_PTR CALLBACK ConnectingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
- bool* activePtr = (bool*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
- switch (uMsg) {
- case WM_INITDIALOG:
- SetWindowLongPtr(hwnd, GWLP_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), newSocket(0),
- readyEvent(CreateEvent(0, TRUE, FALSE, 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_PTR)&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;
- }
|