drawtext auf desktop



  • Hallo.
    Ich möchte Text auf das desktop schreiben und habe mir bissl was mit GDI gebaut.

    Fragen habe ich dabei einige, die vermutlich alle auf "wie geht das eigentlich" hinauslaufen:

    • mache ich das ganze richtig oder ist da viel doof?
    • im moment flimmert das ganze: man sieht die struktur refresh/draw
    • das refresh ist eigentlich unnötig, weil ich so und so alles bemale. allerdings habe ich dann probleme, dass die alte schrift natürlich sichtbar bleibt und man nichts mehr lesen kann

    Grundstruktur des Programms:

    • einige threads, die daten erzeugen

    • ein thread, der daten schreibt:

      • refresh
      • drawtext(daten)
      • print
      • sleep

    meine GDI-Wrapper-Klasse
    noch etwas ungeordnet, aber es funktioniert:

    struct desktop_handle_t
    {
    	desktop_handle_t()
    	{
    		auto desktop_handle = get_desktop_handle();
    
    		desktop.open(desktop_handle);
    		desktop_compatible.open(desktop.value);
    		desktop_bitmap.open(desktop);
    
    		select_src_into_compatible();
    	}
    
    	RECT get_print_rect() const
    	{
    		return desktop.get_rect();
    	}
    
    	HDC get_print_dc() const
    	{
    		return desktop_compatible.value;
    	}
    
    	void refresh()
    	{
    		desktop.clear();
    		copy_desktop_into_bitmap();
    	}
    
    	void print()
    	{
    		copy_compatible_into_desktop();
    	}
    
    	~desktop_handle_t()
    	{
    		try
    		{
    			backup_compatible();
    			desktop_bitmap.close();
    			desktop_compatible.close();
    			desktop.close();
    		}
    		catch (...)
    		{
    			;
    		}
    	}
    
    private:
    	void select_src_into_compatible()
    	{
    		my_assert(compatible_backup == nullptr);
    
    		compatible_backup = (HBITMAP)(SelectObject(desktop_compatible.value, desktop_bitmap.value));
    	}
    
    	void copy_desktop_into_bitmap()
    	{
    		auto dimensions = desktop.get_rect();
    		auto width = dimensions.right - dimensions.left;
    		auto height = dimensions.bottom - dimensions.top;
    
    		auto success = BitBlt(
    			desktop_compatible.value,
    			0,
    			0,
    			width,
    			height,
    			desktop.value,
    			0,
    			0,
    			SRCCOPY
    		);
    
    		if (success == 0)
    		{
    			throw my::platform::exception_t("copy_desktop_into_src: ");
    		}
    	}
    
    	void copy_compatible_into_desktop()
    	{
    		auto dimensions = desktop.get_rect();
    		auto width = dimensions.right - dimensions.left;
    		auto height = dimensions.bottom - dimensions.top;
    
    		auto success = BitBlt(
    			desktop.value,
    			0,
    			0,
    			width,
    			height,
    			desktop_compatible.value,
    			0,
    			0,
    			SRCCOPY
    		);
    
    		if (success == 0)
    		{
    			throw my::platform::exception_t("copy_compatible_into_desktop: ");
    		}
    	}
    
    	void backup_compatible()
    	{
    		if (compatible_backup != nullptr)
    		{
    			SelectObject(desktop_compatible.value, compatible_backup);
    			compatible_backup = nullptr;
    		}
    	}
    
    private:
    	static HWND get_desktop_handle()
    	{
    		auto program_handle = FindWindowA("ProgMan", NULL);
    
    		if (program_handle == nullptr)
    			throw my::platform::exception_t("progman not found");
    
    		auto shell_handle = FindWindowExA(program_handle, NULL, "SHELLDLL_DefView", NULL);
    
    		if (shell_handle == nullptr)
    			throw my::platform::exception_t("SHELLDLL_DefView not found");
    
    		auto desktop_handle_window = FindWindowExA(shell_handle, NULL, "SysListView32", NULL);
    
    		if (desktop_handle_window == nullptr)
    			throw my::platform::exception_t("desktop-HWND not found");
    
    		return desktop_handle_window;
    	}
    	
    	gdi::hdc desktop;
    	gdi::hdc_compatible desktop_compatible;
    	gdi::compatible_bitmap desktop_bitmap;
    	HBITMAP compatible_backup = nullptr;
    };
    

    gdi-wrapper-klassen sind dabei:

    namespace gdi
    {
    	struct hdc_compatible
    	{
    		hdc_compatible(const hdc_compatible&) = delete;
    		hdc_compatible(hdc_compatible&&) = delete;
    		hdc_compatible& operator=(const hdc_compatible&) = delete;
    		hdc_compatible& operator=(hdc_compatible&&) = delete;
    
    		hdc_compatible() : value(nullptr) {}
    		void open(HDC src)
    		{
    			close();
    
    			value = CreateCompatibleDC(src);
    
    			if (value == nullptr)
    			{
    				throw my::platform::exception_t("hdc_compatible: ");
    			}
    		}
    		void close()
    		{
    			if (value != nullptr)
    			{
    				DeleteDC(value);
    				value = nullptr;
    			}
    
    		}
    
    		~hdc_compatible() { close(); }
    
    		HDC value;
    	};
    	struct hdc
    	{
    		hdc(const hdc&) = delete;
    		hdc(hdc&&) = delete;
    		hdc& operator=(const hdc&) = delete;
    		hdc& operator=(hdc&&) = delete;
    
    		hdc() : value(nullptr), hwnd(nullptr) {}
    
    		void clear()
    		{
    			RECT content_rect = get_rect();
    			RedrawWindow(hwnd, &content_rect, NULL, RDW_NOERASE | RDW_INVALIDATE | RDW_UPDATENOW);
    		}
    
    		void open(HWND src)
    		{
    			close();
    
    			hwnd = src;
    			value = GetDC(hwnd);
    
    			if (value == nullptr)
    			{
    				throw my::platform::exception_t("hdc: ");
    			}
    
    			clear();
    		}
    		RECT get_rect() const
    		{
    			RECT ret_val;
    			GetWindowRect(hwnd, &ret_val);
    			return ret_val;
    		}
    		void close()
    		{
    			if (value != nullptr)
    			{
    				clear();
    				ReleaseDC(hwnd, value);
    				value = nullptr;
    			}
    		}
    		~hdc() { close(); }
    
    		HDC value;
    		HWND get_handle() const
    		{
    			return hwnd;
    		}
    	private:
    		HWND hwnd;
    	};
    	struct compatible_bitmap
    	{
    		compatible_bitmap(const compatible_bitmap&) = delete;
    		compatible_bitmap(compatible_bitmap&&) = delete;
    		compatible_bitmap& operator=(const compatible_bitmap&) = delete;
    		compatible_bitmap& operator=(compatible_bitmap&&) = delete;
    
    		compatible_bitmap() : value(nullptr) {}
    
    		void copy_from(HBITMAP src)
    		{
    			close();
    
    			value = (HBITMAP)CopyImage(src, IMAGE_BITMAP, 0, 0, 0);
    
    			if (value == nullptr)
    			{
    				throw my::platform::exception_t("compatible_bitmap (copy): ");
    			}
    		}
    
    		void open(hdc& src)
    		{
    			close();
    
    			auto dimensions = src.get_rect();
    			auto width = dimensions.right - dimensions.left;
    			auto height = dimensions.bottom - dimensions.top;
    
    			value = CreateCompatibleBitmap(src.value, width, height);
    
    			if (value == nullptr)
    			{
    				throw my::platform::exception_t("compatible_bitmap (open): ");
    			}
    		}
    
    		void close()
    		{
    			if (value != nullptr)
    			{
    				DeleteObject(value);
    				value = nullptr;
    			}
    		}
    		~compatible_bitmap() { close(); }
    
    		HBITMAP value;
    	};
    }
    

    wäre schön, wenn mal jemand mit etwas ahnung paar links posten könnte und/oder was dazu sagt

    danke im voraus 🙂


  • Mod

    Du kannst so nicht in ein fremdes Fenster schreiben.
    Das ist nie persitent.

    Du könntest eine DLL schreiben, den Desktop Window Thread hooken und WM_PAINT abfangen und nach Behandlung von WM_PAINT Deine Ausgabe starten.



  • @Martin-Richter
    dass es nicht persistent ist, ist schon klar.
    deshalb male ich es ja immer wieder neu.

    ich denke, ich muss 2 buffer haben und die abwechselnd beschreiben und dann in das compatible_hdc kopieren.
    aber ich dachte, ich frage erst mal, bevor ich (noch mehr) unfug mache 😉

    danke schon mal; aber dort möchte ich unbedingt hinmalen^^



  • Wenn du ein Popupfenster mit dem Stil WS_EX_LAYERED und Colorkey nimmst, erzielst du doch genau den gleichen Effekt? Mit dem Stil WS_EX_TOOLWINDOW wird auch kein Eintrag in der Taskleiste angezeigt.
    Und man hat keine Probleme, wenn der Nutzer ein Fenster drüberzieht. Außerdem kann man den Text (also das Fenster) als Nutzer auch noch selber platzieren.

    Ansonsten hat Petzold das mit LockWindowUpdate und GetDCEx mit entsprechenden Flags gemacht. Das klappte aber schon unter XP nicht (mehr?) gut.