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.

Reply via email to