December 29th, 2011

Using the MNS_DRAGDROP style: Dropping in

Last time, we looked at using the MNS_DRAG­DROP style for dragging items out of a menu. Today, we’ll look at dropping them in.

Take the program from last time and make the following additions. First, let’s add a second item to the menu.

// resource header file
#define IDM_MAIN 1
#define IDC_CLOCK 100
#define IDC_WMP 101
// resource file
IDM_MAIN MENU PRELOAD
BEGIN
    POPUP "&Test"
    BEGIN
        MENUITEM "&Clock", IDC_CLOCK
        MENUITEM "&WMP", IDC_WMP
    END
END
// scratch.cpp
HRESULT GetMenuObject(HWND hwnd, HMENU hmenu, UINT uPos,
                      REFIID riid, void **ppvOut)
{
 HRESULT hr = E_NOTIMPL;
 *ppvOut = NULL;
 if (hmenu == GetSubMenu(GetMenu(hwnd), 0)) {
  switch (GetMenuItemID(hmenu, uPos)) {
  case IDC_CLOCK:
   hr = GetUIObjectOfFile(hwnd, L"C:\\Windows\\clock.avi",
                                             riid, ppvOut);
   break;
  case IDC_WMP:
   hr = GetUIObjectOfFile(hwnd, L"C:\\Program Files"
                  L"\\Windows Media Player\\wmplayer.exe",
                                             riid, ppvOut);
   break;
  }
 }
 return hr;
}

Yes, I hard-coded another path. This is a demo, not production code.

Anyway, it’s time to hook up the WM_MENU­GET­OBJECT message:

#define HANDLE_WM_MENUGETOBJECT(hwnd, wParam, lParam, fn) \
 (fn)((hwnd), (MENUGETOBJECTINFO*)(lParam))
LRESULT OnMenuGetObject(HWND hwnd, MENUGETOBJECTINFO *pmgoi)
{
 LRESULT lres = MNGO_NOINTERFACE;
 if (!(pmgoi->dwFlags & (MNGOF_BOTTOMGAP | MNGOF_TOPGAP)) &&
     SUCCEEDED(GetMenuObject(hwnd, pmgoi->hmenu, pmgoi->uPos,
               *(IID*)pmgoi->riid, &pmgoi->pvObj))) {
  lres = MNGO_NOERROR;
 }
 return lres;
}
    HANDLE_MSG(hwnd, WM_MENUGETOBJECT, OnMenuGetObject);

To handle the WM_MENU­GET­OBJECT message, you convert the hmenu, uPos pair into a COM object, requesting the interface provided by the riid member, and putting the result into the pvObj member. (Exercise: Why is the riid member typed as void * rather than REFIID?)

When the user tries to drop on a menu item, we just give them the corresponding object in the shell namespace. Notice that I filter out the GAP messages, since they indicate that the user is trying to drop between items rather than on them.

Run this program, open the Test menu, and drag the Clock menu item onto the WMP menu item. If all goes well (assuming you changed the path for clock.avi to some other AVI file), the AVI file will be opened by Windows Media Player, since that’s the behavior of Windows Media Player when you drop an AVI file on it.

So that’s menu drag/drop. It’s really not all that exciting. Of course, what people tend to be most interested in is not generic drag/drop for menus but menu customization via drag/drop. That’s not something that MNS_DRAG­DROP gives you directly; that’s something you need to build yourself out of the building blocks provided.

We’ll snap some blocks together next time.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.