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.