vnchttpconnect.cpp

来自「Web VNC samples delphi」· C++ 代码 · 共 851 行 · 第 1/2 页

CPP
851
字号
      char tmpfilename[1024];
      int response;
      JSAMPROW row_pointer[1];
      jpeg_error_mgr jerr;
      cinfo.err = jpeg_std_error(&jerr);
      
      offsetx = tileSize;
      offsety = tileSize;
      sscanf(parmstart + 1, "%d,%d,%d,%d", &fetchx, &fetchy, &offsetx, &offsety);
      if (fetchx > width
          || fetchy > height
          || fetchx < 0
          || fetchy < 0
          || fetchx + offsetx > width
          || fetchy + offsety > height
          || offsetx < 0
          || offsety < 0
          || offsetx > tileSize
          || offsety > tileSize) return;
      _snprintf(tmpfilename, 1024, "res/tmp_%02X_%02d_%02d.jpg", rand(), fetchx, fetchy);
      outfile = fopen(tmpfilename, "wb");
      if (!outfile) return;
      if (!imgbuffer) imgbuffer = new char[width * height * depth / 8];
      rect.left = fetchx;
      rect.top = fetchy;
      rect.bottom = rect.top + offsety;
      rect.right = rect.left + offsetx;
      if (rect.bottom > height) rect.bottom = height;
      if (rect.right > width) rect.right = width;
      RECT bufrect;
      bufrect = rect;
      rect.top += v_desktop->m_bmrect.top;
      rect.bottom += v_desktop->m_bmrect.top;
      rect.left += v_desktop->m_bmrect.left;
      rect.right += v_desktop->m_bmrect.left;
      v_desktop->CopyToBuffer(rect, (BYTE *)imgbuffer);
      jpeg_create_compress(&cinfo);
      jpeg_stdio_dest(&cinfo, outfile);
      cinfo.image_height = rect.bottom - rect.top;
      cinfo.image_width = rect.right - rect.left;
      cinfo.input_components = 3;
      cinfo.in_color_space = JCS_RGB;
      jpeg_set_defaults(&cinfo);
      jpeg_set_quality(&cinfo, 20, false);
      jpeg_start_compress(&cinfo, TRUE);
      scanlinebuffer = new char[tileSize * 3];
      for (int scan = 0; scan < cinfo.image_height; scan++) {
        str = (imgbuffer + (depth/8) * (width * (bufrect.top + scan) + bufrect.left));
        for (int x = 0; x < cinfo.image_width; x++) {
          scanlinebuffer[x*3] = str[x*4+2];
          scanlinebuffer[x*3+1] = str[x*4+1];
          scanlinebuffer[x*3+2] = str[x*4];
        }
        row_pointer[0] = (JSAMPROW)scanlinebuffer;
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
      }
      delete scanlinebuffer;
      jpeg_finish_compress(&cinfo);
      jpeg_destroy_compress(&cinfo);
      response = ftell(outfile);
      fseek(outfile, 0, SEEK_SET);
      _snprintf(gbuf, 1024, "Content-type: image/jpeg\r\nContent-length: %d\r\n\r\n", response);
      socket->SendExact(gbuf, strlen(gbuf));
      fclose(outfile);
      if (outfile = fopen(tmpfilename, "rb")) {
        while (!feof(outfile)) {
          response = fread(gbuf, 1, 1024, outfile);
          socket->SendExact(gbuf, response);
          Sleep(10);
        }
        fclose(outfile);
      }
      unlink(tmpfilename);

      break;
    case 'k':
      if (!validated) return;
      //Key events
      str = parmstart + 1;
      char * pc;
      pc = strchr(str, ' ');
      if (pc) *pc = 0;
      for (int i = 0; i < 1024; i++) {
        unsigned int chr = str[i];
        if (chr == 0) break;
        if (chr == '%') {
          int v;
          if (_snscanf(str + i + 1, 1023 - i, "%02x", &v)) {
            chr = v;
            for (int j = 0; j < 2 && str[i]; j++, i++);
          }
          else {
            break;
          }
        }
      switch (chr) {
        case '\x0D': chr = XK_Return; break;
        case '\x08': chr = XK_BackSpace; break;
        case '\x1B': chr = XK_Escape; break;
        }
      vncKeymap::keyEvent(chr, 1, m_server);
      vncKeymap::keyEvent(chr, 0, m_server);
      }
      str = "Content-type: text/html\r\nContent-length: 6\r\n\r\nThanks";
      socket->SendExact(str, strlen(str));
      break;
    case 'h':
      //Crosshair image
      str = "Content-type: image/png\r\n\r\n";
      socket->SendExact(str, strlen(str));
      outfile = fopen("res/crosshair.png", "rb");
      if (outfile) {
        while (!feof(outfile)) {
          response = fread(gbuf, 1, 1024, outfile);
          socket->SendExact(gbuf, response);
        }
        fclose(outfile);
      }
      break;
    case 'l':
      //List windows and positions
      if (!validated) return;
      windowListCount = 0;
      EnumWindows(&wndEnumProc, 0);
      str = "Content-type: text/plain\r\n\r\n";
      socket->SendExact(str, strlen(str));
      _snprintf(gbuf, 1024, "Full Desktop,0,%d,%d,%d,%d;", 0, width, height, 0);
      socket->SendExact(gbuf, strlen(gbuf));
      for (int i; i < windowListCount; i++) {
        LONG winstyle;
        winstyle = GetWindowLong(windowList[i], GWL_EXSTYLE);
        if (winstyle & WS_EX_TOOLWINDOW) continue;
        //if (!(winstyle & WS_EX_APPWINDOW)) continue;
        if (!IsWindowVisible(windowList[i])) continue;
        WINDOWPLACEMENT wp;
        if (GetWindowPlacement(windowList[i], &wp)) {
          if (wp.showCmd == 0) continue;
        }
        RECT rc;
        GetWindowRect(windowList[i], &rc);
        if (!rc.left && !rc.right && !rc.top && !rc.bottom) continue;
        if (rc.left == rc.right || rc.top == rc.bottom) continue;
        while (str = strchr(gbuf, ',')) *str = '.';
        while (str = strchr(gbuf, ';')) *str = ':';
        if (!GetWindowText(windowList[i], gbuf, 1024)) continue;
        socket->SendExact(gbuf, strlen(gbuf));
        rc.left -= v_desktop->m_bmrect.left;
        rc.right -= v_desktop->m_bmrect.left;
        rc.top -= v_desktop->m_bmrect.top;
        rc.bottom -= v_desktop->m_bmrect.top;
        _snprintf(gbuf, 1024, ",%d,%d,%d,%d,%d;", windowList[i], rc.top, rc.right, rc.bottom, rc.left);
        socket->SendExact(gbuf, strlen(gbuf));
      }
      break;
    case 'w':
      //Activate window and return rect
      HWND wnd;
      wnd = NULL;
      sscanf(parmstart + 1, "%d", &wnd);
      if (!wnd) {
        str = "Content-type: text/plain\r\n\r\n";
        socket->SendExact(str, strlen(str));
        _snprintf(gbuf, 1024, "%d,%d,%d,%d", 0, width, height, 0);
        socket->SendExact(gbuf, strlen(gbuf));
        socket->Close();
        return;
      }
      if (!IsWindow(wnd)) return;
      DWORD oldFLTO;
      SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)&oldFLTO, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
      SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
      ShowWindow(wnd, SW_SHOWNORMAL);
      SetForegroundWindow(wnd);
      SetWindowPos(wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
      RECT rc;
      GetWindowRect(wnd, &rc);
      rc.left -= v_desktop->m_bmrect.left;
      rc.top -= v_desktop->m_bmrect.top;
      rc.right -= v_desktop->m_bmrect.left;
      rc.bottom -= v_desktop->m_bmrect.top;
      str = "Content-type: text/plain\r\n\r\n";
      socket->SendExact(str, strlen(str));
      _snprintf(gbuf, 1024, "%d,%d,%d,%d", rc.top, rc.right, rc.bottom, rc.left);
      socket->SendExact(gbuf, strlen(gbuf));
      socket->Close();
      SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)oldFLTO, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
      break;
  }
  socket->Close();
}

