diff options
Diffstat (limited to 'scripts/windows_input/Native.cs')
| -rw-r--r-- | scripts/windows_input/Native.cs | 63 |
1 files changed, 56 insertions, 7 deletions
diff --git a/scripts/windows_input/Native.cs b/scripts/windows_input/Native.cs index 5f941f1a..42b387b1 100644 --- a/scripts/windows_input/Native.cs +++ b/scripts/windows_input/Native.cs @@ -115,6 +115,7 @@ namespace HerdrInputGauntlet { [DllImport("user32.dll")] static extern bool CloseClipboard(); [DllImport("user32.dll")] static extern bool EmptyClipboard(); [DllImport("user32.dll")] static extern IntPtr SetClipboardData(uint format,IntPtr value); + [DllImport("user32.dll",CharSet=CharSet.Unicode)] static extern uint RegisterClipboardFormat(string format); [DllImport("kernel32.dll")] static extern IntPtr GlobalAlloc(uint flags,UIntPtr size); [DllImport("kernel32.dll")] static extern IntPtr GlobalLock(IntPtr memory); [DllImport("kernel32.dll")] static extern bool GlobalUnlock(IntPtr memory); @@ -142,6 +143,7 @@ namespace HerdrInputGauntlet { } public static uint SetEmptyClipboard(IntPtr owner,string text) { + if(owner==IntPtr.Zero) throw new Exception("Clipboard owner is required"); if(!OpenClipboard(owner)) throw new Exception("Clipboard busy; refusing replacement"); IntPtr memory=IntPtr.Zero; try { @@ -155,17 +157,64 @@ namespace HerdrInputGauntlet { if(!EmptyClipboard() || SetClipboardData(13,memory)==IntPtr.Zero) throw new Exception("Clipboard write failed"); memory=IntPtr.Zero; // ownership transferred to Windows } finally { if(memory!=IntPtr.Zero) GlobalFree(memory); CloseClipboard(); } + return AdoptClipboardLease(owner); + } + public static uint SetEmptyClipboardImage(IntPtr owner,string text) { + if(owner==IntPtr.Zero) throw new Exception("Clipboard owner is required"); + if(!OpenClipboard(owner)) throw new Exception("Clipboard busy; refusing replacement"); + IntPtr pngMemory=IntPtr.Zero,textMemory=IntPtr.Zero; + bool complete=false; + try { + if(CountClipboardFormats()!=0) throw new Exception("Clipboard changed or contains user data; refusing replacement"); + byte[] png=Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAANSURBVBhXY/jPwPAfAAUAAf+mXJtdAAAAAElFTkSuQmCC"); + pngMemory=GlobalAlloc(2,new UIntPtr((uint)png.Length)); + if(pngMemory==IntPtr.Zero) throw new Exception("Clipboard allocation failed"); + var pointer=GlobalLock(pngMemory); + if(pointer==IntPtr.Zero) throw new Exception("Clipboard allocation failed"); + try { Marshal.Copy(png,0,pointer,png.Length); } finally { GlobalUnlock(pngMemory); } + if(!EmptyClipboard()) throw new Exception("Clipboard clear failed"); + uint pngFormat=RegisterClipboardFormat("PNG"); + if(pngFormat==0 || SetClipboardData(pngFormat,pngMemory)==IntPtr.Zero) throw new Exception("Clipboard image write failed"); + pngMemory=IntPtr.Zero; + if(text!=null) { + byte[] data=Encoding.Unicode.GetBytes(text+"\0"); + textMemory=GlobalAlloc(2,new UIntPtr((uint)data.Length)); + if(textMemory==IntPtr.Zero) throw new Exception("Clipboard allocation failed"); + pointer=GlobalLock(textMemory); + if(pointer==IntPtr.Zero) throw new Exception("Clipboard allocation failed"); + try { Marshal.Copy(data,0,pointer,data.Length); } finally { GlobalUnlock(textMemory); } + if(SetClipboardData(13,textMemory)==IntPtr.Zero) throw new Exception("Clipboard text write failed"); + textMemory=IntPtr.Zero; + } + complete=true; + } finally { + if(!complete) EmptyClipboard(); + if(pngMemory!=IntPtr.Zero) GlobalFree(pngMemory); + if(textMemory!=IntPtr.Zero) GlobalFree(textMemory); + CloseClipboard(); + } + return AdoptClipboardLease(owner); + } + static uint AdoptClipboardLease(IntPtr owner) { // Closing can synthesize additional formats and advance the sequence. - // Reopen before adopting it so another writer cannot become our lease. - if(!OpenClipboard(owner)) throw new Exception("Clipboard busy; cannot establish test ownership"); + uint sequence=GetClipboardSequenceNumber(); try { - if(owner==IntPtr.Zero || GetClipboardOwner()!=owner) throw new Exception("Clipboard ownership changed; refusing cleanup lease"); - return GetClipboardSequenceNumber(); - } finally { CloseClipboard(); } + if(!OpenClipboard(owner)) throw new Exception("Clipboard busy; cannot establish test ownership"); + try { + if(GetClipboardOwner()!=owner || GetClipboardSequenceNumber()!=sequence) + throw new Exception("Clipboard ownership changed; refusing cleanup lease"); + return sequence; + } finally { CloseClipboard(); } + } catch(Exception error) { + if(!ClearOwnedClipboard(owner,sequence)) + throw new Exception("Could not clean clipboard after ownership verification failed",error); + throw; + } } - public static bool ClearOwnedClipboard(uint sequence) { + public static bool ClearOwnedClipboard(IntPtr owner,uint sequence) { + if(owner==IntPtr.Zero) return false; if(!OpenClipboard(IntPtr.Zero)) return false; - try { return GetClipboardSequenceNumber()!=sequence || EmptyClipboard(); } + try { return GetClipboardSequenceNumber()!=sequence || GetClipboardOwner()!=owner || EmptyClipboard(); } finally { CloseClipboard(); } } public static string Title(IntPtr hwnd) { var text=new StringBuilder(1024); GetWindowText(hwnd,text,text.Capacity); return text.ToString(); } |
