home *** CD-ROM | disk | FTP | other *** search
/ Chip 2003 November / Chip_2003-11_cd1.bin / software / dave / dqsd.exe / src / DQSDTools / MenuBuilder.cpp < prev    next >
C/C++ Source or Header  |  2002-10-23  |  22KB  |  799 lines

  1. // MenuBuilder.cpp : Implementation of CMenuBuilder
  2. #include "stdafx.h"
  3. #include <windowsx.h>        // For GET_X_LPARAM, etc macros
  4.  
  5. #include "DQSDTools.h"
  6. #include "MenuBuilder.h"
  7. #include "Utilities.h"
  8.  
  9.  
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CMenuBuilder
  12.  
  13. LPCTSTR CMenuBuilder::DQSD_REG_KEY = _T("CLSID\\{226b64e8-dc75-4eea-a6c8-abcb4d1d37ff}");
  14. LPCTSTR CMenuBuilder::DQSD_SEC_KEY = _T("CLSID\\{226b64e8-dc75-4eea-a6c8-abcb4d1d37ff}\\SecureFiles");
  15.  
  16. #define TOOLBAR_TRACKER_WINDOW_CLASS_NAME        "DQSDMenuTrackerClass"
  17. #define TOOLBAR_TRACKER_WINDOW_NAME                "DQSDMenuTracker"
  18.  
  19. HWND        CMenuBuilder::m_hTooltipWnd;
  20.  
  21. STDMETHODIMP CMenuBuilder::SetSite(IUnknown* pUnkSite)
  22. {
  23. #if defined(DQSD_NOSECURITY) && defined(_DEBUG)
  24. #pragma message(  __FILE__ " ** WARNING! ** Compilation without security restrictions...do not distribute the resulting binary! " )
  25. #else
  26.     USES_CONVERSION;
  27.  
  28.     HRESULT hr;
  29.  
  30.     m_spUnkSite = pUnkSite;
  31.  
  32.     CComPtr<IServiceProvider> spSrvProv;
  33.     if (FAILED(hr = GetSite(IID_IServiceProvider, (void**)&spSrvProv)))
  34.         return hr;
  35.  
  36.     CComPtr<IWebBrowser2> spWebBrowser;
  37.     if (FAILED(hr = spSrvProv->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (void**)&spWebBrowser)))
  38.         return hr;
  39.  
  40.     CComBSTR bstrURL;
  41.     if (FAILED(hr = spWebBrowser->get_LocationURL(&bstrURL)))
  42.         return hr;
  43.  
  44.     HKEY hDqsdKey;
  45.     if (ERROR_SUCCESS != RegOpenKey(HKEY_CLASSES_ROOT, DQSD_SEC_KEY, &hDqsdKey))
  46.     {
  47.         Error(IDS_ERR_UNAUTHCALLER, IID_ILauncher);
  48.         return E_FAIL;
  49.     }
  50.  
  51.     
  52.     DWORD dt;
  53.     TCHAR filebuf[MAX_PATH];
  54.     DWORD filelen = sizeof(filebuf);
  55.     DWORD idw = 0;
  56.     BOOL success = FALSE;
  57.  
  58.     while (ERROR_SUCCESS == RegEnumValue(hDqsdKey, idw, filebuf, &filelen, NULL, &dt, NULL, NULL))
  59.     {
  60.         idw++;
  61.         if (URLMatchesFilename(OLE2T(bstrURL), filebuf))
  62.         {
  63.             success = TRUE;
  64.             break;
  65.         }
  66.  
  67.         filelen = sizeof(filebuf);
  68.     }
  69.  
  70.     if (success == FALSE)
  71.     {
  72.         Error(IDS_ERR_UNAUTHCALLER, IID_ILauncher);
  73.         return E_FAIL;
  74.     }
  75.  
  76. #endif
  77.  
  78.   return S_OK;
  79. }
  80.  
  81. STDMETHODIMP CMenuBuilder::Display(LPDISPATCH pDispDocument, VARIANT* pvarSelection)
  82. {
  83.     USES_CONVERSION;
  84.  
  85.     BSTR bstrSelection = NULL;
  86.     VariantInit( pvarSelection );
  87.     pvarSelection->pbstrVal = NULL;
  88.     pvarSelection->vt = VT_NULL;
  89.  
  90.     HWND hwndDQSD = UtilitiesFindDQSDWindow(pDispDocument);
  91.  
  92.     RECT rcParentWnd;
  93.     ::GetWindowRect( hwndDQSD, &rcParentWnd );
  94.  
  95.     HWND hPopupLinkedWindow;
  96.     UINT menuOptions = TPM_RETURNCMD|TPM_BOTTOMALIGN|getHorizontalPosition();
  97.     // Are we going to try tooltip tracking?
  98.     if(m_hTrackerWnd != NULL)
  99.     {
  100.         hPopupLinkedWindow = m_hTrackerWnd;
  101.     }
  102.     else
  103.     {
  104.         hPopupLinkedWindow = hwndDQSD;
  105.         menuOptions |= TPM_NONOTIFY;
  106.     }
  107.  
  108.     int nMenuX = rcParentWnd.right;
  109.     switch ( m_nHorizontalAlignment )
  110.     {
  111.     case EHorizontalAlignment::CENTER: 
  112.         nMenuX = rcParentWnd.left + ( ( rcParentWnd.right - rcParentWnd.left ) / 2 );
  113.         break;
  114.     case EHorizontalAlignment::LEFT:
  115.         nMenuX = rcParentWnd.left;
  116.         break;
  117.     case EHorizontalAlignment::RIGHT:
  118.         nMenuX = rcParentWnd.right;
  119.         break;
  120.     }
  121.  
  122.     int iMenuItem = ::TrackPopupMenuEx( m_hMain, menuOptions, nMenuX, rcParentWnd.top, hPopupLinkedWindow, NULL );
  123.     if ( iMenuItem > 0 )
  124.     {
  125.         bstrSelection = ::SysAllocString( T2CW( m_mapKeys[ iMenuItem ].c_str() ) );
  126.  
  127.         VariantInit( pvarSelection );
  128.         pvarSelection->bstrVal = bstrSelection;
  129.         pvarSelection->vt = VT_BSTR;
  130.     }
  131.  
  132.     ::DestroyMenu( m_hMain );
  133.     m_hMain = NULL;
  134.  
  135.     return S_OK;
  136. }
  137.  
  138. STDMETHODIMP CMenuBuilder::AppendMenuItem(BSTR bstrItem, BSTR bstrKey, BSTR bstrToolTip, VARIANT* pvhMenu )
  139. {
  140.     USES_CONVERSION;
  141.  
  142.     HMENU hmenu = (HMENU)m_hMain;
  143.     if (pvhMenu && ((VT_I4 == pvhMenu->vt) || (VT_I2 == pvhMenu->vt)) )
  144.     {
  145.         hmenu = pvhMenu->intVal ? (HMENU)pvhMenu->intVal : (HMENU)m_hMain;
  146.     }
  147.  
  148.     BOOL bSuccess = ::AppendMenu( hmenu, MF_STRING, m_nMenuItem+1, W2T( bstrItem ) );
  149.     if ( !bSuccess )
  150.         return E_FAIL;
  151.  
  152.     m_nMenuItem++;
  153.     m_mapKeys[ m_nMenuItem ] = std::string( W2T( bstrKey ) );
  154.     m_toolTips[m_nMenuItem] = std::string( W2T( bstrToolTip ) );
  155.  
  156.     return S_OK;
  157. }
  158.  
  159. STDMETHODIMP CMenuBuilder::AppendSubMenu(BSTR bstrName, VARIANT* pvParentMenu, long *phmenu)
  160. {
  161.     *phmenu = (long)::CreatePopupMenu();
  162.  
  163.     USES_CONVERSION;
  164.  
  165.     HMENU hmenu = (HMENU)m_hMain;
  166.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  167.     {
  168.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  169.     }
  170.  
  171.     ::AppendMenu( hmenu, MF_POPUP, (UINT_PTR)*phmenu, W2T( bstrName ) );
  172.     
  173.     return S_OK;
  174. }
  175.  
  176. STDMETHODIMP CMenuBuilder::AppendSeparator(VARIANT* pvParentMenu)
  177. {
  178.     USES_CONVERSION;
  179.  
  180.     HMENU hmenu = (HMENU)m_hMain;
  181.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  182.     {
  183.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  184.     }
  185.  
  186.     ::AppendMenu( hmenu, MF_SEPARATOR, NULL, NULL );
  187.  
  188.     return S_OK;
  189. }
  190.  
  191. STDMETHODIMP CMenuBuilder::get_HorizontalAlignment(short *pVal)
  192. {
  193.     *pVal = (SHORT)(m_nHorizontalAlignment & 0x0000FFFF);
  194.  
  195.     return S_OK;
  196. }
  197.  
  198. STDMETHODIMP CMenuBuilder::put_HorizontalAlignment(short newVal)
  199. {
  200.     switch ( newVal )
  201.     {
  202.     case EHorizontalAlignment::CENTER:
  203.     case EHorizontalAlignment::LEFT:
  204.     case EHorizontalAlignment::RIGHT:
  205.         m_nHorizontalAlignment = newVal;
  206.         break;
  207.     default:
  208.         Error(IDS_ERR_INVALIDHORIZALIGNMENT, IID_IMenuBuilder);
  209.         return E_FAIL;
  210.     }
  211.  
  212.     return S_OK;
  213. }
  214.  
  215. UINT CMenuBuilder::getHorizontalPosition()
  216. {
  217.     switch ( m_nHorizontalAlignment )
  218.     {
  219.     case EHorizontalAlignment::CENTER: return TPM_CENTERALIGN;
  220.     case EHorizontalAlignment::LEFT: return TPM_LEFTALIGN;
  221.     case EHorizontalAlignment::RIGHT: return TPM_RIGHTALIGN;
  222.     }
  223.     return TPM_RIGHTALIGN;
  224. }
  225.  
  226. LRESULT CALLBACK CMenuBuilder::TrackerWndProc(
  227.     HWND hwnd,      // handle to window
  228.     UINT uMsg,      // message identifier
  229.     WPARAM wParam,  // first message parameter
  230.     LPARAM lParam   // second message parameter
  231.     )
  232. {
  233. //    static BOOL bAdded[500];
  234.     static bool bAdded;
  235.  
  236.     if(uMsg == WM_INITMENUPOPUP)
  237.     {
  238.         // It's a new popup - delete any tips
  239.         int nTools = ::SendMessage(m_hTooltipWnd, TTM_GETTOOLCOUNT, 0, 0);
  240.         ATLTRACE("Tooltips: %d existing tools\n", nTools);
  241.         for(int nTool = nTools-1; nTool >= 0; nTool--)
  242.         {
  243.             TOOLINFO ti;
  244.             ZeroMemory(&ti, sizeof(ti));
  245.             ti.cbSize = sizeof(TOOLINFO);
  246.  
  247.             if(::SendMessage(m_hTooltipWnd, TTM_ENUMTOOLS, nTool, (LPARAM)&ti))
  248.             {
  249.                 ATLTRACE("Tool %d - hWnd 0x%x, id %d\n", nTool, ti.hwnd, ti.uId);
  250.  
  251.                 ::SendMessage(m_hTooltipWnd, TTM_DELTOOL, 0, (LPARAM)&ti);
  252.  
  253.             }
  254.         }
  255. //        ZeroMemory(bAdded, sizeof(bAdded));
  256.         bAdded = false;
  257.     }
  258.     if(uMsg == WM_MENUSELECT)
  259.     {
  260.         if(HIWORD(wParam) & MF_POPUP)
  261.         {
  262.             ATLTRACE("Popup - ignoring\n");
  263.         }
  264.         else
  265.         {
  266.             UINT itemId = LOWORD(wParam);
  267.             HMENU hMenu = (HMENU)lParam;
  268.             CMenuBuilder* pThis;
  269.  
  270.             pThis = (CMenuBuilder*)GetWindowLong(hwnd, GWL_USERDATA);
  271.  
  272.             // Is there a tooltip for this item?
  273.             if(pThis != NULL && pThis->m_toolTips.count(itemId) > 0)
  274.             {
  275.  
  276. /*
  277. Even worse!  This doesn't work on scrolling menus...
  278.                 // The GetMenuItemRect call requires the zero-based position of the menu item
  279.                 // Unfortunately, I only have the ID in this message call.
  280.                 // To look up the position, I think I need to loop through the items until I find a 
  281.                 // matching ID - very clunky, but the only conversion functions seem to go
  282.                 // Pos->ID, and not the other way
  283.                 int nItems = GetMenuItemCount(hMenu);
  284.                 int nItemPosition;
  285.                 for(nItemPosition = 0; nItemPosition < nItems; nItemPosition++)
  286.                 {
  287.                     if(GetMenuItemID(hMenu, nItemPosition) == itemId)
  288.                     {
  289.                         // We've found it
  290.                         break;
  291.                     }
  292.                 }
  293. */
  294.                 // It's worse than I thought.
  295.                 // Because very long menus can scroll, nItemPosition needs to be relative
  296.                 // to the topmost DISPLAYED item, rather than the top of the whole menu.
  297.                 // I've resorted to hit-testing each item rectangle, to find the one that we want
  298.                 // Because I'm too lazy to change the code, there's a redudant second look-up
  299.                 // of the item rectangle after this loop completes.
  300.                 POINT cursorPos;
  301.                 DWORD messagePos = GetMessagePos();
  302.                 cursorPos.x = GET_X_LPARAM(messagePos);
  303.                 cursorPos.y = GET_Y_LPARAM(messagePos);
  304.  
  305.                 int nItems = ::GetMenuItemCount(hMenu);
  306.                 int nItemPosition;
  307.                 for(nItemPosition = 0; nItemPosition < nItems; nItemPosition++)
  308.                 {
  309.                     RECT itemRect;
  310.                     GetMenuItemRect(NULL, hMenu, nItemPosition, &itemRect);
  311.                     if(PtInRect(&itemRect, cursorPos))
  312.                     {
  313.                         // We've found our item
  314.                         break;
  315.                     }
  316.                 }
  317.  
  318. //                ATLTRACE("ItemId: %d\n", itemId);
  319.  
  320.                 // If we don't find it, nItemPosition will be == nItems, so the GetMenuItemRect call will fail
  321.                 // and we'll cope with that
  322.                 RECT itemRect;
  323.                 if(GetMenuItemRect(NULL, hMenu, nItemPosition, &itemRect))
  324.                 {
  325.  
  326.     //                ATLTRACE("ItemRect: %d,%d,%d,%d\n", itemRect.left, itemRect.top, itemRect.right, itemRect.bottom);
  327.  
  328.                     TOOLINFO ti;
  329.                     ZeroMemory(&ti, sizeof(ti));
  330.                     ti.cbSize = sizeof(ti);
  331.  
  332.                     if(bAdded)
  333.                     {
  334.                         ::SendMessage(m_hTooltipWnd, TTM_GETTOOLINFO, 0, (LPARAM)&ti);
  335.                     }
  336.  
  337. //                    Rectangle(GetDC(NULL), itemRect.left, itemRect.top, itemRect.right, itemRect.bottom);
  338.  
  339.                     POINT topLeft;
  340.                     topLeft.x = itemRect.left;
  341.                     topLeft.y = itemRect.top;
  342.  
  343.                     // Find the menu's window
  344.                     ti.hwnd = WindowFromPoint(topLeft);
  345.  
  346.                     ti.uFlags = TTF_TRANSPARENT;
  347.                     ti.uId = 1;        
  348.  
  349.                     // This looks horrible, because I'm casting away the const, but it's safe
  350.                     // because I don't ask the ToolTip window to overwrite any data
  351.                     ti.lpszText = (LPTSTR)(pThis->m_toolTips[itemId].c_str());
  352.  
  353. //                    char tipTraceBuffer[100];
  354. //                    tipTraceBuffer[0] = '\0';
  355. //                    strncat(tipTraceBuffer, ti.lpszText, 99);
  356. //                    ATLTRACE("TipText: '%s'\n", tipTraceBuffer);
  357.  
  358.                     // Map the rectangle relative to the menu window
  359. //                    RECT menuWindowRect;
  360. //                    ::GetWindowRect(ti.hwnd, &menuWindowRect);
  361. //                    ATLTRACE("Menu Window: %d,%d,%d,%d\n", menuWindowRect.left, menuWindowRect.top, menuWindowRect.right, menuWindowRect.bottom);
  362.  
  363. //                    itemRect.left -= menuWindowRect.left;
  364. //                    itemRect.top -= menuWindowRect.top;
  365. //                    itemRect.right -= menuWindowRect.left;
  366. //                    itemRect.bottom -= menuWindowRect.top;
  367.  
  368.                     MapWindowPoints(NULL, ti.hwnd, (LPPOINT)&itemRect, 2);
  369.                     ti.rect = itemRect;
  370.                     
  371. //                    ATLTRACE("ToolRect: (wnd %x) %d,%d,%d,%d\n", ti.hwnd, ti.rect.left, ti.rect.top, ti.rect.right, ti.rect.bottom);
  372.             
  373.                     if(bAdded)
  374.                     {
  375. //                        ATLTRACE("Moving\n");
  376.                         ::SendMessage(m_hTooltipWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
  377.  
  378.                         ::SendMessage(m_hTooltipWnd, TTM_SETTOOLINFO, 0, (LPARAM)&ti);
  379.                         ::SendMessage(m_hTooltipWnd, TTM_NEWTOOLRECT, 0, (LPARAM)&ti);
  380.                     }
  381.                     else
  382.                     {
  383. //                        ATLTRACE("Adding\n");
  384.                         if(!::SendMessage(m_hTooltipWnd, TTM_ADDTOOL, 0, (LPARAM)&ti))
  385.                         {
  386.                             ATLTRACE("AddTool failed\n");
  387.                         }
  388.                         else
  389.                         {
  390.                             bAdded = true;
  391.                         }
  392.                     }
  393.  
  394.                     // Send a simulated mouse-move to the tooltip window to let it know that it should display the tip
  395.                     static MSG msgHere = { NULL,WM_MOUSEMOVE,0,0,0,0 };
  396.                     msgHere.hwnd = ti.hwnd;
  397.                     msgHere.lParam = MAKELPARAM(ti.rect.left, ti.rect.top);
  398.                     msgHere.pt.x = ti.rect.left + 5;
  399.                     msgHere.pt.y = ti.rect.top + 5;
  400.  
  401. //                    ATLTRACE("Sending mouse move %d,%d\n", ti.rect.left, ti.rect.top);
  402.  
  403.                     ::SendMessage(m_hTooltipWnd, TTM_RELAYEVENT, 0, (LPARAM)&msgHere);
  404.                 }
  405.             }
  406.         }
  407.     }
  408.  
  409.     return DefWindowProc(hwnd, uMsg,wParam,lParam);
  410. }
  411.  
  412.  
  413. // WGD - This was a sub-class WndProc for the tip window, while I was learning about how TTs work...
  414. /*
  415. WNDPROC lpfnOldWndProc;
  416. LONG FAR PASCAL ToolTipSubClassFunc(   HWND hWnd,
  417.                UINT uMsg,
  418.                WPARAM wParam,
  419.                LONG lParam)
  420. {
  421.  
  422.     if(uMsg == WM_PAINT)
  423.     {   
  424.         ATLTRACE("WM_PAINT\n");    
  425.     }
  426.     else if(uMsg == WM_ACTIVATE)
  427.     { 
  428.         ATLTRACE("WM_ACTIVATE\n");
  429.     }
  430.     else if(uMsg == WM_WINDOWPOSCHANGING)
  431.     {
  432.         LPWINDOWPOS pWndPos = (LPWINDOWPOS)lParam;
  433.         ATLTRACE("WM_WINDOWPOSCHANGING (%d) (%d,%d, 0x%x)\n", IsWindowVisible(hWnd), pWndPos->cx, pWndPos->cy, pWndPos->flags);
  434.     }
  435.     else if(uMsg == WM_TIMER || uMsg == WM_NCHITTEST)
  436.     { 
  437.  
  438.     }
  439.     else if(uMsg < 0x400)
  440.     {
  441.         ATLTRACE("WM_ 0x%x\n", uMsg);
  442.     }
  443.  
  444.  
  445.  
  446.     if(0) // uMsg != TTM_GETTOOLINFO)
  447.     {
  448.         ATLTRACE("ToolTipSubClassFunc - msg 0x%x\n", uMsg);
  449.  
  450.         if(uMsg == TTM_RELAYEVENT)
  451.         {
  452.             MSG* pMsg = (MSG*)lParam;
  453.  
  454. //            if(pMsg->message != WM_MOUSEMOVE)
  455.             {
  456.                 ATLTRACE("Relayed msg = 0x%x @ %d,%d\n", pMsg->message, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam));
  457.             }
  458.         }
  459.         else if(uMsg == TTM_HITTEST)
  460.         {
  461.             TTHITTESTINFO* pHti = (TTHITTESTINFO*)lParam;
  462.             BOOL bResult = CallWindowProc(lpfnOldWndProc, hWnd, uMsg, wParam, lParam);
  463.             ATLTRACE("Hittest %d,%d, result %d\n", pHti->pt.x, pHti->pt.y, bResult);
  464.             return bResult;
  465.         }
  466.         else if(uMsg == TTM_WINDOWFROMPOINT)
  467.         {
  468.             POINT* pPoint = (POINT*)lParam;
  469.             HANDLE result = (HANDLE)CallWindowProc(lpfnOldWndProc, hWnd, uMsg, wParam, lParam);
  470.             ATLTRACE("WndFromPoint %d,%d, result 0x%x\n", pPoint->x, pPoint->y, result);
  471.             if(pPoint->x == 0 && pPoint->y == 0)
  472.             {
  473.                 return 0;
  474.             }
  475.             return (LONG)result;
  476.         }
  477.         
  478.     }
  479.  
  480.     return CallWindowProc(lpfnOldWndProc, hWnd, uMsg, wParam, lParam);
  481.  
  482. }
  483. */
  484.  
  485. // Set up the tracking window which can follow the menu position and display tooltips
  486. STDMETHODIMP CMenuBuilder::InitialiseTooltips(long displayTimeMultiplier)
  487. {
  488.     // Create a window which we use to receive menu tracking info
  489.     WNDCLASS wc;
  490.     ZeroMemory(&wc, sizeof(wc));
  491.     wc.lpfnWndProc = TrackerWndProc;
  492.     wc.lpszClassName = TOOLBAR_TRACKER_WINDOW_CLASS_NAME;
  493.  
  494.     HWND hExistingWindow = FindWindow(wc.lpszClassName, TOOLBAR_TRACKER_WINDOW_NAME);
  495.     if(hExistingWindow != NULL)
  496.     {
  497.         // THere's already hotkey window
  498.         ATLTRACE("MenuTracker - window exists\n");
  499.         DestroyWindow(hExistingWindow);
  500.     }
  501.  
  502.     RegisterClass(&wc);
  503.  
  504.     // Create the menu tracking window
  505.     m_hTrackerWnd = CreateWindow(wc.lpszClassName, TOOLBAR_TRACKER_WINDOW_NAME, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
  506.     if(m_hTrackerWnd == NULL)
  507.     {
  508.         ATLTRACE("Failed to create a window for MenuTracker (err %d)\n", GetLastError());
  509.         return Error(IDS_ERR_MENU_TRACKER_WINDOW_FAILED, IID_ILauncher, E_FAIL);
  510.     }
  511.  
  512.     // Store a 'this' pointer on the tracker window
  513.     ::SetWindowLong(m_hTrackerWnd, GWL_USERDATA, (LONG)this);
  514.  
  515.     // Create a tooltip window
  516.     if(m_hTooltipWnd != NULL)
  517.     {
  518.         DestroyWindow(m_hTooltipWnd);
  519.     }
  520.  
  521.     m_hTooltipWnd = CreateWindow(TOOLTIPS_CLASS,
  522.         NULL,
  523.         TTS_NOPREFIX | TTS_ALWAYSTIP,         
  524.         CW_USEDEFAULT,
  525.         CW_USEDEFAULT,
  526.         CW_USEDEFAULT,
  527.         CW_USEDEFAULT,
  528.         NULL,
  529.         NULL,
  530.         _Module.GetModuleInstance(),
  531.         NULL
  532.         );
  533.     if(m_hTooltipWnd == NULL)
  534.     {
  535.         return Error(_T("Failed to create tooltip window"), IID_ILauncher, E_FAIL);
  536.     }
  537.  
  538.     ::SetWindowPos(m_hTooltipWnd,
  539.         HWND_TOPMOST,
  540.         0,
  541.         0,
  542.         0,
  543.         0,
  544.         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
  545.  
  546.     RECT tipMargin = { 5,5,5,5 };
  547.     ::SendMessage(m_hTooltipWnd, TTM_SETMARGIN, 0, (LPARAM)&tipMargin);
  548.  
  549.     // Set a maximum width - this enables multi-line tooltips
  550.     RECT workArea;
  551.     SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&workArea, 0);
  552.     ::SendMessage(m_hTooltipWnd, TTM_SETMAXTIPWIDTH, 0, (workArea.right-workArea.left)/3);
  553.  
  554.     // Set the tool tip time multiplier
  555.     // (GetDoubleClickTime()*10 is the system default)
  556.     ATLTRACE("InitToolTips: DisplayTimeMult %d\n", displayTimeMultiplier);
  557.     displayTimeMultiplier = max(1, displayTimeMultiplier);
  558.     ::SendMessage(m_hTooltipWnd, TTM_SETDELAYTIME, TTDT_AUTOPOP, GetDoubleClickTime()*10*displayTimeMultiplier);
  559.  
  560. // Subclass the tooltip window - just for debugging
  561. //    lpfnOldWndProc = (WNDPROC)SetWindowLong(m_hTooltipWnd, GWL_WNDPROC, (DWORD)ToolTipSubClassFunc);
  562.  
  563.     return S_OK;
  564. }
  565.  
  566. STDMETHODIMP CMenuBuilder::InsertMenuItem(BSTR bstrItem, BSTR bstrKey, BSTR bstrToolTip, UINT position, VARIANT* pvhMenu )
  567. {
  568.     USES_CONVERSION;
  569.  
  570.     HMENU hmenu = (HMENU)m_hMain;
  571.     if (pvhMenu && ((VT_I4 == pvhMenu->vt) || (VT_I2 == pvhMenu->vt)) )
  572.     {
  573.         hmenu = pvhMenu->intVal ? (HMENU)pvhMenu->intVal : (HMENU)m_hMain;
  574.     }
  575.  
  576.     MENUITEMINFO menuItem;
  577.     memset(&menuItem, 0, sizeof(MENUITEMINFO));
  578.     menuItem.cbSize = sizeof(MENUITEMINFO);
  579.     menuItem.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID; 
  580.     menuItem.fType = MFT_STRING; 
  581.     menuItem.fState = MFS_ENABLED; 
  582.     menuItem.wID = (m_nMenuItem+1);
  583.     menuItem.dwTypeData = W2T( bstrItem );
  584.     menuItem.cch = lstrlen( W2T( bstrItem) );
  585.  
  586.     BOOL bSuccess = ::InsertMenuItem( hmenu, position, TRUE, &menuItem);
  587.     if ( !bSuccess)
  588.         return E_FAIL;
  589.  
  590.     m_nMenuItem++;
  591.     m_mapKeys[ m_nMenuItem ] = std::string( W2T( bstrKey ) );
  592.     m_toolTips[m_nMenuItem] = std::string( W2T( bstrToolTip ) );
  593.  
  594.     return S_OK;
  595. }
  596.  
  597. STDMETHODIMP CMenuBuilder::InsertSeparator(UINT position, VARIANT* pvParentMenu)
  598. {
  599.     USES_CONVERSION;
  600.  
  601.     HMENU hmenu = (HMENU)m_hMain;
  602.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  603.     {
  604.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  605.     }
  606.  
  607.     MENUITEMINFO menuItem;
  608.     memset(&menuItem, 0, sizeof(MENUITEMINFO));
  609.     menuItem.cbSize = sizeof(MENUITEMINFO);
  610.     menuItem.fMask = MIIM_TYPE | MIIM_STATE; 
  611.     menuItem.fType = MFT_SEPARATOR; 
  612.     menuItem.fState = MFS_ENABLED; 
  613.  
  614.     BOOL bSuccess = ::InsertMenuItem( (HMENU)hmenu, position, TRUE, &menuItem);
  615.     if ( !bSuccess)
  616.         return E_FAIL;
  617.  
  618.     return S_OK;
  619. }
  620.  
  621. STDMETHODIMP CMenuBuilder::InsertSubMenu(BSTR bstrName, UINT position, VARIANT* pvParentMenu, long *phmenu)
  622. {
  623.     *phmenu = (long)::CreatePopupMenu();
  624.  
  625.     USES_CONVERSION;
  626.  
  627.     HMENU hmenu = (HMENU)m_hMain;
  628.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  629.     {
  630.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  631.     }
  632.  
  633.     MENUITEMINFO menuItem;
  634.     memset(&menuItem, 0, sizeof(MENUITEMINFO));
  635.     menuItem.cbSize = sizeof(MENUITEMINFO);
  636.     menuItem.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU; 
  637.     menuItem.fType = MFT_STRING; 
  638.     menuItem.fState = MFS_ENABLED; 
  639.     menuItem.hSubMenu = (HMENU)*phmenu;
  640.     menuItem.dwTypeData = W2T( bstrName );
  641.     menuItem.cch = lstrlen( W2T( bstrName) );
  642.  
  643.     BOOL bSuccess = ::InsertMenuItem( (HMENU)hmenu, position, TRUE, &menuItem);
  644.     if ( !bSuccess)
  645.         return E_FAIL;
  646.  
  647.     return S_OK;
  648. }
  649.  
  650. STDMETHODIMP CMenuBuilder::GetMenuItemCount(VARIANT* pvParentMenu, long *pCount)
  651. {
  652.     USES_CONVERSION;
  653.  
  654.     HMENU hmenu = (HMENU)m_hMain;
  655.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  656.     {
  657.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  658.     }
  659.  
  660.     int retval = ::GetMenuItemCount(hmenu);
  661.     if (retval == -1)
  662.     {
  663.         return Error(_T("Invalid menu handle"), IID_IMenuBuilder, E_FAIL);
  664.     }
  665.     *pCount = (long)retval;
  666.     return S_OK;
  667. }
  668.  
  669. STDMETHODIMP CMenuBuilder::FindSubMenu(BSTR bstrName, VARIANT* pvParentMenu, long *phmenu)
  670. {
  671.     USES_CONVERSION;
  672.  
  673.     *phmenu = -1;
  674.  
  675.     HMENU hmenu = (HMENU)m_hMain;
  676.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  677.     {
  678.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  679.     }
  680.  
  681.     int nItems = ::GetMenuItemCount(hmenu);
  682.     int nItemPosition;
  683.     for(nItemPosition = 0; nItemPosition < nItems; nItemPosition++)
  684.     {
  685.         TCHAR menuName[101];
  686.         int len = ::GetMenuString(hmenu, nItemPosition, menuName, 100, MF_BYPOSITION);
  687.         if (len != 0)
  688.         {
  689.             if (lstrcmp(W2T(bstrName), menuName)==0)
  690.             {
  691.                 *phmenu = (long)::GetSubMenu(hmenu, nItemPosition);
  692.                 if (*phmenu == 0)
  693.                 {
  694.                     *phmenu = -1;
  695.                 }
  696.                 break;
  697.             }
  698.         }
  699.     }
  700.  
  701.     return S_OK;
  702. }
  703.  
  704. STDMETHODIMP CMenuBuilder::FindMenuItem(BSTR bstrName, VARIANT* pvParentMenu, long *pPosition)
  705. {
  706.     USES_CONVERSION;
  707.  
  708.     *pPosition = -1;
  709.  
  710.     HMENU hmenu = (HMENU)m_hMain;
  711.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  712.     {
  713.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  714.     }
  715.  
  716.     int nItems = ::GetMenuItemCount(hmenu);
  717.     int nItemPosition;
  718.     for(nItemPosition = 0; nItemPosition < nItems; nItemPosition++)
  719.     {
  720.         TCHAR menuName[101];
  721.         int len = ::GetMenuString(hmenu, nItemPosition, menuName, 100, MF_BYPOSITION);
  722.         if (len != 0)
  723.         {
  724.             if (lstrcmp(W2T(bstrName), menuName)==0)
  725.             {
  726.                 *pPosition = (long)nItemPosition;
  727.                 break;
  728.             }
  729.         }
  730.     }
  731.     return S_OK;
  732. }
  733.  
  734. STDMETHODIMP CMenuBuilder::GetMenuString(UINT position, VARIANT* pvParentMenu, BSTR* pbstrResult)
  735. {
  736.     USES_CONVERSION;
  737.  
  738.     HMENU hmenu = (HMENU)m_hMain;
  739.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  740.     {
  741.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  742.     }
  743.  
  744.     CComBSTR bstrMenuName;
  745.     TCHAR menuName[101];
  746.     int nResult = ::GetMenuString(hmenu, position, menuName, 100, MF_BYPOSITION);
  747.     if (nResult > 0) {
  748.         bstrMenuName.Append(menuName);
  749.     }
  750.     *pbstrResult = bstrMenuName.Detach();
  751.     return S_OK;
  752. }
  753.  
  754. STDMETHODIMP CMenuBuilder::GetMenuItemID(UINT position, VARIANT* pvParentMenu, long *nID)
  755. {
  756.     USES_CONVERSION;
  757.  
  758.     HMENU hmenu = (HMENU)m_hMain;
  759.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  760.     {
  761.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  762.     }
  763.  
  764.     if (nID != NULL) {
  765.         *nID = (long)::GetMenuItemID(hmenu, position);
  766.         return S_OK;
  767.     } else {
  768.         return E_FAIL;
  769.     }
  770. }
  771.  
  772. STDMETHODIMP CMenuBuilder::EnableMenuItem(UINT position, VARIANT* pvParentMenu)
  773. {
  774.     USES_CONVERSION;
  775.  
  776.     HMENU hmenu = (HMENU)m_hMain;
  777.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  778.     {
  779.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  780.     }
  781.  
  782.     ::EnableMenuItem(hmenu, position, MF_BYPOSITION | MF_ENABLED);
  783.     return S_OK;
  784. }
  785.  
  786.  
  787. STDMETHODIMP CMenuBuilder::DisableMenuItem(UINT position, VARIANT* pvParentMenu)
  788. {
  789.     USES_CONVERSION;
  790.  
  791.     HMENU hmenu = (HMENU)m_hMain;
  792.     if (pvParentMenu && ((VT_I4 == pvParentMenu->vt) || (VT_I2 == pvParentMenu->vt)) )
  793.     {
  794.         hmenu = pvParentMenu->intVal ? (HMENU)pvParentMenu->intVal : (HMENU)m_hMain;
  795.     }
  796.     ::EnableMenuItem(hmenu, position, MF_BYPOSITION | MF_GRAYED);
  797.     return S_OK;
  798. }
  799.