//
// Parse the request tail after the '?' character, and format a sequence
// of <param> tags for the index HTML page with embedded applet.
//

BOOL vncHTTPConnectThread::ParseParams(const char *request,
									   char *result, int max_bytes)
{
	char param_request[128];
	char param_formatted[196];

	result[0] = '\0';
	int cur_bytes = 0;

	const char *tail = request;
	for (;;) {
		// Copy individual "name=value" string into a buffer
		char *delim_ptr = strchr((char *)tail, '&');
		if (delim_ptr == NULL) {
			if (strlen(tail) >= sizeof(param_request)) {
				return FALSE;
			}
			strcpy(param_request, tail);
		} else {
			int len = delim_ptr - tail;
			if (len >= sizeof(param_request)) {
				return FALSE;
			}
			memcpy(param_request, tail, len);
			param_request[len] = '\0';
		}

		// Split the request into parameter name and value
		char *value_str = strchr(&param_request[1], '=');
		if (value_str == NULL) {
			return FALSE;
		}
		*value_str++ = '\0';
		if (strlen(value_str) == 0) {
			return FALSE;
		}

		// Validate both parameter name and value
		if (!ValidateString(param_request) || !ValidateString(value_str)) {
			return FALSE;
		}

		// Prepare HTML-formatted representation of the name=value pair
		int len = sprintf(param_formatted,
						  "      <PARAM NAME=\"%s\" VALUE=\"%s\">\n",
						  param_request, value_str);
		if (cur_bytes + len + 1 > max_bytes) {
			return FALSE;
		}
		strcat(result, param_formatted);
		cur_bytes += len;

		// Go to the next parameter
		if (delim_ptr == NULL) {
			break;
		}
		tail = delim_ptr + 1;
	}
	return TRUE;
}

