Thanks, I didn't realize that NativeWindow was capable of its own window. "CreateHandle(new CreateParams())" is what I neeeded.
BTW: I also peek at the WM_DESTROY message in my loop and jump out of the chain if necessary. That way misuse of the component could not corrupt the chain. I don't know if it was necessary but, it made me feel better. --- Marko Milisavljevic <[EMAIL PROTECTED]> wrote: > Mike, > > There is no need for consumer of your component to > know anything about > the hidden window you create to listen to clipboard > messages. I just > built the same thing myself last week. The key is, > the class that > subclasses NativeWindow is private and nested inside > your component. > Your component passes it "this" when you instantiate > it, so it has > access to component's private methods and will raise > the event on it's > behalf. I use a custom event that returns > Clipboard.GetDataObject(), or > you can also just use System.EventHandler and let > consumer of your event > get his own data from the clipboard. > > Below is the relevant code with some comments, > hereby placed in public > domain. > > Hope this helps, > Marko > > public delegate void > ClipboardChangedEventHandler(object sender, > ClipboardChangedEventArgs e); > > public class ClipboardChangedEventArgs : > System.EventArgs { > public readonly IDataObject ClipboardData; > > public ClipboardChangedEventArgs(IDataObject > clipboard) { > ClipboardData = clipboard; > } > } > > public class ClipboardViewer : > System.ComponentModel.Component { > public event ClipboardChangedEventHandler > ClipboardChanged; > > private ClipboardViewerHelper > clipViewHelper; > > public ClipboardViewer () { > clipViewHelper = new > ClipboardViewerHelper(); > } > > protected override void Dispose(bool > disposing) { > if (disposing) { > if (clipViewHelper != null) > { > > clipViewHelper.Dispose(); > clipViewHelper = > null; > } > } > base.Dispose(disposing); > } > > protected virtual void > OnClipboardChanged(ClipboardChangedEventArgs e) { > if (ClipboardChanged != null) { > // It is imperative to raise > event > asynchronously, since this method got called during > // processing of > WM_DRAWCLIPBOARD message. If > consumer of this event does something like pop > // up a MessageBox, we will > crash. This lets us > exit WndProc before event gets processed by > // whoever is consuming it. > > ClipboardChanged.BeginInvoke(this, e, null, > null); > } > } > > private class ClipboardViewerHelper : > System.Windows.Forms.NativeWindow, IDisposable { > > private const int WM_DRAWCLIPBOARD = > 0x308; > private const int WM_CHANGECBCHAIN = > 0x30D; > > [DllImport("user32")] > public static extern bool > ChangeClipboardChain(IntPtr > HWnd, IntPtr HWndNext); > > [DllImport("user32", > SetLastError=true)] > public static extern IntPtr > SetClipboardViewer(IntPtr > HWnd); > > [DllImport("user32.dll", > CharSet=CharSet.Auto, > SetLastError=true)] > public static extern bool > SendNotifyMessage(IntPtr hwnd, > WindowsMessages wMsg, IntPtr wParam, IntPtr lParam); > > private IntPtr hwndNextViewer = > IntPtr.Zero; > private ClipboardViewer owner; > private bool disposed = false; > > public > ClipboardViewerHelper(ClipboardViewer Owner) { > owner = Owner; > CreateHandle(new > CreateParams()); > hwndNextViewer = > SetClipboardViewer(this.Handle); > } > > ~ClipboardViewerHelper() { > Dispose(false); > } > > public void Dispose() { > Dispose(true); > GC.SuppressFinalize(this); > } > > protected virtual void Dispose(bool > disposing) { > lock(this) { > if (!disposed) { > if > (disposing) { > > owner = null; > } > > ChangeClipboardChain(this.Handle, hwndNextViewer); > > DestroyHandle(); > disposed = > true; > } > } > } > > protected override void WndProc(ref > Message m) { > switch (m.Msg) { > case > WM_DRAWCLIPBOARD: > if > (hwndNextViewer != > IntPtr.Zero) { > > SendNotifyMessage(hwndNextViewer, > (WindowsMessages)m.Msg, m.WParam, > m.LParam); > } > try { > > owner.OnClipboardChanged(new > ClipboardChangedEventArgs(Clipboard.GetDataObject())); > } > catch > (Exception e) { > // > better to be silent > here, throwing exceptions or putting up message > boxes > // > from inside WndProc > could crash us or freeze the previous window in > ClipboardViewer chain. > > Debug.WriteLine("can't > Clipboard.GetDataObject(), " + e.ToString()); > } > break; > case > WM_CHANGECBCHAIN: > if (m.WParam > == hwndNextViewer) > { > > hwndNextViewer = > m.LParam; > } > else { > if > (hwndNextViewer != > IntPtr.Zero) { > === message truncated === __________________________________________________ Do You Yahoo!? Yahoo! - Official partner of 2002 FIFA World Cup http://fifaworldcup.yahoo.com You can read messages from the Advanced DOTNET archive, unsubscribe from Advanced DOTNET, or subscribe to other DevelopMentor lists at http://discuss.develop.com.