diff foosdk/sdk/pfc/win-objects.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/foosdk/sdk/pfc/win-objects.h	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,348 @@
+#pragma once
+
+#include "ref_counter.h"
+
+namespace pfc {
+	BOOL winFormatSystemErrorMessage(pfc::string_base & p_out,DWORD p_code);
+
+	// Prefix filesystem paths with \\?\ and \\?\UNC where appropriate.
+	void winPrefixPath(pfc::string_base & out, const char * p_path);
+	// Reverse winPrefixPath
+	void winUnPrefixPath(pfc::string_base & out, const char * p_path);
+
+	string8 winPrefixPath( const char * in );
+	string8 winUnPrefixPath( const char * in );
+
+	class LastErrorRevertScope {
+	public:
+		LastErrorRevertScope() : m_val(GetLastError()) {}
+		~LastErrorRevertScope() { SetLastError(m_val); }
+
+	private:
+		const DWORD m_val;
+	};
+
+	string8 getWindowText(HWND wnd);
+	void setWindowText(HWND wnd, const char * txt); 
+	string8 getWindowClassName( HWND wnd );
+	HWND findOwningPopup(HWND wnd);
+}
+
+pfc::string8 format_win32_error(DWORD code);
+pfc::string8 format_hresult(HRESULT code);
+pfc::string8 format_hresult(HRESULT code, const char * msgOverride);
+
+class exception_win32 : public std::exception {
+public:
+	exception_win32(DWORD p_code) : std::exception(format_win32_error(p_code)), m_code(p_code) {}
+	DWORD get_code() const {return m_code;}
+private:
+	DWORD m_code;
+};
+
+#ifdef PFC_WINDOWS_DESKTOP_APP
+
+void uAddWindowStyle(HWND p_wnd,LONG p_style);
+void uRemoveWindowStyle(HWND p_wnd,LONG p_style);
+void uAddWindowExStyle(HWND p_wnd,LONG p_style);
+void uRemoveWindowExStyle(HWND p_wnd,LONG p_style);
+unsigned MapDialogWidth(HWND p_dialog,unsigned p_value);
+bool IsKeyPressed(unsigned vk);
+
+//! Returns current modifier keys pressed, using win32 MOD_* flags.
+unsigned GetHotkeyModifierFlags();
+
+class CClipboardOpenScope {
+public:
+	CClipboardOpenScope() : m_open(false) {}
+	~CClipboardOpenScope() {Close();}
+	bool Open(HWND p_owner);
+	void Close();
+private:
+	bool m_open;
+	
+	PFC_CLASS_NOT_COPYABLE_EX(CClipboardOpenScope)
+};
+
+class CGlobalLockScope {
+public:
+	CGlobalLockScope(HGLOBAL p_handle);
+	~CGlobalLockScope();
+	void * GetPtr() const {return m_ptr;}
+	t_size GetSize() const {return GlobalSize(m_handle);}
+private:
+	void * m_ptr;
+	HGLOBAL m_handle;
+
+	PFC_CLASS_NOT_COPYABLE_EX(CGlobalLockScope)
+};
+
+template<typename TItem> class CGlobalLockScopeT {
+public:
+	CGlobalLockScopeT(HGLOBAL handle) : m_scope(handle) {}
+	TItem * GetPtr() const {return reinterpret_cast<TItem*>(m_scope.GetPtr());}
+	t_size GetSize() const {
+		const t_size val = m_scope.GetSize();
+		PFC_ASSERT( val % sizeof(TItem) == 0 );
+		return val / sizeof(TItem);
+	}
+private:
+	CGlobalLockScope m_scope;
+};
+
+//! Resigns active window status passing it to the parent window, if wnd or a child popup of is active. \n
+//! Use this to mitigate Windows 10 1809 active window handling bugs - call prior to DestroyWindow()
+void ResignActiveWindow(HWND wnd);
+//! Is point inside a control?
+bool IsPointInsideControl(const POINT& pt, HWND wnd);
+//! Is <child> a control inside <parent> window? Also returns true if child==parent.
+bool IsWindowChildOf(HWND child, HWND parent);
+//! Is <child> window a child (popup or control) of <parent> window? Also returns true if child==parent.
+bool IsPopupWindowChildOf(HWND child, HWND parent);
+
+class win32_menu {
+public:
+	win32_menu(HMENU p_initval) : m_menu(p_initval) {}
+	win32_menu() : m_menu(NULL) {}
+	~win32_menu() {release();}
+	void release();
+	void set(HMENU p_menu) {release(); m_menu = p_menu;}
+	void create_popup();
+	HMENU get() const {return m_menu;}
+	HMENU detach() {return pfc::replace_t(m_menu,(HMENU)NULL);}
+	
+	bool is_valid() const {return m_menu != NULL;}
+private:
+	win32_menu(const win32_menu &) = delete;
+	void operator=(const win32_menu &) = delete;
+
+	HMENU m_menu;
+};
+
+#endif
+
+class win32_event {
+public:
+	win32_event() : m_handle(NULL) {}
+	~win32_event() {release();}
+
+	void create(bool p_manualreset,bool p_initialstate);
+	
+	void set(HANDLE p_handle) {release(); m_handle = p_handle;}
+	HANDLE get() const {return m_handle;}
+	HANDLE get_handle() const {return m_handle;}
+	HANDLE detach() {return pfc::replace_t(m_handle,(HANDLE)NULL);}
+	bool is_valid() const {return m_handle != NULL;}
+	
+	void release();
+
+	//! Returns true when signaled, false on timeout
+	bool wait_for(double p_timeout_seconds) {return g_wait_for(get(),p_timeout_seconds);}
+    void wait() { wait_for(-1); }
+    void wait_and_clear() { wait(); set_state(false); }
+    
+	static DWORD g_calculate_wait_time(double p_seconds);
+
+	//! Returns true when signaled, false on timeout
+	static bool g_wait_for(HANDLE p_event,double p_timeout_seconds);
+
+	void set_state(bool p_state);
+	bool is_set() { return wait_for(0); }
+
+    // Two-wait event functions, return 0 on timeout, 1 on evt1 set, 2 on evt2 set
+    static int g_twoEventWait( win32_event & ev1, win32_event & ev2, double timeout );
+    static int g_twoEventWait( HANDLE ev1, HANDLE ev2, double timeout );
+
+	// Multi-wait. Returns SIZE_MAX on timeout, 0 based event index if either event becomes set.
+	static size_t g_multiWait(const HANDLE* events, size_t count, double timeout);
+    static size_t g_multiWait( std::initializer_list<HANDLE> const & arg, double timeout );
+private:
+	win32_event(const win32_event&) = delete;
+	void operator=(const win32_event &) = delete;
+
+	HANDLE m_handle;
+};
+
+namespace pfc {
+	typedef HANDLE eventHandle_t;
+
+	static constexpr eventHandle_t eventInvalid = NULL;
+
+	class event : public win32_event {
+	public:
+		event(bool initial = false) { create(true, initial); }
+
+		HANDLE get_handle() const { return win32_event::get(); }
+	};
+}
+
+void uSleepSeconds(double p_time,bool p_alertable);
+
+#ifdef PFC_WINDOWS_DESKTOP_APP
+
+class win32_icon {
+public:
+	win32_icon(HICON p_initval) : m_icon(p_initval) {}
+	win32_icon() : m_icon(NULL) {}
+	~win32_icon() {release();}
+
+	void release();
+
+	void set(HICON p_icon) {release(); m_icon = p_icon;}
+	HICON get() const {return m_icon;}
+	HICON detach() {return pfc::replace_t(m_icon,(HICON)NULL);}
+
+	bool is_valid() const {return m_icon != NULL;}
+
+private:
+	win32_icon(const win32_icon&) = delete;
+	const win32_icon & operator=(const win32_icon &) = delete;
+
+	HICON m_icon;
+};
+
+class win32_accelerator {
+public:
+	win32_accelerator() : m_accel(NULL) {}
+	~win32_accelerator() {release();}
+	HACCEL get() const {return m_accel;}
+
+	void load(HINSTANCE p_inst,const TCHAR * p_id);
+	void release();
+private:
+	HACCEL m_accel;
+	PFC_CLASS_NOT_COPYABLE_EX(win32_accelerator);
+};
+
+class SelectObjectScope {
+public:
+	SelectObjectScope(HDC p_dc,HGDIOBJ p_obj) throw() : m_dc(p_dc), m_obj(SelectObject(p_dc,p_obj)) {}
+	~SelectObjectScope() throw() {SelectObject(m_dc,m_obj);}
+private:
+	PFC_CLASS_NOT_COPYABLE_EX(SelectObjectScope)
+	HDC m_dc;
+	HGDIOBJ m_obj;
+};
+
+// WARNING: Windows is known to truncate the coordinates to float32 internally instead of retaining original int
+// With large values, this OffsetWindowOrgEx behaves erratically
+class OffsetWindowOrgScope {
+public:
+	OffsetWindowOrgScope(HDC dc, const POINT & pt) throw() : m_dc(dc), m_pt(pt) {
+		OffsetWindowOrgEx(m_dc, m_pt.x, m_pt.y, NULL);
+	}
+	~OffsetWindowOrgScope() throw() {
+		OffsetWindowOrgEx(m_dc, -m_pt.x, -m_pt.y, NULL);
+	}
+
+private:
+	const HDC m_dc;
+	const POINT m_pt;
+};
+class DCStateScope {
+public:
+	DCStateScope(HDC p_dc) throw() : m_dc(p_dc) {
+		m_state = SaveDC(m_dc);
+	}
+	~DCStateScope() throw() {
+		RestoreDC(m_dc,m_state);
+	}
+private:
+	const HDC m_dc;
+	int m_state;
+};
+#endif // #ifdef PFC_WINDOWS_DESKTOP_APP
+
+class exception_com : public std::exception {
+public:
+	exception_com(HRESULT p_code) : std::exception(format_hresult(p_code)), m_code(p_code) {}
+	exception_com(HRESULT p_code, const char * msg) : std::exception(format_hresult(p_code, msg)), m_code(p_code) {}
+	HRESULT get_code() const {return m_code;}
+private:
+	HRESULT m_code;
+};
+
+#ifdef PFC_WINDOWS_DESKTOP_APP
+
+// Same format as _WIN32_WINNT macro.
+WORD GetWindowsVersionCode() throw();
+
+#endif
+
+//! Simple implementation of a COM reference counter. The initial reference count is zero, so it can be used with pfc::com_ptr_t<> with plain operator=/constructor rather than attach().
+template<typename TBase> class ImplementCOMRefCounter : public TBase {
+public:
+    template<typename ... arg_t> ImplementCOMRefCounter(arg_t && ... arg) : TBase(std::forward<arg_t>(arg) ...) {}
+
+	ULONG STDMETHODCALLTYPE AddRef() override {
+		return ++m_refcounter;
+	}
+	ULONG STDMETHODCALLTYPE Release() override {
+		long val = --m_refcounter;
+		if (val == 0) delete this;
+		return val;
+	}
+protected:
+	virtual ~ImplementCOMRefCounter() {}
+private:
+	pfc::refcounter m_refcounter;
+};
+
+
+
+template<typename TPtr>
+class CoTaskMemObject {
+public:
+	CoTaskMemObject() : m_ptr() {}
+
+	~CoTaskMemObject() {CoTaskMemFree(m_ptr);}
+	void Reset() {CoTaskMemFree(pfc::replace_null_t(m_ptr));}
+	TPtr * Receive() {Reset(); return &m_ptr;}
+
+	TPtr m_ptr;
+	PFC_CLASS_NOT_COPYABLE(CoTaskMemObject, CoTaskMemObject<TPtr> );
+};
+
+
+namespace pfc {
+    bool isShiftKeyPressed();
+    bool isCtrlKeyPressed();
+    bool isAltKeyPressed();
+
+	class winHandle {
+	public:
+		winHandle(HANDLE h_ = INVALID_HANDLE_VALUE) : h(h_) {}
+		~winHandle() { Close(); }
+		void Close() {
+			if (h != INVALID_HANDLE_VALUE && h != NULL ) { CloseHandle(h); h = INVALID_HANDLE_VALUE; }
+		}
+
+		void Attach(HANDLE h_) { Close(); h = h_; }
+		HANDLE Detach() { HANDLE t = h; h = INVALID_HANDLE_VALUE; return t; }
+
+		HANDLE Get() const { return h; }
+		operator HANDLE() const { return h; }
+
+		HANDLE h;
+	private:
+		winHandle(const winHandle&) = delete;
+		void operator=(const winHandle&) = delete;
+	};
+    
+    void winSleep( double seconds );
+    void sleepSeconds(double seconds);
+    void yield();
+
+#ifdef PFC_WINDOWS_DESKTOP_APP
+	void winSetThreadDescription(HANDLE hThread, const wchar_t * desc);
+
+	pfc::string8 format_window(HWND wnd);
+	pfc::string8 format_windowStyle(DWORD);
+#endif // PFC_WINDOWS_DESKTOP_APP
+
+	int winNaturalSortCompare(const char* s1, const char* s2);
+	int winNaturalSortCompare(const wchar_t* s1, const wchar_t* s2);
+	int winNaturalSortCompareI(const char* s1, const char* s2);
+	int winNaturalSortCompareI(const wchar_t* s1, const wchar_t* s2);
+
+}