コード例 #1
0
            /// <summary>
            /// Creates native/unmanaged window of a class registered with <see cref="RegisterWindowClass"/> with null <i>wndProc</i>, and sets its window procedure.
            /// </summary>
            /// <exception cref="ArgumentException">The class is not registered with <see cref="RegisterWindowClass"/>, or registered with non-null <i>wndProc</i>.</exception>
            /// <exception cref="AuException">Failed to create window. Unlikely.</exception>
            /// <remarks>
            /// Calls API <msdn>CreateWindowEx</msdn>.
            /// Protects the <i>wndProc</i> delegate from GC.
            /// Later call <see cref="DestroyWindow"/> or <see cref="Close"/>.
            /// </remarks>
            public static AWnd CreateWindow(Native.WNDPROC wndProc, string className, string name = null, WS style = 0, WS2 exStyle = 0, int x = 0, int y = 0, int width = 0, int height = 0, AWnd parent = default, LPARAM controlId = default, IntPtr hInstance = default, LPARAM param = default)
            {
                var a = t_windows ??= new List <(AWnd w, Native.WNDPROC p)>();

                for (int i = a.Count; --i >= 0;)
                {
                    if (!a[i].w.IsAlive)
                    {
                        a.RemoveAt(i);
                    }
                }

                lock (s_classes) {
                    if (!s_classes.TryGetValue(className, out var wp) || wp != null)
                    {
                        throw new ArgumentException("Window class must be registered with RegisterWindowClass with null wndProc");
                    }
                }

                AWnd w;

                //need to cubclass the new window. But not after CreateWindowEx, because wndProc must receive all messages.
#if CW_CBT                                       //slightly slower and dirtier. Invented before Core, to support multiple appdomains.
                using (AHookWin.ThreadCbt(c => { //let CBT hook subclass before any messages
                    if (c.code == HookData.CbtEvent.CREATEWND)
                    {
                        //note: unhook as soon as possible. Else possible exception etc.
                        //	If eg hook proc uses 'lock' and that 'lock' must wait,
                        //		our hook proc is called again and again while waiting, until 'lock' throws exception.
                        //	In STA thread 'lock' dispatches messages, but I don't know why hook proc is called multiple times for same event.
                        c.hook.Unhook();

                        var ww = (AWnd)c.wParam;
                        Debug.Assert(ww.ClassNameIs(className));
                        ww.SetWindowLong(Native.GWL.WNDPROC, Marshal.GetFunctionPointerForDelegate(wndProc));
                    }
                    else
                    {
                        Debug.Assert(false);
                    }
                    return(false);
                })) {
                    w = Api.CreateWindowEx(exStyle, className, name, style, x, y, width, height, parent, controlId, hInstance, param);
                }
#else
                t_cwProc = wndProc;                 //let _DefWndProc subclass on first message
                try { w = Api.CreateWindowEx(exStyle, className, name, style, x, y, width, height, parent, controlId, hInstance, param); }
                finally { t_cwProc = null; }        //if CreateWindowEx failed and _CWProc not called
#endif

                if (w.Is0)
                {
                    throw new AuException(0);
                }
                a.Add((w, wndProc));
                return(w);
            }
