⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 activex.cpp

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 CPP
📖 第 1 页 / 共 5 页
字号:
		params.cNamedArgs = 0;

		MSTSCLib::IMsTscAxEvents ** sinks = GetSinks();

		for(size_t i = 0; i < m_EventSinksCount; ++ i)
			sinks[i]->Invoke(eventId, IID_NULL, 0, DISPATCH_METHOD, &params, retval, NULL, NULL);
	}

	typedef void (RdpClient::* AsyncEventCallback)
	(
		DISPID eventId,
		VARIANTARG * rgvarg,
		unsigned int cArgs,
		VARIANTARG * retVal
	);

	void CleanupEventArgumentsCallback
	(
		DISPID eventId,
		VARIANTARG * rgvarg,
		unsigned int cArgs,
		VARIANTARG * retVal
	)
	{
		assert((rgvarg == NULL) == (cArgs == 0));

		for(unsigned int i = 0; i < cArgs; ++ i)
			VariantClear(&rgvarg[i]);

		if(retVal)
			VariantClear(retVal);
	}

	// synchronous call from inside the apartment that owns the object
	void FireEventInsideApartment
	(
		DISPID eventId,
		VARIANTARG * rgvarg = NULL,
		unsigned int cArgs = 0,
		VARIANTARG * retval = NULL,
		AsyncEventCallback callback = NULL
	)
	{
		assert(InsideApartment());

		if(retval == NULL && callback)
		{
			VARIANTARG localRetval = { };
			retval = &localRetval;
		}

		InvokeSinks(eventId, rgvarg, cArgs, retval);

		if(callback)
			(this->*callback)(eventId, rgvarg, cArgs, retval);
	}

	struct EventArguments
	{
		DISPID eventId;
		VARIANTARG * rgvarg;
		unsigned int cArgs;
		VARIANTARG * retval;
		AsyncEventCallback callback;
	};

	struct RedirectArguments
	{
		uint32 flags;
		uint32 server_len;
		wchar_t * server;
		uint32 cookie_len;
		char * cookie;
		uint32 username_len;
		wchar_t * username;
		uint32 domain_len;
		wchar_t * domain;
		uint32 password_len;
		wchar_t * password;
	};

	enum
	{
		RDPC_WM_ = WM_USER,
		RDPC_WM_SYNC_EVENT,
		RDPC_WM_ASYNC_EVENT,
		RDPC_WM_DISCONNECT,
		RDPC_WM_REQUEST_CLOSE,
		RDPC_WM_REDIRECT,
	};

	static VOID CALLBACK DisconnectAPC(ULONG_PTR)
	{
		// no need to do anything. The interruption will be enough
	}

	bool HandleEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result)
	{
		result = 0;

		switch(uMsg)
		{
			/* Regular event to be dispatched to the container's sink */
		case RDPC_WM_SYNC_EVENT:
			assert(InSendMessage());

		case RDPC_WM_ASYNC_EVENT:
			{
				const EventArguments * eventArgs = reinterpret_cast<EventArguments *>(lParam);
				assert(eventArgs);

				FireEventInsideApartment
				(
					eventArgs->eventId,
					eventArgs->rgvarg,
					eventArgs->cArgs,
					eventArgs->retval,
					eventArgs->callback
				);

				if(uMsg == RDPC_WM_ASYNC_EVENT)
					delete eventArgs;
			}

			break;

			/* The protocol thread is about to die: prepare for disconnection */
		case RDPC_WM_DISCONNECT:
			{
				assert(m_Connected);
				assert(InsideApartment());
				assert(InSendMessage());

				// Unblock the protocol thread and wait for it to terminate
				ReplyMessage(0);
				JoinProtocolThread();

				// Finish disconnecting
				PerformDisconnect(static_cast<long>(wParam));
			}

			break;

		case RDPC_WM_REDIRECT:
			{
				assert(InSendMessage());
				assert(lParam);
				assert(m_Connected);
				assert(m_protocolState.redirect);

				RedirectArguments * redirectArgs = reinterpret_cast<RedirectArguments *>(lParam);

				// BUGBUG: this is extremely messy and more prone to out-of-memory than it should be
				LPSTR lpszNewServer = NULL;
				LPSTR lpszNewCookie = NULL;
				BSTR strNewUsername = NULL;
				BSTR strNewDomain = NULL;
				BSTR strNewPassword = NULL;
				HRESULT hr = S_OK;

				for(;;)
				{
					// Allocate the new properties
					hr = E_OUTOFMEMORY;

					// FIXME: convert the hostname to Punycode, not the ANSI codepage
					lpszNewServer = AllocLpsz(redirectArgs->server, redirectArgs->server_len / sizeof(OLECHAR));

					if(lpszNewServer == NULL && redirectArgs->server_len)
						break;

					lpszNewCookie = AllocLpsz(redirectArgs->cookie, redirectArgs->cookie_len);

					if(lpszNewCookie == NULL && redirectArgs->cookie_len)
						break;

					strNewUsername = SysAllocStringLen(redirectArgs->username, redirectArgs->username_len / sizeof(OLECHAR));

					if(strNewUsername == NULL && redirectArgs->username_len)
						break;

					strNewDomain = SysAllocStringLen(redirectArgs->domain, redirectArgs->domain_len / sizeof(OLECHAR));

					if(strNewDomain == NULL && redirectArgs->domain_len)
						break;

					strNewPassword = SysAllocStringLen(redirectArgs->password, redirectArgs->password_len / sizeof(OLECHAR));
					
					if(strNewPassword == NULL && redirectArgs->password_len)
						break;

					hr = S_OK;
					break;
				}

				// Success
				if(SUCCEEDED(hr))
				{
					// set the new properties
					ReplaceProperty(m_Server, lpszNewServer);
					ReplaceProperty(m_LoadBalanceInfo, lpszNewCookie);
					ReplaceProperty(m_UserName, strNewUsername);
					ReplaceProperty(m_Domain, strNewDomain);
					ReplaceProperty(m_ClearTextPassword, strNewPassword);
				}
				// Failure
				else
				{
					// free the buffers
					FreeLpsz(lpszNewServer);
					FreeLpsz(lpszNewCookie);
					SysFreeString(strNewUsername);
					SysFreeString(strNewDomain);
					SysFreeString(strNewPassword);

					// signal the error
					m_protocolState.disconnect_reason = 262;
					m_protocolState.redirect = False;
					result = -1;
				}
			}

			break;

			// BUGBUG: this could potentially disconnect an unrelated connection established later...
		case RDPC_WM_REQUEST_CLOSE:
			{
				assert(!InSendMessage());

				if(m_Connected)
				{
					// Ask confirmation to the container in case we are logged in
					if(m_loggedIn && !FireConfirmClose())
						break;

					// For reentrancy (OnConfirmClose could deviously call Disconnect)
					if(m_protocolThread == NULL)
						break;

					// Terminate the protocol thread. It will fire the Disconnected event on exit
					TerminateProtocolThread();
				}
			}

			break;

		default:
			return false;
		}

		// If the calling thread is blocked, unblock it ASAP
		if(InSendMessage())
			ReplyMessage(result);

		return true;
	}

	// synchronous call from outside the apartment
	void FireEventOutsideApartment
	(
		DISPID eventId,
		VARIANTARG * rgvarg = NULL,
		unsigned int cArgs = 0,
		VARIANTARG * retval = NULL,
		AsyncEventCallback callback = NULL
	)
	{
		assert(!InsideApartment());
		EventArguments syncEvent = { eventId, rgvarg, cArgs, retval, callback };
		SendMessage(m_controlWindow, RDPC_WM_SYNC_EVENT, 0, reinterpret_cast<LPARAM>(&syncEvent));
	}

	// asynchronous call from outside the apartment
	HRESULT FireEventOutsideApartmentAsync
	(
		DISPID eventId,
		VARIANTARG * rgvarg = NULL,
		unsigned int cArgs = 0, 
		VARIANTARG * retval = NULL,
		AsyncEventCallback callback = NULL
	)
	{
		assert(!InsideApartment());

		EventArguments * asyncEvent = new EventArguments();

		if(asyncEvent == NULL)
			return E_OUTOFMEMORY;

		asyncEvent->eventId = eventId;
		asyncEvent->rgvarg = rgvarg;
		asyncEvent->cArgs = cArgs;
		asyncEvent->retval = NULL;

		if(!PostMessage(m_controlWindow, RDPC_WM_ASYNC_EVENT, 0, reinterpret_cast<LPARAM>(asyncEvent)))
		{
			delete asyncEvent;
			return HRESULT_FROM_WIN32(GetLastError());
		}

		return S_OK;
	}

	// Specific events
	void FireConnecting()
	{
		// Source: protocol
		FireEventOutsideApartment(1);
	}

	void FireConnected()
	{
		// Source: protocol
		FireEventOutsideApartment(2);
	}

	void FireLoginComplete()
	{
		// Source: protocol
		FireEventOutsideApartment(3);
	}

	void FireDisconnected(long reason)
	{
		// Source: protocol. Special handling
		SendMessage(m_controlWindow, RDPC_WM_DISCONNECT, reason, 0);
	}

	void FireEnterFullScreenMode()
	{
		// Source: UI window
		FireEventInsideApartment(5);
	}

	void FireLeaveFullScreenMode()
	{
		// Source: UI window
		FireEventInsideApartment(6);
	}

	HRESULT FireChannelReceivedData(char (& chanName)[CHANNEL_NAME_LEN + 1], void * chanData, unsigned int chanDataSize)
	{
		// BUGBUG: what to do when we run out of memory?

		OLECHAR wchanName[ARRAYSIZE(chanName)];
		std::copy(chanName + 0, chanName + ARRAYSIZE(chanName), wchanName);

		BSTR bstrChanName = SysAllocString(wchanName);

		if(bstrChanName == NULL)
			return E_OUTOFMEMORY;

		BSTR bstrChanData = SysAllocStringByteLen(NULL, chanDataSize);

		if(bstrChanData == NULL)
		{
			SysFreeString(bstrChanName);
			return E_OUTOFMEMORY;
		}

		CopyMemory(bstrChanData, chanData, chanDataSize);

		VARIANTARG args[2] = { };

		args[1].vt = VT_BSTR;
		args[1].bstrVal = bstrChanName;

		args[0].vt = VT_BSTR;
		args[0].bstrVal = bstrChanData;

		// Source: protocol
		HRESULT hr = FireEventOutsideApartmentAsync(7, args, ARRAYSIZE(args), NULL, &RdpClient::CleanupEventArgumentsCallback);

		if(FAILED(hr))
			CleanupEventArgumentsCallback(7, args, ARRAYSIZE(args), NULL);

		return hr;
	}

	void FireRequestGoFullScreen()
	{
		// Source: UI window
		FireEventInsideApartment(8);
	}

	void FireRequestLeaveFullScreen()
	{
		// Source: UI window
		FireEventInsideApartment(9);
	}

	void FireFatalError(long errorCode)
	{
		VARIANTARG arg = { };

		arg.vt = VT_I4;
		arg.lVal = errorCode;

		// Source: protocol
		FireEventOutsideApartment(10, &arg, 1);
	}

	void FireFatalErrorFromApartment(long errorCode)
	{
		VARIANTARG arg = { };

		arg.vt = VT_I4;
		arg.lVal = errorCode;

		// Source: control
		FireEventInsideApartment(10, &arg, 1);
	}

	void FireWarning(long warningCode)
	{
		VARIANTARG arg = { };

		arg.vt = VT_I4;
		arg.lVal = warningCode;

		// Source: protocol
		FireEventOutsideApartment(11, &arg, 1);
	}

	void FireRemoteDesktopSizeChange(long width, long height)
	{
		VARIANTARG args[2] = { };

		args[1].vt = VT_I4;
		args[1].lVal = width;

		args[0].vt = VT_I4;
		args[0].lVal = height;

		// Source: UI window
		FireEventInsideApartment(12, args, ARRAYSIZE(args));
	}

	void FireIdleTimeoutNotification()
	{
		// Source: input thread
		FireEventOutsideApartment(13);
	}

	void FireRequestContainerMinimize()
	{
		// Source: UI window
		FireEventInsideApartment(14);
	}

	bool FireConfirmClose()
	{
		VARIANTARG retval = { };
		VARIANT_BOOL allowClose = VARIANT_TRUE;

		retval.vt = VT_BYREF | VT_BOOL;
		retval.pboolVal = &allowClose;

		// Source: control
		FireEventInsideApartment(15, NULL, 0, &retval);

		return allowClose != VARIANT_FALSE;
	}

    HRESULT FireReceivedTSPublicKey(void * publicKey, unsigned int publicKeyLength)
	{
		assert(m_Connected);

		if(!m_NotifyTSPublicKey)
			return S_OK;

		BSTR bstrPublicKey = SysAllocStringByteLen(NULL, publicKeyLength);

		if(bstrPublicKey == NULL)
			return E_OUTOFMEMORY;

		CopyMemory(bstrPublicKey, publicKey, publicKeyLength);

		VARIANT_BOOL continueLogon = VARIANT_TRUE;
		VARIANTARG arg = { };
		VARIANTARG retval = { };

		arg.vt = VT_BSTR;
		arg.bstrVal = bstrPublicKey;

		retval.vt = VT_BYREF | VT_BOOL;
		retval.pboolVal = &continueLogon;

		// Source: protocol
		FireEventOutsideApartment(16, &arg, 1, &retval);

		return continueLogon ? S_OK : S_FALSE;
	}

	LONG FireAutoReconnecting(long disconnectReason, long attemptCount)
	{
		LONG continueStatus = MSTSCLib::autoReconnectContinueAutomatic;
		VARIANTARG args[2] = { };
		VARIANTARG retval = { };

		args[1].vt = VT_I4;
		args[1].lVal = disconnectReason;

		args[0].vt = VT_I4;
		args[0].lVal = attemptCount;

		retval.vt = VT_BYREF | VT_I4;
		retval.plVal = &continueStatus;

		// Source: protocol
		FireEventOutsideApartment(17, args, ARRAYSIZE(args), &retval);

		return continueStatus;
	}

    void FireAuthenticationWarningDisplayed()
	{
		// Source: protocol
		FireEventOutsideApartment(18);
	}

    void FireAuthenticationWarningDismissed()
	{
		// Source: protocol
		FireEventOutsideApartment(19);
	}

	/* Actual IUnknown implementation */
	HRESULT queryInterface(REFIID riid, void ** ppvObject)
	{
		IUnknown * pvObject = NULL;

		using namespace MSTSCLib;

		if(riid == IID_IUnknown)
			pvObject = static_cast<IUnknown *>(&m_inner);
		else if(riid == IID_IConnectionPointContainer)
			pvObject = static_cast<IConnectionPointContainer *>(this);
		else if(riid == IID_IDataObject)
			pvObject = static_cast<IDataObject *>(this);
		else if(riid == IID_IObjectSafety)
			pvObject = static_cast<IObjectSafety *>(this);
		else if(riid == IID_IOleControl)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -