views:

50

answers:

1

I'm trying allow drag and drop to the tray icon on my application.

I know it's impossible to do this with the higher level C# WindowsForms API, since NotifyIcon doesn't support drag events.

So with a little help of a more windows-experienced friend I set out to try this via Win32 API. The idea was registering a hook in the tray window handler (after setting DragAcceptFiles(hWnd,TRUE); on the "SysPager" window handler).

The hooking and dropping part is working from the tray to the DLL.

LRESULT CALLBACK myHookProc (int code, WPARAM wParam, LPARAM lParam){
  if (code == HC_ACTION)
  {
    PMSG msg = (PMSG) lParam;
    switch(msg->message){
      case WM_DROPFILES:
        ::MessageBox(NULL, L"Dropped files!", L"Test", MB_OK);
        // call my app's registered hook
        break;
  }
  return CallNextHookEx(oldHookProc, code, wParam, lParam);
}

As expected I get the message box popping up.

The problem is that I now need to call a function on my C# (WindowsForms) application to notify of this event. Here's where I ran into brick wall.

When I register the callback from my application in the DLL, I store it; but when myHookProc is called, it's value is NULL.

Turns out I was misunderstanding how DLLs work; there isn't a shared instance between my application and the tray area (they're copied or each has its own "instance" if you could call it that) so I can't use any static variables or anything like that to hold the callback reference back to my application.

Spent a couple of hours investigating this and the only solution seems to be shared memory (tried the #pragma data_seg I ran into in some forum, but to no avail), but it starts to feel too much of an overkill for such a "simple" use case.

So the million dollar questions are:

  1. Is it really necessary to offload the hooking to a DLL?
  2. Do I really need to resort to shared memory to accomplish this?
  3. (Bonus question) WM_DROPFILES only works for files; how can I get a drop event fired for text?

Please keep in mind this is my first shot with .NET, C# and Win32 (less than a week); detailed answers explaining why - rather than just stating - will be greatly appreciated!

Thanks.

+1  A: 

Yes, you really need to do those things because the window is owned by another process. Global hooks require a DLL that can be injected. Full D+D support requires RegisterDragDrop and COM code. Icky COM code.

And no, you really should not do this because somebody else might have already had the same idea as you. And got his program shipped first. The appcompat team at MSFT must have a nightmare with it. Careful with Raymond Chen, he's got a Bad Temper.

Hans Passant
I understand it's a bad idea because of the very reasons you mention - someone else's app might try to do the same and then it becomes a big mess. However, this project (http://www.codeproject.com/KB/cpp/DragnDropOnTrayIcon.aspx) seems to be able to find the specific application icon if its not hidden. With this, is it still that much of a bad idea?
brunodecarvalho
I've tested it and it successfully detected whether you drop something on top of your icon or not, however it always shows the allow drop sign on the tray... Anyway, the UX is kind of weird for a windows app... dragging something to the tray.
brunodecarvalho
Bizarre, you don't usually see projects there where the author admits he couldn't make it work. Hard to see how this is anything more than a waste of your time.
Hans Passant
I'm with you on this one. I'll release the app without this feature. If I get a lot of people crying about it, I'll then give it a second shot :)
brunodecarvalho