コード例 #2
0
            //public void ShowAnimate(bool show)
            //{
            //	//Don't add AWnd function, because:
            //		//Rarely used.
            //		//Api.AnimateWindow() works only with windows of current thread.
            //		//Only programmers would need it, and they can call the API directly.
            //}


            /// <summary>
            /// Registers new window class in this process.
            /// </summary>
            /// <param name="className">Class name.</param>
            /// <param name="wndProc">
            /// Delegate of a window procedure. See <msdn>Window Procedures</msdn>.
            ///
            /// Use null when you need a different delegate (method or target object) for each window instance; create windows with <see cref="CreateWindow(Native.WNDPROC, string, string, WS, WS2, int, int, int, int, AWnd, LPARAM, IntPtr, LPARAM)"/> or <see cref="CreateMessageOnlyWindow(Native.WNDPROC, string)"/>.
            /// If not null, it must be a static method; create windows with any other function, including API <msdn>CreateWindowEx</msdn>.
            /// </param>
            /// <param name="ex">
            /// Can be used to specify more fields of <msdn>WNDCLASSEX</msdn> that is passed to API <msdn>RegisterClassEx</msdn>.
            /// Defaults: hCursor = arrow; hbrBackground = COLOR_BTNFACE+1; style = CS_GLOBALCLASS; others = 0/null/default.
            /// This function also adds CS_GLOBALCLASS style.
            /// </param>
            /// <exception cref="ArgumentException"><i>wndProc</i> is an instance method. Must be static method or null. If need instance method, use null here and pass <i>wndProc</i> to <see cref="CreateWindow"/>.</exception>
            /// <exception cref="InvalidOperationException">The class already registered with this function and different <i>wndProc</i> (another method or another target object).</exception>
            /// <exception cref="Win32Exception">Failed, for example if the class already exists and was registered not with this function.</exception>
            /// <remarks>
            /// Calls API <msdn>RegisterClassEx</msdn>.
            /// The window class is registered until this process ends. Don't need to unregister.
            /// If called next time for the same window class, does nothing if <i>wndProc</i> is equal to the previous (or both null). Then ignores <i>ex</i>. Throws exception if different.
            /// Thread-safe.
            /// Protects the <i>wndProc</i> delegate from GC.
            /// </remarks>
            public static unsafe void RegisterWindowClass(string className, Native.WNDPROC wndProc = null, WndClassEx ex = null)
            {
                if (wndProc?.Target != null)
                {
                    throw new ArgumentException("wndProc must be static method or null. Use non-static wndProc with CreateWindow.");
                }

                lock (s_classes) {
                    if (s_classes.TryGetValue(className, out var wpPrev))
                    {
                        if (wpPrev != wndProc)
                        {
                            throw new InvalidOperationException("Window class already registered");                                           //another method or another target object
                        }
                        return;
                    }
                    var x = new Api.WNDCLASSEX(ex);

                    fixed(char *pCN = className)
                    {
                        x.lpszClassName = pCN;
                        if (wndProc != null)
                        {
                            x.lpfnWndProc = Marshal.GetFunctionPointerForDelegate(wndProc);
                        }
                        else
                        {
#if CW_CBT
                            if (s_defWindowProc == default)
                            {
                                s_defWindowProc = Api.GetProcAddress("user32.dll", "DefWindowProcW");
                            }
                            x.lpfnWndProc = s_defWindowProc;
#else
                            if (s_cwProcFP == default)
                            {
                                s_cwProcFP = Marshal.GetFunctionPointerForDelegate(s_cwProc);
                            }
                            x.lpfnWndProc = s_cwProcFP;
#endif
                        }
                        x.style |= Api.CS_GLOBALCLASS;

                        if (0 == Api.RegisterClassEx(x))
                        {
                            throw new Win32Exception();
                        }
                        //note: we don't return atom because: 1. Rarely used. 2. If assigned to an unused field, compiler may remove the function call.

                        s_classes.Add(className, wndProc);
                    }
                }
            }
コード例 #3
0
            /// <summary>
            /// Subclasses clipOwner.
            /// </summary>
            /// <param name="paste">true if used for paste, false if for copy.</param>
            /// <param name="data">If used for paste, can be string containing Unicode text or int/string dictionary containing clipboard format/data.</param>
            /// <param name="clipOwner">Our clipboard owner window.</param>
            /// <param name="wFocus">The target control or window.</param>
            public _ClipboardListener(bool paste, object data, AWnd clipOwner, AWnd wFocus)
            {
                _paste   = paste;
                _data    = data;
                _wndProc = _WndProc;
                _wFocus  = wFocus;
                clipOwner.SetWindowLong(Native.GWL.WNDPROC, Marshal.GetFunctionPointerForDelegate(_wndProc));

                //rejected: use SetClipboardViewer to block clipboard managers/viewers/etc. This was used in QM2.
                //	Nowadays most such programs don't use SetClipboardViewer. Probably they use AddClipboardFormatListener+WM_CLIPBOARDUPDATE.
                //	known apps that have clipboard viewer installed with SetClipboardViewer:
                //		OpenOffice, LibreOffice: tested Writer, Calc.
                //		VLC: after first Paste.
                //_wPrevClipViewer = Api.SetClipboardViewer(clipOwner);
                //AOutput.Write(_wPrevClipViewer);

                //TRY: Hook posted messages (in C++ dll) and block WM_CLIPBOARDUPDATE. Then don't need _DisableClipboardHistory.
            }
コード例 #4
0
 /// <summary>
 /// Creates native/unmanaged <msdn>message-only window</msdn> of a class registered with <see cref="RegisterWindowClass"/> with null <i>wndProc</i>, and sets its window procedure.
 /// </summary>
 /// <param name="className">Window class name.</param>
 /// <param name="wndProc"></param>
 /// <exception cref="ArgumentException">The class is not registered with <see cref="RegisterWindowClass"/>, or registered with non-null <i>wndProc</i>.</exception>
 /// <exception cref="AuException">Failed to create window. Unlikely.</exception>
 /// <remarks>
 /// Styles: WS_POPUP, WS_EX_NOACTIVATE.
 /// Protects the <i>wndProc</i> delegate from GC.
 /// Later call <see cref="DestroyWindow"/> or <see cref="Close"/>.
 /// </remarks>
 public static AWnd CreateMessageOnlyWindow(Native.WNDPROC wndProc, string className)
 {
     return(CreateWindow(wndProc, className, null, WS.POPUP, WS2.NOACTIVATE, parent: Native.HWND.MESSAGE));
     //note: WS_EX_NOACTIVATE is important.
 }