//
// Check if the string consists only of alphanumeric characters, '+' signs,
// underscores, and dots. Replace all '+' signs with spaces.
//

BOOL vncHTTPConnectThread::ValidateString(char *str)
{
	for (char *ptr = str; *ptr != '\0'; ptr++) {
		if (!isalnum(*ptr) && *ptr != '_' && *ptr != '.') {
			if (*ptr == '+') {
				*ptr = ' ';
			} else {
				return FALSE;
			}
		}
	}
	return TRUE;
}

char *vncHTTPConnectThread::ReadLine(VSocket *socket, char delimiter, int max)
{
	// Allocate the maximum required buffer
	char *buffer = new char[max+1];
	int buffpos = 0;

	// Read in data until a delimiter is read
	for (;;)
	{
		char c;

		if (!socket->ReadExact(&c, 1))
		{
			delete [] buffer;
			return NULL;
		}

		if (c == delimiter)
		{
			buffer[buffpos] = 0;
			return buffer;
		}

		buffer[buffpos] = c;
		buffpos++;

		if (buffpos == (max-1))
		{
			buffer[buffpos] = 0;
			return buffer;
		}
	}
}

//
// Listening thread.
//

class vncHTTPListenThread : public omni_thread
{
public:
	// Init routine
	virtual BOOL Init(VSocket *socket, vncServer *server, BOOL allow_params);

	// Code to be executed by the thread
	virtual void *run_undetached(void * arg);

	// Fields used internally
	BOOL		m_shutdown;

protected:
	vncServer	*m_server;
	VSocket		*m_listen_socket;
	BOOL		m_allow_params;
};

BOOL vncHTTPListenThread::Init(VSocket *listen_socket, vncServer *server,
							   BOOL allow_params)
{
	m_server = server;
	m_listen_socket = listen_socket;
	m_allow_params = allow_params;

	// Start the thread
	m_shutdown = FALSE;
	start_undetached();

	return TRUE;
}

// Code to be executed by the thread
void *vncHTTPListenThread::run_undetached(void * arg)
{
	vnclog.Print(LL_INTINFO, VNCLOG("started HTTP server thread\n"));

	// Go into a loop, listening for connections on the given socket
	while (!m_shutdown) {
		// Accept an incoming connection
		VSocket *new_socket;
		if (!m_listen_socket->TryAccept(&new_socket, 100))
			break;
		if (new_socket != NULL) {
			// Start a client thread for this connection
			vnclog.Print(LL_CLIENTS, VNCLOG("HTTP client connected\n"));
			omni_thread *m_thread = new vncHTTPConnectThread;
			if (m_thread == NULL)
				break;
			((vncHTTPConnectThread *)m_thread)->Init(new_socket, m_server,
													 m_allow_params);
		}
	}

	vnclog.Print(LL_INTINFO, VNCLOG("quitting HTTP server thread\n"));
	return NULL;
}

//
// The vncSockConnect class implementation
//

vncHTTPConnect::vncHTTPConnect()
{
	m_listen_thread = NULL;
}

BOOL vncHTTPConnect::Init(vncServer *server, UINT listen_port, BOOL allow_params)
{
	// Save the port number
	m_listen_port = listen_port;

	// Create the listening socket
	if (!m_listen_socket.Create())
		return FALSE;

	// Bind it
	if (!m_listen_socket.Bind(m_listen_port, server->LoopbackOnly()))
		return FALSE;

	// Set it to listen
	if (!m_listen_socket.Listen())
		return FALSE;

	// Create the new thread
	m_listen_thread = new vncHTTPListenThread;
	if (m_listen_thread == NULL)
		return FALSE;

	// And start it running
	return ((vncHTTPListenThread *)m_listen_thread)->Init(&m_listen_socket, server,
														  allow_params);
}

vncHTTPConnect::~vncHTTPConnect()
{
	m_listen_socket.Shutdown();

	// Join with our lovely thread
	if (m_listen_thread != NULL) {
		((vncHTTPListenThread *)m_listen_thread)->m_shutdown = TRUE;

		void *returnval;
		m_listen_thread->join(&returnval);
		m_listen_thread = NULL;

		m_listen_socket.Close();
    }
}

⌨️ 快捷键说明

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